From 877a2dfd52782f72ba2d28483212166f2326b1fa Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sat, 14 Jan 2012 18:36:26 +0100 Subject: [PATCH] Adding bridge between protocol handlers (ports) This is required to bridge traffic beween non-mISDN handlers, such as GSM, SIP and voice box. Also it bridges traffic between mISDN handlers and non-mISDN handlers. It is the fundamental step to get rid of mISDN (loop interface) for non-mISDN handlers. This is required to bridge audio e.g. between SIP and GSM without using mISDN. There will be no limitations on 'b-channels' anymore. Still GSM and SIP requires mISDN, but this will be changed later. With that bridge I cleaned up some code and also removed the MESSAGE_DATA, which is not required anymore. --- Makefile.am | 15 +++--- apppbx.cpp | 59 +++++++-------------- apppbx.h | 1 + genext.c | 4 +- joinpbx.cpp | 58 +++------------------ joinpbx.h | 1 - mISDN.cpp | 66 ++++++++---------------- mISDN.h | 10 +--- macro.h | 16 +++--- main.c | 23 +++++---- main.h | 14 ++--- message.c | 9 ++-- message.h | 20 ++------ port.cpp | 167 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------ port.h | 18 +++++++ select.c | 4 +- select.h | 3 +- sip.cpp | 17 +++---- trace.c | 2 +- vbox.cpp | 22 ++++---- vbox.h | 2 + 21 files changed, 285 insertions(+), 246 deletions(-) diff --git a/Makefile.am b/Makefile.am index a97a7ec..629bb50 100644 --- a/Makefile.am +++ b/Makefile.am @@ -133,14 +133,13 @@ endif INCLUDES = $(all_includes) $(GSM_INCLUDE) $(SS5_INCLUDE) $(SIP_INCLUDE) -Wall $(INSTALLATION_DEFINES) -lcr_SOURCES = $(GSM_SOURCE) $(SS5_SOURCE) $(SIP_SOURCE) select.c action.cpp mISDN.cpp \ - tones.c loop.c remote.cpp action_efi.cpp crypt.cpp mail.c trace.c \ - action_vbox.cpp dss1.cpp main.c \ - vbox.cpp alawulaw.c endpoint.cpp interface.c message.c \ - apppbx.cpp endpointapp.cpp join.cpp options.c \ - extension.c joinpbx.cpp port.cpp \ - callerid.c joinremote.cpp route.c \ - cause.c socket_server.c +lcr_SOURCES = \ + main.c select.c trace.c \ options.c \ tones.c \ alawulaw.c \ cause.c \ interface.c \ message.c \ callerid.c \ socket_server.c \ + port.cpp \ vbox.cpp \ mISDN.cpp \ dss1.cpp \ loop.c remote.cpp \ + $(GSM_SOURCE) $(SS5_SOURCE) $(SIP_SOURCE) \ + endpoint.cpp \ endpointapp.cpp \ + apppbx.cpp \ route.c \ action.cpp action_efi.cpp \ action_vbox.cpp \ extension.c \ crypt.cpp \ mail.c \ + join.cpp \ joinpbx.cpp \ joinremote.cpp lcr_LDADD = $(LIBCRYPTO) -lmisdn -lpthread $(GSM_LIB) $(SIP_LIB) diff --git a/apppbx.cpp b/apppbx.cpp index d3937a7..1b119b2 100644 --- a/apppbx.cpp +++ b/apppbx.cpp @@ -2621,17 +2621,6 @@ void EndpointAppPBX::ea_message_port(unsigned int port_id, int message_type, uni // PDEBUG(DEBUG_EPOINT, "received message %d (terminal %s, caller id %s)\n", message, e_ext.number, e_callerinfo.id); switch(message_type) { - case MESSAGE_DATA: /* data from port */ - /* check if there is a call */ - if (!ea_endpoint->ep_join_id) - break; - /* continue if only one portlist */ - if (ea_endpoint->ep_portlist->next != NULL) - break; - /* forward message */ - message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param); - break; - case MESSAGE_TONE_EOF: /* tone is end of file */ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current tone is now end of file.\n", ea_endpoint->ep_serial); if (e_action) { @@ -3235,6 +3224,19 @@ void EndpointAppPBX::join_mISDNsignal(struct port_list *portlist, int message_ty } } +/* join MESSAGE_BRIDE */ +void EndpointAppPBX::join_bridge(struct port_list *portlist, int message_type, union parameter *param) +{ + struct lcr_msg *message; + + while(portlist) { + message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_BRIDGE); + memcpy(&message->param, param, sizeof(union parameter)); + message_put(message); + portlist = portlist->next; + } +} + /* join MESSAGE_NOTIFY */ void EndpointAppPBX::join_notify(struct port_list *portlist, int message_type, union parameter *param) { @@ -3316,21 +3318,6 @@ void EndpointAppPBX::ea_message_join(unsigned int join_id, int message_type, uni portlist = ea_endpoint->ep_portlist; - /* send MESSAGE_DATA to port */ - if (message_type == MESSAGE_DATA) { - if (join_id == ea_endpoint->ep_join_id) { // still linked with JOIN - /* skip if no port relation */ - if (!portlist) - return; - /* skip if more than one port relation */ - if (portlist->next) - return; - /* forward audio data to port */ - message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param); - return; - } - } - // PDEBUG(DEBUG_EPOINT, "EPOINT(%d) received message %d for active JOIN (terminal %s, caller id %s state=%d)\n", ea_endpoint->ep_serial, message, e_ext.number, e_callerinfo.id, e_state); switch(message_type) { /* JOIN SENDS TONE message */ @@ -3420,23 +3407,11 @@ void EndpointAppPBX::ea_message_join(unsigned int join_id, int message_type, uni join_mISDNsignal(portlist, message_type, param); break; -#if 0 - kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert - /* JOIN requests bchannel */ - case MESSAGE_BCHANNEL: /* indicates the need of own bchannel access */ - PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received bchannel assignment %d from join.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id, param->bchannel.type); - /* only one port is expected to be connected to bchannel */ - if (!portlist) - break; - if (portlist->next) - break; - e_join_pattern = 1; - SCPY(e_tone, ""); - set_tone(portlist, NULL); - message = message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param); - logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT); + /* JOIN sends bridge message */ + case MESSAGE_BRIDGE: /* bride message to port */ + PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received bridge message.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id); + join_bridge(portlist, message_type, param); break; -#endif /* JOIN has pattern available */ case MESSAGE_PATTERN: /* indicating pattern available */ diff --git a/apppbx.h b/apppbx.h index cfe99c1..552e7ca 100644 --- a/apppbx.h +++ b/apppbx.h @@ -214,6 +214,7 @@ class EndpointAppPBX : public EndpointApp void ea_message_join(unsigned int join_id, int message, union parameter *param); void join_crypt(struct port_list *portlist, int message_type, union parameter *param); void join_mISDNsignal(struct port_list *portlist, int message_type, union parameter *param); + void join_bridge(struct port_list *portlist, int message_type, union parameter *param); void join_setup(struct port_list *portlist, int message_type, union parameter *param); void join_information(struct port_list *portlist, int message_type, union parameter *param); void join_overlap(struct port_list *portlist, int message_type, union parameter *param); diff --git a/genext.c b/genext.c index 4d34bbe..e9de687 100644 --- a/genext.c +++ b/genext.c @@ -30,11 +30,11 @@ int fhuse = 0; struct isdn_cause isdn_cause[128]; struct isdn_location isdn_location[16]; -void _printdebug(const char *function, int line, unsigned int mask, const char *fmt, ...) +void _printdebug(const char *file, const char *function, int line, unsigned int mask, const char *fmt, ...) { } -void _printerror(const char *function, int line, const char *fmt, ...) +void _printerror(const char *file, const char *function, int line, const char *fmt, ...) { char buffer[4096]; va_list args; diff --git a/joinpbx.cpp b/joinpbx.cpp index 4b06540..a98765f 100644 --- a/joinpbx.cpp +++ b/joinpbx.cpp @@ -367,15 +367,12 @@ void JoinPBX::bridge(void) } /* - * request data from endpoint/port if: - * - two relations - * - any without mISDN - * in this case we bridge + * Bridge between port instances if: + * - one or all are not mISDN */ - message = message_create(j_serial, relation->epoint_id, JOIN_TO_EPOINT, MESSAGE_mISDNSIGNAL); - message->param.mISDNsignal.message = mISDNSIGNAL_JOINDATA; - message->param.mISDNsignal.joindata = (relations==2 && !allmISDN); - PDEBUG(DEBUG_JOIN, "join%d EP%d set joindata=%d\n", j_serial, relation->epoint_id, message->param.mISDNsignal.joindata); + message = message_create(j_serial, relation->epoint_id, JOIN_TO_EPOINT, MESSAGE_BRIDGE); + message->param.bridge_id = j_serial; + PDEBUG(DEBUG_JOIN, "join%u EP%u requests bridge=%u\n", j_serial, relation->epoint_id, message->param.bridge_id); message_put(message); relation = relation->next; @@ -413,43 +410,6 @@ void JoinPBX::bridge(void) } } -/* - * bridging is only possible with two connected endpoints - */ -void JoinPBX::bridge_data(unsigned int epoint_from, struct join_relation *relation_from, union parameter *param) -{ - struct join_relation *relation_to; - - /* if we are alone */ - if (!j_relation->next) - return; - - /* if we are more than two */ - if (j_relation->next->next) - return; - - /* skip if source endpoint has NOT audio mode CONNECT */ - if (relation_from->channel_state != 1) - return; - - /* get destination relation */ - relation_to = j_relation; - if (relation_to == relation_from) { - /* oops, we are the first, so destination is: */ - relation_to = relation_to->next; - } - - /* skip if destination endpoint has NOT audio mode CONNECT */ - if (relation_to->channel_state != 1) - return; - - /* now we may send our data to the endpoint where it - * will be delivered to the port - */ -//printf("from %d, to %d\n", relation_from->epoint_id, relation_to->epoint_id); - message_forward(j_serial, relation_to->epoint_id, JOIN_TO_EPOINT, param); -} - /* release join from endpoint * if the join has two relations, all relations are freed and the join will be * destroyed @@ -651,7 +611,7 @@ void JoinPBX::message_epoint(unsigned int epoint_id, int message_type, union par // joinpbx_debug(join,"Join::message_epoint"); // } if (options.deb & DEBUG_JOIN) { - if (message_type != MESSAGE_DATA) { + if (message_type) { cl = join_first; while(cl) { if (cl->j_type == JOIN_TYPE_PBX) @@ -772,12 +732,6 @@ void JoinPBX::message_epoint(unsigned int epoint_id, int message_type, union par } return; - /* audio data */ - case MESSAGE_DATA: - /* now send audio data to the other endpoint */ - bridge_data(epoint_id, relation, param); - return; - /* relations sends a connect */ case MESSAGE_CONNECT: /* outgoing setup type becomes connected */ diff --git a/joinpbx.h b/joinpbx.h index 7c05eee..bf42c9a 100644 --- a/joinpbx.h +++ b/joinpbx.h @@ -66,7 +66,6 @@ class JoinPBX : public Join int j_partyline_jingle; /* also play jingle on join/leave */ void bridge(void); - void bridge_data(unsigned int epoint_from, struct join_relation *relation_from, union parameter *param); void remove_relation(struct join_relation *relation); struct join_relation *add_relation(void); int out_setup(unsigned int epoint_id, int message, union parameter *param, char *newnumber, char *newkeypad); diff --git a/mISDN.cpp b/mISDN.cpp index d683bcd..002f83f 100644 --- a/mISDN.cpp +++ b/mISDN.cpp @@ -141,7 +141,6 @@ PmISDN::PmISDN(int type, mISDNport *mISDNport, char *portname, struct port_setti p_m_echo = 0; p_m_tone = 0; p_m_rxoff = 0; - p_m_joindata = 0; p_m_inband_send_on = 0; p_m_inband_receive_on = 0; p_m_dtmf = !mISDNport->ifport->nodtmf; @@ -1338,7 +1337,7 @@ void PmISDN::load_tx(void) } if (p_tone_name[0] || p_m_crypt_msg_loops || p_m_inband_send_on || p_m_load) { - schedule_timer(&p_m_loadtimer, 0, ISDN_TRANSMIT*125); + schedule_timer(&p_m_loadtimer, 0, PORT_TRANSMIT * 125); } } @@ -1364,8 +1363,6 @@ static int mISDN_timeout(struct lcr_timer *timer, void *instance, int i) void PmISDN::bchannel_receive(struct mISDNhead *hh, unsigned char *data, int len) { unsigned int cont = *((unsigned int *)data); - unsigned char *data_temp; - unsigned int length_temp; struct lcr_msg *message; unsigned char *p; int l; @@ -1488,23 +1485,8 @@ void PmISDN::bchannel_receive(struct mISDNhead *hh, unsigned char *data, int len cryptman_listen_bch(data, len); } - p = data; - - /* send data to epoint */ - if (p_m_joindata && ACTIVE_EPOINT(p_epointlist)) { /* only if we have an epoint object */ - length_temp = len; - data_temp = p; - while(length_temp) { - message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_DATA); - message->param.data.len = (length_temp>sizeof(message->param.data.data))?sizeof(message->param.data.data):length_temp; - memcpy(message->param.data.data, data_temp, message->param.data.len); - message_put(message); - if (length_temp <= sizeof(message->param.data.data)) - break; - data_temp += sizeof(message->param.data.data); - length_temp -= sizeof(message->param.data.data); - } - } + /* send to remote, if bridged */ + bridge_tx(data, len); } @@ -1672,15 +1654,6 @@ void PmISDN::message_mISDNsignal(unsigned int epoint_id, int message_id, union p set_conf(oldconf, newconf); break; - case mISDNSIGNAL_JOINDATA: - if (p_m_joindata != param->mISDNsignal.joindata) { - p_m_joindata = param->mISDNsignal.joindata; - PDEBUG(DEBUG_BCHANNEL, "we change to joindata=%d.\n", p_m_joindata); - update_rxoff(); - } else - PDEBUG(DEBUG_BCHANNEL, "we already have joindata=%d.\n", p_m_joindata); - break; - case mISDNSIGNAL_DELAY: if (p_m_delay != param->mISDNsignal.delay) { p_m_delay = param->mISDNsignal.delay; @@ -1767,32 +1740,31 @@ void PmISDN::message_crypt(unsigned int epoint_id, int message_id, union paramet */ int PmISDN::message_epoint(unsigned int epoint_id, int message_id, union parameter *param) { - if (Port::message_epoint(epoint_id, message_id, param)) - return(1); + if (Port::message_epoint(epoint_id, message_id, param)) { + if (message_id == MESSAGE_BRIDGE) + update_rxoff(); + return 1; + } switch(message_id) { - case MESSAGE_DATA: /* tx-data from upper layer */ - txfromup(param->data.data, param->data.len); - return(1); - case MESSAGE_mISDNSIGNAL: /* user command */ PDEBUG(DEBUG_ISDN, "PmISDN(%s) received special ISDN SIGNAL %d.\n", p_name, param->mISDNsignal.message); message_mISDNsignal(epoint_id, message_id, param); - return(1); + return 1; case MESSAGE_CRYPT: /* crypt control command */ PDEBUG(DEBUG_ISDN, "PmISDN(%s) received encryption command '%d'.\n", p_name, param->crypt.type); message_crypt(epoint_id, message_id, param); - return(1); + return 1; } - return(0); + return 0; } void PmISDN::update_rxoff(void) { /* call bridges in user space OR crypto OR recording */ - if (p_m_joindata || p_m_crypt_msg_loops || p_m_crypt_listen || p_record || p_m_inband_receive_on) { + if (p_bridge || p_m_crypt_msg_loops || p_m_crypt_listen || p_record || p_m_inband_receive_on) { /* rx IS required */ if (p_m_rxoff) { /* turn on RX */ @@ -2556,22 +2528,22 @@ void mISDNport_close(struct mISDNport *mISDNport) /* * enque data from upper buffer */ -void PmISDN::txfromup(unsigned char *data, int length) +int PmISDN::bridge_rx(unsigned char *data, int length) { unsigned char buf[MISDN_HEADER_LEN+((length>ISDN_LOAD)?length:ISDN_LOAD)]; struct mISDNhead *hh = (struct mISDNhead *)buf; int ret; if (p_m_b_index < 0) - return; + return -EIO; if (p_m_mISDNport->b_state[p_m_b_index] != B_STATE_ACTIVE) - return; + return -EINVAL; /* check if high priority tones exist * ignore data in this case */ if (p_tone_name[0] || p_m_crypt_msg_loops || p_m_inband_send_on) - return; + return -EBUSY; /* preload procedure * if transmit buffer in DSP module is empty, @@ -2585,14 +2557,14 @@ void PmISDN::txfromup(unsigned char *data, int length) if (ret <= 0) PERROR("Failed to send to socket %d\n", p_m_mISDNport->b_sock[p_m_b_index].fd); p_m_load += ISDN_LOAD; - schedule_timer(&p_m_loadtimer, 0, ISDN_TRANSMIT*125); + schedule_timer(&p_m_loadtimer, 0, PORT_TRANSMIT * 125); } /* drop if load would exceed ISDN_MAXLOAD * this keeps the delay not too high */ if (p_m_load+length > ISDN_MAXLOAD) - return; + return -EINVAL; /* make and send frame */ hh->prim = PH_DATA_REQ; @@ -2602,6 +2574,8 @@ void PmISDN::txfromup(unsigned char *data, int length) if (ret <= 0) PERROR("Failed to send to socket %d\n", p_m_mISDNport->b_sock[p_m_b_index].fd); p_m_load += length; + + return 0; } int PmISDN::inband_send(unsigned char *buffer, int len) diff --git a/mISDN.h b/mISDN.h index 859b073..c310023 100644 --- a/mISDN.h +++ b/mISDN.h @@ -132,10 +132,10 @@ class PmISDN : public Port int p_m_mute; /* if set, conf is disconnected */ int p_m_tone; /* current kernel space tone */ int p_m_rxoff; /* rx from driver is disabled */ -// int p_m_nodata; /* all parties within a conf are isdn ports, so pure bridging is possible */ int p_m_txdata; /* get what we transmit */ int p_m_dtmf; /* dtmf decoding is enabled */ - int p_m_joindata; /* the call requires data due to no briging capability */ + + int bridge_rx(unsigned char *data, int len); struct lcr_timer p_m_loadtimer; /* timer for audio transmission */ virtual void update_load(void); @@ -143,10 +143,6 @@ class PmISDN : public Port int p_m_load; /* current data in dsp tx buffer */ unsigned int p_m_last_tv_sec; /* time stamp of last tx_load call, (to sync audio data */ unsigned int p_m_last_tv_msec; -// int p_m_fromup_buffer_readp; /* buffer for audio from remote endpoint */ -// int p_m_fromup_buffer_writep; -// unsigned char p_m_fromup_buffer[FROMUP_BUFFER_SIZE]; - void txfromup(unsigned char *data, int length); int p_m_crypt; /* encryption is enabled */ int p_m_crypt_msg_loops; /* sending a message */ @@ -171,8 +167,6 @@ class PmISDN : public Port int p_m_b_channel; /* number 1,2 1..15,17... */ int p_m_b_exclusive; /* if bchannel is exclusive */ int p_m_b_reserve; /* set if channel is reserved */ -// long long p_m_jittercheck; /* time of audio data */ -// long long p_m_jitterdropped; /* number of bytes dropped */ int p_m_b_mode; /* bchannel mode */ int p_m_hold; /* if port is on hold */ struct lcr_timer p_m_timeout; /* timeout of timers */ diff --git a/macro.h b/macro.h index d97c41f..5d2bce5 100644 --- a/macro.h +++ b/macro.h @@ -63,9 +63,9 @@ static inline void sprint(char *dst, unsigned int siz, const char *fmt, ...) #define UNPRINT snprintf #define VUNPRINT vsnprintf +#define FATAL(fmt, arg...) _fatal(__FILE__, __FUNCTION__, __LINE__, fmt, ##arg) /* fatal error with error message and exit */ -#define FATAL(fmt, arg...) fatal(__FUNCTION__, __LINE__, fmt, ##arg) -static inline void fatal(const char *function, int line, const char *fmt, ...) +static inline void _fatal(const char *file, const char *function, int line, const char *fmt, ...) { va_list args; char buffer[256]; @@ -74,23 +74,23 @@ static inline void fatal(const char *function, int line, const char *fmt, ...) vsnprintf(buffer, sizeof(buffer), fmt, args); va_end(args); buffer[sizeof(buffer)-1] = '\0'; - fprintf(stderr, "FATAL ERROR in function %s, line %d: %s", function, line, buffer); + fprintf(stderr, "FATAL ERROR in function %s/%s, line %d: %s", file, function, line, buffer); fprintf(stderr, "This error is not recoverable, must exit here.\n"); #ifdef DEBUG_FUNC - debug(function, line, "FATAL", buffer); - debug(function, line, "FATAL", (char *)"This error is not recoverable, must exit here.\n"); + debug(file, function, line, "FATAL", buffer); + debug(file, function, line, "FATAL", (char *)"This error is not recoverable, must exit here.\n"); #endif exit(EXIT_FAILURE); } /* memory allocation with setting to zero */ -#define MALLOC(size) _malloc(size, __FUNCTION__, __LINE__) -static inline void *_malloc(unsigned int size, const char *function, int line) +#define MALLOC(size) _malloc(size, __FILE__, __FUNCTION__, __LINE__) +static inline void *_malloc(unsigned int size, const char *file, const char *function, int line) { void *addr; addr = malloc(size); if (!addr) - fatal(function, line, "No memory for %d bytes.\n", size); + _fatal(file, function, line, "No memory for %d bytes.\n", size); memset(addr, 0, size); return addr; } diff --git a/main.c b/main.c index 07cfb8f..1f5872a 100644 --- a/main.c +++ b/main.c @@ -53,7 +53,7 @@ int last_debug = 0; int debug_newline = 1; int nooutput = 0; -void debug(const char *function, int line, const char *prefix, char *buffer) +void debug(const char *file, const char *function, int line, const char *prefix, char *buffer) { time_t now; struct tm *now_tm; @@ -73,7 +73,7 @@ void debug(const char *function, int line, const char *prefix, char *buffer) if (debug_newline) printf("\033[32m%06d %s\033[37m%s", debug_count%1000000, prefix?prefix:"", prefix?" ":""); if (function) - printf("(in %s() line %d): %s", function, line, buffer); + printf("(in %s/%s() line %d): %s", file, function, line, buffer); else printf("%s", buffer); } @@ -95,7 +95,7 @@ void debug(const char *function, int line, const char *prefix, char *buffer) } -void _printdebug(const char *function, int line, unsigned int mask, const char *fmt, ...) +void _printdebug(const char *file, const char *function, int line, unsigned int mask, const char *fmt, ...) { char buffer[4096]; va_list args; @@ -109,12 +109,12 @@ void _printdebug(const char *function, int line, unsigned int mask, const char * buffer[sizeof(buffer)-1]=0; va_end(args); - debug(function, line, "DEBUG", buffer); + debug(file, function, line, "DEBUG", buffer); pthread_mutex_unlock(&mutexd); } -void _printerror(const char *function, int line, const char *fmt, ...) +void _printerror(const char *file, const char *function, int line, const char *fmt, ...) { char buffer[4096]; va_list args; @@ -127,7 +127,7 @@ void _printerror(const char *function, int line, const char *fmt, ...) va_end(args); if (options.deb) - debug(function, line, "ERROR", buffer); + debug(file, function, line, "ERROR", buffer); else { /* only if we do not debug */ if (function) fprintf(stderr, "ERROR (in %s() line %d) %s", function, line, buffer); @@ -182,7 +182,7 @@ int main(int argc, char *argv[]) struct sched_param schedp; int created_mutexd = 0,/* created_mutext = 0,*/ created_mutexe = 0, created_lock = 0, created_signal = 0, created_debug = 0, - created_misdn = 0; + created_misdn = 0, created_message = 0; char tracetext[256], lock[128]; char options_error[256]; int polling = 0; @@ -457,6 +457,7 @@ init is done when interface is up /* init message */ init_message(); + created_message = 1; /*** main loop ***/ SPRINT(tracetext, "%s %s started, waiting for calls...", NAME, VERSION_STRING); @@ -506,9 +507,6 @@ init is done when interface is up end_trace(); ret=0; - /* clean messacleane */ - cleanup_message(); - /* free all */ free: @@ -528,7 +526,6 @@ free: } /* destroy objects */ - while(port_first) { debug_count++; delete port_first; @@ -560,6 +557,10 @@ free: PDEBUG(DEBUG_MSG, "freed %d pending messages\n", i); } + /* clean messages */ + if (created_message) + cleanup_message(); + /* free tones */ if (toneset_first) free_tones(); diff --git a/main.h b/main.h index a0295b5..9a97f3a 100644 --- a/main.h +++ b/main.h @@ -51,14 +51,14 @@ extern int fhuse; extern FILE *debug_fp; -#define PDEBUG(mask, fmt, arg...) _printdebug(__FUNCTION__, __LINE__, mask, fmt, ## arg) -#define PERROR(fmt, arg...) _printerror(__FUNCTION__, __LINE__, fmt, ## arg) -#define PDEBUG_RUNTIME(mask, fmt, arg...) _printdebug(NULL, 0, mask, fmt, ## arg) -#define PERROR_RUNTIME(fmt, arg...) _printerror(NULL, 0, fmt, ## arg) -void _printdebug(const char *function, int line, unsigned int mask, const char *fmt, ...); -void _printerror(const char *function, int line, const char *fmt, ...); +#define PDEBUG(mask, fmt, arg...) _printdebug(__FILE__, __FUNCTION__, __LINE__, mask, fmt, ## arg) +#define PERROR(fmt, arg...) _printerror(__FILE__, __FUNCTION__, __LINE__, fmt, ## arg) +#define PDEBUG_RUNTIME(mask, fmt, arg...) _printdebug(NULL, NULL, 0, mask, fmt, ## arg) +#define PERROR_RUNTIME(fmt, arg...) _printerror(NULL, NULL, 0, fmt, ## arg) +void _printdebug(const char *file, const char *function, int line, unsigned int mask, const char *fmt, ...); +void _printerror(const char *file, const char *function, int line, const char *fmt, ...); #define DEBUG_FUNC -void debug(const char *function, int line, const char *prefix, char *buffer); +void debug(const char *file, const char *function, int line, const char *prefix, char *buffer); #define DEBUG_CONFIG 0x0001 #define DEBUG_MSG 0x0002 diff --git a/message.c b/message.c index e2f01ec..1e4d37d 100644 --- a/message.c +++ b/message.c @@ -49,7 +49,7 @@ struct lcr_msg *message_create(int id_from, int id_to, int flow, int type) } /* attaches a message to the end of the message chain */ -void message_put(struct lcr_msg *message) +void _message_put(struct lcr_msg *message, const char *file, int line) { if (message->id_to == 0) { PDEBUG(DEBUG_MSG, "message %s not written, because destination is 0.\n", messages_txt[message->type]); @@ -57,8 +57,8 @@ void message_put(struct lcr_msg *message) return; } - if ((options.deb&DEBUG_MSG) && message->type != MESSAGE_DATA) - PDEBUG(DEBUG_MSG, "message %s written from %ld to %ld (memory %x)\n", messages_txt[message->type], message->id_from, message->id_to, message); + if ((options.deb & DEBUG_MSG)) + PDEBUG(DEBUG_MSG, "message %s written from %ld to %ld (memory %x at file %s, line %d)\n", messages_txt[message->type], message->id_from, message->id_to, message, file, line); *messagepointer_end = message; messagepointer_end = &(message->next); @@ -102,8 +102,7 @@ struct lcr_msg *message_get(void) message->keep = 0; - if ((options.deb&DEBUG_MSG) && message->type != MESSAGE_DATA) - + if ((options.deb & DEBUG_MSG)) PDEBUG(DEBUG_MSG, "message %s reading from %ld to %ld (memory %x)\n", messages_txt[message->type], message->id_from, message->id_to, message); return(message); diff --git a/message.h b/message.h index c2076af..4cfc5b1 100644 --- a/message.h +++ b/message.h @@ -122,7 +122,6 @@ enum { /* diversion types */ enum { /* isdnsignal */ mISDNSIGNAL_VOLUME, /* change volume */ mISDNSIGNAL_CONF, /* joint/split conference */ - mISDNSIGNAL_JOINDATA, /* data required by join instance */ mISDNSIGNAL_ECHO, /* enable/disable echoe */ mISDNSIGNAL_DELAY, /* use delay or adaptive jitter */ }; @@ -277,13 +276,6 @@ struct park_info { int len; }; -#define ISDN_TRANSMIT 256 -/* DATA */ -struct param_data { - unsigned char data[ISDN_TRANSMIT]; /* audio data */ - int len; /* audio data */ -}; - struct param_play { char file[512]; /* file name */ int offset; /* offset to start file at (in seconds) */ @@ -304,7 +296,6 @@ struct param_mISDNsignal { int tx_gain; int rx_gain; int conf; - int joindata; int tone; int echo; int delay; @@ -352,7 +343,6 @@ union parameter { int state; /* MESSAGE_TIMEOUT */ int knock; /* MESSAGE_KNOCK 0=off !0=on */ int audiopath; /* MESSAGE_audiopath see RELATION_CHANNEL_* (join.h) */ - struct param_data data; /* MESSAGE_DATA */ struct param_play play; /* MESSAGE_VBOX_PLAY */ int speed; /* MESSAGE_VBOX_PLAY_SPEED */ struct param_counter counter; /* MESSAGE_TONE_COUNTER */ @@ -362,6 +352,7 @@ union parameter { struct param_hello hello; /* MESSAGE_HELLO */ struct param_bchannel bchannel; /* MESSAGE_BCHANNEL */ struct param_newref newref; /* MESSAGE_NEWREF */ + unsigned int bridge_id; /* MESSAGE_BRIDGE */ }; enum { /* message flow */ @@ -403,11 +394,9 @@ enum { /* messages between entities */ MESSAGE_SUSPEND, /* suspend port */ MESSAGE_RESUME, /* resume port */ MESSAGE_AUDIOPATH, /* set status of audio path to endpoint (to call, audio is also set) */ -// MESSAGE_REMOTE_AUDIO, /* tell remote to set audio status */ MESSAGE_PATTERN, /* pattern information tones available */ MESSAGE_NOPATTERN, /* pattern information tones unavailable */ MESSAGE_CRYPT, /* encryption message */ - MESSAGE_DATA, /* audio/hdlc data */ MESSAGE_VBOX_PLAY, /* play recorded file */ MESSAGE_VBOX_PLAY_SPEED,/* change speed of file */ MESSAGE_VBOX_TONE, /* set answering VBOX tone */ @@ -416,6 +405,7 @@ enum { /* messages between entities */ MESSAGE_BCHANNEL, /* request/assign/remove bchannel */ MESSAGE_HELLO, /* hello message for remote application */ MESSAGE_NEWREF, /* special message to create and inform ref */ + MESSAGE_BRIDGE, /* control port bridge */ }; #define MESSAGES static const char *messages_txt[] = { \ @@ -439,11 +429,9 @@ enum { /* messages between entities */ "MESSAGE_SUSPEND", \ "MESSAGE_RESUME", \ "MESSAGE_AUDIOPATH", \ -/* "MESSAGE_REMOTE_AUDIO",*/ \ "MESSAGE_PATTERN", \ "MESSAGE_NOPATTERN", \ "MESSAGE_CRYPT", \ - "MESSAGE_DATA", \ "MESSAGE_VBOX_PLAY", \ "MESSAGE_VBOX_PLAY_SPEED", \ "MESSAGE_VBOX_TONE", \ @@ -452,11 +440,13 @@ enum { /* messages between entities */ "MESSAGE_BCHANNEL", \ "MESSAGE_HELLO", \ "MESSAGE_NEWREF", \ + "MESSAGE_BRIDGE", \ }; struct lcr_msg *message_create(int id_from, int id_to, int flow, int type); -void message_put(struct lcr_msg *message); +#define message_put(m) _message_put(m, __FILE__, __LINE__) +void _message_put(struct lcr_msg *message, const char *file, int line); struct lcr_msg *message_forward(int id_from, int id_to, int flow, union parameter *param); struct lcr_msg *message_get(void); void message_free(struct lcr_msg *message); diff --git a/port.cpp b/port.cpp index a083fa2..74f8aac 100644 --- a/port.cpp +++ b/port.cpp @@ -54,6 +54,9 @@ class Port *port_first = NULL; unsigned int port_serial = 1; /* must be 1, because 0== no port */ +struct port_bridge *p_bridge_first; + +static void remove_bridge(struct port_bridge *bridge, class Port *port); /* free epointlist relation */ @@ -146,7 +149,7 @@ Port::Port(int type, const char *portname, struct port_settings *settings) { class Port *temp, **tempp; - PDEBUG(DEBUG_PORT, "new port of type %d, name '%s'\n", type, portname); + PDEBUG(DEBUG_PORT, "new port of type 0x%x, name '%s'\n", type, portname); /* initialize object */ if (settings) @@ -169,6 +172,7 @@ Port::Port(int type, const char *portname, struct port_settings *settings) memset(&p_redirinfo, 0, sizeof(p_redirinfo)); memset(&p_capainfo, 0, sizeof(p_capainfo)); p_echotest = 0; + p_bridge = 0; /* call recording */ p_record = NULL; @@ -202,13 +206,18 @@ Port::~Port(void) class Port *temp, **tempp; struct lcr_msg *message; + PDEBUG(DEBUG_PORT, "removing port of type 0x%x, name '%s'\n", p_type, p_name); + + if (p_bridge) { + PDEBUG(DEBUG_PORT, "Removing us from bridge %u\n", p_bridge->bridge_id); + remove_bridge(p_bridge, this); + } + if (p_record) close_record(0, 0); classuse--; - PDEBUG(DEBUG_PORT, "removing port of type %d, name '%s'\n", p_type, p_name); - /* disconnect port from endpoint */ while(p_epointlist) { /* send disconnect */ @@ -589,38 +598,42 @@ try_loop: } -/* endpoint sends messages to the port - * this is called by the message_epoint inherited by child classes - * therefor a return=1 means: stop, no more processing +/* Endpoint sends messages to the port + * This is called by the message_epoint, inherited by child classes. + * Therefor a return 1 means: "already handled here" */ //extern struct lcr_msg *dddebug; int Port::message_epoint(unsigned int epoint_id, int message_id, union parameter *param) { /* check if we got audio data from one remote port */ switch(message_id) { - case MESSAGE_TONE: /* play tone */ - PDEBUG(DEBUG_PORT, "PORT(%s) isdn port with (caller id %s) setting tone '%s' dir '%s'\n", p_name, p_callerinfo.id, param->tone.name, param->tone.dir); + case MESSAGE_TONE: /* play tone */ + PDEBUG(DEBUG_PORT, "PORT(%s) setting tone '%s' dir '%s'\n", p_name, param->tone.name, param->tone.dir); set_tone(param->tone.dir,param->tone.name); - return(1); + return 1; - case MESSAGE_VBOX_TONE: /* play tone of answering machine */ + case MESSAGE_VBOX_TONE: /* play tone of answering machine */ PDEBUG(DEBUG_PORT, "PORT(%s) set answering machine tone '%s' '%s'\n", p_name, param->tone.dir, param->tone.name); set_vbox_tone(param->tone.dir, param->tone.name); - return(1); + return 1; - case MESSAGE_VBOX_PLAY: /* play recording of answering machine */ + case MESSAGE_VBOX_PLAY: /* play recording of answering machine */ PDEBUG(DEBUG_PORT, "PORT(%s) set answering machine file to play '%s' (offset %d seconds)\n", p_name, param->play.file, param->play.offset); set_vbox_play(param->play.file, param->play.offset); - return(1); + return 1; - case MESSAGE_VBOX_PLAY_SPEED: /* set speed of playback (recording of answering machine) */ + case MESSAGE_VBOX_PLAY_SPEED: /* set speed of playback (recording of answering machine) */ PDEBUG(DEBUG_PORT, "PORT(%s) set answering machine playback speed %d (times)\n", p_name, param->speed); set_vbox_speed(param->speed); - return(1); + return 1; + case MESSAGE_BRIDGE: /* create / join / leave / destroy bridge */ + PDEBUG(DEBUG_PORT, "PORT(%s) bridging to id %d\n", p_name, param->bridge_id); + bridge(param->bridge_id); + return 1; } - return(0); + return 0; } @@ -1154,3 +1167,125 @@ void Port::update_load(void) { } + +/* + * bridge handling + */ + +static void remove_bridge(struct port_bridge *bridge, class Port *port) +{ + struct port_bridge **temp = &p_bridge_first; + while (*temp) { + if (*temp == bridge) { + int remove = 0; + + /* Remove us from bridge. If bridge is empty, remove it completely. */ + if (bridge->sunrise == port) { + bridge->sunrise = NULL; + if (!bridge->sunset) + remove = 1; + } + if (bridge->sunset == port) { + bridge->sunset = NULL; + if (!bridge->sunrise) + remove = 1; + } + if (remove) { + PDEBUG(DEBUG_PORT, "Remove bridge %u\n", bridge->bridge_id); + *temp = bridge->next; + FREE(bridge, sizeof(struct port_bridge)); + memuse--; + } + return; + } + temp = &((*temp)->next); + } + PERROR("Bridge %p not found in list\n", bridge); +} + +void Port::bridge(unsigned int bridge_id) +{ + /* Remove bridge, if we leave bridge or if we join a different bridge. */ + if (p_bridge && bridge_id != p_bridge->bridge_id) { + PDEBUG(DEBUG_PORT, "Remove port %u from bridge %u, because out new bridge is %u\n", p_serial, p_bridge->bridge_id, bridge_id); + remove_bridge(p_bridge, this); + p_bridge = NULL; + } + + /* if we leave bridge */ + if (!bridge_id) + return; + + /* find bridge */ + if (!p_bridge) { + struct port_bridge *temp = p_bridge_first; + + while (temp) { + if (temp->bridge_id == bridge_id) + break; + temp = temp->next; + } + p_bridge = temp; + if (p_bridge) + PDEBUG(DEBUG_PORT, "Port %d found existing bridge %u.\n", p_serial, p_bridge->bridge_id); + } + + /* create bridge */ + if (!p_bridge) { + struct port_bridge **temp = &p_bridge_first; + + p_bridge = (struct port_bridge *) MALLOC(sizeof(struct port_bridge)); + memuse++; + p_bridge->bridge_id = bridge_id; + p_bridge->sunrise = this; + + /* attach bridge instance to list */ + while (*temp) + temp = &((*temp)->next); + *temp = p_bridge; + PDEBUG(DEBUG_PORT, "Port %d creating not existing bridge %u.\n", p_serial, p_bridge->bridge_id); + } + + /* already joined */ + if (p_bridge->sunrise == this || p_bridge->sunset == this) + return; + + /* join bridge */ + if (!p_bridge->sunrise) { + p_bridge->sunrise = this; + return; + } + if (!p_bridge->sunset) { + p_bridge->sunset = this; + return; + } + + PERROR("Bridge ID %u cannot be joined by port %u, because it is already occupied by ports %u and %u.\n", p_bridge->bridge_id, p_serial, p_bridge->sunrise->p_serial, p_bridge->sunset->p_serial); + p_bridge = NULL; +} + +/* send data to remote Port */ +int Port::bridge_tx(unsigned char *data, int len) +{ + class Port *to_port = NULL; + + /* get remote port from bridge */ + if (!p_bridge) + return -EINVAL; + if (p_bridge->sunrise == this) + to_port = p_bridge->sunset; + if (p_bridge->sunset == this) + to_port = p_bridge->sunrise; + if (!to_port) + return -EINVAL; + +// printf("Traffic: %u -> %u (bridge %u)\n", p_serial, to_port->p_serial, p_bridge->bridge_id); + return to_port->bridge_rx(data, len); +} + +/* receive data from remote Port (dummy, needs to be inherited) */ +int Port::bridge_rx(unsigned char *data, int len) +{ + return 0; /* datenklo */ +} + diff --git a/port.h b/port.h index 0d6a5f9..066ace7 100644 --- a/port.h +++ b/port.h @@ -111,6 +111,8 @@ enum { /* event list from listening to tty */ #define RECORD_BUFFER_LENGTH 1024 // must be a binary border & must be greater 256, because 256 will be written if buffer overflows #define RECORD_BUFFER_MASK 1023 +#define PORT_TRANSMIT 256 // how much to transmit via bridge, if it is not defined by received data length + /* structure of epoint_list */ struct epoint_list { struct epoint_list *next; @@ -147,6 +149,16 @@ struct port_settings { int no_seconds; }; +/* port bridge instance */ +struct port_bridge { + struct port_bridge *next; /* next bridge node */ + unsigned int bridge_id; /* unique ID to identify bridge */ + class Port *sunrise; /* one side of the bridge */ + class Port *sunset; /* other side of the bridge */ +}; + +extern struct port_bridge *p_bridge_first; + /* generic port class */ class Port { @@ -189,6 +201,12 @@ class Port /* endpoint relation */ struct epoint_list *p_epointlist; /* endpoint relation */ + /* audio bridging */ + struct port_bridge *p_bridge; /* linked to a port bridge or NULL */ + void bridge(unsigned int bridge_id); /* join a bridge */ + int bridge_tx(unsigned char *data, int len); /* used to transmit data to remote port */ + virtual int bridge_rx(unsigned char *data, int len); /* function to be inherited, so data is received */ + /* state */ int p_state; /* state of port */ void new_state(int state); /* set new state */ diff --git a/select.c b/select.c index 8763739..3ae8a20 100644 --- a/select.c +++ b/select.c @@ -371,10 +371,10 @@ void _del_work(struct lcr_work *work, const char *func) #endif } -void trigger_work(struct lcr_work *work) +void _trigger_work(struct lcr_work *work, const char *func) { if (!work->inuse) { - FATAL("Work not added\n"); + FATAL("Work not added, (called from func %s)\n", func); } /* event already triggered */ diff --git a/select.h b/select.h index c4e1418..36d0eeb 100644 --- a/select.h +++ b/select.h @@ -57,6 +57,7 @@ struct lcr_work { int _add_work(struct lcr_work *work, int (*cb)(struct lcr_work *work, void *instance, int index), void *instance, int index, const char *func); #define del_work(a) _del_work(a, __func__); void _del_work(struct lcr_work *work, const char *func); -void trigger_work(struct lcr_work *work); +#define trigger_work(a) _trigger_work(a, __func__); +void _trigger_work(struct lcr_work *work, const char *func); diff --git a/sip.cpp b/sip.cpp index adcc057..40c5572 100644 --- a/sip.cpp +++ b/sip.cpp @@ -1078,18 +1078,15 @@ int Psip::message_epoint(unsigned int epoint_id, int message_id, union parameter class Endpoint *epoint; if (PmISDN::message_epoint(epoint_id, message_id, param)) - return(1); + return 1; epoint = find_epoint_id(epoint_id); if (!epoint) { PDEBUG(DEBUG_SIP, "PORT(%s) no endpoint object found where the message is from.\n", p_name); - return(0); + return 0; } switch(message_id) { - case MESSAGE_DATA: - return(1); - case MESSAGE_ALERTING: /* call is ringing on LCR side */ if (p_state != PORT_STATE_IN_SETUP && p_state != PORT_STATE_IN_PROCEEDING) @@ -1099,7 +1096,7 @@ int Psip::message_epoint(unsigned int epoint_id, int message_id, union parameter add_trace("respond", "value", "180 Ringing"); end_trace(); new_state(PORT_STATE_IN_ALERTING); - return(1); + return 1; case MESSAGE_CONNECT: /* call is connected on LCR side */ if (p_state != PORT_STATE_IN_SETUP @@ -1107,22 +1104,22 @@ int Psip::message_epoint(unsigned int epoint_id, int message_id, union parameter && p_state != PORT_STATE_IN_ALERTING) return 0; message_connect(epoint_id, message_id, param); - return(1); + return 1; case MESSAGE_DISCONNECT: /* call has been disconnected */ case MESSAGE_RELEASE: /* call has been released */ message_release(epoint_id, message_id, param); - return(1); + return 1; case MESSAGE_SETUP: /* dial-out command received from epoint */ message_setup(epoint_id, message_id, param); - return(1); + return 1; default: PDEBUG(DEBUG_SIP, "PORT(%s) SP port with (caller id %s) received an unsupported message: %d\n", p_name, p_callerinfo.id, message_id); } - return(0); + return 0; } int Psip::parse_sdp(sip_t const *sip, unsigned int *ip, unsigned short *port) diff --git a/trace.c b/trace.c index a810d8c..ffecfbb 100644 --- a/trace.c +++ b/trace.c @@ -274,7 +274,7 @@ void _end_trace(const char *__file, int __line) if (string) { /* process debug */ if (options.deb) - debug(NULL, 0, "TRACE", string); + debug(NULL, NULL, 0, "TRACE", string); /* process log */ if (options.log[0]) { fp = fopen(options.log, "a"); diff --git a/vbox.cpp b/vbox.cpp index 28daf09..c8c3012 100644 --- a/vbox.cpp +++ b/vbox.cpp @@ -103,7 +103,7 @@ void VBoxPort::send_announcement(void) { struct lcr_msg *message; unsigned int tosend; - unsigned char buffer[ISDN_TRANSMIT]; + unsigned char buffer[PORT_TRANSMIT + PORT_TRANSMIT]; /* use twice of the buffer, so we can send more in case of delayed main loop execution */ class Endpoint *epoint; int temp; struct timeval current_time; @@ -118,7 +118,7 @@ void VBoxPort::send_announcement(void) /* set time the first time */ if (!p_vbox_audio_start) - p_vbox_audio_start = now - ISDN_TRANSMIT; + p_vbox_audio_start = now - PORT_TRANSMIT; /* calculate the number of bytes */ tosend = (unsigned int)(now - p_vbox_audio_start) - p_vbox_audio_transferred; @@ -126,7 +126,7 @@ void VBoxPort::send_announcement(void) tosend = sizeof(buffer); /* schedule next event */ - temp = ISDN_TRANSMIT + ISDN_TRANSMIT - tosend; + temp = PORT_TRANSMIT + PORT_TRANSMIT - tosend; if (temp < 0) temp = 0; schedule_timer(&p_vbox_announce_timer, 0, temp*125); @@ -184,13 +184,17 @@ void VBoxPort::send_announcement(void) } else { if (p_record) record(buffer, tosend, 0); // from down - message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_DATA); - message->param.data.len = tosend; - memcpy(message->param.data.data, buffer, tosend); - message_put(message); + /* send to remote, if bridged */ + bridge_tx(buffer, tosend); } } +int VBoxPort::bridge_rx(unsigned char *data, int len) +{ + if (p_record) + record(data, len, 1); // from up + return 0; +} /* * endpoint sends messages to the vbox port @@ -211,10 +215,6 @@ int VBoxPort::message_epoint(unsigned int epoint_id, int message_id, union param } switch(message_id) { - case MESSAGE_DATA: - record(param->data.data, param->data.len, 1); // from up - return(1); - case MESSAGE_DISCONNECT: /* call has been disconnected */ new_state(PORT_STATE_OUT_DISCONNECT); vbox_trace_header(this, "DISCONNECT to VBox", DIRECTION_OUT); diff --git a/vbox.h b/vbox.h index dd9d4aa..69cf83c 100644 --- a/vbox.h +++ b/vbox.h @@ -18,6 +18,8 @@ class VBoxPort : public Port int message_epoint(unsigned int epoint_id, int message, union parameter *param); void send_announcement(void); + int bridge_rx(unsigned char *data, int len); + private: struct EndpointAppPBX *p_vbox_apppbx; /* pbx application */ unsigned int p_vbox_timeout; /* timeout for recording */ -- 2.13.6