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:
parent
473d6569ef
commit
b0bd74e35e
|
@ -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 \
|
||||
|
|
43
Makefile.in
43
Makefile.in
|
@ -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
2
README
|
@ -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.
|
||||
|
||||
|
||||
|
||||
|
|
56
action.cpp
56
action.cpp
|
@ -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(¤t_time, NULL);
|
||||
if (timeout && TIME_SMALLER(&e_match_timeout.timeout, ¤t_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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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(¤t_time);
|
||||
current_tm = localtime(¤t_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(¤t_time);
|
||||
current_tm = localtime(¤t_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;
|
||||
|
|
409
apppbx.cpp
409
apppbx.cpp
|
@ -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, ¶m->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, ¶m->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
|
||||
|
|
27
apppbx.h
27
apppbx.h
|
@ -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);
|
||||
|
|
116
bchannel.c
116
bchannel.c
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
475
chan_lcr.c
475
chan_lcr.c
|
@ -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, ¶m->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(¶m, 0, sizeof(param));
|
||||
strcpy(param.hello.application, "asterisk");
|
||||
send_message(MESSAGE_HELLO, 0, ¶m);
|
||||
|
||||
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(¶m, 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);
|
||||
|
|
|
@ -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, ...);
|
||||
|
|
60
crypt.cpp
60
crypt.cpp
|
@ -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(¤t_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(¤t_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(¤t_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;
|
||||
|
|
2
crypt.h
2
crypt.h
|
@ -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);
|
||||
|
|
98
dss1.cpp
98
dss1.cpp
|
@ -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(¤t_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
2
dss1.h
|
@ -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 */
|
||||
|
|
23
endpoint.cpp
23
endpoint.cpp
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
151
gsm.cpp
|
@ -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
3
gsm.h
|
@ -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;
|
||||
|
|
9
join.cpp
9
join.cpp
|
@ -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
1
join.h
|
@ -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 */
|
||||
|
|
49
joinpbx.cpp
49
joinpbx.cpp
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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
556
mISDN.cpp
|
@ -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(¤t_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
18
mISDN.h
|
@ -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);
|
||||
|
|
4
macro.h
4
macro.h
|
@ -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
257
main.c
|
@ -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
6
main.h
|
@ -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
|
||||
|
|
80
message.c
80
message.c
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
10
message.h
10
message.h
|
@ -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);
|
||||
|
||||
|
||||
|
|
10
options.c
10
options.c
|
@ -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"
|
||||
|
|
27
port.cpp
27
port.cpp
|
@ -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
3
port.h
|
@ -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
35
route.c
|
@ -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(¤t_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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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(¤t_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(¤t, 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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
|
194
socket_server.c
194
socket_server.c
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
97
ss5.cpp
|
@ -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
4
ss5.h
|
@ -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 */
|
||||
|
|
9
trace.c
9
trace.c
|
@ -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(¤t_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
200
vbox.cpp
|
@ -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(¤ttime);
|
||||
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(¤t_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(¤ttime);
|
||||
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
7
vbox.h
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue