Replaced polling loop for LCR and chan_lcr with select based event loop.

Now LCR and chan_lcr will not use any CPU until there is work to do.
This commit is contained in:
Andreas Eversberg 2010-01-16 11:20:23 +01:00
parent 473d6569ef
commit b0bd74e35e
48 changed files with 2121 additions and 1549 deletions

View File

@ -72,7 +72,7 @@ if ENABLE_ASTERISK_CHANNEL_DRIVER
noinst_PROGRAMS = chan_lcr.so
chan_lcr_so_SOURCES =
chan_lcr_so_LDFLAGS = -shared
chan_lcr_so_LDADD = chan_lcr.po bchannel.po options.po callerid.po
chan_lcr_so_LDADD = chan_lcr.po bchannel.po options.po callerid.po select.po
chan_lcr.po: chan_lcr.c chan_lcr.h
$(CC) $(INCLUDES) -D_GNU_SOURCE -fPIC -c chan_lcr.c -o chan_lcr.po
@ -86,6 +86,9 @@ callerid.po: callerid.c callerid.h
options.po: options.c options.h
$(CC) $(INCLUDES) -D_GNU_SOURCE -fPIC -c options.c -o options.po
select.po: select.c select.h
$(CC) $(INCLUDES) -D_GNU_SOURCE -fPIC -c select.c -o select.po
install-exec-hook:
mkdir -p $(astmoddir)
$(INSTALL) -d $(astmoddir)
@ -94,7 +97,7 @@ endif
INCLUDES = $(all_includes) $(GSM_INCLUDE) $(SS5_INCLUDE) -Wall -I/usr/include/mISDNuser $(INSTALLATION_DEFINES)
lcr_SOURCES = $(GSM_SOURCE) $(SS5_SOURCE) action.cpp mISDN.cpp tones.c \
lcr_SOURCES = $(GSM_SOURCE) $(SS5_SOURCE) select.c action.cpp mISDN.cpp tones.c \
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 \

View File

@ -61,7 +61,8 @@ am_chan_lcr_so_OBJECTS =
chan_lcr_so_OBJECTS = $(am_chan_lcr_so_OBJECTS)
@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@chan_lcr_so_DEPENDENCIES = \
@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@ chan_lcr.po bchannel.po \
@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@ options.po callerid.po
@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@ options.po callerid.po \
@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@ select.po
am_genextension_OBJECTS = genext.$(OBJEXT) options.$(OBJEXT) \
extension.$(OBJEXT)
genextension_OBJECTS = $(am_genextension_OBJECTS)
@ -78,28 +79,28 @@ genwave_LDADD = $(LDADD)
am__lcr_SOURCES_DIST = gsm_audio.c gsm.cpp gsm_conf.c \
openbsc/src/bsc_init.c openbsc/src/vty_interface.c \
openbsc/src/vty_interface_layer3.c ss5.cpp ss5_encode.c \
ss5_decode.c action.cpp mISDN.cpp tones.c 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
ss5_decode.c select.c action.cpp mISDN.cpp tones.c \
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
@ENABLE_GSM_TRUE@am__objects_1 = gsm_audio.$(OBJEXT) gsm.$(OBJEXT) \
@ENABLE_GSM_TRUE@ gsm_conf.$(OBJEXT) bsc_init.$(OBJEXT) \
@ENABLE_GSM_TRUE@ vty_interface.$(OBJEXT) \
@ENABLE_GSM_TRUE@ vty_interface_layer3.$(OBJEXT)
@ENABLE_SS5_TRUE@am__objects_2 = ss5.$(OBJEXT) ss5_encode.$(OBJEXT) \
@ENABLE_SS5_TRUE@ ss5_decode.$(OBJEXT)
am_lcr_OBJECTS = $(am__objects_1) $(am__objects_2) action.$(OBJEXT) \
mISDN.$(OBJEXT) tones.$(OBJEXT) action_efi.$(OBJEXT) \
crypt.$(OBJEXT) mail.$(OBJEXT) trace.$(OBJEXT) \
action_vbox.$(OBJEXT) dss1.$(OBJEXT) main.$(OBJEXT) \
vbox.$(OBJEXT) alawulaw.$(OBJEXT) endpoint.$(OBJEXT) \
interface.$(OBJEXT) message.$(OBJEXT) apppbx.$(OBJEXT) \
endpointapp.$(OBJEXT) join.$(OBJEXT) options.$(OBJEXT) \
extension.$(OBJEXT) joinpbx.$(OBJEXT) port.$(OBJEXT) \
callerid.$(OBJEXT) joinremote.$(OBJEXT) route.$(OBJEXT) \
cause.$(OBJEXT) socket_server.$(OBJEXT)
am_lcr_OBJECTS = $(am__objects_1) $(am__objects_2) select.$(OBJEXT) \
action.$(OBJEXT) mISDN.$(OBJEXT) tones.$(OBJEXT) \
action_efi.$(OBJEXT) crypt.$(OBJEXT) mail.$(OBJEXT) \
trace.$(OBJEXT) action_vbox.$(OBJEXT) dss1.$(OBJEXT) \
main.$(OBJEXT) vbox.$(OBJEXT) alawulaw.$(OBJEXT) \
endpoint.$(OBJEXT) interface.$(OBJEXT) message.$(OBJEXT) \
apppbx.$(OBJEXT) endpointapp.$(OBJEXT) join.$(OBJEXT) \
options.$(OBJEXT) extension.$(OBJEXT) joinpbx.$(OBJEXT) \
port.$(OBJEXT) callerid.$(OBJEXT) joinremote.$(OBJEXT) \
route.$(OBJEXT) cause.$(OBJEXT) socket_server.$(OBJEXT)
lcr_OBJECTS = $(am_lcr_OBJECTS)
am__DEPENDENCIES_1 =
@ENABLE_GSM_TRUE@am__DEPENDENCIES_2 = /usr/lib/libgsm.a \
@ -258,9 +259,9 @@ INSTALLATION_DEFINES = \
@ENABLE_SS5_TRUE@SS5_SOURCE = ss5.cpp ss5_encode.c ss5_decode.c
@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@chan_lcr_so_SOURCES =
@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@chan_lcr_so_LDFLAGS = -shared
@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@chan_lcr_so_LDADD = chan_lcr.po bchannel.po options.po callerid.po
@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@chan_lcr_so_LDADD = chan_lcr.po bchannel.po options.po callerid.po select.po
INCLUDES = $(all_includes) $(GSM_INCLUDE) $(SS5_INCLUDE) -Wall -I/usr/include/mISDNuser $(INSTALLATION_DEFINES)
lcr_SOURCES = $(GSM_SOURCE) $(SS5_SOURCE) action.cpp mISDN.cpp tones.c \
lcr_SOURCES = $(GSM_SOURCE) $(SS5_SOURCE) select.c action.cpp mISDN.cpp tones.c \
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 \
@ -446,6 +447,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/options.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/port.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/route.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/select.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket_server.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss5.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss5_decode.Po@am__quote@
@ -819,6 +821,9 @@ uninstall-am: uninstall-binPROGRAMS uninstall-info-am \
@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@options.po: options.c options.h
@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@ $(CC) $(INCLUDES) -D_GNU_SOURCE -fPIC -c options.c -o options.po
@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@select.po: select.c select.h
@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@ $(CC) $(INCLUDES) -D_GNU_SOURCE -fPIC -c select.c -o select.po
@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@install-exec-hook:
@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@ mkdir -p $(astmoddir)
@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@ $(INSTALL) -d $(astmoddir)

2
README
View File

@ -532,6 +532,8 @@ New release Version 1.7
Changes after Version 1.7
- Added new option to interface.conf: "nonotify" to disable notify messages.
- Replaced polling main loop by event driven "select()" loop.
- Also replaced polling main loop by event driven "select()" loop on chan_lcr.

View File

