X-Git-Url: http://git.eversberg.eu/gitweb.cgi?p=lcr.git;a=blobdiff_plain;f=port.cpp;h=4afca9c7978729533a701f6f57f547a1835540d4;hp=e88175b6358ac420cdf391ce550ef99b6ba98b23;hb=5463e1b62a39ce417b610584e3d34a8bc30ac15e;hpb=b0bd74e35e935aa976b68c594def4e8d2c22ef95 diff --git a/port.cpp b/port.cpp index e88175b..4afca9c 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,8 +149,6 @@ 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); - /* initialize object */ if (settings) memcpy(&p_settings, settings, sizeof(struct port_settings)); @@ -169,6 +170,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; @@ -191,6 +193,8 @@ Port::Port(int type, const char *portname, struct port_settings *settings) *tempp = this; classuse++; + + PDEBUG(DEBUG_PORT, "new port (%d) of type 0x%x, name '%s'\n", p_serial, type, portname); } @@ -202,13 +206,18 @@ Port::~Port(void) class Port *temp, **tempp; struct lcr_msg *message; + PDEBUG(DEBUG_PORT, "removing port (%d) of type 0x%x, name '%s'\n", p_serial, 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 */ @@ -292,7 +301,7 @@ void Port::set_tone(const char *dir, const char *name) if (name == NULL) name = ""; - if (!dir && !dir[0]) + if (!dir || !dir[0]) dir = options.tones_dir; /* just in case we have no PmISDN instance */ /* no counter, no eof, normal speed */ @@ -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; } @@ -647,6 +660,7 @@ int Port::open_record(int type, int vbox, int skip, char *extension, int anon_ig char filename[256]; time_t now; struct tm *now_tm; + int ret; if (!extension) { PERROR("Port(%d) not an extension\n", p_serial); @@ -711,7 +725,7 @@ int Port::open_record(int type, int vbox, int skip, char *extension, int anon_ig case CODEC_MONO: case CODEC_STEREO: case CODEC_8BIT: - fwrite(dummyheader, sizeof(dummyheader), 1, p_record); + ret = fwrite(dummyheader, sizeof(dummyheader), 1, p_record); break; case CODEC_LAW: @@ -739,6 +753,7 @@ void Port::close_record(int beep, int mute) char *p; struct caller_info callerinfo; const char *valid_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890_.-!$%&/()=+*;~"; + int ret; if (!p_record) return; @@ -801,7 +816,7 @@ void Port::close_record(int beep, int mute) } i = 0; while(i < beep) { - fwrite(beep_mono, sizeof(beep_mono), 1, p_record); + ret = fwrite(beep_mono, sizeof(beep_mono), 1, p_record); i += sizeof(beep_mono); p_record_length += sizeof(beep_mono); } @@ -861,7 +876,7 @@ void Port::close_record(int beep, int mute) fmt.bits_sample = 8; /* one channel */ break; } - fwrite(&fmt, sizeof(fmt), 1, p_record); + ret = fwrite(&fmt, sizeof(fmt), 1, p_record); /* data */ fprintf(p_record, "data%c%c%c%c", (unsigned char)(size&0xff), (unsigned char)((size>>8)&0xff), (unsigned char)((size>>16)&0xff), (unsigned char)(size>>24)); @@ -939,6 +954,7 @@ void Port::record(unsigned char *data, int length, int dir_fromup) signed short *s; int free, i, ii; signed int sample; + int ret; /* no recording */ if (!p_record || !length) @@ -988,7 +1004,7 @@ same_again: p_record_buffer_readp = (p_record_buffer_readp + 1) & RECORD_BUFFER_MASK; i++; } - fwrite(write_buffer, 512, 1, p_record); + ret = fwrite(write_buffer, 512, 1, p_record); p_record_length += 512; break; @@ -1011,7 +1027,7 @@ same_again: i++; } } - fwrite(write_buffer, 1024, 1, p_record); + ret = fwrite(write_buffer, 1024, 1, p_record); p_record_length += 1024; break; @@ -1023,7 +1039,7 @@ same_again: p_record_buffer_readp = (p_record_buffer_readp + 1) & RECORD_BUFFER_MASK; i++; } - fwrite(write_buffer, 512, 1, p_record); + ret = fwrite(write_buffer, 512, 1, p_record); p_record_length += 512; break; @@ -1035,7 +1051,7 @@ same_again: p_record_buffer_readp = (p_record_buffer_readp + 1) & RECORD_BUFFER_MASK; i++; } - fwrite(write_buffer, 256, 1, p_record); + ret = fwrite(write_buffer, 256, 1, p_record); p_record_length += 256; break; } @@ -1075,7 +1091,7 @@ different_again: *s++ = sample; i++; } - fwrite(write_buffer, ii<<1, 1, p_record); + ret = fwrite(write_buffer, ii<<1, 1, p_record); p_record_length += (ii<<1); break; @@ -1098,7 +1114,7 @@ different_again: i++; } } - fwrite(write_buffer, ii<<2, 1, p_record); + ret = fwrite(write_buffer, ii<<2, 1, p_record); p_record_length += (ii<<2); break; @@ -1114,7 +1130,7 @@ different_again: *d++ = (sample+0x8000) >> 8; i++; } - fwrite(write_buffer, ii, 1, p_record); + ret = fwrite(write_buffer, ii, 1, p_record); p_record_length += ii; break; @@ -1130,7 +1146,7 @@ different_again: *d++ = audio_s16_to_law[sample & 0xffff]; i++; } - fwrite(write_buffer, ii, 1, p_record); + ret = fwrite(write_buffer, ii, 1, p_record); p_record_length += ii; break; } @@ -1151,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 */ +} +