From 5ad4c41dc406a15beaa0a7b73d9dada1df74f939 Mon Sep 17 00:00:00 2001 From: Super User Date: Sun, 3 Feb 2008 13:47:33 +0100 Subject: now gives warning if mISDN branch is wrong. also some work on chan_lcr. modified: Makefile modified: apppbx.cpp modified: bchannel.c modified: chan_lcr.c modified: chan_lcr.h modified: dss1.cpp modified: dss1.h modified: extension.c modified: extension.h modified: genrc.c modified: ie.cpp renamed: admin_client.c -> lcradmin.c renamed: admin.h -> lcrsocket.h modified: mISDN.cpp modified: main.h renamed: admin_server.c -> socket_server.c renamed: admin_server.h -> socket_server.h modified: todo.txt --- Makefile | 12 +- admin.h | 185 ------ admin_client.c | 1757 ------------------------------------------------------- admin_server.c | 1323 ----------------------------------------- admin_server.h | 40 -- apppbx.cpp | 10 +- bchannel.c | 2 + chan_lcr.c | 187 +++++- chan_lcr.h | 2 + dss1.cpp | 20 +- dss1.h | 1 - extension.c | 23 - extension.h | 1 - genrc.c | 14 +- ie.cpp | 52 -- lcradmin.c | 1757 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ lcrsocket.h | 185 ++++++ mISDN.cpp | 50 +- main.h | 2 +- socket_server.c | 1323 +++++++++++++++++++++++++++++++++++++++++ socket_server.h | 40 ++ todo.txt | 37 +- 22 files changed, 3581 insertions(+), 3442 deletions(-) delete mode 100644 admin.h delete mode 100644 admin_client.c delete mode 100644 admin_server.c delete mode 100644 admin_server.h create mode 100644 lcradmin.c create mode 100644 lcrsocket.h create mode 100644 socket_server.c create mode 100644 socket_server.h diff --git a/Makefile b/Makefile index fd73542..c19a500 100644 --- a/Makefile +++ b/Makefile @@ -146,8 +146,8 @@ crypt.o: crypt.cpp *.h Makefile genext.o: genext.c *.h Makefile $(PP) -c $(CFLAGS) genext.c -o genext.o -admin_server.o: admin_server.c *.h Makefile - $(PP) -c $(CFLAGS) admin_server.c -o admin_server.o +socket_server.o: socket_server.c *.h Makefile + $(PP) -c $(CFLAGS) socket_server.c -o socket_server.o trace.o: trace.c *.h Makefile $(PP) -c $(CFLAGS) trace.c -o trace.o @@ -187,7 +187,7 @@ $(LCR): main.o \ join.o \ joinpbx.o \ joinremote.o \ - admin_server.o \ + socket_server.o \ trace.o $(PP) $(LIBDIR) \ main.o \ @@ -214,12 +214,12 @@ $(LCR): main.o \ join.o \ joinpbx.o \ joinremote.o \ - admin_server.o \ + socket_server.o \ trace.o \ $(LIBS) -o $(LCR) -$(LCRADMIN): admin_client.c cause.c *.h Makefile - $(PP) $(LIBDIR) $(CFLAGS) $(CURSES) -lm admin_client.c cause.c \ +$(LCRADMIN): lcradmin.c cause.c *.h Makefile + $(PP) $(LIBDIR) $(CFLAGS) $(CURSES) -lm lcradmin.c cause.c \ -o $(LCRADMIN) $(CHAN_LCR): chan_lcr.o bchannel.o diff --git a/admin.h b/admin.h deleted file mode 100644 index a34820d..0000000 --- a/admin.h +++ /dev/null @@ -1,185 +0,0 @@ -/*****************************************************************************\ -** ** -** Linux Call Router ** -** ** -**---------------------------------------------------------------------------** -** Copyright: Andreas Eversberg ** -** ** -** Administration tool header file ** -** ** -\*****************************************************************************/ - -#define SOCKET_NAME "/var/run/LCR.socket" - -/* structures that define message between admin-tool and pbx */ - -enum { /* messages */ - ADMIN_REQUEST_CMD_INTERFACE, - ADMIN_RESPONSE_CMD_INTERFACE, - ADMIN_REQUEST_CMD_ROUTE, - ADMIN_RESPONSE_CMD_ROUTE, - ADMIN_REQUEST_CMD_DIAL, - ADMIN_RESPONSE_CMD_DIAL, - ADMIN_REQUEST_CMD_RELEASE, - ADMIN_RESPONSE_CMD_RELEASE, - ADMIN_REQUEST_CMD_BLOCK, - ADMIN_RESPONSE_CMD_BLOCK, - ADMIN_REQUEST_STATE, - ADMIN_RESPONSE_STATE, - ADMIN_RESPONSE_S_REMOTE, - ADMIN_RESPONSE_S_INTERFACE, - ADMIN_RESPONSE_S_PORT, - ADMIN_RESPONSE_S_EPOINT, - ADMIN_RESPONSE_S_JOIN, - ADMIN_CALL_SETUP, - ADMIN_CALL_SETUP_ACK, - ADMIN_CALL_PROCEEDING, - ADMIN_CALL_ALERTING, - ADMIN_CALL_CONNECT, - ADMIN_CALL_DISCONNECT, - ADMIN_CALL_RELEASE, - ADMIN_CALL_NOTIFY, - ADMIN_TRACE_REQUEST, - ADMIN_TRACE_RESPONSE, - ADMIN_MESSAGE, -}; - -struct admin_response_cmd { - int error; /* error code 0 = ok*/ - char message[256]; /* info / response text */ - int block; - int portnum; -}; - -struct admin_response_state { - char version_string[64]; - struct tm tm; - char logfile[128]; - int interfaces; - int remotes; - int joins; - int epoints; - int ports; -}; - -struct admin_response_interface { - char interface_name[32]; - int portnum; - int block; - int ntmode; - int ptp; - int pri; - int extension; - int use; /* number of ports that use this interface */ - int l1link; /* down(0) or up(1) */ - int l2link; /* down(0) or up(1) */ - int channels; - char busy[256]; /* if port is idle(0) busy(1) */ - unsigned long port[256]; /* current port */ -}; - -struct admin_response_remote { - char name[32]; /* name of remote application */ -}; - -struct admin_response_join { - unsigned long serial; /* join serial number */ - char remote[32]; /* remote application name */ - unsigned long partyline; -}; - -struct admin_response_epoint { - unsigned long serial; - unsigned long join; /* link to join */ -// int join_notify; /* if relation notified on hold */ -// int join_hold; /* if relation on hold */ - int rx_state; - int tx_state; - int state; - char terminal[16]; - char callerid[64]; - char dialing[64]; - char action[32]; - int park; /* if parked */ - int park_len; - unsigned char park_callid[8]; - int crypt; /* crypt state */ -}; - -struct admin_response_port { - unsigned long serial; /* port serial number */ - char name[64]; /* name of port */ - unsigned long epoint; /* link to epoint */ - int state; - int isdn; /* if port is isdn */ - int isdn_chan; /* bchannel number */ - int isdn_hold; /* on hold */ - int isdn_ces; /* ces to use (>=0)*/ -}; - -struct admin_call { - char interface[64]; /* name of port */ - char callerid[64]; /* use caller id */ - char dialing[64]; /* number to dial */ - int present; /* presentation */ - int cause; /* cause to send */ - int location; - int notify; - int bc_capa; - int bc_mode; - int bc_info1; - int hlc; - int exthlc; -}; - -struct admin_trace_req { - int detail; - char category; - int port; - char interface[64]; - char caller[34]; - char dialing[64]; -}; - -struct admin_trace_rsp { - char text[1024]; -}; - -struct admin_msg { - int type; /* type of message */ - unsigned long ref; /* reference to individual endpoints */ - union parameter param; /* parameter union */ -}; - -struct admin_message { - int message; /* type of admin message */ - union u { - struct admin_response_cmd x; - struct admin_response_state s; - struct admin_response_interface i; - struct admin_response_port p; - struct admin_response_epoint e; - struct admin_response_join j; - struct admin_response_remote r; - struct admin_call call; - struct admin_msg msg; - struct admin_trace_req trace_req; - struct admin_trace_rsp trace_rsp; - } u; -}; - -/* call states */ -enum { - ADMIN_STATE_IDLE, - ADMIN_STATE_IN_SETUP, - ADMIN_STATE_OUT_SETUP, - ADMIN_STATE_IN_OVERLAP, - ADMIN_STATE_OUT_OVERLAP, - ADMIN_STATE_IN_PROCEEDING, - ADMIN_STATE_OUT_PROCEEDING, - ADMIN_STATE_IN_ALERTING, - ADMIN_STATE_OUT_ALERTING, - ADMIN_STATE_CONNECT, - ADMIN_STATE_IN_DISCONNECT, - ADMIN_STATE_OUT_DISCONNECT, -}; diff --git a/admin_client.c b/admin_client.c deleted file mode 100644 index 2c0b362..0000000 --- a/admin_client.c +++ /dev/null @@ -1,1757 +0,0 @@ -/*****************************************************************************\ -** ** -** Linux Call Router ** -** ** -**---------------------------------------------------------------------------** -** Copyright: Andreas Eversberg ** -** ** -** Administration tool ** -** ** -\*****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "macro.h" -#include "join.h" -#include "joinpbx.h" -#include "extension.h" -#include "message.h" -#include "admin.h" -#include "cause.h" - -#define LTEE {addch(ACS_LTEE);addch(ACS_HLINE);addch(ACS_HLINE);} -#define LLCORNER {addch(ACS_LLCORNER);addch(ACS_HLINE);addch(ACS_HLINE);} -#define VLINE {addch(ACS_VLINE);addstr(" ");} -#define EMPTY {addstr(" ");} -//char rotator[] = {'-', '\\', '|', '/'}; -int lastlines, lastcols; -int show_interfaces = 2, - show_calls = 1, - show_log = 1; - -enum { - MODE_STATE, - MODE_INTERFACE, - MODE_ROUTE, - MODE_DIAL, - MODE_RELEASE, - MODE_UNBLOCK, - MODE_BLOCK, - MODE_UNLOAD, - MODE_TESTCALL, - MODE_TRACE, -}; - -char *text_interfaces[] = { - "off", - "brief", - "active channels", - "all channels", -}; - -char *text_calls[] = { - "off", - "brief", - "structured", -}; - -char red = 1, - green = 2, - yellow = 3, - blue = 4, - mangenta = 5, - cyan = 6, - white = 7; - -#define LOGLINES 128 -char logline[LOGLINES][512]; -unsigned long logcur = 0; -int logfh = -1; -char logfile[128]; - -/* - * curses - */ -void init_curses(void) -{ - /* init curses */ - initscr(); cbreak(); noecho(); - start_color(); - nodelay(stdscr, TRUE); - if (COLOR_PAIRS>=8 && COLORS>=8) - { - init_pair(1,1,0); - init_pair(2,2,0); - init_pair(3,3,0); - init_pair(4,4,0); - init_pair(5,5,0); - init_pair(6,6,0); - init_pair(7,7,0); - } - lastlines = LINES; - lastcols = COLS; -} - -void cleanup_curses(void) -{ - endwin(); -} - -void color(int color) -{ - if (COLOR_PAIRS>=8 && COLORS>=8) - attrset(COLOR_PAIR(color)); -} - -/* - * permanently show current state using ncurses - */ -int debug_port(struct admin_message *msg, struct admin_message *m, int line, int i, int vline) -{ - char buffer[256]; - - color(white); - addstr("PORT:"); - color(yellow); - SPRINT(buffer,"%s(%d)", m[i].u.p.name,m[i].u.p.serial); - addstr(buffer); - color(cyan); - addstr(" state="); - switch (m[i].u.p.state) - { - case ADMIN_STATE_IDLE: - color(red); - addstr("'idle'"); - break; - case ADMIN_STATE_IN_SETUP: - color(red); - addstr("'in << setup'"); - break; - case ADMIN_STATE_OUT_SETUP: - color(red); - addstr("'out >> setup'"); - break; - case ADMIN_STATE_IN_OVERLAP: - color(yellow); - addstr("'in << overlap'"); - break; - case ADMIN_STATE_OUT_OVERLAP: - color(yellow); - addstr("'out >> overlap'"); - break; - case ADMIN_STATE_IN_PROCEEDING: - color(mangenta); - addstr("'in << proc'"); - break; - case ADMIN_STATE_OUT_PROCEEDING: - color(mangenta); - addstr("'out >> proc'"); - break; - case ADMIN_STATE_IN_ALERTING: - color(cyan); - addstr("'in << alert'"); - break; - case ADMIN_STATE_OUT_ALERTING: - color(cyan); - addstr("'out >> alert'"); - break; - case ADMIN_STATE_CONNECT: - color(white); - addstr("'connect'"); - break; - case ADMIN_STATE_IN_DISCONNECT: - color(blue); - addstr("'in << disc'"); - break; - case ADMIN_STATE_OUT_DISCONNECT: - color(blue); - addstr("'out >> disc'"); - break; - default: - color(blue); - addstr("'--NONE--'"); - } - - if (m[i].u.p.isdn) - { - color(cyan); - addstr(" bchannel="); - color(white); - SPRINT(buffer,"%d", m[i].u.p.isdn_chan); - addstr(buffer); - if (m[i].u.p.isdn_ces >= 0) - { - color(cyan); - addstr(" ces="); - color(yellow); - SPRINT(buffer, "%d", m[i].u.p.isdn_ces); - addstr(buffer); - } - if (m[i].u.p.isdn_hold) - { - color(red); - addstr(" hold"); - } - } - - return(line); -} -int debug_epoint(struct admin_message *msg, struct admin_message *m, int line, int i, int vline) -{ - unsigned long epoint = m[i].u.e.serial; - char buffer[256]; - unsigned char c; - int j, jj; - int ltee; - - color(white); - SPRINT(buffer,"EPOINT(%d)", epoint); - addstr(buffer); - color(cyan); - addstr(" state="); - switch (m[i].u.e.state) - { - case ADMIN_STATE_IDLE: - color(red); - addstr("'idle'"); - break; - case ADMIN_STATE_IN_SETUP: - color(red); - addstr("'in << setup'"); - break; - case ADMIN_STATE_OUT_SETUP: - color(red); - addstr("'out >> setup'"); - break; - case ADMIN_STATE_IN_OVERLAP: - color(yellow); - addstr("'in << overlap'"); - break; - case ADMIN_STATE_OUT_OVERLAP: - color(yellow); - addstr("'out >> overlap'"); - break; - case ADMIN_STATE_IN_PROCEEDING: - color(mangenta); - addstr("'in << proc'"); - break; - case ADMIN_STATE_OUT_PROCEEDING: - color(mangenta); - addstr("'out >> proc'"); - break; - case ADMIN_STATE_IN_ALERTING: - color(cyan); - addstr("'in << alert'"); - break; - case ADMIN_STATE_OUT_ALERTING: - color(cyan); - addstr("'out >> alert'"); - break; - case ADMIN_STATE_CONNECT: - color(white); - addstr("'connect'"); - break; - case ADMIN_STATE_IN_DISCONNECT: - color(blue); - addstr("'in << disc'"); - break; - case ADMIN_STATE_OUT_DISCONNECT: - color(blue); - addstr("'out >> disc'"); - break; - default: - color(blue); - addstr("'--NONE--'"); - } - if (m[i].u.e.terminal[0]) - { - color(cyan); - addstr(" terminal="); - color(green); - addstr(m[i].u.e.terminal); - } - color(white); - SPRINT(buffer, " %s", m[i].u.e.callerid); - addstr(buffer); - color(cyan); - addstr("->"); - color(white); - addstr(m[i].u.e.dialing); - if (m[i].u.e.action[0]) - { - color(cyan); - addstr(" action="); - color(yellow); - addstr(m[i].u.e.action); - } - if (m[i].u.e.park) - { - color(cyan); - addstr(" park="); /* 9 digits */ - color(green); - UCPY(buffer, "\""); /* 9 digits */ - j = 0; - jj = m[i].u.e.park_len; - while(j < jj) - { - c = m[i].u.e.park_callid[j]; - if (c >= 32 && c < 127 && c != '[') - { - SCCAT(buffer, c); - } else - UPRINT(buffer+strlen(buffer), "[%02x]", c); - j++; - } - SCAT(buffer, "\""); - addstr(buffer); - } else - { - color(red); - switch(m[i].u.e.rx_state) - { - case NOTIFY_STATE_SUSPEND: - addstr(" in=suspend"); - break; - case NOTIFY_STATE_HOLD: - addstr(" in=hold"); - break; - case NOTIFY_STATE_CONFERENCE: - addstr(" in=conference"); - break; - } - switch(m[i].u.e.tx_state) - { - case NOTIFY_STATE_SUSPEND: - addstr(" out=suspend"); - break; - case NOTIFY_STATE_HOLD: - addstr(" out=hold"); - break; - case NOTIFY_STATE_CONFERENCE: - addstr(" out=conference"); - break; - } - } - if (m[i].u.e.crypt) - { - color(cyan); - addstr(" crypt="); - if (m[i].u.e.crypt) /* crypt on */ - { - color(green); - addstr("active"); - } else - { - color(yellow); - addstr("pending"); - } - } - /* loop all related ports */ - ltee = 0; - j = msg->u.s.interfaces+msg->u.s.joins+msg->u.s.epoints; - jj = j + msg->u.s.ports; - while(j < jj) - { - if (m[j].u.p.epoint == epoint) - { - color(cyan); - move(++line>1?line:1, 1); - if (vline) - VLINE - else - EMPTY - move(line>1?line:1, 5); - LTEE - ltee = line; - move(line>1?line:1, 8); - if (line+2 >= LINES) break; - line = debug_port(msg, m, line, j, vline); - if (line+2 >= LINES) break; - } - j++; - } - if (ltee) - { - color(cyan); - move(ltee>1?line:1, 5); - LLCORNER - } - - return(line); -} -int debug_join(struct admin_message *msg, struct admin_message *m, int line, int i) -{ - unsigned long join = m[i].u.j.serial; - char buffer[256]; - int j, jj; - - color(white); - SPRINT(buffer,"JOIN(%d)", join); - addstr(buffer); - if (m[i].u.j.partyline) - { - color(cyan); - addstr(" partyline="); - color(white); - SPRINT(buffer, "%d\n", m[i].u.j.partyline); - addstr(buffer); - } - if (m[i].u.j.remote[0]) - { - color(cyan); - addstr(" remote="); - color(white); - SPRINT(buffer, "%s\n", m[i].u.j.remote); - addstr(buffer); - } - /* find number of epoints */ - j = msg->u.s.interfaces+msg->u.s.joins; - jj = j + msg->u.s.epoints; - i = 0; - while(j < jj) - { - if (m[j].u.e.join == join) - i++; - j++; - } - /* loop all related endpoints */ - j = msg->u.s.interfaces+msg->u.s.joins; - jj = j + msg->u.s.epoints; - while(j < jj) - { - if (m[j].u.e.join == join) - { - i--; - move(++line>1?line:1, 1); - color(cyan); - if (i) - LTEE - else - LLCORNER - move(line>1?line:1, 4); - if (line+2 >= LINES) break; - line = debug_epoint(msg, m, line, j, i?1:0); - if (line+2 >= LINES) break; - } - j++; - } - - return(line); -} -char *admin_state(int sock, char *argv[]) -{ - struct admin_message msg, - *m; - char buffer[512], - *p; - int line, offset = 0, hoffset = 0; - int i, ii, j, jj, k; - unsigned long l, ll; - int num; - int len; - int off; - int ltee; - int anything; - int enter = 0; - char enter_string[128] = "", ch; - fd_set select_rfds; - struct timeval select_tv; - - /* flush logfile name */ - logfile[0] = '\0'; - - /* init curses */ - init_curses(); - - again: - /* send reload command */ - memset(&msg, 0, sizeof(msg)); - msg.message = ADMIN_REQUEST_STATE; -// printf("sizeof=%d\n",sizeof(msg));fflush(stdout); - if (write(sock, &msg, sizeof(msg)) != sizeof(msg)) - { - cleanup_curses(); - return("Broken pipe while sending command."); - } - - /* receive response */ - if (read(sock, &msg, sizeof(msg)) != sizeof(msg)) - { - cleanup_curses(); - return("Broken pipe while receiving response."); - } - - if (msg.message != ADMIN_RESPONSE_STATE) - { - cleanup_curses(); - return("Response not valid. Expecting state response."); - } - num = msg.u.s.interfaces + msg.u.s.remotes + msg.u.s.joins + msg.u.s.epoints + msg.u.s.ports; - m = (struct admin_message *)MALLOC(num*sizeof(struct admin_message)); - off=0; - if (num) - { - readagain: - if ((len = read(sock, ((unsigned char *)(m))+off, num*sizeof(struct admin_message)-off)) != num*(int)sizeof(struct admin_message)-off) - { - if (len <= 0) { - FREE(m, 0); - // fprintf(stderr, "got=%d expected=%d\n", i, num*sizeof(struct admin_message)); - cleanup_curses(); - return("Broken pipe while receiving state infos."); - } - if (len < num*(int)sizeof(struct admin_message)) - { - off+=len; - goto readagain; - } - } - } - j = 0; - i = 0; -// fprintf("getting =%d interfaces\n", msg.u.s.interfaces); - while(i < msg.u.s.interfaces) - { -// fprintf(stderr, "j=%d message=%d\n", j, m[j].message); - if (m[j].message != ADMIN_RESPONSE_S_INTERFACE) - { - FREE(m, 0); - cleanup_curses(); - return("Response not valid. Expecting interface information."); - } - i++; - j++; - } - i = 0; - while(i < msg.u.s.remotes) - { - if (m[j].message != ADMIN_RESPONSE_S_REMOTE) - { - FREE(m, 0); - cleanup_curses(); - return("Response not valid. Expecting remote application information."); - } - i++; - j++; - } - i = 0; - while(i < msg.u.s.joins) - { - if (m[j].message != ADMIN_RESPONSE_S_JOIN) - { - FREE(m, 0); - cleanup_curses(); - return("Response not valid. Expecting join information."); - } - i++; - j++; - } - i = 0; - while(i < msg.u.s.epoints) - { - if (m[j].message != ADMIN_RESPONSE_S_EPOINT) - { - FREE(m, 0); - cleanup_curses(); - return("Response not valid. Expecting endpoint information."); - } - i++; - j++; - } - i = 0; - while(i < msg.u.s.ports) - { - if (m[j].message != ADMIN_RESPONSE_S_PORT) - { - FREE(m, 0); - cleanup_curses(); - return("Response not valid. Expecting port information."); - } - i++; - j++; - } - // now j is the number of message blocks - - /* display start */ - erase(); - - line = 1-offset; - - /* change log */ - if (!!strcmp(logfile, msg.u.s.logfile)) - { - SCPY(logfile, msg.u.s.logfile); - if (logfh >= 0) - close(logfh); - i = 0; - ii = LOGLINES; - while(i < ii) - { - logline[i][0] = '~'; - logline[i][1] = '\0'; - i++; - } - logcur = 0; - logfh = open(logfile, O_RDONLY|O_NONBLOCK); - if (logfh >= 0) - { - /* seek at the end -8000 chars */ - lseek(logfh, -8000, SEEK_END); - /* if not at the beginning, read until endofline */ - logline[logcur % LOGLINES][0] = '\0'; - l = read(logfh, logline[logcur % LOGLINES], sizeof(logline[logcur % LOGLINES])-1); - if (l > 0) - { - /* read first line and skip junk */ - logline[logcur % LOGLINES][l] = '\0'; - if ((p = strchr(logline[logcur % LOGLINES],'\n'))) - { - logcur++; - SCPY(logline[logcur % LOGLINES], p+1); - SCPY(logline[(logcur-1) % LOGLINES], "..."); - } - goto finish_line; - } - } - } - - /* read log */ - if (logfh >= 0) - { - while(42) - { - ll = strlen(logline[logcur % LOGLINES]); - l = read(logfh, logline[logcur % LOGLINES]+ll, sizeof(logline[logcur % LOGLINES])-ll-1); - if (l<=0) - break; - logline[logcur % LOGLINES][ll+l] = '\0'; - finish_line: - /* put data to lines */ - while ((p = strchr(logline[logcur % LOGLINES],'\n'))) - { - *p = '\0'; - logcur++; - SCPY(logline[logcur % LOGLINES], p+1); - } - /* if line is full without return, go next line */ - if (strlen(logline[logcur % LOGLINES]) == sizeof(logline[logcur % LOGLINES])-1) - { - logcur++; - logline[logcur % LOGLINES][0] = '\0'; - } - } - } - - /* display interfaces */ - if (show_interfaces > 0) - { - anything = 0; - i = 0; - ii = i + msg.u.s.interfaces; - while(i < ii) - { - /* show interface summary */ - move(++line>1?line:1, 0); - color(white); - if (m[i].u.i.block >= 2) - { - SPRINT(buffer, "%s (%d)%s", m[i].u.i.interface_name, m[i].u.i.portnum, (m[i].u.i.extension)?" (extension)":""); - addstr(buffer); - color(red); - addstr(" not loaded"); - } else - { - SPRINT(buffer, "%s (%d) %s %s%s use:%d", m[i].u.i.interface_name, m[i].u.i.portnum, (m[i].u.i.ntmode)?"NT-mode":"TE-mode", (m[i].u.i.ptp)?"ptp ":"ptmp", (m[i].u.i.extension)?" extension":"", m[i].u.i.use); - addstr(buffer); - if (m[i].u.i.ptp || !m[i].u.i.ntmode) - { - color((m[i].u.i.l2link)?green:red); - addstr((m[i].u.i.l2link)?" L2 UP":" L2 down"); - } - color((m[i].u.i.l1link)?green:blue); - addstr((m[i].u.i.l1link)?" L1 ACTIVE":" L1 inactive"); - if (m[i].u.i.block) - { - color(red); - addstr(" blocked"); - } - if (line+2 >= LINES) goto end; - /* show channels */ - if (show_interfaces > 1) - { - ltee = 0; - j = k =0; - jj = m[i].u.i.channels; - while(j < jj) - { - /* show all channels */ - if (show_interfaces>2 || m[i].u.i.busy[j]>0) - { - color(cyan); - /* show left side / right side */ - if ((k & 1) && (COLS > 70)) - { - move(line>1?line:1,4+((COLS-4)/2)); - } else - { - move(++line>1?line:1, 1); - LTEE - ltee = 1; - } - k++; - color(white); - if (m[i].u.i.pri) - SPRINT(buffer,"S%2d: ", j+1+(j>=15)); - else - SPRINT(buffer,"B%2d: ", j+1); - addstr(buffer); - switch(m[i].u.i.busy[j]) - { - case B_STATE_IDLE: - if ((!m[i].u.i.l2link && m[i].u.i.ptp) || m[i].u.i.block) - { - color(red); - addstr("blocked "); - } else - { - color(blue); - addstr("idle "); - } - break; - case B_STATE_ACTIVATING: - color(yellow); - addstr("act'ing "); - break; - case B_STATE_ACTIVE: - color(green); - addstr("busy "); - break; - case B_STATE_DEACTIVATING: - color(yellow); - addstr("dact'ing"); - break; - case B_STATE_EXPORTING: - color(yellow); - addstr("exp'ing "); - break; - case B_STATE_REMOTE: - color(green); - addstr("remote "); - break; - case B_STATE_IMPORTING: - color(yellow); - addstr("imp'ing "); - break; - } - if (m[i].u.i.port[j]) - { - /* search for port */ - l = msg.u.s.interfaces+msg.u.s.joins+msg.u.s.epoints; - ll = l+msg.u.s.ports; - while(l < ll) - { - if (m[l].u.p.serial == m[i].u.i.port[j]) - { - SPRINT(buffer, " %s(%ld)", m[l].u.p.name, m[l].u.p.serial); - addstr(buffer); - } - l++; - } - } - if (line+2 >= LINES) - { - if (ltee) - { - color(cyan); - move(line>1?line:1, 1); - LLCORNER - } - goto end; - } - } - j++; - } - if (ltee) - { - color(cyan); - move(line>1?line:1, 1); - LLCORNER - } - if (line+2 >= LINES) goto end; - /* show summary if no channels were shown */ - if (show_interfaces<2 && ltee==0) - { - color(cyan); - move(++line>1?line:1, 1); - LLCORNER - - if (m[i].u.i.l2link && m[i].u.i.block==0) - { - color(green); - SPRINT(buffer,"all %d channels free", m[i].u.i.channels); - } else - { - color(red); - SPRINT(buffer,"all %d channels blocked", m[i].u.i.channels); - } - addstr(buffer); - } - if (line+2 >= LINES) goto end; - } - } - i++; - anything = 1; - } - i = 0; - ii = i + msg.u.s.remotes; - while(i < ii) - { - /* show remote summary */ - move(++line>1?line:1, 0); - color(white); - SPRINT(buffer, "Remote: %s", m[i].u.r.name); - addstr(buffer); - i++; - } - if (anything) - line++; - if (line+2 >= LINES) goto end; - } - /* display calls (brief) */ - if (show_calls == 1) - { - anything = 0; - i = msg.u.s.interfaces+msg.u.s.joins; - ii = i+msg.u.s.epoints; - while(i < ii) - { - /* for each endpoint... */ - if (!m[i].u.e.join) - { - move(++line>1?line:1, 0); - color(white); - SPRINT(buffer, "(%d): ", m[i].u.e.serial); - addstr(buffer); - color(cyan); - if (m[i].u.e.terminal[0]) - { - addstr("intern="); - color(green); - addstr(m[i].u.e.terminal); - } else - addstr("extern"); - color(white); - SPRINT(buffer, " %s", m[i].u.e.callerid); - addstr(buffer); - color(cyan); - addstr("->"); - color(white); - SPRINT(buffer, "%s", m[i].u.e.dialing); - addstr(buffer); - if (m[i].u.e.action[0]) - { - color(cyan); - addstr(" action="); - color(yellow); - addstr(m[i].u.e.action); - } - if (line+2 >= LINES) goto end; - } - i++; - anything = 1; - } - j = msg.u.s.interfaces; - jj = j+msg.u.s.joins; - while(j < jj) - { - /* for each call... */ - move(++line>1?line:1, 0); - color(white); - SPRINT(buffer, "(%d):", m[j].u.j.serial); - addstr(buffer); - i = msg.u.s.interfaces+msg.u.s.joins; - ii = i+msg.u.s.epoints; - while(i < ii) - { - /* for each endpoint... */ - if (m[i].u.e.join == m[j].u.j.serial) - { - color(white); - SPRINT(buffer, " (%d)", m[i].u.e.serial); - addstr(buffer); - color(cyan); - if (m[i].u.e.terminal[0]) - { - addstr("int="); - color(green); - addstr(m[i].u.e.terminal); - } else - addstr("ext"); - color(white); - SPRINT(buffer, "-%s", m[i].u.e.callerid); - addstr(buffer); - color(cyan); - addstr(">"); - color(white); - SPRINT(buffer, "%s", m[i].u.e.dialing); - addstr(buffer); - } - i++; - anything = 1; - } - if (line+2 >= LINES) goto end; - j++; - } - if (anything) - line++; - if (line+2 >= LINES) goto end; - } - /* display calls (structurd) */ - if (show_calls == 2) - { - /* show all ports with no epoint */ - anything = 0; - i = msg.u.s.interfaces+msg.u.s.joins+msg.u.s.epoints; - ii = i+msg.u.s.ports; - while(i < ii) - { - if (!m[i].u.p.epoint) - { - move(++line>1?line:1, 8); - if (line+2 >= LINES) goto end; - line = debug_port(&msg, m, line, i, 0); - if (line+2 >= LINES) goto end; - anything = 1; - } - i++; - } - if (anything) - line++; - if (line+2 >= LINES) goto end; - - /* show all epoints with no call */ - anything = 0; - i = msg.u.s.interfaces+msg.u.s.joins; - ii = i+msg.u.s.epoints; - while(i < ii) - { - if (!m[i].u.e.join) - { - move(++line>1?line:1, 4); - if (line+2 >= LINES) goto end; - line = debug_epoint(&msg, m, line, i, 0); - if (line+2 >= LINES) goto end; - anything = 1; - } - i++; - } - if (anything) - line++; - if (line+2 >= LINES) goto end; - - /* show all joins */ - anything = 0; - i = msg.u.s.interfaces; - ii = i+msg.u.s.joins; - while(i < ii) - { - move(++line>1?line:1, 0); - if (line+2 >= LINES) goto end; - line = debug_join(&msg, m, line, i); - if (line+2 >= LINES) goto end; - i++; - anything = 1; - } - if (anything) - line++; - if (line+2 >= LINES) goto end; - - } - - /* show log */ - if (show_log) - { - if (line+2 < LINES) - { - move(line++>1?line-1:1, 0); - color(blue); - hline(ACS_HLINE, COLS); - color(white); - - l = logcur-(LINES-line-2); - ll = logcur; - if (ll-l >= LOGLINES) - l = ll-LOGLINES+1; - while(l!=ll) - { - move(line++>1?line-1:1, 0); - if ((int)strlen(logline[l % LOGLINES]) > hoffset) - SCPY(buffer, logline[l % LOGLINES] + hoffset); - else - buffer[0] = '\0'; - if (COLS < (int)strlen(buffer)) - { - buffer[COLS-1] = '\0'; - addstr(buffer); - color(mangenta); - addch('*'); - color(white); - } else - addstr(buffer); - l++; - } - } - } - - end: - /* free memory */ - FREE(m, 0); - /* display name/time */ -// move(0, 0); -// hline(' ', COLS); - move(0, 0); - color(cyan); - msg.u.s.version_string[sizeof(msg.u.s.version_string)-1] = '\0'; - SPRINT(buffer, "LCR %s", msg.u.s.version_string); - addstr(buffer); - if (COLS>50) - { - move(0, COLS-19); - SPRINT(buffer, "%04d-%02d-%02d %02d:%02d:%02d", - msg.u.s.tm.tm_year+1900, msg.u.s.tm.tm_mon+1, msg.u.s.tm.tm_mday, - msg.u.s.tm.tm_hour, msg.u.s.tm.tm_min, msg.u.s.tm.tm_sec); - addstr(buffer); - } - /* displeay head line */ - move(1, 0); - color(blue); - hline(ACS_HLINE, COLS); - if (offset) - { - move(1, 1); - SPRINT(buffer, "Offset +%d", offset); - color(red); - addstr(buffer); - } - if (hoffset) - { - move(1, 13); - SPRINT(buffer, "H-Offset +%d", hoffset); - color(red); - addstr(buffer); - } - /* display end */ - move(LINES-2, 0); - color(blue); - hline(ACS_HLINE, COLS); - move(LINES-1, 0); - if (enter) - { - color(white); - SPRINT(buffer, "-> %s", enter_string); - } else - { - color(cyan); - SPRINT(buffer, "i=interfaces '%s' c=calls '%s' l=log q=quit +-*/=scroll enter", text_interfaces[show_interfaces], text_calls[show_calls]); - } - addstr(buffer); - refresh(); - - /* resize */ - if (lastlines!=LINES || lastcols!=COLS) - { - cleanup_curses(); - init_curses(); - goto again; - } - - if (enter) - { - /* user input in enter mode */ - ch = getch(); - enter_again: - if (ch == 10) - { - FILE *fp; - - enter = 0; - if (!enter_string[0]) - goto again; - - SPRINT(logline[logcur++ % LOGLINES], "> %s", enter_string); - if (!!strncmp(enter_string, "interface", 10) && - !!strncmp(enter_string, "route", 6) && - !!strncmp(enter_string, "release ", 8) && - !!strncmp(enter_string, "block ", 6) && - !!strncmp(enter_string, "unblock ", 8) && - !!strncmp(enter_string, "unload ", 7)) - { - SPRINT(logline[logcur++ % LOGLINES], "usage:"); - SPRINT(logline[logcur++ % LOGLINES], "interface (reload interface.conf)"); - SPRINT(logline[logcur++ % LOGLINES], "route (reload routing.conf)"); - SPRINT(logline[logcur++ % LOGLINES], "release (release endpoint with given ID)"); - SPRINT(logline[logcur++ % LOGLINES], "block (block port for further calls)"); - SPRINT(logline[logcur++ % LOGLINES], "unblock (unblock port for further calls, load if not loaded)"); - SPRINT(logline[logcur++ % LOGLINES], "unload (unload mISDN stack, release call calls)"); - } else - { - /* applend output to log window */ - SPRINT(buffer, "%s %s", argv[0], enter_string); - fp = popen(buffer, "r"); - if (fp) - { - while(fgets(logline[logcur % LOGLINES], sizeof(logline[0]), fp)) - logline[logcur++ % LOGLINES][sizeof(logline[0])-1] = '\0'; - pclose(fp); - } else - { - SPRINT(logline[logcur++ % LOGLINES], "failed to execute '%s'", buffer); - } - } - logline[logcur % LOGLINES][0] = '\0'; - enter_string[0] = '\0'; - goto again; - } - if (ch>=32 && ch<=126) - { - SCCAT(enter_string, ch); - ch = getch(); - if (ch > 0) - goto enter_again; - goto again; - } else - if (ch==8 || ch==127) - { - if (enter_string[0]) - enter_string[strlen(enter_string)-1] = '\0'; - ch = getch(); - if (ch > 0) - goto enter_again; - goto again; - } else - if (ch != 3) - { - ch = getch(); - if (ch > 0) - goto enter_again; - FD_ZERO(&select_rfds); - FD_SET(0, &select_rfds); - select_tv.tv_sec = 0; - select_tv.tv_usec = 250000; - select(1, &select_rfds, NULL, NULL, &select_tv); - goto again; - } - } else - { - /* user input in normal mode */ - switch(getch()) - { - case 12: /* refresh */ - cleanup_curses(); - init_curses(); - goto again; - break; - - case 3: /* abort */ - case 'q': - case 'Q': - break; - - case 'i': /* toggle interface */ - show_interfaces++; - if (show_interfaces > 3) show_interfaces = 0; - goto again; - - case 'c': /* toggle calls */ - show_calls++; - if (show_calls > 2) show_calls = 0; - goto again; - - case 'l': /* toggle log */ - show_log++; - if (show_log > 1) show_log = 0; - goto again; - - case '+': /* scroll down */ - offset++; - goto again; - - case '-': /* scroll up */ - if (offset) - offset--; - goto again; - - case '*': /* scroll right */ - hoffset += 2; - goto again; - - case '/': /* scroll left */ - if (hoffset) - hoffset -= 2; - goto again; - - case 10: /* entermode */ - enter = 1; - goto again; - - default: - FD_ZERO(&select_rfds); - FD_SET(0, &select_rfds); - select_tv.tv_sec = 0; - select_tv.tv_usec = 250000; - select(1, &select_rfds, NULL, NULL, &select_tv); - goto again; - } - } - - /* check for logfh */ - if (logfh >= 0) - close(logfh); - logfh = -1; - - /* cleanup curses and exit */ - cleanup_curses(); - - return(NULL); -} - - -/* - * Send command and show error message. - */ -char *admin_cmd(int sock, int mode, char *extension, char *number) -{ - static struct admin_message msg; - - /* send reload command */ - memset(&msg, 0, sizeof(msg)); - switch(mode) - { - case MODE_INTERFACE: - msg.message = ADMIN_REQUEST_CMD_INTERFACE; - break; - case MODE_ROUTE: - msg.message = ADMIN_REQUEST_CMD_ROUTE; - break; - case MODE_DIAL: - msg.message = ADMIN_REQUEST_CMD_DIAL; - SPRINT(msg.u.x.message, "%s:%s", extension?:"", number?:""); - break; - case MODE_RELEASE: - msg.message = ADMIN_REQUEST_CMD_RELEASE; - SCPY(msg.u.x.message, number); - break; - case MODE_UNBLOCK: - msg.message = ADMIN_REQUEST_CMD_BLOCK; - msg.u.x.portnum = atoi(number); - msg.u.x.block = 0; - break; - case MODE_BLOCK: - msg.message = ADMIN_REQUEST_CMD_BLOCK; - msg.u.x.portnum = atoi(number); - msg.u.x.block = 1; - break; - case MODE_UNLOAD: - msg.message = ADMIN_REQUEST_CMD_BLOCK; - msg.u.x.portnum = atoi(number); - msg.u.x.block = 2; - break; - } - - if (write(sock, &msg, sizeof(msg)) != sizeof(msg)) - return("Broken pipe while sending command."); - - /* receive response */ - if (read(sock, &msg, sizeof(msg)) != sizeof(msg)) - return("Broken pipe while receiving response."); - switch(mode) - { - case MODE_INTERFACE: - if (msg.message != ADMIN_RESPONSE_CMD_INTERFACE) - return("Response not valid."); - break; - case MODE_ROUTE: - if (msg.message != ADMIN_RESPONSE_CMD_ROUTE) - return("Response not valid."); - break; - case MODE_DIAL: - if (msg.message != ADMIN_RESPONSE_CMD_DIAL) - return("Response not valid."); - break; - case MODE_RELEASE: - if (msg.message != ADMIN_RESPONSE_CMD_RELEASE) - return("Response not valid."); - break; - case MODE_UNBLOCK: - case MODE_BLOCK: - case MODE_UNLOAD: - if (msg.message != ADMIN_RESPONSE_CMD_BLOCK) - return("Response not valid."); - break; - } - - /* process response */ - if (msg.u.x.error) - { - return(msg.u.x.message); - } - printf("Command successfull.\n"); - return(NULL); -} - - -/* - * makes a testcall - */ -#define GET_NOW() { \ - gettimeofday(&now_tv, &now_tz); \ - now_d = ((double)(now_tv.tv_usec))/1000000 + now_tv.tv_sec; \ - } -char *admin_testcall(int sock, int argc, char *argv[]) -{ - static struct admin_message msg; - int ar = 2; - int stimeout = 0, ptimeout = 0, atimeout = 0, ctimeout = 0; - int l; - double timer = 0, now_d; - unsigned long on = 1; - struct timeval now_tv; - struct timezone now_tz; - - printf("pid=%d\n", getpid()); fflush(stdout); - - while (argc > ar) - { - if (!strcmp(argv[ar], "--setup-timeout")) - { - ar++; - if (argc == ar) - return("Missing setup timeout value.\n"); - stimeout = atoi(argv[ar]); - ar++; - } else - if (!strcmp(argv[ar], "--proceeding-timeout")) - { - ar++; - if (argc == ar) - return("Missing proceeding timeout value.\n"); - ptimeout = atoi(argv[ar]); - ar++; - } else - if (!strcmp(argv[ar], "--alerting-timeout")) - { - ar++; - if (argc == ar) - return("Missing alerting timeout value.\n"); - atimeout = atoi(argv[ar]); - ar++; - } else - if (!strcmp(argv[ar], "--connect-timeout")) - { - ar++; - if (argc == ar) - return("Missing connect timeout value.\n"); - ctimeout = atoi(argv[ar]); - ar++; - } else - { - break; - } - } - - /* send reload command */ - memset(&msg, 0, sizeof(msg)); - msg.message = ADMIN_CALL_SETUP; - msg.u.call.present = 1; - - if (argc > ar) - { - SCPY(msg.u.call.interface, argv[ar]); - } - ar++; - if (argc > ar) - { - SCPY(msg.u.call.callerid, argv[ar]); - } - ar++; - if (argc > ar) - { - SCPY(msg.u.call.dialing, argv[ar]); - } - ar++; - if (argc > ar) - { - if (argv[ar][0] == 'r') - msg.u.call.present = 0; - } - ar++; - msg.u.call.bc_capa = 0x00; /*INFO_BC_SPEECH*/ - msg.u.call.bc_mode = 0x00; /*INFO_BMODE_CIRCUIT*/ - msg.u.call.bc_info1 = 0; - msg.u.call.hlc = 0; - msg.u.call.exthlc = 0; - if (argc > ar) - msg.u.call.bc_capa = strtol(argv[ar],NULL,0); - else - msg.u.call.bc_info1 = 3 | 0x80; /* alaw, if no capability is given at all */ - ar++; - if (argc > ar) { - msg.u.call.bc_mode = strtol(argv[ar],NULL,0); - if (msg.u.call.bc_mode) msg.u.call.bc_mode = 2; - } - ar++; - if (argc > ar) { - msg.u.call.bc_info1 = strtol(argv[ar],NULL,0); - if (msg.u.call.bc_info1 < 0) - msg.u.call.bc_info1 = 0; - else - msg.u.call.bc_info1 |= 0x80; - } - ar++; - if (argc > ar) { - msg.u.call.hlc = strtol(argv[ar],NULL,0); - if (msg.u.call.hlc < 0) - msg.u.call.hlc = 0; - else - msg.u.call.hlc |= 0x80; - } - ar++; - if (argc > ar) { - msg.u.call.exthlc = strtol(argv[ar],NULL,0); - if (msg.u.call.exthlc < 0) - msg.u.call.exthlc = 0; - else - msg.u.call.exthlc |= 0x80; - } - ar++; - - if (write(sock, &msg, sizeof(msg)) != sizeof(msg)) - return("Broken pipe while sending command."); - - if (ioctl(sock, FIONBIO, (unsigned char *)(&on)) < 0) - return("Failed to set socket into non-blocking IO."); - - if (stimeout) - { - GET_NOW(); - timer = now_d + (double)stimeout; - } - - /* receive response */ -next: - l = read(sock, &msg, sizeof(msg)); - if (l < 0) - { - if (errno == EWOULDBLOCK) - { - if (timer) - { - GET_NOW(); - if (timer <= now_d) - { - printf("Timeout\n"); fflush(stdout); - return(NULL); - } - } - usleep(30000); - goto next; - } - return("Broken pipe while receiving response."); - } - if (l != sizeof(msg)) - return("Response has unexpected message size."); - switch(msg.message) - { - case ADMIN_CALL_SETUP_ACK: - printf("SETUP ACKNOWLEDGE\n"); fflush(stdout); - goto next; - - case ADMIN_CALL_PROCEEDING: - printf("PROCEEDING\n"); fflush(stdout); - if (ptimeout) - { - GET_NOW(); - timer = now_d + (double)ptimeout; - } - goto next; - - case ADMIN_CALL_ALERTING: - printf("ALERTING\n"); fflush(stdout); - if (atimeout) - { - GET_NOW(); - timer = now_d + (double)atimeout; - } - goto next; - - case ADMIN_CALL_CONNECT: - printf("CONNECT\n number=%s\n", msg.u.call.callerid); fflush(stdout); - if (ctimeout) - { - GET_NOW(); - timer = now_d + (double)ctimeout; - } - goto next; - - case ADMIN_CALL_NOTIFY: - printf("NOTIFY\n notify=%d\n number=%s\n", msg.u.call.notify, msg.u.call.callerid); fflush(stdout); - goto next; - - case ADMIN_CALL_DISCONNECT: - printf("DISCONNECT\n cause=%d %s\n location=%d %s\n", msg.u.call.cause, (msg.u.call.cause>0 && msg.u.call.cause<128)?isdn_cause[msg.u.call.cause].german:"", msg.u.call.location, (msg.u.call.location>=0 && msg.u.call.location<128)?isdn_location[msg.u.call.location].german:""); fflush(stdout); - break; - - case ADMIN_CALL_RELEASE: - printf("RELEASE\n cause=%d %s\n location=%d %s\n", msg.u.call.cause, (msg.u.call.cause>0 && msg.u.call.cause<128)?isdn_cause[msg.u.call.cause].german:"", msg.u.call.location, (msg.u.call.location>=0 && msg.u.call.location<128)?isdn_location[msg.u.call.location].german:""); fflush(stdout); - break; - - default: - return("Response not valid."); - } - - printf("Call released.\n"); fflush(stdout); - return(NULL); -} - - -/* - * makes a trace - */ -char *admin_trace(int sock, int argc, char *argv[]) -{ - static struct admin_message msg; - int i; - - /* show help */ - if (argc > 2) if (!strcasecmp(argv[2], "help")) - { - printf("Trace Help\n----------\n"); - printf("%s trace [brief|short] [= [...]]\n\n", argv[0]); - printf("By default a complete trace is shown in detailed format.\n"); - printf("To show a more compact format, use 'brief' or 'short' keyword.\n"); - printf("Use filter values to select specific trace messages.\n"); - printf("All given filter values must match. If no filter is given, anything matches.\n\n"); - printf("Filters:\n"); - printf(" category=\n"); - printf(" 0x01 = CH: channel object trace\n"); - printf(" 0x02 = EP: endpoint object trace\n"); - printf(" port= select only given port for trace\n"); - printf(" interface= select only given interface for trace\n"); - printf(" caller= select only given caller id for trace\n"); - printf(" dialing= select only given dialed number for trace\n"); - return(NULL); - } - - /* init trace request */ - memset(&msg, 0, sizeof(msg)); - msg.message = ADMIN_TRACE_REQUEST; - msg.u.trace_req.detail = 3; - - /* parse args */ - i = 2; - while(i < argc) - { - if (!strcasecmp(argv[i], "brief")) - msg.u.trace_req.detail = 1; - else if (!strcasecmp(argv[i], "short")) - msg.u.trace_req.detail = 2; - else if (!strncasecmp(argv[i], "category=", 9)) - msg.u.trace_req.category = atoi(argv[i]+9); - else if (!strncasecmp(argv[i], "port=", 5)) - msg.u.trace_req.port = atoi(argv[i]+5); - else if (!strncasecmp(argv[i], "interface=", 10)) - SCPY(msg.u.trace_req.interface, argv[i]+10); - else if (!strncasecmp(argv[i], "caller=", 7)) - SCPY(msg.u.trace_req.caller, argv[i]+7); - else if (!strncasecmp(argv[i], "dialing=", 8)) - SCPY(msg.u.trace_req.dialing, argv[i]+8); - else return("Invalid trace option, try 'trace help'."); - - i++; - } - - /* send trace request */ - if (write(sock, &msg, sizeof(msg)) != sizeof(msg)) - return("Broken pipe while sending trace request."); - - /* receive response */ -next: - if (read(sock, &msg, sizeof(msg)) != sizeof(msg)) - return("Broken pipe while receiving response."); - - if (msg.message != ADMIN_TRACE_RESPONSE) - return("Response not valid."); - - printf("%s", msg.u.trace_rsp.text); - goto next; -} - - -/* - * main function - */ -int main(int argc, char *argv[]) -{ - int mode; - char *socket_name = SOCKET_NAME; - int sock, conn; - struct sockaddr_un sock_address; - char *ret; - - - /* show options */ - if (argc <= 1) - { - usage: - printf("\n"); - printf("Usage: %s state | interface | route | dial ...\n", argv[0]); - printf("state - View current states using graphical console output.\n"); - printf("interface - Tell LCR to reload \"interface.conf\".\n"); - printf("route - Tell LCR to reload \"route.conf\".\n"); - printf("dial - Tell LCR the next number to dial for extension.\n"); - printf("release - Tell LCR to release endpoint with given number.\n"); - printf("block - Block given port.\n"); - printf("unblock - Unblock given port.\n"); - printf("unload - Unload port. To load port use 'block' or 'unblock'.\n"); - printf("testcall [options] [present|restrict []] - Testcall\n"); - printf(" -> options = --setup-timeout --proceeding-timeout \n"); - printf(" --alerting-timeout --connect-timeout \n"); - printf(" -> capability = (Values must be numbers, -1 to omit.)\n"); - printf("trace [brief|short] [ [...]] - Shows call trace. Use filter to reduce output.\n"); - printf(" -> Use 'trace help' to see filter description.\n"); - printf("\n"); - return(0); - } - - /* check mode */ - if (!(strcasecmp(argv[1],"state"))) - { - mode = MODE_STATE; - } else - if (!(strcasecmp(argv[1],"interface"))) - { - mode = MODE_INTERFACE; - } else - if (!(strcasecmp(argv[1],"route"))) - { - mode = MODE_ROUTE; - } else - if (!(strcasecmp(argv[1],"dial"))) - { - if (argc <= 3) - goto usage; - mode = MODE_DIAL; - } else - if (!(strcasecmp(argv[1],"release"))) - { - if (argc <= 2) - goto usage; - mode = MODE_RELEASE; - } else - if (!(strcasecmp(argv[1],"unblock"))) - { - if (argc <= 2) - goto usage; - mode = MODE_UNBLOCK; - } else - if (!(strcasecmp(argv[1],"block"))) - { - if (argc <= 2) - goto usage; - mode = MODE_BLOCK; - } else - if (!(strcasecmp(argv[1],"unload"))) - { - if (argc <= 2) - goto usage; - mode = MODE_UNLOAD; - } else - if (!(strcasecmp(argv[1],"testcall"))) - { - if (argc <= 4) - goto usage; - mode = MODE_TESTCALL; - } else - if (!(strcasecmp(argv[1],"trace"))) - { - mode = MODE_TRACE; - } else - { - goto usage; - } - -//pipeagain: - /* open socket */ - if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) - { - fprintf(stderr, "Failed to create socket.\n"); - exit(EXIT_FAILURE); - } - memset(&sock_address, 0, sizeof(sock_address)); - sock_address.sun_family = PF_UNIX; - UCPY(sock_address.sun_path, socket_name); - if ((conn = connect(sock, (struct sockaddr *)&sock_address, SUN_LEN(&sock_address))) < 0) - { - close(sock); - fprintf(stderr, "Failed to connect to socket \"%s\".\nIs LCR running?\n", sock_address.sun_path); - exit(EXIT_FAILURE); - } - - /* process mode */ - switch(mode) - { - case MODE_STATE: - ret = admin_state(sock, argv); - break; - - case MODE_INTERFACE: - case MODE_ROUTE: - ret = admin_cmd(sock, mode, NULL, NULL); - break; - - case MODE_DIAL: - ret = admin_cmd(sock, mode, argv[2], argv[3]); - break; - - case MODE_RELEASE: - case MODE_UNBLOCK: - case MODE_BLOCK: - case MODE_UNLOAD: - ret = admin_cmd(sock, mode, NULL, argv[2]); - break; - - case MODE_TESTCALL: - ret = admin_testcall(sock, argc, argv); - break; - - case MODE_TRACE: - ret = admin_trace(sock, argc, argv); - break; - } - - close(sock); - /* now we say good bye */ - if (ret) - { -// if (!strncasecmp(ret, "Broken Pipe", 11)) -// goto pipeagain; - printf("%s\n", ret); - exit(EXIT_FAILURE); - } -} - - - - - diff --git a/admin_server.c b/admin_server.c deleted file mode 100644 index 2624ad7..0000000 --- a/admin_server.c +++ /dev/null @@ -1,1323 +0,0 @@ -/*****************************************************************************\ -** ** -** Linux Call Router ** -** ** -**---------------------------------------------------------------------------** -** Copyright: Andreas Eversberg ** -** ** -** Socket link server ** -** ** -\*****************************************************************************/ - -#include -//#include -//#include -#include -//#include -//#include -//#include -//#include -//#include -#include -//#include -//#include -//#include -//#include -#include -#include -#include -#include "main.h" - - -char *socket_name = SOCKET_NAME; -int sock = -1; -struct sockaddr_un sock_address; - -struct admin_list *admin_first = NULL; - -/* - * initialize admin socket - */ -int admin_init(void) -{ - unsigned long on = 1; - - /* open and bind socket */ - if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) - { - PERROR("Failed to create admin socket. (errno=%d)\n", errno); - return(-1); - } - fhuse++; - memset(&sock_address, 0, sizeof(sock_address)); - sock_address.sun_family = AF_UNIX; - UCPY(sock_address.sun_path, socket_name); - unlink(socket_name); - if (bind(sock, (struct sockaddr *)(&sock_address), SUN_LEN(&sock_address)) < 0) - { - close(sock); - unlink(socket_name); - fhuse--; - sock = -1; - PERROR("Failed to bind admin socket to \"%s\". (errno=%d)\n", sock_address.sun_path, errno); - return(-1); - } - if (listen(sock, 5) < 0) - { - close(sock); - unlink(socket_name); - fhuse--; - sock = -1; - PERROR("Failed to listen to socket \"%s\". (errno=%d)\n", sock_address.sun_path, errno); - return(-1); - } - if (ioctl(sock, FIONBIO, (unsigned char *)(&on)) < 0) - { - close(sock); - unlink(socket_name); - fhuse--; - sock = -1; - PERROR("Failed to set socket \"%s\" into non-blocking mode. (errno=%d)\n", sock_address.sun_path, errno); - return(-1); - } - return(0); -} - - -/* - * free connection - * also releases all remote joins - */ -void free_connection(struct admin_list *admin) -{ - struct admin_queue *response; - void *temp; - union parameter param; - class Join *join, *joinnext; - - /* free remote joins */ - if (admin->remote_name[0]) - { - join = join_first; - while(join) - { - joinnext = join->next; - if (join->j_type==JOIN_TYPE_REMOTE) if (((class JoinRemote *)join)->j_remote_id == admin->sock) - { - memset(¶m, 0, sizeof(param)); - param.disconnectinfo.cause = CAUSE_OUTOFORDER; - param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL; - ((class JoinRemote *)join)->message_remote(MESSAGE_RELEASE, ¶m); - /* join is now destroyed, so we go to next join */ - } - join = joinnext; - } - } - - if (admin->sock >= 0) - { - close(admin->sock); - fhuse--; - } -// printf("new\n", response); - response = admin->response; - while (response) - { -//#warning -// printf("%x\n", response); - temp = response->next; - FREE(response, 0); - memuse--; - response = (struct admin_queue *)temp; - } -// printf("new2\n", response); - FREE(admin, 0); -// printf("new3\n", response); - memuse--; -} - - -/* - * cleanup admin socket - */ -void admin_cleanup(void) -{ - struct admin_list *admin, *next;; - - admin = admin_first; - while(admin) - { -//printf("clean\n"); - next = admin->next; - free_connection(admin); - admin = next; - } - - if (sock >= 0) - { - close(sock); - fhuse--; - } -} - - -/* - * do interface reload - */ -int admin_interface(struct admin_queue **responsep) -{ - struct admin_queue *response; /* response pointer */ - char *err_txt = ""; - int err = 0; - - if (read_interfaces()) - { - relink_interfaces(); - free_interfaces(interface_first); - interface_first = interface_newlist; - interface_newlist = NULL; - } else - { - err_txt = interface_error; - err = -1; - } - /* create state response */ - response = (struct admin_queue *)MALLOC(sizeof(struct admin_queue)+sizeof(admin_message)); - memuse++; - response->num = 1; - /* message */ - response->am[0].message = ADMIN_RESPONSE_CMD_INTERFACE; - /* error */ - response->am[0].u.x.error = err; - /* message */ - SCPY(response->am[0].u.x.message, err_txt); - /* attach to response chain */ - *responsep = response; - responsep = &response->next; - - return(0); -} - - -/* - * do route reload - */ -int admin_route(struct admin_queue **responsep) -{ - struct route_ruleset *ruleset_new; - struct admin_queue *response; /* response pointer */ - char err_txt[256] = ""; - int err = 0; -#if 0 - int n; -#endif - class EndpointAppPBX *apppbx; - -#if 0 - n = 0; - apppbx = apppbx_first; - while(apppbx) - { - n++; - apppbx = apppbx->next; - } - if (apppbx_first) - { - SPRINT(err_txt, "Cannot reload routing, because %d endpoints active\n", n); - err = -1; - goto response; - } -#endif - if (!(ruleset_new = ruleset_parse())) - { - SPRINT(err_txt, ruleset_error); - err = -1; - goto response; - } - ruleset_free(ruleset_first); - ruleset_first = ruleset_new; - ruleset_main = getrulesetbyname("main"); - if (!ruleset_main) - { - SPRINT(err_txt, "Ruleset reloaded, but rule 'main' not found.\n"); - err = -1; - } - apppbx = apppbx_first; - while(apppbx) - { - if (apppbx->e_action) - { - switch(apppbx->e_action->index) - { - case ACTION_INTERNAL: - apppbx->e_action = &action_internal; - break; - case ACTION_EXTERNAL: - apppbx->e_action = &action_external; - break; - case ACTION_REMOTE: - apppbx->e_action = &action_remote; - break; - case ACTION_VBOX_RECORD: - apppbx->e_action = &action_vbox; - break; - case ACTION_PARTYLINE: - apppbx->e_action = &action_partyline; - break; - default: - goto release; - } - } else if (apppbx->e_state != EPOINT_STATE_CONNECT) - { - release: - apppbx->e_callback = 0; - apppbx->e_action = NULL; - apppbx->release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); - start_trace(0, - NULL, - numberrize_callerinfo(apppbx->e_callerinfo.id, apppbx->e_callerinfo.ntype), - apppbx->e_dialinginfo.id, - DIRECTION_NONE, - CATEGORY_EP, - apppbx->ea_endpoint->ep_serial, - "KICK (reload routing)"); - end_trace(); - } - - apppbx->e_action_timeout = NULL; - apppbx->e_rule = NULL; - apppbx->e_ruleset = NULL; - - apppbx = apppbx->next; - } - - response: - /* create state response */ - response = (struct admin_queue *)MALLOC(sizeof(struct admin_queue)+sizeof(admin_message)); - memuse++; - response->num = 1; - /* message */ - response->am[0].message = ADMIN_RESPONSE_CMD_ROUTE; - /* error */ - response->am[0].u.x.error = err; - /* message */ - SCPY(response->am[0].u.x.message, err_txt); - /* attach to response chain */ - *responsep = response; - responsep = &response->next; - - return(0); -} - - -/* - * do dialing - */ -int admin_dial(struct admin_queue **responsep, char *message) -{ - struct extension ext; /* temporary extension's settings */ - struct admin_queue *response; /* response pointer */ - char *p; /* pointer to dialing digits */ - - /* create state response */ - response = (struct admin_queue *)MALLOC(sizeof(struct admin_queue)+sizeof(admin_message)); - memuse++; - response->num = 1; - /* message */ - response->am[0].message = ADMIN_RESPONSE_CMD_DIAL; - - /* process request */ - if (!(p = strchr(message,':'))) - { - response->am[0].u.x.error = -EINVAL; - SPRINT(response->am[0].u.x.message, "no seperator ':' in message to seperate number from extension"); - goto out; - } - *p++ = 0; - - /* modify extension */ - if (!read_extension(&ext, message)) - { - response->am[0].u.x.error = -EINVAL; - SPRINT(response->am[0].u.x.message, "extension doesn't exist"); - goto out; - } - SCPY(ext.next, p); - write_extension(&ext, message); - - out: - /* attach to response chain */ - *responsep = response; - responsep = &response->next; - return(0); -} - - -/* - * do tracing - */ -int admin_trace(struct admin_list *admin, struct admin_trace_req *trace) -{ - memcpy(&admin->trace, trace, sizeof(struct admin_trace_req)); - return(0); -} - - -/* - * do blocking - * - * 0 = make port available - * 1 = make port administratively blocked - * 2 = unload port - * the result is returned: - * 0 = port is now available - * 1 = port is now blocked - * 2 = port cannot be loaded or has been unloaded - * -1 = port doesn't exist - */ -int admin_block(struct admin_queue **responsep, int portnum, int block) -{ - struct admin_queue *response; /* response pointer */ - struct interface *interface; - struct interface_port *ifport; - - /* create block response */ - response = (struct admin_queue *)MALLOC(sizeof(struct admin_queue)+sizeof(admin_message)); - memuse++; - response->num = 1; - /* message */ - response->am[0].message = ADMIN_RESPONSE_CMD_BLOCK; - response->am[0].u.x.portnum = portnum; - - /* search for port */ - interface = interface_first; - while(interface) - { - ifport = interface->ifport; - while(ifport) - { - if (ifport->portnum == portnum) - break; - ifport = ifport->next; - } - if (ifport) - break; - interface = interface->next; - } - /* not found, we return -1 */ - if (!ifport) - { - response->am[0].u.x.block = -1; - response->am[0].u.x.error = 1; - SPRINT(response->am[0].u.x.message, "Port %d does not exist.", portnum); - goto out; - } - - /* no interface */ - if (!ifport->mISDNport) - { - /* not loaded anyway */ - if (block >= 2) - { - response->am[0].u.x.block = 2; - goto out; - } - - /* try loading interface */ - ifport->block = block; - load_port(ifport); - - /* port cannot load */ - if (ifport->block >= 2) - { - response->am[0].u.x.block = 2; - response->am[0].u.x.error = 1; - SPRINT(response->am[0].u.x.message, "Port %d will not load.", portnum); - goto out; - } - - /* port loaded */ - response->am[0].u.x.block = ifport->block; - goto out; - } - - /* if we shall unload interface */ - if (block >= 2) - { - mISDNport_close(ifport->mISDNport); - ifport->mISDNport = 0; - ifport->block = 2; - goto out; - } - - /* port new blocking state */ - ifport->block = response->am[0].u.x.block = block; - - out: - /* attach to response chain */ - *responsep = response; - responsep = &response->next; - return(0); -} - - -/* - * do release - */ -int admin_release(struct admin_queue **responsep, char *message) -{ - unsigned long id; - struct admin_queue *response; /* response pointer */ - class EndpointAppPBX *apppbx; - - /* create state response */ - response = (struct admin_queue *)MALLOC(sizeof(struct admin_queue)+sizeof(admin_message)); - memuse++; - response->num = 1; - /* message */ - response->am[0].message = ADMIN_RESPONSE_CMD_RELEASE; - - id = atoi(message); - apppbx = apppbx_first; - while(apppbx) - { - if (apppbx->ea_endpoint->ep_serial == id) - break; - apppbx = apppbx->next; - } - if (!apppbx) - { - response->am[0].u.x.error = -EINVAL; - SPRINT(response->am[0].u.x.message, "Given endpoint %d doesn't exist.", id); - goto out; - } - - apppbx->e_callback = 0; - apppbx->release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); - - out: - /* attach to response chain */ - *responsep = response; - responsep = &response->next; - return(0); -} - - -/* - * do call - */ -int admin_call(struct admin_list *admin, struct admin_message *msg) -{ - class Endpoint *epoint; - class EndpointAppPBX *apppbx; - - if (!(epoint = new Endpoint(0, 0))) - FATAL("No memory for Endpoint instance\n"); - if (!(epoint->ep_app = apppbx = new DEFAULT_ENDPOINT_APP(epoint, 1))) // outgoing - FATAL("No memory for Endpoint Application instance\n"); - apppbx->e_adminid = admin->sockserial; - admin->epointid = epoint->ep_serial; - SCPY(apppbx->e_callerinfo.id, nationalize_callerinfo(msg->u.call.callerid, &apppbx->e_callerinfo.ntype)); - if (msg->u.call.present) - apppbx->e_callerinfo.present = INFO_PRESENT_ALLOWED; - else - apppbx->e_callerinfo.present = INFO_PRESENT_RESTRICTED; - apppbx->e_callerinfo.screen = INFO_SCREEN_NETWORK; - -//printf("hh=%d\n", apppbx->e_capainfo.hlc); - - apppbx->e_capainfo.bearer_capa = msg->u.call.bc_capa; - apppbx->e_capainfo.bearer_mode = msg->u.call.bc_mode; - apppbx->e_capainfo.bearer_info1 = msg->u.call.bc_info1; - apppbx->e_capainfo.hlc = msg->u.call.hlc; - apppbx->e_capainfo.exthlc = msg->u.call.exthlc; - SCPY(apppbx->e_dialinginfo.id, msg->u.call.dialing); - SCPY(apppbx->e_dialinginfo.interfaces, msg->u.call.interface); - apppbx->e_dialinginfo.sending_complete = 1; - - apppbx->new_state(PORT_STATE_OUT_SETUP); - apppbx->out_setup(); - return(0); -} - - -/* - * this function is called for response whenever a call state changes. - */ -void admin_call_response(int adminid, int message, char *connected, int cause, int location, int notify) -{ - struct admin_list *admin; - struct admin_queue *response, **responsep; /* response pointer */ - - /* searching for admin id - * maybe there is no admin instance, because the calling port was not - * initiated by admin_call */ - admin = admin_first; - while(admin) - { - if (adminid == admin->sockserial) - break; - admin = admin->next; - } - if (!admin) - return; - - /* seek to end of response list */ - response = admin->response; - responsep = &admin->response; - while(response) - { - responsep = &response->next; - response = response->next; - } - - /* create state response */ - response = (struct admin_queue *)MALLOC(sizeof(struct admin_queue)+sizeof(admin_message)); - memuse++; - response->num = 1; - /* message */ - response->am[0].message = message; -// printf("MESSAGE: %d\n", message); - - SCPY(response->am[0].u.call.callerid, connected); - response->am[0].u.call.cause = cause; - response->am[0].u.call.location = location; - response->am[0].u.call.notify = notify; - - /* attach to response chain */ - *responsep = response; - responsep = &response->next; -} - - -/* - * send data to the remote socket join instance - */ -int admin_message_to_join(struct admin_msg *msg, char *remote_name, int sock_id) -{ - class Join *join; - struct admin_list *admin; - - /* hello message */ - if (msg->type == MESSAGE_HELLO) - { - if (remote_name[0]) - { - PERROR("Remote application repeats hello message.\n"); - return(-1); - } - /* look for second application */ - admin = admin_first; - while(admin) - { - if (!strcmp(admin->remote_name, msg->param.hello.application)) - break; - admin = admin->next; - } - if (admin) - { - PERROR("Remote application connects twice??? (ignoring)\n"); - return(-1); - } - /* set remote socket instance */ - SCPY(remote_name, msg->param.hello.application); - return(0); - } - - /* check we have no application name */ - if (remote_name[0]) - { - PERROR("Remote application did not send us a hello message.\n"); - return(-1); - } - - /* new join */ - if (msg->type == MESSAGE_NEWREF) - { - /* create new join instance */ - join = new JoinRemote(0, remote_name, sock_id); // must have no serial, because no endpoint is connected - if (!join) - FATAL("No memory for remote join instance\n"); - return(0); - } - - /* bchannel message - * no ref given for *_ack */ - if (msg->type == MESSAGE_BCHANNEL) - if (msg->param.bchannel.type == BCHANNEL_ASSIGN_ACK - || msg->param.bchannel.type == BCHANNEL_REMOVE_ACK) - { - /* no ref, but address */ - message_bchannel_from_join(NULL, msg->param.bchannel.type, msg->param.bchannel.handle); - return(0); - } - - /* check for ref */ - if (!msg->ref) - { - PERROR("Remote application did not send us a valid ref with a message.\n"); - return(-1); - } - - /* find join instance */ - join = join_first; - while(join) - { - if (join->j_serial == msg->ref) - break; - join = join->next; - } - if (!join) - { - PERROR("No join found with serial %d.\n", msg->ref); - return(-1); - } - - /* check application */ - if (join->j_type != JOIN_TYPE_REMOTE) - { - PERROR("Ref %d does not belong to a remote join instance.\n", msg->ref); - return(-1); - } - if (sock_id != ((class JoinRemote *)join)->j_remote_id) - { - PERROR("Ref %d belongs to remote application %s, but not to sending application %s.\n", msg->ref, ((class JoinRemote *)join)->j_remote_name, remote_name); - return(-1); - } - - /* send message */ - ((class JoinRemote *)join)->message_remote(msg->type, &msg->param); - - return(0); -} - - -/* - * this function is called for every message to remote socket - */ -int admin_message_from_join(int remote_id, unsigned long ref, int message_type, union parameter *param) -{ - struct admin_list *admin; - struct admin_queue *response, **responsep; /* response pointer */ - - /* searching for admin id - * maybe there is no given remote application - */ - admin = admin_first; - while(admin) - { - if (admin->remote_name[0] && admin->sock==remote_id) - break; - admin = admin->next; - } - /* no given remote application connected */ - if (!admin) - return(-1); - - /* seek to end of response list */ - response = admin->response; - responsep = &admin->response; - while(response) - { - responsep = &response->next; - response = response->next; - } - - /* create state response */ - response = (struct admin_queue *)MALLOC(sizeof(struct admin_queue)+sizeof(admin_message)); - memuse++; - response->num = 1; - - /* message */ - response->am[0].u.msg.type = message_type; - response->am[0].u.msg.ref = ref; - memcpy(&response->am[0].u.msg.param, param, sizeof(union parameter)); - - /* attach to response chain */ - *responsep = response; - responsep = &response->next; - - return(0); -} - - -/* - * do state debugging - */ -int admin_state(struct admin_queue **responsep) -{ - - class Port *port; - class EndpointAppPBX *apppbx; - class Join *join; - class Pdss1 *pdss1; - struct interface *interface; - struct interface_port *ifport; - struct mISDNport *mISDNport; - int i; - int num; - int anybusy; - struct admin_queue *response; - struct admin_list *admin; - - /* create state response */ - response = (struct admin_queue *)MALLOC(sizeof(struct admin_queue)+sizeof(admin_message)); - memuse++; - response->num = 1; - /* message */ - response->am[0].message = ADMIN_RESPONSE_STATE; - /* version */ - SCPY(response->am[0].u.s.version_string, VERSION_STRING); - /* time */ - memcpy(&response->am[0].u.s.tm, now_tm, sizeof(struct tm)); - /* log file */ - SCPY(response->am[0].u.s.logfile, options.log); - /* interface count */ - i = 0; - interface = interface_first; - while(interface) - { - ifport = interface->ifport; - while(ifport) - { - i++; - ifport = ifport->next; - } - interface = interface->next; - } - response->am[0].u.s.interfaces = i; - /* remote connection count */ - i = 0; - admin = admin_first; - while(admin) - { - if (admin->remote_name[0]) - i++; - admin = admin->next; - } - response->am[0].u.s.remotes = i; - /* join count */ - join = join_first; - i = 0; - while(join) - { - i++; - join = join->next; - } - response->am[0].u.s.joins = i; - /* apppbx count */ - apppbx = apppbx_first; - i = 0; - while(apppbx) - { - i++; - apppbx = apppbx->next; - } - response->am[0].u.s.epoints = i; - /* port count */ - i = 0; - port = port_first; - while(port) - { - i++; - port = port->next; - } - response->am[0].u.s.ports = i; - /* attach to response chain */ - *responsep = response; - responsep = &response->next; - - /* create response for all interfaces */ - num = (response->am[0].u.s.interfaces)+(response->am[0].u.s.joins)+(response->am[0].u.s.epoints)+(response->am[0].u.s.ports); - if (num == 0) - return(0); - response = (struct admin_queue *)MALLOC(sizeof(admin_queue)+(num*sizeof(admin_message))); - memuse++; - response->num = num; - *responsep = response; - responsep = &response->next; - interface = interface_first; - num = 0; - while(interface) - { - ifport = interface->ifport; - while(ifport) - { - /* message */ - response->am[num].message = ADMIN_RESPONSE_S_INTERFACE; - /* interface */ - SCPY(response->am[num].u.i.interface_name, interface->name); - /* portnum */ - response->am[num].u.i.portnum = ifport->portnum; - /* iftype */ - response->am[num].u.i.extension = interface->extension; - /* block */ - response->am[num].u.i.block = ifport->block; - if (ifport->mISDNport) - { - mISDNport = ifport->mISDNport; - - /* ptp */ - response->am[num].u.i.ptp = mISDNport->ptp; - /* ntmode */ - response->am[num].u.i.ntmode = mISDNport->ntmode; - /* pri */ - response->am[num].u.i.pri = mISDNport->pri; - /* use */ - response->am[num].u.i.use = mISDNport->use; - /* l1link */ - response->am[num].u.i.l1link = mISDNport->l1link; - /* l2link */ - response->am[num].u.i.l2link = mISDNport->l2link; - /* channels */ - response->am[num].u.i.channels = mISDNport->b_num; - /* channel info */ - i = 0; - anybusy = 0; - while(i < mISDNport->b_num) - { - response->am[num].u.i.busy[i] = mISDNport->b_state[i]; - if (mISDNport->b_port[i]) - response->am[num].u.i.port[i] = mISDNport->b_port[i]->p_serial; - i++; - } - } - num++; - - ifport = ifport->next; - } - interface = interface->next; - } - - /* create response for all remotes */ - admin = admin_first; - while(admin) - { - if (admin->remote_name[0]) - { - /* message */ - response->am[num].message = ADMIN_RESPONSE_S_REMOTE; - /* name */ - SCPY(response->am[num].u.r.name, admin->remote_name); - /* */ - num++; - } - admin = admin->next; - } - - /* create response for all joins */ - join = join_first; - while(join) - { - /* message */ - response->am[num].message = ADMIN_RESPONSE_S_JOIN; - /* serial */ - response->am[num].u.j.serial = join->j_serial; - /* partyline */ - if (join->j_type == JOIN_TYPE_PBX) - response->am[num].u.j.partyline = ((class JoinPBX *)join)->j_partyline; - /* remote application */ - if (join->j_type == JOIN_TYPE_REMOTE) - SCPY(response->am[num].u.j.remote, ((class JoinRemote *)join)->j_remote_name); - /* */ - join = join->next; - num++; - } - - /* create response for all endpoint */ - apppbx = apppbx_first; - while(apppbx) - { - /* message */ - response->am[num].message = ADMIN_RESPONSE_S_EPOINT; - /* serial */ - response->am[num].u.e.serial = apppbx->ea_endpoint->ep_serial; - /* join */ - response->am[num].u.e.join = apppbx->ea_endpoint->ep_join_id; - /* rx notification */ - response->am[num].u.e.rx_state = apppbx->e_rx_state; - /* tx notification */ - response->am[num].u.e.tx_state = apppbx->e_tx_state; - /* state */ - switch(apppbx->e_state) - { - case EPOINT_STATE_IN_SETUP: - response->am[num].u.e.state = ADMIN_STATE_IN_SETUP; - break; - case EPOINT_STATE_OUT_SETUP: - response->am[num].u.e.state = ADMIN_STATE_OUT_SETUP; - break; - case EPOINT_STATE_IN_OVERLAP: - response->am[num].u.e.state = ADMIN_STATE_IN_OVERLAP; - break; - case EPOINT_STATE_OUT_OVERLAP: - response->am[num].u.e.state = ADMIN_STATE_OUT_OVERLAP; - break; - case EPOINT_STATE_IN_PROCEEDING: - response->am[num].u.e.state = ADMIN_STATE_IN_PROCEEDING; - break; - case EPOINT_STATE_OUT_PROCEEDING: - response->am[num].u.e.state = ADMIN_STATE_OUT_PROCEEDING; - break; - case EPOINT_STATE_IN_ALERTING: - response->am[num].u.e.state = ADMIN_STATE_IN_ALERTING; - break; - case EPOINT_STATE_OUT_ALERTING: - response->am[num].u.e.state = ADMIN_STATE_OUT_ALERTING; - break; - case EPOINT_STATE_CONNECT: - response->am[num].u.e.state = ADMIN_STATE_CONNECT; - break; - case EPOINT_STATE_IN_DISCONNECT: - response->am[num].u.e.state = ADMIN_STATE_IN_DISCONNECT; - break; - case EPOINT_STATE_OUT_DISCONNECT: - response->am[num].u.e.state = ADMIN_STATE_OUT_DISCONNECT; - break; - default: - response->am[num].u.e.state = ADMIN_STATE_IDLE; - } - /* terminal */ - SCPY(response->am[num].u.e.terminal, apppbx->e_ext.number); - /* callerid */ - SCPY(response->am[num].u.e.callerid, apppbx->e_callerinfo.id); - /* dialing */ - SCPY(response->am[num].u.e.dialing, apppbx->e_dialinginfo.id); - /* action string */ - if (apppbx->e_action) - SCPY(response->am[num].u.e.action, action_defs[apppbx->e_action->index].name); -// if (apppbx->e_action) -// printf("action=%s\n",action_defs[apppbx->e_action->index].name); - /* park */ - response->am[num].u.e.park = apppbx->ea_endpoint->ep_park; - if (apppbx->ea_endpoint->ep_park && apppbx->ea_endpoint->ep_park_len && apppbx->ea_endpoint->ep_park_len<=(int)sizeof(response->am[num].u.e.park_callid)) - memcpy(response->am[num].u.e.park_callid, apppbx->ea_endpoint->ep_park_callid, apppbx->ea_endpoint->ep_park_len); - response->am[num].u.e.park_len = apppbx->ea_endpoint->ep_park_len; - /* crypt */ - if (apppbx->e_crypt == CRYPT_ON) - response->am[num].u.e.crypt = 1; - /* */ - apppbx = apppbx->next; - num++; - } - - /* create response for all ports */ - port = port_first; - while(port) - { - /* message */ - response->am[num].message = ADMIN_RESPONSE_S_PORT; - /* serial */ - response->am[num].u.p.serial = port->p_serial; - /* name */ - SCPY(response->am[num].u.p.name, port->p_name); - /* epoint */ - response->am[num].u.p.epoint = ACTIVE_EPOINT(port->p_epointlist); - /* state */ - switch(port->p_state) - { - case PORT_STATE_IN_SETUP: - response->am[num].u.p.state = ADMIN_STATE_IN_SETUP; - break; - case PORT_STATE_OUT_SETUP: - response->am[num].u.p.state = ADMIN_STATE_OUT_SETUP; - break; - case PORT_STATE_IN_OVERLAP: - response->am[num].u.p.state = ADMIN_STATE_IN_OVERLAP; - break; - case PORT_STATE_OUT_OVERLAP: - response->am[num].u.p.state = ADMIN_STATE_OUT_OVERLAP; - break; - case PORT_STATE_IN_PROCEEDING: - response->am[num].u.p.state = ADMIN_STATE_IN_PROCEEDING; - break; - case PORT_STATE_OUT_PROCEEDING: - response->am[num].u.p.state = ADMIN_STATE_OUT_PROCEEDING; - break; - case PORT_STATE_IN_ALERTING: - response->am[num].u.p.state = ADMIN_STATE_IN_ALERTING; - break; - case PORT_STATE_OUT_ALERTING: - response->am[num].u.p.state = ADMIN_STATE_OUT_ALERTING; - break; - case PORT_STATE_CONNECT: - response->am[num].u.p.state = ADMIN_STATE_CONNECT; - break; - case PORT_STATE_IN_DISCONNECT: - response->am[num].u.p.state = ADMIN_STATE_IN_DISCONNECT; - break; - case PORT_STATE_OUT_DISCONNECT: - response->am[num].u.p.state = ADMIN_STATE_OUT_DISCONNECT; - break; - default: - response->am[num].u.p.state = ADMIN_STATE_IDLE; - } - /* isdn */ - if ((port->p_type&PORT_CLASS_mISDN_MASK) == PORT_CLASS_mISDN_DSS1) - { - response->am[num].u.p.isdn = 1; - pdss1 = (class Pdss1 *)port; - response->am[num].u.p.isdn_chan = pdss1->p_m_b_channel; - response->am[num].u.p.isdn_hold = pdss1->p_m_hold; - response->am[num].u.p.isdn_ces = pdss1->p_m_d_ces; - } - /* */ - port = port->next; - num++; - } - return(0); -} - -int sockserial = 1; // must start with 1, because 0 is used if no serial is set -/* - * handle admin socket (non blocking) - */ -int admin_handle(void) -{ - struct admin_list *admin, **adminp; - void *temp; - struct admin_message msg; - int len; - int new_sock; - socklen_t sock_len = sizeof(sock_address); - unsigned long on = 1; - int work = 0; /* if work was done */ - struct Endpoint *epoint; - - if (sock < 0) - return(0); - - /* check for new incoming connections */ - if ((new_sock = accept(sock, (struct sockaddr *)&sock_address, &sock_len)) >= 0) - { - work = 1; - /* insert new socket */ - admin = (struct admin_list *)MALLOC(sizeof(struct admin_list)); - if (ioctl(new_sock, FIONBIO, (unsigned char *)(&on)) >= 0) - { -//#warning -// PERROR("DEBUG incoming socket %d, serial=%d\n", new_sock, sockserial); - memuse++; - fhuse++; - admin->sockserial = sockserial++; - admin->next = admin_first; - admin_first = admin; - admin->sock = new_sock; - } else { - close(new_sock); - FREE(admin, sizeof(struct admin_list)); - } - } else - { - if (errno != EWOULDBLOCK) - { - PERROR("Failed to accept connection from socket \"%s\". (errno=%d) Closing socket.\n", sock_address.sun_path, errno); - admin_cleanup(); - return(1); - } - } - - /* loop all current socket connections */ - admin = admin_first; - adminp = &admin_first; - while(admin) - { - /* read command */ - len = read(admin->sock, &msg, sizeof(msg)); - if (len < 0) - { - if (errno != EWOULDBLOCK) - { - work = 1; - brokenpipe: - printf("Broken pipe on socket %d. (errno=%d).\n", admin->sock, errno); - PDEBUG(DEBUG_LOG, "Broken pipe on socket %d. (errno=%d).\n", admin->sock, errno); - *adminp = admin->next; - free_connection(admin); - admin = *adminp; - continue; - } - goto send_data; - } - work = 1; -//#warning -//PERROR("DEBUG socket %d got data. serial=%d\n", admin->sock, admin->sockserial); - if (len == 0) - { - end: - - /*release endpoint if exists */ - if (admin->epointid) - { - epoint = find_epoint_id(admin->epointid); - if (epoint) - { - ((class DEFAULT_ENDPOINT_APP *)epoint->ep_app)-> - release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); - } - } - -//#warning -//PERROR("DEBUG socket %d closed by remote.\n", admin->sock); - *adminp = admin->next; - free_connection(admin); - admin = *adminp; -//PERROR("DEBUG (admin_first=%x)\n", admin_first); - continue; - } - if (len != sizeof(msg)) - { - PERROR("Short/long read on socket %d. (len=%d != size=%d).\n", admin->sock, len, sizeof(msg)); - *adminp = admin->next; - free_connection(admin); - admin = *adminp; - continue; - } - /* process socket command */ - if (admin->response) - { - PERROR("Data from socket %d while sending response.\n", admin->sock); - *adminp = admin->next; - free_connection(admin); - admin = *adminp; - continue; - } - switch (msg.message) - { - case ADMIN_REQUEST_CMD_INTERFACE: - if (admin_interface(&admin->response) < 0) - { - PERROR("Failed to create dial response for socket %d.\n", admin->sock); - goto response_error; - } - break; - - case ADMIN_REQUEST_CMD_ROUTE: - if (admin_route(&admin->response) < 0) - { - PERROR("Failed to create dial response for socket %d.\n", admin->sock); - goto response_error; - } - break; - - case ADMIN_REQUEST_CMD_DIAL: - if (admin_dial(&admin->response, msg.u.x.message) < 0) - { - PERROR("Failed to create dial response for socket %d.\n", admin->sock); - goto response_error; - } - break; - - case ADMIN_REQUEST_CMD_RELEASE: - if (admin_release(&admin->response, msg.u.x.message) < 0) - { - PERROR("Failed to create release response for socket %d.\n", admin->sock); - goto response_error; - } - break; - - case ADMIN_REQUEST_STATE: - if (admin_state(&admin->response) < 0) - { - PERROR("Failed to create state response for socket %d.\n", admin->sock); - goto response_error; - } - break; - - case ADMIN_TRACE_REQUEST: - if (admin_trace(admin, &msg.u.trace_req) < 0) - { - PERROR("Failed to create trace response for socket %d.\n", admin->sock); - goto response_error; - } - break; - - case ADMIN_REQUEST_CMD_BLOCK: - if (admin_block(&admin->response, msg.u.x.portnum, msg.u.x.block) < 0) - { - PERROR("Failed to create block response for socket %d.\n", admin->sock); - goto response_error; - } - break; - - case ADMIN_MESSAGE: - if (admin_message_to_join(&msg.u.msg, admin->remote_name, admin->sock) < 0) - { - PERROR("Failed to deliver message for socket %d.\n", admin->sock); - goto response_error; - } -#if 0 -#warning DEBUGGING -{ - struct admin_queue *response; - printf("Chain: "); - response = admin->response; - while(response) - { - printf("%c", '0'+response->am[0].message); - response=response->next; - } - printf("\n"); -} -#endif - break; - - case ADMIN_CALL_SETUP: - if (admin_call(admin, &msg) < 0) - { - PERROR("Failed to create call for socket %d.\n", admin->sock); - response_error: - *adminp = admin->next; - free_connection(admin); - admin = *adminp; - continue; - } - break; - - default: - PERROR("Invalid message %d from socket %d.\n", msg.message, admin->sock); - *adminp = admin->next; - free_connection(admin); - admin = *adminp; - continue; - } - /* write queue */ - send_data: - if (admin->response) - { -//#warning -//PERROR("DEBUG socket %d sending data.\n", admin->sock); - len = write(admin->sock, ((unsigned char *)(admin->response->am))+admin->response->offset, sizeof(struct admin_message)*(admin->response->num)-admin->response->offset); - if (len < 0) - { - if (errno != EWOULDBLOCK) - { - work = 1; - goto brokenpipe; - } - goto next; - } - work = 1; - if (len == 0) - goto end; - if (len < (int)(sizeof(struct admin_message)*(admin->response->num)-admin->response->offset)) - { - admin->response->offset+=len; - goto next; - } else - { - temp = admin->response; - admin->response = admin->response->next; - FREE(temp, 0); - memuse--; - } - } - /* done with socket instance */ - next: - adminp = &admin->next; - admin = admin->next; - } - - return(work); -} - diff --git a/admin_server.h b/admin_server.h deleted file mode 100644 index 9d1c8a2..0000000 --- a/admin_server.h +++ /dev/null @@ -1,40 +0,0 @@ -/*****************************************************************************\ -** ** -** PBX4Linux ** -** ** -**---------------------------------------------------------------------------** -** Copyright: Andreas Eversberg ** -** ** -** Administration tool header file (server) ** -** ** -\*****************************************************************************/ - -#include "admin.h" - -struct admin_queue { - struct admin_queue *next; - ulong offset; /* current offset writing */ - ulong num; /* number of admin messages */ - struct admin_message am[0]; -}; - -struct admin_list { - struct admin_list *next; - int sock; - int sockserial; - char remote_name[32]; /* socket is connected remote application */ - struct admin_trace_req trace; /* stores trace, if detail != 0 */ - unsigned long epointid; - struct admin_queue *response; -}; - -extern struct admin_list *admin_first; -int admin_init(void); -void admin_cleanup(void); -int admin_handle(void); -void admin_call_response(int adminid, int message, char *connected, int cause, int location, int notify); -int admin_message_to_join(struct admin_message *msg, int remote_id); -int admin_message_from_join(int remote_id, unsigned long ref, int message_type, union parameter *param); - - - diff --git a/apppbx.cpp b/apppbx.cpp index c2619e9..66aba31 100644 --- a/apppbx.cpp +++ b/apppbx.cpp @@ -1001,7 +1001,7 @@ void EndpointAppPBX::out_setup(void) goto check_anycall_intern; } /* directory.list */ - if (e_callerinfo.id[0] && (e_ext.centrex || e_ext.display_name)) + if (e_callerinfo.id[0] && e_ext.display_name) { dirname = parse_directory(e_callerinfo.id, e_callerinfo.ntype); if (dirname) @@ -1025,8 +1025,8 @@ void EndpointAppPBX::out_setup(void) SCPY(message->param.setup.callerinfo.display, apply_callerid_display(message->param.setup.callerinfo.id, message->param.setup.callerinfo.itype, message->param.setup.callerinfo.ntype, message->param.setup.callerinfo.present, message->param.setup.callerinfo.screen, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name)); //printf("\n\ndisplay = %s\n\n\n",message->param.setup.callerinfo.display); /* use cnip, if enabld */ - if (!e_ext.centrex) - message->param.setup.callerinfo.name[0] = '\0'; + // if (!e_ext.centrex) + // message->param.setup.callerinfo.name[0] = '\0'; /* screen clip if prefix is required */ if (message->param.setup.callerinfo.id[0] && e_ext.clip_prefix[0]) { @@ -2986,8 +2986,8 @@ void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type, SCPY(message->param.connectinfo.display, apply_callerid_display(message->param.connectinfo.id, message->param.connectinfo.itype, message->param.connectinfo.ntype, message->param.connectinfo.present, message->param.connectinfo.screen, message->param.connectinfo.extension, message->param.connectinfo.name)); /* use conp, if enabld */ - if (!e_ext.centrex) - message->param.connectinfo.name[0] = '\0'; +// if (!e_ext.centrex) +// message->param.connectinfo.name[0] = '\0'; /* send connect */ message_put(message); diff --git a/bchannel.c b/bchannel.c index ea8e8e1..a66a62a 100644 --- a/bchannel.c +++ b/bchannel.c @@ -424,6 +424,8 @@ static void bchannel_activated(struct bchannel *channel) ph_control(handle, DTMF_TONE_START, 0, "DSP-DTMF", 1); if (channel->b_crypt_len) ph_control_block(handle, BF_ENABLE_KEY, channel->b_crypt_key, channel->b_crypt_len, "DSP-CRYPT", channel->b_crypt_len); + if (channel->b_conf) + ph_control(handle, CMX_CONF_JOIN, channel->b_conf, "DSP-CONF", channel->b_conf); channel->b_state = BSTATE_ACTIVE; } diff --git a/chan_lcr.c b/chan_lcr.c index 9216699..3f6c29d 100644 --- a/chan_lcr.c +++ b/chan_lcr.c @@ -42,7 +42,7 @@ with that reference. #include #include "extension.h" #include "message.h" -#include "admin.h" +#include "lcrsocket.h" #include "cause.h" #include "bchannel.h" #include "chan_lcr.h" @@ -112,6 +112,28 @@ void free_call(struct chan_call *call) } } +unsigned short new_brige_id(void) +{ + struct chan_call *call; + unsigned short id = 1; + + /* search for lowest bridge id that is not in use and not 0 */ + while(id) + { + call = call_first; + while(call) + { + if (call->bridge_id == id) + break; + call = call->next; + } + if (!call) + break; + id++; + } + return(id); +} + /* * receive bchannel data @@ -195,6 +217,8 @@ int receive_message(int message_type, unsigned long ref, union parameter *param) { bchannel->ref = ref; call->bchannel_handle = param->bchannel.handle; +#warning hier muesen alle stati gesetzt werden falls sie vor dem b-kanal verfügbar waren + bchannel_join(call->bridge_id); } if (bchannel_create(bchannel)) bchannel_activate(bchannel, 1); @@ -495,6 +519,146 @@ void lcr_thread(void) } } +/* call from asterisk (new instance) */ +static int lcr_call(struct ast_channel *ast, char *dest, int timeout) +{ + int port=0; + int r; + struct chan_list *ch=MISDN_ASTERISK_TECH_PVT(ast); + struct misdn_bchannel *newbc; + char *opts=NULL, *ext; + char dest_cp[256]; + + { + strncpy(dest_cp,dest,sizeof(dest_cp)-1); + dest_cp[sizeof(dest_cp)]=0; + + ext=dest_cp; + strsep(&ext,"/"); + if (ext) { + opts=ext; + strsep(&opts,"/"); + } else { + ast_log(LOG_WARNING, "Malformed dialstring\n"); + return -1; + } + } + + if (!ast) { + ast_log(LOG_WARNING, " --> ! misdn_call called on ast_channel *ast where ast == NULL\n"); + return -1; + } + + if (((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) || !dest ) { + ast_log(LOG_WARNING, " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL)\n", ast->name); + ast->hangupcause=41; + ast_setstate(ast, AST_STATE_DOWN); + return -1; + } + + if (!ch) { + ast_log(LOG_WARNING, " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL)\n", ast->name); + ast->hangupcause=41; + ast_setstate(ast, AST_STATE_DOWN); + return -1; + } + + newbc=ch->bc; + + if (!newbc) { + ast_log(LOG_WARNING, " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL)\n", ast->name); + ast->hangupcause=41; + ast_setstate(ast, AST_STATE_DOWN); + return -1; + } + + port=newbc->port; + + + chan_misdn_log(1, port, "* CALL: %s\n",dest); + + chan_misdn_log(2, port, " --> * dad:%s tech:%s ctx:%s\n",ast->exten,ast->name, ast->context); + + chan_misdn_log(3, port, " --> * adding2newbc ext %s\n",ast->exten); + if (ast->exten) { + int l = sizeof(newbc->dad); + strncpy(ast->exten,ext,sizeof(ast->exten)); + + strncpy(newbc->dad,ext,l); + + newbc->dad[l-1] = 0; + } + newbc->rad[0]=0; + chan_misdn_log(3, port, " --> * adding2newbc callerid %s\n",AST_CID_P(ast)); + if (ast_strlen_zero(newbc->oad) && AST_CID_P(ast) ) { + + if (AST_CID_P(ast)) { + int l = sizeof(newbc->oad); + strncpy(newbc->oad,AST_CID_P(ast), l); + newbc->oad[l-1] = 0; + } + } + + { + struct chan_list *ch=MISDN_ASTERISK_TECH_PVT(ast); + if (!ch) { ast_verbose("No chan_list in misdn_call\n"); return -1;} + + newbc->capability=ast->transfercapability; + pbx_builtin_setvar_helper(ast,"TRANSFERCAPABILITY",ast_transfercapability2str(newbc->capability)); + if ( ast->transfercapability == INFO_CAPABILITY_DIGITAL_UNRESTRICTED) { + chan_misdn_log(2, port, " --> * Call with flag Digital\n"); + } + + + /* update screening and presentation */ + update_config(ch,ORG_AST); + + /* fill in some ies from channel vary*/ + import_ch(ast, newbc, ch); + + /* Finally The Options Override Everything */ + if (opts) + misdn_set_opt_exec(ast,opts); + else + chan_misdn_log(2,port,"NO OPTS GIVEN\n"); + + /*check for bridging*/ + int bridging; + misdn_cfg_get( 0, MISDN_GEN_BRIDGING, &bridging, sizeof(int)); + if (bridging && ch->other_ch) { + chan_misdn_log(1, port, "Disabling EC (aka Pipeline) on both Sides\n"); + *ch->bc->pipeline=0; + *ch->other_ch->bc->pipeline=0; + } + + r=misdn_lib_send_event( newbc, EVENT_SETUP ); + + /** we should have l3id after sending setup **/ + ch->l3id=newbc->l3_id; + } + + if ( r == -ENOCHAN ) { + chan_misdn_log(0, port, " --> * Theres no Channel at the moment .. !\n"); + chan_misdn_log(1, port, " --> * SEND: State Down pid:%d\n",newbc?newbc->pid:-1); + ast->hangupcause=34; + ast_setstate(ast, AST_STATE_DOWN); + return -1; + } + + chan_misdn_log(2, port, " --> * SEND: State Dialing pid:%d\n",newbc?newbc->pid:1); + + ast_setstate(ast, AST_STATE_DIALING); + ast->hangupcause=16; + +wenn pattern available soll gestoppt werden, sonst nicht: + if (newbc->nt) stop_bc_tones(ch); + + ch->state=MISDN_CALLING; + + return 0; +} + + static struct ast_channel_tech misdn_tech = { .type="lcr", .description="Channel driver for connecting to Linux-Call-Router", @@ -542,12 +706,13 @@ int load_module(void) return -1; } - ast_cli_register(&cli_show_cls); - ast_cli_register(&cli_show_cl); - ast_cli_register(&cli_show_config); - - ast_cli_register(&cli_reload); + ast_cli_register(&cli_show_lcr); + ast_cli_register(&cli_show_calls); + ast_cli_register(&cli_reload_routing); + ast_cli_register(&cli_reload_interfaces); + ast_cli_register(&cli_port_block); + ast_cli_register(&cli_port_unblock); ast_register_application("misdn_set_opt", misdn_set_opt_exec, "misdn_set_opt", "misdn_set_opt(::..):\n" @@ -582,10 +747,12 @@ int unload_module(void) if (!g_config_initialized) return 0; - ast_cli_unregister(&cli_show_cls); - ast_cli_unregister(&cli_show_cl); - ast_cli_unregister(&cli_show_config); - ast_cli_unregister(&cli_reload); + ast_cli_unregister(&cli_show_lcr); + ast_cli_unregister(&cli_show_calls); + ast_cli_unregister(&cli_reload_routing); + ast_cli_unregister(&cli_reload_interfaces); + ast_cli_unregister(&cli_port_block); + ast_cli_unregister(&cli_port_unblock); ast_unregister_application("misdn_set_opt"); ast_channel_unregister(&lcr_tech); diff --git a/chan_lcr.h b/chan_lcr.h index 0f861fe..8633d3a 100644 --- a/chan_lcr.h +++ b/chan_lcr.h @@ -14,6 +14,8 @@ struct chan_call { struct chan_call *next; unsigned long ref; /* callref, is 0, if not yet set */ unsigned long bchannel_handle; /* reference to bchannel, if set */ + + unsigned short bridge_id; /* 0 = off, equal ids are bridged */ }; diff --git a/dss1.cpp b/dss1.cpp index 49af6ea..7021860 100644 --- a/dss1.cpp +++ b/dss1.cpp @@ -25,8 +25,6 @@ extern "C" { #include } -//#define CENTREX - #include "q931.h" #include "ie.cpp" @@ -501,11 +499,9 @@ void Pdss1::setup_ind(unsigned long prim, unsigned long dinfo, void *data) dec_ie_calling_pn(setup->CALLING_PN, (Q931_info_t *)((unsigned long)data+headerlen), &calling_type, &calling_plan, &calling_present, &calling_screen, (unsigned char *)p_callerinfo.id, sizeof(p_callerinfo.id)); dec_ie_called_pn(setup->CALLED_PN, (Q931_info_t *)((unsigned long)data+headerlen), &called_type, &called_plan, (unsigned char *)p_dialinginfo.id, sizeof(p_dialinginfo.id)); dec_ie_keypad(setup->KEYPAD, (Q931_info_t *)((unsigned long)data+headerlen), (unsigned char *)keypad, sizeof(keypad)); -#ifdef CENTREX /* te-mode: CNIP (calling name identification presentation) */ if (!p_m_d_ntmode) dec_facility_centrex(setup->FACILITY, (Q931_info_t *)((unsigned long)data+headerlen), (unsigned char *)p_callerinfo.name, sizeof(p_callerinfo.name)); -#endif dec_ie_useruser(setup->USER_USER, (Q931_info_t *)((unsigned long)data+headerlen), &useruser_protocol, useruser, &useruser_len); dec_ie_complete(setup->COMPLETE, (Q931_info_t *)((unsigned long)data+headerlen), &p_dialinginfo.sending_complete); dec_ie_redir_nr(setup->REDIR_NR, (Q931_info_t *)((unsigned long)data+headerlen), &redir_type, &redir_plan, &redir_present, &redir_screen, &redir_reason, (unsigned char *)p_redirinfo.id, sizeof(p_redirinfo.id)); @@ -1016,11 +1012,9 @@ void Pdss1::connect_ind(unsigned long prim, unsigned long dinfo, void *data) l1l2l3_trace_header(p_m_mISDNport, this, prim, DIRECTION_IN); dec_ie_channel_id(connect->CHANNEL_ID, (Q931_info_t *)((unsigned long)data+headerlen), &exclusive, &channel); dec_ie_connected_pn(connect->CONNECT_PN, (Q931_info_t *)((unsigned long)data+headerlen), &type, &plan, &present, &screen, (unsigned char *)p_connectinfo.id, sizeof(p_connectinfo.id)); -#ifdef CENTREX /* te-mode: CONP (connected name identification presentation) */ if (!p_m_d_ntmode) dec_facility_centrex(connect->FACILITY, (Q931_info_t *)((unsigned long)data+headerlen), (unsigned char *)p_connectinfo.name, sizeof(p_connectinfo.name)); -#endif end_trace(); /* select channel */ @@ -2310,11 +2304,9 @@ void Pdss1::message_setup(unsigned long epoint_id, int message_id, union paramet /* display */ if (p_callerinfo.display[0] && p_m_d_ntmode) enc_ie_display(&setup->DISPLAY, dmsg, (unsigned char *)p_callerinfo.display); -#ifdef CENTREX /* nt-mode: CNIP (calling name identification presentation) */ - if (p_callerinfo.name[0] && p_m_d_ntmode) - enc_facility_centrex(&setup->FACILITY, dmsg, (unsigned char *)p_callerinfo.name, 1); -#endif +// if (p_callerinfo.name[0] && p_m_d_ntmode) +// enc_facility_centrex(&setup->FACILITY, dmsg, (unsigned char *)p_callerinfo.name, 1); end_trace(); /* send setup message now */ @@ -2650,11 +2642,9 @@ void Pdss1::message_connect(unsigned long epoint_id, int message_id, union param /* display */ if (p_connectinfo.display[0] && p_m_d_ntmode) enc_ie_display(&connect->DISPLAY, dmsg, (unsigned char *)p_connectinfo.display); -#ifdef CENTREX /* nt-mode: CONP (connected name identification presentation) */ - if (p_connectinfo.name[0] && p_m_d_ntmode) - enc_facility_centrex(&connect->FACILITY, dmsg, (unsigned char *)p_connectinfo.name, 0); -#endif +// if (p_connectinfo.name[0] && p_m_d_ntmode) +// enc_facility_centrex(&connect->FACILITY, dmsg, (unsigned char *)p_connectinfo.name, 0); /* date & time */ if (p_m_d_ntmode) { @@ -3271,7 +3261,7 @@ int stack2manager_te(struct mISDNport *mISDNport, msg_t *msg) if (frm->prim == (CC_RELEASE_CR | INDICATION)) { - PERROR("unhandled message from stack: call ref released (l3id=0x%x)\n", frm->dinfo); + PDEBUG(DEBUG_ISDN, "unhandled message from stack: call ref released (l3id=0x%x)\n", frm->dinfo); free_msg(msg); return(0); } diff --git a/dss1.h b/dss1.h index 488e56b..49121fa 100644 --- a/dss1.h +++ b/dss1.h @@ -94,7 +94,6 @@ class Pdss1 : public PmISDN void dec_ie_redir_dn(unsigned char *p, Q931_info_t *qi, int *type, int *plan, int *present, unsigned char *number, int number_len); void enc_ie_facility(unsigned char **ntmode, msg_t *msg, unsigned char *facility, int facility_len); void dec_ie_facility(unsigned char *p, Q931_info_t *qi, unsigned char *facility, int *facility_len); - void enc_facility_centrex(unsigned char **ntmode, msg_t *msg, unsigned char *cnip, int setup); void dec_facility_centrex(unsigned char *p, Q931_info_t *qi, unsigned char *cnip, int cnip_len); void enc_ie_useruser(unsigned char **ntmode, msg_t *msg, int protocol, unsigned char *user, int user_len); void dec_ie_useruser(unsigned char *p, Q931_info_t *qi, int *protocol, unsigned char *user, int *user_len); diff --git a/extension.c b/extension.c index 391bb88..0309b33 100644 --- a/extension.c +++ b/extension.c @@ -396,24 +396,6 @@ int read_extension(struct extension *ext, char *num) PDEBUG(DEBUG_CONFIG, "unknown parameter given keypad: %s\n", param); } } else - if (!strcmp(option,"centrex")) - { - i=0; - while(ext_yesno[i]) - { - if (!strcasecmp(param,ext_yesno[i])) - break; - i++; - } - if (ext_yesno[i]) - { - ext->centrex = i; - PDEBUG(DEBUG_CONFIG, "use centrex to display name %s\n", ext_yesno[i]); - } else - { - PDEBUG(DEBUG_CONFIG, "unknown parameter given centrex: %s\n", param); - } - } else if (!strcmp(option,"rights")) { i=0; @@ -1094,11 +1076,6 @@ int write_extension(struct extension *ext, char *number) fprintf(fp,"# DTMF tone, but the digit is transmitted via D-channel diaing info.\n"); fprintf(fp,"keypad %s\n\n",(ext->keypad)?"yes":"no"); - fprintf(fp,"# Called Name Identification Presentation (CNIP/CONP)\n"); - fprintf(fp,"# If supported by telephone, special information element on the d-channel are\n"); - fprintf(fp,"# used to show name of caller. It is supported by newer Siemens telephones\n# (Centrex).\n"); - fprintf(fp,"centrex %s #this is currently not working!!!\n\n",(ext->centrex)?"yes":"no"); - fprintf(fp,"# Ignore restriction of COLP and CLIP\n"); fprintf(fp,"# In this case even restricted numbers are presented to this extension.\n"); fprintf(fp,"# This also works for incoming external anonymous calls IF:\n"); diff --git a/extension.h b/extension.h index 4672637..88bfc72 100644 --- a/extension.h +++ b/extension.h @@ -132,7 +132,6 @@ struct extension { int colp; /* how to present called line id on forwarded calls */ char clip_prefix[32]; /* prefix for screening incoming clip */ int keypad; /* support keypad for call control */ - int centrex; /* present name of caller/called on internal extension */ int anon_ignore; /* ignore anonymouse calls */ int rights; int delete_ext; /* delete function for external dialing */ diff --git a/genrc.c b/genrc.c index 7c5089f..e42abb2 100644 --- a/genrc.c +++ b/genrc.c @@ -171,14 +171,14 @@ int main(void) fprintf(fp, "# rc script for mISDN driver\n\n"); fprintf(fp, "case \"$1\" in\n"); fprintf(fp, "\tstart|--start)\n"); - fprintf(fp, "\t\t%s %smISDN_core%s debug=0x%x\n", input[0]?"insmod -f":"modprobe", input, input[0]?".ko":"", coredebug); + fprintf(fp, "\t\t%s %smISDN_core%s debug=0x%x\n", input[0]?"insmod -f":"modprobe --ignore-install", input, input[0]?".ko":"", coredebug); if (anyte) { - fprintf(fp, "\t\t%s %smISDN_l1%s debug=0x%x\n", input[0]?"insmod -f":"modprobe", input, input[0]?".ko":"", l1debug); - fprintf(fp, "\t\t%s %smISDN_l2%s debug=0x%x\n", input[0]?"insmod -f":"modprobe", input, input[0]?".ko":"", l2debug); - fprintf(fp, "\t\t%s %sl3udss1%s debug=0x%x\n", input[0]?"insmod -f":"modprobe", input, input[0]?".ko":"", l3debug); + fprintf(fp, "\t\t%s %smISDN_l1%s debug=0x%x\n", input[0]?"insmod -f":"modprobe --ignore-install", input, input[0]?".ko":"", l1debug); + fprintf(fp, "\t\t%s %smISDN_l2%s debug=0x%x\n", input[0]?"insmod -f":"modprobe --ignore-install", input, input[0]?".ko":"", l2debug); + fprintf(fp, "\t\t%s %sl3udss1%s debug=0x%x\n", input[0]?"insmod -f":"modprobe --ignore-install", input, input[0]?".ko":"", l3debug); } - fprintf(fp, "\t\t%s %smISDN_dsp%s debug=0x%x options=0x%x\n", input[0]?"insmod -f":"modprobe", input, input[0]?".ko":"", dspdebug, lawopt); + fprintf(fp, "\t\t%s %smISDN_dsp%s debug=0x%x options=0x%x\n", input[0]?"insmod -f":"modprobe --ignore-install", input, input[0]?".ko":"", dspdebug, lawopt); j = 0; while(cards[j].card) { @@ -202,9 +202,9 @@ int main(void) if (types[0]) { types[strlen(types)-1] = '\0'; - fprintf(fp, "\t\t%s %s%s%s type=%s protocol=%s layermask=%s debug=0x%x\n", input[0]?"insmod -f":"modprobe", input, cards[j].module, input[0]?".ko":"", types, protocol, layermask, carddebug); + fprintf(fp, "\t\t%s %s%s%s type=%s protocol=%s layermask=%s debug=0x%x\n", input[0]?"insmod -f":"modprobe --ignore-install", input, cards[j].module, input[0]?".ko":"", types, protocol, layermask, carddebug); } else - fprintf(fp, "\t\t%s %s%s%s protocol=%s layermask=%s debug=0x%x\n", input[0]?"insmod -f":"modprobe", input, cards[j].module, input[0]?".ko":"", protocol, layermask, carddebug); + fprintf(fp, "\t\t%s %s%s%s protocol=%s layermask=%s debug=0x%x\n", input[0]?"insmod -f":"modprobe --ignore-install", input, cards[j].module, input[0]?".ko":"", protocol, layermask, carddebug); } j++; } diff --git a/ie.cpp b/ie.cpp index f866349..5e3074a 100644 --- a/ie.cpp +++ b/ie.cpp @@ -1450,58 +1450,6 @@ void Pdss1::dec_ie_facility(unsigned char *p, Q931_info_t *qi, unsigned char *fa } -/* facility for siemens CENTEX (known parts implemented only) */ -void Pdss1::enc_facility_centrex(unsigned char **ntmode, msg_t *msg, unsigned char *cnip, int setup) -{ - unsigned char centrex[256]; - int i = 0; - - if (!cnip) - return; - - /* centrex facility */ - centrex[i++] = CENTREX_FAC; - centrex[i++] = CENTREX_ID; - - /* cnip */ - if (strlen((char *)cnip) > 15) - { - PDEBUG(DEBUG_PORT, "%s: CNIP/CONP text too long (max 13 chars), cutting.\n"); - cnip[15] = '\0'; - } - // dunno what the 8 bytes mean - if (setup) - { - centrex[i++] = 0x17; - centrex[i++] = 0x02; - centrex[i++] = 0x02; - centrex[i++] = 0x44; - centrex[i++] = 0x18; - centrex[i++] = 0x02; - centrex[i++] = 0x01; - centrex[i++] = 0x09; - } else - { - centrex[i++] = 0x18; - centrex[i++] = 0x02; - centrex[i++] = 0x02; - centrex[i++] = 0x81; - centrex[i++] = 0x09; - centrex[i++] = 0x02; - centrex[i++] = 0x01; - centrex[i++] = 0x0a; - } - - centrex[i++] = 0x80; - centrex[i++] = strlen((char *)cnip); - UCPY((char *)(¢rex[i]), (char *)cnip); - i += strlen((char *)cnip); - add_trace("facility", "cnip", "%s", cnip); - - /* encode facility */ - enc_ie_facility(ntmode, msg, centrex, i); -} - void Pdss1::dec_facility_centrex(unsigned char *p, Q931_info_t *qi, unsigned char *cnip, int cnip_len) { unsigned char centrex[256]; diff --git a/lcradmin.c b/lcradmin.c new file mode 100644 index 0000000..cf97f69 --- /dev/null +++ b/lcradmin.c @@ -0,0 +1,1757 @@ +/*****************************************************************************\ +** ** +** Linux Call Router ** +** ** +**---------------------------------------------------------------------------** +** Copyright: Andreas Eversberg ** +** ** +** Administration tool ** +** ** +\*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "macro.h" +#include "join.h" +#include "joinpbx.h" +#include "extension.h" +#include "message.h" +#include "lcrsocket.h" +#include "cause.h" + +#define LTEE {addch(ACS_LTEE);addch(ACS_HLINE);addch(ACS_HLINE);} +#define LLCORNER {addch(ACS_LLCORNER);addch(ACS_HLINE);addch(ACS_HLINE);} +#define VLINE {addch(ACS_VLINE);addstr(" ");} +#define EMPTY {addstr(" ");} +//char rotator[] = {'-', '\\', '|', '/'}; +int lastlines, lastcols; +int show_interfaces = 2, + show_calls = 1, + show_log = 1; + +enum { + MODE_STATE, + MODE_INTERFACE, + MODE_ROUTE, + MODE_DIAL, + MODE_RELEASE, + MODE_UNBLOCK, + MODE_BLOCK, + MODE_UNLOAD, + MODE_TESTCALL, + MODE_TRACE, +}; + +char *text_interfaces[] = { + "off", + "brief", + "active channels", + "all channels", +}; + +char *text_calls[] = { + "off", + "brief", + "structured", +}; + +char red = 1, + green = 2, + yellow = 3, + blue = 4, + mangenta = 5, + cyan = 6, + white = 7; + +#define LOGLINES 128 +char logline[LOGLINES][512]; +unsigned long logcur = 0; +int logfh = -1; +char logfile[128]; + +/* + * curses + */ +void init_curses(void) +{ + /* init curses */ + initscr(); cbreak(); noecho(); + start_color(); + nodelay(stdscr, TRUE); + if (COLOR_PAIRS>=8 && COLORS>=8) + { + init_pair(1,1,0); + init_pair(2,2,0); + init_pair(3,3,0); + init_pair(4,4,0); + init_pair(5,5,0); + init_pair(6,6,0); + init_pair(7,7,0); + } + lastlines = LINES; + lastcols = COLS; +} + +void cleanup_curses(void) +{ + endwin(); +} + +void color(int color) +{ + if (COLOR_PAIRS>=8 && COLORS>=8) + attrset(COLOR_PAIR(color)); +} + +/* + * permanently show current state using ncurses + */ +int debug_port(struct admin_message *msg, struct admin_message *m, int line, int i, int vline) +{ + char buffer[256]; + + color(white); + addstr("PORT:"); + color(yellow); + SPRINT(buffer,"%s(%d)", m[i].u.p.name,m[i].u.p.serial); + addstr(buffer); + color(cyan); + addstr(" state="); + switch (m[i].u.p.state) + { + case ADMIN_STATE_IDLE: + color(red); + addstr("'idle'"); + break; + case ADMIN_STATE_IN_SETUP: + color(red); + addstr("'in << setup'"); + break; + case ADMIN_STATE_OUT_SETUP: + color(red); + addstr("'out >> setup'"); + break; + case ADMIN_STATE_IN_OVERLAP: + color(yellow); + addstr("'in << overlap'"); + break; + case ADMIN_STATE_OUT_OVERLAP: + color(yellow); + addstr("'out >> overlap'"); + break; + case ADMIN_STATE_IN_PROCEEDING: + color(mangenta); + addstr("'in << proc'"); + break; + case ADMIN_STATE_OUT_PROCEEDING: + color(mangenta); + addstr("'out >> proc'"); + break; + case ADMIN_STATE_IN_ALERTING: + color(cyan); + addstr("'in << alert'"); + break; + case ADMIN_STATE_OUT_ALERTING: + color(cyan); + addstr("'out >> alert'"); + break; + case ADMIN_STATE_CONNECT: + color(white); + addstr("'connect'"); + break; + case ADMIN_STATE_IN_DISCONNECT: + color(blue); + addstr("'in << disc'"); + break; + case ADMIN_STATE_OUT_DISCONNECT: + color(blue); + addstr("'out >> disc'"); + break; + default: + color(blue); + addstr("'--NONE--'"); + } + + if (m[i].u.p.isdn) + { + color(cyan); + addstr(" bchannel="); + color(white); + SPRINT(buffer,"%d", m[i].u.p.isdn_chan); + addstr(buffer); + if (m[i].u.p.isdn_ces >= 0) + { + color(cyan); + addstr(" ces="); + color(yellow); + SPRINT(buffer, "%d", m[i].u.p.isdn_ces); + addstr(buffer); + } + if (m[i].u.p.isdn_hold) + { + color(red); + addstr(" hold"); + } + } + + return(line); +} +int debug_epoint(struct admin_message *msg, struct admin_message *m, int line, int i, int vline) +{ + unsigned long epoint = m[i].u.e.serial; + char buffer[256]; + unsigned char c; + int j, jj; + int ltee; + + color(white); + SPRINT(buffer,"EPOINT(%d)", epoint); + addstr(buffer); + color(cyan); + addstr(" state="); + switch (m[i].u.e.state) + { + case ADMIN_STATE_IDLE: + color(red); + addstr("'idle'"); + break; + case ADMIN_STATE_IN_SETUP: + color(red); + addstr("'in << setup'"); + break; + case ADMIN_STATE_OUT_SETUP: + color(red); + addstr("'out >> setup'"); + break; + case ADMIN_STATE_IN_OVERLAP: + color(yellow); + addstr("'in << overlap'"); + break; + case ADMIN_STATE_OUT_OVERLAP: + color(yellow); + addstr("'out >> overlap'"); + break; + case ADMIN_STATE_IN_PROCEEDING: + color(mangenta); + addstr("'in << proc'"); + break; + case ADMIN_STATE_OUT_PROCEEDING: + color(mangenta); + addstr("'out >> proc'"); + break; + case ADMIN_STATE_IN_ALERTING: + color(cyan); + addstr("'in << alert'"); + break; + case ADMIN_STATE_OUT_ALERTING: + color(cyan); + addstr("'out >> alert'"); + break; + case ADMIN_STATE_CONNECT: + color(white); + addstr("'connect'"); + break; + case ADMIN_STATE_IN_DISCONNECT: + color(blue); + addstr("'in << disc'"); + break; + case ADMIN_STATE_OUT_DISCONNECT: + color(blue); + addstr("'out >> disc'"); + break; + default: + color(blue); + addstr("'--NONE--'"); + } + if (m[i].u.e.terminal[0]) + { + color(cyan); + addstr(" terminal="); + color(green); + addstr(m[i].u.e.terminal); + } + color(white); + SPRINT(buffer, " %s", m[i].u.e.callerid); + addstr(buffer); + color(cyan); + addstr("->"); + color(white); + addstr(m[i].u.e.dialing); + if (m[i].u.e.action[0]) + { + color(cyan); + addstr(" action="); + color(yellow); + addstr(m[i].u.e.action); + } + if (m[i].u.e.park) + { + color(cyan); + addstr(" park="); /* 9 digits */ + color(green); + UCPY(buffer, "\""); /* 9 digits */ + j = 0; + jj = m[i].u.e.park_len; + while(j < jj) + { + c = m[i].u.e.park_callid[j]; + if (c >= 32 && c < 127 && c != '[') + { + SCCAT(buffer, c); + } else + UPRINT(buffer+strlen(buffer), "[%02x]", c); + j++; + } + SCAT(buffer, "\""); + addstr(buffer); + } else + { + color(red); + switch(m[i].u.e.rx_state) + { + case NOTIFY_STATE_SUSPEND: + addstr(" in=suspend"); + break; + case NOTIFY_STATE_HOLD: + addstr(" in=hold"); + break; + case NOTIFY_STATE_CONFERENCE: + addstr(" in=conference"); + break; + } + switch(m[i].u.e.tx_state) + { + case NOTIFY_STATE_SUSPEND: + addstr(" out=suspend"); + break; + case NOTIFY_STATE_HOLD: + addstr(" out=hold"); + break; + case NOTIFY_STATE_CONFERENCE: + addstr(" out=conference"); + break; + } + } + if (m[i].u.e.crypt) + { + color(cyan); + addstr(" crypt="); + if (m[i].u.e.crypt) /* crypt on */ + { + color(green); + addstr("active"); + } else + { + color(yellow); + addstr("pending"); + } + } + /* loop all related ports */ + ltee = 0; + j = msg->u.s.interfaces+msg->u.s.joins+msg->u.s.epoints; + jj = j + msg->u.s.ports; + while(j < jj) + { + if (m[j].u.p.epoint == epoint) + { + color(cyan); + move(++line>1?line:1, 1); + if (vline) + VLINE + else + EMPTY + move(line>1?line:1, 5); + LTEE + ltee = line; + move(line>1?line:1, 8); + if (line+2 >= LINES) break; + line = debug_port(msg, m, line, j, vline); + if (line+2 >= LINES) break; + } + j++; + } + if (ltee) + { + color(cyan); + move(ltee>1?line:1, 5); + LLCORNER + } + + return(line); +} +int debug_join(struct admin_message *msg, struct admin_message *m, int line, int i) +{ + unsigned long join = m[i].u.j.serial; + char buffer[256]; + int j, jj; + + color(white); + SPRINT(buffer,"JOIN(%d)", join); + addstr(buffer); + if (m[i].u.j.partyline) + { + color(cyan); + addstr(" partyline="); + color(white); + SPRINT(buffer, "%d\n", m[i].u.j.partyline); + addstr(buffer); + } + if (m[i].u.j.remote[0]) + { + color(cyan); + addstr(" remote="); + color(white); + SPRINT(buffer, "%s\n", m[i].u.j.remote); + addstr(buffer); + } + /* find number of epoints */ + j = msg->u.s.interfaces+msg->u.s.joins; + jj = j + msg->u.s.epoints; + i = 0; + while(j < jj) + { + if (m[j].u.e.join == join) + i++; + j++; + } + /* loop all related endpoints */ + j = msg->u.s.interfaces+msg->u.s.joins; + jj = j + msg->u.s.epoints; + while(j < jj) + { + if (m[j].u.e.join == join) + { + i--; + move(++line>1?line:1, 1); + color(cyan); + if (i) + LTEE + else + LLCORNER + move(line>1?line:1, 4); + if (line+2 >= LINES) break; + line = debug_epoint(msg, m, line, j, i?1:0); + if (line+2 >= LINES) break; + } + j++; + } + + return(line); +} +char *admin_state(int sock, char *argv[]) +{ + struct admin_message msg, + *m; + char buffer[512], + *p; + int line, offset = 0, hoffset = 0; + int i, ii, j, jj, k; + unsigned long l, ll; + int num; + int len; + int off; + int ltee; + int anything; + int enter = 0; + char enter_string[128] = "", ch; + fd_set select_rfds; + struct timeval select_tv; + + /* flush logfile name */ + logfile[0] = '\0'; + + /* init curses */ + init_curses(); + + again: + /* send reload command */ + memset(&msg, 0, sizeof(msg)); + msg.message = ADMIN_REQUEST_STATE; +// printf("sizeof=%d\n",sizeof(msg));fflush(stdout); + if (write(sock, &msg, sizeof(msg)) != sizeof(msg)) + { + cleanup_curses(); + return("Broken pipe while sending command."); + } + + /* receive response */ + if (read(sock, &msg, sizeof(msg)) != sizeof(msg)) + { + cleanup_curses(); + return("Broken pipe while receiving response."); + } + + if (msg.message != ADMIN_RESPONSE_STATE) + { + cleanup_curses(); + return("Response not valid. Expecting state response."); + } + num = msg.u.s.interfaces + msg.u.s.remotes + msg.u.s.joins + msg.u.s.epoints + msg.u.s.ports; + m = (struct admin_message *)MALLOC(num*sizeof(struct admin_message)); + off=0; + if (num) + { + readagain: + if ((len = read(sock, ((unsigned char *)(m))+off, num*sizeof(struct admin_message)-off)) != num*(int)sizeof(struct admin_message)-off) + { + if (len <= 0) { + FREE(m, 0); + // fprintf(stderr, "got=%d expected=%d\n", i, num*sizeof(struct admin_message)); + cleanup_curses(); + return("Broken pipe while receiving state infos."); + } + if (len < num*(int)sizeof(struct admin_message)) + { + off+=len; + goto readagain; + } + } + } + j = 0; + i = 0; +// fprintf("getting =%d interfaces\n", msg.u.s.interfaces); + while(i < msg.u.s.interfaces) + { +// fprintf(stderr, "j=%d message=%d\n", j, m[j].message); + if (m[j].message != ADMIN_RESPONSE_S_INTERFACE) + { + FREE(m, 0); + cleanup_curses(); + return("Response not valid. Expecting interface information."); + } + i++; + j++; + } + i = 0; + while(i < msg.u.s.remotes) + { + if (m[j].message != ADMIN_RESPONSE_S_REMOTE) + { + FREE(m, 0); + cleanup_curses(); + return("Response not valid. Expecting remote application information."); + } + i++; + j++; + } + i = 0; + while(i < msg.u.s.joins) + { + if (m[j].message != ADMIN_RESPONSE_S_JOIN) + { + FREE(m, 0); + cleanup_curses(); + return("Response not valid. Expecting join information."); + } + i++; + j++; + } + i = 0; + while(i < msg.u.s.epoints) + { + if (m[j].message != ADMIN_RESPONSE_S_EPOINT) + { + FREE(m, 0); + cleanup_curses(); + return("Response not valid. Expecting endpoint information."); + } + i++; + j++; + } + i = 0; + while(i < msg.u.s.ports) + { + if (m[j].message != ADMIN_RESPONSE_S_PORT) + { + FREE(m, 0); + cleanup_curses(); + return("Response not valid. Expecting port information."); + } + i++; + j++; + } + // now j is the number of message blocks + + /* display start */ + erase(); + + line = 1-offset; + + /* change log */ + if (!!strcmp(logfile, msg.u.s.logfile)) + { + SCPY(logfile, msg.u.s.logfile); + if (logfh >= 0) + close(logfh); + i = 0; + ii = LOGLINES; + while(i < ii) + { + logline[i][0] = '~'; + logline[i][1] = '\0'; + i++; + } + logcur = 0; + logfh = open(logfile, O_RDONLY|O_NONBLOCK); + if (logfh >= 0) + { + /* seek at the end -8000 chars */ + lseek(logfh, -8000, SEEK_END); + /* if not at the beginning, read until endofline */ + logline[logcur % LOGLINES][0] = '\0'; + l = read(logfh, logline[logcur % LOGLINES], sizeof(logline[logcur % LOGLINES])-1); + if (l > 0) + { + /* read first line and skip junk */ + logline[logcur % LOGLINES][l] = '\0'; + if ((p = strchr(logline[logcur % LOGLINES],'\n'))) + { + logcur++; + SCPY(logline[logcur % LOGLINES], p+1); + SCPY(logline[(logcur-1) % LOGLINES], "..."); + } + goto finish_line; + } + } + } + + /* read log */ + if (logfh >= 0) + { + while(42) + { + ll = strlen(logline[logcur % LOGLINES]); + l = read(logfh, logline[logcur % LOGLINES]+ll, sizeof(logline[logcur % LOGLINES])-ll-1); + if (l<=0) + break; + logline[logcur % LOGLINES][ll+l] = '\0'; + finish_line: + /* put data to lines */ + while ((p = strchr(logline[logcur % LOGLINES],'\n'))) + { + *p = '\0'; + logcur++; + SCPY(logline[logcur % LOGLINES], p+1); + } + /* if line is full without return, go next line */ + if (strlen(logline[logcur % LOGLINES]) == sizeof(logline[logcur % LOGLINES])-1) + { + logcur++; + logline[logcur % LOGLINES][0] = '\0'; + } + } + } + + /* display interfaces */ + if (show_interfaces > 0) + { + anything = 0; + i = 0; + ii = i + msg.u.s.interfaces; + while(i < ii) + { + /* show interface summary */ + move(++line>1?line:1, 0); + color(white); + if (m[i].u.i.block >= 2) + { + SPRINT(buffer, "%s (%d)%s", m[i].u.i.interface_name, m[i].u.i.portnum, (m[i].u.i.extension)?" (extension)":""); + addstr(buffer); + color(red); + addstr(" not loaded"); + } else + { + SPRINT(buffer, "%s (%d) %s %s%s use:%d", m[i].u.i.interface_name, m[i].u.i.portnum, (m[i].u.i.ntmode)?"NT-mode":"TE-mode", (m[i].u.i.ptp)?"ptp ":"ptmp", (m[i].u.i.extension)?" extension":"", m[i].u.i.use); + addstr(buffer); + if (m[i].u.i.ptp || !m[i].u.i.ntmode) + { + color((m[i].u.i.l2link)?green:red); + addstr((m[i].u.i.l2link)?" L2 UP":" L2 down"); + } + color((m[i].u.i.l1link)?green:blue); + addstr((m[i].u.i.l1link)?" L1 ACTIVE":" L1 inactive"); + if (m[i].u.i.block) + { + color(red); + addstr(" blocked"); + } + if (line+2 >= LINES) goto end; + /* show channels */ + if (show_interfaces > 1) + { + ltee = 0; + j = k =0; + jj = m[i].u.i.channels; + while(j < jj) + { + /* show all channels */ + if (show_interfaces>2 || m[i].u.i.busy[j]>0) + { + color(cyan); + /* show left side / right side */ + if ((k & 1) && (COLS > 70)) + { + move(line>1?line:1,4+((COLS-4)/2)); + } else + { + move(++line>1?line:1, 1); + LTEE + ltee = 1; + } + k++; + color(white); + if (m[i].u.i.pri) + SPRINT(buffer,"S%2d: ", j+1+(j>=15)); + else + SPRINT(buffer,"B%2d: ", j+1); + addstr(buffer); + switch(m[i].u.i.busy[j]) + { + case B_STATE_IDLE: + if ((!m[i].u.i.l2link && m[i].u.i.ptp) || m[i].u.i.block) + { + color(red); + addstr("blocked "); + } else + { + color(blue); + addstr("idle "); + } + break; + case B_STATE_ACTIVATING: + color(yellow); + addstr("act'ing "); + break; + case B_STATE_ACTIVE: + color(green); + addstr("busy "); + break; + case B_STATE_DEACTIVATING: + color(yellow); + addstr("dact'ing"); + break; + case B_STATE_EXPORTING: + color(yellow); + addstr("exp'ing "); + break; + case B_STATE_REMOTE: + color(green); + addstr("remote "); + break; + case B_STATE_IMPORTING: + color(yellow); + addstr("imp'ing "); + break; + } + if (m[i].u.i.port[j]) + { + /* search for port */ + l = msg.u.s.interfaces+msg.u.s.joins+msg.u.s.epoints; + ll = l+msg.u.s.ports; + while(l < ll) + { + if (m[l].u.p.serial == m[i].u.i.port[j]) + { + SPRINT(buffer, " %s(%ld)", m[l].u.p.name, m[l].u.p.serial); + addstr(buffer); + } + l++; + } + } + if (line+2 >= LINES) + { + if (ltee) + { + color(cyan); + move(line>1?line:1, 1); + LLCORNER + } + goto end; + } + } + j++; + } + if (ltee) + { + color(cyan); + move(line>1?line:1, 1); + LLCORNER + } + if (line+2 >= LINES) goto end; + /* show summary if no channels were shown */ + if (show_interfaces<2 && ltee==0) + { + color(cyan); + move(++line>1?line:1, 1); + LLCORNER + + if (m[i].u.i.l2link && m[i].u.i.block==0) + { + color(green); + SPRINT(buffer,"all %d channels free", m[i].u.i.channels); + } else + { + color(red); + SPRINT(buffer,"all %d channels blocked", m[i].u.i.channels); + } + addstr(buffer); + } + if (line+2 >= LINES) goto end; + } + } + i++; + anything = 1; + } + i = 0; + ii = i + msg.u.s.remotes; + while(i < ii) + { + /* show remote summary */ + move(++line>1?line:1, 0); + color(white); + SPRINT(buffer, "Remote: %s", m[i].u.r.name); + addstr(buffer); + i++; + } + if (anything) + line++; + if (line+2 >= LINES) goto end; + } + /* display calls (brief) */ + if (show_calls == 1) + { + anything = 0; + i = msg.u.s.interfaces+msg.u.s.joins; + ii = i+msg.u.s.epoints; + while(i < ii) + { + /* for each endpoint... */ + if (!m[i].u.e.join) + { + move(++line>1?line:1, 0); + color(white); + SPRINT(buffer, "(%d): ", m[i].u.e.serial); + addstr(buffer); + color(cyan); + if (m[i].u.e.terminal[0]) + { + addstr("intern="); + color(green); + addstr(m[i].u.e.terminal); + } else + addstr("extern"); + color(white); + SPRINT(buffer, " %s", m[i].u.e.callerid); + addstr(buffer); + color(cyan); + addstr("->"); + color(white); + SPRINT(buffer, "%s", m[i].u.e.dialing); + addstr(buffer); + if (m[i].u.e.action[0]) + { + color(cyan); + addstr(" action="); + color(yellow); + addstr(m[i].u.e.action); + } + if (line+2 >= LINES) goto end; + } + i++; + anything = 1; + } + j = msg.u.s.interfaces; + jj = j+msg.u.s.joins; + while(j < jj) + { + /* for each call... */ + move(++line>1?line:1, 0); + color(white); + SPRINT(buffer, "(%d):", m[j].u.j.serial); + addstr(buffer); + i = msg.u.s.interfaces+msg.u.s.joins; + ii = i+msg.u.s.epoints; + while(i < ii) + { + /* for each endpoint... */ + if (m[i].u.e.join == m[j].u.j.serial) + { + color(white); + SPRINT(buffer, " (%d)", m[i].u.e.serial); + addstr(buffer); + color(cyan); + if (m[i].u.e.terminal[0]) + { + addstr("int="); + color(green); + addstr(m[i].u.e.terminal); + } else + addstr("ext"); + color(white); + SPRINT(buffer, "-%s", m[i].u.e.callerid); + addstr(buffer); + color(cyan); + addstr(">"); + color(white); + SPRINT(buffer, "%s", m[i].u.e.dialing); + addstr(buffer); + } + i++; + anything = 1; + } + if (line+2 >= LINES) goto end; + j++; + } + if (anything) + line++; + if (line+2 >= LINES) goto end; + } + /* display calls (structurd) */ + if (show_calls == 2) + { + /* show all ports with no epoint */ + anything = 0; + i = msg.u.s.interfaces+msg.u.s.joins+msg.u.s.epoints; + ii = i+msg.u.s.ports; + while(i < ii) + { + if (!m[i].u.p.epoint) + { + move(++line>1?line:1, 8); + if (line+2 >= LINES) goto end; + line = debug_port(&msg, m, line, i, 0); + if (line+2 >= LINES) goto end; + anything = 1; + } + i++; + } + if (anything) + line++; + if (line+2 >= LINES) goto end; + + /* show all epoints with no call */ + anything = 0; + i = msg.u.s.interfaces+msg.u.s.joins; + ii = i+msg.u.s.epoints; + while(i < ii) + { + if (!m[i].u.e.join) + { + move(++line>1?line:1, 4); + if (line+2 >= LINES) goto end; + line = debug_epoint(&msg, m, line, i, 0); + if (line+2 >= LINES) goto end; + anything = 1; + } + i++; + } + if (anything) + line++; + if (line+2 >= LINES) goto end; + + /* show all joins */ + anything = 0; + i = msg.u.s.interfaces; + ii = i+msg.u.s.joins; + while(i < ii) + { + move(++line>1?line:1, 0); + if (line+2 >= LINES) goto end; + line = debug_join(&msg, m, line, i); + if (line+2 >= LINES) goto end; + i++; + anything = 1; + } + if (anything) + line++; + if (line+2 >= LINES) goto end; + + } + + /* show log */ + if (show_log) + { + if (line+2 < LINES) + { + move(line++>1?line-1:1, 0); + color(blue); + hline(ACS_HLINE, COLS); + color(white); + + l = logcur-(LINES-line-2); + ll = logcur; + if (ll-l >= LOGLINES) + l = ll-LOGLINES+1; + while(l!=ll) + { + move(line++>1?line-1:1, 0); + if ((int)strlen(logline[l % LOGLINES]) > hoffset) + SCPY(buffer, logline[l % LOGLINES] + hoffset); + else + buffer[0] = '\0'; + if (COLS < (int)strlen(buffer)) + { + buffer[COLS-1] = '\0'; + addstr(buffer); + color(mangenta); + addch('*'); + color(white); + } else + addstr(buffer); + l++; + } + } + } + + end: + /* free memory */ + FREE(m, 0); + /* display name/time */ +// move(0, 0); +// hline(' ', COLS); + move(0, 0); + color(cyan); + msg.u.s.version_string[sizeof(msg.u.s.version_string)-1] = '\0'; + SPRINT(buffer, "LCR %s", msg.u.s.version_string); + addstr(buffer); + if (COLS>50) + { + move(0, COLS-19); + SPRINT(buffer, "%04d-%02d-%02d %02d:%02d:%02d", + msg.u.s.tm.tm_year+1900, msg.u.s.tm.tm_mon+1, msg.u.s.tm.tm_mday, + msg.u.s.tm.tm_hour, msg.u.s.tm.tm_min, msg.u.s.tm.tm_sec); + addstr(buffer); + } + /* displeay head line */ + move(1, 0); + color(blue); + hline(ACS_HLINE, COLS); + if (offset) + { + move(1, 1); + SPRINT(buffer, "Offset +%d", offset); + color(red); + addstr(buffer); + } + if (hoffset) + { + move(1, 13); + SPRINT(buffer, "H-Offset +%d", hoffset); + color(red); + addstr(buffer); + } + /* display end */ + move(LINES-2, 0); + color(blue); + hline(ACS_HLINE, COLS); + move(LINES-1, 0); + if (enter) + { + color(white); + SPRINT(buffer, "-> %s", enter_string); + } else + { + color(cyan); + SPRINT(buffer, "i=interfaces '%s' c=calls '%s' l=log q=quit +-*/=scroll enter", text_interfaces[show_interfaces], text_calls[show_calls]); + } + addstr(buffer); + refresh(); + + /* resize */ + if (lastlines!=LINES || lastcols!=COLS) + { + cleanup_curses(); + init_curses(); + goto again; + } + + if (enter) + { + /* user input in enter mode */ + ch = getch(); + enter_again: + if (ch == 10) + { + FILE *fp; + + enter = 0; + if (!enter_string[0]) + goto again; + + SPRINT(logline[logcur++ % LOGLINES], "> %s", enter_string); + if (!!strncmp(enter_string, "interface", 10) && + !!strncmp(enter_string, "route", 6) && + !!strncmp(enter_string, "release ", 8) && + !!strncmp(enter_string, "block ", 6) && + !!strncmp(enter_string, "unblock ", 8) && + !!strncmp(enter_string, "unload ", 7)) + { + SPRINT(logline[logcur++ % LOGLINES], "usage:"); + SPRINT(logline[logcur++ % LOGLINES], "interface (reload interface.conf)"); + SPRINT(logline[logcur++ % LOGLINES], "route (reload routing.conf)"); + SPRINT(logline[logcur++ % LOGLINES], "release (release endpoint with given ID)"); + SPRINT(logline[logcur++ % LOGLINES], "block (block port for further calls)"); + SPRINT(logline[logcur++ % LOGLINES], "unblock (unblock port for further calls, load if not loaded)"); + SPRINT(logline[logcur++ % LOGLINES], "unload (unload mISDN stack, release call calls)"); + } else + { + /* applend output to log window */ + SPRINT(buffer, "%s %s", argv[0], enter_string); + fp = popen(buffer, "r"); + if (fp) + { + while(fgets(logline[logcur % LOGLINES], sizeof(logline[0]), fp)) + logline[logcur++ % LOGLINES][sizeof(logline[0])-1] = '\0'; + pclose(fp); + } else + { + SPRINT(logline[logcur++ % LOGLINES], "failed to execute '%s'", buffer); + } + } + logline[logcur % LOGLINES][0] = '\0'; + enter_string[0] = '\0'; + goto again; + } + if (ch>=32 && ch<=126) + { + SCCAT(enter_string, ch); + ch = getch(); + if (ch > 0) + goto enter_again; + goto again; + } else + if (ch==8 || ch==127) + { + if (enter_string[0]) + enter_string[strlen(enter_string)-1] = '\0'; + ch = getch(); + if (ch > 0) + goto enter_again; + goto again; + } else + if (ch != 3) + { + ch = getch(); + if (ch > 0) + goto enter_again; + FD_ZERO(&select_rfds); + FD_SET(0, &select_rfds); + select_tv.tv_sec = 0; + select_tv.tv_usec = 250000; + select(1, &select_rfds, NULL, NULL, &select_tv); + goto again; + } + } else + { + /* user input in normal mode */ + switch(getch()) + { + case 12: /* refresh */ + cleanup_curses(); + init_curses(); + goto again; + break; + + case 3: /* abort */ + case 'q': + case 'Q': + break; + + case 'i': /* toggle interface */ + show_interfaces++; + if (show_interfaces > 3) show_interfaces = 0; + goto again; + + case 'c': /* toggle calls */ + show_calls++; + if (show_calls > 2) show_calls = 0; + goto again; + + case 'l': /* toggle log */ + show_log++; + if (show_log > 1) show_log = 0; + goto again; + + case '+': /* scroll down */ + offset++; + goto again; + + case '-': /* scroll up */ + if (offset) + offset--; + goto again; + + case '*': /* scroll right */ + hoffset += 2; + goto again; + + case '/': /* scroll left */ + if (hoffset) + hoffset -= 2; + goto again; + + case 10: /* entermode */ + enter = 1; + goto again; + + default: + FD_ZERO(&select_rfds); + FD_SET(0, &select_rfds); + select_tv.tv_sec = 0; + select_tv.tv_usec = 250000; + select(1, &select_rfds, NULL, NULL, &select_tv); + goto again; + } + } + + /* check for logfh */ + if (logfh >= 0) + close(logfh); + logfh = -1; + + /* cleanup curses and exit */ + cleanup_curses(); + + return(NULL); +} + + +/* + * Send command and show error message. + */ +char *admin_cmd(int sock, int mode, char *extension, char *number) +{ + static struct admin_message msg; + + /* send reload command */ + memset(&msg, 0, sizeof(msg)); + switch(mode) + { + case MODE_INTERFACE: + msg.message = ADMIN_REQUEST_CMD_INTERFACE; + break; + case MODE_ROUTE: + msg.message = ADMIN_REQUEST_CMD_ROUTE; + break; + case MODE_DIAL: + msg.message = ADMIN_REQUEST_CMD_DIAL; + SPRINT(msg.u.x.message, "%s:%s", extension?:"", number?:""); + break; + case MODE_RELEASE: + msg.message = ADMIN_REQUEST_CMD_RELEASE; + SCPY(msg.u.x.message, number); + break; + case MODE_UNBLOCK: + msg.message = ADMIN_REQUEST_CMD_BLOCK; + msg.u.x.portnum = atoi(number); + msg.u.x.block = 0; + break; + case MODE_BLOCK: + msg.message = ADMIN_REQUEST_CMD_BLOCK; + msg.u.x.portnum = atoi(number); + msg.u.x.block = 1; + break; + case MODE_UNLOAD: + msg.message = ADMIN_REQUEST_CMD_BLOCK; + msg.u.x.portnum = atoi(number); + msg.u.x.block = 2; + break; + } + + if (write(sock, &msg, sizeof(msg)) != sizeof(msg)) + return("Broken pipe while sending command."); + + /* receive response */ + if (read(sock, &msg, sizeof(msg)) != sizeof(msg)) + return("Broken pipe while receiving response."); + switch(mode) + { + case MODE_INTERFACE: + if (msg.message != ADMIN_RESPONSE_CMD_INTERFACE) + return("Response not valid."); + break; + case MODE_ROUTE: + if (msg.message != ADMIN_RESPONSE_CMD_ROUTE) + return("Response not valid."); + break; + case MODE_DIAL: + if (msg.message != ADMIN_RESPONSE_CMD_DIAL) + return("Response not valid."); + break; + case MODE_RELEASE: + if (msg.message != ADMIN_RESPONSE_CMD_RELEASE) + return("Response not valid."); + break; + case MODE_UNBLOCK: + case MODE_BLOCK: + case MODE_UNLOAD: + if (msg.message != ADMIN_RESPONSE_CMD_BLOCK) + return("Response not valid."); + break; + } + + /* process response */ + if (msg.u.x.error) + { + return(msg.u.x.message); + } + printf("Command successfull.\n"); + return(NULL); +} + + +/* + * makes a testcall + */ +#define GET_NOW() { \ + gettimeofday(&now_tv, &now_tz); \ + now_d = ((double)(now_tv.tv_usec))/1000000 + now_tv.tv_sec; \ + } +char *admin_testcall(int sock, int argc, char *argv[]) +{ + static struct admin_message msg; + int ar = 2; + int stimeout = 0, ptimeout = 0, atimeout = 0, ctimeout = 0; + int l; + double timer = 0, now_d; + unsigned long on = 1; + struct timeval now_tv; + struct timezone now_tz; + + printf("pid=%d\n", getpid()); fflush(stdout); + + while (argc > ar) + { + if (!strcmp(argv[ar], "--setup-timeout")) + { + ar++; + if (argc == ar) + return("Missing setup timeout value.\n"); + stimeout = atoi(argv[ar]); + ar++; + } else + if (!strcmp(argv[ar], "--proceeding-timeout")) + { + ar++; + if (argc == ar) + return("Missing proceeding timeout value.\n"); + ptimeout = atoi(argv[ar]); + ar++; + } else + if (!strcmp(argv[ar], "--alerting-timeout")) + { + ar++; + if (argc == ar) + return("Missing alerting timeout value.\n"); + atimeout = atoi(argv[ar]); + ar++; + } else + if (!strcmp(argv[ar], "--connect-timeout")) + { + ar++; + if (argc == ar) + return("Missing connect timeout value.\n"); + ctimeout = atoi(argv[ar]); + ar++; + } else + { + break; + } + } + + /* send reload command */ + memset(&msg, 0, sizeof(msg)); + msg.message = ADMIN_CALL_SETUP; + msg.u.call.present = 1; + + if (argc > ar) + { + SCPY(msg.u.call.interface, argv[ar]); + } + ar++; + if (argc > ar) + { + SCPY(msg.u.call.callerid, argv[ar]); + } + ar++; + if (argc > ar) + { + SCPY(msg.u.call.dialing, argv[ar]); + } + ar++; + if (argc > ar) + { + if (argv[ar][0] == 'r') + msg.u.call.present = 0; + } + ar++; + msg.u.call.bc_capa = 0x00; /*INFO_BC_SPEECH*/ + msg.u.call.bc_mode = 0x00; /*INFO_BMODE_CIRCUIT*/ + msg.u.call.bc_info1 = 0; + msg.u.call.hlc = 0; + msg.u.call.exthlc = 0; + if (argc > ar) + msg.u.call.bc_capa = strtol(argv[ar],NULL,0); + else + msg.u.call.bc_info1 = 3 | 0x80; /* alaw, if no capability is given at all */ + ar++; + if (argc > ar) { + msg.u.call.bc_mode = strtol(argv[ar],NULL,0); + if (msg.u.call.bc_mode) msg.u.call.bc_mode = 2; + } + ar++; + if (argc > ar) { + msg.u.call.bc_info1 = strtol(argv[ar],NULL,0); + if (msg.u.call.bc_info1 < 0) + msg.u.call.bc_info1 = 0; + else + msg.u.call.bc_info1 |= 0x80; + } + ar++; + if (argc > ar) { + msg.u.call.hlc = strtol(argv[ar],NULL,0); + if (msg.u.call.hlc < 0) + msg.u.call.hlc = 0; + else + msg.u.call.hlc |= 0x80; + } + ar++; + if (argc > ar) { + msg.u.call.exthlc = strtol(argv[ar],NULL,0); + if (msg.u.call.exthlc < 0) + msg.u.call.exthlc = 0; + else + msg.u.call.exthlc |= 0x80; + } + ar++; + + if (write(sock, &msg, sizeof(msg)) != sizeof(msg)) + return("Broken pipe while sending command."); + + if (ioctl(sock, FIONBIO, (unsigned char *)(&on)) < 0) + return("Failed to set socket into non-blocking IO."); + + if (stimeout) + { + GET_NOW(); + timer = now_d + (double)stimeout; + } + + /* receive response */ +next: + l = read(sock, &msg, sizeof(msg)); + if (l < 0) + { + if (errno == EWOULDBLOCK) + { + if (timer) + { + GET_NOW(); + if (timer <= now_d) + { + printf("Timeout\n"); fflush(stdout); + return(NULL); + } + } + usleep(30000); + goto next; + } + return("Broken pipe while receiving response."); + } + if (l != sizeof(msg)) + return("Response has unexpected message size."); + switch(msg.message) + { + case ADMIN_CALL_SETUP_ACK: + printf("SETUP ACKNOWLEDGE\n"); fflush(stdout); + goto next; + + case ADMIN_CALL_PROCEEDING: + printf("PROCEEDING\n"); fflush(stdout); + if (ptimeout) + { + GET_NOW(); + timer = now_d + (double)ptimeout; + } + goto next; + + case ADMIN_CALL_ALERTING: + printf("ALERTING\n"); fflush(stdout); + if (atimeout) + { + GET_NOW(); + timer = now_d + (double)atimeout; + } + goto next; + + case ADMIN_CALL_CONNECT: + printf("CONNECT\n number=%s\n", msg.u.call.callerid); fflush(stdout); + if (ctimeout) + { + GET_NOW(); + timer = now_d + (double)ctimeout; + } + goto next; + + case ADMIN_CALL_NOTIFY: + printf("NOTIFY\n notify=%d\n number=%s\n", msg.u.call.notify, msg.u.call.callerid); fflush(stdout); + goto next; + + case ADMIN_CALL_DISCONNECT: + printf("DISCONNECT\n cause=%d %s\n location=%d %s\n", msg.u.call.cause, (msg.u.call.cause>0 && msg.u.call.cause<128)?isdn_cause[msg.u.call.cause].german:"", msg.u.call.location, (msg.u.call.location>=0 && msg.u.call.location<128)?isdn_location[msg.u.call.location].german:""); fflush(stdout); + break; + + case ADMIN_CALL_RELEASE: + printf("RELEASE\n cause=%d %s\n location=%d %s\n", msg.u.call.cause, (msg.u.call.cause>0 && msg.u.call.cause<128)?isdn_cause[msg.u.call.cause].german:"", msg.u.call.location, (msg.u.call.location>=0 && msg.u.call.location<128)?isdn_location[msg.u.call.location].german:""); fflush(stdout); + break; + + default: + return("Response not valid."); + } + + printf("Call released.\n"); fflush(stdout); + return(NULL); +} + + +/* + * makes a trace + */ +char *admin_trace(int sock, int argc, char *argv[]) +{ + static struct admin_message msg; + int i; + + /* show help */ + if (argc > 2) if (!strcasecmp(argv[2], "help")) + { + printf("Trace Help\n----------\n"); + printf("%s trace [brief|short] [= [...]]\n\n", argv[0]); + printf("By default a complete trace is shown in detailed format.\n"); + printf("To show a more compact format, use 'brief' or 'short' keyword.\n"); + printf("Use filter values to select specific trace messages.\n"); + printf("All given filter values must match. If no filter is given, anything matches.\n\n"); + printf("Filters:\n"); + printf(" category=\n"); + printf(" 0x01 = CH: channel object trace\n"); + printf(" 0x02 = EP: endpoint object trace\n"); + printf(" port= select only given port for trace\n"); + printf(" interface= select only given interface for trace\n"); + printf(" caller= select only given caller id for trace\n"); + printf(" dialing= select only given dialed number for trace\n"); + return(NULL); + } + + /* init trace request */ + memset(&msg, 0, sizeof(msg)); + msg.message = ADMIN_TRACE_REQUEST; + msg.u.trace_req.detail = 3; + + /* parse args */ + i = 2; + while(i < argc) + { + if (!strcasecmp(argv[i], "brief")) + msg.u.trace_req.detail = 1; + else if (!strcasecmp(argv[i], "short")) + msg.u.trace_req.detail = 2; + else if (!strncasecmp(argv[i], "category=", 9)) + msg.u.trace_req.category = atoi(argv[i]+9); + else if (!strncasecmp(argv[i], "port=", 5)) + msg.u.trace_req.port = atoi(argv[i]+5); + else if (!strncasecmp(argv[i], "interface=", 10)) + SCPY(msg.u.trace_req.interface, argv[i]+10); + else if (!strncasecmp(argv[i], "caller=", 7)) + SCPY(msg.u.trace_req.caller, argv[i]+7); + else if (!strncasecmp(argv[i], "dialing=", 8)) + SCPY(msg.u.trace_req.dialing, argv[i]+8); + else return("Invalid trace option, try 'trace help'."); + + i++; + } + + /* send trace request */ + if (write(sock, &msg, sizeof(msg)) != sizeof(msg)) + return("Broken pipe while sending trace request."); + + /* receive response */ +next: + if (read(sock, &msg, sizeof(msg)) != sizeof(msg)) + return("Broken pipe while receiving response."); + + if (msg.message != ADMIN_TRACE_RESPONSE) + return("Response not valid."); + + printf("%s", msg.u.trace_rsp.text); + goto next; +} + + +/* + * main function + */ +int main(int argc, char *argv[]) +{ + int mode; + char *socket_name = SOCKET_NAME; + int sock, conn; + struct sockaddr_un sock_address; + char *ret; + + + /* show options */ + if (argc <= 1) + { + usage: + printf("\n"); + printf("Usage: %s state | interface | route | dial ...\n", argv[0]); + printf("state - View current states using graphical console output.\n"); + printf("interface - Tell LCR to reload \"interface.conf\".\n"); + printf("route - Tell LCR to reload \"route.conf\".\n"); + printf("dial - Tell LCR the next number to dial for extension.\n"); + printf("release - Tell LCR to release endpoint with given number.\n"); + printf("block - Block given port.\n"); + printf("unblock - Unblock given port.\n"); + printf("unload - Unload port. To load port use 'block' or 'unblock'.\n"); + printf("testcall [options] [present|restrict []] - Testcall\n"); + printf(" -> options = --setup-timeout --proceeding-timeout \n"); + printf(" --alerting-timeout --connect-timeout \n"); + printf(" -> capability = (Values must be numbers, -1 to omit.)\n"); + printf("trace [brief|short] [ [...]] - Shows call trace. Use filter to reduce output.\n"); + printf(" -> Use 'trace help' to see filter description.\n"); + printf("\n"); + return(0); + } + + /* check mode */ + if (!(strcasecmp(argv[1],"state"))) + { + mode = MODE_STATE; + } else + if (!(strcasecmp(argv[1],"interface"))) + { + mode = MODE_INTERFACE; + } else + if (!(strcasecmp(argv[1],"route"))) + { + mode = MODE_ROUTE; + } else + if (!(strcasecmp(argv[1],"dial"))) + { + if (argc <= 3) + goto usage; + mode = MODE_DIAL; + } else + if (!(strcasecmp(argv[1],"release"))) + { + if (argc <= 2) + goto usage; + mode = MODE_RELEASE; + } else + if (!(strcasecmp(argv[1],"unblock"))) + { + if (argc <= 2) + goto usage; + mode = MODE_UNBLOCK; + } else + if (!(strcasecmp(argv[1],"block"))) + { + if (argc <= 2) + goto usage; + mode = MODE_BLOCK; + } else + if (!(strcasecmp(argv[1],"unload"))) + { + if (argc <= 2) + goto usage; + mode = MODE_UNLOAD; + } else + if (!(strcasecmp(argv[1],"testcall"))) + { + if (argc <= 4) + goto usage; + mode = MODE_TESTCALL; + } else + if (!(strcasecmp(argv[1],"trace"))) + { + mode = MODE_TRACE; + } else + { + goto usage; + } + +//pipeagain: + /* open socket */ + if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) + { + fprintf(stderr, "Failed to create socket.\n"); + exit(EXIT_FAILURE); + } + memset(&sock_address, 0, sizeof(sock_address)); + sock_address.sun_family = PF_UNIX; + UCPY(sock_address.sun_path, socket_name); + if ((conn = connect(sock, (struct sockaddr *)&sock_address, SUN_LEN(&sock_address))) < 0) + { + close(sock); + fprintf(stderr, "Failed to connect to socket \"%s\".\nIs LCR running?\n", sock_address.sun_path); + exit(EXIT_FAILURE); + } + + /* process mode */ + switch(mode) + { + case MODE_STATE: + ret = admin_state(sock, argv); + break; + + case MODE_INTERFACE: + case MODE_ROUTE: + ret = admin_cmd(sock, mode, NULL, NULL); + break; + + case MODE_DIAL: + ret = admin_cmd(sock, mode, argv[2], argv[3]); + break; + + case MODE_RELEASE: + case MODE_UNBLOCK: + case MODE_BLOCK: + case MODE_UNLOAD: + ret = admin_cmd(sock, mode, NULL, argv[2]); + break; + + case MODE_TESTCALL: + ret = admin_testcall(sock, argc, argv); + break; + + case MODE_TRACE: + ret = admin_trace(sock, argc, argv); + break; + } + + close(sock); + /* now we say good bye */ + if (ret) + { +// if (!strncasecmp(ret, "Broken Pipe", 11)) +// goto pipeagain; + printf("%s\n", ret); + exit(EXIT_FAILURE); + } +} + + + + + diff --git a/lcrsocket.h b/lcrsocket.h new file mode 100644 index 0000000..a34820d --- /dev/null +++ b/lcrsocket.h @@ -0,0 +1,185 @@ +/*****************************************************************************\ +** ** +** Linux Call Router ** +** ** +**---------------------------------------------------------------------------** +** Copyright: Andreas Eversberg ** +** ** +** Administration tool header file ** +** ** +\*****************************************************************************/ + +#define SOCKET_NAME "/var/run/LCR.socket" + +/* structures that define message between admin-tool and pbx */ + +enum { /* messages */ + ADMIN_REQUEST_CMD_INTERFACE, + ADMIN_RESPONSE_CMD_INTERFACE, + ADMIN_REQUEST_CMD_ROUTE, + ADMIN_RESPONSE_CMD_ROUTE, + ADMIN_REQUEST_CMD_DIAL, + ADMIN_RESPONSE_CMD_DIAL, + ADMIN_REQUEST_CMD_RELEASE, + ADMIN_RESPONSE_CMD_RELEASE, + ADMIN_REQUEST_CMD_BLOCK, + ADMIN_RESPONSE_CMD_BLOCK, + ADMIN_REQUEST_STATE, + ADMIN_RESPONSE_STATE, + ADMIN_RESPONSE_S_REMOTE, + ADMIN_RESPONSE_S_INTERFACE, + ADMIN_RESPONSE_S_PORT, + ADMIN_RESPONSE_S_EPOINT, + ADMIN_RESPONSE_S_JOIN, + ADMIN_CALL_SETUP, + ADMIN_CALL_SETUP_ACK, + ADMIN_CALL_PROCEEDING, + ADMIN_CALL_ALERTING, + ADMIN_CALL_CONNECT, + ADMIN_CALL_DISCONNECT, + ADMIN_CALL_RELEASE, + ADMIN_CALL_NOTIFY, + ADMIN_TRACE_REQUEST, + ADMIN_TRACE_RESPONSE, + ADMIN_MESSAGE, +}; + +struct admin_response_cmd { + int error; /* error code 0 = ok*/ + char message[256]; /* info / response text */ + int block; + int portnum; +}; + +struct admin_response_state { + char version_string[64]; + struct tm tm; + char logfile[128]; + int interfaces; + int remotes; + int joins; + int epoints; + int ports; +}; + +struct admin_response_interface { + char interface_name[32]; + int portnum; + int block; + int ntmode; + int ptp; + int pri; + int extension; + int use; /* number of ports that use this interface */ + int l1link; /* down(0) or up(1) */ + int l2link; /* down(0) or up(1) */ + int channels; + char busy[256]; /* if port is idle(0) busy(1) */ + unsigned long port[256]; /* current port */ +}; + +struct admin_response_remote { + char name[32]; /* name of remote application */ +}; + +struct admin_response_join { + unsigned long serial; /* join serial number */ + char remote[32]; /* remote application name */ + unsigned long partyline; +}; + +struct admin_response_epoint { + unsigned long serial; + unsigned long join; /* link to join */ +// int join_notify; /* if relation notified on hold */ +// int join_hold; /* if relation on hold */ + int rx_state; + int tx_state; + int state; + char terminal[16]; + char callerid[64]; + char dialing[64]; + char action[32]; + int park; /* if parked */ + int park_len; + unsigned char park_callid[8]; + int crypt; /* crypt state */ +}; + +struct admin_response_port { + unsigned long serial; /* port serial number */ + char name[64]; /* name of port */ + unsigned long epoint; /* link to epoint */ + int state; + int isdn; /* if port is isdn */ + int isdn_chan; /* bchannel number */ + int isdn_hold; /* on hold */ + int isdn_ces; /* ces to use (>=0)*/ +}; + +struct admin_call { + char interface[64]; /* name of port */ + char callerid[64]; /* use caller id */ + char dialing[64]; /* number to dial */ + int present; /* presentation */ + int cause; /* cause to send */ + int location; + int notify; + int bc_capa; + int bc_mode; + int bc_info1; + int hlc; + int exthlc; +}; + +struct admin_trace_req { + int detail; + char category; + int port; + char interface[64]; + char caller[34]; + char dialing[64]; +}; + +struct admin_trace_rsp { + char text[1024]; +}; + +struct admin_msg { + int type; /* type of message */ + unsigned long ref; /* reference to individual endpoints */ + union parameter param; /* parameter union */ +}; + +struct admin_message { + int message; /* type of admin message */ + union u { + struct admin_response_cmd x; + struct admin_response_state s; + struct admin_response_interface i; + struct admin_response_port p; + struct admin_response_epoint e; + struct admin_response_join j; + struct admin_response_remote r; + struct admin_call call; + struct admin_msg msg; + struct admin_trace_req trace_req; + struct admin_trace_rsp trace_rsp; + } u; +}; + +/* call states */ +enum { + ADMIN_STATE_IDLE, + ADMIN_STATE_IN_SETUP, + ADMIN_STATE_OUT_SETUP, + ADMIN_STATE_IN_OVERLAP, + ADMIN_STATE_OUT_OVERLAP, + ADMIN_STATE_IN_PROCEEDING, + ADMIN_STATE_OUT_PROCEEDING, + ADMIN_STATE_IN_ALERTING, + ADMIN_STATE_OUT_ALERTING, + ADMIN_STATE_CONNECT, + ADMIN_STATE_IN_DISCONNECT, + ADMIN_STATE_OUT_DISCONNECT, +}; diff --git a/mISDN.cpp b/mISDN.cpp index 7bd1388..7bdb30d 100644 --- a/mISDN.cpp +++ b/mISDN.cpp @@ -9,7 +9,6 @@ ** ** \*****************************************************************************/ - #include "main.h" #include #include @@ -32,6 +31,43 @@ extern "C" { } #endif +#ifndef CMX_TXDATA_ON +#define OLD_MISDN +#endif +#ifndef CMX_TXDATA_OFF +#define OLD_MISDN +#endif +#ifndef CMX_DELAY +#define OLD_MISDN +#endif +#ifndef PIPELINE_CFG +#define OLD_MISDN +#endif +#ifndef CMX_TX_DATA +#define OLD_MISDN +#endif + +#ifdef OLD_MISDN +#warning +#warning ********************************************************* +#warning * +#warning * It seems that you use an older version of mISDN. +#warning * Features like voice recording or echo will not work. +#warning * Also it causes problems with loading modules and may +#warning * not work at all. +#warning * +#warning * Please upgrade to newer version. A working version can +#warning * be found at www.linux-call-router.de. +#warning * +#warning * Do not use the mISDN_1_1 branch, it does not have all +#warning * the features that are required. Use the master branch +#warning * instead. +#warning * +#warning ********************************************************* +#warning +#error +#endif + #ifndef ISDN_PID_L4_B_USER #define ISDN_PID_L4_B_USER 0x440000ff #endif @@ -633,16 +669,20 @@ static void _bchannel_configure(struct mISDNport *mISDNport, int i) } /* set dsp features */ +#ifndef OLD_MISDN if (port->p_m_txdata) ph_control(mISDNport, port, handle, (port->p_m_txdata)?CMX_TXDATA_ON:CMX_TXDATA_OFF, 0, "DSP-TXDATA", port->p_m_txdata); if (port->p_m_delay) ph_control(mISDNport, port, handle, CMX_DELAY, port->p_m_delay, "DSP-DELAY", port->p_m_delay); +#endif if (port->p_m_tx_gain) ph_control(mISDNport, port, handle, VOL_CHANGE_TX, port->p_m_tx_gain, "DSP-TX_GAIN", port->p_m_tx_gain); if (port->p_m_rx_gain) ph_control(mISDNport, port, handle, VOL_CHANGE_RX, port->p_m_rx_gain, "DSP-RX_GAIN", port->p_m_rx_gain); +#ifndef OLD_MISDN if (port->p_m_pipeline[0]) ph_control_block(mISDNport, port, handle, PIPELINE_CFG, port->p_m_pipeline, strlen(port->p_m_pipeline)+1, "DSP-PIPELINE", 0); +#endif if (port->p_m_conf) ph_control(mISDNport, port, handle, CMX_CONF_JOIN, port->p_m_conf, "DSP-CONF", port->p_m_conf); if (port->p_m_echo) @@ -1570,6 +1610,7 @@ void PmISDN::bchannel_receive(iframe_t *frm) { switch(frm->dinfo) { +#ifndef OLD_MISDN case CMX_TX_DATA: if (!p_m_txdata) { @@ -1585,6 +1626,7 @@ void PmISDN::bchannel_receive(iframe_t *frm) if (p_record) record(data, len, 1); // from up break; +#endif default: chan_trace_header(p_m_mISDNport, this, "BCHANNEL signal", DIRECTION_IN); @@ -1870,12 +1912,14 @@ void PmISDN::message_mISDNsignal(unsigned long epoint_id, int message_id, union { p_m_delay = param->mISDNsignal.delay; PDEBUG(DEBUG_BCHANNEL, "we change delay mode to delay=%d.\n", p_m_delay); +#ifndef OLD_MISDN if (p_m_b_index >= 0) if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE) #ifdef SOCKET_MISDN ph_control(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], p_m_delay?CMX_DELAY:CMX_JITTER, p_m_delay, "DSP-DELAY", p_m_delay); #else ph_control(p_m_mISDNport, this, p_m_mISDNport->b_addr[p_m_b_index], p_m_delay?CMX_DELAY:CMX_JITTER, p_m_delay, "DSP-DELAY", p_m_delay); +#endif #endif } else PDEBUG(DEBUG_BCHANNEL, "we already have delay=%d.\n", p_m_delay); @@ -2208,8 +2252,10 @@ int mISDN_handler(void) /* turn on RX */ isdnport->p_m_txdata = 1; PDEBUG(DEBUG_BCHANNEL, "%s: transmit data is required, so we turn them on\n"); +#ifndef OLD_MISDN if (mISDNport->b_port[i] && mISDNport->b_state[i] == B_STATE_ACTIVE) ph_control(mISDNport, isdnport, mISDNport->b_addr[isdnport->p_m_b_index], CMX_TXDATA_ON, 0, "DSP-TXDATA", 1); +#endif return(1); } } else @@ -2220,8 +2266,10 @@ int mISDN_handler(void) /* turn off RX */ isdnport->p_m_txdata = 0; PDEBUG(DEBUG_BCHANNEL, "%s: transmit data is not required, so we turn them off\n"); +#ifndef OLD_MISDN if (mISDNport->b_port[i] && mISDNport->b_state[i] == B_STATE_ACTIVE) ph_control(mISDNport, isdnport, mISDNport->b_addr[isdnport->p_m_b_index], CMX_TXDATA_OFF, 0, "DSP-TXDATA", 0); +#endif return(1); } } diff --git a/main.h b/main.h index f30a2b4..61ffc80 100644 --- a/main.h +++ b/main.h @@ -140,7 +140,7 @@ extern "C" { #include "alawulaw.h" #include "tones.h" #include "crypt.h" -#include "admin_server.h" +#include "socket_server.h" #include "trace.h" extern double now_d; diff --git a/socket_server.c b/socket_server.c new file mode 100644 index 0000000..2624ad7 --- /dev/null +++ b/socket_server.c @@ -0,0 +1,1323 @@ +/*****************************************************************************\ +** ** +** Linux Call Router ** +** ** +**---------------------------------------------------------------------------** +** Copyright: Andreas Eversberg ** +** ** +** Socket link server ** +** ** +\*****************************************************************************/ + +#include +//#include +//#include +#include +//#include +//#include +//#include +//#include +//#include +#include +//#include +//#include +//#include +//#include +#include +#include +#include +#include "main.h" + + +char *socket_name = SOCKET_NAME; +int sock = -1; +struct sockaddr_un sock_address; + +struct admin_list *admin_first = NULL; + +/* + * initialize admin socket + */ +int admin_init(void) +{ + unsigned long on = 1; + + /* open and bind socket */ + if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) + { + PERROR("Failed to create admin socket. (errno=%d)\n", errno); + return(-1); + } + fhuse++; + memset(&sock_address, 0, sizeof(sock_address)); + sock_address.sun_family = AF_UNIX; + UCPY(sock_address.sun_path, socket_name); + unlink(socket_name); + if (bind(sock, (struct sockaddr *)(&sock_address), SUN_LEN(&sock_address)) < 0) + { + close(sock); + unlink(socket_name); + fhuse--; + sock = -1; + PERROR("Failed to bind admin socket to \"%s\". (errno=%d)\n", sock_address.sun_path, errno); + return(-1); + } + if (listen(sock, 5) < 0) + { + close(sock); + unlink(socket_name); + fhuse--; + sock = -1; + PERROR("Failed to listen to socket \"%s\". (errno=%d)\n", sock_address.sun_path, errno); + return(-1); + } + if (ioctl(sock, FIONBIO, (unsigned char *)(&on)) < 0) + { + close(sock); + unlink(socket_name); + fhuse--; + sock = -1; + PERROR("Failed to set socket \"%s\" into non-blocking mode. (errno=%d)\n", sock_address.sun_path, errno); + return(-1); + } + return(0); +} + + +/* + * free connection + * also releases all remote joins + */ +void free_connection(struct admin_list *admin) +{ + struct admin_queue *response; + void *temp; + union parameter param; + class Join *join, *joinnext; + + /* free remote joins */ + if (admin->remote_name[0]) + { + join = join_first; + while(join) + { + joinnext = join->next; + if (join->j_type==JOIN_TYPE_REMOTE) if (((class JoinRemote *)join)->j_remote_id == admin->sock) + { + memset(¶m, 0, sizeof(param)); + param.disconnectinfo.cause = CAUSE_OUTOFORDER; + param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL; + ((class JoinRemote *)join)->message_remote(MESSAGE_RELEASE, ¶m); + /* join is now destroyed, so we go to next join */ + } + join = joinnext; + } + } + + if (admin->sock >= 0) + { + close(admin->sock); + fhuse--; + } +// printf("new\n", response); + response = admin->response; + while (response) + { +//#warning +// printf("%x\n", response); + temp = response->next; + FREE(response, 0); + memuse--; + response = (struct admin_queue *)temp; + } +// printf("new2\n", response); + FREE(admin, 0); +// printf("new3\n", response); + memuse--; +} + + +/* + * cleanup admin socket + */ +void admin_cleanup(void) +{ + struct admin_list *admin, *next;; + + admin = admin_first; + while(admin) + { +//printf("clean\n"); + next = admin->next; + free_connection(admin); + admin = next; + } + + if (sock >= 0) + { + close(sock); + fhuse--; + } +} + + +/* + * do interface reload + */ +int admin_interface(struct admin_queue **responsep) +{ + struct admin_queue *response; /* response pointer */ + char *err_txt = ""; + int err = 0; + + if (read_interfaces()) + { + relink_interfaces(); + free_interfaces(interface_first); + interface_first = interface_newlist; + interface_newlist = NULL; + } else + { + err_txt = interface_error; + err = -1; + } + /* create state response */ + response = (struct admin_queue *)MALLOC(sizeof(struct admin_queue)+sizeof(admin_message)); + memuse++; + response->num = 1; + /* message */ + response->am[0].message = ADMIN_RESPONSE_CMD_INTERFACE; + /* error */ + response->am[0].u.x.error = err; + /* message */ + SCPY(response->am[0].u.x.message, err_txt); + /* attach to response chain */ + *responsep = response; + responsep = &response->next; + + return(0); +} + + +/* + * do route reload + */ +int admin_route(struct admin_queue **responsep) +{ + struct route_ruleset *ruleset_new; + struct admin_queue *response; /* response pointer */ + char err_txt[256] = ""; + int err = 0; +#if 0 + int n; +#endif + class EndpointAppPBX *apppbx; + +#if 0 + n = 0; + apppbx = apppbx_first; + while(apppbx) + { + n++; + apppbx = apppbx->next; + } + if (apppbx_first) + { + SPRINT(err_txt, "Cannot reload routing, because %d endpoints active\n", n); + err = -1; + goto response; + } +#endif + if (!(ruleset_new = ruleset_parse())) + { + SPRINT(err_txt, ruleset_error); + err = -1; + goto response; + } + ruleset_free(ruleset_first); + ruleset_first = ruleset_new; + ruleset_main = getrulesetbyname("main"); + if (!ruleset_main) + { + SPRINT(err_txt, "Ruleset reloaded, but rule 'main' not found.\n"); + err = -1; + } + apppbx = apppbx_first; + while(apppbx) + { + if (apppbx->e_action) + { + switch(apppbx->e_action->index) + { + case ACTION_INTERNAL: + apppbx->e_action = &action_internal; + break; + case ACTION_EXTERNAL: + apppbx->e_action = &action_external; + break; + case ACTION_REMOTE: + apppbx->e_action = &action_remote; + break; + case ACTION_VBOX_RECORD: + apppbx->e_action = &action_vbox; + break; + case ACTION_PARTYLINE: + apppbx->e_action = &action_partyline; + break; + default: + goto release; + } + } else if (apppbx->e_state != EPOINT_STATE_CONNECT) + { + release: + apppbx->e_callback = 0; + apppbx->e_action = NULL; + apppbx->release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); + start_trace(0, + NULL, + numberrize_callerinfo(apppbx->e_callerinfo.id, apppbx->e_callerinfo.ntype), + apppbx->e_dialinginfo.id, + DIRECTION_NONE, + CATEGORY_EP, + apppbx->ea_endpoint->ep_serial, + "KICK (reload routing)"); + end_trace(); + } + + apppbx->e_action_timeout = NULL; + apppbx->e_rule = NULL; + apppbx->e_ruleset = NULL; + + apppbx = apppbx->next; + } + + response: + /* create state response */ + response = (struct admin_queue *)MALLOC(sizeof(struct admin_queue)+sizeof(admin_message)); + memuse++; + response->num = 1; + /* message */ + response->am[0].message = ADMIN_RESPONSE_CMD_ROUTE; + /* error */ + response->am[0].u.x.error = err; + /* message */ + SCPY(response->am[0].u.x.message, err_txt); + /* attach to response chain */ + *responsep = response; + responsep = &response->next; + + return(0); +} + + +/* + * do dialing + */ +int admin_dial(struct admin_queue **responsep, char *message) +{ + struct extension ext; /* temporary extension's settings */ + struct admin_queue *response; /* response pointer */ + char *p; /* pointer to dialing digits */ + + /* create state response */ + response = (struct admin_queue *)MALLOC(sizeof(struct admin_queue)+sizeof(admin_message)); + memuse++; + response->num = 1; + /* message */ + response->am[0].message = ADMIN_RESPONSE_CMD_DIAL; + + /* process request */ + if (!(p = strchr(message,':'))) + { + response->am[0].u.x.error = -EINVAL; + SPRINT(response->am[0].u.x.message, "no seperator ':' in message to seperate number from extension"); + goto out; + } + *p++ = 0; + + /* modify extension */ + if (!read_extension(&ext, message)) + { + response->am[0].u.x.error = -EINVAL; + SPRINT(response->am[0].u.x.message, "extension doesn't exist"); + goto out; + } + SCPY(ext.next, p); + write_extension(&ext, message); + + out: + /* attach to response chain */ + *responsep = response; + responsep = &response->next; + return(0); +} + + +/* + * do tracing + */ +int admin_trace(struct admin_list *admin, struct admin_trace_req *trace) +{ + memcpy(&admin->trace, trace, sizeof(struct admin_trace_req)); + return(0); +} + + +/* + * do blocking + * + * 0 = make port available + * 1 = make port administratively blocked + * 2 = unload port + * the result is returned: + * 0 = port is now available + * 1 = port is now blocked + * 2 = port cannot be loaded or has been unloaded + * -1 = port doesn't exist + */ +int admin_block(struct admin_queue **responsep, int portnum, int block) +{ + struct admin_queue *response; /* response pointer */ + struct interface *interface; + struct interface_port *ifport; + + /* create block response */ + response = (struct admin_queue *)MALLOC(sizeof(struct admin_queue)+sizeof(admin_message)); + memuse++; + response->num = 1; + /* message */ + response->am[0].message = ADMIN_RESPONSE_CMD_BLOCK; + response->am[0].u.x.portnum = portnum; + + /* search for port */ + interface = interface_first; + while(interface) + { + ifport = interface->ifport; + while(ifport) + { + if (ifport->portnum == portnum) + break; + ifport = ifport->next; + } + if (ifport) + break; + interface = interface->next; + } + /* not found, we return -1 */ + if (!ifport) + { + response->am[0].u.x.block = -1; + response->am[0].u.x.error = 1; + SPRINT(response->am[0].u.x.message, "Port %d does not exist.", portnum); + goto out; + } + + /* no interface */ + if (!ifport->mISDNport) + { + /* not loaded anyway */ + if (block >= 2) + { + response->am[0].u.x.block = 2; + goto out; + } + + /* try loading interface */ + ifport->block = block; + load_port(ifport); + + /* port cannot load */ + if (ifport->block >= 2) + { + response->am[0].u.x.block = 2; + response->am[0].u.x.error = 1; + SPRINT(response->am[0].u.x.message, "Port %d will not load.", portnum); + goto out; + } + + /* port loaded */ + response->am[0].u.x.block = ifport->block; + goto out; + } + + /* if we shall unload interface */ + if (block >= 2) + { + mISDNport_close(ifport->mISDNport); + ifport->mISDNport = 0; + ifport->block = 2; + goto out; + } + + /* port new blocking state */ + ifport->block = response->am[0].u.x.block = block; + + out: + /* attach to response chain */ + *responsep = response; + responsep = &response->next; + return(0); +} + + +/* + * do release + */ +int admin_release(struct admin_queue **responsep, char *message) +{ + unsigned long id; + struct admin_queue *response; /* response pointer */ + class EndpointAppPBX *apppbx; + + /* create state response */ + response = (struct admin_queue *)MALLOC(sizeof(struct admin_queue)+sizeof(admin_message)); + memuse++; + response->num = 1; + /* message */ + response->am[0].message = ADMIN_RESPONSE_CMD_RELEASE; + + id = atoi(message); + apppbx = apppbx_first; + while(apppbx) + { + if (apppbx->ea_endpoint->ep_serial == id) + break; + apppbx = apppbx->next; + } + if (!apppbx) + { + response->am[0].u.x.error = -EINVAL; + SPRINT(response->am[0].u.x.message, "Given endpoint %d doesn't exist.", id); + goto out; + } + + apppbx->e_callback = 0; + apppbx->release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); + + out: + /* attach to response chain */ + *responsep = response; + responsep = &response->next; + return(0); +} + + +/* + * do call + */ +int admin_call(struct admin_list *admin, struct admin_message *msg) +{ + class Endpoint *epoint; + class EndpointAppPBX *apppbx; + + if (!(epoint = new Endpoint(0, 0))) + FATAL("No memory for Endpoint instance\n"); + if (!(epoint->ep_app = apppbx = new DEFAULT_ENDPOINT_APP(epoint, 1))) // outgoing + FATAL("No memory for Endpoint Application instance\n"); + apppbx->e_adminid = admin->sockserial; + admin->epointid = epoint->ep_serial; + SCPY(apppbx->e_callerinfo.id, nationalize_callerinfo(msg->u.call.callerid, &apppbx->e_callerinfo.ntype)); + if (msg->u.call.present) + apppbx->e_callerinfo.present = INFO_PRESENT_ALLOWED; + else + apppbx->e_callerinfo.present = INFO_PRESENT_RESTRICTED; + apppbx->e_callerinfo.screen = INFO_SCREEN_NETWORK; + +//printf("hh=%d\n", apppbx->e_capainfo.hlc); + + apppbx->e_capainfo.bearer_capa = msg->u.call.bc_capa; + apppbx->e_capainfo.bearer_mode = msg->u.call.bc_mode; + apppbx->e_capainfo.bearer_info1 = msg->u.call.bc_info1; + apppbx->e_capainfo.hlc = msg->u.call.hlc; + apppbx->e_capainfo.exthlc = msg->u.call.exthlc; + SCPY(apppbx->e_dialinginfo.id, msg->u.call.dialing); + SCPY(apppbx->e_dialinginfo.interfaces, msg->u.call.interface); + apppbx->e_dialinginfo.sending_complete = 1; + + apppbx->new_state(PORT_STATE_OUT_SETUP); + apppbx->out_setup(); + return(0); +} + + +/* + * this function is called for response whenever a call state changes. + */ +void admin_call_response(int adminid, int message, char *connected, int cause, int location, int notify) +{ + struct admin_list *admin; + struct admin_queue *response, **responsep; /* response pointer */ + + /* searching for admin id + * maybe there is no admin instance, because the calling port was not + * initiated by admin_call */ + admin = admin_first; + while(admin) + { + if (adminid == admin->sockserial) + break; + admin = admin->next; + } + if (!admin) + return; + + /* seek to end of response list */ + response = admin->response; + responsep = &admin->response; + while(response) + { + responsep = &response->next; + response = response->next; + } + + /* create state response */ + response = (struct admin_queue *)MALLOC(sizeof(struct admin_queue)+sizeof(admin_message)); + memuse++; + response->num = 1; + /* message */ + response->am[0].message = message; +// printf("MESSAGE: %d\n", message); + + SCPY(response->am[0].u.call.callerid, connected); + response->am[0].u.call.cause = cause; + response->am[0].u.call.location = location; + response->am[0].u.call.notify = notify; + + /* attach to response chain */ + *responsep = response; + responsep = &response->next; +} + + +/* + * send data to the remote socket join instance + */ +int admin_message_to_join(struct admin_msg *msg, char *remote_name, int sock_id) +{ + class Join *join; + struct admin_list *admin; + + /* hello message */ + if (msg->type == MESSAGE_HELLO) + { + if (remote_name[0]) + { + PERROR("Remote application repeats hello message.\n"); + return(-1); + } + /* look for second application */ + admin = admin_first; + while(admin) + { + if (!strcmp(admin->remote_name, msg->param.hello.application)) + break; + admin = admin->next; + } + if (admin) + { + PERROR("Remote application connects twice??? (ignoring)\n"); + return(-1); + } + /* set remote socket instance */ + SCPY(remote_name, msg->param.hello.application); + return(0); + } + + /* check we have no application name */ + if (remote_name[0]) + { + PERROR("Remote application did not send us a hello message.\n"); + return(-1); + } + + /* new join */ + if (msg->type == MESSAGE_NEWREF) + { + /* create new join instance */ + join = new JoinRemote(0, remote_name, sock_id); // must have no serial, because no endpoint is connected + if (!join) + FATAL("No memory for remote join instance\n"); + return(0); + } + + /* bchannel message + * no ref given for *_ack */ + if (msg->type == MESSAGE_BCHANNEL) + if (msg->param.bchannel.type == BCHANNEL_ASSIGN_ACK + || msg->param.bchannel.type == BCHANNEL_REMOVE_ACK) + { + /* no ref, but address */ + message_bchannel_from_join(NULL, msg->param.bchannel.type, msg->param.bchannel.handle); + return(0); + } + + /* check for ref */ + if (!msg->ref) + { + PERROR("Remote application did not send us a valid ref with a message.\n"); + return(-1); + } + + /* find join instance */ + join = join_first; + while(join) + { + if (join->j_serial == msg->ref) + break; + join = join->next; + } + if (!join) + { + PERROR("No join found with serial %d.\n", msg->ref); + return(-1); + } + + /* check application */ + if (join->j_type != JOIN_TYPE_REMOTE) + { + PERROR("Ref %d does not belong to a remote join instance.\n", msg->ref); + return(-1); + } + if (sock_id != ((class JoinRemote *)join)->j_remote_id) + { + PERROR("Ref %d belongs to remote application %s, but not to sending application %s.\n", msg->ref, ((class JoinRemote *)join)->j_remote_name, remote_name); + return(-1); + } + + /* send message */ + ((class JoinRemote *)join)->message_remote(msg->type, &msg->param); + + return(0); +} + + +/* + * this function is called for every message to remote socket + */ +int admin_message_from_join(int remote_id, unsigned long ref, int message_type, union parameter *param) +{ + struct admin_list *admin; + struct admin_queue *response, **responsep; /* response pointer */ + + /* searching for admin id + * maybe there is no given remote application + */ + admin = admin_first; + while(admin) + { + if (admin->remote_name[0] && admin->sock==remote_id) + break; + admin = admin->next; + } + /* no given remote application connected */ + if (!admin) + return(-1); + + /* seek to end of response list */ + response = admin->response; + responsep = &admin->response; + while(response) + { + responsep = &response->next; + response = response->next; + } + + /* create state response */ + response = (struct admin_queue *)MALLOC(sizeof(struct admin_queue)+sizeof(admin_message)); + memuse++; + response->num = 1; + + /* message */ + response->am[0].u.msg.type = message_type; + response->am[0].u.msg.ref = ref; + memcpy(&response->am[0].u.msg.param, param, sizeof(union parameter)); + + /* attach to response chain */ + *responsep = response; + responsep = &response->next; + + return(0); +} + + +/* + * do state debugging + */ +int admin_state(struct admin_queue **responsep) +{ + + class Port *port; + class EndpointAppPBX *apppbx; + class Join *join; + class Pdss1 *pdss1; + struct interface *interface; + struct interface_port *ifport; + struct mISDNport *mISDNport; + int i; + int num; + int anybusy; + struct admin_queue *response; + struct admin_list *admin; + + /* create state response */ + response = (struct admin_queue *)MALLOC(sizeof(struct admin_queue)+sizeof(admin_message)); + memuse++; + response->num = 1; + /* message */ + response->am[0].message = ADMIN_RESPONSE_STATE; + /* version */ + SCPY(response->am[0].u.s.version_string, VERSION_STRING); + /* time */ + memcpy(&response->am[0].u.s.tm, now_tm, sizeof(struct tm)); + /* log file */ + SCPY(response->am[0].u.s.logfile, options.log); + /* interface count */ + i = 0; + interface = interface_first; + while(interface) + { + ifport = interface->ifport; + while(ifport) + { + i++; + ifport = ifport->next; + } + interface = interface->next; + } + response->am[0].u.s.interfaces = i; + /* remote connection count */ + i = 0; + admin = admin_first; + while(admin) + { + if (admin->remote_name[0]) + i++; + admin = admin->next; + } + response->am[0].u.s.remotes = i; + /* join count */ + join = join_first; + i = 0; + while(join) + { + i++; + join = join->next; + } + response->am[0].u.s.joins = i; + /* apppbx count */ + apppbx = apppbx_first; + i = 0; + while(apppbx) + { + i++; + apppbx = apppbx->next; + } + response->am[0].u.s.epoints = i; + /* port count */ + i = 0; + port = port_first; + while(port) + { + i++; + port = port->next; + } + response->am[0].u.s.ports = i; + /* attach to response chain */ + *responsep = response; + responsep = &response->next; + + /* create response for all interfaces */ + num = (response->am[0].u.s.interfaces)+(response->am[0].u.s.joins)+(response->am[0].u.s.epoints)+(response->am[0].u.s.ports); + if (num == 0) + return(0); + response = (struct admin_queue *)MALLOC(sizeof(admin_queue)+(num*sizeof(admin_message))); + memuse++; + response->num = num; + *responsep = response; + responsep = &response->next; + interface = interface_first; + num = 0; + while(interface) + { + ifport = interface->ifport; + while(ifport) + { + /* message */ + response->am[num].message = ADMIN_RESPONSE_S_INTERFACE; + /* interface */ + SCPY(response->am[num].u.i.interface_name, interface->name); + /* portnum */ + response->am[num].u.i.portnum = ifport->portnum; + /* iftype */ + response->am[num].u.i.extension = interface->extension; + /* block */ + response->am[num].u.i.block = ifport->block; + if (ifport->mISDNport) + { + mISDNport = ifport->mISDNport; + + /* ptp */ + response->am[num].u.i.ptp = mISDNport->ptp; + /* ntmode */ + response->am[num].u.i.ntmode = mISDNport->ntmode; + /* pri */ + response->am[num].u.i.pri = mISDNport->pri; + /* use */ + response->am[num].u.i.use = mISDNport->use; + /* l1link */ + response->am[num].u.i.l1link = mISDNport->l1link; + /* l2link */ + response->am[num].u.i.l2link = mISDNport->l2link; + /* channels */ + response->am[num].u.i.channels = mISDNport->b_num; + /* channel info */ + i = 0; + anybusy = 0; + while(i < mISDNport->b_num) + { + response->am[num].u.i.busy[i] = mISDNport->b_state[i]; + if (mISDNport->b_port[i]) + response->am[num].u.i.port[i] = mISDNport->b_port[i]->p_serial; + i++; + } + } + num++; + + ifport = ifport->next; + } + interface = interface->next; + } + + /* create response for all remotes */ + admin = admin_first; + while(admin) + { + if (admin->remote_name[0]) + { + /* message */ + response->am[num].message = ADMIN_RESPONSE_S_REMOTE; + /* name */ + SCPY(response->am[num].u.r.name, admin->remote_name); + /* */ + num++; + } + admin = admin->next; + } + + /* create response for all joins */ + join = join_first; + while(join) + { + /* message */ + response->am[num].message = ADMIN_RESPONSE_S_JOIN; + /* serial */ + response->am[num].u.j.serial = join->j_serial; + /* partyline */ + if (join->j_type == JOIN_TYPE_PBX) + response->am[num].u.j.partyline = ((class JoinPBX *)join)->j_partyline; + /* remote application */ + if (join->j_type == JOIN_TYPE_REMOTE) + SCPY(response->am[num].u.j.remote, ((class JoinRemote *)join)->j_remote_name); + /* */ + join = join->next; + num++; + } + + /* create response for all endpoint */ + apppbx = apppbx_first; + while(apppbx) + { + /* message */ + response->am[num].message = ADMIN_RESPONSE_S_EPOINT; + /* serial */ + response->am[num].u.e.serial = apppbx->ea_endpoint->ep_serial; + /* join */ + response->am[num].u.e.join = apppbx->ea_endpoint->ep_join_id; + /* rx notification */ + response->am[num].u.e.rx_state = apppbx->e_rx_state; + /* tx notification */ + response->am[num].u.e.tx_state = apppbx->e_tx_state; + /* state */ + switch(apppbx->e_state) + { + case EPOINT_STATE_IN_SETUP: + response->am[num].u.e.state = ADMIN_STATE_IN_SETUP; + break; + case EPOINT_STATE_OUT_SETUP: + response->am[num].u.e.state = ADMIN_STATE_OUT_SETUP; + break; + case EPOINT_STATE_IN_OVERLAP: + response->am[num].u.e.state = ADMIN_STATE_IN_OVERLAP; + break; + case EPOINT_STATE_OUT_OVERLAP: + response->am[num].u.e.state = ADMIN_STATE_OUT_OVERLAP; + break; + case EPOINT_STATE_IN_PROCEEDING: + response->am[num].u.e.state = ADMIN_STATE_IN_PROCEEDING; + break; + case EPOINT_STATE_OUT_PROCEEDING: + response->am[num].u.e.state = ADMIN_STATE_OUT_PROCEEDING; + break; + case EPOINT_STATE_IN_ALERTING: + response->am[num].u.e.state = ADMIN_STATE_IN_ALERTING; + break; + case EPOINT_STATE_OUT_ALERTING: + response->am[num].u.e.state = ADMIN_STATE_OUT_ALERTING; + break; + case EPOINT_STATE_CONNECT: + response->am[num].u.e.state = ADMIN_STATE_CONNECT; + break; + case EPOINT_STATE_IN_DISCONNECT: + response->am[num].u.e.state = ADMIN_STATE_IN_DISCONNECT; + break; + case EPOINT_STATE_OUT_DISCONNECT: + response->am[num].u.e.state = ADMIN_STATE_OUT_DISCONNECT; + break; + default: + response->am[num].u.e.state = ADMIN_STATE_IDLE; + } + /* terminal */ + SCPY(response->am[num].u.e.terminal, apppbx->e_ext.number); + /* callerid */ + SCPY(response->am[num].u.e.callerid, apppbx->e_callerinfo.id); + /* dialing */ + SCPY(response->am[num].u.e.dialing, apppbx->e_dialinginfo.id); + /* action string */ + if (apppbx->e_action) + SCPY(response->am[num].u.e.action, action_defs[apppbx->e_action->index].name); +// if (apppbx->e_action) +// printf("action=%s\n",action_defs[apppbx->e_action->index].name); + /* park */ + response->am[num].u.e.park = apppbx->ea_endpoint->ep_park; + if (apppbx->ea_endpoint->ep_park && apppbx->ea_endpoint->ep_park_len && apppbx->ea_endpoint->ep_park_len<=(int)sizeof(response->am[num].u.e.park_callid)) + memcpy(response->am[num].u.e.park_callid, apppbx->ea_endpoint->ep_park_callid, apppbx->ea_endpoint->ep_park_len); + response->am[num].u.e.park_len = apppbx->ea_endpoint->ep_park_len; + /* crypt */ + if (apppbx->e_crypt == CRYPT_ON) + response->am[num].u.e.crypt = 1; + /* */ + apppbx = apppbx->next; + num++; + } + + /* create response for all ports */ + port = port_first; + while(port) + { + /* message */ + response->am[num].message = ADMIN_RESPONSE_S_PORT; + /* serial */ + response->am[num].u.p.serial = port->p_serial; + /* name */ + SCPY(response->am[num].u.p.name, port->p_name); + /* epoint */ + response->am[num].u.p.epoint = ACTIVE_EPOINT(port->p_epointlist); + /* state */ + switch(port->p_state) + { + case PORT_STATE_IN_SETUP: + response->am[num].u.p.state = ADMIN_STATE_IN_SETUP; + break; + case PORT_STATE_OUT_SETUP: + response->am[num].u.p.state = ADMIN_STATE_OUT_SETUP; + break; + case PORT_STATE_IN_OVERLAP: + response->am[num].u.p.state = ADMIN_STATE_IN_OVERLAP; + break; + case PORT_STATE_OUT_OVERLAP: + response->am[num].u.p.state = ADMIN_STATE_OUT_OVERLAP; + break; + case PORT_STATE_IN_PROCEEDING: + response->am[num].u.p.state = ADMIN_STATE_IN_PROCEEDING; + break; + case PORT_STATE_OUT_PROCEEDING: + response->am[num].u.p.state = ADMIN_STATE_OUT_PROCEEDING; + break; + case PORT_STATE_IN_ALERTING: + response->am[num].u.p.state = ADMIN_STATE_IN_ALERTING; + break; + case PORT_STATE_OUT_ALERTING: + response->am[num].u.p.state = ADMIN_STATE_OUT_ALERTING; + break; + case PORT_STATE_CONNECT: + response->am[num].u.p.state = ADMIN_STATE_CONNECT; + break; + case PORT_STATE_IN_DISCONNECT: + response->am[num].u.p.state = ADMIN_STATE_IN_DISCONNECT; + break; + case PORT_STATE_OUT_DISCONNECT: + response->am[num].u.p.state = ADMIN_STATE_OUT_DISCONNECT; + break; + default: + response->am[num].u.p.state = ADMIN_STATE_IDLE; + } + /* isdn */ + if ((port->p_type&PORT_CLASS_mISDN_MASK) == PORT_CLASS_mISDN_DSS1) + { + response->am[num].u.p.isdn = 1; + pdss1 = (class Pdss1 *)port; + response->am[num].u.p.isdn_chan = pdss1->p_m_b_channel; + response->am[num].u.p.isdn_hold = pdss1->p_m_hold; + response->am[num].u.p.isdn_ces = pdss1->p_m_d_ces; + } + /* */ + port = port->next; + num++; + } + return(0); +} + +int sockserial = 1; // must start with 1, because 0 is used if no serial is set +/* + * handle admin socket (non blocking) + */ +int admin_handle(void) +{ + struct admin_list *admin, **adminp; + void *temp; + struct admin_message msg; + int len; + int new_sock; + socklen_t sock_len = sizeof(sock_address); + unsigned long on = 1; + int work = 0; /* if work was done */ + struct Endpoint *epoint; + + if (sock < 0) + return(0); + + /* check for new incoming connections */ + if ((new_sock = accept(sock, (struct sockaddr *)&sock_address, &sock_len)) >= 0) + { + work = 1; + /* insert new socket */ + admin = (struct admin_list *)MALLOC(sizeof(struct admin_list)); + if (ioctl(new_sock, FIONBIO, (unsigned char *)(&on)) >= 0) + { +//#warning +// PERROR("DEBUG incoming socket %d, serial=%d\n", new_sock, sockserial); + memuse++; + fhuse++; + admin->sockserial = sockserial++; + admin->next = admin_first; + admin_first = admin; + admin->sock = new_sock; + } else { + close(new_sock); + FREE(admin, sizeof(struct admin_list)); + } + } else + { + if (errno != EWOULDBLOCK) + { + PERROR("Failed to accept connection from socket \"%s\". (errno=%d) Closing socket.\n", sock_address.sun_path, errno); + admin_cleanup(); + return(1); + } + } + + /* loop all current socket connections */ + admin = admin_first; + adminp = &admin_first; + while(admin) + { + /* read command */ + len = read(admin->sock, &msg, sizeof(msg)); + if (len < 0) + { + if (errno != EWOULDBLOCK) + { + work = 1; + brokenpipe: + printf("Broken pipe on socket %d. (errno=%d).\n", admin->sock, errno); + PDEBUG(DEBUG_LOG, "Broken pipe on socket %d. (errno=%d).\n", admin->sock, errno); + *adminp = admin->next; + free_connection(admin); + admin = *adminp; + continue; + } + goto send_data; + } + work = 1; +//#warning +//PERROR("DEBUG socket %d got data. serial=%d\n", admin->sock, admin->sockserial); + if (len == 0) + { + end: + + /*release endpoint if exists */ + if (admin->epointid) + { + epoint = find_epoint_id(admin->epointid); + if (epoint) + { + ((class DEFAULT_ENDPOINT_APP *)epoint->ep_app)-> + release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); + } + } + +//#warning +//PERROR("DEBUG socket %d closed by remote.\n", admin->sock); + *adminp = admin->next; + free_connection(admin); + admin = *adminp; +//PERROR("DEBUG (admin_first=%x)\n", admin_first); + continue; + } + if (len != sizeof(msg)) + { + PERROR("Short/long read on socket %d. (len=%d != size=%d).\n", admin->sock, len, sizeof(msg)); + *adminp = admin->next; + free_connection(admin); + admin = *adminp; + continue; + } + /* process socket command */ + if (admin->response) + { + PERROR("Data from socket %d while sending response.\n", admin->sock); + *adminp = admin->next; + free_connection(admin); + admin = *adminp; + continue; + } + switch (msg.message) + { + case ADMIN_REQUEST_CMD_INTERFACE: + if (admin_interface(&admin->response) < 0) + { + PERROR("Failed to create dial response for socket %d.\n", admin->sock); + goto response_error; + } + break; + + case ADMIN_REQUEST_CMD_ROUTE: + if (admin_route(&admin->response) < 0) + { + PERROR("Failed to create dial response for socket %d.\n", admin->sock); + goto response_error; + } + break; + + case ADMIN_REQUEST_CMD_DIAL: + if (admin_dial(&admin->response, msg.u.x.message) < 0) + { + PERROR("Failed to create dial response for socket %d.\n", admin->sock); + goto response_error; + } + break; + + case ADMIN_REQUEST_CMD_RELEASE: + if (admin_release(&admin->response, msg.u.x.message) < 0) + { + PERROR("Failed to create release response for socket %d.\n", admin->sock); + goto response_error; + } + break; + + case ADMIN_REQUEST_STATE: + if (admin_state(&admin->response) < 0) + { + PERROR("Failed to create state response for socket %d.\n", admin->sock); + goto response_error; + } + break; + + case ADMIN_TRACE_REQUEST: + if (admin_trace(admin, &msg.u.trace_req) < 0) + { + PERROR("Failed to create trace response for socket %d.\n", admin->sock); + goto response_error; + } + break; + + case ADMIN_REQUEST_CMD_BLOCK: + if (admin_block(&admin->response, msg.u.x.portnum, msg.u.x.block) < 0) + { + PERROR("Failed to create block response for socket %d.\n", admin->sock); + goto response_error; + } + break; + + case ADMIN_MESSAGE: + if (admin_message_to_join(&msg.u.msg, admin->remote_name, admin->sock) < 0) + { + PERROR("Failed to deliver message for socket %d.\n", admin->sock); + goto response_error; + } +#if 0 +#warning DEBUGGING +{ + struct admin_queue *response; + printf("Chain: "); + response = admin->response; + while(response) + { + printf("%c", '0'+response->am[0].message); + response=response->next; + } + printf("\n"); +} +#endif + break; + + case ADMIN_CALL_SETUP: + if (admin_call(admin, &msg) < 0) + { + PERROR("Failed to create call for socket %d.\n", admin->sock); + response_error: + *adminp = admin->next; + free_connection(admin); + admin = *adminp; + continue; + } + break; + + default: + PERROR("Invalid message %d from socket %d.\n", msg.message, admin->sock); + *adminp = admin->next; + free_connection(admin); + admin = *adminp; + continue; + } + /* write queue */ + send_data: + if (admin->response) + { +//#warning +//PERROR("DEBUG socket %d sending data.\n", admin->sock); + len = write(admin->sock, ((unsigned char *)(admin->response->am))+admin->response->offset, sizeof(struct admin_message)*(admin->response->num)-admin->response->offset); + if (len < 0) + { + if (errno != EWOULDBLOCK) + { + work = 1; + goto brokenpipe; + } + goto next; + } + work = 1; + if (len == 0) + goto end; + if (len < (int)(sizeof(struct admin_message)*(admin->response->num)-admin->response->offset)) + { + admin->response->offset+=len; + goto next; + } else + { + temp = admin->response; + admin->response = admin->response->next; + FREE(temp, 0); + memuse--; + } + } + /* done with socket instance */ + next: + adminp = &admin->next; + admin = admin->next; + } + + return(work); +} + diff --git a/socket_server.h b/socket_server.h new file mode 100644 index 0000000..305deb5 --- /dev/null +++ b/socket_server.h @@ -0,0 +1,40 @@ +/*****************************************************************************\ +** ** +** PBX4Linux ** +** ** +**---------------------------------------------------------------------------** +** Copyright: Andreas Eversberg ** +** ** +** Administration tool header file (server) ** +** ** +\*****************************************************************************/ + +#include "lcrsocket.h" + +struct admin_queue { + struct admin_queue *next; + ulong offset; /* current offset writing */ + ulong num; /* number of admin messages */ + struct admin_message am[0]; +}; + +struct admin_list { + struct admin_list *next; + int sock; + int sockserial; + char remote_name[32]; /* socket is connected remote application */ + struct admin_trace_req trace; /* stores trace, if detail != 0 */ + unsigned long epointid; + struct admin_queue *response; +}; + +extern struct admin_list *admin_first; +int admin_init(void); +void admin_cleanup(void); +int admin_handle(void); +void admin_call_response(int adminid, int message, char *connected, int cause, int location, int notify); +int admin_message_to_join(struct admin_message *msg, int remote_id); +int admin_message_from_join(int remote_id, unsigned long ref, int message_type, union parameter *param); + + + diff --git a/todo.txt b/todo.txt index e43d19b..72615af 100644 --- a/todo.txt +++ b/todo.txt @@ -1,3 +1,25 @@ +chan_lcr: + +show calls +show lcr +block/unblock port +reload interfaces/routing +release call + +setup: es werden setupdaten gespeichert, bis eine ref vom lcr erfolgt. +dabei werden zusätzliche wahlinformationen der rufummer hinzugefügt. + +bridge: jede instanz (chan_call) hat eine bridge_id +wenn keine bridge, dann ist sie 0. +mit new_bridge_id() wird eine neue id gesucht. diese wird in beide instanzen eingetragen +zudem wird fuer jede instanz (zwei) der bridge eine bchannel_join ausgeführt, wenn die bchannels verfügbar sind. +schon implementiert: falls der bchannel später kommt, wird der join beim exporieren des b-channels ausgeführt. + + + + + + doku: rx_vol -> rx_gain context @@ -26,20 +48,5 @@ delay - per param setzen, lokal als mISDNsignal und remote mittels setup -old stuff.... - -NOTE: check CENTREX - -durchstellen mit disconnect -durchstellen mit keypad -short ring -sleep relaxed -auto pick -alarm clock (timer) -sonderwahlton -facility: diversion, 3pty, ... - - - -- cgit v1.2.3-55-g7522