@ -644,16 +644,16 @@ void EndpointAppPBX::action_dialing_login(void)
e_ruleset = NULL;
e_rule = NULL;
e_action = &action_password;
e_match_timeout = 0;
unsched_timer(&e_match_timeout);
e_match_to_action = NULL;
e_dialinginfo.id[0] = '\0';
e_extdialing = strchr(e_dialinginfo.id, '\0');
/* set timeout */
e_password_timeout = now+20;
schedule_timer(&e_password_timeout, 20, 0);
/* do dialing */
process_dialing();
process_dialing(0);
} else {
/* make call state */
new_state(EPOINT_STATE_IN_OVERLAP);
@ -945,7 +945,7 @@ void EndpointAppPBX::_action_redial_reply(int in)
SCPY(e_dialinginfo.id, last);
e_extdialing = e_dialinginfo.id;
e_action = NULL;
process_dialing();
process_dialing(0);
return;
}
e_extdialing[0] = '\0';
@ -1039,10 +1039,10 @@ void EndpointAppPBX::action_dialing_powerdial(void)
/* do dialing */
SCPY(e_dialinginfo.id, e_ext.last_out[0]);
e_powerdialing = -1; /* indicates the existence of powerdialing but no redial time given */
e_powerdial_on = 1; /* indicates the existence of powerdialing but no redial time given */
e_powercount = 0;
e_action = NULL;
process_dialing();
process_dialing(0);
}
@ -1144,7 +1144,7 @@ void EndpointAppPBX::action_hangup_callback(void)
end_trace();
/* set time to callback */
e_callback = now_d + delay;
schedule_timer(&e_callback_timeout, delay, 0);
}
@ -1197,7 +1197,7 @@ void EndpointAppPBX::action_dialing_abbrev(void)
SCPY(e_dialinginfo.id, phone);
e_extdialing = e_dialinginfo.id;
e_action = NULL;
process_dialing();
process_dialing(0);
}
@ -1701,7 +1701,7 @@ void EndpointAppPBX::_action_goto_menu(int mode)
/* do dialing with new ruleset */
e_action = NULL;
process_dialing();
process_dialing(0);
}
/* process dialing goto
@ -1839,7 +1839,7 @@ void EndpointAppPBX::action_dialing_help(void)
e_extdialing = e_dialinginfo.id+strlen(numbering->prefix);
PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s selected a new menu '%s' dialing: %s\n", ea_endpoint->ep_serial, e_ext.number, numb_actions[numbering->action], e_dialinginfo.id);
nesting?:
process_dialing();
process_dialing(0);
return;
}
@ -2098,11 +2098,16 @@ void EndpointAppPBX::action_dialing_password_wr(void)
* depending on the detected prefix, subfunctions above (action_*) will be
* calles.
*/
void EndpointAppPBX::process_dialing(void)
void EndpointAppPBX::process_dialing(int timeout)
{
struct port_list *portlist = ea_endpoint->ep_portlist;
struct lcr_msg *message;
struct route_param *rparam;
struct timeval current_time;
/* set if timeout is active, or if timeout value was given due to timeout action */
if (e_action_timeout.active)
timeout = 1;
//#warning Due to HANG-BUG somewhere here, I added some HANG-BUG-DEBUGGING output that cannot be disabled. after bug has been found, this will be removed.
//PDEBUG(~0, "HANG-BUG-DEBUGGING: entered porcess_dialing\n");
@ -2111,8 +2116,8 @@ void EndpointAppPBX::process_dialing(void)
if (!portlist) {
portlist_error:
PDEBUG(DEBUG_EPOINT, "EPOINT(%d): note: dialing call requires exactly one port object to process dialing. this case could happen due to a parked call. we end dialing here.\n", ea_endpoint->ep_serial, e_ext.number);
e_action_timeout = 0;
e_match_timeout = 0;
unsched_timer(&e_action_timeout);
unsched_timer(&e_match_timeout);
return;
}
if (portlist->next) {
@ -2127,15 +2132,15 @@ void EndpointAppPBX::process_dialing(void)
new_state(EPOINT_STATE_OUT_DISCONNECT);
message_disconnect_port(portlist, CAUSE_UNSPECIFIED, LOCATION_PRIVATE_LOCAL, "");
set_tone(portlist, "cause_3f");
e_action_timeout = 0;
e_match_timeout = 0;
unsched_timer(&e_action_timeout);
unsched_timer(&e_match_timeout);
goto end;
}
//PDEBUG(~0, "HANG-BUG-DEBUGGING: before action-timeout processing\n");
/* process timeout */
if (e_action && e_action_timeout) { /* e_action may be NULL, but e_action_timeout may still be set and must be ignored */
e_action_timeout = 0;
if (e_action && timeout) { /* e_action may be NULL, but e_action_timeout may still be set and must be ignored */
unsched_timer(&e_action_timeout);
if (e_state == EPOINT_STATE_CONNECT) {
PDEBUG(DEBUG_ROUTE|DEBUG_EPOINT, "EPOINT(%d): action timed out, but we already have connected, so we stop timer and continue.\n", ea_endpoint->ep_serial);
goto end;
@ -2163,7 +2168,7 @@ void EndpointAppPBX::process_dialing(void)
if (e_state!=EPOINT_STATE_IN_SETUP
&& e_state!=EPOINT_STATE_IN_OVERLAP) {
PDEBUG(DEBUG_EPOINT, "EPOINT(%d): we are not in incoming setup/overlap state, so we ignore init/dialing process.\n", ea_endpoint->ep_serial, e_rule_nesting);
e_match_timeout = 0;
unsched_timer(&e_match_timeout);
goto end;
}
@ -2176,8 +2181,8 @@ void EndpointAppPBX::process_dialing(void)
e_dialinginfo.id[0] = '\0';
e_action = NUMB_ACTION_MENU;
e_menu = 0;
process_dialing();
e_match_timeout = 0;
process_dialing(0);
unsched_timer(&e_match_timeout);
goto end;
}
/* invalid dialing */
@ -2194,7 +2199,7 @@ void EndpointAppPBX::process_dialing(void)
}
new_state(EPOINT_STATE_OUT_DISCONNECT);
set_tone(portlist,"cause_1c");
e_match_timeout = 0;
unsched_timer(&e_match_timeout);
goto end;
}
#endif
@ -2230,10 +2235,11 @@ void EndpointAppPBX::process_dialing(void)
goto process_action;
}
if (e_match_timeout && now_d>=e_match_timeout) {
gettimeofday(&current_time, NULL);
if (timeout && TIME_SMALLER(&e_match_timeout.timeout, &current_time)) {
/* return timeout rule */
PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal '%s' dialing: '%s', timeout in ruleset '%s'\n", ea_endpoint->ep_serial, e_ext.number, e_dialinginfo.id, e_ruleset->name);
e_match_timeout = 0;
unsched_timer(&e_match_timeout);
e_action = e_match_to_action;
e_extdialing = e_match_to_extdialing;
trace_header("ROUTING (timeout)", DIRECTION_NONE);
@ -2272,9 +2278,9 @@ void EndpointAppPBX::process_dialing(void)
action_timeout:
/* set timeout */
e_action_timeout = 0;
unsched_timer(&e_action_timeout);
if (e_action->timeout) {
e_action_timeout = now_d + e_action->timeout;
schedule_timer(&e_action_timeout, e_action->timeout, 0);
PDEBUG(DEBUG_ROUTE|DEBUG_EPOINT, "EPOINT(%d): action has a timeout of %d secods.\n", ea_endpoint->ep_serial, e_action->timeout);
}

View File

@ -101,7 +101,7 @@ void EndpointAppPBX::action_init_vbox_play(void)
e_vbox_state = VBOX_STATE_MENU;
SCPY(e_vbox_display, (char *)((language)?"druecke 2 f. wiedergabe":"press 2 to play"));
e_vbox_display_refresh = 1;
schedule_timer(&e_vbox_refresh, 0, 0);
set_tone_vbox("menu");
e_vbox_menu = -1;
@ -112,7 +112,7 @@ void EndpointAppPBX::action_init_vbox_play(void)
if (e_vbox_index_num == 0) {
e_vbox_state = VBOX_STATE_NOTHING;
SCPY(e_vbox_display, (char *)((language)?"keine Anrufe":"no calls"));
e_vbox_display_refresh = 1;
schedule_timer(&e_vbox_refresh, 0, 0);
set_tone_vbox("nothing");
}
}
@ -232,6 +232,8 @@ void EndpointAppPBX::action_dialing_vbox_play(void)
int language = e_ext.vbox_language;
struct port_list *portlist;
class Port *port;
time_t current_time;
struct tm *current_tm;
portlist = ea_endpoint->ep_portlist;
@ -242,7 +244,7 @@ void EndpointAppPBX::action_dialing_vbox_play(void)
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing digit: %c\n", ea_endpoint->ep_serial, e_extdialing[0]);
e_vbox_display_refresh = 1;
schedule_timer(&e_vbox_refresh, 0, 0);
if (e_vbox_state == VBOX_STATE_RECORD_RECORD) {
if (e_extdialing[0] == '1' || e_extdialing[0] == '0') {
@ -280,10 +282,10 @@ void EndpointAppPBX::action_dialing_vbox_play(void)
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) play recoding.\n", ea_endpoint->ep_serial);
/* play announcement */
e_vbox_counter = 0;
e_vbox_counter_last = 0;
e_vbox_counter_max = 0;
e_vbox_speed = 1;
e_vbox_state = VBOX_STATE_RECORD_PLAY;
schedule_timer(&e_vbox_refresh, 0, 0);
if (e_ext.vbox_language)
SCPY(e_vbox_display, "Wied., 1=stop %s");
else
@ -396,10 +398,12 @@ void EndpointAppPBX::action_dialing_vbox_play(void)
e_vbox_state = VBOX_STATE_CALLINFO_INTRO;
SPRINT(e_vbox_display, "#%d", e_vbox_play+1);
vbox_index_read(e_vbox_play);
if (e_vbox_index_mon!=now_tm->tm_mon || e_vbox_index_year!=now_tm->tm_year) {
time(&current_time);
current_tm = localtime(&current_time);
if (e_vbox_index_mon!=current_tm->tm_mon || e_vbox_index_year!=current_tm->tm_year) {
UPRINT(strchr(e_vbox_display,'\0'), " %s", (language)?months_german[e_vbox_index_mon]:months_english[e_vbox_index_mon]);
}
if (e_vbox_index_mday!=now_tm->tm_mday || e_vbox_index_mon!=now_tm->tm_mon || e_vbox_index_year!=now_tm->tm_year) {
if (e_vbox_index_mday!=current_tm->tm_mday || e_vbox_index_mon!=current_tm->tm_mon || e_vbox_index_year!=current_tm->tm_year) {
UPRINT(strchr(e_vbox_display,'\0'), " %d", e_vbox_index_mday);
}
UPRINT(strchr(e_vbox_display,'\0'), " %02d:%02d", e_vbox_index_hour, e_vbox_index_min);
@ -419,10 +423,10 @@ void EndpointAppPBX::action_dialing_vbox_play(void)
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) play call #%d. abborting announcement and starting with playback\n", ea_endpoint->ep_serial, e_vbox_play+1);
/* the callinfo is played, so we start with the call */
e_vbox_counter = 0;
e_vbox_counter_last = 0;
e_vbox_counter_max = 0;
e_vbox_speed = 1;
e_vbox_state = VBOX_STATE_PLAY;
schedule_timer(&e_vbox_refresh, 0, 0);
SPRINT(e_vbox_display, "#%d %%s", e_vbox_play+1);
if (e_ext.vbox_display == VBOX_DISPLAY_DETAILED)
UPRINT(strchr(e_vbox_display,'\0'), " (%s)", e_vbox_index_callerid);
@ -558,7 +562,7 @@ void EndpointAppPBX::action_dialing_vbox_play(void)
SPRINT(e_dialinginfo.id, "extern:%s", e_vbox_index_callerid);
e_extdialing = e_dialinginfo.id;
e_action = NULL;
process_dialing();
process_dialing(0);
return;
}
break;
@ -600,31 +604,35 @@ void EndpointAppPBX::action_dialing_vbox_play(void)
/*
* this handler is called by Epoint::handler(), whenever the action is NUMB_ACTION_VBOX_PLAY
*/
void EndpointAppPBX::vbox_handler(void)
int vbox_refresh(struct lcr_timer *timer, void *instance, int index)
{
/* refresh if counter changes */
if (e_vbox_state==VBOX_STATE_PLAY || e_vbox_state==VBOX_STATE_RECORD_PLAY)
if (e_vbox_counter != e_vbox_counter_last) {
e_vbox_counter_last = e_vbox_counter;
e_vbox_display_refresh = 1;
}
class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
/* refresh display, if required (include counter) */
if (e_vbox_display_refresh && e_ext.vbox_display!=VBOX_DISPLAY_OFF) {
char counter[32];
struct lcr_msg *message;
/* no display */
if (ea->e_ext.vbox_display == VBOX_DISPLAY_OFF)
return 0;
SPRINT(counter, "%02d:%02d", e_vbox_counter/60, e_vbox_counter%60);
if (e_vbox_counter_max)
UPRINT(strchr(counter,'\0'), " of %02d:%02d", e_vbox_counter_max/60, e_vbox_counter_max%60);
/* refresh display */
char counter[32];
struct lcr_msg *message;
e_vbox_display_refresh = 0;
message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
SPRINT(message->param.notifyinfo.display, e_vbox_display, counter);
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) terminal %s pending display:%s\n", ea_endpoint->ep_serial, e_ext.number, message->param.notifyinfo.display);
message_put(message);
logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
}
SPRINT(counter, "%02d:%02d", ea->e_vbox_counter/60, ea->e_vbox_counter%60);
if (ea->e_vbox_counter_max)
UPRINT(strchr(counter,'\0'), " of %02d:%02d", ea->e_vbox_counter_max/60, ea->e_vbox_counter_max%60);
message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
SPRINT(message->param.notifyinfo.display, ea->e_vbox_display, counter);
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) terminal %s pending display:%s\n", ea->ea_endpoint->ep_serial, ea->e_ext.number, message->param.notifyinfo.display);
message_put(message);
ea->logmessage(message->type, &message->param, ea->ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
/* not playing anymore */
if (!ea->e_vbox_state==VBOX_STATE_PLAY && !ea->e_vbox_state==VBOX_STATE_RECORD_PLAY)
return 0;
schedule_timer(&ea->e_vbox_refresh, 1, 0);
return 0;
}
@ -636,6 +644,8 @@ void EndpointAppPBX::vbox_message_eof(void)
{
char buffer[32];
int language = e_ext.vbox_language;
time_t current_time;
struct tm *current_tm;
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) terminal %s end of file during state: %d\n", ea_endpoint->ep_serial, e_ext.number, e_vbox_state);
@ -644,7 +654,7 @@ void EndpointAppPBX::vbox_message_eof(void)
case VBOX_STATE_NOTHING:
e_vbox_state = VBOX_STATE_MENU;
SCPY(e_vbox_display, (char *)((language)?"druecke 2 f. wiedergabe":"press 2 to play"));
e_vbox_display_refresh = 1;
schedule_timer(&e_vbox_refresh, 0, 0);
set_tone_vbox("menu");
break;
@ -652,7 +662,7 @@ void EndpointAppPBX::vbox_message_eof(void)
if (e_vbox_speed > 0) {
e_vbox_state = VBOX_STATE_MENU;
SCPY(e_vbox_display, (char *)((language)?"druecke 3 f. Naechste":"press 3 for next"));
e_vbox_display_refresh = 1;
schedule_timer(&e_vbox_refresh, 0, 0);
set_tone_vbox("menu");
} else {
/* if we have endoffile because we were playing backwards, we continue to play forward */
@ -664,11 +674,13 @@ void EndpointAppPBX::vbox_message_eof(void)
case VBOX_STATE_PAUSE:
SCPY(e_vbox_display, (char *)((language)?"druecke 2 f. weiterspielen":"press 2 to continue"));
e_vbox_display_refresh = 1;
schedule_timer(&e_vbox_refresh, 0, 0);
break;
case VBOX_STATE_CALLINFO_INTRO:
if (e_vbox_index_mday==now_tm->tm_mday && e_vbox_index_mon==now_tm->tm_mon && e_vbox_index_year==now_tm->tm_year)
time(&current_time);
current_tm = localtime(&current_time);
if (e_vbox_index_mday==current_tm->tm_mday && e_vbox_index_mon==current_tm->tm_mon && e_vbox_index_year==current_tm->tm_year)
goto skip_day_month;
e_vbox_state = VBOX_STATE_CALLINFO_MONTH; //german day
if (e_ext.vbox_language)
@ -764,37 +776,37 @@ void EndpointAppPBX::vbox_message_eof(void)
} else {
/* the callinfo is played, so we start with the call */
e_vbox_counter = 0;
e_vbox_counter_last = 0;
e_vbox_counter_max = 0;
e_vbox_speed = 1;
e_vbox_state = VBOX_STATE_PLAY;
schedule_timer(&e_vbox_refresh, 0, 0);
SPRINT(e_vbox_display, "#%d %%s", e_vbox_play);
if (e_ext.vbox_display == VBOX_DISPLAY_DETAILED)
UPRINT(strchr(e_vbox_display,'\0'), " (%s)", e_vbox_index_callerid);
e_vbox_display_refresh = 1;
schedule_timer(&e_vbox_refresh, 0, 0);
set_play_vbox(e_vbox_index_file, 0);
}
break;
case VBOX_STATE_RECORD_ASK:
set_tone_vbox("record_ask");
e_vbox_display_refresh = 1;
schedule_timer(&e_vbox_refresh, 0, 0);
break;
case VBOX_STATE_STORE_ASK:
set_tone_vbox("store_ask");
e_vbox_display_refresh = 1;
schedule_timer(&e_vbox_refresh, 0, 0);
break;
case VBOX_STATE_DELETE_ASK:
set_tone_vbox("delete_ask");
e_vbox_display_refresh = 1;
schedule_timer(&e_vbox_refresh, 0, 0);
break;
case VBOX_STATE_RECORD_PLAY:
e_vbox_state = VBOX_STATE_RECORD_ASK;
SCPY(e_vbox_display, (char *)((language)?"1=Aufn. 2=Wied. 3=nein":"1=record 2=play 3=no"));
e_vbox_display_refresh = 1;
schedule_timer(&e_vbox_refresh, 0, 0);
set_tone_vbox("record_ask");
break;
@ -803,12 +815,12 @@ void EndpointAppPBX::vbox_message_eof(void)
if (e_vbox_index_num == 0) { /* nothing to play */
e_vbox_state = VBOX_STATE_MENU;
SCPY(e_vbox_display, (char *)((language)?"keine Anrufe":"no calls"));
e_vbox_display_refresh = 1;
schedule_timer(&e_vbox_refresh, 0, 0);
set_tone_vbox("nothing");
} else {
e_vbox_state = VBOX_STATE_MENU;
SCPY(e_vbox_display, (char *)((language)?"druecke 2 f. wiedergabe":"press 2 to play"));
e_vbox_display_refresh = 1;
schedule_timer(&e_vbox_refresh, 0, 0);
set_tone_vbox("menu");
}
break;

View File

@ -14,6 +14,15 @@
class EndpointAppPBX *apppbx_first = NULL;
int action_timeout(struct lcr_timer *timer, void *instance, int index);
int match_timeout(struct lcr_timer *timer, void *instance, int index);
int redial_timeout(struct lcr_timer *timer, void *instance, int index);
int powerdial_timeout(struct lcr_timer *timer, void *instance, int index);
int cfnr_timeout(struct lcr_timer *timer, void *instance, int index);
int cfnr_call_timeout(struct lcr_timer *timer, void *instance, int index);
int password_timeout(struct lcr_timer *timer, void *instance, int index);
int callback_timeout(struct lcr_timer *timer, void *instance, int index);
/*
* EndpointAppPBX constructor
*/
@ -21,6 +30,28 @@ EndpointAppPBX::EndpointAppPBX(class Endpoint *epoint, int origin) : EndpointApp
{
class EndpointAppPBX **apppointer;
memset(&e_crypt_handler, 0, sizeof(e_crypt_handler));
add_timer(&e_crypt_handler, crypt_handler, this, 0);
memset(&e_vbox_refresh, 0, sizeof(e_vbox_refresh));
add_timer(&e_vbox_refresh, vbox_refresh, this, 0);
memset(&e_action_timeout, 0, sizeof(e_action_timeout));
add_timer(&e_action_timeout, action_timeout, this, 0);
memset(&e_match_timeout, 0, sizeof(e_match_timeout));
add_timer(&e_match_timeout, match_timeout, this, 0);
memset(&e_redial_timeout, 0, sizeof(e_redial_timeout));
add_timer(&e_redial_timeout, redial_timeout, this, 0);
memset(&e_powerdial_timeout, 0, sizeof(e_powerdial_timeout));
add_timer(&e_powerdial_timeout, powerdial_timeout, this, 0);
memset(&e_cfnr_timeout, 0, sizeof(e_cfnr_timeout));
add_timer(&e_cfnr_timeout, cfnr_timeout, this, 0);
memset(&e_cfnr_call_timeout, 0, sizeof(e_cfnr_call_timeout));
add_timer(&e_cfnr_call_timeout, cfnr_call_timeout, this, 0);
memset(&e_callback_timeout, 0, sizeof(e_callback_timeout));
add_timer(&e_callback_timeout, callback_timeout, this, 0);
memset(&e_password_timeout, 0, sizeof(e_password_timeout));
add_timer(&e_password_timeout, password_timeout, this, 0);
e_powerdial_on = 0;
/* add application to chain */
next = NULL;
apppointer = &apppbx_first;
@ -48,8 +79,6 @@ EndpointAppPBX::EndpointAppPBX(class Endpoint *epoint, int origin) : EndpointApp
e_rule = e_ruleset->rule_first;
e_rule_nesting = 0;
e_action = NULL;
e_action_timeout = 0;
e_match_timeout = 0;
e_match_to_action = NULL;
e_select = 0;
e_extdialing = e_dialinginfo.id;
@ -58,13 +87,10 @@ EndpointAppPBX::EndpointAppPBX(class Endpoint *epoint, int origin) : EndpointApp
e_hold = 0;
// e_join_tone[0] = e_hold_tone[0] = '\0';
e_join_pattern /*= e_hold_pattern*/ = 0;
e_redial = 0;
e_tone[0] = '\0';
e_adminid = 0; // will be set, if call was initiated via admin socket
e_powerdialing = 0;
e_powerdelay = 0;
e_powerlimit = 0;
e_callback = 0;
e_cbdialing[0] = '\0';
e_cbcaller[0] = '\0';
e_cbto[0] = '\0';
@ -74,9 +100,6 @@ EndpointAppPBX::EndpointAppPBX(class Endpoint *epoint, int origin) : EndpointApp
e_dtmf_time = 0;
e_dtmf_last = 0;
e_enablekeypad = 0;
e_cfnr_release = 0;
e_cfnr_call = 0;
e_password_timeout = 0;
e_multipoint_cause = 0;
e_multipoint_location = 0;
e_dialing_queue[0] = '\0';
@ -107,6 +130,17 @@ EndpointAppPBX::~EndpointAppPBX(void)
{
class EndpointAppPBX *temp, **tempp;
del_timer(&e_crypt_handler);
del_timer(&e_vbox_refresh);
del_timer(&e_action_timeout);
del_timer(&e_match_timeout);
del_timer(&e_redial_timeout);
del_timer(&e_powerdial_timeout);
del_timer(&e_cfnr_timeout);
del_timer(&e_cfnr_call_timeout);
del_timer(&e_callback_timeout);
del_timer(&e_password_timeout);
/* detach */
temp =apppbx_first;
tempp = &apppbx_first;
@ -211,7 +245,7 @@ void EndpointAppPBX::release(int release, int joinlocation, int joincause, int p
}
/* if callback is enabled, call back with the given caller id */
if (e_callback) {
if (e_callback_timeout.active) {
/* reset some stuff */
new_state(EPOINT_STATE_IDLE);
memset(&e_connectinfo, 0, sizeof(struct connect_info));
@ -221,8 +255,10 @@ void EndpointAppPBX::release(int release, int joinlocation, int joincause, int p
if (e_ruleset)
e_rule = e_ruleset->rule_first;
e_action = NULL;
e_action_timeout = 0;
e_match_timeout = 0;
unsched_timer(&e_action_timeout);
unsched_timer(&e_match_timeout);
unsched_timer(&e_cfnr_timeout);
unsched_timer(&e_cfnr_call_timeout);
e_match_to_action = NULL;
//e_select = 0;
e_extdialing = e_dialinginfo.id;
@ -231,8 +267,6 @@ void EndpointAppPBX::release(int release, int joinlocation, int joincause, int p
e_dtmf_time = 0;
e_dtmf_last = 0;
e_enablekeypad = 0;
e_cfnr_release = 0;
e_cfnr_call = 0;
e_multipoint_cause = 0;
e_multipoint_location = 0;
e_dialing_queue[0] = '\0';
@ -273,7 +307,8 @@ void EndpointAppPBX::release(int release, int joinlocation, int joincause, int p
}
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) do pending release of epoint itself.\n", ea_endpoint->ep_serial);
ea_endpoint->ep_use--; /* when e_lock is 0, the endpoint will be deleted */
if (--ea_endpoint->ep_use <= 0) /* when e_lock is 0, the endpoint will be deleted */
trigger_work(&ea_endpoint->ep_delete);
return;
}
}
@ -901,7 +936,7 @@ void EndpointAppPBX::out_setup(void)
p = e_ext.cfnr;
if (*p) {
/* when cfnr is done, out_setup() will setup the call */
if (e_cfnr_call) {
if (e_cfnr_call_timeout.active) {
/* present to forwarded party */
if (e_ext.anon_ignore && e_callerinfo.id[0]) {
e_callerinfo.present = INFO_PRESENT_ALLOWED;
@ -909,8 +944,8 @@ void EndpointAppPBX::out_setup(void)
goto cfnr_only;
}
if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH)) {
e_cfnr_release = now + e_ext.cfnr_delay;
e_cfnr_call = now + e_ext.cfnr_delay + 1; /* call one second after release */
schedule_timer(&e_cfnr_timeout, e_ext.cfnr_delay, 0);
schedule_timer(&e_cfnr_call_timeout, e_ext.cfnr_delay + 1, 0); /* call one second after release */
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) setting time for call-forward-busy to %s with delay %ld.\n", ea_endpoint->ep_serial, e_ext.cfnr, e_ext.cfnr_delay);
}
}
@ -1218,163 +1253,157 @@ void EndpointAppPBX::out_setup(void)
}
/* handler for endpoint
*/
extern int quit;
int EndpointAppPBX::handler(void)
int action_timeout(struct lcr_timer *timer, void *instance, int index)
{
if (e_crypt_state!=CM_ST_NULL) {
cryptman_handler();
}
class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
/* process answering machine (play) handling */
if (e_action) {
if (e_action->index == ACTION_VBOX_PLAY)
vbox_handler();
if (!ea->e_action || ea->e_state == EPOINT_STATE_CONNECT)
return 0;
/* process action timeout */
if (e_action_timeout)
if (now_d >= e_action_timeout) {
if (e_state!=EPOINT_STATE_CONNECT) {
e_redial = 0;
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current action timed out.\n", ea_endpoint->ep_serial);
e_multipoint_cause = 0;
e_multipoint_location = 0;
new_state(EPOINT_STATE_IN_OVERLAP);
e_join_pattern = 0;
process_dialing();
return(1); /* we must exit, because our endpoint might be gone */
} else
e_action_timeout = 0;
}
} else {
/* process action timeout */
if (e_match_timeout)
if (now_d >= e_match_timeout) {
e_redial = 0;
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we got a match timeout.\n", ea_endpoint->ep_serial);
process_dialing();
return(1); /* we must exit, because our endpoint might be gone */
}
}
unsched_timer(&ea->e_redial_timeout);
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current action timed out.\n", ea->ea_endpoint->ep_serial);
ea->e_multipoint_cause = 0;
ea->e_multipoint_location = 0;
ea->new_state(EPOINT_STATE_IN_OVERLAP);
ea->e_join_pattern = 0;
ea->process_dialing(1);
/* we must exit, because our endpoint might be gone */
/* process redialing (epoint redials to port) */
if (e_redial) {
if (now_d >= e_redial) {
e_redial = 0;
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial.\n", ea_endpoint->ep_serial);
new_state(EPOINT_STATE_OUT_SETUP);
/* call special setup routine */
out_setup();
return(1);
}
}
/* process powerdialing (epoint redials to epoint) */
if (e_powerdialing > 0) {
if (now_d >= e_powerdialing) {
e_powerdialing = -1; /* leave power dialing on */
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial of powerdial.\n", ea_endpoint->ep_serial);
/* redial */
e_ruleset = ruleset_main;
if (e_ruleset)
e_rule = e_ruleset->rule_first;
e_action = NULL;
new_state(EPOINT_STATE_IN_OVERLAP);
process_dialing();
return(1);
}
}
/* process call forward no response */
if (e_cfnr_release) {
struct port_list *portlist;
struct lcr_msg *message;
if (now >= e_cfnr_release) {
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-no-response time has expired, hanging up.\n", ea_endpoint->ep_serial);
e_cfnr_release = 0;
/* release all ports */
while((portlist = ea_endpoint->ep_portlist)) {
message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
message_put(message);
logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
ea_endpoint->free_portlist(portlist);
}
/* put on hold */
message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
message->param.audiopath = 0;
message_put(message);
/* indicate no patterns */
message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
message_put(message);
/* set setup state, since we have no response from the new join */
new_state(EPOINT_STATE_OUT_SETUP);
}
} else
if (e_cfnr_call) {
if (now >= e_cfnr_call) {
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-busy time has expired, calling the forwarded number: %s.\n", ea_endpoint->ep_serial, e_ext.cfnr);
out_setup();
e_cfnr_call = 0;
}
}
/* handle connection to user */
if (e_state == EPOINT_STATE_IDLE) {
/* epoint is idle, check callback */
if (e_callback)
if (now_d >= e_callback) {
e_callback = 0; /* done with callback */
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting callback.\n", ea_endpoint->ep_serial);
new_state(EPOINT_STATE_OUT_SETUP);
out_setup();
return(1);
}
}
/* check for password timeout */
if (e_action)
if (e_action->index==ACTION_PASSWORD || e_action->index==ACTION_PASSWORD_WRITE) {
struct port_list *portlist;
if (now >= e_password_timeout) {
e_ruleset = ruleset_main;
if (e_ruleset)
e_rule = e_ruleset->rule_first;
e_action = NULL;
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) password timeout %s\n", ea_endpoint->ep_serial, e_extdialing);
trace_header("PASSWORD timeout", DIRECTION_NONE);
end_trace();
e_connectedmode = 0;
e_dtmf = 0;
new_state(EPOINT_STATE_OUT_DISCONNECT);
portlist = ea_endpoint->ep_portlist;
if (portlist) {
message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
set_tone(portlist, "cause_10");
}
return(1);
}
}
return(0);
return 0;
}
int match_timeout(struct lcr_timer *timer, void *instance, int index)
{
class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
if (!ea->e_action) {
unsched_timer(&ea->e_redial_timeout);
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we got a match timeout.\n", ea->ea_endpoint->ep_serial);
ea->process_dialing(0);
/* we must exit, because our endpoint might be gone */
}
return 0;
}
int redial_timeout(struct lcr_timer *timer, void *instance, int index)
{
class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial.\n", ea->ea_endpoint->ep_serial);
ea->new_state(EPOINT_STATE_OUT_SETUP);
/* call special setup routine */
ea->out_setup();
return 0;
}
int powerdial_timeout(struct lcr_timer *timer, void *instance, int index)
{
class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
/* leave power dialing on */
ea->e_powerdial_on = 1;
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial of powerdial.\n", ea->ea_endpoint->ep_serial);
/* redial */
ea->e_ruleset = ruleset_main;
if (ea->e_ruleset)
ea->e_rule = ea->e_ruleset->rule_first;
ea->e_action = NULL;
ea->new_state(EPOINT_STATE_IN_OVERLAP);
ea->process_dialing(0);
return 0;
}
int cfnr_timeout(struct lcr_timer *timer, void *instance, int index)
{
class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
struct port_list *portlist;
struct lcr_msg *message;
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-no-response time has expired, hanging up.\n", ea->ea_endpoint->ep_serial);
/* release all ports */
while((portlist = ea->ea_endpoint->ep_portlist)) {
message = message_create(ea->ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
message_put(message);
ea->logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
ea->ea_endpoint->free_portlist(portlist);
}
/* put on hold */
message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
message->param.audiopath = 0;
message_put(message);
/* indicate no patterns */
message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
message_put(message);
/* set setup state, since we have no response from the new join */
ea->new_state(EPOINT_STATE_OUT_SETUP);
return 0;
}
int cfnr_call_timeout(struct lcr_timer *timer, void *instance, int index)
{
class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-busy time has expired, calling the forwarded number: %s.\n", ea->ea_endpoint->ep_serial, ea->e_ext.cfnr);
ea->out_setup();
return 0;
}
int callback_timeout(struct lcr_timer *timer, void *instance, int index)
{
class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
if (ea->e_state == EPOINT_STATE_IDLE) {
/* epoint is idle, check callback */
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting callback.\n", ea->ea_endpoint->ep_serial);
ea->new_state(EPOINT_STATE_OUT_SETUP);
ea->out_setup();
}
return 0;
}
int password_timeout(struct lcr_timer *timer, void *instance, int index)
{
class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
if (ea->e_action->index==ACTION_PASSWORD || ea->e_action->index==ACTION_PASSWORD_WRITE) {
struct port_list *portlist;
ea->e_ruleset = ruleset_main;
if (ea->e_ruleset)
ea->e_rule = ea->e_ruleset->rule_first;
ea->e_action = NULL;
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) password timeout %s\n", ea->ea_endpoint->ep_serial, ea->e_extdialing);
ea->trace_header("PASSWORD timeout", DIRECTION_NONE);
end_trace();
ea->e_connectedmode = 0;
ea->e_dtmf = 0;
ea->new_state(EPOINT_STATE_OUT_DISCONNECT);
portlist = ea->ea_endpoint->ep_portlist;
if (portlist) {
ea->message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
ea->set_tone(portlist, "cause_10");
}
}
return 0;
}
/* doing a hookflash */
void EndpointAppPBX::hookflash(void)
{
class Port *port;
time_t now;
/* be sure that we are active */
notify_active();
@ -1408,10 +1437,11 @@ void EndpointAppPBX::hookflash(void)
e_join_pattern = 0;
if (e_dialinginfo.id[0]) {
set_tone(ea_endpoint->ep_portlist, "dialing");
process_dialing();
process_dialing(0);
} else {
set_tone(ea_endpoint->ep_portlist, "dialpbx");
}
time(&now);
e_dtmf_time = now;
e_dtmf_last = '\0';
}
@ -1566,7 +1596,7 @@ void EndpointAppPBX::port_setup(struct port_list *portlist, int message_type, un
else
set_tone(portlist, "dialtone");
}
process_dialing();
process_dialing(0);
if (e_state == EPOINT_STATE_IN_SETUP) {
/* request MORE info, if not already at higher state */
new_state(EPOINT_STATE_IN_OVERLAP);
@ -1599,7 +1629,7 @@ void EndpointAppPBX::port_information(struct port_list *portlist, int message_ty
if (e_action->index == ACTION_VBOX_PLAY) {
/* concat dialing string */
SCAT(e_dialinginfo.id, param->information.id);
process_dialing();
process_dialing(0);
return;
}
@ -1656,12 +1686,16 @@ void EndpointAppPBX::port_information(struct port_list *portlist, int message_ty
}
/* concat dialing string */
SCAT(e_dialinginfo.id, param->information.id);
process_dialing();
process_dialing(0);
}
/* port MESSAGE_DTMF */
void EndpointAppPBX::port_dtmf(struct port_list *portlist, int message_type, union parameter *param)
{
time_t now;
time(&now);
/* only if dtmf detection is enabled */
if (!e_dtmf) {
trace_header("DTMF (disabled)", DIRECTION_IN);
@ -1681,7 +1715,7 @@ NOTE: vbox is now handled due to overlap state
if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
process_dialing();
process_dialing(0);
}
/* continue to process *X# sequences */
}
@ -1755,7 +1789,7 @@ NOTE: vbox is now handled due to overlap state
if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
process_dialing();
process_dialing(0);
}
}
}
@ -1909,6 +1943,7 @@ void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type,
struct port_list *tportlist;
class Port *port;
struct interface *interface;
time_t now;
logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
@ -1932,6 +1967,7 @@ void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type,
}
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (end)\n", ea_endpoint->ep_serial);
time(&now);
e_start = now;
/* screen incoming connected id */
@ -1979,7 +2015,8 @@ void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type,
message_put(message);
}
e_cfnr_call = e_cfnr_release = 0;
unsched_timer(&e_cfnr_timeout);
unsched_timer(&e_cfnr_call_timeout);
if (e_ext.number[0])
e_dtmf = 1; /* allow dtmf */
@ -2053,12 +2090,12 @@ void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type,
/* make call state to enter password */
new_state(EPOINT_STATE_IN_OVERLAP);
e_action = &action_password_write;
e_match_timeout = 0;
unsched_timer(&e_match_timeout);
e_match_to_action = NULL;
e_dialinginfo.id[0] = '\0';
e_extdialing = strchr(e_dialinginfo.id, '\0');
e_password_timeout = now+20;
process_dialing();
schedule_timer(&e_password_timeout, 20, 0);
process_dialing(0);
} else {
/* incoming call (callback) */
e_ruleset = ruleset_main;
@ -2068,7 +2105,7 @@ void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type,
e_extdialing = e_dialinginfo.id;
if (e_dialinginfo.id[0]) {
set_tone(portlist, "dialing");
process_dialing();
process_dialing(0);
} else {
set_tone(portlist, "dialpbx");
}
@ -2151,7 +2188,8 @@ void EndpointAppPBX::port_disconnect_release(struct port_list *portlist, int mes
}
}
e_cfnr_call = e_cfnr_release = 0;
unsched_timer(&e_cfnr_timeout);
unsched_timer(&e_cfnr_call_timeout);
/* process hangup */
process_hangup(e_join_cause, e_join_location);
@ -2816,6 +2854,7 @@ void EndpointAppPBX::join_alerting(struct port_list *portlist, int message_type,
void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type, union parameter *param)
{
struct lcr_msg *message;
time_t now;
new_state(EPOINT_STATE_CONNECT);
// UCPY(e_join_tone, "");
@ -2823,7 +2862,8 @@ void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type,
if (e_ext.number[0])
e_dtmf = 1; /* allow dtmf */
e_powerdialing = 0;
e_powerdial_on = 0;
unsched_timer(&e_powerdial_timeout);
memcpy(&e_connectinfo, &param->connectinfo, sizeof(e_callerinfo));
if(portlist) {
message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
@ -2860,6 +2900,7 @@ void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type,
message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
message->param.audiopath = 1;
message_put(message);
time(&now);
e_start = now;
}
@ -2869,18 +2910,19 @@ void EndpointAppPBX::join_disconnect_release(int message_type, union parameter *
char cause[16];
struct lcr_msg *message;
struct port_list *portlist = NULL;
time_t now;
/* be sure that we are active */
notify_active();
e_tx_state = NOTIFY_STATE_ACTIVE;
/* we are powerdialing, if e_powerdialing is set and limit is not exceeded if given */
if (e_powerdialing && ((e_powercount+1)<e_powerlimit || e_powerlimit<1)) {
/* we are powerdialing, if e_powerdial_on is set and limit is not exceeded if given */
if (e_powerdial_on && ((e_powercount+1)<e_powerlimit || e_powerlimit<1)) {
release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
/* set time for power dialing */
e_powerdialing = now_d + e_powerdelay; /* set redial in the future */
schedule_timer(&e_powerdial_timeout, (int)e_powerdelay, 0); /* set redial in the future */
e_powercount++;
/* set redial tone */
@ -2918,6 +2960,7 @@ void EndpointAppPBX::join_disconnect_release(int message_type, union parameter *
}
/* set stop time */
time(&now);
e_stop = now;
if ((e_state!=EPOINT_STATE_CONNECT
@ -3002,11 +3045,11 @@ void EndpointAppPBX::join_setup(struct port_list *portlist, int message_type, un
new_state(EPOINT_STATE_OUT_OVERLAP);
/* get time */
e_redial = now_d + 1; /* set redial one second in the future */
schedule_timer(&e_redial_timeout, 1, 0);
return;
}
/* if we have a pending redial, so we just adjust the dialing number */
if (e_redial) {
if (e_redial_timeout.active) {
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) redial in progress, so we update the dialing number to %s.\n", ea_endpoint->ep_serial, param->setup.dialinginfo.id);
memcpy(&e_dialinginfo, &param->setup.dialinginfo, sizeof(e_dialinginfo));
return;
@ -3525,7 +3568,7 @@ reject:
message_put(message);
/* beeing paranoid, we make call update */
joinpbx->j_updatebridge = 1;
trigger_work(&joinpbx->j_updatebridge);
if (options.deb & DEBUG_EPOINT) {
class Join *debug_c = join_first;
@ -3703,7 +3746,7 @@ void EndpointAppPBX::join_join(void)
PDEBUG(DEBUG_EPOINT, "EPOINT(%d)d-join completely removed!\n");
/* mixer must update */
our_joinpbx->j_updatebridge = 1; /* update mixer flag */
trigger_work(&our_joinpbx->j_updatebridge);
/* we send a retrieve to that endpoint */
// mixer will update the hold-state of the join and send it to the endpoints is changes

View File

@ -49,6 +49,8 @@ static const char *state_name[] = { \
}; \
int state_name_num = sizeof(state_name) / sizeof(char *);
int vbox_refresh(struct lcr_timer *timer, void *instance, int index);
extern class EndpointAppPBX *apppbx_first;
/* structure of an EndpointAppPBX */
@ -59,7 +61,6 @@ class EndpointAppPBX : public EndpointApp
~EndpointAppPBX();
class EndpointAppPBX *next;
int handler(void);
int e_hold; /* is this endpoint on hold ? */
char e_tone[256]; /* save tone for resuming ports */
@ -79,9 +80,7 @@ class EndpointAppPBX : public EndpointApp
struct route_ruleset *e_ruleset; /* current ruleset pointer (NULL=no ruleset) */
struct route_rule *e_rule; /* current rule pointer (NULL=no rule) */
struct route_action *e_action; /* current action pointer (NULL=no action) */
double e_action_timeout; /* when to timeout */
int e_rule_nesting; /* 'goto'/'menu' recrusion counter to prevent infinie loops */
double e_match_timeout; /* set for the next possible timeout time */
struct route_action *e_match_to_action; /* what todo when timeout */
char *e_match_to_extdialing; /* dialing after matching timeout rule */
int e_select; /* current selection for various selector options */
@ -97,15 +96,11 @@ class EndpointAppPBX : public EndpointApp
/* action */
char e_dialing_queue[32]; /* holds dialing during setup state */
double e_redial; /* time when redialing 0=off */
double e_powerdialing; /* on disconnect redial! 0=off, >0=redial time, -1=on */
double e_powerdelay; /* delay when to redial */
int e_powercount; /* power count */
int e_powerlimit; /* power limit */
double e_callback; /* time when callback (when idle reached) 0=off */
signed int e_cfnr_release; /* time stamp when to do the release for call forward on no response */
signed int e_cfnr_call; /* time stamp when to do the call for call forward on no response */
signed int e_password_timeout; /* time stamp when to do the release for password timeout */
struct lcr_timer e_action_timeout;
struct lcr_timer e_match_timeout;
/* port relation */
int e_multipoint_cause; /* cause value of disconnected multiport calls (highest priority) */
@ -120,6 +115,13 @@ class EndpointAppPBX : public EndpointApp
char e_cbcaller[256]; /* extension for the epoint which calls back */
char e_cbto[32]; /* override callerid to call back to */
struct caller_info e_callbackinfo; /* information about the callback caller */
struct lcr_timer e_redial_timeout;
int e_powerdial_on;
struct lcr_timer e_powerdial_timeout;
struct lcr_timer e_cfnr_timeout;
struct lcr_timer e_cfnr_call_timeout;
struct lcr_timer e_callback_timeout;
struct lcr_timer e_password_timeout;
/* dtmf stuff */
int e_connectedmode; /* if the port should stay connected if the enpoint disconnects or releases (usefull for callback) */
@ -138,7 +140,7 @@ class EndpointAppPBX : public EndpointApp
int e_vbox_state; /* state of vbox during playback */
int e_vbox_menu; /* currently selected menu using '*' and '#' */
char e_vbox_display[128]; /* current display message */
int e_vbox_display_refresh; /* display must be refreshed du to change */
struct lcr_timer e_vbox_refresh; /* display must be refreshed du to change */
int e_vbox_counter; /* current playback counter in seconds */
int e_vbox_counter_max; /* size of file in seconds */
int e_vbox_counter_last; /* temp variable to recognise a change in seconds */
@ -188,6 +190,7 @@ class EndpointAppPBX : public EndpointApp
int e_crypt_rsa_iqmp_len;
int e_crypt_keyengine_busy; /* current job and busy state */
int e_crypt_keyengine_return; /* return */
struct lcr_timer e_crypt_handler; /* poll timer for crypt events */
/* messages */
void hookflash(void);
@ -234,7 +237,6 @@ class EndpointAppPBX : public EndpointApp
void vbox_init(void);
void vbox_index_read(int num);
void vbox_index_remove(int num);
void vbox_handler(void);
void efi_message_eof(void);
void vbox_message_eof(void);
void set_tone_vbox(const char *tone);
@ -296,7 +298,7 @@ class EndpointAppPBX : public EndpointApp
void action_init_pick(void);
void action_dialing_password(void);
void action_dialing_password_wr(void);
void process_dialing(void);
void process_dialing(int timeout);
void process_hangup(int cause, int location);
/* facility function */
@ -310,7 +312,6 @@ class EndpointAppPBX : public EndpointApp
/* crypt */
void cryptman_keyengine(int job);
void cryptman_handler(void);
void cr_ident(int message, unsigned char *param, int len);
void cr_activate(int message, unsigned char *param, int len);
void cr_deactivate(int message, unsigned char *param, int len);

View File

@ -50,6 +50,7 @@
#include "message.h"
#include "lcrsocket.h"
#include "cause.h"
#include "select.h"
#include "bchannel.h"
#include "chan_lcr.h"
#include "callerid.h"
@ -73,7 +74,7 @@ int bchannel_initialize(void)
{
init_af_isdn();
return(0);
return 0;
}
void bchannel_deinitialize(void)
@ -123,6 +124,7 @@ static void ph_control_block(int sock, unsigned int c1, void *c2, int c2_len, ch
CERROR(NULL, NULL, "Failed to send to socket %d\n", sock);
}
static int bchannel_handle(struct lcr_fd *fd, unsigned int what, void *instance, int index);
/*
* create stack
@ -130,12 +132,11 @@ static void ph_control_block(int sock, unsigned int c1, void *c2, int c2_len, ch
int bchannel_create(struct bchannel *bchannel, int mode)
{
int ret;
unsigned int on = 1;
struct sockaddr_mISDN addr;
if (bchannel->b_sock > -1) {
CERROR(bchannel->call, NULL, "Socket already created for handle 0x%x\n", bchannel->handle);
return(0);
return 0;
}
/* open socket */
@ -160,18 +161,14 @@ int bchannel_create(struct bchannel *bchannel, int mode)
}
if (bchannel->b_sock < 0) {
CERROR(bchannel->call, NULL, "Failed to open bchannel-socket for handle 0x%x with mISDN-DSP layer. Did you load mISDN_dsp.ko?\n", bchannel->handle);
return(0);
}
/* set nonblocking io */
ret = ioctl(bchannel->b_sock, FIONBIO, &on);
if (ret < 0) {
CERROR(bchannel->call, NULL, "Failed to set bchannel-socket handle 0x%x into nonblocking IO\n", bchannel->handle);
close(bchannel->b_sock);
bchannel->b_sock = -1;
return(0);
return 0;
}
/* register fd */
memset(&bchannel->lcr_fd, 0, sizeof(bchannel->lcr_fd));
bchannel->lcr_fd.fd = bchannel->b_sock;
register_fd(&bchannel->lcr_fd, LCR_FD_READ | LCR_FD_EXCEPT, bchannel_handle, bchannel, 0);
/* bind socket to bchannel */
addr.family = AF_ISDN;
addr.dev = (bchannel->handle>>8);
@ -179,11 +176,12 @@ int bchannel_create(struct bchannel *bchannel, int mode)
ret = bind(bchannel->b_sock, (struct sockaddr *)&addr, sizeof(addr));
if (ret < 0) {
CERROR(bchannel->call, NULL, "Failed to bind bchannel-socket for handle 0x%x with mISDN-DSP layer. (port %d, channel %d) Did you load mISDN_dsp.ko?\n", bchannel->handle, addr.dev, addr.channel);
unregister_fd(&bchannel->lcr_fd);
close(bchannel->b_sock);
bchannel->b_sock = -1;
return(0);
return 0;
}
return(1);
return 1;
}
@ -264,6 +262,7 @@ static void bchannel_activated(struct bchannel *bchannel)
void bchannel_destroy(struct bchannel *bchannel)
{
if (bchannel->b_sock > -1) {
unregister_fd(&bchannel->lcr_fd);
close(bchannel->b_sock);
bchannel->b_sock = -1;
}
@ -517,63 +516,54 @@ void bchannel_gain(struct bchannel *bchannel, int gain, int tx)
/*
* main loop for processing messages from mISDN
*/
int bchannel_handle(void)
static int bchannel_handle(struct lcr_fd *fd, unsigned int what, void *instance, int index)
{
int ret, work = 0;
struct bchannel *bchannel;
struct bchannel *bchannel = (struct bchannel *)instance;
int ret;
unsigned char buffer[2048+MISDN_HEADER_LEN];
struct mISDNhead *hh = (struct mISDNhead *)buffer;
/* process all bchannels */
bchannel = bchannel_first;
while(bchannel) {
/* handle message from bchannel */
if (bchannel->b_sock > -1) {
ret = recv(bchannel->b_sock, buffer, sizeof(buffer), 0);
if (ret >= (int)MISDN_HEADER_LEN) {
work = 1;
switch(hh->prim) {
/* we don't care about confirms, we use rx data to sync tx */
case PH_DATA_CNF:
break;
ret = recv(bchannel->b_sock, buffer, sizeof(buffer), 0);
if (ret >= (int)MISDN_HEADER_LEN) {
switch(hh->prim) {
/* we don't care about confirms, we use rx data to sync tx */
case PH_DATA_CNF:
break;
/* we receive audio data, we respond to it AND we send tones */
case PH_DATA_IND:
case PH_DATA_REQ:
case DL_DATA_IND:
case PH_CONTROL_IND:
bchannel_receive(bchannel, buffer, ret-MISDN_HEADER_LEN);
break;
/* we receive audio data, we respond to it AND we send tones */
case PH_DATA_IND:
case PH_DATA_REQ:
case DL_DATA_IND:
case PH_CONTROL_IND:
bchannel_receive(bchannel, buffer, ret-MISDN_HEADER_LEN);
break;
case PH_ACTIVATE_IND:
case DL_ESTABLISH_IND:
case PH_ACTIVATE_CNF:
case DL_ESTABLISH_CNF:
CDEBUG(bchannel->call, NULL, "DL_ESTABLISH confirm: bchannel is now activated (socket %d).\n", bchannel->b_sock);
bchannel_activated(bchannel);
break;
case PH_ACTIVATE_IND:
case DL_ESTABLISH_IND:
case PH_ACTIVATE_CNF:
case DL_ESTABLISH_CNF:
CDEBUG(bchannel->call, NULL, "DL_ESTABLISH confirm: bchannel is now activated (socket %d).\n", bchannel->b_sock);
bchannel_activated(bchannel);
break;
case PH_DEACTIVATE_IND:
case DL_RELEASE_IND:
case PH_DEACTIVATE_CNF:
case DL_RELEASE_CNF:
CDEBUG(bchannel->call, NULL, "DL_RELEASE confirm: bchannel is now de-activated (socket %d).\n", bchannel->b_sock);
case PH_DEACTIVATE_IND:
case DL_RELEASE_IND:
case PH_DEACTIVATE_CNF:
case DL_RELEASE_CNF:
CDEBUG(bchannel->call, NULL, "DL_RELEASE confirm: bchannel is now de-activated (socket %d).\n", bchannel->b_sock);
// bchannel_deactivated(bchannel);
break;
break;
default:
CERROR(bchannel->call, NULL, "child message not handled: prim(0x%x) socket(%d) data len(%d)\n", hh->prim, bchannel->b_sock, ret - MISDN_HEADER_LEN);
}
} else {
if (ret < 0 && errno != EWOULDBLOCK)
CERROR(bchannel->call, NULL, "Read from socket %d failed with return code %d\n", bchannel->b_sock, ret);
}
default:
CERROR(bchannel->call, NULL, "child message not handled: prim(0x%x) socket(%d) data len(%d)\n", hh->prim, bchannel->b_sock, ret - MISDN_HEADER_LEN);
}
bchannel = bchannel->next;
} else {
// if (ret < 0 && errno != EWOULDBLOCK)
CERROR(bchannel->call, NULL, "Read from socket %d failed with return code %d\n", bchannel->b_sock, ret);
}
/* if we received at least one b-frame, we will return 1 */
return(work);
return 0;
}
@ -590,7 +580,7 @@ struct bchannel *find_bchannel_handle(unsigned int handle)
break;
bchannel = bchannel->next;
}
return(bchannel);
return bchannel;
}
#if 0
@ -603,7 +593,7 @@ struct bchannel *find_bchannel_ref(unsigned int ref)
break;
bchannel = bchannel->next;
}
return(bchannel);
return bchannel;
}
#endif
@ -616,12 +606,12 @@ struct bchannel *alloc_bchannel(unsigned int handle)
*bchannelp = (struct bchannel *)calloc(1, sizeof(struct bchannel));
if (!*bchannelp)
return(NULL);
return NULL;
(*bchannelp)->handle = handle;
(*bchannelp)->b_state = BSTATE_IDLE;
(*bchannelp)->b_sock = -1;
return(*bchannelp);
return *bchannelp;
}
void free_bchannel(struct bchannel *bchannel)

View File

@ -15,6 +15,7 @@ struct bchannel {
struct chan_call *call; /* link to call process */
unsigned int handle; /* handle for stack id */
int b_sock; /* socket for b-channel */
struct lcr_fd lcr_fd; /* socket register */
int b_mode; /* dsp, raw, dsphdlc */
int b_state;
int b_txdata;
@ -47,7 +48,6 @@ void bchannel_dtmf(struct bchannel *channel, int on);
void bchannel_blowfish(struct bchannel *bchannel, unsigned char *key, int len);
void bchannel_pipeline(struct bchannel *bchannel, char *pipeline);
void bchannel_gain(struct bchannel *bchannel, int gain, int tx);
int bchannel_handle(void);
struct bchannel *find_bchannel_handle(unsigned int handle);
//struct bchannel *find_bchannel_ref(unsigned int ref);
struct bchannel *alloc_bchannel(unsigned int handle);

View File

@ -167,6 +167,7 @@ it is called from ast_channel process which has already locked ast_channel.
#include "callerid.h"
#include "lcrsocket.h"
#include "cause.h"
#include "select.h"
#include "bchannel.h"
#include "options.h"
#include "chan_lcr.h"
@ -198,11 +199,22 @@ static char *desc = "Channel driver for mISDN/LCR Support (Bri/Pri)";
pthread_t chan_tid;
ast_mutex_t chan_lock; /* global lock */
ast_mutex_t log_lock; /* logging log */
/* global_change:
* used to indicate change in file descriptors, so select function's result may
* be obsolete.
*/
int global_change = 0;
int wake_global = 0;
int wake_pipe[2];
struct lcr_fd wake_fd;
int quit;
int glob_channel = 0;
int lcr_sock = -1;
struct lcr_fd socket_fd;
struct lcr_timer socket_retry;
struct admin_list {
struct admin_list *next;
@ -259,7 +271,7 @@ struct chan_call *find_call_ref(unsigned int ref)
break;
call = call->next;
}
return(call);
return call;
}
void free_call(struct chan_call *call)
@ -289,6 +301,7 @@ void free_call(struct chan_call *call)
ast_dsp_free(call->dsp);
CDEBUG(call, NULL, "Call instance freed.\n");
free(call);
global_change = 1;
return;
}
temp = &((*temp)->next);
@ -309,11 +322,11 @@ struct chan_call *alloc_call(void)
if (pipe((*callp)->pipe) < 0) {
CERROR(*callp, NULL, "Failed to create pipe.\n");
free_call(*callp);
return(NULL);
return NULL;
}
fcntl((*callp)->pipe[0], F_SETFL, O_NONBLOCK);
CDEBUG(*callp, NULL, "Call instance allocated.\n");
return(*callp);
return *callp;
}
unsigned short new_bridge_id(void)
@ -334,7 +347,7 @@ unsigned short new_bridge_id(void)
id++;
}
CDEBUG(NULL, NULL, "New bridge ID %d.\n", id);
return(id);
return id;
}
/*
@ -364,8 +377,14 @@ int send_message(int message_type, unsigned int ref, union parameter *param)
admin->msg.u.msg.type = message_type;
admin->msg.u.msg.ref = ref;
memcpy(&admin->msg.u.msg.param, param, sizeof(union parameter));
socket_fd.when |= LCR_FD_WRITE;
if (!wake_global) {
wake_global = 1;
char byte = 0;
write(wake_pipe[1], &byte, 1);
}
return(0);
return 0;
}
/*
@ -923,8 +942,15 @@ static void lcr_in_proceeding(struct chan_call *call, int message_type, union pa
/* change state */
call->state = CHAN_LCR_STATE_OUT_PROCEEDING;
/* queue event for asterisk */
if (call->ast && call->pbx_started)
if (call->ast && call->pbx_started) {
if (!wake_global) {
wake_global = 1;
char byte = 0;
write(wake_pipe[1], &byte, 1);
}
strncat(call->queue_string, "P", sizeof(call->queue_string)-1);
}
}
/*
@ -937,8 +963,14 @@ static void lcr_in_alerting(struct chan_call *call, int message_type, union para
/* change state */
call->state = CHAN_LCR_STATE_OUT_ALERTING;
/* queue event to asterisk */
if (call->ast && call->pbx_started)
if (call->ast && call->pbx_started) {
if (!wake_global) {
wake_global = 1;
char byte = 0;
write(wake_pipe[1], &byte, 1);
}
strncat(call->queue_string, "R", sizeof(call->queue_string)-1);
}
}
/*
@ -962,8 +994,14 @@ static void lcr_in_connect(struct chan_call *call, int message_type, union param
/* copy connectinfo */
memcpy(&call->connectinfo, &param->connectinfo, sizeof(struct connect_info));
/* queue event to asterisk */
if (call->ast && call->pbx_started)
if (call->ast && call->pbx_started) {
if (!wake_global) {
wake_global = 1;
char byte = 0;
write(wake_pipe[1], &byte, 1);
}
strncat(call->queue_string, "N", sizeof(call->queue_string)-1);
}
}
/*
@ -997,9 +1035,14 @@ static void lcr_in_disconnect(struct chan_call *call, int message_type, union pa
/* queue release asterisk */
if (ast) {
ast->hangupcause = call->cause;
if (call->pbx_started)
if (call->pbx_started) {
if (!wake_global) {
wake_global = 1;
char byte = 0;
write(wake_pipe[1], &byte, 1);
}
strcpy(call->queue_string, "H"); // overwrite other indications
else {
} else {
ast_hangup(ast); // call will be destroyed here
}
}
@ -1026,9 +1069,14 @@ static void lcr_in_release(struct chan_call *call, int message_type, union param
/* if we have an asterisk instance, queue hangup, else we are done */
if (ast) {
ast->hangupcause = call->cause;
if (call->pbx_started)
if (call->pbx_started) {
if (!wake_global) {
wake_global = 1;
char byte = 0;
write(wake_pipe[1], &byte, 1);
}
strcpy(call->queue_string, "H");
else {
} else {
ast_hangup(ast); // call will be destroyed here
}
} else {
@ -1064,8 +1112,14 @@ static void lcr_in_information(struct chan_call *call, int message_type, union p
}
/* queue digits */
if (call->state == CHAN_LCR_STATE_IN_DIALING && param->information.id[0])
if (call->state == CHAN_LCR_STATE_IN_DIALING && param->information.id[0]) {
if (!wake_global) {
wake_global = 1;
char byte = 0;
write(wake_pipe[1], &byte, 1);
}
strncat(call->queue_string, param->information.id, sizeof(call->queue_string)-1);
}
/* use bridge to forware message not supported by asterisk */
if (call->state == CHAN_LCR_STATE_CONNECT) {
@ -1134,8 +1188,14 @@ static void lcr_in_pattern(struct chan_call *call, int message_type, union param
send_message(MESSAGE_BCHANNEL, call->ref, &newparam);
}
/* queue PROGRESS, because tones are available */
if (call->ast && call->pbx_started)
if (call->ast && call->pbx_started) {
if (!wake_global) {
wake_global = 1;
char byte = 0;
write(wake_pipe[1], &byte, 1);
}
strncat(call->queue_string, "T", sizeof(call->queue_string)-1);
}
}
/*
@ -1159,6 +1219,11 @@ void lcr_in_dtmf(struct chan_call *call, int val)
CDEBUG(call, call->ast, "Recognised DTMF digit '%c'.\n", val);
digit[0] = val;
digit[1] = '\0';
if (!wake_global) {
wake_global = 1;
char byte = 0;
write(wake_pipe[1], &byte, 1);
}
strncat(call->queue_string, digit, sizeof(call->queue_string)-1);
}
@ -1180,13 +1245,13 @@ int receive_message(int message_type, unsigned int ref, union parameter *param)
CDEBUG(NULL, NULL, "Received BCHANNEL_ASSIGN message. (handle=%08lx) for ref %d\n", param->bchannel.handle, ref);
if ((bchannel = find_bchannel_handle(param->bchannel.handle))) {
CERROR(NULL, NULL, "bchannel handle %x already assigned.\n", (int)param->bchannel.handle);
return(-1);
return -1;
}
/* create bchannel */
bchannel = alloc_bchannel(param->bchannel.handle);
if (!bchannel) {
CERROR(NULL, NULL, "alloc bchannel handle %x failed.\n", (int)param->bchannel.handle);
return(-1);
return -1;
}
/* configure channel */
@ -1242,7 +1307,7 @@ int receive_message(int message_type, unsigned int ref, union parameter *param)
CDEBUG(NULL, NULL, "Received BCHANNEL_REMOVE message. (handle=%08lx)\n", param->bchannel.handle);
if (!(bchannel = find_bchannel_handle(param->bchannel.handle))) {
CERROR(NULL, NULL, "Bchannel handle %x not assigned.\n", (int)param->bchannel.handle);
return(-1);
return -1;
}
/* unklink from call and destroy bchannel */
free_bchannel(bchannel);
@ -1257,7 +1322,7 @@ int receive_message(int message_type, unsigned int ref, union parameter *param)
default:
CDEBUG(NULL, NULL, "Received unknown bchannel message %d.\n", param->bchannel.type);
}
return(0);
return 0;
}
/* handle new ref */
@ -1267,7 +1332,7 @@ int receive_message(int message_type, unsigned int ref, union parameter *param)
CDEBUG(NULL, NULL, "Received new ref by LCR, due to incomming call. (ref=%ld)\n", ref);
if (!ref || find_call_ref(ref)) {
CERROR(NULL, NULL, "Illegal new ref %ld received.\n", ref);
return(-1);
return -1;
}
/* allocate new call instance */
call = alloc_call();
@ -1287,7 +1352,7 @@ int receive_message(int message_type, unsigned int ref, union parameter *param)
/* send release, if ref does not exist */
CDEBUG(NULL, NULL, "No call found, that requests a ref.\n");
send_release_and_import(call, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL);
return(0);
return 0;
}
/* store new ref */
call->ref = ref;
@ -1306,22 +1371,22 @@ int receive_message(int message_type, unsigned int ref, union parameter *param)
send_release_and_import(call, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL);
/* free call */
free_call(call);
return(0);
return 0;
}
}
return(0);
return 0;
}
/* check ref */
if (!ref) {
CERROR(NULL, NULL, "Received message %d without ref.\n", message_type);
return(-1);
return -1;
}
call = find_call_ref(ref);
if (!call) {
/* ignore ref that is not used (anymore) */
CDEBUG(NULL, NULL, "Message %d from LCR ignored, because no call instance found.\n", message_type);
return(0);
return 0;
}
/* handle messages */
@ -1382,7 +1447,7 @@ int receive_message(int message_type, unsigned int ref, union parameter *param)
CDEBUG(call, call->ast, "Message %d from LCR unhandled.\n", message_type);
break;
}
return(0);
return 0;
}
/*
@ -1415,6 +1480,11 @@ again:
goto again;
}
CDEBUG(call, call->ast, "Queue call release, because Asterisk channel is running.\n");
if (!wake_global) {
wake_global = 1;
char byte = 0;
write(wake_pipe[1], &byte, 1);
}
strcpy(call->queue_string, "H");
call = call->next;
}
@ -1424,69 +1494,74 @@ again:
free_bchannel(bchannel_first);
}
void close_socket(void);
/* asterisk handler
* warning! not thread safe
* returns -1 for socket error, 0 for no work, 1 for work
*/
int handle_socket(void)
static int handle_socket(struct lcr_fd *fd, unsigned int what, void *instance, int index)
{
int work = 0;
int len;
struct admin_list *admin;
struct admin_message msg;
/* read from socket */
len = read(lcr_sock, &msg, sizeof(msg));
if (len == 0) {
CERROR(NULL, NULL, "Socket closed.\n");
return(-1); // socket closed
}
if (len > 0) {
if (len != sizeof(msg)) {
CERROR(NULL, NULL, "Socket short read. (len %d)\n", len);
return(-1); // socket error
if ((what & LCR_FD_READ)) {
/* read from socket */
len = read(lcr_sock, &msg, sizeof(msg));
if (len == 0) {
CERROR(NULL, NULL, "Socket closed.\n");
error:
CERROR(NULL, NULL, "Handling of socket failed - closing for some seconds.\n");
close_socket();
release_all_calls();
schedule_timer(&socket_retry, SOCKET_RETRY_TIMER, 0);
return 0;
}
if (msg.message != ADMIN_MESSAGE) {
CERROR(NULL, NULL, "Socket received illegal message %d.\n", msg.message);
return(-1);
}
receive_message(msg.u.msg.type, msg.u.msg.ref, &msg.u.msg.param);
work = 1;
} else {
if (errno != EWOULDBLOCK) {
if (len > 0) {
if (len != sizeof(msg)) {
CERROR(NULL, NULL, "Socket short read. (len %d)\n", len);
goto error;
}
if (msg.message != ADMIN_MESSAGE) {
CERROR(NULL, NULL, "Socket received illegal message %d.\n", msg.message);
goto error;
}
receive_message(msg.u.msg.type, msg.u.msg.ref, &msg.u.msg.param);
} else {
CERROR(NULL, NULL, "Socket failed (errno %d).\n", errno);
return(-1);
goto error;
}
}
/* write to socket */
if (!admin_first)
return(work);
admin = admin_first;
len = write(lcr_sock, &admin->msg, sizeof(msg));
if (len == 0) {
CERROR(NULL, NULL, "Socket closed.\n");
return(-1); // socket closed
}
if (len > 0) {
if (len != sizeof(msg)) {
CERROR(NULL, NULL, "Socket short write. (len %d)\n", len);
return(-1); // socket error
if ((what & LCR_FD_WRITE)) {
/* write to socket */
if (!admin_first) {
socket_fd.when &= ~LCR_FD_WRITE;
return 0;
}
/* free head */
admin_first = admin->next;
free(admin);
work = 1;
} else {
if (errno != EWOULDBLOCK) {
admin = admin_first;
len = write(lcr_sock, &admin->msg, sizeof(msg));
if (len == 0) {
CERROR(NULL, NULL, "Socket closed.\n");
goto error;
}
if (len > 0) {
if (len != sizeof(msg)) {
CERROR(NULL, NULL, "Socket short write. (len %d)\n", len);
goto error;
}
/* free head */
admin_first = admin->next;
free(admin);
global_change = 1;
} else {
CERROR(NULL, NULL, "Socket failed (errno %d).\n", errno);
return(-1);
goto error;
}
}
return(work);
return 0;
}
/*
@ -1494,16 +1569,14 @@ int handle_socket(void)
*/
int open_socket(void)
{
int ret;
int conn;
struct sockaddr_un sock_address;
unsigned int on = 1;
union parameter param;
/* open socket */
if ((lcr_sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
CERROR(NULL, NULL, "Failed to create socket.\n");
return(lcr_sock);
return lcr_sock;
}
/* set socket address and name */
@ -1516,29 +1589,28 @@ int open_socket(void)
close(lcr_sock);
lcr_sock = -1;
CDEBUG(NULL, NULL, "Failed to connect to socket '%s'. Is LCR running?\n", sock_address.sun_path);
return(conn);
return conn;
}
/* set non-blocking io */
if ((ret = ioctl(lcr_sock, FIONBIO, (unsigned char *)(&on))) < 0) {
close(lcr_sock);
lcr_sock = -1;
CERROR(NULL, NULL, "Failed to set socket into non-blocking IO.\n");
return(ret);
}
/* register socket fd */
memset(&socket_fd, 0, sizeof(socket_fd));
socket_fd.fd = lcr_sock;
register_fd(&socket_fd, LCR_FD_READ | LCR_FD_EXCEPT, handle_socket, NULL, 0);
/* enque hello message */
memset(&param, 0, sizeof(param));
strcpy(param.hello.application, "asterisk");
send_message(MESSAGE_HELLO, 0, &param);
return(lcr_sock);
return lcr_sock;
}
void close_socket(void)
{
struct admin_list *admin, *temp;
unregister_fd(&socket_fd);
/* flush pending messages */
admin = admin_first;
while(admin) {
@ -1552,13 +1624,24 @@ void close_socket(void)
if (lcr_sock >= 0)
close(lcr_sock);
lcr_sock = -1;
global_change = 1;
}
/* sending queue to asterisk */
static int queue_send(void)
static int wake_event(struct lcr_fd *fd, unsigned int what, void *instance, int index)
{
char byte;
read(wake_pipe[0], &byte, 1);
wake_global = 0;
return 0;
}
static void handle_queue()
{
int work = 0;
struct chan_call *call;
struct ast_channel *ast;
struct ast_frame fr;
@ -1569,156 +1652,124 @@ static int queue_send(void)
p = call->queue_string;
ast = call->ast;
if (*p && ast) {
/* there is something to queue */
if (!ast_channel_trylock(ast)) { /* succeed */
while(*p) {
switch (*p) {
case 'T':
CDEBUG(call, ast, "Sending queued PROGRESS to Asterisk.\n");
ast_queue_control(ast, AST_CONTROL_PROGRESS);
break;
case 'P':
CDEBUG(call, ast, "Sending queued PROCEEDING to Asterisk.\n");
ast_queue_control(ast, AST_CONTROL_PROCEEDING);
break;
case 'R':
CDEBUG(call, ast, "Sending queued RINGING to Asterisk.\n");
ast_queue_control(ast, AST_CONTROL_RINGING);
ast_setstate(ast, AST_STATE_RINGING);
break;
case 'N':
CDEBUG(call, ast, "Sending queued ANSWER to Asterisk.\n");
ast_queue_control(ast, AST_CONTROL_ANSWER);
break;
case 'H':
CDEBUG(call, ast, "Sending queued HANGUP to Asterisk.\n");
ast_queue_hangup(ast);
break;
case '1': case '2': case '3': case 'A':
case '4': case '5': case '6': case 'B':
case '7': case '8': case '9': case 'C':
case '*': case '0': case '#': case 'D':
CDEBUG(call, ast, "Sending queued digit '%c' to Asterisk.\n", *p);
/* send digit to asterisk */
memset(&fr, 0, sizeof(fr));
#ifdef LCR_FOR_ASTERISK
fr.frametype = AST_FRAME_DTMF_BEGIN;
#endif
ast_channel_lock(ast);
while(*p) {
switch (*p) {
case 'T':
CDEBUG(call, ast, "Sending queued PROGRESS to Asterisk.\n");
ast_queue_control(ast, AST_CONTROL_PROGRESS);
break;
case 'P':
CDEBUG(call, ast, "Sending queued PROCEEDING to Asterisk.\n");
ast_queue_control(ast, AST_CONTROL_PROCEEDING);
break;
case 'R':
CDEBUG(call, ast, "Sending queued RINGING to Asterisk.\n");
ast_queue_control(ast, AST_CONTROL_RINGING);
ast_setstate(ast, AST_STATE_RINGING);
break;
case 'N':
CDEBUG(call, ast, "Sending queued ANSWER to Asterisk.\n");
ast_queue_control(ast, AST_CONTROL_ANSWER);
break;
case 'H':
CDEBUG(call, ast, "Sending queued HANGUP to Asterisk.\n");
ast_queue_hangup(ast);
break;
case '1': case '2': case '3': case 'A':
case '4': case '5': case '6': case 'B':
case '7': case '8': case '9': case 'C':
case '*': case '0': case '#': case 'D':
CDEBUG(call, ast, "Sending queued digit '%c' to Asterisk.\n", *p);
/* send digit to asterisk */
memset(&fr, 0, sizeof(fr));
#ifdef LCR_FOR_ASTERISK
fr.frametype = AST_FRAME_DTMF_BEGIN;
#endif
#ifdef LCR_FOR_CALLWEAVER
fr.frametype = AST_FRAME_DTMF;
#endif
fr.subclass = *p;
fr.delivery = ast_tv(0, 0);
ast_queue_frame(ast, &fr);
#ifdef LCR_FOR_ASTERISK
fr.frametype = AST_FRAME_DTMF_END;
ast_queue_frame(ast, &fr);
#endif
break;
default:
CDEBUG(call, ast, "Ignoring queued digit 0x%02x.\n", *p);
}
p++;
#ifdef LCR_FOR_CALLWEAVER
fr.frametype = AST_FRAME_DTMF;
#endif
fr.subclass = *p;
fr.delivery = ast_tv(0, 0);
ast_queue_frame(ast, &fr);
#ifdef LCR_FOR_ASTERISK
fr.frametype = AST_FRAME_DTMF_END;
ast_queue_frame(ast, &fr);
#endif
break;
default:
CDEBUG(call, ast, "Ignoring queued digit 0x%02x.\n", *p);
}
call->queue_string[0] = '\0';
ast_channel_unlock(ast);
work = 1;
p++;
}
call->queue_string[0] = '\0';
ast_channel_unlock(ast);
}
call = call->next;
}
return work;
}
/* signal handler */
void sighandler(int sigset)
static int handle_retry(struct lcr_timer *timer, void *instance, int index)
{
CDEBUG(NULL, NULL, "Retry to open socket.\n");
if (open_socket() < 0)
schedule_timer(&socket_retry, SOCKET_RETRY_TIMER, 0);
return 0;
}
void lock_chan(void)
{
ast_mutex_lock(&chan_lock);
}
void unlock_chan(void)
{
ast_mutex_unlock(&chan_lock);
}
/* chan_lcr thread */
static void *chan_thread(void *arg)
{
int work;
int ret;
union parameter param;
time_t retry = 0, now;
if (pipe(wake_pipe) < 0) {
CERROR(NULL, NULL, "Failed to open pipe.\n");
return NULL;
}
memset(&wake_fd, 0, sizeof(wake_fd));
wake_fd.fd = wake_pipe[0];
register_fd(&wake_fd, LCR_FD_READ, wake_event, NULL, 0);
memset(&socket_retry, 0, sizeof(socket_retry));
add_timer(&socket_retry, handle_retry, NULL, 0);
bchannel_pid = getpid();
// signal(SIGPIPE, sighandler);
memset(&param, 0, sizeof(union parameter));
if (lcr_sock < 0)
time(&retry);
/* open socket the first time */
handle_retry(NULL, NULL, 0);
ast_mutex_lock(&chan_lock);
while(!quit) {
work = 0;
if (lcr_sock > 0) {
/* handle socket */
ret = handle_socket();
if (ret < 0) {
CERROR(NULL, NULL, "Handling of socket failed - closing for some seconds.\n");
close_socket();
release_all_calls();
time(&retry);
}
if (ret)
work = 1;
} else {
time(&now);
if (retry && now-retry > 5) {
CDEBUG(NULL, NULL, "Retry to open socket.\n");
retry = 0;
if (open_socket() < 0) {
time(&retry);
}
work = 1;
}
}
/* handle mISDN */
ret = bchannel_handle();
if (ret)
work = 1;
/* handle messages to asterisk */
ret = queue_send();
if (ret)
work = 1;
/* delay if no work done */
if (!work) {
ast_mutex_unlock(&chan_lock);
#ifdef LCR_FOR_ASTERISK
usleep(30000);
#endif
#ifdef LCR_FOR_CALLWEAVER
usleep(20000);
#endif
ast_mutex_lock(&chan_lock);
}
handle_queue();
select_main(0, &global_change, lock_chan, unlock_chan);
}
close_socket();
CERROR(NULL, NULL, "Thread exit.\n");
ast_mutex_unlock(&chan_lock);
del_timer(&socket_retry);
// signal(SIGPIPE, SIG_DFL);
unregister_fd(&wake_fd);
close(wake_pipe[0]);
close(wake_pipe[1]);
CERROR(NULL, NULL, "Thread exit.\n");
ast_mutex_unlock(&chan_lock);
return NULL;
}
@ -1963,7 +2014,7 @@ static int lcr_digit(struct ast_channel *ast, char digit)
ast_mutex_unlock(&chan_lock);
#ifdef LCR_FOR_ASTERISK
return(0);
return 0;
}
static int lcr_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
@ -1997,7 +2048,7 @@ static int lcr_digit_end(struct ast_channel *ast, char digit, unsigned int durat
send_digit_to_chan(ast, digit);
}
return (0);
return 0;
}
static int lcr_answer(struct ast_channel *ast)
@ -2152,6 +2203,7 @@ static struct ast_frame *lcr_read(struct ast_channel *ast)
if (len <= 0) {
close(call->pipe[0]);
call->pipe[0] = -1;
global_change = 1;
ast_mutex_unlock(&chan_lock);
return NULL;
} else if (call->rebuffer && call->framepos < 160) {
@ -2704,10 +2756,6 @@ int load_module(void)
ast_mutex_init(&chan_lock);
ast_mutex_init(&log_lock);
if (open_socket() < 0) {
/* continue with closed socket */
}
if (bchannel_initialize()) {
CERROR(NULL, NULL, "Unable to open mISDN device\n");
close_socket();
@ -2835,6 +2883,7 @@ int reload_module(void)
#ifdef LCR_FOR_CALLWEAVER
int usecount(void)
hae
{
int res;
ast_mutex_lock(&usecnt_lock);

View File

@ -132,6 +132,8 @@ enum {
};
#define SOCKET_RETRY_TIMER 5
#define CERROR(call, ast, arg...) chan_lcr_log(__LOG_ERROR, __FILE__, __LINE__, __FUNCTION__, call, ast, ##arg)
#define CDEBUG(call, ast, arg...) chan_lcr_log(__LOG_NOTICE, __FILE__, __LINE__, __FUNCTION__, call, ast, ##arg)
void chan_lcr_log(int type, const char *file, int line, const char *function, struct chan_call *call, struct ast_channel *ast, const char *fmt, ...);

View File

@ -549,7 +549,8 @@ static void *keyengine_child(void *arg)
PDEBUG((DEBUG_EPOINT | DEBUG_CRYPT), "child process done after using libcrypto with return value %d\n", apppbx->e_crypt_keyengine_return);
/* exit process */
apppbx->ea_endpoint->ep_use--;
if (--apppbx->ea_endpoint->ep_use <= 0)
trigger_work(&apppbx->ea_endpoint->ep_delete);
FREE(args, sizeof(struct auth_args));
amemuse--;
return(NULL);
@ -588,37 +589,47 @@ void EndpointAppPBX::cryptman_keyengine(int job)
/* handler for authentication (called by apppbx's handler)
*/
void EndpointAppPBX::cryptman_handler(void)
int crypt_handler(struct lcr_timer *timer, void *instance, int index)
{
if (e_crypt_keyengine_busy) {
if (e_crypt_keyengine_return < 0) {
e_crypt_keyengine_busy = 0;
cryptman_message(CK_ERROR_IND, NULL, 0);
class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
struct timeval current_time;
if (ea->e_crypt_keyengine_busy) {
if (ea->e_crypt_keyengine_return < 0) {
ea->e_crypt_keyengine_busy = 0;
ea->cryptman_message(CK_ERROR_IND, NULL, 0);
} else
if (e_crypt_keyengine_return > 0) {
switch(e_crypt_keyengine_busy) {
if (ea->e_crypt_keyengine_return > 0) {
switch(ea->e_crypt_keyengine_busy) {
case CK_GENRSA_REQ:
e_crypt_keyengine_busy = 0;
cryptman_message(CK_GENRSA_CONF, NULL, 0);
ea->e_crypt_keyengine_busy = 0;
ea->cryptman_message(CK_GENRSA_CONF, NULL, 0);
break;
case CK_CPTRSA_REQ:
e_crypt_keyengine_busy = 0;
cryptman_message(CK_CPTRSA_CONF, NULL, 0);
ea->e_crypt_keyengine_busy = 0;
ea->cryptman_message(CK_CPTRSA_CONF, NULL, 0);
break;
case CK_DECRSA_REQ:
e_crypt_keyengine_busy = 0;
cryptman_message(CK_DECRSA_CONF, NULL, 0);
ea->e_crypt_keyengine_busy = 0;
ea->cryptman_message(CK_DECRSA_CONF, NULL, 0);
break;
}
}
}
/* check for event, make next event */
if (e_crypt_timeout_sec) if (e_crypt_timeout_sec<now_tv.tv_sec || (e_crypt_timeout_sec==now_tv.tv_sec && e_crypt_timeout_usec<now_tv.tv_usec)) {
e_crypt_timeout_sec = 0;
e_crypt_timeout_usec = 0;
cryptman_message(CT_TIMEOUT, NULL, 0);
gettimeofday(&current_time, NULL);
if (ea->e_crypt_timeout_sec) if (ea->e_crypt_timeout_sec<current_time.tv_sec || (ea->e_crypt_timeout_sec==current_time.tv_sec && ea->e_crypt_timeout_usec<current_time.tv_usec)) {
ea->e_crypt_timeout_sec = 0;
ea->e_crypt_timeout_usec = 0;
ea->cryptman_message(CT_TIMEOUT, NULL, 0);
}
/* trigger until state is 0 */
if (ea->e_crypt_state != CM_ST_NULL)
schedule_timer(&ea->e_crypt_handler, 0, 100000);
return 0;
}
@ -679,6 +690,7 @@ void EndpointAppPBX::cr_activate(int message, unsigned char *param, int len)
unsigned char buf[128] = "";
unsigned char msg;
unsigned char bogomips[4], ran[4];
struct timeval current_time;
/* activate listener */
cryptman_msg2crengine(CR_LISTEN_REQ, NULL, 0);
@ -686,7 +698,8 @@ void EndpointAppPBX::cr_activate(int message, unsigned char *param, int len)
msg = CMSG_IDENT;
CM_ADDINF(CM_INFO_MESSAGE, 1, &msg);
/* random number element */
srandom(now_tv.tv_sec ^ now_tv.tv_usec ^ random());
gettimeofday(&current_time, NULL);
srandom(current_time.tv_sec ^ current_time.tv_usec ^ random());
e_crypt_random = random();
ran[0] = e_crypt_random >> 24;
ran[1] = e_crypt_random >> 16;
@ -1484,6 +1497,8 @@ void EndpointAppPBX::cryptman_msg2user(int msg, const char *text)
void EndpointAppPBX::cryptman_state(int state)
{
PDEBUG(DEBUG_CRYPT, "Changing state from %s to %s\n", statename(e_crypt_state), statename(state));
if (state != CM_ST_NULL && e_crypt_state == CM_ST_NULL)
schedule_timer(&e_crypt_handler, 0, 100000);
e_crypt_state = state;
}
@ -1492,9 +1507,12 @@ void EndpointAppPBX::cryptman_state(int state)
*/
void EndpointAppPBX::cryptman_timeout(int secs)
{
struct timeval current_time;
gettimeofday(&current_time, NULL);
if (secs) {
e_crypt_timeout_sec = now_tv.tv_sec+secs;
e_crypt_timeout_usec = now_tv.tv_usec;
e_crypt_timeout_sec = current_time.tv_sec+secs;
e_crypt_timeout_usec = current_time.tv_usec;
PDEBUG(DEBUG_CRYPT, "Changing timeout to %d seconds\n", secs);
} else {
e_crypt_timeout_sec = 0;

View File

@ -170,4 +170,4 @@ int cm_msg_num = sizeof(cm_msg_name) / sizeof(char *);
void crc_init(void);
unsigned int crc32(unsigned char *data, int len);
int cryptman_encode_bch(unsigned char *data, int len, unsigned char *buf, int buf_len);
int crypt_handler(struct lcr_timer *timer, void *instance, int index);

View File

@ -20,6 +20,8 @@ extern unsigned int mt_assign_pid;
#include "ie.cpp"
static int delete_event(struct lcr_work *work, void *instance, int index);
/*
* constructor
*/
@ -29,6 +31,8 @@ Pdss1::Pdss1(int type, struct mISDNport *mISDNport, char *portname, struct port_
p_m_d_ntmode = mISDNport->ntmode;
p_m_d_tespecial = mISDNport->tespecial;
p_m_d_l3id = 0;
memset(&p_m_d_delete, 0, sizeof(p_m_d_delete));
add_work(&p_m_d_delete, delete_event, this, 0);
p_m_d_ces = -1;
p_m_d_queue[0] = '\0';
p_m_d_notify_pending = NULL;
@ -44,6 +48,8 @@ Pdss1::Pdss1(int type, struct mISDNport *mISDNport, char *portname, struct port_
*/
Pdss1::~Pdss1()
{
del_work(&p_m_d_delete);
/* remove queued message */
if (p_m_d_notify_pending)
message_free(p_m_d_notify_pending);
@ -255,7 +261,7 @@ int Pdss1::received_first_reply_to_setup(unsigned int cmd, int channel, int excl
end_trace();
p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_RELEASE_COMPLETE, p_m_d_l3id, l3m);
new_state(PORT_STATE_RELEASE);
p_m_delete = 1;
trigger_work(&p_m_d_delete);
return(-34); /* to epoint: no channel available */
}
@ -422,7 +428,7 @@ void Pdss1::setup_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
end_trace();
p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_RELEASE_COMPLETE, pid, l3m);
new_state(PORT_STATE_RELEASE);
p_m_delete = 1;
trigger_work(&p_m_d_delete);
return;
}
p_m_d_l3id = pid;
@ -453,7 +459,7 @@ void Pdss1::setup_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
end_trace();
p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_RELEASE_COMPLETE, p_m_d_l3id, l3m);
new_state(PORT_STATE_RELEASE);
p_m_delete = 1;
trigger_work(&p_m_d_delete);
return;
}
@ -711,7 +717,7 @@ void Pdss1::setup_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
end_trace();
p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_RELEASE_COMPLETE, p_m_d_l3id, l3m);
new_state(PORT_STATE_RELEASE);
p_m_delete = 1;
trigger_work(&p_m_d_delete);
return;
}
bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE);
@ -803,7 +809,7 @@ void Pdss1::setup_acknowledge_ind(unsigned int cmd, unsigned int pid, struct l3_
message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
message_put(message);
new_state(PORT_STATE_RELEASE);
p_m_delete = 1;
trigger_work(&p_m_d_delete);
return;
}
@ -851,7 +857,7 @@ void Pdss1::proceeding_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3
message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
message_put(message);
new_state(PORT_STATE_RELEASE);
p_m_delete = 1;
trigger_work(&p_m_d_delete);
return;
}
message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROCEEDING);
@ -928,7 +934,7 @@ void Pdss1::alerting_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
message_put(message);
new_state(PORT_STATE_RELEASE);
p_m_delete = 1;
trigger_work(&p_m_d_delete);
return;
}
message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ALERTING);
@ -1005,7 +1011,7 @@ void Pdss1::connect_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
message_put(message);
new_state(PORT_STATE_RELEASE);
p_m_delete = 1;
trigger_work(&p_m_d_delete);
return;
}
@ -1117,7 +1123,7 @@ void Pdss1::disconnect_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3
free_epointlist(p_epointlist);
}
new_state(PORT_STATE_RELEASE);
p_m_delete = 1;
trigger_work(&p_m_d_delete);
return;
}
@ -1197,7 +1203,7 @@ void Pdss1::release_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
}
new_state(PORT_STATE_RELEASE);
p_m_delete = 1;
trigger_work(&p_m_d_delete);
}
/* CC_RESTART INDICATION */
@ -1247,7 +1253,7 @@ void Pdss1::release_complete_ind(unsigned int cmd, unsigned int pid, struct l3_m
}
new_state(PORT_STATE_RELEASE);
p_m_delete = 1;
trigger_work(&p_m_d_delete);
}
/* T312 timeout */
@ -1351,8 +1357,8 @@ void Pdss1::hold_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
#if 0
epoint = find_epoint_id(ACTIVE_EPOINT(p_epointlist));
if (epoint && p_m_d_ntmode) {
p_m_timeout = p_settings.tout_hold;
time(&p_m_timer);
if (p_settings.tout_hold)
schedule_timer(&p_m_timeout, p_settings.tout_hold, 0);
}
#endif
@ -1410,7 +1416,7 @@ void Pdss1::retrieve_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
/* set hold state */
p_m_hold = 0;
p_m_timeout = 0;
unsched_timer(&p_m_timeout);
/* acknowledge retrieve */
l3m = create_l3msg();
@ -1488,7 +1494,7 @@ void Pdss1::suspend_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_SUSPEND_ACKNOWLEDGE, p_m_d_l3id, l3m);
new_state(PORT_STATE_RELEASE);
p_m_delete = 1;
trigger_work(&p_m_d_delete);
}
/* CC_RESUME INDICATION */
@ -1515,7 +1521,7 @@ void Pdss1::resume_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
end_trace();
p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_RESUME_REJECT, pid, l3m);
new_state(PORT_STATE_RELEASE);
p_m_delete = 1;
trigger_work(&p_m_d_delete);
return;
}
p_m_d_l3id = pid;
@ -1558,7 +1564,7 @@ void Pdss1::resume_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
end_trace();
p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_RESUME_REJECT, p_m_d_l3id, l3m);
new_state(PORT_STATE_RELEASE);
p_m_delete = 1;
trigger_work(&p_m_d_delete);
return;
}
bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE);
@ -1778,8 +1784,8 @@ void Pdss1::message_isdn(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
add_trace("callref", NULL, "0x%x", p_m_d_l3id);
end_trace();
p_m_d_l3id = 0;
trigger_work(&p_m_d_delete);
p_m_d_ces = -1;
p_m_delete = 1;
/* sending release to endpoint in case we still have an endpoint
* this is because we don't get any response if a release_complete is received (or a release in release state)
*/
@ -1814,35 +1820,39 @@ void Pdss1::new_state(int state)
/* set timeout */
if (state == PORT_STATE_IN_OVERLAP) {
p_m_timeout = p_m_mISDNport->ifport->tout_dialing;
time(&p_m_timer);
if (p_m_mISDNport->ifport->tout_dialing)
schedule_timer(&p_m_timeout, p_m_mISDNport->ifport->tout_dialing, 0);
}
if (state != p_state) {
unsched_timer(&p_m_timeout);
if (state == PORT_STATE_IN_SETUP
|| state == PORT_STATE_OUT_SETUP
|| state == PORT_STATE_IN_OVERLAP
|| state == PORT_STATE_OUT_OVERLAP) {
p_m_timeout = p_m_mISDNport->ifport->tout_setup;
time(&p_m_timer);
if (p_m_mISDNport->ifport->tout_setup)
schedule_timer(&p_m_timeout, p_m_mISDNport->ifport->tout_setup, 0);
}
if (state == PORT_STATE_IN_PROCEEDING
|| state == PORT_STATE_OUT_PROCEEDING) {
p_m_timeout = p_m_mISDNport->ifport->tout_proceeding;
time(&p_m_timer);
if (p_m_mISDNport->ifport->tout_proceeding)
schedule_timer(&p_m_timeout, p_m_mISDNport->ifport->tout_proceeding, 0);
}
if (state == PORT_STATE_IN_ALERTING
|| state == PORT_STATE_OUT_ALERTING) {
p_m_timeout = p_m_mISDNport->ifport->tout_alerting;
time(&p_m_timer);
if (p_m_mISDNport->ifport->tout_alerting)
schedule_timer(&p_m_timeout, p_m_mISDNport->ifport->tout_alerting, 0);
}
#if 0
if (state == PORT_STATE_CONNECT
|| state == PORT_STATE_CONNECT_WAITING) {
p_m_timeout = 0;
if (p_m_mISDNport->ifport->tout_connect)
schedule_timer(&p_m_timeout, p_m_mISDNport->ifport->tout_connect, 0);
}
#endif
if (state == PORT_STATE_IN_DISCONNECT
|| state == PORT_STATE_OUT_DISCONNECT) {
p_m_timeout = p_m_mISDNport->ifport->tout_disconnect;
time(&p_m_timer);
if (p_m_mISDNport->ifport->tout_disconnect)
schedule_timer(&p_m_timeout, p_m_mISDNport->ifport->tout_disconnect, 0);
}
}
@ -1850,23 +1860,15 @@ void Pdss1::new_state(int state)
}
/*
* handler
*/
int Pdss1::handler(void)
/* deletes only if l3id is release, otherwhise it will be triggered then */
static int delete_event(struct lcr_work *work, void *instance, int index)
{
int ret;
class Pdss1 *isdnport = (class Pdss1 *)instance;
if ((ret = PmISDN::handler()))
return(ret);
if (!isdnport->p_m_d_l3id)
delete isdnport;
/* handle destruction */
if (p_m_delete && p_m_d_l3id==0) {
delete this;
return(-1);
}
return(0);
return 0;
}
@ -1921,7 +1923,7 @@ void Pdss1::message_setup(unsigned int epoint_id, int message_id, union paramete
message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
message_put(message);
new_state(PORT_STATE_RELEASE);
p_m_delete = 1;
trigger_work(&p_m_d_delete);
return;
}
@ -1987,7 +1989,7 @@ void Pdss1::message_setup(unsigned int epoint_id, int message_id, union paramete
message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
message_put(message);
new_state(PORT_STATE_RELEASE);
p_m_delete = 1;
trigger_work(&p_m_d_delete);
return;
}
p_m_d_l3id = mt_assign_pid;
@ -2419,6 +2421,7 @@ void Pdss1::message_connect(unsigned int epoint_id, int message_id, union parame
l3_msg *l3m;
int type, plan, present, screen;
class Endpoint *epoint;
time_t current_time;
/* NT-MODE in setup state we must send PROCEEDING first */
if (p_m_d_ntmode && p_state==PORT_STATE_IN_SETUP) {
@ -2513,7 +2516,8 @@ void Pdss1::message_connect(unsigned int epoint_id, int message_id, union parame
/* date & time */
if (p_m_d_ntmode || p_m_d_tespecial) {
epoint = find_epoint_id(epoint_id);
enc_ie_date(l3m, now, p_settings.no_seconds);
time(&current_time);
enc_ie_date(l3m, current_time, p_settings.no_seconds);
}
end_trace();
/* finally send message */
@ -2552,7 +2556,7 @@ if (/* ||*/ p_state==PORT_STATE_OUT_SETUP) {
end_trace();
p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_RELEASE_COMPLETE, p_m_d_l3id, l3m);
new_state(PORT_STATE_RELEASE);
p_m_delete = 1;
trigger_work(&p_m_d_delete);
return;
}

2
dss1.h
View File

@ -16,9 +16,9 @@ class Pdss1 : public PmISDN
Pdss1(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel, int exclusive, int mode);
~Pdss1();
unsigned int p_m_d_l3id; /* current l3 process id */
struct lcr_work p_m_d_delete; /* timer for audio transmission */
void message_isdn(unsigned int cmd, unsigned int pid, struct l3_msg *l3m);
int p_m_d_ces; /* ntmode: tei&sapi */
int handler(void);
int message_epoint(unsigned int epoint_id, int message, union parameter *param);
int p_m_d_ntmode; /* flags the nt-mode */

View File

@ -33,6 +33,7 @@ class Endpoint *find_epoint_id(unsigned int epoint_id)
return(NULL);
}
int delete_endpoint(struct lcr_work *work, void *instance, int index);
/*
* endpoint constructor (link with either port or join id)
@ -48,6 +49,8 @@ Endpoint::Endpoint(unsigned int port_id, unsigned int join_id)
ep_portlist = NULL;
ep_app = NULL;
memset(&ep_delete, 0, sizeof(ep_delete));
add_work(&ep_delete, delete_endpoint, this, 0);
ep_use = 1;
/* add endpoint to chain */
@ -125,6 +128,8 @@ Endpoint::~Endpoint(void)
FATAL("Endpoint not in Endpoint's list.\n");
*tempp = next;
del_work(&ep_delete);
/* free */
PDEBUG(DEBUG_EPOINT, "removed endpoint %d.\n", ep_serial);
}
@ -183,17 +188,13 @@ void Endpoint::free_portlist(struct port_list *portlist)
}
/* handler for endpoint
*/
int Endpoint::handler(void)
int delete_endpoint(struct lcr_work *work, void *instance, int index)
{
if (ep_use <= 0) {
delete this;
return(-1);
}
class Endpoint *ep = (class Endpoint *)instance;
/* call application handler */
if (ep_app)
return(ep_app->handler());
return(0);
if (ep->ep_use <= 0)
delete ep;
return 0;
}

