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.
This commit is contained in:
Andreas Eversberg 2012-01-14 18:36:26 +01:00
parent 863bc64219
commit 877a2dfd52
21 changed files with 285 additions and 246 deletions

View File

@ -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)

View File

@ -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 */

View File

@ -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);

View File

@ -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;

View File

@ -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 */

View File

@ -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);

View File

@ -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)

10
mISDN.h
View File

@ -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 */

16
macro.h
View File

@ -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;
}

23
main.c
View File

@ -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();

14
main.h
View File

@ -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

View File

@ -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);

View File

@ -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);

167
port.cpp
View File

@ -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 */
}

18
port.h
View File

@ -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 */

View File

@ -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 */

View File

@ -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);

17
sip.cpp
View File

@ -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)

View File

@ -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");

View File

@ -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);

2
vbox.h
View File

@ -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 */