View File

@ -26,7 +26,6 @@ class Endpoint
~Endpoint();
class Endpoint *next; /* next in list */
unsigned int ep_serial; /* a unique serial to identify */
int handler(void);
/* applocaton relation */
class EndpointApp *ep_app; /* link to application class */
@ -41,6 +40,7 @@ class Endpoint
/* if still used by threads */
int ep_use;
struct lcr_work ep_delete;
/* application indipendant states */
int ep_park; /* indicates that the epoint is parked */

View File

@ -28,11 +28,6 @@ EndpointApp::~EndpointApp(void)
classuse--;
}
int EndpointApp::handler(void)
{
return(0);
}
/* mini application for test purpose only */
void EndpointApp::ea_message_port(unsigned int port_id, int message_type, union parameter *param)

View File

@ -18,7 +18,6 @@ class EndpointApp
virtual ~EndpointApp();
class Endpoint *ea_endpoint;
virtual int handler(void);
virtual void ea_message_port(unsigned int port_id, int message, union parameter *param);
virtual void ea_message_join(unsigned int join_id, int message, union parameter *param);
};

151
gsm.cpp
View File

@ -32,8 +32,16 @@ extern int bsc_shutdown_net(struct gsm_network *net);
void talloc_ctx_init(void);
void on_dso_load_token(void);
void on_dso_load_rrlp(void);
void on_dso_load_ho_dec(void);
int bts_model_unknown_init(void);
int bts_model_bs11_init(void);
int bts_model_nanobts_init(void);
static struct debug_target *stderr_target;
/* timer to store statistics */
#define DB_SYNC_INTERVAL 60, 0
static struct timer_list db_sync_timer;
#include "gsm_audio.h"
#undef AF_ISDN
@ -47,6 +55,18 @@ struct lcr_gsm *gsm = NULL;
static unsigned int new_callref = 1;
/* timer handling */
static int _db_store_counter(struct counter *counter, void *data)
{
return db_store_counter(counter);
}
static void db_sync_timer_cb(void *data)
{
/* store counters to database and re-schedule */
counters_for_each(_db_store_counter, NULL);
bsc_schedule_timer(&db_sync_timer, DB_SYNC_INTERVAL);
}
/*
* create and send mncc message
@ -70,6 +90,7 @@ static int send_and_free_mncc(struct gsm_network *net, unsigned int msg_type, vo
return ret;
}
static int delete_event(struct lcr_work *work, void *instance, int index);
/*
* constructor
@ -77,6 +98,8 @@ static int send_and_free_mncc(struct gsm_network *net, unsigned int msg_type, vo
Pgsm::Pgsm(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel, int exclusive, int mode) : PmISDN(type, mISDNport, portname, settings, channel, exclusive, mode)
{
p_callerinfo.itype = (mISDNport->ifport->interface->extension)?INFO_ITYPE_ISDN_EXTENSION:INFO_ITYPE_ISDN;
memset(&p_m_g_delete, 0, sizeof(p_m_g_delete));
add_work(&p_m_g_delete, delete_event, this, 0);
p_m_g_callref = 0;
p_m_g_mode = 0;
p_m_g_gsm_b_sock = -1;
@ -87,7 +110,7 @@ Pgsm::Pgsm(int type, struct mISDNport *mISDNport, char *portname, struct port_se
p_m_g_encoder = gsm_audio_create();
if (!p_m_g_encoder || !p_m_g_decoder) {
PERROR("Failed to create GSM audio codec instance\n");
p_m_delete = 1;
trigger_work(&p_m_g_delete);
}
p_m_g_rxpos = 0;
p_m_g_tch_connected = 0;
@ -102,6 +125,8 @@ Pgsm::~Pgsm()
{
PDEBUG(DEBUG_GSM, "Destroyed GSM process(%s).\n", p_name);
del_work(&p_m_g_delete);
/* remove queued message */
if (p_m_g_notify_pending)
message_free(p_m_g_notify_pending);
@ -121,18 +146,21 @@ Pgsm::~Pgsm()
/* close bsc side bchannel */
void Pgsm::bchannel_close(void)
{
if (p_m_g_gsm_b_sock > -1)
if (p_m_g_gsm_b_sock > -1) {
unregister_fd(&p_m_g_gsm_b_fd);
close(p_m_g_gsm_b_sock);
}
p_m_g_gsm_b_sock = -1;
p_m_g_gsm_b_index = -1;
p_m_g_gsm_b_active = 0;
}
static int b_handler(struct lcr_fd *fd, unsigned int what, void *instance, int index);
/* open bsc side bchannel */
int Pgsm::bchannel_open(int index)
{
int ret;
unsigned int on = 1;
struct sockaddr_mISDN addr;
struct mISDNhead act;
@ -148,14 +176,10 @@ int Pgsm::bchannel_open(int index)
bchannel_close();
return(ret);
}
/* set nonblocking io */
ret = ioctl(p_m_g_gsm_b_sock, FIONBIO, &on);
if (ret < 0) {
PERROR("Failed to set bchannel-socket index %d into nonblocking IO\n", index);
bchannel_close();
return(ret);
}
memset(&p_m_g_gsm_b_fd, 0, sizeof(p_m_g_gsm_b_fd.fd));
p_m_g_gsm_b_fd.fd = p_m_g_gsm_b_sock;
register_fd(&p_m_g_gsm_b_fd, LCR_FD_READ, b_handler, this, 0);
/* bind socket to bchannel */
addr.family = AF_ISDN;
@ -374,7 +398,7 @@ void Pgsm::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_mnc
end_trace();
send_and_free_mncc((struct gsm_network *)gsm->network, mncc->msg_type, mncc);
new_state(PORT_STATE_RELEASE);
p_m_delete = 1;
trigger_work(&p_m_g_delete);
return;
}
p_m_g_callref = callref;
@ -395,7 +419,7 @@ void Pgsm::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_mnc
end_trace();
send_and_free_mncc((struct gsm_network *)gsm->network, mncc->msg_type, mncc);
new_state(PORT_STATE_RELEASE);
p_m_delete = 1;
trigger_work(&p_m_g_delete);
return;
}
@ -467,7 +491,7 @@ void Pgsm::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_mnc
end_trace();
send_and_free_mncc((struct gsm_network *)gsm->network, mncc->msg_type, mncc);
new_state(PORT_STATE_RELEASE);
p_m_delete = 1;
trigger_work(&p_m_g_delete);
return;
}
bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE);
@ -725,7 +749,7 @@ void Pgsm::disc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc
free_epointlist(p_epointlist);
}
new_state(PORT_STATE_RELEASE);
p_m_delete = 1;
trigger_work(&p_m_g_delete);
}
/* CC_RELEASE INDICATION */
@ -754,7 +778,7 @@ void Pgsm::rel_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc
free_epointlist(p_epointlist);
}
new_state(PORT_STATE_RELEASE);
p_m_delete = 1;
trigger_work(&p_m_g_delete);
}
/* NOTIFY INDICATION */
@ -985,7 +1009,7 @@ void Pgsm::message_setup(unsigned int epoint_id, int message_id, union parameter
message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
message_put(message);
new_state(PORT_STATE_RELEASE);
p_m_delete = 1;
trigger_work(&p_m_g_delete);
return;
}
@ -999,7 +1023,7 @@ void Pgsm::message_setup(unsigned int epoint_id, int message_id, union parameter
message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
message_put(message);
new_state(PORT_STATE_RELEASE);
p_m_delete = 1;
trigger_work(&p_m_g_delete);
return;
}
@ -1019,7 +1043,7 @@ void Pgsm::message_setup(unsigned int epoint_id, int message_id, union parameter
message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
message_put(message);
new_state(PORT_STATE_RELEASE);
p_m_delete = 1;
trigger_work(&p_m_g_delete);
return;
}
bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE);
@ -1351,7 +1375,7 @@ void Pgsm::message_release(unsigned int epoint_id, int message_id, union paramet
send_and_free_mncc((struct gsm_network *)gsm->network, mncc->msg_type, mncc);
new_state(PORT_STATE_RELEASE);
p_m_delete = 1;
trigger_work(&p_m_g_delete);
return;
}
@ -1434,28 +1458,29 @@ int Pgsm::message_epoint(unsigned int epoint_id, int message_id, union parameter
}
/*
* handler
*/
int Pgsm::handler(void)
/* deletes only if l3id is release, otherwhise it will be triggered then */
static int delete_event(struct lcr_work *work, void *instance, int index)
{
class Pgsm *gsmport = (class Pgsm *)instance;
delete gsmport;
return 0;
}
/*
* handler of bchannel events
*/
static int b_handler(struct lcr_fd *fd, unsigned int what, void *instance, int index)
{
class Pgsm *gsmport = (class Pgsm *)instance;
int ret;
int work = 0;
unsigned char buffer[2048+MISDN_HEADER_LEN];
struct mISDNhead *hh = (struct mISDNhead *)buffer;
if ((ret = PmISDN::handler()))
return(ret);
/* handle destruction */
if (p_m_delete) {
delete this;
return(-1);
}
/* handle message from bchannel */
if (p_m_g_gsm_b_sock > -1) {
ret = recv(p_m_g_gsm_b_sock, buffer, sizeof(buffer), 0);
if (gsmport->p_m_g_gsm_b_sock > -1) {
ret = recv(gsmport->p_m_g_gsm_b_sock, buffer, sizeof(buffer), 0);
if (ret >= (int)MISDN_HEADER_LEN) {
switch(hh->prim) {
/* we don't care about confirms, we use rx data to sync tx */
@ -1463,37 +1488,21 @@ int Pgsm::handler(void)
break;
/* we receive audio data, we respond to it AND we send tones */
case PH_DATA_IND:
bchannel_receive(hh, buffer+MISDN_HEADER_LEN, ret-MISDN_HEADER_LEN);
gsmport->bchannel_receive(hh, buffer+MISDN_HEADER_LEN, ret-MISDN_HEADER_LEN);
break;
case PH_ACTIVATE_IND:
p_m_g_gsm_b_active = 1;
gsmport->p_m_g_gsm_b_active = 1;
break;
case PH_DEACTIVATE_IND:
p_m_g_gsm_b_active = 0;
gsmport->p_m_g_gsm_b_active = 0;
break;
}
work = 1;
} else {
if (ret < 0 && errno != EWOULDBLOCK)
PERROR("Read from GSM port, index %d failed with return code %d\n", ret);
}
}
return(work);
}
/*
* handles bsc select function within LCR's main loop
*/
int handle_gsm(void)
{
int ret1, ret2;
ret1 = bsc_upqueue((struct gsm_network *)gsm->network);
ret2 = bsc_select_main(1); /* polling */
if (ret1 || ret2)
return 1;
return 0;
}
@ -1599,10 +1608,21 @@ int gsm_init(void)
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
int pcapfd, rc;
debug_init();
tall_bsc_ctx = talloc_named_const(NULL, 1, "openbsc");
talloc_ctx_init();
on_dso_load_token();
on_dso_load_rrlp();
on_dso_load_ho_dec();
stderr_target = debug_target_create_stderr();
debug_add_target(stderr_target);
bts_model_unknown_init();
bts_model_bs11_init();
bts_model_nanobts_init();
/* enable filters */
debug_set_all_filter(stderr_target, 1);
/* seed the PRNG */
srand(time(NULL));
@ -1618,7 +1638,6 @@ int gsm_init(void)
}
/* set debug */
stderr_target = debug_target_create_stderr();
if (gsm->conf.debug[0])
debug_parse_category_mask(stderr_target, gsm->conf.debug);
@ -1655,6 +1674,11 @@ int gsm_init(void)
}
printf("DB: Database prepared.\n");
/* setup the timer */
db_sync_timer.cb = db_sync_timer_cb;
db_sync_timer.data = NULL;
bsc_schedule_timer(&db_sync_timer, DB_SYNC_INTERVAL);
/* bootstrap network */
if (gsm->conf.openbsc_cfg[0] == '/')
SCPY(cfg, gsm->conf.openbsc_cfg);
@ -1675,3 +1699,18 @@ int gsm_init(void)
return 0;
}
/*
* handles bsc select function within LCR's main loop
*/
int handle_gsm(void)
{
int ret1, ret2;
ret1 = bsc_upqueue((struct gsm_network *)gsm->network);
debug_reset_context();
ret2 = bsc_select_main(1); /* polling */
if (ret1 || ret2)
return 1;
return 0;
}

3
gsm.h
View File

@ -33,9 +33,11 @@ class Pgsm : public PmISDN
Pgsm(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel, int exclusive, int mode);
~Pgsm();
struct lcr_work p_m_g_delete; /* timer for audio transmission */
unsigned int p_m_g_callref; /* ref by OpenBSC */
unsigned int p_m_g_mode; /* data/transparent mode */
int p_m_g_gsm_b_sock; /* gsm bchannel socket */
struct lcr_fd p_m_g_gsm_b_fd; /* event node */
int p_m_g_gsm_b_index; /* gsm bchannel socket index to use */
int p_m_g_gsm_b_active; /* gsm bchannel socket is activated */
struct lcr_msg *p_m_g_notify_pending; /* queue for NOTIFY if not connected */
@ -72,7 +74,6 @@ class Pgsm : public PmISDN
void message_disconnect(unsigned int epoint_id, int message_id, union parameter *param);
void message_release(unsigned int epoint_id, int message_id, union parameter *param);
int message_epoint(unsigned int epoint_id, int message_id, union parameter *param);
int handler(void);
};
extern char *gsm_conf_error;

View File

@ -91,15 +91,6 @@ void Join::message_epoint(unsigned int epoint_id, int message_type, union parame
}
/* join process is called from the main loop
* it processes the current calling state.
* returns 0 if nothing was done
*/
int Join::handler(void)
{
return(0);
}
/* free all join structures */
void join_free(void)
{

1
join.h
View File

@ -24,7 +24,6 @@ class Join
virtual ~Join();
class Join *next; /* next node in list of joins */
virtual void message_epoint(unsigned int epoint_id, int message, union parameter *param);
virtual int handler(void);
unsigned int j_type; /* join type (pbx or asterisk) */
unsigned int j_serial; /* serial/unique number of join */

View File

@ -202,6 +202,7 @@ void joinpbx_debug(class JoinPBX *joinpbx, const char *function)
PDEBUG(DEBUG_JOIN, "end\n");
}
int update_bridge(struct lcr_work *work, void *instance, int index);
/*
* constructor for a new join
@ -223,11 +224,12 @@ JoinPBX::JoinPBX(class Endpoint *epoint) : Join()
j_dialed[0] = '\0';
j_todial[0] = '\0';
j_pid = getpid();
j_updatebridge = 0;
j_partyline = 0;
j_partyline_jingle = 0;
j_multicause = 0;
j_multilocation = 0;
memset(&j_updatebridge, 0, sizeof(j_updatebridge));
add_work(&j_updatebridge, update_bridge, this, 0);
/* initialize a relation only to the calling interface */
relation = j_relation = (struct join_relation *)MALLOC(sizeof(struct join_relation));
@ -258,12 +260,23 @@ JoinPBX::~JoinPBX()
cmemuse--;
relation = rtemp;
}
del_work(&j_updatebridge);
}
/* bridge sets the audio flow of all bchannels assiociated to 'this' join
* also it changes and notifies active/hold/conference states
*/
int update_bridge(struct lcr_work *work, void *instance, int index)
{
class JoinPBX *joinpbx = (class JoinPBX *)instance;
joinpbx->bridge();
return 0;
}
void JoinPBX::bridge(void)
{
struct join_relation *relation;
@ -453,7 +466,7 @@ int JoinPBX::release(struct join_relation *relation, int location, int cause)
/* remove from bridge */
if (relation->channel_state != 0) {
relation->channel_state = 0;
j_updatebridge = 1; /* update bridge flag */
trigger_work(&j_updatebridge);
// note: if join is not released, bridge must be updated
}
@ -677,7 +690,7 @@ void JoinPBX::message_epoint(unsigned int epoint_id, int message_type, union par
SPRINT(message->param.connectinfo.id, "%d", j_partyline);
message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
message_put(message);
j_updatebridge = 1; /* update bridge flag */
trigger_work(&j_updatebridge);
if (j_partyline_jingle)
play_jingle(1);
break;
@ -686,7 +699,7 @@ void JoinPBX::message_epoint(unsigned int epoint_id, int message_type, union par
PDEBUG(DEBUG_JOIN, "join received channel message: %d.\n", param->audiopath);
if (relation->channel_state != param->audiopath) {
relation->channel_state = param->audiopath;
j_updatebridge = 1; /* update bridge flag */
trigger_work(&j_updatebridge);
if (options.deb & DEBUG_JOIN)
joinpbx_debug(this, "Join::message_epoint{after setting new channel state}");
}
@ -721,7 +734,7 @@ void JoinPBX::message_epoint(unsigned int epoint_id, int message_type, union par
PDEBUG(DEBUG_JOIN, "join received channel message: %d.\n", param->audiopath);
if (relation->channel_state != param->audiopath) {
relation->channel_state = param->audiopath;
j_updatebridge = 1; /* update bridge flag */
trigger_work(&j_updatebridge);
if (options.deb & DEBUG_JOIN)
joinpbx_debug(this, "Join::message_epoint{after setting new channel state}");
}
@ -739,7 +752,7 @@ void JoinPBX::message_epoint(unsigned int epoint_id, int message_type, union par
new_state = track_notify(relation->rx_state, param->notifyinfo.notify);
if (new_state != relation->rx_state) {
relation->rx_state = new_state;
j_updatebridge = 1;
trigger_work(&j_updatebridge);
if (options.deb & DEBUG_JOIN)
joinpbx_debug(this, "Join::message_epoint{after setting new rx state}");
}
@ -895,30 +908,6 @@ void JoinPBX::message_epoint(unsigned int epoint_id, int message_type, union par
}
/* join process is called from the main loop
* it processes the current calling state.
* returns 0 if join nothing was done
*/
int JoinPBX::handler(void)
{
// struct join_relation *relation;
// char dialing[32][32];
// int port[32];
// int found;
// int i, j;
// char *p;
/* the bridge must be updated */
if (j_updatebridge) {
bridge();
j_updatebridge = 0;
return(1);
}
return(0);
}
int track_notify(int oldstate, int notify)
{
int newstate = oldstate;

View File

@ -50,7 +50,6 @@ class JoinPBX : public Join
JoinPBX(class Endpoint *epoint);
~JoinPBX();
void message_epoint(unsigned int epoint_id, int message, union parameter *param);
int handler(void);
int release(struct join_relation *relation, int location, int cause);
char j_caller[32]; /* caller number */
@ -60,7 +59,7 @@ class JoinPBX : public Join
int j_multicause, j_multilocation;
int j_pid; /* pid of join to generate bridge id */
int j_updatebridge; /* bridge must be updated */
struct lcr_work j_updatebridge; /* bridge must be updated */
struct join_relation *j_relation; /* list of endpoints that are related to the join */
int j_partyline; /* if set, join is conference room */

View File

@ -49,17 +49,6 @@ JoinRemote::~JoinRemote()
{
}
/* join process is called from the main loop
* it processes the current calling state.
* returns 0 if join nothing was done
*/
int JoinRemote::handler(void)
{
return(0);
}
void JoinRemote::message_epoint(unsigned int epoint_id, int message_type, union parameter *param)
{
/* if endpoint has just been removed, but still a message in the que */

View File

@ -16,7 +16,6 @@ class JoinRemote : public Join
~JoinRemote();
void message_epoint(unsigned int epoint_id, int message, union parameter *param);
void message_remote(int message_type, union parameter *param);
int handler(void);
int j_remote_id;
char j_remote_name[32];

View File

@ -25,6 +25,7 @@
#include "macro.h"
#include "options.h"
#include "join.h"
#include "select.h"
#include "joinpbx.h"
#include "extension.h"
#include "message.h"

556
mISDN.cpp
View File

@ -45,6 +45,12 @@ int mISDN_rand_count = 0;
unsigned int mt_assign_pid = ~0;
int mISDNsocket = -1;
static int upqueue_pipe[2];
static struct lcr_fd upqueue_fd;
int upqueue_avail = 0;
static int mISDN_upqueue(struct lcr_fd *fd, unsigned int what, void *instance, int i);
static int mISDN_timeout(struct lcr_timer *timer, void *instance, int i);
int mISDN_initialize(void)
{
@ -74,6 +80,12 @@ int mISDN_initialize(void)
} else
mISDN_debug_init(0, NULL, NULL, NULL);
if (pipe(upqueue_pipe) < 0)
FATAL("Failed to open pipe\n");
memset(&upqueue_fd, 0, sizeof(upqueue_fd.fd));
upqueue_fd.fd = upqueue_pipe[0];
register_fd(&upqueue_fd, LCR_FD_READ, mISDN_upqueue, NULL, 0);
return(0);
}
@ -89,8 +101,17 @@ void mISDN_deinitialize(void)
if (mISDNsocket > -1)
close(mISDNsocket);
if (upqueue_fd.inuse) {
unregister_fd(&upqueue_fd);
close(upqueue_pipe[0]);
close(upqueue_pipe[1]);
}
upqueue_avail = 0;
}
int load_timer(struct lcr_timer *timer, void *instance, int index);
/*
* constructor
*/
@ -103,7 +124,6 @@ PmISDN::PmISDN(int type, mISDNport *mISDNport, char *portname, struct port_setti
p_m_b_exclusive = 0;
p_m_b_reserve = 0;
p_m_b_mode = mode;
p_m_delete = 0;
p_m_hold = 0;
p_m_tx_gain = mISDNport->ifport->interface->tx_gain;
p_m_rx_gain = mISDNport->ifport->interface->rx_gain;
@ -118,13 +138,15 @@ PmISDN::PmISDN(int type, mISDNport *mISDNport, char *portname, struct port_setti
p_m_inband_send_on = 0;
p_m_inband_receive_on = 0;
p_m_dtmf = !mISDNport->ifport->nodtmf;
p_m_timeout = 0;
p_m_timer = 0;
memset(&p_m_timeout, 0, sizeof(p_m_timeout));
add_timer(&p_m_timeout, mISDN_timeout, this, 0);
p_m_remote_ref = 0; /* channel shall be exported to given remote */
p_m_remote_id = 0; /* remote admin socket */
SCPY(p_m_pipeline, mISDNport->ifport->interface->pipeline);
/* audio */
memset(&p_m_loadtimer, 0, sizeof(p_m_loadtimer));
add_timer(&p_m_loadtimer, load_timer, this, 0);
p_m_load = 0;
p_m_last_tv_sec = 0;
@ -173,6 +195,9 @@ PmISDN::~PmISDN()
{
struct lcr_msg *message;
del_timer(&p_m_timeout);
del_timer(&p_m_loadtimer);
/* remove bchannel relation */
drop_bchannel();
@ -357,6 +382,7 @@ void ph_control_block(struct mISDNport *mISDNport, class PmISDN *isdnport, int s
end_trace();
}
static int b_sock_callback(struct lcr_fd *fd, unsigned int what, void *instance, int i);
/*
* subfunction for bchannel_event
@ -365,47 +391,40 @@ void ph_control_block(struct mISDNport *mISDNport, class PmISDN *isdnport, int s
static int _bchannel_create(struct mISDNport *mISDNport, int i)
{
int ret;
unsigned int on = 1;
struct sockaddr_mISDN addr;
if (mISDNport->b_socket[i] > -1) {
if (mISDNport->b_sock[i].inuse) {
PERROR("Error: Socket already created for index %d\n", i);
return(0);
}
/* open socket */
//#warning testing without DSP
// mISDNport->b_socket[i] = socket(PF_ISDN, SOCK_DGRAM, (mISDNport->b_mode[i]==B_MODE_HDLC)?ISDN_P_B_HDLC:ISDN_P_B_RAW);
mISDNport->b_socket[i] = socket(PF_ISDN, SOCK_DGRAM, (mISDNport->b_mode[i]==B_MODE_HDLC)?ISDN_P_B_L2DSPHDLC:ISDN_P_B_L2DSP);
if (mISDNport->b_socket[i] < 0) {
// mISDNport->b_sock[i].fd = socket(PF_ISDN, SOCK_DGRAM, (mISDNport->b_mode[i]==B_MODE_HDLC)?ISDN_P_B_HDLC:ISDN_P_B_RAW);
mISDNport->b_sock[i].fd = socket(PF_ISDN, SOCK_DGRAM, (mISDNport->b_mode[i]==B_MODE_HDLC)?ISDN_P_B_L2DSPHDLC:ISDN_P_B_L2DSP);
if (mISDNport->b_sock[i].fd < 0) {
PERROR("Error: Failed to open bchannel-socket for index %d with mISDN-DSP layer. Did you load mISDN_dsp.ko?\n", i);
return(0);
}
/* set nonblocking io */
ret = ioctl(mISDNport->b_socket[i], FIONBIO, &on);
if (ret < 0) {
PERROR("Error: Failed to set bchannel-socket index %d into nonblocking IO\n", i);
close(mISDNport->b_socket[i]);
mISDNport->b_socket[i] = -1;
return(0);
}
/* register callback for read */
register_fd(&mISDNport->b_sock[i], LCR_FD_READ, b_sock_callback, mISDNport, i);
/* bind socket to bchannel */
addr.family = AF_ISDN;
addr.dev = mISDNport->portnum;
addr.channel = i+1+(i>=15);
ret = bind(mISDNport->b_socket[i], (struct sockaddr *)&addr, sizeof(addr));
ret = bind(mISDNport->b_sock[i].fd, (struct sockaddr *)&addr, sizeof(addr));
if (ret < 0) {
PERROR("Error: Failed to bind bchannel-socket for index %d with mISDN-DSP layer (errno=%d). Did you load mISDN_dsp.ko?\n", i, errno);
close(mISDNport->b_socket[i]);
mISDNport->b_socket[i] = -1;
close(mISDNport->b_sock[i].fd);
unregister_fd(&mISDNport->b_sock[i]);
return(0);
}
chan_trace_header(mISDNport, mISDNport->b_port[i], "BCHANNEL create socket", DIRECTION_OUT);
add_trace("channel", NULL, "%d", i+1+(i>=15));
add_trace("socket", NULL, "%d", mISDNport->b_socket[i]);
add_trace("socket", NULL, "%d", mISDNport->b_sock[i].fd);
end_trace();
return(1);
@ -416,23 +435,23 @@ static int _bchannel_create(struct mISDNport *mISDNport, int i)
* subfunction for bchannel_event
* activate / deactivate request
*/
static void _bchannel_activate(struct mISDNport *mISDNport, int i, int activate)
static void _bchannel_activate(struct mISDNport *mISDNport, int i, int activate, int timeout)
{
struct mISDNhead act;
int ret;
if (mISDNport->b_socket[i] < 0)
if (!mISDNport->b_sock[i].inuse)
return;
act.prim = (activate)?PH_ACTIVATE_REQ:PH_DEACTIVATE_REQ;
act.id = 0;
ret = sendto(mISDNport->b_socket[i], &act, MISDN_HEADER_LEN, 0, NULL, 0);
ret = sendto(mISDNport->b_sock[i].fd, &act, MISDN_HEADER_LEN, 0, NULL, 0);
if (ret <= 0)
PERROR("Failed to send to socket %d\n", mISDNport->b_socket[i]);
PERROR("Failed to send to socket %d\n", mISDNport->b_sock[i].fd);
/* trace */
chan_trace_header(mISDNport, mISDNport->b_port[i], activate ? "BCHANNEL activate" : "BCHANNEL deactivate", DIRECTION_OUT);
add_trace("channel", NULL, "%d", i+1+(i>=15));
if (mISDNport->b_timer[i])
if (timeout)
add_trace("event", NULL, "timeout recovery");
end_trace();
}
@ -447,9 +466,9 @@ static void _bchannel_configure(struct mISDNport *mISDNport, int i)
struct PmISDN *port;
int handle, mode;
if (mISDNport->b_socket[i] < 0)
if (!mISDNport->b_sock[i].inuse)
return;
handle = mISDNport->b_socket[i];
handle = mISDNport->b_sock[i].fd;
port = mISDNport->b_port[i];
mode = mISDNport->b_mode[i];
if (!port) {
@ -491,7 +510,7 @@ void PmISDN::set_conf(int oldconf, int newconf)
PDEBUG(DEBUG_BCHANNEL, "we change conference from conf=%d to conf=%d.\n", oldconf, newconf);
if (p_m_b_index > -1)
if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE)
ph_control(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], (newconf)?DSP_CONF_JOIN:DSP_CONF_SPLIT, newconf, "DSP-CONF", newconf);
ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, (newconf)?DSP_CONF_JOIN:DSP_CONF_SPLIT, newconf, "DSP-CONF", newconf);
} else
PDEBUG(DEBUG_BCHANNEL, "we already have conf=%d.\n", newconf);
}
@ -503,14 +522,14 @@ void PmISDN::set_conf(int oldconf, int newconf)
*/
static void _bchannel_destroy(struct mISDNport *mISDNport, int i)
{
if (mISDNport->b_socket[i] < 0)
if (!mISDNport->b_sock[i].inuse)
return;
chan_trace_header(mISDNport, mISDNport->b_port[i], "BCHANNEL remove socket", DIRECTION_OUT);
add_trace("channel", NULL, "%d", i+1+(i>=15));
add_trace("socket", NULL, "%d", mISDNport->b_socket[i]);
add_trace("socket", NULL, "%d", mISDNport->b_sock[i].fd);
end_trace();
close(mISDNport->b_socket[i]);
mISDNport->b_socket[i] = -1;
close(mISDNport->b_sock[i].fd);
unregister_fd(&mISDNport->b_sock[i]);
}
@ -610,7 +629,7 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
{
class PmISDN *b_port = mISDNport->b_port[i];
int state = mISDNport->b_state[i];
double timer = mISDNport->b_timer[i];
int timer = -1; // no change
unsigned int p_m_remote_ref = 0;
unsigned int p_m_remote_id = 0;
int p_m_tx_gain = 0;
@ -652,9 +671,9 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
} else {
/* create stack and send activation request */
if (_bchannel_create(mISDNport, i)) {
_bchannel_activate(mISDNport, i, 1);
_bchannel_activate(mISDNport, i, 1, 0);
state = B_STATE_ACTIVATING;
timer = now_d + B_TIMER_ACTIVATING;
timer = B_TIMER_ACTIVATING;
}
}
break;
@ -711,9 +730,9 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
case B_STATE_ACTIVE:
/* bchannel is active, so we deactivate */
_bchannel_activate(mISDNport, i, 0);
_bchannel_activate(mISDNport, i, 0, 0);
state = B_STATE_DEACTIVATING;
timer = now_d + B_TIMER_DEACTIVATING;
timer = B_TIMER_DEACTIVATING;
break;
default:
@ -773,9 +792,9 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
b_port->p_m_load = 0;
} else {
/* bchannel is active, but exported OR not used anymore (or has wrong stack config), so we deactivate */
_bchannel_activate(mISDNport, i, 0);
_bchannel_activate(mISDNport, i, 0, 0);
state = B_STATE_DEACTIVATING;
timer = now_d + B_TIMER_DEACTIVATING;
timer = B_TIMER_DEACTIVATING;
}
break;
@ -824,9 +843,9 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
case B_STATE_ACTIVE:
/* bchannel is active, so we deactivate */
_bchannel_activate(mISDNport, i, 0);
_bchannel_activate(mISDNport, i, 0, 0);
state = B_STATE_DEACTIVATING;
timer = now_d + B_TIMER_DEACTIVATING;
timer = B_TIMER_DEACTIVATING;
break;
case B_STATE_REMOTE:
@ -872,9 +891,9 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
mISDNport->b_remote_ref[i] = p_m_remote_ref;
} else {
if (_bchannel_create(mISDNport, i)) {
_bchannel_activate(mISDNport, i, 1);
_bchannel_activate(mISDNport, i, 1, 0);
state = B_STATE_ACTIVATING;
timer = now_d + B_TIMER_ACTIVATING;
timer = B_TIMER_ACTIVATING;
}
}
}
@ -904,9 +923,9 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
mISDNport->b_remote_ref[i] = p_m_remote_ref;
} else {
if (_bchannel_create(mISDNport, i)) {
_bchannel_activate(mISDNport, i, 1);
_bchannel_activate(mISDNport, i, 1, 0);
state = B_STATE_ACTIVATING;
timer = now_d + B_TIMER_ACTIVATING;
timer = B_TIMER_ACTIVATING;
}
}
}
@ -926,13 +945,13 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
break;
case B_STATE_ACTIVATING:
_bchannel_activate(mISDNport, i, 1);
timer = now_d + B_TIMER_ACTIVATING;
_bchannel_activate(mISDNport, i, 1, 1);
timer = B_TIMER_ACTIVATING;
break;
case B_STATE_DEACTIVATING:
_bchannel_activate(mISDNport, i, 0);
timer = now_d + B_TIMER_DEACTIVATING;
_bchannel_activate(mISDNport, i, 0, 1);
timer = B_TIMER_DEACTIVATING;
break;
default:
@ -945,7 +964,10 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
}
mISDNport->b_state[i] = state;
mISDNport->b_timer[i] = timer;
if (timer == 0)
unsched_timer(&mISDNport->b_timer[i]);
else if (timer > 0)
schedule_timer(&mISDNport->b_timer[i], timer, 0);
}
@ -1204,31 +1226,46 @@ on empty load, remote-audio causes the load with the remote audio to be increase
+--------------------+----------------------+
*/
int PmISDN::handler(void)
void PmISDN::update_load(void)
{
/* don't trigger load event if: */
if (!p_tone_name[0] && !p_m_crypt_msg_loops && !p_m_inband_send_on)
return;
/* don't trigger load event if event already active */
if (p_m_loadtimer.active)
return;
schedule_timer(&p_m_loadtimer, 0, 0); /* no delay the first time */
}
int load_timer(struct lcr_timer *timer, void *instance, int index)
{
class PmISDN *isdnport = (class PmISDN *)instance;
isdnport->load_tx();
return 0;
}
void PmISDN::load_tx(void)
{
struct lcr_msg *message;
int elapsed = 0;
int ret;
if ((ret = Port::handler()))
return(ret);
struct timeval current_time;
/* get elapsed */
gettimeofday(&current_time, NULL);
if (p_m_last_tv_sec) {
elapsed = 8000 * (now_tv.tv_sec - p_m_last_tv_sec)
+ 8 * (now_tv.tv_usec/1000 - p_m_last_tv_msec);
} else {
/* set clock of first process ever in this instance */
p_m_last_tv_sec = now_tv.tv_sec;
p_m_last_tv_msec = now_tv.tv_usec/1000;
elapsed = 8000 * (current_time.tv_sec - p_m_last_tv_sec)
+ 8 * (current_time.tv_usec/1000 - p_m_last_tv_msec);
}
/* process only if we have a minimum of samples, to make packets not too small */
if (elapsed >= ISDN_TRANSMIT
&& p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE) {
/* set clock of last process! */
p_m_last_tv_sec = now_tv.tv_sec;
p_m_last_tv_msec = now_tv.tv_usec/1000;
/* set clock of last process! */
p_m_last_tv_sec = current_time.tv_sec;
p_m_last_tv_msec = current_time.tv_usec/1000;
/* process only if we have samples and we are active */
if (elapsed && p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE) {
/* update load */
if (elapsed < p_m_load)
p_m_load -= elapsed;
@ -1237,7 +1274,7 @@ int PmISDN::handler(void)
/* to send data, tone must be on */
if ((p_tone_name[0] || p_m_crypt_msg_loops || p_m_inband_send_on) /* what tones? */
&& (p_m_load < ISDN_LOAD) /* enough load? */
&& (p_m_load < ISDN_LOAD) /* not too much load? */
&& (p_state==PORT_STATE_CONNECT || p_m_mISDNport->tones || p_m_inband_send_on)) { /* connected or inband-tones? */
int tosend = ISDN_LOAD - p_m_load, length;
unsigned char buf[MISDN_HEADER_LEN+tosend];
@ -1267,6 +1304,8 @@ int PmISDN::handler(void)
/* next loop */
p_m_crypt_msg_current = 0;
p_m_crypt_msg_loops--;
if (!p_m_crypt_msg_loops)
update_rxoff();
// puts("eine loop weniger");
}
@ -1283,32 +1322,34 @@ int PmISDN::handler(void)
if (ISDN_LOAD - p_m_load - tosend > 0) {
frm->prim = PH_DATA_REQ;
frm->id = 0;
ret = sendto(p_m_mISDNport->b_socket[p_m_b_index], buf, MISDN_HEADER_LEN+ISDN_LOAD-p_m_load-tosend, 0, NULL, 0);
ret = sendto(p_m_mISDNport->b_sock[p_m_b_index].fd, buf, MISDN_HEADER_LEN+ISDN_LOAD-p_m_load-tosend, 0, NULL, 0);
if (ret <= 0)
PERROR("Failed to send to socket %d (samples = %d)\n", p_m_mISDNport->b_socket[p_m_b_index], ISDN_LOAD-p_m_load-tosend);
PERROR("Failed to send to socket %d (samples = %d)\n", p_m_mISDNport->b_sock[p_m_b_index].fd, ISDN_LOAD-p_m_load-tosend);
p_m_load += ISDN_LOAD - p_m_load - tosend;
}
}
}
// NOTE: deletion is done by the child class
/* handle timeouts */
if (p_m_timeout) {
if (p_m_timer+p_m_timeout < now_d) {
PDEBUG(DEBUG_ISDN, "(%s) timeout after %d seconds detected (state=%d).\n", p_name, p_m_timeout, p_state);
p_m_timeout = 0;
/* send timeout to endpoint */
message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_TIMEOUT);
message->param.state = p_state;
message_put(message);
return(1);
}
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);
}
return(0); /* nothing done */
}
/* handle timeouts */
static int mISDN_timeout(struct lcr_timer *timer, void *instance, int i)
{
class PmISDN *isdnport = (class PmISDN *)instance;
struct lcr_msg *message;
PDEBUG(DEBUG_ISDN, "(%s) timeout after %d seconds detected (state=%d).\n", isdnport->p_name, isdnport->p_m_timeout.timeout.tv_sec, isdnport->p_state);
/* send timeout to endpoint */
message = message_create(isdnport->p_serial, ACTIVE_EPOINT(isdnport->p_epointlist), PORT_TO_EPOINT, MESSAGE_TIMEOUT);
message->param.state = isdnport->p_state;
message_put(message);
return 0;
}
/*
* whenever we get audio data from bchannel, we process it here
@ -1466,7 +1507,7 @@ void PmISDN::set_echotest(int echo)
PDEBUG(DEBUG_ISDN, "we set echo to echo=%d.\n", p_m_echo);
if (p_m_b_channel)
if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE)
ph_control(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], p_m_echo?DSP_ECHO_ON:DSP_ECHO_OFF, 0, "DSP-ECHO", p_m_echo);
ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, p_m_echo?DSP_ECHO_ON:DSP_ECHO_OFF, 0, "DSP-ECHO", p_m_echo);
}
}
@ -1509,7 +1550,7 @@ void PmISDN::set_tone(const char *dir, const char *tone)
if (p_m_b_index > -1)
if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT) {
PDEBUG(DEBUG_ISDN, "we reset tone from id=%d to OFF.\n", p_m_tone);
ph_control(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], DSP_TONE_PATT_OFF, 0, "DSP-TONE", 0);
ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, DSP_TONE_PATT_OFF, 0, "DSP-TONE", 0);
}
p_m_tone = 0;
Port::set_tone(dir, tone);
@ -1581,7 +1622,7 @@ void PmISDN::set_tone(const char *dir, const char *tone)
PDEBUG(DEBUG_ISDN, "we set tone to id=%d.\n", p_m_tone);
if (p_m_b_index > -1)
if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT)
ph_control(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], p_m_tone?DSP_TONE_PATT_ON:DSP_TONE_PATT_OFF, p_m_tone, "DSP-TONE", p_m_tone);
ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, p_m_tone?DSP_TONE_PATT_ON:DSP_TONE_PATT_OFF, p_m_tone, "DSP-TONE", p_m_tone);
}
/* turn user-space tones off in cases of no tone OR dsp tone */
Port::set_tone("",NULL);
@ -1600,7 +1641,7 @@ void PmISDN::message_mISDNsignal(unsigned int epoint_id, int message_id, union p
PDEBUG(DEBUG_BCHANNEL, "we change tx-volume to shift=%d.\n", p_m_tx_gain);
if (p_m_b_index > -1)
if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT)
ph_control(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], DSP_VOL_CHANGE_TX, p_m_tx_gain, "DSP-TX_GAIN", p_m_tx_gain);
ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, DSP_VOL_CHANGE_TX, p_m_tx_gain, "DSP-TX_GAIN", p_m_tx_gain);
} else
PDEBUG(DEBUG_BCHANNEL, "we already have tx-volume shift=%d.\n", p_m_rx_gain);
if (p_m_rx_gain != param->mISDNsignal.rx_gain) {
@ -1608,7 +1649,7 @@ void PmISDN::message_mISDNsignal(unsigned int epoint_id, int message_id, union p
PDEBUG(DEBUG_BCHANNEL, "we change rx-volume to shift=%d.\n", p_m_rx_gain);
if (p_m_b_index > -1)
if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT)
ph_control(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], DSP_VOL_CHANGE_RX, p_m_rx_gain, "DSP-RX_GAIN", p_m_rx_gain);
ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, DSP_VOL_CHANGE_RX, p_m_rx_gain, "DSP-RX_GAIN", p_m_rx_gain);
} else
PDEBUG(DEBUG_BCHANNEL, "we already have rx-volume shift=%d.\n", p_m_rx_gain);
break;
@ -1624,6 +1665,7 @@ void PmISDN::message_mISDNsignal(unsigned int epoint_id, int message_id, union p
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;
@ -1634,7 +1676,7 @@ void PmISDN::message_mISDNsignal(unsigned int epoint_id, int message_id, union p
PDEBUG(DEBUG_BCHANNEL, "we change delay mode to delay=%d.\n", p_m_delay);
if (p_m_b_index > -1)
if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT)
ph_control(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], p_m_delay?DSP_DELAY:DSP_JITTER, p_m_delay, "DSP-DELAY", p_m_delay);
ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, p_m_delay?DSP_DELAY:DSP_JITTER, p_m_delay, "DSP-DELAY", p_m_delay);
} else
PDEBUG(DEBUG_BCHANNEL, "we already have delay=%d.\n", p_m_delay);
break;
@ -1665,7 +1707,7 @@ void PmISDN::message_crypt(unsigned int epoint_id, int message_id, union paramet
PDEBUG(DEBUG_BCHANNEL, "we set encryption to crypt=%d. (0 means OFF)\n", p_m_crypt);
if (p_m_b_index > -1)
if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT)
ph_control_block(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], p_m_crypt?DSP_BF_ENABLE_KEY:DSP_BF_DISABLE, p_m_crypt_key, p_m_crypt_key_len, "DSP-CRYPT", p_m_crypt_key_len);
ph_control_block(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, p_m_crypt?DSP_BF_ENABLE_KEY:DSP_BF_DISABLE, p_m_crypt_key, p_m_crypt_key_len, "DSP-CRYPT", p_m_crypt_key_len);
break;
case CC_DACT_REQ: /* deactivate session encryption */
@ -1675,11 +1717,13 @@ void PmISDN::message_crypt(unsigned int epoint_id, int message_id, union paramet
case CR_LISTEN_REQ: /* start listening to messages */
p_m_crypt_listen = 1;
update_rxoff();
p_m_crypt_listen_state = 0;
break;
case CR_UNLISTEN_REQ: /* stop listening to messages */
p_m_crypt_listen = 0;
update_rxoff();
break;
case CR_MESSAGE_REQ: /* send message */
@ -1690,11 +1734,13 @@ void PmISDN::message_crypt(unsigned int epoint_id, int message_id, union paramet
}
p_m_crypt_msg_current = 0; /* reset */
p_m_crypt_msg_loops = 6; /* enable */
update_rxoff();
update_load();
#if 0
/* disable txmix, or we get corrupt data due to audio process */
if (p_m_txmix && p_m_b_index>=0 && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT) {
PDEBUG(DEBUG_BCHANNEL, "for sending CR_MESSAGE_REQ, we reset txmix from txmix=%d.\n", p_m_txmix);
ph_control(p_m_mISDNport, this, p_mISDNport->b_socket[p_m_b_index], DSP_MIX_OFF, 0, "DSP-TXMIX", 0);
ph_control(p_m_mISDNport, this, p_mISDNport->b_sock[p_m_b_index].fd, DSP_MIX_OFF, 0, "DSP-TXMIX", 0);
}
#endif
break;
@ -1732,131 +1778,68 @@ int PmISDN::message_epoint(unsigned int epoint_id, int message_id, union paramet
return(0);
}
/*
* main loop for processing messages from mISDN
*/
int mISDN_handler(void)
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) {
/* rx IS required */
if (p_m_rxoff) {
/* turn on RX */
p_m_rxoff = 0;
PDEBUG(DEBUG_BCHANNEL, "%s: receive data is required, so we turn them on\n", __FUNCTION__);
if (p_m_b_index > -1)
if (p_m_mISDNport->b_port[p_m_b_index] && p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE)
ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, DSP_RECEIVE_ON, 0, "DSP-RXOFF", 0);
}
} else {
/* rx NOT required */
if (!p_m_rxoff) {
/* turn off RX */
p_m_rxoff = 1;
PDEBUG(DEBUG_BCHANNEL, "%s: receive data is not required, so we turn them off\n", __FUNCTION__);
if (p_m_b_index > -1)
if (p_m_mISDNport->b_port[p_m_b_index] && p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE)
ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, DSP_RECEIVE_OFF, 0, "DSP-RXOFF", 1);
}
}
/* recording */
if (p_record) {
/* txdata IS required */
if (!p_m_txdata) {
/* turn on RX */
p_m_txdata = 1;
PDEBUG(DEBUG_BCHANNEL, "%s: transmit data is required, so we turn them on\n", __FUNCTION__);
if (p_m_b_index > -1)
if (p_m_mISDNport->b_port[p_m_b_index] && p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE)
ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, DSP_TXDATA_ON, 0, "DSP-TXDATA", 1);
}
} else {
/* txdata NOT required */
if (p_m_txdata) {
/* turn off RX */
p_m_txdata = 0;
PDEBUG(DEBUG_BCHANNEL, "%s: transmit data is not required, so we turn them off\n", __FUNCTION__);
if (p_m_b_index > -1)
if (p_m_mISDNport->b_port[p_m_b_index] && p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE)
ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, DSP_TXDATA_OFF, 0, "DSP-TXDATA", 0);
}
}
}
static int mISDN_upqueue(struct lcr_fd *fd, unsigned int what, void *instance, int i)
{
int ret, work = 0;
struct mISDNport *mISDNport;
class PmISDN *isdnport;
int i;
unsigned char buffer[2048+MISDN_HEADER_LEN];
struct mISDNhead *hh = (struct mISDNhead *)buffer;
struct mbuffer *mb;
struct l3_msg *l3m;
char byte;
/* unset global semaphore */
read(fd->fd, &byte, 1);
upqueue_avail = 0;
/* process all ports */
mISDNport = mISDNport_first;
while(mISDNport) {
/* process all bchannels */
i = 0;
while(i < mISDNport->b_num) {
/* process timer events for bchannel handling */
if (mISDNport->b_timer[i]) {
if (mISDNport->b_timer[i] <= now_d)
bchannel_event(mISDNport, i, B_EVENT_TIMEOUT);
}
/* handle port of bchannel */
isdnport=mISDNport->b_port[i];
if (isdnport) {
/* call bridges in user space OR crypto OR recording */
if (isdnport->p_m_joindata || isdnport->p_m_crypt_msg_loops || isdnport->p_m_crypt_listen || isdnport->p_record || isdnport->p_m_inband_receive_on) {
/* rx IS required */
if (isdnport->p_m_rxoff) {
/* turn on RX */
isdnport->p_m_rxoff = 0;
PDEBUG(DEBUG_BCHANNEL, "%s: receive data is required, so we turn them on\n", __FUNCTION__);
if (mISDNport->b_port[i] && mISDNport->b_state[i] == B_STATE_ACTIVE)
ph_control(mISDNport, isdnport, mISDNport->b_socket[i], DSP_RECEIVE_ON, 0, "DSP-RXOFF", 0);
return(1);
}
} else {
/* rx NOT required */
if (!isdnport->p_m_rxoff) {
/* turn off RX */
isdnport->p_m_rxoff = 1;
PDEBUG(DEBUG_BCHANNEL, "%s: receive data is not required, so we turn them off\n", __FUNCTION__);
if (mISDNport->b_port[i] && mISDNport->b_state[i] == B_STATE_ACTIVE)
ph_control(mISDNport, isdnport, mISDNport->b_socket[i], DSP_RECEIVE_OFF, 0, "DSP-RXOFF", 1);
return(1);
}
}
/* recording */
if (isdnport->p_record) {
/* txdata IS required */
if (!isdnport->p_m_txdata) {
/* turn on RX */
isdnport->p_m_txdata = 1;
PDEBUG(DEBUG_BCHANNEL, "%s: transmit data is required, so we turn them on\n", __FUNCTION__);
if (mISDNport->b_port[i] && mISDNport->b_state[i] == B_STATE_ACTIVE)
ph_control(mISDNport, isdnport, mISDNport->b_socket[i], DSP_TXDATA_ON, 0, "DSP-TXDATA", 1);
return(1);
}
} else {
/* txdata NOT required */
if (isdnport->p_m_txdata) {
/* turn off RX */
isdnport->p_m_txdata = 0;
PDEBUG(DEBUG_BCHANNEL, "%s: transmit data is not required, so we turn them off\n", __FUNCTION__);
if (mISDNport->b_port[i] && mISDNport->b_state[i] == B_STATE_ACTIVE)
ph_control(mISDNport, isdnport, mISDNport->b_socket[i], DSP_TXDATA_OFF, 0, "DSP-TXDATA", 0);
return(1);
}
}
}
/* handle message from bchannel */
if (mISDNport->b_socket[i] > -1) {
ret = recv(mISDNport->b_socket[i], buffer, sizeof(buffer), 0);
if (ret >= (int)MISDN_HEADER_LEN) {
work = 1;
switch(hh->prim) {
/* we don't care about confirms, we use rx data to sync tx */
case PH_DATA_CNF:
break;
/* we receive audio data, we respond to it AND we send tones */
case PH_DATA_IND:
case DL_DATA_IND:
case PH_DATA_REQ:
case DL_DATA_REQ:
case PH_CONTROL_IND:
if (mISDNport->b_port[i])
mISDNport->b_port[i]->bchannel_receive(hh, buffer+MISDN_HEADER_LEN, ret-MISDN_HEADER_LEN);
else
PDEBUG(DEBUG_BCHANNEL, "b-channel is not associated to an ISDNPort (socket %d), ignoring.\n", mISDNport->b_socket[i]);
break;
case PH_ACTIVATE_IND:
case DL_ESTABLISH_IND:
case PH_ACTIVATE_CNF:
case DL_ESTABLISH_CNF:
PDEBUG(DEBUG_BCHANNEL, "DL_ESTABLISH confirm: bchannel is now activated (socket %d).\n", mISDNport->b_socket[i]);
bchannel_event(mISDNport, i, B_EVENT_ACTIVATED);
break;
case PH_DEACTIVATE_IND:
case DL_RELEASE_IND:
case PH_DEACTIVATE_CNF:
case DL_RELEASE_CNF:
PDEBUG(DEBUG_BCHANNEL, "DL_RELEASE confirm: bchannel is now de-activated (socket %d).\n", mISDNport->b_socket[i]);
bchannel_event(mISDNport, i, B_EVENT_DEACTIVATED);
break;
default:
PERROR("child message not handled: prim(0x%x) socket(%d) msg->len(%d)\n", hh->prim, mISDNport->b_socket[i], ret-MISDN_HEADER_LEN);
}
} else {
if (ret < 0 && errno != EWOULDBLOCK)
PERROR("Read from port %d, index %d failed with return code %d\n", mISDNport->portnum, i, ret);
}
}
i++;
}
/* handle queued up-messages (d-channel) */
if (!mISDNport->gsm) {
while ((mb = mdequeue(&mISDNport->upqueue))) {
@ -1916,8 +1899,8 @@ int mISDN_handler(void)
if (l3m->pid < 128)
mISDNport->l2mask[l3m->pid >> 3] |= (1 << (l3m->pid & 7));
if ((!mISDNport->ntmode || mISDNport->ptp) && l3m->pid < 127) {
if (mISDNport->l2establish) {
mISDNport->l2establish = 0;
if (mISDNport->l2establish.active) {
unsched_timer(&mISDNport->l2establish);
PDEBUG(DEBUG_ISDN, "the link became active before l2establish timer expiry.\n");
}
}
@ -1926,7 +1909,7 @@ int mISDN_handler(void)
case MT_L2RELEASE:
if (l3m->pid < 128)
mISDNport->l2mask[l3m->pid >> 3] &= ~(1 << (l3m->pid & 7));
if (!mISDNport->l2establish) {
if (!mISDNport->l2establish.active) {
l1l2l3_trace_header(mISDNport, NULL, L2_RELEASE_IND, DIRECTION_IN);
add_trace("tei", NULL, "%d", l3m->pid);
end_trace();
@ -1935,9 +1918,9 @@ int mISDN_handler(void)
mISDNport->l2link = 0;
}
if (!mISDNport->gsm && (!mISDNport->ntmode || mISDNport->ptp) && l3m->pid < 127) {
if (!mISDNport->l2establish && mISDNport->l2hold) {
if (!mISDNport->l2establish.active && mISDNport->l2hold) {
PDEBUG(DEBUG_ISDN, "set timer and establish.\n");
time(&mISDNport->l2establish);
schedule_timer(&mISDNport->l2establish, 5, 0);
mISDNport->ml3->to_layer3(mISDNport->ml3, MT_L2ESTABLISH, 0, NULL);
}
}
@ -1951,36 +1934,94 @@ int mISDN_handler(void)
free_l3_msg(l3m);
}
}
#if 0
if (mISDNport->l1timeout && now>mISDNport->l1timeout)
{ ---}
PDEBUG(DEBUG_ISDN, "the L1 establish timer expired, we release all pending messages.\n", mISDNport->portnum);
mISDNport->l1timeout = 0;
#endif
/* layer 2 establish timer */
if (mISDNport->l2establish) {
if (now-mISDNport->l2establish > 5) {
mISDNport->l2establish = 0;
if (!mISDNport->gsm && mISDNport->l2hold && (mISDNport->ptp || !mISDNport->ntmode)) {
// PDEBUG(DEBUG_ISDN, "the L2 establish timer expired, we try to establish the link portnum=%d.\n", mISDNport->portnum);
mISDNport->ml3->to_layer3(mISDNport->ml3, MT_L2ESTABLISH, 0, NULL);
time(&mISDNport->l2establish);
return(1);
}
}
}
mISDNport = mISDNport->next;
}
/* if we received at least one b-frame, we will return 1 */
return(work);
return 0;
}
/* l2 establish timer fires */
static int l2establish_timeout(struct lcr_timer *timer, void *instance, int i)
{
struct mISDNport *mISDNport = (struct mISDNport *)instance;
if (!mISDNport->gsm && mISDNport->l2hold && (mISDNport->ptp || !mISDNport->ntmode)) {
// PDEBUG(DEBUG_ISDN, "the L2 establish timer expired, we try to establish the link portnum=%d.\n", mISDNport->portnum);
mISDNport->ml3->to_layer3(mISDNport->ml3, MT_L2ESTABLISH, 0, NULL);
schedule_timer(&mISDNport->l2establish, 5, 0); /* 5 seconds */
}
return 0;
}
/* handle frames from bchannel */
static int b_sock_callback(struct lcr_fd *fd, unsigned int what, void *instance, int i)
{
struct mISDNport *mISDNport = (struct mISDNport *)instance;
unsigned char buffer[2048+MISDN_HEADER_LEN];
struct mISDNhead *hh = (struct mISDNhead *)buffer;
int ret;
ret = recv(fd->fd, buffer, sizeof(buffer), 0);
if (ret < 0) {
PERROR("read error frame, errno %d\n", errno);
return 0;
}
if (ret < (int)MISDN_HEADER_LEN) {
PERROR("read short frame, got %d, expected %d\n", ret, (int)MISDN_HEADER_LEN);
return 0;
}
switch(hh->prim) {
/* we don't care about confirms, we use rx data to sync tx */
case PH_DATA_CNF:
break;
/* we receive audio data, we respond to it AND we send tones */
case PH_DATA_IND:
case DL_DATA_IND:
case PH_DATA_REQ:
case DL_DATA_REQ:
case PH_CONTROL_IND:
if (mISDNport->b_port[i])
mISDNport->b_port[i]->bchannel_receive(hh, buffer+MISDN_HEADER_LEN, ret-MISDN_HEADER_LEN);
else
PDEBUG(DEBUG_BCHANNEL, "b-channel is not associated to an ISDNPort (socket %d), ignoring.\n", fd->fd);
break;
case PH_ACTIVATE_IND:
case DL_ESTABLISH_IND:
case PH_ACTIVATE_CNF:
case DL_ESTABLISH_CNF:
PDEBUG(DEBUG_BCHANNEL, "DL_ESTABLISH confirm: bchannel is now activated (socket %d).\n", fd->fd);
bchannel_event(mISDNport, i, B_EVENT_ACTIVATED);
break;
case PH_DEACTIVATE_IND:
case DL_RELEASE_IND:
case PH_DEACTIVATE_CNF:
case DL_RELEASE_CNF:
PDEBUG(DEBUG_BCHANNEL, "DL_RELEASE confirm: bchannel is now de-activated (socket %d).\n", fd->fd);
bchannel_event(mISDNport, i, B_EVENT_DEACTIVATED);
break;
default:
PERROR("child message not handled: prim(0x%x) socket(%d) msg->len(%d)\n", hh->prim, fd->fd, ret-MISDN_HEADER_LEN);
}
return 0;
}
/* process timer events for bchannel handling */
static int b_timer_timeout(struct lcr_timer *timer, void *instance, int i)
{
struct mISDNport *mISDNport = (struct mISDNport *)instance;
puts("fires");
bchannel_event(mISDNport, i, B_EVENT_TIMEOUT);
return 0;
}
int do_layer3(struct mlayer3 *ml3, unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
{
/* IMPORTAINT:
@ -2018,6 +2059,11 @@ int do_layer3(struct mlayer3 *ml3, unsigned int cmd, unsigned int pid, struct l3
l3m->type = cmd;
l3m->pid = pid;
mqueue_tail(&mISDNport->upqueue, mb);
if (!upqueue_avail) {
upqueue_avail = 1;
char byte = 0;
write(upqueue_pipe[1], &byte, 1);
}
return 0;
}
@ -2193,6 +2239,7 @@ struct mISDNport *mISDNport_open(struct interface_port *ifport)
while(*mISDNportp)
mISDNportp = &((*mISDNportp)->next);
mISDNport = (struct mISDNport *)MALLOC(sizeof(struct mISDNport));
add_timer(&mISDNport->l2establish, l2establish_timeout, mISDNport, 0);
if (gsm | ss5) {
/* gsm/ss5 link is always active */
mISDNport->l1link = 1;
@ -2309,7 +2356,7 @@ struct mISDNport *mISDNport_open(struct interface_port *ifport)
i = 0;
while(i < mISDNport->b_num) {
mISDNport->b_state[i] = B_STATE_IDLE;
mISDNport->b_socket[i] = -1;
add_timer(&mISDNport->b_timer[i], b_timer_timeout, mISDNport, i);
i++;
}
@ -2319,7 +2366,7 @@ struct mISDNport *mISDNport_open(struct interface_port *ifport)
l1l2l3_trace_header(mISDNport, NULL, L2_ESTABLISH_REQ, DIRECTION_OUT);
add_trace("tei", NULL, "%d", 0);
end_trace();
time(&mISDNport->l2establish);
schedule_timer(&mISDNport->l2establish, 5, 0); /* 5 seconds */
}
/* for nt-mode ptmp the link is always up */
@ -2415,12 +2462,16 @@ void mISDNport_close(struct mISDNport *mISDNport)
/* free bchannels */
i = 0;
while(i < mISDNport->b_num) {
if (mISDNport->b_socket[i] > -1) {
if (mISDNport->b_sock[i].inuse) {
_bchannel_destroy(mISDNport, i);
PDEBUG(DEBUG_BCHANNEL, "freeing %s port %d bchannel (index %d).\n", (mISDNport->ntmode)?"NT":"TE", mISDNport->portnum, i);
}
if (mISDNport->b_timer[i].inuse) {
del_timer(&mISDNport->b_timer[i]);
}
i++;
}
del_timer(&mISDNport->l2establish);
/* close layer 3, if open */
if (!mISDNport->gsm && mISDNport->ml3) {
@ -2480,14 +2531,15 @@ void PmISDN::txfromup(unsigned char *data, int length)
* if transmit buffer in DSP module is empty,
* preload it to DSP_LOAD to prevent jitter gaps.
*/
if (p_m_load==0 && ISDN_LOAD>0) {
if (p_m_load == 0 && ISDN_LOAD > 0) {
hh->prim = PH_DATA_REQ;
hh->id = 0;
memset(buf+MISDN_HEADER_LEN, (options.law=='a')?0x2a:0xff, ISDN_LOAD);
ret = sendto(p_m_mISDNport->b_socket[p_m_b_index], buf, MISDN_HEADER_LEN+ISDN_LOAD, 0, NULL, 0);
ret = sendto(p_m_mISDNport->b_sock[p_m_b_index].fd, buf, MISDN_HEADER_LEN+ISDN_LOAD, 0, NULL, 0);
if (ret <= 0)
PERROR("Failed to send to socket %d\n", p_m_mISDNport->b_socket[p_m_b_index]);
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);
}
/* drop if load would exceed ISDN_MAXLOAD
@ -2500,9 +2552,9 @@ void PmISDN::txfromup(unsigned char *data, int length)
hh->prim = PH_DATA_REQ;
hh->id = 0;
memcpy(buf+MISDN_HEADER_LEN, data, length);
ret = sendto(p_m_mISDNport->b_socket[p_m_b_index], buf, MISDN_HEADER_LEN+length, 0, NULL, 0);
ret = sendto(p_m_mISDNport->b_sock[p_m_b_index].fd, buf, MISDN_HEADER_LEN+length, 0, NULL, 0);
if (ret <= 0)
PERROR("Failed to send to socket %d\n", p_m_mISDNport->b_socket[p_m_b_index]);
PERROR("Failed to send to socket %d\n", p_m_mISDNport->b_sock[p_m_b_index].fd);
p_m_load += length;
}
@ -2516,6 +2568,8 @@ void PmISDN::inband_send_on(void)
{
PDEBUG(DEBUG_PORT, "turning inband signalling send on.\n");
p_m_inband_send_on = 1;
/* trigger inband transmit */
update_load();
}
void PmISDN::inband_send_off(void)
@ -2537,12 +2591,14 @@ void PmISDN::inband_receive_on(void)
/* this must work during constructor, see ss5.cpp */
PDEBUG(DEBUG_PORT, "turning inband signalling receive on.\n");
p_m_inband_receive_on = 1;
update_rxoff();
}
void PmISDN::inband_receive_off(void)
{
PDEBUG(DEBUG_PORT, "turning inband signalling receive off.\n");
p_m_inband_receive_on = 0;
update_rxoff();
}
void PmISDN::mute_on(void)

18
mISDN.h
View File

@ -44,7 +44,7 @@ struct mISDNport {
unsigned char l2mask[16]; /* 128 bits for each tei */
int l1hold; /* set, if layer 1 should be holt */
int l2hold; /* set, if layer 2 must be hold/checked */
time_t l2establish; /* time until establishing after link failure */
struct lcr_timer l2establish; /* time until establishing after link failure */
int use; /* counts the number of port that uses this port */
int ntmode; /* is TRUE if port is NT mode */
int tespecial; /* is TRUE if port uses special TE mode */
@ -55,10 +55,10 @@ struct mISDNport {
int b_reserved; /* number of bchannels reserved or in use */
class PmISDN *b_port[128]; /* bchannel assigned to port object */
struct mqueue upqueue;
int b_socket[128];
struct lcr_fd b_sock[128]; /* socket list elements */
int b_mode[128]; /* B_MODE_* */
int b_state[128]; /* statemachine, 0 = IDLE */
double b_timer[128]; /* timer for state machine */
struct lcr_timer b_timer[128]; /* timer for bchannel state machine */
int b_remote_id[128]; /* the socket currently exported (0=none) */
unsigned int b_remote_ref[128]; /* the ref currently exported */
int locally; /* local causes are sent as local causes not remote */
@ -97,7 +97,6 @@ void mISDNport_static(struct mISDNport *mISDNport);
void mISDNport_close_all(void);
void mISDNport_close(struct mISDNport *mISDNport);
void mISDN_port_reorder(void);
int mISDN_handler(void);
void enc_ie_cause_standalone(struct l3_msg *l3m, int location, int cause);
int stack2manager(struct mISDNport *mISDNport, unsigned int cmd, unsigned int pid, struct l3_msg *l3m);
void ph_control(struct mISDNport *mISDNport, class PmISDN *isdnport, unsigned int handle, unsigned int c1, unsigned int c2, const char *trace_name, int trace_value);
@ -115,7 +114,6 @@ class PmISDN : public Port
PmISDN(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel, int exclusive, int mode);
~PmISDN();
void bchannel_receive(struct mISDNhead *hh, unsigned char *data, int len);
int handler(void);
void transmit(unsigned char *buffer, int length);
int message_epoint(unsigned int epoint_id, int message, union parameter *param);
void message_mISDNsignal(unsigned int epoint_id, int message_id, union parameter *param);
@ -133,8 +131,11 @@ class PmISDN : public Port
int p_m_dtmf; /* dtmf decoding is enabled */
int p_m_joindata; /* the call requires data due to no briging capability */
struct lcr_timer p_m_loadtimer; /* timer for audio transmission */
virtual void update_load(void);
void load_tx(void);
int p_m_load; /* current data in dsp tx buffer */
unsigned int p_m_last_tv_sec; /* time stamp of last handler call, (to sync audio data */
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;
@ -167,10 +168,8 @@ class PmISDN : public Port
// 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_delete; /* true if obj. must del. */
int p_m_hold; /* if port is on hold */
unsigned int p_m_timeout; /* timeout of timers */
time_t p_m_timer; /* start of timer */
struct lcr_timer p_m_timeout; /* timeout of timers */
unsigned int p_m_remote_ref; /* join to export bchannel to */
int p_m_remote_id; /* sock to export bchannel to */
@ -185,6 +184,7 @@ class PmISDN : public Port
void inband_receive_off(void);
void mute_on(void);
void mute_off(void);
void update_rxoff(void);
int seize_bchannel(int channel, int exclusive); /* requests / reserves / links bchannels, but does not open it! */
void drop_bchannel(void);

View File

@ -77,8 +77,8 @@ static inline void fatal(const char *function, int line, const char *fmt, ...)
fprintf(stderr, "FATAL ERROR in function %s, line %d: %s", function, line, buffer);
fprintf(stderr, "This error is not recoverable, must exit here.\n");
#ifdef DEBUG_FUNC
debug(function, line, "FATAL ERROR", buffer);
debug(function, line, "FATAL ERROR", (char *)"This error is not recoverable, must exit here.\n");
debug(function, line, "FATAL", buffer);
debug(function, line, "FATAL", (char *)"This error is not recoverable, must exit here.\n");
#endif
exit(EXIT_FAILURE);
}

257
main.c
View File

@ -11,19 +11,14 @@
#include "main.h"
MESSAGES
//MESSAGES
double now_d, last_d;
time_t now;
struct tm *now_tm;
struct timeval now_tv;
struct timezone now_tz;
#define GET_NOW() \
{ \
gettimeofday(&now_tv, &now_tz); \
now_d = ((double)(now_tv.tv_usec))/1000000 + now_tv.tv_sec; \
now = now_tv.tv_sec; \
now_tm = localtime(&now); \
}
FILE *debug_fp = NULL;
@ -49,22 +44,21 @@ int classuse = 0;
int fduse = 0;
int fhuse = 0;
const char *debug_prefix = NULL;
int debug_count = 0;
int last_debug = 0;
int debug_newline = 1;
int nooutput = 0;
void debug_usleep(int msec, const char *file, int line, int hour, int min, int sec)
{
usleep(msec);
}
void debug(const char *function, int line, const char *prefix, char *buffer)
{
time_t now;
struct tm *now_tm;
/* if we have a new debug count, we add a mark */
if (last_debug != debug_count) {
last_debug = debug_count;
time(&now);
now_tm = localtime(&now);
if (!nooutput)
printf("\033[34m--------------------- %04d.%02d.%02d %02d:%02d:%02d %06d\033[36m\n", now_tm->tm_year+1900, now_tm->tm_mon+1, now_tm->tm_mday, now_tm->tm_hour, now_tm->tm_min, now_tm->tm_sec, debug_count%1000000);
if (debug_fp)
@ -110,7 +104,7 @@ void _printdebug(const char *function, int line, unsigned int mask, const char *
buffer[sizeof(buffer)-1]=0;
va_end(args);
debug(function, line, debug_prefix, buffer);
debug(function, line, "DEBUG", buffer);
pthread_mutex_unlock(&mutexd);
}
@ -167,21 +161,18 @@ void sighandler(int sigset)
*/
int main(int argc, char *argv[])
{
#ifdef WITH_GSM
double now_d, last_d;
int all_idle;
#endif
int ret = -1;
int lockfd = -1; /* file lock */
struct lcr_msg *message;
class Port *port;
class Endpoint *epoint;
class Join *join;
int i;
int all_idle;
char prefix_string[64];
struct sched_param schedp;
const char *debug_prefix = "alloc";
int created_mutexd = 0,/* created_mutext = 0,*/ created_mutexe = 0,
created_lock = 0, created_signal = 0, created_debug = 0,
created_misdn = 0;
int idletime = 0, idlecheck = 0;
char tracetext[256], lock[128];
#if 0
@ -192,9 +183,6 @@ int main(int argc, char *argv[])
/* lock LCR process */
// pthread_mutex_lock(&mutex_lcr);
/* current time */
GET_NOW();
/* show version */
printf("\n** %s Version %s\n\n", NAME, VERSION_STRING);
@ -437,15 +425,20 @@ int main(int argc, char *argv[])
signal(SIGPIPE,sighandler);
created_signal = 1;
/* init message */
init_message();
/*** main loop ***/
SPRINT(tracetext, "%s %s started, waiting for calls...", NAME, VERSION_STRING);
start_trace(-1, NULL, NULL, NULL, 0, 0, 0, tracetext);
printf("%s\n", tracetext);
end_trace();
GET_NOW();
quit = 0;
#ifdef WITH_GSM
GET_NOW();
#endif
while(!quit) {
#ifdef WITH_GSM
last_d = now_d;
GET_NOW();
if (now_d-last_d > 1.0) {
@ -454,165 +447,19 @@ int main(int argc, char *argv[])
/* all loops must be counted from the beginning since nodes might get freed during handler */
all_idle = 1;
//#warning debugging usleep crash
// debug_usleep(1, __FILE__, __LINE__, now_tm->tm_hour, now_tm->tm_min, now_tm->tm_sec);
/* handle mISDN messages from kernel */
debug_prefix = "ISDN";
if (mISDN_handler())
/* must be processed after all queues, so they are empty */
if (select_main(1, NULL, NULL, NULL))
all_idle = 0;
//#warning debugging usleep crash
// debug_usleep(1, __FILE__, __LINE__, now_tm->tm_hour, now_tm->tm_min, now_tm->tm_sec);
BUDETECT
/* loop through all port ports and call their handler */
port_again:
port = port_first;
while(port) {
debug_prefix = port->p_name;
debug_count++;
ret = port->handler();
if (ret)
all_idle = 0;
if (ret < 0) /* port has been destroyed */
goto port_again;
port = port->next;
}
/* loop through all epoint and call their handler */
epoint_again:
epoint = epoint_first;
while(epoint) {
debug_prefix = prefix_string;
SPRINT(prefix_string, "ep%ld", epoint->ep_serial);
debug_count++;
ret = epoint->handler();
if (ret)
all_idle = 0;
if (ret < 0) /* epoint has been destroyed */
goto epoint_again;
epoint = epoint->next;
}
/* loop through all joins and call their handler */
join_again:
join = join_first;
while(join) {
debug_prefix = "join";
debug_count++;
ret = join->handler();
if (ret)
all_idle = 0;
if (ret < 0) /* join has been destroyed */
goto join_again;
join = join->next;
}
debug_prefix = 0;
/* process any message */
debug_count++;
debug_prefix = "message";
while ((message = message_get())) {
all_idle = 0;
switch(message->flow) {
case PORT_TO_EPOINT:
debug_prefix = "msg port->epoint";
epoint = find_epoint_id(message->id_to);
if (epoint) {
if (epoint->ep_app) {
epoint->ep_app->ea_message_port(message->id_from, message->type, &message->param);
} else {
PDEBUG(DEBUG_MSG, "Warning: message %s from port %d to endpoint %d. endpoint doesn't have an application.\n", messages_txt[message->type], message->id_from, message->id_to);
}
} else {
PDEBUG(DEBUG_MSG, "Warning: message %s from port %d to endpoint %d. endpoint doesn't exist anymore.\n", messages_txt[message->type], message->id_from, message->id_to);
}
break;
case EPOINT_TO_JOIN:
debug_prefix = "msg epoint->join";
join = find_join_id(message->id_to);
if (join) {
join->message_epoint(message->id_from, message->type, &message->param);
} else {
PDEBUG(DEBUG_MSG, "Warning: message %s from endpoint %d to join %d. join doesn't exist anymore\n", messages_txt[message->type], message->id_from, message->id_to);
}
break;
case JOIN_TO_EPOINT:
debug_prefix = "msg join->epoint";
epoint = find_epoint_id(message->id_to);
if (epoint) {
if (epoint->ep_app) {
epoint->ep_app->ea_message_join(message->id_from, message->type, &message->param);
} else {
PDEBUG(DEBUG_MSG, "Warning: message %s from join %d to endpoint %d. endpoint doesn't have an application.\n", messages_txt[message->type], message->id_from, message->id_to);
}
} else {
PDEBUG(DEBUG_MSG, "Warning: message %s from join %d to endpoint %d. endpoint doesn't exist anymore.\n", messages_txt[message->type], message->id_from, message->id_to);
}
break;
case EPOINT_TO_PORT:
debug_prefix = "msg epoint->port";
port = find_port_id(message->id_to);
if (port) {
port->message_epoint(message->id_from, message->type, &message->param);
BUDETECT
} else {
PDEBUG(DEBUG_MSG, "Warning: message %s from endpoint %d to port %d. port doesn't exist anymore\n", messages_txt[message->type], message->id_from, message->id_to);
}
break;
default:
PERROR("Message flow %d unknown.\n", message->flow);
}
message_free(message);
debug_count++;
debug_prefix = "message";
}
BUDETECT
/* handle socket */
if (admin_handle())
all_idle = 0;
BUDETECT
#ifdef WITH_GSM
/* handle gsm */
if (options.gsm)
while(handle_gsm())
all_idle = 0;
#endif
BUDETECT
#if 0
/* check for child to exit (eliminate zombies) */
if (waitpid(-1, NULL, WNOHANG) > 0) {
PDEBUG(DEBUG_EPOINT, "a child process (created by endpoint) has exitted.\n");
all_idle = 0;
}
#endif
//#warning debugging usleep crash
// debug_usleep(1, __FILE__, __LINE__, now_tm->tm_hour, now_tm->tm_min, now_tm->tm_sec);
/* do idle checking */
if (idlecheck != now) {
PDEBUG(DEBUG_IDLETIME, "Idle time : %d%%\n", idletime/10000);
idletime = 0;
idlecheck = now;
}
/* did we do nothing? so we wait to give time to other processes */
if (all_idle) {
// pthread_mutex_unlock(&mutex_lcr); // unlock LCR
debug_usleep(4000, __FILE__, __LINE__, now_tm->tm_hour, now_tm->tm_min, now_tm->tm_sec);
// pthread_mutex_lock(&mutex_lcr); // lock LCR
idletime += 4000;
usleep(10000);
}
#else
select_main(0, NULL, NULL, NULL);
#endif
}
SPRINT(tracetext, "%s terminated", NAME);
printf("%s\n", tracetext);
@ -622,10 +469,12 @@ BUDETECT
end_trace();
ret=0;
/* clean messacleane */
cleanup_message();
/* free all */
free:
/* set scheduler & priority
*/
if (options.schedule > 1) {
@ -642,7 +491,6 @@ free:
}
/* destroy objects */
debug_prefix = "free";
while(port_first) {
debug_count++;
@ -748,55 +596,4 @@ free:
}
#ifdef BUDETECT_DEF
/* special debug function to detect buffer overflow
*/
int budetect_stop = 0;
void budetect(const char *file, int line, const char *function)
{
if (budetect_stop)
return;
/* modify this function to detect race-bugs */
#warning DID YOU MODIFY THIS FUNCTION TO DETECT THE BUFFER OVERFLOW BUG?
class Port *port;
class PmISDN *pmisdn;
struct mISDNport *mISDNport = mISDNport_first;
int i, ii;
while(mISDNport) {
i = 0;
ii = mISDNport->b_num;
while(i < ii) {
if (mISDNport->b_port[i]) {
port = port_first;
while(port) {
if ((port->p_type&PORT_CLASS_MASK) == PORT_CLASS_ISDN) {
pmisdn = (class PmISDN *)port;
if (pmisdn->p_isdn_crypt_listen) {
PERROR_RUNTIME("************************************************\n");
PERROR_RUNTIME("** BUG detected in %s, line %d, function %s\n", file, line, function);
PERROR_RUNTIME("** p_isdn_crypt_listen = %d\n", pmisdn->p_isdn_crypt_listen);
PERROR_RUNTIME("************************************************\n");
budetect_stop = 1;
}
}
if (port == mISDNport->b_port[i])
break;
port = port->next;
if (!port) {
PERROR_RUNTIME("************************************************\n");
PERROR_RUNTIME("** BUG detected in %s, line %d, function %s\n", file, line, function);
PERROR_RUNTIME("** b_port not in list.\n");
PERROR_RUNTIME("************************************************\n");
budetect_stop = 1;
}
}
}
i++;
}
mISDNport = mISDNport->next;
}
}
#endif

6
main.h
View File

@ -136,6 +136,7 @@ extern "C" {
}
#endif
#include "macro.h"
#include "select.h"
#include "options.h"
#include "interface.h"
#include "extension.h"
@ -168,11 +169,6 @@ extern "C" {
#include "trace.h"
extern int quit;
extern double now_d;
extern time_t now;
extern struct tm *now_tm;
extern struct timeval now_tv;
extern struct timezone now_tz;
#define DIRECTION_NONE 0
#define DIRECTION_OUT 1

View File

@ -15,6 +15,20 @@ MESSAGES
struct lcr_msg *message_first = NULL;
struct lcr_msg **messagepointer_end = &message_first;
struct lcr_work message_work;
static int work_message(struct lcr_work *work, void *instance, int index);
void init_message(void)
{
memset(&message_work, 0, sizeof(message_work));
add_work(&message_work, work_message, NULL, 0);
}
void cleanup_message(void)
{
del_work(&message_work);
}
/* creates a new message with the given attributes. the message must be filled then. after filling, the message_put must be called */
struct lcr_msg *message_create(int id_from, int id_to, int flow, int type)
@ -50,6 +64,9 @@ void message_put(struct lcr_msg *message)
messagepointer_end = &(message->next);
/* Nullify next pointer if recycled messages */
*messagepointer_end=NULL;
/* trigger work */
trigger_work(&message_work);
}
struct lcr_msg *message_forward(int id_from, int id_to, int flow, union parameter *param)
@ -102,3 +119,66 @@ void message_free(struct lcr_msg *message)
}
static int work_message(struct lcr_work *work, void *instance, int index)
{
struct lcr_msg *message;
class Port *port;
class Endpoint *epoint;
class Join *join;
while ((message = message_get())) {
switch(message->flow) {
case PORT_TO_EPOINT:
epoint = find_epoint_id(message->id_to);
if (epoint) {
if (epoint->ep_app) {
epoint->ep_app->ea_message_port(message->id_from, message->type, &message->param);
} else {
PDEBUG(DEBUG_MSG, "Warning: message %s from port %d to endpoint %d. endpoint doesn't have an application.\n", messages_txt[message->type], message->id_from, message->id_to);
}
} else {
PDEBUG(DEBUG_MSG, "Warning: message %s from port %d to endpoint %d. endpoint doesn't exist anymore.\n", messages_txt[message->type], message->id_from, message->id_to);
}
break;
case EPOINT_TO_JOIN:
join = find_join_id(message->id_to);
if (join) {
join->message_epoint(message->id_from, message->type, &message->param);
} else {
PDEBUG(DEBUG_MSG, "Warning: message %s from endpoint %d to join %d. join doesn't exist anymore\n", messages_txt[message->type], message->id_from, message->id_to);
}
break;
case JOIN_TO_EPOINT:
epoint = find_epoint_id(message->id_to);
if (epoint) {
if (epoint->ep_app) {
epoint->ep_app->ea_message_join(message->id_from, message->type, &message->param);
} else {
PDEBUG(DEBUG_MSG, "Warning: message %s from join %d to endpoint %d. endpoint doesn't have an application.\n", messages_txt[message->type], message->id_from, message->id_to);
}
} else {
PDEBUG(DEBUG_MSG, "Warning: message %s from join %d to endpoint %d. endpoint doesn't exist anymore.\n", messages_txt[message->type], message->id_from, message->id_to);
}
break;
case EPOINT_TO_PORT:
port = find_port_id(message->id_to);
if (port) {
port->message_epoint(message->id_from, message->type, &message->param);
BUDETECT
} else {
PDEBUG(DEBUG_MSG, "Warning: message %s from endpoint %d to port %d. port doesn't exist anymore\n", messages_txt[message->type], message->id_from, message->id_to);
}
break;
default:
PERROR("Message flow %d unknown.\n", message->flow);
}
message_free(message);
}
return 0;
}

View File

@ -9,8 +9,6 @@
** **
\*****************************************************************************/
#define ISDN_TRANSMIT 256 // samples
enum { /* interface types */
INFO_ITYPE_ISDN, /* call from external */
INFO_ITYPE_ISDN_EXTENSION, /* call from internal extension */
@ -271,10 +269,11 @@ struct park_info {
int len;
};
#define ISDN_TRANSMIT 256
/* DATA */
struct param_data {
unsigned char data[ISDN_TRANSMIT]; /* audio/hdlc data */
int len; /* audio/hdlc data */
unsigned char data[ISDN_TRANSMIT]; /* audio data */
int len; /* audio data */
};
struct param_play {
@ -444,6 +443,7 @@ void message_put(struct lcr_msg *message);
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);
void init_message(void);
void cleanup_message(void);

View File

@ -9,11 +9,11 @@
** **
\*****************************************************************************/
#include "stdio.h"
#include "string.h"
#include "stdarg.h"
#include "unistd.h"
#include "stdlib.h"
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include <stdlib.h>
#include "macro.h"
#include "extension.h"
#include "options.h"

View File

@ -316,6 +316,8 @@ void Port::set_tone(const char *dir, const char *name)
SCPY(p_tone_dir, dir);
SCPY(p_tone_name, name);
}
/* trigger playback */
update_load();
} else {
p_tone_name[0]= '\0';
p_tone_dir[0]= '\0';
@ -382,6 +384,8 @@ void Port::set_vbox_tone(const char *dir, const char *name)
SPRINT(p_tone_dir, dir);
SPRINT(p_tone_name, name);
/* trigger playback */
update_load();
/* now we check if the cause exists, otherwhise we use error tone. */
if (p_tone_dir[0]) {
@ -585,13 +589,6 @@ try_loop:
}
/* port handler:
* process transmission clock */
int Port::handler(void)
{
return(0);
}
/* 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
@ -648,6 +645,8 @@ int Port::open_record(int type, int vbox, int skip, char *extension, int anon_ig
/* RIFFxxxxWAVEfmt xxxx(fmt-size)dataxxxx... */
char dummyheader[8+4+8+sizeof(fmt)+8];
char filename[256];
time_t now;
struct tm *now_tm;
if (!extension) {
PERROR("Port(%d) not an extension\n", p_serial);
@ -676,8 +675,11 @@ int Port::open_record(int type, int vbox, int skip, char *extension, int anon_ig
if (vbox == 1)
UPRINT(strchr(filename,'\0'), "/announcement");
else
else {
time(&now);
now_tm = localtime(&now);
UPRINT(strchr(filename,'\0'), "/%04d-%02d-%02d_%02d%02d%02d", now_tm->tm_year+1900, now_tm->tm_mon+1, now_tm->tm_mday, now_tm->tm_hour, now_tm->tm_min, now_tm->tm_sec);
}
if (vbox == 2) {
p_record_vbox_year = now_tm->tm_year;
p_record_vbox_mon = now_tm->tm_mon;
@ -698,6 +700,7 @@ int Port::open_record(int type, int vbox, int skip, char *extension, int anon_ig
PERROR("Port(%d) cannot record because file cannot be opened '%s'\n", p_serial, filename);
return(0);
}
update_rxoff();
fduse++;
p_record_type = type;
@ -882,6 +885,7 @@ void Port::close_record(int beep, int mute)
fclose(p_record);
fduse--;
p_record = NULL;
update_rxoff();
if (rename(p_record_filename, filename) < 0) {
PERROR("Port(%d) cannot rename from '%s' to '%s'\n", p_serial, p_record_filename, filename);
@ -1139,4 +1143,11 @@ different_again:
}
void Port::update_rxoff(void)
{
}
void Port::update_load(void)
{
}

3
port.h
View File

@ -137,11 +137,11 @@ class Port
virtual ~Port();
class Port *next; /* next port in list */
int p_type; /* type of port */
virtual int handler(void);
virtual int message_epoint(unsigned int epoint_id, int message, union parameter *param);
virtual void set_echotest(int echotest);
virtual void set_tone(const char *dir, const char *name);
virtual int read_audio(unsigned char *buffer, int length);
virtual void update_load(void);
struct port_settings p_settings;
@ -205,6 +205,7 @@ class Port
int p_record_anon_ignore;
char p_record_vbox_email[128];
int p_record_vbox_email_file;
virtual void update_rxoff(void); /* inherited by mISDNport, to control rxoff */
void free_epointlist(struct epoint_list *epointlist);
void free_epointid(unsigned int epoint_id);

35
route.c
View File

@ -1791,12 +1791,14 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
int integer;
char *string;
FILE *tfp;
double timeout;
long long timeout, now_ll = 0, match_timeout = 0;
struct timeval current_time;
struct mISDNport *mISDNport;
struct admin_list *admin;
time_t now;
struct tm *now_tm;
/* reset timeout action */
e_match_timeout = 0; /* no timeout */
e_match_to_action = NULL;
SCPY(callerid, numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype, options.national, options.international));
@ -1910,22 +1912,32 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
goto match_string_prefix;
case MATCH_TIME:
time(&now);
now_tm = localtime(&now);
integer = now_tm->tm_hour*100 + now_tm->tm_min;
goto match_integer;
case MATCH_MDAY:
time(&now);
now_tm = localtime(&now);
integer = now_tm->tm_mday;
goto match_integer;
case MATCH_MONTH:
time(&now);
now_tm = localtime(&now);
integer = now_tm->tm_mon+1;
goto match_integer;
case MATCH_YEAR:
time(&now);
now_tm = localtime(&now);
integer = now_tm->tm_year + 1900;
goto match_integer;
case MATCH_WDAY:
time(&now);
now_tm = localtime(&now);
integer = now_tm->tm_wday;
integer = integer?integer:7; /* correct sunday */
goto match_integer;
@ -1963,7 +1975,11 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
break;
case MATCH_TIMEOUT:
timeout = now_d + cond->integer_value;
if (!now_ll) {
gettimeofday(&current_time, NULL);
now_ll = current_time.tv_sec * MICRO_SECONDS + current_time.tv_usec;
}
timeout = now_ll + (cond->integer_value * MICRO_SECONDS);
istrue = 1;
break;
@ -2166,10 +2182,10 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
cond = cond->next;
}
if (timeout>now_d && match==1) /* the matching rule with timeout in the future */
if (e_match_timeout<1 || timeout<e_match_timeout) { /* first timeout or lower */
if (timeout>now_ll && match==1) /* the matching rule with timeout in the future */
if (match_timeout == 0 || timeout < match_timeout) { /* first timeout or lower */
/* set timeout in the furture */
e_match_timeout = timeout;
match_timeout = timeout;
e_match_to_action = rule->action_first;
e_match_to_extdialing = e_dialinginfo.id + dialing_required;
match = 0; /* matches in the future */
@ -2177,7 +2193,7 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
if (match == 1) {
/* matching, we return first action */
action = rule->action_first;
e_match_timeout = 0; /* no timeout */
match_timeout = 0; /* no timeout */
e_match_to_action = NULL;
e_extdialing = e_dialinginfo.id + dialing_required;
break;
@ -2188,6 +2204,11 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
}
rule = rule->next;
}
if (match_timeout == 0)
unsched_timer(&e_match_timeout); /* no timeout */
else {
schedule_timer(&e_match_timeout, match_timeout / 1000000, match_timeout % 1000000);
}
return(action);
}

434
select.c Normal file
View File

@ -0,0 +1,434 @@
/* based on code from OpenBSC */
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/time.h>
#include "macro.h"
#include "select.h"
static int maxfd = 0;
static int unregistered;
static struct lcr_fd *fd_first = NULL;
static struct timeval *nearest_timer(struct timeval *select_timer, int *work);
static int next_work(void);
int _register_fd(struct lcr_fd *fd, int when, int (*cb)(struct lcr_fd *fd, unsigned int what, void *instance, int index), void *instance, int index, const char *func)
{
int flags;
if (fd->inuse)
FATAL("FD that is registered in function %s is already in use\n", func);
// printf("registering fd %d %s\n", fd->fd, func);
/* make FD nonblocking */
flags = fcntl(fd->fd, F_GETFL);
if (flags < 0)
FATAL("Failed to F_GETFL\n");
flags |= O_NONBLOCK;
flags = fcntl(fd->fd, F_SETFL, flags);
if (flags < 0)
FATAL("Failed to F_SETFL O_NONBLOCK\n");
/* Register FD */
if (fd->fd > maxfd)
maxfd = fd->fd;
/* append to list */
fd->inuse = 1;
fd->when = when;
fd->cb = cb;
fd->cb_instance = instance;
fd->cb_index = index;
fd->next = fd_first;
fd_first = fd;
return 0;
}
void _unregister_fd(struct lcr_fd *fd, const char *func)
{
struct lcr_fd **lcr_fdp;
/* find pointer to fd */
lcr_fdp = &fd_first;
while(*lcr_fdp) {
if (*lcr_fdp == fd)
break;
lcr_fdp = &((*lcr_fdp)->next);
}
if (!*lcr_fdp) {
FATAL("FD unregistered in function %s not in list\n", func);
}
/* remove fd from list */
fd->inuse = 0;
*lcr_fdp = fd->next;
unregistered = 1;
}
int select_main(int polling, int *global_change, void (*lock)(void), void (*unlock)(void))
{
struct lcr_fd *lcr_fd;
fd_set readset, writeset, exceptset;
int work = 0, temp, rc;
struct timeval no_time = {0, 0};
struct timeval select_timer, *timer;
/* goto again;
*
* this ensures that select is only called until:
* - no work event exists
* - and no timeout occurred
*
* if no future timeout exists, select will wait infinit.
*/
again:
/* process all work events */
if (next_work()) {
work = 1;
goto again;
}
/* process timer events and get timeout for next timer event */
temp = 0;
timer = nearest_timer(&select_timer, &temp);
if (temp) {
work = 1;
goto again;
}
if (polling)
timer = &no_time;
#warning TESTING
if (!timer)
printf("wait till infinity ..."); fflush(stdout);
FD_ZERO(&readset);
FD_ZERO(&writeset);
FD_ZERO(&exceptset);
/* prepare read and write fdsets */
lcr_fd = fd_first;
while(lcr_fd) {
if (lcr_fd->when & LCR_FD_READ)
FD_SET(lcr_fd->fd, &readset);
if (lcr_fd->when & LCR_FD_WRITE)
FD_SET(lcr_fd->fd, &writeset);
if (lcr_fd->when & LCR_FD_EXCEPT)
FD_SET(lcr_fd->fd, &exceptset);
lcr_fd = lcr_fd->next;
}
if (unlock)
unlock();
rc = select(maxfd+1, &readset, &writeset, &exceptset, timer);
if (lock)
lock();
#warning TESTING
if (!timer)
printf("interrupted.\n");
if (rc < 0)
return 0;
if (global_change && *global_change) {
*global_change = 0;
return 1;
}
/* fire timers */
#if 0
bsc_update_timers();
#endif
/* call registered callback functions */
restart:
unregistered = 0;
lcr_fd = fd_first;
while(lcr_fd) {
int flags = 0;
if (FD_ISSET(lcr_fd->fd, &readset)) {
flags |= LCR_FD_READ;
FD_CLR(lcr_fd->fd, &readset);
}
if (FD_ISSET(lcr_fd->fd, &writeset)) {
flags |= LCR_FD_WRITE;
FD_CLR(lcr_fd->fd, &writeset);
}
if (FD_ISSET(lcr_fd->fd, &exceptset)) {
flags |= LCR_FD_EXCEPT;
FD_CLR(lcr_fd->fd, &exceptset);
}
if (flags) {
work = 1;
lcr_fd->cb(lcr_fd, flags, lcr_fd->cb_instance, lcr_fd->cb_index);
if (unregistered)
goto restart;
return 1;
}
lcr_fd = lcr_fd->next;
}
return work;
}
static struct lcr_timer *timer_first = NULL;
int _add_timer(struct lcr_timer *timer, int (*cb)(struct lcr_timer *timer, void *instance, int index), void *instance, int index, const char *func)
{
if (timer->inuse) {
FATAL("timer that is registered in function %s is already in use\n", func);
}
#if 0
struct lcr_timer *test = timer_first;
while(test) {
if (test == timer)
FATAL("Timer already in list %s\n", func);
test = test->next;
}
#endif
timer->inuse = 1;
timer->active = 0;
timer->timeout.tv_sec = 0;
timer->timeout.tv_usec = 0;
timer->cb = cb;
timer->cb_instance = instance;
timer->cb_index = index;
timer->next = timer_first;
timer_first = timer;
return 0;
}
void _del_timer(struct lcr_timer *timer, const char *func)
{
struct lcr_timer **lcr_timerp;
/* find pointer to timer */
lcr_timerp = &timer_first;
while(*lcr_timerp) {
if (*lcr_timerp == timer)
break;
lcr_timerp = &((*lcr_timerp)->next);
}
if (!*lcr_timerp) {
FATAL("timer deleted in function %s not in list\n", func);
}
/* remove timer from list */
timer->inuse = 0;
*lcr_timerp = timer->next;
}
void schedule_timer(struct lcr_timer *timer, int seconds, int microseconds)
{
struct timeval current_time;
if (!timer->inuse) {
FATAL("Timer not added\n");
}
gettimeofday(&current_time, NULL);
unsigned long long currentTime = current_time.tv_sec * MICRO_SECONDS + current_time.tv_usec;
currentTime += seconds * MICRO_SECONDS + microseconds;
timer->timeout.tv_sec = currentTime / MICRO_SECONDS;
timer->timeout.tv_usec = currentTime % MICRO_SECONDS;
timer->active = 1;
}
void unsched_timer(struct lcr_timer *timer)
{
timer->active = 0;
}
/* if a timeout is reached, process timer, if not, return timer value for select */
static struct timeval *nearest_timer(struct timeval *select_timer, int *work)
{
struct timeval current;
struct timeval *nearest = NULL;
struct lcr_timer *lcr_timer, *lcr_nearest = NULL;
/* find nearest timer, or NULL, if no timer active */
lcr_timer = timer_first;
while(lcr_timer) {
if (lcr_timer->active && (!nearest || TIME_SMALLER(&lcr_timer->timeout, nearest))) {
nearest = &lcr_timer->timeout;
lcr_nearest = lcr_timer;
}
lcr_timer = lcr_timer->next;
}
select_timer->tv_sec = 0;
select_timer->tv_usec = 0;
if (!nearest)
return NULL; /* wait until infinity */
gettimeofday(&current, NULL);
unsigned long long nearestTime = nearest->tv_sec * MICRO_SECONDS + nearest->tv_usec;
unsigned long long currentTime = current.tv_sec * MICRO_SECONDS + current.tv_usec;
if (nearestTime > currentTime) {
select_timer->tv_sec = (nearestTime - currentTime) / MICRO_SECONDS;
select_timer->tv_usec = (nearestTime - currentTime) % MICRO_SECONDS;
return select_timer;
} else {
lcr_nearest->active = 0;
(*lcr_nearest->cb)(lcr_nearest, lcr_nearest->cb_instance, lcr_nearest->cb_index);
/* don't wait so we can process the queues, indicate "work=1" */
select_timer->tv_sec = 0;
select_timer->tv_usec = 0;
*work = 1;
return select_timer;
}
}
static struct lcr_work *work_first = NULL; /* chain of work */
static struct lcr_work *first_event = NULL, *last_event = NULL; /* chain of active events */
#ifdef DEBUG_WORK
void show_chain(const char *func)
{
struct lcr_work *work = first_event;
printf("chain:%s\n", func);
while(work) {
printf("%p - %p - %p\n", work->prev_event, work, work->next_event);
work = work->next_event;
}
}
#endif
int _add_work(struct lcr_work *work, int (*cb)(struct lcr_work *work, void *instance, int index), void *instance, int index, const char *func)
{
if (work->inuse) {
FATAL("work that is registered in function %s is already in use\n", func);
}
#ifdef DEBUG_WORK
printf("add work %p from function %s\n", work, func);
show_chain("before add");
#endif
work->inuse = 1;
work->active = 0;
work->cb = cb;
work->cb_instance = instance;
work->cb_index = index;
work->next = work_first;
work_first = work;
#ifdef DEBUG_WORK
show_chain("after add");
#endif
return 0;
}
void _del_work(struct lcr_work *work, const char *func)
{
struct lcr_work **lcr_workp;
#ifdef DEBUG_WORK
show_chain("before detach");
#endif
if (work->active) {
/* first event removed */
if (!work->prev_event)
first_event = work->next_event;
else
work->prev_event->next_event = work->next_event;
/* last event removed */
if (!work->next_event)
last_event = work->prev_event;
else
work->next_event->prev_event = work->prev_event;
}
#ifdef DEBUG_WORK
show_chain("after detach");
#endif
/* find pointer to work */
lcr_workp = &work_first;
while(*lcr_workp) {
if (*lcr_workp == work)
break;
lcr_workp = &((*lcr_workp)->next);
}
if (!*lcr_workp) {
FATAL("work deleted by '%s' not in list\n", func);
}
/* remove work from list */
work->inuse = 0;
*lcr_workp = work->next;
#ifdef DEBUG_WORK
show_chain("after delete");
#endif
}
void trigger_work(struct lcr_work *work)
{
if (!work->inuse) {
FATAL("Work not added\n");
}
/* event already triggered */
if (work->active)
return;
#ifdef DEBUG_WORK
show_chain("before trigger");
#endif
/* append to tail of chain */
if (last_event)
last_event->next_event = work;
work->prev_event = last_event;
work->next_event = NULL;
last_event = work;
if (!first_event)
first_event = work;
#ifdef DEBUG_WORK
show_chain("after trigger");
#endif
work->active = 1;
}
/* get first work and remove from event chain */
static int next_work(void)
{
struct lcr_work *lcr_work;
if (!first_event)
return 0;
#ifdef DEBUG_WORK
show_chain("before next_work");
#endif
if (!first_event->inuse) {
FATAL("Work not added\n");
}
/* detach from event chain */
lcr_work = first_event;
first_event = lcr_work->next_event;
if (!first_event)
last_event = NULL;
else
first_event->prev_event = NULL;
#ifdef DEBUG_WORK
show_chain("after next_work");
#endif
lcr_work->active = 0;
(*lcr_work->cb)(lcr_work, lcr_work->cb_instance, lcr_work->cb_index);
return 1;
}

62
select.h Normal file
View File

@ -0,0 +1,62 @@
#define LCR_FD_READ 1
#define LCR_FD_WRITE 2
#define LCR_FD_EXCEPT 4
#define MICRO_SECONDS 1000000LL
#define TIME_SMALLER(left, right) \
(((left)->tv_sec*MICRO_SECONDS+(left)->tv_usec) <= ((right)->tv_sec*MICRO_SECONDS+(right)->tv_usec))
struct lcr_fd {
struct lcr_fd *next; /* pointer to next element in list */
int inuse; /* if in use */
int fd; /* file descriptior if in use */
int when; /* select on what event */
int (*cb)(struct lcr_fd *fd, unsigned int what, void *instance, int index); /* callback */
void *cb_instance;
int cb_index;
};
#define register_fd(a, b, c, d, e) _register_fd(a, b, c, d, e, __func__);
int _register_fd(struct lcr_fd *fd, int when, int (*cb)(struct lcr_fd *fd, unsigned int what, void *instance, int index), void *instance, int index, const char *func);
#define unregister_fd(a) _unregister_fd(a, __func__);
void _unregister_fd(struct lcr_fd *fd, const char *func);
int select_main(int polling, int *global_change, void (*lock)(void), void (*unlock)(void));
struct lcr_timer {
struct lcr_timer *next; /* pointer to next element in list */
int inuse; /* if in use */
int active; /* if timer is currently active */
struct timeval timeout; /* timestamp when to timeout */
int (*cb)(struct lcr_timer *timer, void *instance, int index); /* callback */
void *cb_instance;
int cb_index;
};
#define add_timer(a, b, c, d) _add_timer(a, b, c, d, __func__);
int _add_timer(struct lcr_timer *timer, int (*cb)(struct lcr_timer *timer, void *instance, int index), void *instance, int index, const char *func);
#define del_timer(a) _del_timer(a, __func__);
void _del_timer(struct lcr_timer *timer, const char *func);
void schedule_timer(struct lcr_timer *timer, int seconds, int microseconds);
void unsched_timer(struct lcr_timer *timer);
struct lcr_work {
struct lcr_work *next; /* pointer to next element in list */
struct lcr_work *prev_event, *next_event; /* pointer to previous/next event, if triggered */
int inuse; /* if in use */
int active; /* if timer is currently active */
int (*cb)(struct lcr_work *work, void *instance, int index); /* callback */
void *cb_instance;
int cb_index;
};
#define add_work(a, b, c, d) _add_work(a, b, c, d, __func__);
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);

View File

@ -20,14 +20,15 @@ int sock = -1;
struct sockaddr_un sock_address;
struct admin_list *admin_first = NULL;
static struct lcr_fd admin_fd;
int admin_handle(struct lcr_fd *fd, unsigned int what, void *instance, int index);
/*
* initialize admin socket
*/
int admin_init(void)
{
unsigned int on = 1;
/* open and bind socket */
if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
PERROR("Failed to create admin socket. (errno=%d)\n", errno);
@ -55,14 +56,9 @@ int admin_init(void)
PERROR("Failed to listen to socket \"%s\". (errno=%d)\n", sock_address.sun_path, errno);
return(-1);
}
if (ioctl(sock, FIONBIO, (unsigned char *)(&on)) < 0) {
close(sock);
unlink(socket_name);
fhuse--;
sock = -1;
PERROR("Failed to set socket \"%s\" into non-blocking mode. (errno=%d)\n", sock_address.sun_path, errno);
return(-1);
}
memset(&admin_fd, 0, sizeof(admin_fd));
admin_fd.fd = sock;
register_fd(&admin_fd, LCR_FD_READ | LCR_FD_EXCEPT, admin_handle, NULL, 0);
if (chmod(socket_name, options.socketrights) < 0) {
PERROR("Failed to change socket rights to %d. (errno=%d)\n", options.socketrights, errno);
}
@ -86,6 +82,7 @@ void free_connection(struct admin_list *admin)
class Join *join, *joinnext;
struct mISDNport *mISDNport;
int i, ii;
struct admin_list **adminp;
/* free remote joins */
if (admin->remote_name[0]) {
@ -107,7 +104,7 @@ void free_connection(struct admin_list *admin)
while(i < ii) {
if (mISDNport->b_remote_id[i] == admin->sock) {
mISDNport->b_state[i] = B_STATE_IDLE;
mISDNport->b_timer[i] = 0;
unsched_timer(&mISDNport->b_timer[i]);
mISDNport->b_remote_id[i] = 0;
mISDNport->b_remote_ref[i] = 0;
}
@ -131,22 +128,28 @@ void free_connection(struct admin_list *admin)
}
if (admin->sock >= 0) {
unregister_fd(&admin->fd);
close(admin->sock);
fhuse--;
}
// printf("new\n", response);
response = admin->response;
while (response) {
//#warning
// printf("%x\n", response);
temp = response->next;
FREE(response, 0);
memuse--;
response = (struct admin_queue *)temp;
}
// printf("new2\n", response);
adminp = &admin_first;
while(*adminp) {
if (*adminp == admin)
break;
adminp = &((*adminp)->next);
}
if (*adminp)
*adminp = (*adminp)->next;
FREE(admin, 0);
// printf("new3\n", response);
memuse--;
}
@ -160,13 +163,13 @@ void admin_cleanup(void)
admin = admin_first;
while(admin) {
//printf("clean\n");
next = admin->next;
free_connection(admin);
admin = next;
}
if (sock >= 0) {
unregister_fd(&admin_fd);
close(sock);
fhuse--;
}
@ -206,7 +209,6 @@ int admin_interface(struct admin_queue **responsep)
/* attach to response chain */
*responsep = response;
responsep = &response->next;
return(0);
}
@ -274,7 +276,7 @@ int admin_route(struct admin_queue **responsep)
}
} else if (apppbx->e_state != EPOINT_STATE_CONNECT) {
release:
apppbx->e_callback = 0;
unsched_timer(&apppbx->e_callback_timeout);
apppbx->e_action = NULL;
apppbx->release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
start_trace(-1,
@ -288,7 +290,7 @@ int admin_route(struct admin_queue **responsep)
end_trace();
}
apppbx->e_action_timeout = 0;
unsched_timer(&apppbx->e_action_timeout);
apppbx->e_rule = NULL;
apppbx->e_ruleset = NULL;
@ -309,7 +311,6 @@ int admin_route(struct admin_queue **responsep)
/* attach to response chain */
*responsep = response;
responsep = &response->next;
return(0);
}
@ -486,7 +487,7 @@ int admin_release(struct admin_queue **responsep, char *message)
goto out;
}
apppbx->e_callback = 0;
unsched_timer(&apppbx->e_callback_timeout);
apppbx->release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
out:
@ -518,7 +519,6 @@ int admin_call(struct admin_list *admin, struct admin_message *msg)
apppbx->e_callerinfo.present = INFO_PRESENT_RESTRICTED;
apppbx->e_callerinfo.screen = INFO_SCREEN_NETWORK;
//printf("hh=%d\n", apppbx->e_capainfo.hlc);
apppbx->e_capainfo.bearer_capa = msg->u.call.bc_capa;
apppbx->e_capainfo.bearer_mode = msg->u.call.bc_mode;
@ -569,7 +569,6 @@ void admin_call_response(int adminid, int message, const char *connected, int ca
response->num = 1;
/* message */
response->am[0].message = message;
// printf("MESSAGE: %d\n", message);
SCPY(response->am[0].u.call.callerid, connected);
response->am[0].u.call.cause = cause;
@ -579,6 +578,7 @@ void admin_call_response(int adminid, int message, const char *connected, int ca
/* attach to response chain */
*responsep = response;
responsep = &response->next;
admin->fd.when |= LCR_FD_WRITE;
}
@ -722,7 +722,7 @@ int admin_message_from_join(int remote_id, unsigned int ref, int message_type, u
(*responsep)->am[0].u.msg.type = message_type;
(*responsep)->am[0].u.msg.ref = ref;
memcpy(&(*responsep)->am[0].u.msg.param, param, sizeof(union parameter));
admin->fd.when |= LCR_FD_WRITE;
return(0);
}
@ -732,7 +732,6 @@ int admin_message_from_join(int remote_id, unsigned int ref, int message_type, u
*/
int admin_state(struct admin_queue **responsep)
{
class Port *port;
class EndpointAppPBX *apppbx;
class Join *join;
@ -745,6 +744,8 @@ int admin_state(struct admin_queue **responsep)
int anybusy;
struct admin_queue *response;
struct admin_list *admin;
struct tm *now_tm;
time_t now;
/* create state response */
response = (struct admin_queue *)MALLOC(sizeof(struct admin_queue)+sizeof(admin_message));
@ -755,6 +756,8 @@ int admin_state(struct admin_queue **responsep)
/* version */
SCPY(response->am[0].u.s.version_string, VERSION_STRING);
/* time */
time(&now);
now_tm = localtime(&now);
memcpy(&response->am[0].u.s.tm, now_tm, sizeof(struct tm));
/* log file */
SCPY(response->am[0].u.s.logfile, options.log);
@ -1064,68 +1067,54 @@ int sockserial = 1; // must start with 1, because 0 is used if no serial is set
/*
* handle admin socket (non blocking)
*/
int admin_handle(void)
int admin_handle_con(struct lcr_fd *fd, unsigned int what, void *instance, int index);
int admin_handle(struct lcr_fd *fd, unsigned int what, void *instance, int index)
{
struct admin_list *admin, **adminp;
void *temp;
struct admin_message msg;
int len;
int new_sock;
socklen_t sock_len = sizeof(sock_address);
unsigned int on = 1;
int work = 0; /* if work was done */
struct Endpoint *epoint;
if (sock < 0)
return(0);
struct admin_list *admin;
/* check for new incoming connections */
if ((new_sock = accept(sock, (struct sockaddr *)&sock_address, &sock_len)) >= 0) {
work = 1;
/* insert new socket */
admin = (struct admin_list *)MALLOC(sizeof(struct admin_list));
if (ioctl(new_sock, FIONBIO, (unsigned char *)(&on)) >= 0) {
//#warning
// PERROR("DEBUG incoming socket %d, serial=%d\n", new_sock, sockserial);
memuse++;
fhuse++;
admin->sockserial = sockserial++;
admin->next = admin_first;
admin_first = admin;
admin->sock = new_sock;
} else {
close(new_sock);
FREE(admin, sizeof(struct admin_list));
}
memuse++;
fhuse++;
admin->sockserial = sockserial++;
admin->next = admin_first;
admin_first = admin;
admin->sock = new_sock;
admin->fd.fd = new_sock;
register_fd(&admin->fd, LCR_FD_READ | LCR_FD_EXCEPT, admin_handle_con, admin, 0);
} else {
if (errno != EWOULDBLOCK) {
PERROR("Failed to accept connection from socket \"%s\". (errno=%d) Closing socket.\n", sock_address.sun_path, errno);
admin_cleanup();
return(1);
return 0;
}
}
/* loop all current socket connections */
admin = admin_first;
adminp = &admin_first;
while(admin) {
return 0;
}
int admin_handle_con(struct lcr_fd *fd, unsigned int what, void *instance, int index)
{
struct admin_list *admin = (struct admin_list *)instance;
void *temp;
struct admin_message msg;
int len;
struct Endpoint *epoint;
if ((what & LCR_FD_READ)) {
/* read command */
len = read(admin->sock, &msg, sizeof(msg));
if (len < 0) {
if (errno != EWOULDBLOCK) {
work = 1;
brokenpipe:
PDEBUG(DEBUG_LOG, "Broken pipe on socket %d. (errno=%d).\n", admin->sock, errno);
*adminp = admin->next;
free_connection(admin);
admin = *adminp;
continue;
}
goto send_data;
brokenpipe:
PDEBUG(DEBUG_LOG, "Broken pipe on socket %d. (errno=%d).\n", admin->sock, errno);
free_connection(admin);
return 0;
}
work = 1;
//#warning
//PERROR("DEBUG socket %d got data. serial=%d\n", admin->sock, admin->sockserial);
if (len == 0) {
end:
@ -1138,28 +1127,19 @@ int admin_handle(void)
}
}
//#warning
//PERROR("DEBUG socket %d closed by remote.\n", admin->sock);
*adminp = admin->next;
free_connection(admin);
admin = *adminp;
//PERROR("DEBUG (admin_first=%x)\n", admin_first);
continue;
return 0;
}
if (len != sizeof(msg)) {
PERROR("Short/long read on socket %d. (len=%d != size=%d).\n", admin->sock, len, sizeof(msg));
*adminp = admin->next;
free_connection(admin);
admin = *adminp;
continue;
return 0;
}
/* process socket command */
if (admin->response && msg.message != ADMIN_MESSAGE) {
PERROR("Data from socket %d while sending response.\n", admin->sock);
*adminp = admin->next;
free_connection(admin);
admin = *adminp;
continue;
return 0;
}
switch (msg.message) {
case ADMIN_REQUEST_CMD_INTERFACE:
@ -1167,6 +1147,7 @@ int admin_handle(void)
PERROR("Failed to create dial response for socket %d.\n", admin->sock);
goto response_error;
}
admin->fd.when |= LCR_FD_WRITE;
break;
case ADMIN_REQUEST_CMD_ROUTE:
@ -1174,6 +1155,7 @@ int admin_handle(void)
PERROR("Failed to create dial response for socket %d.\n", admin->sock);
goto response_error;
}
admin->fd.when |= LCR_FD_WRITE;
break;
case ADMIN_REQUEST_CMD_DIAL:
@ -1181,6 +1163,7 @@ int admin_handle(void)
PERROR("Failed to create dial response for socket %d.\n", admin->sock);
goto response_error;
}
admin->fd.when |= LCR_FD_WRITE;
break;
case ADMIN_REQUEST_CMD_RELEASE:
@ -1188,6 +1171,7 @@ int admin_handle(void)
PERROR("Failed to create release response for socket %d.\n", admin->sock);
goto response_error;
}
admin->fd.when |= LCR_FD_WRITE;
break;
case ADMIN_REQUEST_STATE:
@ -1195,6 +1179,7 @@ int admin_handle(void)
PERROR("Failed to create state response for socket %d.\n", admin->sock);
goto response_error;
}
admin->fd.when |= LCR_FD_WRITE;
break;
case ADMIN_TRACE_REQUEST:
@ -1202,6 +1187,7 @@ int admin_handle(void)
PERROR("Failed to create trace response for socket %d.\n", admin->sock);
goto response_error;
}
admin->fd.when |= LCR_FD_WRITE;
break;
case ADMIN_REQUEST_CMD_BLOCK:
@ -1209,6 +1195,7 @@ int admin_handle(void)
PERROR("Failed to create block response for socket %d.\n", admin->sock);
goto response_error;
}
admin->fd.when |= LCR_FD_WRITE;
break;
case ADMIN_MESSAGE:
@ -1216,71 +1203,46 @@ int admin_handle(void)
PERROR("Failed to deliver message for socket %d.\n", admin->sock);
goto response_error;
}
#if 0
#warning DEBUGGING
{
struct admin_queue *response;
printf("Chain: ");
response = admin->response;
while(response) {
printf("%c", '0'+response->am[0].message);
response=response->next;
}
printf("\n");
}
#endif
break;
case ADMIN_CALL_SETUP:
if (admin_call(admin, &msg) < 0) {
PERROR("Failed to create call for socket %d.\n", admin->sock);
response_error:
*adminp = admin->next;
free_connection(admin);
admin = *adminp;
continue;
return 0;
}
break;
default:
PERROR("Invalid message %d from socket %d.\n", msg.message, admin->sock);
*adminp = admin->next;
free_connection(admin);
admin = *adminp;
continue;
return 0;
}
}
if ((what & LCR_FD_WRITE)) {
/* write queue */
send_data:
if (admin->response) {
//#warning
//PERROR("DEBUG socket %d sending data.\n", admin->sock);
len = write(admin->sock, ((unsigned char *)(admin->response->am))+admin->response->offset, sizeof(struct admin_message)*(admin->response->num)-admin->response->offset);
if (len < 0) {
if (errno != EWOULDBLOCK) {
work = 1;
goto brokenpipe;
}
goto next;
goto brokenpipe;
}
work = 1;
if (len == 0)
goto end;
if (len < (int)(sizeof(struct admin_message)*(admin->response->num) - admin->response->offset)) {
admin->response->offset+=len;
goto next;
return 0;
} else {
temp = admin->response;
admin->response = admin->response->next;
FREE(temp, 0);
memuse--;
}
}
/* done with socket instance */
next:
adminp = &admin->next;
admin = admin->next;
} else
admin->fd.when &= ~LCR_FD_WRITE;
}
return(work);
return 0;
}

View File

@ -21,6 +21,7 @@ struct admin_queue {
struct admin_list {
struct admin_list *next;
int sock;
struct lcr_fd fd;
int sockserial;
char remote_name[32]; /* socket is connected remote application */
struct admin_trace_req trace; /* stores trace, if detail != 0 */
@ -31,7 +32,6 @@ struct admin_list {
extern struct admin_list *admin_first;
int admin_init(void);
void admin_cleanup(void);
int admin_handle(void);
void admin_call_response(int adminid, int message, const char *connected, int cause, int location, int notify);
int admin_message_to_join(struct admin_message *msg, int remote_id);
int admin_message_from_join(int remote_id, unsigned int ref, int message_type, union parameter *param);

97
ss5.cpp
View File

@ -333,6 +333,7 @@ class Pss5 *ss5_hunt_line(struct mISDNport *mISDNport)
return NULL;
}
int queue_event(struct lcr_work *work, void *instance, int index);
/*
* constructor
@ -352,8 +353,8 @@ Pss5::Pss5(int type, struct mISDNport *mISDNport, char *portname, struct port_se
//p_m_s_decoder_buffer;
p_m_s_sample_nr = 0;
p_m_s_recog = 0;
p_m_s_timer = 0.0;
p_m_s_timer_fn = NULL;
memset(&p_m_s_queue, 0, sizeof(p_m_s_queue));
add_work(&p_m_s_queue, queue_event, this, 0);
p_m_s_answer = 0;
p_m_s_busy_flash = 0;
p_m_s_clear_back = 0;
@ -372,6 +373,7 @@ Pss5::Pss5(int type, struct mISDNport *mISDNport, char *portname, struct port_se
*/
Pss5::~Pss5()
{
del_work(&p_m_s_queue);
}
@ -383,7 +385,47 @@ void Pss5::_new_ss5_state(int state, const char *func, int line)
PDEBUG(DEBUG_SS5, "%s(%s:%d): changing SS5 state from %s to %s\n", p_name, func, line, ss5_state_name[p_m_s_state], ss5_state_name[state]);
p_m_s_state = state;
p_m_s_signal = SS5_SIGNAL_NULL;
if (p_m_s_state == SS5_STATE_IDLE && (p_m_s_answer || p_m_s_busy_flash || p_m_s_clear_back))
trigger_work(&p_m_s_queue);
}
int queue_event(struct lcr_work *work, void *instance, int index)
{
class Pss5 *ss5port = (class Pss5 *)instance;
if (ss5port->p_m_s_state == SS5_STATE_IDLE) {
/* if answer signal is queued */
if (ss5port->p_m_s_answer) {
ss5port->p_m_s_answer = 0;
/* start answer */
ss5_trace_header(ss5port->p_m_mISDNport, ss5port, SS5_ANSWER_REQ, ss5port->p_m_b_channel);
end_trace();
ss5port->start_signal(SS5_STATE_ANSWER);
}
/* if busy-flash signal is queued */
if (ss5port->p_m_s_busy_flash) {
ss5port->p_m_s_busy_flash = 0;
/* start busy-flash */
ss5_trace_header(ss5port->p_m_mISDNport, ss5port, SS5_BUSY_FLASH_REQ, ss5port->p_m_b_channel);
end_trace();
ss5port->start_signal(SS5_STATE_BUSY_FLASH);
}
/* if clear-back signal is queued */
if (ss5port->p_m_s_clear_back) {
ss5port->p_m_s_clear_back = 0;
/* start clear-back */
ss5_trace_header(ss5port->p_m_mISDNport, ss5port, SS5_CLEAR_BACK_REQ, ss5port->p_m_b_channel);
end_trace();
ss5port->start_signal(SS5_STATE_CLEAR_BACK);
}
}
return 0;
}
void Pss5::_new_ss5_signal(int signal, const char *func, int line)
{
if (p_m_s_signal)
@ -1606,8 +1648,6 @@ void Pss5::do_release(int cause, int location)
{
struct lcr_msg *message;
p_m_s_timer = 0.0;
/* sending release to endpoint */
while(p_epointlist) {
message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
@ -1672,52 +1712,6 @@ void Pss5::do_setup(char *dial, int complete)
}
/*
* handler
*/
int Pss5::handler(void)
{
int ret;
if ((ret = PmISDN::handler()))
return(ret);
/* handle timer */
if (p_m_s_timer && p_m_s_timer < now) {
p_m_s_timer = 0.0;
(this->*(p_m_s_timer_fn))();
}
/* if answer signal is queued */
if (p_m_s_answer && p_m_s_state == SS5_STATE_IDLE) {
p_m_s_answer = 0;
/* start answer */
ss5_trace_header(p_m_mISDNport, this, SS5_ANSWER_REQ, p_m_b_channel);
end_trace();
start_signal(SS5_STATE_ANSWER);
}
/* if busy-flash signal is queued */
if (p_m_s_busy_flash && p_m_s_state == SS5_STATE_IDLE) {
p_m_s_busy_flash = 0;
/* start busy-flash */
ss5_trace_header(p_m_mISDNport, this, SS5_BUSY_FLASH_REQ, p_m_b_channel);
end_trace();
start_signal(SS5_STATE_BUSY_FLASH);
}
/* if clear-back signal is queued */
if (p_m_s_clear_back && p_m_s_state == SS5_STATE_IDLE) {
p_m_s_clear_back = 0;
/* start clear-back */
ss5_trace_header(p_m_mISDNport, this, SS5_CLEAR_BACK_REQ, p_m_b_channel);
end_trace();
start_signal(SS5_STATE_CLEAR_BACK);
}
return(0);
}
/*
* handles all messages from endpoint
@ -1917,6 +1911,7 @@ void Pss5::message_connect(unsigned int epoint_id, int message_id, union paramet
if (p_state != PORT_STATE_CONNECT) {
new_state(PORT_STATE_CONNECT);
p_m_s_answer = 1;
trigger_work(&p_m_s_queue);
}
set_tone("", NULL);
@ -1937,8 +1932,6 @@ if (0 || p_type==PORT_TYPE_SS5_OUT) { /* outgoing exchange */
start_signal(SS5_STATE_CLEAR_BACK);
new_state(PORT_STATE_OUT_DISCONNECT);
// p_m_s_timer_fn = &Pss5::register_timeout;
// p_m_s_timer = now + 30.0;
}
/* MESSAGE_RELEASE */

4
ss5.h
View File

@ -25,7 +25,6 @@ class Pss5 : public PmISDN
public:
Pss5(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel, int exclusive, int mode);
~Pss5();
int handler(void);
int message_epoint(unsigned int epoint_id, int message, union parameter *param);
void set_tone(const char *dir, const char *name);
@ -43,8 +42,7 @@ class Pss5 : public PmISDN
unsigned char p_m_s_delay_mute[400/SS5_DECODER_NPOINTS]; /* 40 ms delay on mute, so a 'chirp' can be heared */
int p_m_s_sample_nr; /* decoder's sample number, counter */
int p_m_s_recog; /* sample counter to wait for signal recognition time */
double p_m_s_timer;
void (Pss5::*p_m_s_timer_fn)(void);
struct lcr_work p_m_s_queue;
int p_m_s_answer; /* queued signal */
int p_m_s_busy_flash; /* queued signal */
int p_m_s_clear_back; /* queued signal */

View File

@ -22,6 +22,8 @@ static const char *spaces = " ";
*/
void _start_trace(const char *__file, int __line, int port, struct interface *interface, const char *caller, const char *dialing, int direction, int category, int serial, const char *name)
{
struct timeval current_time;
if (trace.name[0])
PERROR("trace already started (name=%s) in file %s line %d\n", trace.name, __file, __line);
memset(&trace, 0, sizeof(struct trace));
@ -39,8 +41,9 @@ void _start_trace(const char *__file, int __line, int port, struct interface *in
SCPY(trace.name, name);
if (!trace.name[0])
SCPY(trace.name, "<unknown>");
trace.sec = now_tv.tv_sec;
trace.usec = now_tv.tv_usec;
gettimeofday(&current_time, NULL);
trace.sec = current_time.tv_sec;
trace.usec = current_time.tv_usec;
}
@ -270,7 +273,7 @@ void _end_trace(const char *__file, int __line)
if (string) {
/* process debug */
if (options.deb)
debug(NULL, 0, "trace", string);
debug(NULL, 0, "TRACE", string);
/* process log */
if (options.log[0]) {
fp = fopen(options.log, "a");

200
vbox.cpp
View File

@ -17,6 +17,9 @@
/* note: recording log is written at endpoint */
int announce_timer(struct lcr_timer *timer, void *instance, int index);
int record_timeout(struct lcr_timer *timer, void *instance, int index);
/*
* initialize vbox port
*/
@ -26,8 +29,11 @@ VBoxPort::VBoxPort(int type, struct port_settings *settings) : Port(type, "vbox"
p_vbox_announce_fh = -1;
p_vbox_audio_start = 0;
p_vbox_audio_transferred = 0;
p_vbox_record_start = 0;
p_vbox_record_limit = 0;
memset(&p_vbox_announce_timer, 0, sizeof(p_vbox_announce_timer));
add_timer(&p_vbox_announce_timer, announce_timer, this, 0);
memset(&p_vbox_record_timeout, 0, sizeof(p_vbox_record_timeout));
add_timer(&p_vbox_record_timeout, record_timeout, this, 0);
}
@ -36,6 +42,8 @@ VBoxPort::VBoxPort(int type, struct port_settings *settings) : Port(type, "vbox"
*/
VBoxPort::~VBoxPort()
{
del_timer(&p_vbox_announce_timer);
del_timer(&p_vbox_record_timeout);
if (p_vbox_announce_fh >= 0) {
close(p_vbox_announce_fh);
p_vbox_announce_fh = -1;
@ -58,119 +66,130 @@ static void vbox_trace_header(class VBoxPort *vbox, const char *message, int dir
}
/*
* handler of vbox
*/
int VBoxPort::handler(void)
int record_timeout(struct lcr_timer *timer, void *instance, int index)
{
class VBoxPort *vboxport = (class VBoxPort *)instance;
struct lcr_msg *message;
while(vboxport->p_epointlist) {
/* send release */
message = message_create(vboxport->p_serial, vboxport->p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
message->param.disconnectinfo.cause = 16;
message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
message_put(message);
vbox_trace_header(vboxport, "RELEASE from VBox (recoding limit reached)", DIRECTION_IN);
add_trace("cause", "value", "%d", message->param.disconnectinfo.cause);
add_trace("cause", "location", "%d", message->param.disconnectinfo.location);
end_trace();
/* remove epoint */
vboxport->free_epointlist(vboxport->p_epointlist);
}
/* recording is close during destruction */
delete vboxport;
return 0;
}
int announce_timer(struct lcr_timer *timer, void *instance, int index)
{
class VBoxPort *vboxport = (class VBoxPort *)instance;
/* port my self destruct here */
vboxport->send_announcement();
return 0;
}
void VBoxPort::send_announcement(void)
{
struct lcr_msg *message;
unsigned int tosend;
unsigned char buffer[ISDN_TRANSMIT];
time_t currenttime;
class Endpoint *epoint;
int ret;
int temp;
struct timeval current_time;
long long now;
if ((ret = Port::handler()))
return(ret);
/* don't restart timer, if announcement is played */
if (p_vbox_announce_fh < 0)
return;
if (p_vbox_record_start && p_vbox_record_limit) {
time(&currenttime);
if (currenttime > (p_vbox_record_limit+p_vbox_record_start)) {
while(p_epointlist) {
/* send release */
message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
message->param.disconnectinfo.cause = 16;
message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
message_put(message);
vbox_trace_header(this, "RELEASE from VBox (recoding limit reached)", DIRECTION_IN);
add_trace("cause", "value", "%d", message->param.disconnectinfo.cause);
add_trace("cause", "location", "%d", message->param.disconnectinfo.location);
end_trace();
/* remove epoint */
free_epointlist(p_epointlist);
}
/* recording is close during destruction */
delete this;
return(-1); /* must return because port is gone */
}
}
gettimeofday(&current_time, NULL);
now = current_time.tv_sec * MICRO_SECONDS + current_time.tv_usec;
/* set time the first time */
if (p_vbox_audio_start < 1) {
p_vbox_audio_start = now_d;
return(0);
}
if (!p_vbox_audio_start)
p_vbox_audio_start = now - ISDN_TRANSMIT;
/* calculate the number of bytes */
tosend = (unsigned int)((now_d-p_vbox_audio_start)*8000) - p_vbox_audio_transferred;
tosend = (unsigned int)(now - p_vbox_audio_start) - p_vbox_audio_transferred;
/* wait for more */
if (tosend < sizeof(buffer))
return(0);
tosend = sizeof(buffer);
/* schedule next event */
temp = ISDN_TRANSMIT + ISDN_TRANSMIT - tosend;
if (temp < 0)
temp = 0;
schedule_timer(&p_vbox_announce_timer, 0, temp*125);
if (tosend > sizeof(buffer))
tosend = sizeof(buffer);
/* add the number of samples elapsed */
p_vbox_audio_transferred += tosend;
/* if announcement is currently played, send audio data */
if (p_vbox_announce_fh >=0) {
tosend = read_tone(p_vbox_announce_fh, buffer, p_vbox_announce_codec, tosend, p_vbox_announce_size, &p_vbox_announce_left, 1);
if (tosend <= 0) {
/* end of file */
close(p_vbox_announce_fh);
p_vbox_announce_fh = -1;
fhuse--;
tosend = read_tone(p_vbox_announce_fh, buffer, p_vbox_announce_codec, tosend, p_vbox_announce_size, &p_vbox_announce_left, 1);
if (tosend <= 0) {
/* end of file */
close(p_vbox_announce_fh);
p_vbox_announce_fh = -1;
fhuse--;
time(&currenttime);
p_vbox_record_start = currenttime;
if (p_vbox_record_limit)
schedule_timer(&p_vbox_record_timeout, p_vbox_record_limit, 0);
/* connect if not already */
epoint = find_epoint_id(ACTIVE_EPOINT(p_epointlist));
if (epoint) {
/* if we sent our announcement during ringing, we must now connect */
if (p_vbox_ext.vbox_free) {
/* send connect message */
message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_CONNECT);
memcpy(&message->param.connectinfo, &p_connectinfo, sizeof(struct connect_info));
message_put(message);
vbox_trace_header(this, "CONNECT from VBox (announcement is over)", DIRECTION_IN);
end_trace();
new_state(PORT_STATE_CONNECT);
}
}
/* start recording, if not already */
if (p_vbox_mode == VBOX_MODE_NORMAL) {
/* recording start */
open_record(p_vbox_ext.vbox_codec, 2, 0, p_vbox_ext.number, p_vbox_ext.anon_ignore, p_vbox_ext.vbox_email, p_vbox_ext.vbox_email_file);
vbox_trace_header(this, "RECORDING (announcement is over)", DIRECTION_IN);
end_trace();
} else // else!!
if (p_vbox_mode == VBOX_MODE_ANNOUNCEMENT) {
/* send release */
message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
message->param.disconnectinfo.cause = 16;
message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
/* connect if not already */
epoint = find_epoint_id(ACTIVE_EPOINT(p_epointlist));
if (epoint) {
/* if we sent our announcement during ringing, we must now connect */
if (p_vbox_ext.vbox_free) {
/* send connect message */
message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_CONNECT);
memcpy(&message->param.connectinfo, &p_connectinfo, sizeof(struct connect_info));
message_put(message);
vbox_trace_header(this, "RELEASE from VBox (after annoucement)", DIRECTION_IN);
add_trace("cause", "value", "%d", message->param.disconnectinfo.cause);
add_trace("cause", "location", "%d", message->param.disconnectinfo.location);
vbox_trace_header(this, "CONNECT from VBox (announcement is over)", DIRECTION_IN);
end_trace();
/* recording is close during destruction */
delete this;
return(-1); /* must return because port is gone */
new_state(PORT_STATE_CONNECT);
}
} 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);
}
}
return(1);
/* start recording, if not already */
if (p_vbox_mode == VBOX_MODE_NORMAL) {
/* recording start */
open_record(p_vbox_ext.vbox_codec, 2, 0, p_vbox_ext.number, p_vbox_ext.anon_ignore, p_vbox_ext.vbox_email, p_vbox_ext.vbox_email_file);
vbox_trace_header(this, "RECORDING (announcement is over)", DIRECTION_IN);
end_trace();
} else // else!!
if (p_vbox_mode == VBOX_MODE_ANNOUNCEMENT) {
/* send release */
message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
message->param.disconnectinfo.cause = 16;
message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
message_put(message);
vbox_trace_header(this, "RELEASE from VBox (after annoucement)", DIRECTION_IN);
add_trace("cause", "value", "%d", message->param.disconnectinfo.cause);
add_trace("cause", "location", "%d", message->param.disconnectinfo.location);
end_trace();
/* recording is close during destruction */
delete this;
return; /* must return because port is gone */
}
} 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);
}
}
@ -288,6 +307,7 @@ int VBoxPort::message_epoint(unsigned int epoint_id, int message_id, union param
/* play the announcement */
if ((p_vbox_announce_fh = open_tone(filename, &p_vbox_announce_codec, &p_vbox_announce_size, &p_vbox_announce_left)) >= 0) {
fhuse++;
schedule_timer(&p_vbox_announce_timer, 0, 300000);
}
vbox_trace_header(this, "ANNOUNCEMENT", DIRECTION_OUT);
add_trace("file", "name", "%s", filename);

7
vbox.h
View File

@ -16,7 +16,7 @@ class VBoxPort : public Port
VBoxPort(int type, struct port_settings *settings);
~VBoxPort();
int message_epoint(unsigned int epoint_id, int message, union parameter *param);
int handler(void);
void send_announcement(void);
private:
struct EndpointAppPBX *p_vbox_apppbx; /* pbx application */
@ -29,9 +29,10 @@ class VBoxPort : public Port
signed int p_vbox_announce_left; /* the number of bytes left of announcement sample */
signed int p_vbox_announce_size; /* size of current announcement (in bytes) */
int p_vbox_mode; /* type of recording VBOX_MODE_* */
double p_vbox_audio_start; /* time stamp of starting of audio (<1 == not yet started) */
long long p_vbox_audio_start; /* time stamp of starting of audio (0 == not yet started) */
unsigned int p_vbox_audio_transferred; /* number of samples sent to endpoint */
signed int p_vbox_record_start; /* start for recording */
struct lcr_timer p_vbox_announce_timer; /* timer for sending announcement */
struct lcr_timer p_vbox_record_timeout; /* timer for recording limit */
signed int p_vbox_record_limit; /* limit for recording */
struct extension p_vbox_ext; /* save settings of extension */