Replaced polling loop for LCR and chan_lcr with select based event loop.
authorAndreas Eversberg <jolly@eversberg.eu>
Sat, 16 Jan 2010 10:20:23 +0000 (11:20 +0100)
committerAndreas Eversberg <jolly@eversberg.eu>
Sat, 16 Jan 2010 10:20:23 +0000 (11:20 +0100)
Now LCR and chan_lcr will not use any CPU until there is work to do.

48 files changed:
Makefile.am
Makefile.in
README
action.cpp
action_vbox.cpp
apppbx.cpp
apppbx.h
bchannel.c
bchannel.h
chan_lcr.c
chan_lcr.h
crypt.cpp
crypt.h
dss1.cpp
dss1.h
endpoint.cpp
endpoint.h
endpointapp.cpp
endpointapp.h
gsm.cpp
gsm.h
join.cpp
join.h
joinpbx.cpp
joinpbx.h
joinremote.cpp
joinremote.h
lcradmin.c
mISDN.cpp
mISDN.h
macro.h
main.c
main.h
message.c
message.h
options.c
port.cpp
port.h
route.c
select.c [new file with mode: 0644]
select.h [new file with mode: 0644]
socket_server.c
socket_server.h
ss5.cpp
ss5.h
trace.c
vbox.cpp
vbox.h

index bce48d1..17f9a29 100644 (file)
@@ -72,7 +72,7 @@ if ENABLE_ASTERISK_CHANNEL_DRIVER
 noinst_PROGRAMS = chan_lcr.so
 chan_lcr_so_SOURCES =
 chan_lcr_so_LDFLAGS = -shared
-chan_lcr_so_LDADD = chan_lcr.po bchannel.po options.po callerid.po
+chan_lcr_so_LDADD = chan_lcr.po bchannel.po options.po callerid.po select.po
 
 chan_lcr.po: chan_lcr.c chan_lcr.h
        $(CC) $(INCLUDES) -D_GNU_SOURCE -fPIC -c chan_lcr.c -o chan_lcr.po
@@ -86,6 +86,9 @@ callerid.po: callerid.c callerid.h
 options.po: options.c options.h
        $(CC) $(INCLUDES) -D_GNU_SOURCE -fPIC -c options.c -o options.po
 
+select.po: select.c select.h
+       $(CC) $(INCLUDES) -D_GNU_SOURCE -fPIC -c select.c -o select.po
+
 install-exec-hook:
        mkdir -p $(astmoddir)
        $(INSTALL) -d $(astmoddir)
@@ -94,7 +97,7 @@ endif
 
 INCLUDES = $(all_includes) $(GSM_INCLUDE) $(SS5_INCLUDE) -Wall -I/usr/include/mISDNuser $(INSTALLATION_DEFINES)
 
-lcr_SOURCES = $(GSM_SOURCE) $(SS5_SOURCE) action.cpp       mISDN.cpp        tones.c \
+lcr_SOURCES = $(GSM_SOURCE) $(SS5_SOURCE) select.c action.cpp       mISDN.cpp        tones.c \
        action_efi.cpp   crypt.cpp        mail.c           trace.c \
        action_vbox.cpp  dss1.cpp         main.c           \
        vbox.cpp alawulaw.c       endpoint.cpp     interface.c     message.c \
index 1bf2262..1a2bd77 100644 (file)
@@ -61,7 +61,8 @@ am_chan_lcr_so_OBJECTS =
 chan_lcr_so_OBJECTS = $(am_chan_lcr_so_OBJECTS)
 @ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@chan_lcr_so_DEPENDENCIES =  \
 @ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@  chan_lcr.po bchannel.po \
-@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@  options.po callerid.po
+@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@  options.po callerid.po \
+@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@  select.po
 am_genextension_OBJECTS = genext.$(OBJEXT) options.$(OBJEXT) \
        extension.$(OBJEXT)
 genextension_OBJECTS = $(am_genextension_OBJECTS)
@@ -78,28 +79,28 @@ genwave_LDADD = $(LDADD)
 am__lcr_SOURCES_DIST = gsm_audio.c gsm.cpp gsm_conf.c \
        openbsc/src/bsc_init.c openbsc/src/vty_interface.c \
        openbsc/src/vty_interface_layer3.c ss5.cpp ss5_encode.c \
-       ss5_decode.c action.cpp mISDN.cpp tones.c action_efi.cpp \
-       crypt.cpp mail.c trace.c action_vbox.cpp dss1.cpp main.c \
-       vbox.cpp alawulaw.c endpoint.cpp interface.c message.c \
-       apppbx.cpp endpointapp.cpp join.cpp options.c extension.c \
-       joinpbx.cpp port.cpp callerid.c joinremote.cpp route.c cause.c \
-       socket_server.c
+       ss5_decode.c select.c action.cpp mISDN.cpp tones.c \
+       action_efi.cpp crypt.cpp mail.c trace.c action_vbox.cpp \
+       dss1.cpp main.c vbox.cpp alawulaw.c endpoint.cpp interface.c \
+       message.c apppbx.cpp endpointapp.cpp join.cpp options.c \
+       extension.c joinpbx.cpp port.cpp callerid.c joinremote.cpp \
+       route.c cause.c socket_server.c
 @ENABLE_GSM_TRUE@am__objects_1 = gsm_audio.$(OBJEXT) gsm.$(OBJEXT) \
 @ENABLE_GSM_TRUE@      gsm_conf.$(OBJEXT) bsc_init.$(OBJEXT) \
 @ENABLE_GSM_TRUE@      vty_interface.$(OBJEXT) \
 @ENABLE_GSM_TRUE@      vty_interface_layer3.$(OBJEXT)
 @ENABLE_SS5_TRUE@am__objects_2 = ss5.$(OBJEXT) ss5_encode.$(OBJEXT) \
 @ENABLE_SS5_TRUE@      ss5_decode.$(OBJEXT)
-am_lcr_OBJECTS = $(am__objects_1) $(am__objects_2) action.$(OBJEXT) \
-       mISDN.$(OBJEXT) tones.$(OBJEXT) action_efi.$(OBJEXT) \
-       crypt.$(OBJEXT) mail.$(OBJEXT) trace.$(OBJEXT) \
-       action_vbox.$(OBJEXT) dss1.$(OBJEXT) main.$(OBJEXT) \
-       vbox.$(OBJEXT) alawulaw.$(OBJEXT) endpoint.$(OBJEXT) \
-       interface.$(OBJEXT) message.$(OBJEXT) apppbx.$(OBJEXT) \
-       endpointapp.$(OBJEXT) join.$(OBJEXT) options.$(OBJEXT) \
-       extension.$(OBJEXT) joinpbx.$(OBJEXT) port.$(OBJEXT) \
-       callerid.$(OBJEXT) joinremote.$(OBJEXT) route.$(OBJEXT) \
-       cause.$(OBJEXT) socket_server.$(OBJEXT)
+am_lcr_OBJECTS = $(am__objects_1) $(am__objects_2) select.$(OBJEXT) \
+       action.$(OBJEXT) mISDN.$(OBJEXT) tones.$(OBJEXT) \
+       action_efi.$(OBJEXT) crypt.$(OBJEXT) mail.$(OBJEXT) \
+       trace.$(OBJEXT) action_vbox.$(OBJEXT) dss1.$(OBJEXT) \
+       main.$(OBJEXT) vbox.$(OBJEXT) alawulaw.$(OBJEXT) \
+       endpoint.$(OBJEXT) interface.$(OBJEXT) message.$(OBJEXT) \
+       apppbx.$(OBJEXT) endpointapp.$(OBJEXT) join.$(OBJEXT) \
+       options.$(OBJEXT) extension.$(OBJEXT) joinpbx.$(OBJEXT) \
+       port.$(OBJEXT) callerid.$(OBJEXT) joinremote.$(OBJEXT) \
+       route.$(OBJEXT) cause.$(OBJEXT) socket_server.$(OBJEXT)
 lcr_OBJECTS = $(am_lcr_OBJECTS)
 am__DEPENDENCIES_1 =
 @ENABLE_GSM_TRUE@am__DEPENDENCIES_2 = /usr/lib/libgsm.a \
@@ -258,9 +259,9 @@ INSTALLATION_DEFINES = \
 @ENABLE_SS5_TRUE@SS5_SOURCE = ss5.cpp ss5_encode.c ss5_decode.c
 @ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@chan_lcr_so_SOURCES = 
 @ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@chan_lcr_so_LDFLAGS = -shared
-@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@chan_lcr_so_LDADD = chan_lcr.po bchannel.po options.po callerid.po
+@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@chan_lcr_so_LDADD = chan_lcr.po bchannel.po options.po callerid.po select.po
 INCLUDES = $(all_includes) $(GSM_INCLUDE) $(SS5_INCLUDE) -Wall -I/usr/include/mISDNuser $(INSTALLATION_DEFINES)
-lcr_SOURCES = $(GSM_SOURCE) $(SS5_SOURCE) action.cpp       mISDN.cpp        tones.c \
+lcr_SOURCES = $(GSM_SOURCE) $(SS5_SOURCE) select.c action.cpp       mISDN.cpp        tones.c \
        action_efi.cpp   crypt.cpp        mail.c           trace.c \
        action_vbox.cpp  dss1.cpp         main.c           \
        vbox.cpp alawulaw.c       endpoint.cpp     interface.c     message.c \
@@ -446,6 +447,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/options.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/port.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/route.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/select.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket_server.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss5.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss5_decode.Po@am__quote@
@@ -819,6 +821,9 @@ uninstall-am: uninstall-binPROGRAMS uninstall-info-am \
 @ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@options.po: options.c options.h
 @ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@  $(CC) $(INCLUDES) -D_GNU_SOURCE -fPIC -c options.c -o options.po
 
+@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@select.po: select.c select.h
+@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@  $(CC) $(INCLUDES) -D_GNU_SOURCE -fPIC -c select.c -o select.po
+
 @ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@install-exec-hook:
 @ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@  mkdir -p $(astmoddir)
 @ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@  $(INSTALL) -d $(astmoddir)
diff --git a/README b/README
index c495bd7..2515150 100644 (file)
--- a/README
+++ b/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.
 
 
 
index d720dbe..bf7c23d 100644 (file)
@@ -644,16 +644,16 @@ void EndpointAppPBX::action_dialing_login(void)
                e_ruleset = NULL;
                e_rule = NULL;
                e_action = &action_password;
-               e_match_timeout = 0;
+               unsched_timer(&e_match_timeout);
                e_match_to_action = NULL;
                e_dialinginfo.id[0] = '\0';
                e_extdialing = strchr(e_dialinginfo.id, '\0');
 
                /* set timeout */
-               e_password_timeout = now+20;
+               schedule_timer(&e_password_timeout, 20, 0);
 
                /* do dialing */
-               process_dialing();
+               process_dialing(0);
        } else {
                /* make call state  */
                new_state(EPOINT_STATE_IN_OVERLAP);
@@ -945,7 +945,7 @@ void EndpointAppPBX::_action_redial_reply(int in)
                SCPY(e_dialinginfo.id, last);
                e_extdialing = e_dialinginfo.id;
                e_action = NULL;
-               process_dialing();
+               process_dialing(0);
                return;
        }
        e_extdialing[0] = '\0';
@@ -1039,10 +1039,10 @@ void EndpointAppPBX::action_dialing_powerdial(void)
 
        /* do dialing */
        SCPY(e_dialinginfo.id, e_ext.last_out[0]);
-       e_powerdialing = -1; /* indicates the existence of powerdialing but no redial time given */
+       e_powerdial_on = 1; /* indicates the existence of powerdialing but no redial time given */
        e_powercount = 0;
        e_action = NULL;
-       process_dialing();
+       process_dialing(0);
 }
 
 
@@ -1144,7 +1144,7 @@ void EndpointAppPBX::action_hangup_callback(void)
        end_trace();
 
        /* set time to callback */
-       e_callback = now_d + delay;
+       schedule_timer(&e_callback_timeout, delay, 0);
 }
 
 
@@ -1197,7 +1197,7 @@ void EndpointAppPBX::action_dialing_abbrev(void)
        SCPY(e_dialinginfo.id, phone);
        e_extdialing = e_dialinginfo.id;
        e_action = NULL;
-       process_dialing();
+       process_dialing(0);
 }
 
 
@@ -1701,7 +1701,7 @@ void EndpointAppPBX::_action_goto_menu(int mode)
 
        /* do dialing with new ruleset */
        e_action = NULL;
-       process_dialing();
+       process_dialing(0);
 }
 
 /* process dialing goto
@@ -1839,7 +1839,7 @@ void EndpointAppPBX::action_dialing_help(void)
                e_extdialing = e_dialinginfo.id+strlen(numbering->prefix);
                PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s selected a new menu '%s' dialing: %s\n", ea_endpoint->ep_serial, e_ext.number, numb_actions[numbering->action], e_dialinginfo.id);
 nesting?:
-               process_dialing();
+               process_dialing(0);
                return;
        }
 
@@ -2098,11 +2098,16 @@ void EndpointAppPBX::action_dialing_password_wr(void)
  * depending on the detected prefix, subfunctions above (action_*) will be
  * calles.
  */
-void EndpointAppPBX::process_dialing(void)
+void EndpointAppPBX::process_dialing(int timeout)
 {
        struct port_list *portlist = ea_endpoint->ep_portlist;
        struct lcr_msg *message;
        struct route_param *rparam;
+       struct timeval current_time;
+
+       /* set if timeout is active, or if timeout value was given due to timeout action */
+       if (e_action_timeout.active)
+               timeout = 1;
 
 //#warning Due to HANG-BUG somewhere here, I added some HANG-BUG-DEBUGGING output that cannot be disabled. after bug has been found, this will be removed.
 //PDEBUG(~0, "HANG-BUG-DEBUGGING: entered porcess_dialing\n");
@@ -2111,8 +2116,8 @@ void EndpointAppPBX::process_dialing(void)
        if (!portlist) {
                portlist_error:
                PDEBUG(DEBUG_EPOINT, "EPOINT(%d): note: dialing call requires exactly one port object to process dialing. this case could happen due to a parked call. we end dialing here.\n", ea_endpoint->ep_serial, e_ext.number);
-               e_action_timeout = 0;
-               e_match_timeout = 0;
+               unsched_timer(&e_action_timeout);
+               unsched_timer(&e_match_timeout);
                return;
        }
        if (portlist->next) {
@@ -2127,15 +2132,15 @@ void EndpointAppPBX::process_dialing(void)
                new_state(EPOINT_STATE_OUT_DISCONNECT);
                message_disconnect_port(portlist, CAUSE_UNSPECIFIED, LOCATION_PRIVATE_LOCAL, "");
                set_tone(portlist, "cause_3f");
-               e_action_timeout = 0;
-               e_match_timeout = 0;
+               unsched_timer(&e_action_timeout);
+               unsched_timer(&e_match_timeout);
                goto end;
        }
 
 //PDEBUG(~0, "HANG-BUG-DEBUGGING: before action-timeout processing\n");
        /* process timeout */
-       if (e_action && e_action_timeout) { /* e_action may be NULL, but e_action_timeout may still be set and must be ignored */
-               e_action_timeout = 0;
+       if (e_action && timeout) { /* e_action may be NULL, but e_action_timeout may still be set and must be ignored */
+               unsched_timer(&e_action_timeout);
                if (e_state == EPOINT_STATE_CONNECT) {
                        PDEBUG(DEBUG_ROUTE|DEBUG_EPOINT, "EPOINT(%d): action timed out, but we already have connected, so we stop timer and continue.\n", ea_endpoint->ep_serial);
                        goto end;
@@ -2163,7 +2168,7 @@ void EndpointAppPBX::process_dialing(void)
        if (e_state!=EPOINT_STATE_IN_SETUP
         && e_state!=EPOINT_STATE_IN_OVERLAP) {
                PDEBUG(DEBUG_EPOINT, "EPOINT(%d): we are not in incoming setup/overlap state, so we ignore init/dialing process.\n", ea_endpoint->ep_serial, e_rule_nesting);
-               e_match_timeout = 0;
+               unsched_timer(&e_match_timeout);
                goto end;
        }
 
@@ -2176,8 +2181,8 @@ void EndpointAppPBX::process_dialing(void)
                        e_dialinginfo.id[0] = '\0';
                        e_action = NUMB_ACTION_MENU;
                        e_menu = 0;
-                       process_dialing();
-                       e_match_timeout = 0;
+                       process_dialing(0);
+                       unsched_timer(&e_match_timeout);
                        goto end;
                }
                /* invalid dialing */
@@ -2194,7 +2199,7 @@ void EndpointAppPBX::process_dialing(void)
                }
                new_state(EPOINT_STATE_OUT_DISCONNECT);
                set_tone(portlist,"cause_1c");
-               e_match_timeout = 0;
+               unsched_timer(&e_match_timeout);
                goto end;
        }
 #endif
@@ -2230,10 +2235,11 @@ void EndpointAppPBX::process_dialing(void)
                        goto process_action;
                }
 
-               if (e_match_timeout && now_d>=e_match_timeout) {
+               gettimeofday(&current_time, NULL);
+               if (timeout && TIME_SMALLER(&e_match_timeout.timeout, &current_time)) {
                        /* return timeout rule */
                        PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal '%s' dialing: '%s', timeout in ruleset '%s'\n", ea_endpoint->ep_serial, e_ext.number, e_dialinginfo.id, e_ruleset->name);
-                       e_match_timeout = 0;
+                       unsched_timer(&e_match_timeout);
                        e_action = e_match_to_action;
                        e_extdialing = e_match_to_extdialing;
                        trace_header("ROUTING (timeout)", DIRECTION_NONE);
@@ -2272,9 +2278,9 @@ void EndpointAppPBX::process_dialing(void)
                action_timeout:
 
                /* set timeout */
-               e_action_timeout = 0;
+               unsched_timer(&e_action_timeout);
                if (e_action->timeout) {
-                       e_action_timeout = now_d + e_action->timeout;
+                       schedule_timer(&e_action_timeout, e_action->timeout, 0);
                        PDEBUG(DEBUG_ROUTE|DEBUG_EPOINT, "EPOINT(%d): action has a timeout of %d secods.\n", ea_endpoint->ep_serial, e_action->timeout);
                }
 
index e325c0f..120bfa6 100644 (file)
@@ -101,7 +101,7 @@ void EndpointAppPBX::action_init_vbox_play(void)
 
        e_vbox_state = VBOX_STATE_MENU;
        SCPY(e_vbox_display, (char *)((language)?"druecke 2 f. wiedergabe":"press 2 to play"));
-       e_vbox_display_refresh = 1;
+       schedule_timer(&e_vbox_refresh, 0, 0);
        set_tone_vbox("menu");
 
        e_vbox_menu = -1;
@@ -112,7 +112,7 @@ void EndpointAppPBX::action_init_vbox_play(void)
        if (e_vbox_index_num == 0) {
                e_vbox_state = VBOX_STATE_NOTHING;
                SCPY(e_vbox_display, (char *)((language)?"keine Anrufe":"no calls"));
-               e_vbox_display_refresh = 1;
+               schedule_timer(&e_vbox_refresh, 0, 0);
                set_tone_vbox("nothing");
        }
 }
@@ -232,6 +232,8 @@ void EndpointAppPBX::action_dialing_vbox_play(void)
        int language = e_ext.vbox_language;
        struct port_list *portlist;
        class Port *port;
+       time_t current_time;
+       struct tm *current_tm;
        
        portlist = ea_endpoint->ep_portlist;
 
@@ -242,7 +244,7 @@ void EndpointAppPBX::action_dialing_vbox_play(void)
 
        PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing digit: %c\n", ea_endpoint->ep_serial, e_extdialing[0]);
 
-       e_vbox_display_refresh = 1;
+       schedule_timer(&e_vbox_refresh, 0, 0);
 
        if (e_vbox_state == VBOX_STATE_RECORD_RECORD) {
                if (e_extdialing[0] == '1' || e_extdialing[0] == '0') {
@@ -280,10 +282,10 @@ void EndpointAppPBX::action_dialing_vbox_play(void)
                        PDEBUG(DEBUG_EPOINT, "EPOINT(%d) play recoding.\n", ea_endpoint->ep_serial);
                        /* play announcement */
                        e_vbox_counter = 0;
-                       e_vbox_counter_last = 0;
                        e_vbox_counter_max = 0;
                        e_vbox_speed = 1;
                        e_vbox_state = VBOX_STATE_RECORD_PLAY;
+                       schedule_timer(&e_vbox_refresh, 0, 0);
                        if (e_ext.vbox_language)
                                SCPY(e_vbox_display, "Wied., 1=stop %s");
                        else
@@ -396,10 +398,12 @@ void EndpointAppPBX::action_dialing_vbox_play(void)
                e_vbox_state = VBOX_STATE_CALLINFO_INTRO;
                SPRINT(e_vbox_display, "#%d", e_vbox_play+1);
                vbox_index_read(e_vbox_play);
-               if (e_vbox_index_mon!=now_tm->tm_mon || e_vbox_index_year!=now_tm->tm_year) {
+               time(&current_time);
+               current_tm = localtime(&current_time);
+               if (e_vbox_index_mon!=current_tm->tm_mon || e_vbox_index_year!=current_tm->tm_year) {
                        UPRINT(strchr(e_vbox_display,'\0'), " %s", (language)?months_german[e_vbox_index_mon]:months_english[e_vbox_index_mon]);
                }
-               if (e_vbox_index_mday!=now_tm->tm_mday || e_vbox_index_mon!=now_tm->tm_mon || e_vbox_index_year!=now_tm->tm_year) {
+               if (e_vbox_index_mday!=current_tm->tm_mday || e_vbox_index_mon!=current_tm->tm_mon || e_vbox_index_year!=current_tm->tm_year) {
                        UPRINT(strchr(e_vbox_display,'\0'), " %d", e_vbox_index_mday);
                }
                UPRINT(strchr(e_vbox_display,'\0'), " %02d:%02d", e_vbox_index_hour, e_vbox_index_min);
@@ -419,10 +423,10 @@ void EndpointAppPBX::action_dialing_vbox_play(void)
                        PDEBUG(DEBUG_EPOINT, "EPOINT(%d) play call #%d. abborting announcement and starting with playback\n", ea_endpoint->ep_serial, e_vbox_play+1);
                        /* the callinfo is played, so we start with the call */
                        e_vbox_counter = 0;
-                       e_vbox_counter_last = 0;
                        e_vbox_counter_max = 0;
                        e_vbox_speed = 1;
                        e_vbox_state = VBOX_STATE_PLAY;
+                       schedule_timer(&e_vbox_refresh, 0, 0);
                        SPRINT(e_vbox_display, "#%d %%s", e_vbox_play+1);
                        if (e_ext.vbox_display == VBOX_DISPLAY_DETAILED)
                                UPRINT(strchr(e_vbox_display,'\0'), " (%s)", e_vbox_index_callerid);
@@ -558,7 +562,7 @@ void EndpointAppPBX::action_dialing_vbox_play(void)
                                SPRINT(e_dialinginfo.id, "extern:%s", e_vbox_index_callerid);
                                e_extdialing = e_dialinginfo.id;
                                e_action = NULL;
-                               process_dialing();
+                               process_dialing(0);
                                return;
                        }
                        break;
@@ -600,31 +604,35 @@ void EndpointAppPBX::action_dialing_vbox_play(void)
 /*
  * this handler is called by Epoint::handler(), whenever the action is NUMB_ACTION_VBOX_PLAY
  */
-void EndpointAppPBX::vbox_handler(void)
+int vbox_refresh(struct lcr_timer *timer, void *instance, int index)
 {
-       /* refresh if counter changes */
-       if (e_vbox_state==VBOX_STATE_PLAY || e_vbox_state==VBOX_STATE_RECORD_PLAY)
-       if (e_vbox_counter != e_vbox_counter_last) {
-               e_vbox_counter_last = e_vbox_counter;
-               e_vbox_display_refresh = 1;
-       }
+       class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
 
-       /* refresh display, if required (include counter) */
-       if (e_vbox_display_refresh && e_ext.vbox_display!=VBOX_DISPLAY_OFF) {
-               char counter[32];
-               struct lcr_msg *message;
-
-               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);
-
-               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);
-       }
+       /* no display */
+       if (ea->e_ext.vbox_display == VBOX_DISPLAY_OFF)
+               return 0;
+
+       /* refresh display */
+       char counter[32];
+       struct lcr_msg *message;
+
+       SPRINT(counter, "%02d:%02d", ea->e_vbox_counter/60, ea->e_vbox_counter%60);
+       if (ea->e_vbox_counter_max)
+               UPRINT(strchr(counter,'\0'), " of %02d:%02d", ea->e_vbox_counter_max/60, ea->e_vbox_counter_max%60);
+
+       message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
+       SPRINT(message->param.notifyinfo.display, ea->e_vbox_display, counter);
+       PDEBUG(DEBUG_EPOINT, "EPOINT(%d) terminal %s pending display:%s\n", ea->ea_endpoint->ep_serial, ea->e_ext.number, message->param.notifyinfo.display);
+       message_put(message);
+       ea->logmessage(message->type, &message->param, ea->ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
+
+       /* not playing anymore */
+       if (!ea->e_vbox_state==VBOX_STATE_PLAY && !ea->e_vbox_state==VBOX_STATE_RECORD_PLAY)
+               return 0;
+       
+       schedule_timer(&ea->e_vbox_refresh, 1, 0);
+
+       return 0;
 }
 
 
@@ -636,6 +644,8 @@ void EndpointAppPBX::vbox_message_eof(void)
 {
        char buffer[32];
        int language = e_ext.vbox_language;
+       time_t current_time;
+       struct tm *current_tm;
 
        PDEBUG(DEBUG_EPOINT, "EPOINT(%d) terminal %s end of file during state: %d\n", ea_endpoint->ep_serial, e_ext.number, e_vbox_state);
 
@@ -644,7 +654,7 @@ void EndpointAppPBX::vbox_message_eof(void)
                case VBOX_STATE_NOTHING:
                e_vbox_state = VBOX_STATE_MENU;
                SCPY(e_vbox_display, (char *)((language)?"druecke 2 f. wiedergabe":"press 2 to play"));
-               e_vbox_display_refresh = 1;
+               schedule_timer(&e_vbox_refresh, 0, 0);
                set_tone_vbox("menu");
                break;
 
@@ -652,7 +662,7 @@ void EndpointAppPBX::vbox_message_eof(void)
                if (e_vbox_speed > 0) {
                        e_vbox_state = VBOX_STATE_MENU;
                        SCPY(e_vbox_display, (char *)((language)?"druecke 3 f. Naechste":"press 3 for next"));
-                       e_vbox_display_refresh = 1;
+               schedule_timer(&e_vbox_refresh, 0, 0);
                        set_tone_vbox("menu");
                } else {
                        /* if we have endoffile because we were playing backwards, we continue to play forward */
@@ -664,11 +674,13 @@ void EndpointAppPBX::vbox_message_eof(void)
 
                case VBOX_STATE_PAUSE:
                SCPY(e_vbox_display, (char *)((language)?"druecke 2 f. weiterspielen":"press 2 to continue"));
-               e_vbox_display_refresh = 1;
+               schedule_timer(&e_vbox_refresh, 0, 0);
                break;
 
                case VBOX_STATE_CALLINFO_INTRO:
-               if (e_vbox_index_mday==now_tm->tm_mday && e_vbox_index_mon==now_tm->tm_mon && e_vbox_index_year==now_tm->tm_year)
+               time(&current_time);
+               current_tm = localtime(&current_time);
+               if (e_vbox_index_mday==current_tm->tm_mday && e_vbox_index_mon==current_tm->tm_mon && e_vbox_index_year==current_tm->tm_year)
                        goto skip_day_month;
                e_vbox_state = VBOX_STATE_CALLINFO_MONTH; //german day
                if (e_ext.vbox_language)
@@ -764,37 +776,37 @@ void EndpointAppPBX::vbox_message_eof(void)
                } else {
                        /* the callinfo is played, so we start with the call */
                        e_vbox_counter = 0;
-                       e_vbox_counter_last = 0;
                        e_vbox_counter_max = 0;
                        e_vbox_speed = 1;
                        e_vbox_state = VBOX_STATE_PLAY;
+                       schedule_timer(&e_vbox_refresh, 0, 0);
                        SPRINT(e_vbox_display, "#%d %%s", e_vbox_play);
                        if (e_ext.vbox_display == VBOX_DISPLAY_DETAILED)
                                UPRINT(strchr(e_vbox_display,'\0'), " (%s)", e_vbox_index_callerid);
-                       e_vbox_display_refresh = 1;
+                       schedule_timer(&e_vbox_refresh, 0, 0);
                        set_play_vbox(e_vbox_index_file, 0);
                }
                break;
 
                case VBOX_STATE_RECORD_ASK:
                set_tone_vbox("record_ask");
-               e_vbox_display_refresh = 1;
+               schedule_timer(&e_vbox_refresh, 0, 0);
                break;
 
                case VBOX_STATE_STORE_ASK:
                set_tone_vbox("store_ask");
-               e_vbox_display_refresh = 1;
+               schedule_timer(&e_vbox_refresh, 0, 0);
                break;
 
                case VBOX_STATE_DELETE_ASK:
                set_tone_vbox("delete_ask");
-               e_vbox_display_refresh = 1;
+               schedule_timer(&e_vbox_refresh, 0, 0);
                break;
 
                case VBOX_STATE_RECORD_PLAY:
                e_vbox_state = VBOX_STATE_RECORD_ASK;
                SCPY(e_vbox_display, (char *)((language)?"1=Aufn. 2=Wied. 3=nein":"1=record 2=play 3=no"));
-               e_vbox_display_refresh = 1;
+               schedule_timer(&e_vbox_refresh, 0, 0);
                set_tone_vbox("record_ask");
                break;
 
@@ -803,12 +815,12 @@ void EndpointAppPBX::vbox_message_eof(void)
                if (e_vbox_index_num == 0) { /* nothing to play */
                        e_vbox_state = VBOX_STATE_MENU;
                        SCPY(e_vbox_display, (char *)((language)?"keine Anrufe":"no calls"));
-                       e_vbox_display_refresh = 1;
+               schedule_timer(&e_vbox_refresh, 0, 0);
                        set_tone_vbox("nothing");
                } else {
                        e_vbox_state = VBOX_STATE_MENU;
                        SCPY(e_vbox_display, (char *)((language)?"druecke 2 f. wiedergabe":"press 2 to play"));
-                       e_vbox_display_refresh = 1;
+               schedule_timer(&e_vbox_refresh, 0, 0);
                        set_tone_vbox("menu");
                }
                break;
index 9858207..46b1f62 100644 (file)
 
 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)
 
 }
 
+int action_timeout(struct lcr_timer *timer, void *instance, int index)
+{
+       class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
 
-/* handler for endpoint
- */
+       if (!ea->e_action || ea->e_state == EPOINT_STATE_CONNECT)
+               return 0;
+
+       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 */
 
-extern int quit;
-int EndpointAppPBX::handler(void)
+       return 0;
+}
+
+int match_timeout(struct lcr_timer *timer, void *instance, int index)
 {
-       if (e_crypt_state!=CM_ST_NULL) {
-               cryptman_handler();
-       }
-
-       /* process answering machine (play) handling */
-       if (e_action) {
-               if (e_action->index == ACTION_VBOX_PLAY)
-                       vbox_handler();
-
-               /* 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 */
-               }
+       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;
+}
 
-       /* 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);
+int redial_timeout(struct lcr_timer *timer, void *instance, int index)
+{
+       class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
 
-                       new_state(EPOINT_STATE_OUT_SETUP);
-                       /* call special setup routine */
-                       out_setup();
+       PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial.\n", ea->ea_endpoint->ep_serial);
 
-                       return(1);
-               }
-       }
+       ea->new_state(EPOINT_STATE_OUT_SETUP);
+       /* call special setup routine */
+       ea->out_setup();
 
-       /* 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);
+       return 0;
+}
 
-                       /* 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);
-               }
-       }
+int powerdial_timeout(struct lcr_timer *timer, void *instance, int index)
+{
+       class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
 
-       /* process call forward no response */
-       if (e_cfnr_release) {
-               struct port_list *portlist;
-               struct lcr_msg *message;
+       /* leave power dialing on */
+       ea->e_powerdial_on = 1;
+       PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial of powerdial.\n", ea->ea_endpoint->ep_serial);
 
-               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;
+       /* 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);
 
-                       /* 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;
-               }
+       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);
 
-       /* handle connection to user */
-       if (e_state == EPOINT_STATE_IDLE) {
+       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 */
-               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);
-               }
+               PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting callback.\n", ea->ea_endpoint->ep_serial);
+               ea->new_state(EPOINT_STATE_OUT_SETUP);
+               ea->out_setup();
        }
 
-       /* check for password timeout */
-       if (e_action)
-       if (e_action->index==ACTION_PASSWORD || e_action->index==ACTION_PASSWORD_WRITE) {
+       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;
 
-               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);
+               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);
-}
 
+       return 0;
+}
 
 /* doing a hookflash */
 void EndpointAppPBX::hookflash(void)
 {
        class Port *port;
+       time_t now;
 
        /* be sure that we are active */
        notify_active();
@@ -1408,10 +1437,11 @@ void EndpointAppPBX::hookflash(void)
        e_join_pattern = 0;
        if (e_dialinginfo.id[0]) {
                set_tone(ea_endpoint->ep_portlist, "dialing");
-               process_dialing();
+               process_dialing(0);
        } else {
                set_tone(ea_endpoint->ep_portlist, "dialpbx");
        }
+       time(&now);
        e_dtmf_time = now;
        e_dtmf_last = '\0';
 }
@@ -1566,7 +1596,7 @@ void EndpointAppPBX::port_setup(struct port_list *portlist, int message_type, un
                else
                        set_tone(portlist, "dialtone");
        }
-       process_dialing();
+       process_dialing(0);
        if (e_state == EPOINT_STATE_IN_SETUP) {
                /* request MORE info, if not already at higher state */
                new_state(EPOINT_STATE_IN_OVERLAP);
@@ -1599,7 +1629,7 @@ void EndpointAppPBX::port_information(struct port_list *portlist, int message_ty
        if (e_action->index == ACTION_VBOX_PLAY) {
                /* concat dialing string */
                SCAT(e_dialinginfo.id, param->information.id);
-               process_dialing();
+               process_dialing(0);
                return;
        }
 
@@ -1656,12 +1686,16 @@ void EndpointAppPBX::port_information(struct port_list *portlist, int message_ty
        }
        /* concat dialing string */
        SCAT(e_dialinginfo.id, param->information.id);
-       process_dialing();
+       process_dialing(0);
 }
 
 /* port MESSAGE_DTMF */
 void EndpointAppPBX::port_dtmf(struct port_list *portlist, int message_type, union parameter *param)
 {
+       time_t now;
+
+       time(&now);
+
        /* only if dtmf detection is enabled */
        if (!e_dtmf) {
                trace_header("DTMF (disabled)", DIRECTION_IN);
@@ -1681,7 +1715,7 @@ NOTE: vbox is now handled due to overlap state
                if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
                        e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
                        e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
-                       process_dialing();
+                       process_dialing(0);
                }
                /* continue to process *X# sequences */
        }
@@ -1755,7 +1789,7 @@ NOTE: vbox is now handled due to overlap state
                if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
                        e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
                        e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
-                       process_dialing();
+                       process_dialing(0);
                }
        }
 }
@@ -1909,6 +1943,7 @@ void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type,
        struct port_list *tportlist;
        class Port *port;
        struct interface        *interface;
+       time_t now;
 
        logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
 
@@ -1932,6 +1967,7 @@ void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type,
        }
        PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (end)\n", ea_endpoint->ep_serial);
 
+       time(&now);
        e_start = now;
 
        /* screen incoming connected id */
@@ -1979,7 +2015,8 @@ void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type,
                message_put(message);
        }
 
-       e_cfnr_call = e_cfnr_release = 0;
+       unsched_timer(&e_cfnr_timeout);
+       unsched_timer(&e_cfnr_call_timeout);
        if (e_ext.number[0])
                e_dtmf = 1; /* allow dtmf */
 
@@ -2053,12 +2090,12 @@ void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type,
                        /* make call state to enter password */
                        new_state(EPOINT_STATE_IN_OVERLAP);
                        e_action = &action_password_write;
-                       e_match_timeout = 0;
+                       unsched_timer(&e_match_timeout);
                        e_match_to_action = NULL;
                        e_dialinginfo.id[0] = '\0';
                        e_extdialing = strchr(e_dialinginfo.id, '\0');
-                       e_password_timeout = now+20;
-                       process_dialing();
+                       schedule_timer(&e_password_timeout, 20, 0);
+                       process_dialing(0);
                } else {
                        /* incoming call (callback) */
                        e_ruleset = ruleset_main;
@@ -2068,7 +2105,7 @@ void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type,
                        e_extdialing = e_dialinginfo.id;
                        if (e_dialinginfo.id[0]) {
                                set_tone(portlist, "dialing");
-                               process_dialing();
+                               process_dialing(0);
                        } else {
                                set_tone(portlist, "dialpbx");
                        }
@@ -2151,7 +2188,8 @@ void EndpointAppPBX::port_disconnect_release(struct port_list *portlist, int mes
                }
        }
 
-       e_cfnr_call = e_cfnr_release = 0;
+       unsched_timer(&e_cfnr_timeout);
+       unsched_timer(&e_cfnr_call_timeout);
 
        /* process hangup */
        process_hangup(e_join_cause, e_join_location);
@@ -2816,6 +2854,7 @@ void EndpointAppPBX::join_alerting(struct port_list *portlist, int message_type,
 void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type, union parameter *param)
 {
        struct lcr_msg *message;
+       time_t now;
 
        new_state(EPOINT_STATE_CONNECT);
 //                     UCPY(e_join_tone, "");
@@ -2823,7 +2862,8 @@ void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type,
        if (e_ext.number[0])
                e_dtmf = 1; /* allow dtmf */
 
-       e_powerdialing = 0;
+       e_powerdial_on = 0;
+       unsched_timer(&e_powerdial_timeout);
        memcpy(&e_connectinfo, &param->connectinfo, sizeof(e_callerinfo));
        if(portlist) {
                message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
@@ -2860,6 +2900,7 @@ void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type,
        message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
        message->param.audiopath = 1;
        message_put(message);
+       time(&now);
        e_start = now;
 }
 
@@ -2869,18 +2910,19 @@ void EndpointAppPBX::join_disconnect_release(int message_type, union parameter *
        char cause[16];
        struct lcr_msg *message;
        struct port_list *portlist = NULL;
+       time_t now;
 
 
        /* be sure that we are active */
        notify_active();
        e_tx_state = NOTIFY_STATE_ACTIVE;
 
-       /* we are powerdialing, if e_powerdialing is set and limit is not exceeded if given */
-       if (e_powerdialing && ((e_powercount+1)<e_powerlimit || e_powerlimit<1)) {
+       /* we are powerdialing, if e_powerdial_on is set and limit is not exceeded if given */
+       if (e_powerdial_on && ((e_powercount+1)<e_powerlimit || e_powerlimit<1)) {
                release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
 
                /* set time for power dialing */
-               e_powerdialing = now_d + e_powerdelay; /* set redial in the future */
+               schedule_timer(&e_powerdial_timeout, (int)e_powerdelay, 0); /* set redial in the future */
                e_powercount++;
 
                /* set redial tone */
@@ -2918,6 +2960,7 @@ void EndpointAppPBX::join_disconnect_release(int message_type, union parameter *
        }
 
        /* set stop time */
+       time(&now);
        e_stop = now;
 
        if ((e_state!=EPOINT_STATE_CONNECT
@@ -3002,11 +3045,11 @@ void EndpointAppPBX::join_setup(struct port_list *portlist, int message_type, un
                        new_state(EPOINT_STATE_OUT_OVERLAP);
 
                        /* get time */
-                       e_redial = now_d + 1; /* set redial one second in the future */
+                       schedule_timer(&e_redial_timeout, 1, 0);
                        return;
                }
                /* if we have a pending redial, so we just adjust the dialing number */
-               if (e_redial) {
+               if (e_redial_timeout.active) {
                        PDEBUG(DEBUG_EPOINT, "EPOINT(%d) redial in progress, so we update the dialing number to %s.\n", ea_endpoint->ep_serial, param->setup.dialinginfo.id);
                        memcpy(&e_dialinginfo, &param->setup.dialinginfo, sizeof(e_dialinginfo));
                        return;
@@ -3525,7 +3568,7 @@ reject:
        message_put(message);
 
        /* beeing paranoid, we make call update */
-       joinpbx->j_updatebridge = 1;
+       trigger_work(&joinpbx->j_updatebridge);
 
        if (options.deb & DEBUG_EPOINT) {
                class Join *debug_c = join_first;
@@ -3703,7 +3746,7 @@ void EndpointAppPBX::join_join(void)
        PDEBUG(DEBUG_EPOINT, "EPOINT(%d)d-join completely removed!\n");
 
        /* mixer must update */
-       our_joinpbx->j_updatebridge = 1; /* update mixer flag */
+       trigger_work(&our_joinpbx->j_updatebridge);
 
        /* we send a retrieve to that endpoint */
        // mixer will update the hold-state of the join and send it to the endpoints is changes
index 78355b5..b10a119 100644 (file)
--- a/apppbx.h
+++ b/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);
index fd3e33d..9e878fe 100644 (file)
@@ -50,6 +50,7 @@
 #include "message.h"
 #include "lcrsocket.h"
 #include "cause.h"
+#include "select.h"
 #include "bchannel.h"
 #include "chan_lcr.h"
 #include "callerid.h"
@@ -73,7 +74,7 @@ int bchannel_initialize(void)
 {
        init_af_isdn();
 
-       return(0);
+       return 0;
 }
 
 void bchannel_deinitialize(void)
@@ -123,6 +124,7 @@ static void ph_control_block(int sock, unsigned int c1, void *c2, int c2_len, ch
                CERROR(NULL, NULL, "Failed to send to socket %d\n", sock);
 }
 
+static int bchannel_handle(struct lcr_fd *fd, unsigned int what, void *instance, int index);
 
 /*
  * create stack
@@ -130,12 +132,11 @@ static void ph_control_block(int sock, unsigned int c1, void *c2, int c2_len, ch
 int bchannel_create(struct bchannel *bchannel, int mode)
 {
        int ret;
-       unsigned int on = 1;
        struct sockaddr_mISDN addr;
 
        if (bchannel->b_sock > -1) {
                CERROR(bchannel->call, NULL, "Socket already created for handle 0x%x\n", bchannel->handle);
-               return(0);
+               return 0;
        }
 
        /* open socket */
@@ -160,18 +161,14 @@ int bchannel_create(struct bchannel *bchannel, int mode)
        }
        if (bchannel->b_sock < 0) {
                CERROR(bchannel->call, NULL, "Failed to open bchannel-socket for handle 0x%x with mISDN-DSP layer. Did you load mISDN_dsp.ko?\n", bchannel->handle);
-               return(0);
-       }
-       
-       /* set nonblocking io */
-       ret = ioctl(bchannel->b_sock, FIONBIO, &on);
-       if (ret < 0) {
-               CERROR(bchannel->call, NULL, "Failed to set bchannel-socket handle 0x%x into nonblocking IO\n", bchannel->handle);
-               close(bchannel->b_sock);
-               bchannel->b_sock = -1;
-               return(0);
+               return 0;
        }
 
+       /* register fd */
+       memset(&bchannel->lcr_fd, 0, sizeof(bchannel->lcr_fd));
+       bchannel->lcr_fd.fd = bchannel->b_sock;
+       register_fd(&bchannel->lcr_fd, LCR_FD_READ | LCR_FD_EXCEPT, bchannel_handle, bchannel, 0);
+
        /* bind socket to bchannel */
        addr.family = AF_ISDN;
        addr.dev = (bchannel->handle>>8);
@@ -179,11 +176,12 @@ int bchannel_create(struct bchannel *bchannel, int mode)
        ret = bind(bchannel->b_sock, (struct sockaddr *)&addr, sizeof(addr));
        if (ret < 0) {
                CERROR(bchannel->call, NULL, "Failed to bind bchannel-socket for handle 0x%x with mISDN-DSP layer. (port %d, channel %d) Did you load mISDN_dsp.ko?\n", bchannel->handle, addr.dev, addr.channel);
+               unregister_fd(&bchannel->lcr_fd);
                close(bchannel->b_sock);
                bchannel->b_sock = -1;
-               return(0);
+               return 0;
        }
-       return(1);
+       return 1;
 }
 
 
@@ -264,6 +262,7 @@ static void bchannel_activated(struct bchannel *bchannel)
 void bchannel_destroy(struct bchannel *bchannel)
 {
        if (bchannel->b_sock > -1) {
+               unregister_fd(&bchannel->lcr_fd);
                close(bchannel->b_sock);
                bchannel->b_sock = -1;
        }
@@ -517,63 +516,54 @@ void bchannel_gain(struct bchannel *bchannel, int gain, int tx)
 /*
  * main loop for processing messages from mISDN
  */
-int bchannel_handle(void)
+static int bchannel_handle(struct lcr_fd *fd, unsigned int what, void *instance, int index)
 {
-       int ret, work = 0;
-       struct bchannel *bchannel;
+       struct bchannel *bchannel = (struct bchannel *)instance;
+       int ret;
        unsigned char buffer[2048+MISDN_HEADER_LEN];
        struct mISDNhead *hh = (struct mISDNhead *)buffer;
 
-       /* process all bchannels */
-       bchannel = bchannel_first;
-       while(bchannel) {
-               /* handle message from bchannel */
-               if (bchannel->b_sock > -1) {
-                       ret = recv(bchannel->b_sock, buffer, sizeof(buffer), 0);
-                       if (ret >= (int)MISDN_HEADER_LEN) {
-                               work = 1;
-                               switch(hh->prim) {
-                                       /* we don't care about confirms, we use rx data to sync tx */
-                                       case PH_DATA_CNF:
-                                       break;
-
-                                       /* 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_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);
+       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;
+
+                       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);
 //                                     bchannel_deactivated(bchannel);
-                                       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);
-                       }
+                       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);
                }
-               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)
index f7b3860..2b03444 100644 (file)
@@ -15,6 +15,7 @@ struct bchannel {
        struct chan_call *call;         /* link to call process */
        unsigned int handle;            /* handle for stack id */
        int b_sock;                     /* socket for b-channel */
+       struct lcr_fd lcr_fd;           /* socket register */
        int b_mode;                     /* dsp, raw, dsphdlc */
        int b_state;
        int b_txdata;
@@ -47,7 +48,6 @@ void bchannel_dtmf(struct bchannel *channel, int on);
 void bchannel_blowfish(struct bchannel *bchannel, unsigned char *key, int len);
 void bchannel_pipeline(struct bchannel *bchannel, char *pipeline);
 void bchannel_gain(struct bchannel *bchannel, int gain, int tx);
-int bchannel_handle(void);
 struct bchannel *find_bchannel_handle(unsigned int handle);
 //struct bchannel *find_bchannel_ref(unsigned int ref);
 struct bchannel *alloc_bchannel(unsigned int handle);
index 61905bf..d0993b7 100644 (file)
@@ -167,6 +167,7 @@ it is called from ast_channel process which has already locked ast_channel.
 #include "callerid.h"
 #include "lcrsocket.h"
 #include "cause.h"
+#include "select.h"
 #include "bchannel.h"
 #include "options.h"
 #include "chan_lcr.h"
@@ -198,11 +199,22 @@ static char *desc = "Channel driver for mISDN/LCR Support (Bri/Pri)";
 pthread_t chan_tid;
 ast_mutex_t chan_lock; /* global lock */
 ast_mutex_t log_lock; /* logging log */
+/* global_change:
+ * used to indicate change in file descriptors, so select function's result may
+ * be obsolete.
+ */
+int global_change = 0;
+int wake_global = 0;
+int wake_pipe[2];
+struct lcr_fd wake_fd;
+       
 int quit;
 
 int glob_channel = 0;
 
 int lcr_sock = -1;
+struct lcr_fd socket_fd;
+struct lcr_timer socket_retry;
 
 struct admin_list {
        struct admin_list *next;
@@ -259,7 +271,7 @@ struct chan_call *find_call_ref(unsigned int ref)
                        break;
                call = call->next;
        }
-       return(call);
+       return call;
 }
 
 void free_call(struct chan_call *call)
@@ -289,6 +301,7 @@ void free_call(struct chan_call *call)
                                ast_dsp_free(call->dsp);
                        CDEBUG(call, NULL, "Call instance freed.\n");
                        free(call);
+                       global_change = 1;
                        return;
                }
                temp = &((*temp)->next);
@@ -309,11 +322,11 @@ struct chan_call *alloc_call(void)
        if (pipe((*callp)->pipe) < 0) {
                CERROR(*callp, NULL, "Failed to create pipe.\n");
                free_call(*callp);
-               return(NULL);
+               return NULL;
        }
        fcntl((*callp)->pipe[0], F_SETFL, O_NONBLOCK);
        CDEBUG(*callp, NULL, "Call instance allocated.\n");
-       return(*callp);
+       return *callp;
 }
 
 unsigned short new_bridge_id(void)
@@ -334,7 +347,7 @@ unsigned short new_bridge_id(void)
                id++;
        }
        CDEBUG(NULL, NULL, "New bridge ID %d.\n", id);
-       return(id);
+       return id;
 }
 
 /*
@@ -364,8 +377,14 @@ int send_message(int message_type, unsigned int ref, union parameter *param)
        admin->msg.u.msg.type = message_type;
        admin->msg.u.msg.ref = ref;
        memcpy(&admin->msg.u.msg.param, param, sizeof(union parameter));
+       socket_fd.when |= LCR_FD_WRITE;
+       if (!wake_global) {
+               wake_global = 1;
+               char byte = 0;
+               write(wake_pipe[1], &byte, 1);
+       }
 
-       return(0);
+       return 0;
 }
 
 /*
@@ -923,8 +942,15 @@ static void lcr_in_proceeding(struct chan_call *call, int message_type, union pa
        /* change state */
        call->state = CHAN_LCR_STATE_OUT_PROCEEDING;
        /* queue event for asterisk */
-       if (call->ast && call->pbx_started)
+       if (call->ast && call->pbx_started) {
+               if (!wake_global) {
+                       wake_global = 1;
+                       char byte = 0;
+                       write(wake_pipe[1], &byte, 1);
+               }
                strncat(call->queue_string, "P", sizeof(call->queue_string)-1);
+       }
+
 }
 
 /*
@@ -937,8 +963,14 @@ static void lcr_in_alerting(struct chan_call *call, int message_type, union para
        /* change state */
        call->state = CHAN_LCR_STATE_OUT_ALERTING;
        /* queue event to asterisk */
-       if (call->ast && call->pbx_started)
+       if (call->ast && call->pbx_started) {
+               if (!wake_global) {
+                       wake_global = 1;
+                       char byte = 0;
+                       write(wake_pipe[1], &byte, 1);
+               }
                strncat(call->queue_string, "R", sizeof(call->queue_string)-1);
+       }
 }
 
 /*
@@ -962,8 +994,14 @@ static void lcr_in_connect(struct chan_call *call, int message_type, union param
        /* copy connectinfo */
        memcpy(&call->connectinfo, &param->connectinfo, sizeof(struct connect_info));
        /* queue event to asterisk */
-       if (call->ast && call->pbx_started)
+       if (call->ast && call->pbx_started) {
+               if (!wake_global) {
+                       wake_global = 1;
+                       char byte = 0;
+                       write(wake_pipe[1], &byte, 1);
+               }
                strncat(call->queue_string, "N", sizeof(call->queue_string)-1);
+       }
 }
 
 /*
@@ -997,9 +1035,14 @@ static void lcr_in_disconnect(struct chan_call *call, int message_type, union pa
        /* queue release asterisk */
        if (ast) {
                ast->hangupcause = call->cause;
-               if (call->pbx_started)
+               if (call->pbx_started) {
+                       if (!wake_global) {
+                               wake_global = 1;
+                               char byte = 0;
+                               write(wake_pipe[1], &byte, 1);
+                       }
                        strcpy(call->queue_string, "H"); // overwrite other indications
-               else {
+               else {
                        ast_hangup(ast); // call will be destroyed here
                }
        }
@@ -1026,9 +1069,14 @@ static void lcr_in_release(struct chan_call *call, int message_type, union param
        /* if we have an asterisk instance, queue hangup, else we are done */
        if (ast) {
                ast->hangupcause = call->cause;
-               if (call->pbx_started)
+               if (call->pbx_started) {
+                       if (!wake_global) {
+                               wake_global = 1;
+                               char byte = 0;
+                               write(wake_pipe[1], &byte, 1);
+                       }
                        strcpy(call->queue_string, "H");
-               else {
+               else {
                        ast_hangup(ast); // call will be destroyed here
                }
        } else {
@@ -1064,8 +1112,14 @@ static void lcr_in_information(struct chan_call *call, int message_type, union p
        }
        
        /* queue digits */
-       if (call->state == CHAN_LCR_STATE_IN_DIALING && param->information.id[0])
+       if (call->state == CHAN_LCR_STATE_IN_DIALING && param->information.id[0]) {
+               if (!wake_global) {
+                       wake_global = 1;
+                       char byte = 0;
+                       write(wake_pipe[1], &byte, 1);
+               }
                strncat(call->queue_string, param->information.id, sizeof(call->queue_string)-1);
+       }
 
        /* use bridge to forware message not supported by asterisk */
        if (call->state == CHAN_LCR_STATE_CONNECT) {
@@ -1134,8 +1188,14 @@ static void lcr_in_pattern(struct chan_call *call, int message_type, union param
                send_message(MESSAGE_BCHANNEL, call->ref, &newparam);
        }
        /* queue PROGRESS, because tones are available */
-       if (call->ast && call->pbx_started)
+       if (call->ast && call->pbx_started) {
+               if (!wake_global) {
+                       wake_global = 1;
+                       char byte = 0;
+                       write(wake_pipe[1], &byte, 1);
+               }
                strncat(call->queue_string, "T", sizeof(call->queue_string)-1);
+       }
 }
 
 /*
@@ -1159,6 +1219,11 @@ void lcr_in_dtmf(struct chan_call *call, int val)
        CDEBUG(call, call->ast, "Recognised DTMF digit '%c'.\n", val);
        digit[0] = val;
        digit[1] = '\0';
+       if (!wake_global) {
+               wake_global = 1;
+               char byte = 0;
+               write(wake_pipe[1], &byte, 1);
+       }
        strncat(call->queue_string, digit, sizeof(call->queue_string)-1);
 }
 
@@ -1180,13 +1245,13 @@ int receive_message(int message_type, unsigned int ref, union parameter *param)
                        CDEBUG(NULL, NULL, "Received BCHANNEL_ASSIGN message. (handle=%08lx) for ref %d\n", param->bchannel.handle, ref);
                        if ((bchannel = find_bchannel_handle(param->bchannel.handle))) {
                                CERROR(NULL, NULL, "bchannel handle %x already assigned.\n", (int)param->bchannel.handle);
-                               return(-1);
+                               return -1;
                        }
                        /* create bchannel */
                        bchannel = alloc_bchannel(param->bchannel.handle);
                        if (!bchannel) {
                                CERROR(NULL, NULL, "alloc bchannel handle %x failed.\n", (int)param->bchannel.handle);
-                               return(-1);
+                               return -1;
                        }
 
                        /* configure channel */
@@ -1242,7 +1307,7 @@ int receive_message(int message_type, unsigned int ref, union parameter *param)
                        CDEBUG(NULL, NULL, "Received BCHANNEL_REMOVE message. (handle=%08lx)\n", param->bchannel.handle);
                        if (!(bchannel = find_bchannel_handle(param->bchannel.handle))) {
                                CERROR(NULL, NULL, "Bchannel handle %x not assigned.\n", (int)param->bchannel.handle);
-                               return(-1);
+                               return -1;
                        }
                        /* unklink from call and destroy bchannel */
                        free_bchannel(bchannel);
@@ -1257,7 +1322,7 @@ int receive_message(int message_type, unsigned int ref, union parameter *param)
                        default:
                        CDEBUG(NULL, NULL, "Received unknown bchannel message %d.\n", param->bchannel.type);
                }
-               return(0);
+               return 0;
        }
 
        /* handle new ref */
@@ -1267,7 +1332,7 @@ int receive_message(int message_type, unsigned int ref, union parameter *param)
                        CDEBUG(NULL, NULL, "Received new ref by LCR, due to incomming call. (ref=%ld)\n", ref);
                        if (!ref || find_call_ref(ref)) {
                                CERROR(NULL, NULL, "Illegal new ref %ld received.\n", ref);
-                               return(-1);
+                               return -1;
                        }
                        /* allocate new call instance */
                        call = alloc_call();
@@ -1287,7 +1352,7 @@ int receive_message(int message_type, unsigned int ref, union parameter *param)
                                /* send release, if ref does not exist */
                                CDEBUG(NULL, NULL, "No call found, that requests a ref.\n");
                                send_release_and_import(call, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL);
-                               return(0);
+                               return 0;
                        }
                        /* store new ref */
                        call->ref = ref;
@@ -1306,22 +1371,22 @@ int receive_message(int message_type, unsigned int ref, union parameter *param)
                                        send_release_and_import(call, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL);
                                /* free call */
                                free_call(call);
-                               return(0);
+                               return 0;
                        }
                }
-               return(0);
+               return 0;
        }
 
        /* check ref */
        if (!ref) {
                CERROR(NULL, NULL, "Received message %d without ref.\n", message_type);
-               return(-1);
+               return -1;
        }
        call = find_call_ref(ref);
        if (!call) {
                /* ignore ref that is not used (anymore) */
                CDEBUG(NULL, NULL, "Message %d from LCR ignored, because no call instance found.\n", message_type);
-               return(0);
+               return 0;
        }
 
        /* handle messages */
@@ -1382,7 +1447,7 @@ int receive_message(int message_type, unsigned int ref, union parameter *param)
                CDEBUG(call, call->ast, "Message %d from LCR unhandled.\n", message_type);
                break;
        }
-       return(0);
+       return 0;
 }
 
 /*
@@ -1415,6 +1480,11 @@ again:
                        goto again;
                }
                CDEBUG(call, call->ast, "Queue call release, because Asterisk channel is running.\n");
+               if (!wake_global) {
+                       wake_global = 1;
+                       char byte = 0;
+                       write(wake_pipe[1], &byte, 1);
+               }
                strcpy(call->queue_string, "H");
                call = call->next;
        }
@@ -1424,69 +1494,74 @@ again:
                free_bchannel(bchannel_first);
 }
 
+void close_socket(void);
 
 /* asterisk handler
  * warning! not thread safe
  * returns -1 for socket error, 0 for no work, 1 for work
  */
-int handle_socket(void)
+static int handle_socket(struct lcr_fd *fd, unsigned int what, void *instance, int index)
 {
-       int work = 0;
        int len;
        struct admin_list *admin;
        struct admin_message msg;
 
-       /* read from socket */
-       len = read(lcr_sock, &msg, sizeof(msg));
-       if (len == 0) {
-               CERROR(NULL, NULL, "Socket closed.\n");
-               return(-1); // socket closed
-       }
-       if (len > 0) {
-               if (len != sizeof(msg)) {
-                       CERROR(NULL, NULL, "Socket short read. (len %d)\n", len);
-                       return(-1); // socket error
+       if ((what & LCR_FD_READ)) {
+               /* read from socket */
+               len = read(lcr_sock, &msg, sizeof(msg));
+               if (len == 0) {
+                       CERROR(NULL, NULL, "Socket closed.\n");
+                       error:
+                       CERROR(NULL, NULL, "Handling of socket failed - closing for some seconds.\n");
+                       close_socket();
+                       release_all_calls();
+                       schedule_timer(&socket_retry, SOCKET_RETRY_TIMER, 0);
+                       return 0;
                }
-               if (msg.message != ADMIN_MESSAGE) {
-                       CERROR(NULL, NULL, "Socket received illegal message %d.\n", msg.message);
-                       return(-1);
-               }
-               receive_message(msg.u.msg.type, msg.u.msg.ref, &msg.u.msg.param);
-               work = 1;
-       } else {
-               if (errno != EWOULDBLOCK) {
+               if (len > 0) {
+                       if (len != sizeof(msg)) {
+                               CERROR(NULL, NULL, "Socket short read. (len %d)\n", len);
+                               goto error;
+                       }
+                       if (msg.message != ADMIN_MESSAGE) {
+                               CERROR(NULL, NULL, "Socket received illegal message %d.\n", msg.message);
+                               goto error;
+                       }
+                       receive_message(msg.u.msg.type, msg.u.msg.ref, &msg.u.msg.param);
+               } else {
                        CERROR(NULL, NULL, "Socket failed (errno %d).\n", errno);
-                       return(-1);
+                       goto error;
                }
        }
 
-       /* write to socket */
-       if (!admin_first)
-               return(work);
-       admin = admin_first;
-       len = write(lcr_sock, &admin->msg, sizeof(msg));
-       if (len == 0) {
-               CERROR(NULL, NULL, "Socket closed.\n");
-               return(-1); // socket closed
-       }
-       if (len > 0) {
-               if (len != sizeof(msg)) {
-                       CERROR(NULL, NULL, "Socket short write. (len %d)\n", len);
-                       return(-1); // socket error
+       if ((what & LCR_FD_WRITE)) {
+               /* write to socket */
+               if (!admin_first) {
+                       socket_fd.when &= ~LCR_FD_WRITE;
+                       return 0;
                }
-               /* free head */
-               admin_first = admin->next;
-               free(admin);
-
-               work = 1;
-       } else {
-               if (errno != EWOULDBLOCK) {
+               admin = admin_first;
+               len = write(lcr_sock, &admin->msg, sizeof(msg));
+               if (len == 0) {
+                       CERROR(NULL, NULL, "Socket closed.\n");
+                       goto error;
+               }
+               if (len > 0) {
+                       if (len != sizeof(msg)) {
+                               CERROR(NULL, NULL, "Socket short write. (len %d)\n", len);
+                               goto error;
+                       }
+                       /* free head */
+                       admin_first = admin->next;
+                       free(admin);
+                       global_change = 1;
+               } else {
                        CERROR(NULL, NULL, "Socket failed (errno %d).\n", errno);
-                       return(-1);
+                       goto error;
                }
        }
 
-       return(work);
+       return 0;
 }
 
 /*
@@ -1494,16 +1569,14 @@ int handle_socket(void)
  */
 int open_socket(void)
 {
-       int ret;
        int conn;
        struct sockaddr_un sock_address;
-       unsigned int on = 1;
        union parameter param;
 
        /* open socket */
        if ((lcr_sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
                CERROR(NULL, NULL, "Failed to create socket.\n");
-               return(lcr_sock);
+               return lcr_sock;
        }
 
        /* set socket address and name */
@@ -1516,29 +1589,28 @@ int open_socket(void)
                close(lcr_sock);
                lcr_sock = -1;
                CDEBUG(NULL, NULL, "Failed to connect to socket '%s'. Is LCR running?\n", sock_address.sun_path);
-               return(conn);
+               return conn;
        }
 
-       /* set non-blocking io */
-       if ((ret = ioctl(lcr_sock, FIONBIO, (unsigned char *)(&on))) < 0) {
-               close(lcr_sock);
-               lcr_sock = -1;
-               CERROR(NULL, NULL, "Failed to set socket into non-blocking IO.\n");
-               return(ret);
-       }
+       /* register socket fd */
+       memset(&socket_fd, 0, sizeof(socket_fd));
+       socket_fd.fd = lcr_sock;
+       register_fd(&socket_fd, LCR_FD_READ | LCR_FD_EXCEPT, handle_socket, NULL, 0);
 
        /* enque hello message */
        memset(&param, 0, sizeof(param));
        strcpy(param.hello.application, "asterisk");
        send_message(MESSAGE_HELLO, 0, &param);
 
-       return(lcr_sock);
+       return lcr_sock;
 }
 
 void close_socket(void)
 {
        struct admin_list *admin, *temp;
-       
+
+       unregister_fd(&socket_fd);
+
        /* flush pending messages */
        admin = admin_first;
        while(admin) {
@@ -1552,13 +1624,24 @@ void close_socket(void)
        if (lcr_sock >= 0)      
                close(lcr_sock);
        lcr_sock = -1;
+       global_change = 1;
 }
 
 
 /* sending queue to asterisk */
-static int queue_send(void)
+static int wake_event(struct lcr_fd *fd, unsigned int what, void *instance, int index)
+{
+       char byte;
+
+       read(wake_pipe[0], &byte, 1);
+
+       wake_global = 0;
+
+       return 0;
+}
+
+static void handle_queue()
 {
-       int work = 0;
        struct chan_call *call;
        struct ast_channel *ast;
        struct ast_frame fr;
@@ -1569,156 +1652,124 @@ static int queue_send(void)
                p = call->queue_string;
                ast = call->ast;
                if (*p && ast) {
-                       /* there is something to queue */
-                       if (!ast_channel_trylock(ast)) { /* succeed */
-                               while(*p) {
-                                       switch (*p) {
-                                       case 'T':
-                                               CDEBUG(call, ast, "Sending queued PROGRESS to Asterisk.\n");
-                                               ast_queue_control(ast, AST_CONTROL_PROGRESS);
-                                               break;
-                                       case 'P':
-                                               CDEBUG(call, ast, "Sending queued PROCEEDING to Asterisk.\n");
-                                               ast_queue_control(ast, AST_CONTROL_PROCEEDING);
-                                               break;
-                                       case 'R':
-                                               CDEBUG(call, ast, "Sending queued RINGING to Asterisk.\n");
-                                               ast_queue_control(ast, AST_CONTROL_RINGING);
-                                               ast_setstate(ast, AST_STATE_RINGING);
-                                               break;
-                                       case 'N':
-                                               CDEBUG(call, ast, "Sending queued ANSWER to Asterisk.\n");
-                                               ast_queue_control(ast, AST_CONTROL_ANSWER);
-                                               break;
-                                       case 'H':
-                                               CDEBUG(call, ast, "Sending queued HANGUP to Asterisk.\n");
-                                               ast_queue_hangup(ast);
-                                               break;
-                                       case '1': case '2': case '3': case 'A':
-                                       case '4': case '5': case '6': case 'B':
-                                       case '7': case '8': case '9': case 'C':
-                                       case '*': case '0': case '#': case 'D':
-                                               CDEBUG(call, ast, "Sending queued digit '%c' to Asterisk.\n", *p);
-                                               /* send digit to asterisk */
-                                               memset(&fr, 0, sizeof(fr));
-                                               
-                                               #ifdef LCR_FOR_ASTERISK
-                                               fr.frametype = AST_FRAME_DTMF_BEGIN;
-                                               #endif
-
-                                               #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++;
+                       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);
                                }
-                               call->queue_string[0] = '\0';
-                               ast_channel_unlock(ast);
-                               work = 1;
+                               p++;
                        }
+                       call->queue_string[0] = '\0';
+                       ast_channel_unlock(ast);
                }
                call = call->next;
        }
+}
+
+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;
+}
 
-       return work;
+void lock_chan(void)
+{
+       ast_mutex_lock(&chan_lock);
 }
 
-/* signal handler */
-void sighandler(int sigset)
+void unlock_chan(void)
 {
+       ast_mutex_unlock(&chan_lock);
 }
 
 /* chan_lcr thread */
 static void *chan_thread(void *arg)
 {
-       int work;
-       int ret;
-       union parameter param;
-       time_t retry = 0, now;
+       if (pipe(wake_pipe) < 0) {
+               CERROR(NULL, NULL, "Failed to open pipe.\n");
+               return NULL;
+       }
+       memset(&wake_fd, 0, sizeof(wake_fd));
+       wake_fd.fd = wake_pipe[0];
+       register_fd(&wake_fd, LCR_FD_READ, wake_event, NULL, 0);
+
+       memset(&socket_retry, 0, sizeof(socket_retry));
+       add_timer(&socket_retry, handle_retry, NULL, 0);
 
        bchannel_pid = getpid();
 
-//     signal(SIGPIPE, sighandler);
-       
-       memset(&param, 0, sizeof(union parameter));
-       if (lcr_sock < 0)
-               time(&retry);
+       /* open socket the first time */
+       handle_retry(NULL, NULL, 0);
 
        ast_mutex_lock(&chan_lock);
 
        while(!quit) {
-               work = 0;
-
-               if (lcr_sock > 0) {
-                       /* handle socket */
-                       ret = handle_socket();
-                       if (ret < 0) {
-                               CERROR(NULL, NULL, "Handling of socket failed - closing for some seconds.\n");
-                               close_socket();
-                               release_all_calls();
-                               time(&retry);
-                       }
-                       if (ret)
-                               work = 1;
-               } else {
-                       time(&now);
-                       if (retry && now-retry > 5) {
-                               CDEBUG(NULL, NULL, "Retry to open socket.\n");
-                               retry = 0;
-                               if (open_socket() < 0) {
-                                       time(&retry);
-                               }
-                               work = 1;
-                       }
-                                       
-               }
-
-               /* handle mISDN */
-               ret = bchannel_handle();
-               if (ret)
-                       work = 1;
-
-               /* handle messages to asterisk */
-               ret = queue_send();
-               if (ret)
-                       work = 1;
-
-               /* delay if no work done */
-               if (!work) {
-                       ast_mutex_unlock(&chan_lock);
-
-                       #ifdef LCR_FOR_ASTERISK                 
-                       usleep(30000);
-                       #endif
-                       
-                       #ifdef LCR_FOR_CALLWEAVER                       
-                       usleep(20000);
-                       #endif
-                       
-                       ast_mutex_lock(&chan_lock);
-               }
+               handle_queue();
+               select_main(0, &global_change, lock_chan, unlock_chan);
        }
 
        close_socket();
 
+       del_timer(&socket_retry);
+
+       unregister_fd(&wake_fd);
+       close(wake_pipe[0]);
+       close(wake_pipe[1]);
+
        CERROR(NULL, NULL, "Thread exit.\n");
-       
-       ast_mutex_unlock(&chan_lock);
 
-//     signal(SIGPIPE, SIG_DFL);
+       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);
index 5905ea1..3a64593 100644 (file)
@@ -132,6 +132,8 @@ enum {
 };
 
 
+#define SOCKET_RETRY_TIMER     5
+
 #define CERROR(call, ast, arg...) chan_lcr_log(__LOG_ERROR, __FILE__, __LINE__,  __FUNCTION__, call, ast, ##arg)
 #define CDEBUG(call, ast, arg...) chan_lcr_log(__LOG_NOTICE, __FILE__, __LINE__,  __FUNCTION__, call, ast, ##arg)
 void chan_lcr_log(int type, const char *file, int line, const char *function,  struct chan_call *call, struct ast_channel *ast, const char *fmt, ...);
index 44e901c..125b516 100644 (file)
--- a/crypt.cpp
+++ b/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(&current_time, NULL);
+       if (ea->e_crypt_timeout_sec) if (ea->e_crypt_timeout_sec<current_time.tv_sec || (ea->e_crypt_timeout_sec==current_time.tv_sec && ea->e_crypt_timeout_usec<current_time.tv_usec)) {
+               ea->e_crypt_timeout_sec = 0;
+               ea->e_crypt_timeout_usec = 0;
+               ea->cryptman_message(CT_TIMEOUT, NULL, 0);
        }
+
+       /* trigger until state is 0 */
+       if (ea->e_crypt_state != CM_ST_NULL)
+               schedule_timer(&ea->e_crypt_handler, 0, 100000);
+
+       return 0;
 }
 
 
@@ -679,6 +690,7 @@ void EndpointAppPBX::cr_activate(int message, unsigned char *param, int len)
        unsigned char buf[128] = "";
        unsigned char msg;
        unsigned char bogomips[4], ran[4];
+       struct timeval current_time;
 
        /* activate listener */
        cryptman_msg2crengine(CR_LISTEN_REQ, NULL, 0);
@@ -686,7 +698,8 @@ void EndpointAppPBX::cr_activate(int message, unsigned char *param, int len)
        msg = CMSG_IDENT;
        CM_ADDINF(CM_INFO_MESSAGE, 1, &msg);
        /* random number element */
-       srandom(now_tv.tv_sec ^ now_tv.tv_usec ^ random());
+       gettimeofday(&current_time, NULL);
+       srandom(current_time.tv_sec ^ current_time.tv_usec ^ random());
        e_crypt_random = random();
        ran[0] = e_crypt_random >> 24;
        ran[1] = e_crypt_random >> 16;
@@ -1484,6 +1497,8 @@ void EndpointAppPBX::cryptman_msg2user(int msg, const char *text)
 void EndpointAppPBX::cryptman_state(int state)
 {
        PDEBUG(DEBUG_CRYPT, "Changing state from %s to %s\n", statename(e_crypt_state), statename(state));
+       if (state != CM_ST_NULL && e_crypt_state == CM_ST_NULL)
+               schedule_timer(&e_crypt_handler, 0, 100000);
        e_crypt_state = state;
 }
 
@@ -1492,9 +1507,12 @@ void EndpointAppPBX::cryptman_state(int state)
  */
 void EndpointAppPBX::cryptman_timeout(int secs)
 {
+       struct timeval current_time;
+
+       gettimeofday(&current_time, NULL);
        if (secs) {
-               e_crypt_timeout_sec = now_tv.tv_sec+secs;
-               e_crypt_timeout_usec = now_tv.tv_usec;
+               e_crypt_timeout_sec = current_time.tv_sec+secs;
+               e_crypt_timeout_usec = current_time.tv_usec;
                PDEBUG(DEBUG_CRYPT, "Changing timeout to %d seconds\n", secs);
        } else {
                e_crypt_timeout_sec = 0;
diff --git a/crypt.h b/crypt.h
index f5a030c..5659082 100644 (file)
--- a/crypt.h
+++ b/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);
index 75ff448..4a96e28 100644 (file)
--- a/dss1.cpp
+++ b/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(&current_time);
+               enc_ie_date(l3m, current_time, p_settings.no_seconds);
        }
        end_trace();
        /* finally send message */
@@ -2552,7 +2556,7 @@ if (/*     ||*/ p_state==PORT_STATE_OUT_SETUP) {
                end_trace();
                p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_RELEASE_COMPLETE, p_m_d_l3id, l3m);
                new_state(PORT_STATE_RELEASE);
-               p_m_delete = 1;
+               trigger_work(&p_m_d_delete);
                return;
        }
 
diff --git a/dss1.h b/dss1.h
index 6683a52..f2486ab 100644 (file)
--- a/dss1.h
+++ b/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 */
index 28ea12f..cda79c2 100644 (file)
@@ -33,6 +33,7 @@ class Endpoint *find_epoint_id(unsigned int epoint_id)
        return(NULL);
 }
 
+int delete_endpoint(struct lcr_work *work, void *instance, int index);
 
 /*
  * endpoint constructor (link with either port or join id)
@@ -48,6 +49,8 @@ Endpoint::Endpoint(unsigned int port_id, unsigned int join_id)
 
         ep_portlist = NULL;
        ep_app = NULL;
+       memset(&ep_delete, 0, sizeof(ep_delete));
+       add_work(&ep_delete, delete_endpoint, this, 0);
        ep_use = 1;
 
        /* add endpoint to chain */
@@ -125,6 +128,8 @@ Endpoint::~Endpoint(void)
                FATAL("Endpoint not in Endpoint's list.\n");
        *tempp = next;
 
+       del_work(&ep_delete);
+
        /* free */
        PDEBUG(DEBUG_EPOINT, "removed endpoint %d.\n", ep_serial);
 }
@@ -183,17 +188,13 @@ void Endpoint::free_portlist(struct port_list *portlist)
 }
 
 
-/* handler for endpoint
- */
-int Endpoint::handler(void)
+int delete_endpoint(struct lcr_work *work, void *instance, int index)
 {
-       if (ep_use <= 0) {
-               delete this;
-               return(-1);
-       }
+       class Endpoint *ep = (class Endpoint *)instance;
 
-       /* call application handler */
-       if (ep_app)
-               return(ep_app->handler());
-       return(0);
+       if (ep->ep_use <= 0)
+               delete ep;
+
+       return 0;
 }
+
index 963b5dd..a3080bc 100644 (file)
@@ -26,7 +26,6 @@ class Endpoint
        ~Endpoint();
        class Endpoint          *next;          /* next in list */
        unsigned int            ep_serial;      /* a unique serial to identify */
-       int                     handler(void);
 
        /* applocaton relation */
        class EndpointApp       *ep_app;                /* link to application class */
@@ -41,6 +40,7 @@ class Endpoint
 
        /* if still used by threads */
        int                     ep_use;
+       struct lcr_work         ep_delete;
 
        /* application indipendant states */
        int                     ep_park;                /* indicates that the epoint is parked */
index a3c6f56..158b3d6 100644 (file)
@@ -28,11 +28,6 @@ EndpointApp::~EndpointApp(void)
        classuse--;
 }
 
-int EndpointApp::handler(void)
-{
-       return(0);
-}
-
 /* mini application for test purpose only */
 
 void EndpointApp::ea_message_port(unsigned int port_id, int message_type, union parameter *param)
index a330a63..a24faae 100644 (file)
@@ -18,7 +18,6 @@ class EndpointApp
        virtual ~EndpointApp();
 
        class Endpoint          *ea_endpoint;
-       virtual int             handler(void);
        virtual void ea_message_port(unsigned int port_id, int message, union parameter *param);
        virtual void ea_message_join(unsigned int join_id, int message, union parameter *param);
 };
diff --git a/gsm.cpp b/gsm.cpp
index e747ff0..3358329 100644 (file)
--- a/gsm.cpp
+++ b/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
 }
 
 
+/* 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
+ * handler of bchannel events
  */
-int Pgsm::handler(void)
+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;
+}
+
diff --git a/gsm.h b/gsm.h
index 15477ef..6c09fa8 100644 (file)
--- a/gsm.h
+++ b/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;
index b1a06bb..5dcbde2 100644 (file)
--- a/join.cpp
+++ b/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)
 {
diff --git a/join.h b/join.h
index 5c5f3f2..442aa5d 100644 (file)
--- a/join.h
+++ b/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 */
index d3640b1..4b06540 100644 (file)
@@ -202,6 +202,7 @@ void joinpbx_debug(class JoinPBX *joinpbx, const char *function)
        PDEBUG(DEBUG_JOIN, "end\n");
 }
 
+int update_bridge(struct lcr_work *work, void *instance, int index);
 
 /*
  * constructor for a new join 
@@ -223,11 +224,12 @@ JoinPBX::JoinPBX(class Endpoint *epoint) : Join()
        j_dialed[0] = '\0';
        j_todial[0] = '\0';
        j_pid = getpid();
-       j_updatebridge = 0;
        j_partyline = 0;
        j_partyline_jingle = 0;
        j_multicause = 0;
        j_multilocation = 0;
+       memset(&j_updatebridge, 0, sizeof(j_updatebridge));
+       add_work(&j_updatebridge, update_bridge, this, 0);
 
        /* initialize a relation only to the calling interface */
        relation = j_relation = (struct join_relation *)MALLOC(sizeof(struct join_relation));
@@ -258,12 +260,23 @@ JoinPBX::~JoinPBX()
                cmemuse--;
                relation = rtemp;
        }
+
+       del_work(&j_updatebridge);
 }
 
 
 /* bridge sets the audio flow of all bchannels assiociated to 'this' join
  * also it changes and notifies active/hold/conference states
  */
+int update_bridge(struct lcr_work *work, void *instance, int index)
+{
+        class JoinPBX *joinpbx = (class JoinPBX *)instance;
+
+        joinpbx->bridge();
+
+        return 0;
+}
+
 void JoinPBX::bridge(void)
 {
        struct join_relation *relation;
@@ -453,7 +466,7 @@ int JoinPBX::release(struct join_relation *relation, int location, int cause)
        /* remove from bridge */
        if (relation->channel_state != 0) {
                relation->channel_state = 0;
-               j_updatebridge = 1; /* update bridge flag */
+               trigger_work(&j_updatebridge);
                // note: if join is not released, bridge must be updated
        }
 
@@ -677,7 +690,7 @@ void JoinPBX::message_epoint(unsigned int epoint_id, int message_type, union par
                        SPRINT(message->param.connectinfo.id, "%d", j_partyline);
                        message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
                        message_put(message);
-                       j_updatebridge = 1; /* update bridge flag */
+                       trigger_work(&j_updatebridge);
                        if (j_partyline_jingle)
                               play_jingle(1);
                        break;
@@ -686,7 +699,7 @@ void JoinPBX::message_epoint(unsigned int epoint_id, int message_type, union par
                        PDEBUG(DEBUG_JOIN, "join received channel message: %d.\n", param->audiopath);
                        if (relation->channel_state != param->audiopath) {
                                relation->channel_state = param->audiopath;
-                               j_updatebridge = 1; /* update bridge flag */
+                               trigger_work(&j_updatebridge);
                                if (options.deb & DEBUG_JOIN)
                                        joinpbx_debug(this, "Join::message_epoint{after setting new channel state}");
                        }
@@ -721,7 +734,7 @@ void JoinPBX::message_epoint(unsigned int epoint_id, int message_type, union par
                PDEBUG(DEBUG_JOIN, "join received channel message: %d.\n", param->audiopath);
                if (relation->channel_state != param->audiopath) {
                        relation->channel_state = param->audiopath;
-                       j_updatebridge = 1; /* update bridge flag */
+                       trigger_work(&j_updatebridge);
                        if (options.deb & DEBUG_JOIN)
                                joinpbx_debug(this, "Join::message_epoint{after setting new channel state}");
                }
@@ -739,7 +752,7 @@ void JoinPBX::message_epoint(unsigned int epoint_id, int message_type, union par
                        new_state = track_notify(relation->rx_state, param->notifyinfo.notify);
                        if (new_state != relation->rx_state) {
                                relation->rx_state = new_state;
-                               j_updatebridge = 1;
+                               trigger_work(&j_updatebridge);
                                if (options.deb & DEBUG_JOIN)
                                        joinpbx_debug(this, "Join::message_epoint{after setting new rx state}");
                        }
@@ -895,30 +908,6 @@ void JoinPBX::message_epoint(unsigned int epoint_id, int message_type, union par
 }
 
 
-/* join process is called from the main loop
- * it processes the current calling state.
- * returns 0 if join nothing was done
- */
-int JoinPBX::handler(void)
-{
-//     struct join_relation *relation;
-//     char dialing[32][32];
-//     int port[32];
-//     int found;
-//     int i, j;
-//     char *p;
-
-       /* the bridge must be updated */
-       if (j_updatebridge) {
-               bridge();
-               j_updatebridge = 0;
-               return(1);
-       }
-
-       return(0);
-}
-
-
 int track_notify(int oldstate, int notify)
 {
        int newstate = oldstate;
index 18e38c0..7c05eee 100644 (file)
--- a/joinpbx.h
+++ b/joinpbx.h
@@ -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 */
index a4f9380..167bbce 100644 (file)
@@ -49,17 +49,6 @@ JoinRemote::~JoinRemote()
 {
 }
 
-
-/* join process is called from the main loop
- * it processes the current calling state.
- * returns 0 if join nothing was done
- */
-int JoinRemote::handler(void)
-{
-       return(0);
-}
-
-
 void JoinRemote::message_epoint(unsigned int epoint_id, int message_type, union parameter *param)
 {
        /* if endpoint has just been removed, but still a message in the que */
index b837da6..1582133 100644 (file)
@@ -16,7 +16,6 @@ class JoinRemote : public Join
        ~JoinRemote();
        void message_epoint(unsigned int epoint_id, int message, union parameter *param);
        void message_remote(int message_type, union parameter *param);
-       int handler(void);
 
        int j_remote_id;
        char j_remote_name[32];
index 222700b..0b6d627 100644 (file)
@@ -25,6 +25,7 @@
 #include "macro.h"
 #include "options.h"
 #include "join.h"
+#include "select.h"
 #include "joinpbx.h"
 #include "extension.h"
 #include "message.h"
index e531b14..3e7751e 100644 (file)
--- a/mISDN.cpp
+++ b/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(&current_time, NULL);
        if (p_m_last_tv_sec) {
-               elapsed = 8000 * (now_tv.tv_sec - p_m_last_tv_sec)
-                       + 8 * (now_tv.tv_usec/1000 - p_m_last_tv_msec);
-       } else {
-               /* set clock of first process ever in this instance */
-               p_m_last_tv_sec = now_tv.tv_sec;
-               p_m_last_tv_msec = now_tv.tv_usec/1000;
+               elapsed = 8000 * (current_time.tv_sec - p_m_last_tv_sec)
+                       + 8 * (current_time.tv_usec/1000 - p_m_last_tv_msec);
        }
-       /* process only if we have a minimum of samples, to make packets not too small */
-       if (elapsed >= ISDN_TRANSMIT
-        && p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE) {
-               /* set clock of last process! */
-               p_m_last_tv_sec = now_tv.tv_sec;
-               p_m_last_tv_msec = now_tv.tv_usec/1000;
+       /* set clock of last process! */
+       p_m_last_tv_sec = current_time.tv_sec;
+       p_m_last_tv_msec = current_time.tv_usec/1000;
 
+       /* process only if we have samples and we are active */
+       if (elapsed && p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE) {
                /* update load */
                if (elapsed < p_m_load)
                        p_m_load -= elapsed;
@@ -1237,7 +1274,7 @@ int PmISDN::handler(void)
 
                /* to send data, tone must be on */
                if ((p_tone_name[0] || p_m_crypt_msg_loops || p_m_inband_send_on) /* what tones? */
-                && (p_m_load < ISDN_LOAD) /* enough load? */
+                && (p_m_load < ISDN_LOAD) /* not too much load? */
                 && (p_state==PORT_STATE_CONNECT || p_m_mISDNport->tones || p_m_inband_send_on)) { /* connected or inband-tones? */
                        int tosend = ISDN_LOAD - p_m_load, length; 
                        unsigned char buf[MISDN_HEADER_LEN+tosend];
@@ -1267,6 +1304,8 @@ int PmISDN::handler(void)
                                        /* next loop */
                                        p_m_crypt_msg_current = 0;
                                        p_m_crypt_msg_loops--;
+                                       if (!p_m_crypt_msg_loops)
+                                               update_rxoff();
 //                                     puts("eine loop weniger");
                                }
 
@@ -1283,32 +1322,34 @@ int PmISDN::handler(void)
                        if (ISDN_LOAD - p_m_load - tosend > 0) {
                                frm->prim = PH_DATA_REQ;
                                frm->id = 0;
-                               ret = sendto(p_m_mISDNport->b_socket[p_m_b_index], buf, MISDN_HEADER_LEN+ISDN_LOAD-p_m_load-tosend, 0, NULL, 0);
+                               ret = sendto(p_m_mISDNport->b_sock[p_m_b_index].fd, buf, MISDN_HEADER_LEN+ISDN_LOAD-p_m_load-tosend, 0, NULL, 0);
                                if (ret <= 0)
-                                       PERROR("Failed to send to socket %d (samples = %d)\n", p_m_mISDNport->b_socket[p_m_b_index], ISDN_LOAD-p_m_load-tosend);
+                                       PERROR("Failed to send to socket %d (samples = %d)\n", p_m_mISDNport->b_sock[p_m_b_index].fd, ISDN_LOAD-p_m_load-tosend);
                                p_m_load += ISDN_LOAD - p_m_load - tosend;
                        }
                }
        }
 
-       // NOTE: deletion is done by the child class
-
-       /* handle timeouts */
-       if (p_m_timeout) {
-               if (p_m_timer+p_m_timeout < now_d) {
-                       PDEBUG(DEBUG_ISDN, "(%s) timeout after %d seconds detected (state=%d).\n", p_name, p_m_timeout, p_state);
-                       p_m_timeout = 0;
-                       /* send timeout to endpoint */
-                       message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_TIMEOUT);
-                       message->param.state = p_state;
-                       message_put(message);
-                       return(1);
-               }
+       if (p_tone_name[0] || p_m_crypt_msg_loops || p_m_inband_send_on || p_m_load) {
+               schedule_timer(&p_m_loadtimer, 0, ISDN_TRANSMIT*125);
        }
-       
-       return(0); /* nothing done */
 }
 
+/* handle timeouts */
+static int mISDN_timeout(struct lcr_timer *timer, void *instance, int i)
+{
+       class PmISDN *isdnport = (class PmISDN *)instance;
+       struct lcr_msg *message;
+
+       PDEBUG(DEBUG_ISDN, "(%s) timeout after %d seconds detected (state=%d).\n", isdnport->p_name, isdnport->p_m_timeout.timeout.tv_sec, isdnport->p_state);
+       /* send timeout to endpoint */
+       message = message_create(isdnport->p_serial, ACTIVE_EPOINT(isdnport->p_epointlist), PORT_TO_EPOINT, MESSAGE_TIMEOUT);
+       message->param.state = isdnport->p_state;
+       message_put(message);
+
+       return 0;
+}
+       
 
 /*
  * whenever we get audio data from bchannel, we process it here
@@ -1466,7 +1507,7 @@ void PmISDN::set_echotest(int echo)
                PDEBUG(DEBUG_ISDN, "we set echo to echo=%d.\n", p_m_echo);
                if (p_m_b_channel)
                        if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE)
-                               ph_control(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], p_m_echo?DSP_ECHO_ON:DSP_ECHO_OFF, 0, "DSP-ECHO", p_m_echo);
+                               ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, p_m_echo?DSP_ECHO_ON:DSP_ECHO_OFF, 0, "DSP-ECHO", p_m_echo);
        }
 }
 
@@ -1509,7 +1550,7 @@ void PmISDN::set_tone(const char *dir, const char *tone)
                if (p_m_b_index > -1)
                if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT) {
                        PDEBUG(DEBUG_ISDN, "we reset tone from id=%d to OFF.\n", p_m_tone);
-                       ph_control(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], DSP_TONE_PATT_OFF, 0, "DSP-TONE", 0);
+                       ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, DSP_TONE_PATT_OFF, 0, "DSP-TONE", 0);
                }
                p_m_tone = 0;
                Port::set_tone(dir, tone);
@@ -1581,7 +1622,7 @@ void PmISDN::set_tone(const char *dir, const char *tone)
                PDEBUG(DEBUG_ISDN, "we set tone to id=%d.\n", p_m_tone);
                if (p_m_b_index > -1)
                if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT)
-                       ph_control(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], p_m_tone?DSP_TONE_PATT_ON:DSP_TONE_PATT_OFF, p_m_tone, "DSP-TONE", p_m_tone);
+                       ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, p_m_tone?DSP_TONE_PATT_ON:DSP_TONE_PATT_OFF, p_m_tone, "DSP-TONE", p_m_tone);
        }
        /* turn user-space tones off in cases of no tone OR dsp tone */
        Port::set_tone("",NULL);
@@ -1600,7 +1641,7 @@ void PmISDN::message_mISDNsignal(unsigned int epoint_id, int message_id, union p
                        PDEBUG(DEBUG_BCHANNEL, "we change tx-volume to shift=%d.\n", p_m_tx_gain);
                        if (p_m_b_index > -1)
                        if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT)
-                               ph_control(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], DSP_VOL_CHANGE_TX, p_m_tx_gain, "DSP-TX_GAIN", p_m_tx_gain);
+                               ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, DSP_VOL_CHANGE_TX, p_m_tx_gain, "DSP-TX_GAIN", p_m_tx_gain);
                } else
                        PDEBUG(DEBUG_BCHANNEL, "we already have tx-volume shift=%d.\n", p_m_rx_gain);
                if (p_m_rx_gain != param->mISDNsignal.rx_gain) {
@@ -1608,7 +1649,7 @@ void PmISDN::message_mISDNsignal(unsigned int epoint_id, int message_id, union p
                        PDEBUG(DEBUG_BCHANNEL, "we change rx-volume to shift=%d.\n", p_m_rx_gain);
                        if (p_m_b_index > -1)
                        if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT)
-                               ph_control(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], DSP_VOL_CHANGE_RX, p_m_rx_gain, "DSP-RX_GAIN", p_m_rx_gain);
+                               ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, DSP_VOL_CHANGE_RX, p_m_rx_gain, "DSP-RX_GAIN", p_m_rx_gain);
                } else
                        PDEBUG(DEBUG_BCHANNEL, "we already have rx-volume shift=%d.\n", p_m_rx_gain);
                break;
@@ -1624,6 +1665,7 @@ void PmISDN::message_mISDNsignal(unsigned int epoint_id, int message_id, union p
                if (p_m_joindata != param->mISDNsignal.joindata) {
                        p_m_joindata = param->mISDNsignal.joindata;
                        PDEBUG(DEBUG_BCHANNEL, "we change to joindata=%d.\n", p_m_joindata);
+                       update_rxoff();
                } else
                        PDEBUG(DEBUG_BCHANNEL, "we already have joindata=%d.\n", p_m_joindata);
                break;
@@ -1634,7 +1676,7 @@ void PmISDN::message_mISDNsignal(unsigned int epoint_id, int message_id, union p
                        PDEBUG(DEBUG_BCHANNEL, "we change delay mode to delay=%d.\n", p_m_delay);
                        if (p_m_b_index > -1)
                        if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT)
-                               ph_control(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], p_m_delay?DSP_DELAY:DSP_JITTER, p_m_delay, "DSP-DELAY", p_m_delay);
+                               ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, p_m_delay?DSP_DELAY:DSP_JITTER, p_m_delay, "DSP-DELAY", p_m_delay);
                } else
                        PDEBUG(DEBUG_BCHANNEL, "we already have delay=%d.\n", p_m_delay);
                break;
@@ -1665,7 +1707,7 @@ void PmISDN::message_crypt(unsigned int epoint_id, int message_id, union paramet
                PDEBUG(DEBUG_BCHANNEL, "we set encryption to crypt=%d. (0 means OFF)\n", p_m_crypt);
                if (p_m_b_index > -1)
                if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT)
-                       ph_control_block(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], p_m_crypt?DSP_BF_ENABLE_KEY:DSP_BF_DISABLE, p_m_crypt_key, p_m_crypt_key_len, "DSP-CRYPT", p_m_crypt_key_len);
+                       ph_control_block(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, p_m_crypt?DSP_BF_ENABLE_KEY:DSP_BF_DISABLE, p_m_crypt_key, p_m_crypt_key_len, "DSP-CRYPT", p_m_crypt_key_len);
                break;
 
                case CC_DACT_REQ:            /* deactivate session encryption */
@@ -1675,11 +1717,13 @@ void PmISDN::message_crypt(unsigned int epoint_id, int message_id, union paramet
 
                case CR_LISTEN_REQ:          /* start listening to messages */
                p_m_crypt_listen = 1;
+               update_rxoff();
                p_m_crypt_listen_state = 0;
                break;
 
                case CR_UNLISTEN_REQ:        /* stop listening to messages */
                p_m_crypt_listen = 0;
+               update_rxoff();
                break;
 
                case CR_MESSAGE_REQ:         /* send message */
@@ -1690,11 +1734,13 @@ void PmISDN::message_crypt(unsigned int epoint_id, int message_id, union paramet
                }
                p_m_crypt_msg_current = 0; /* reset */
                p_m_crypt_msg_loops = 6; /* enable */
+               update_rxoff();
+               update_load();
 #if 0
                /* disable txmix, or we get corrupt data due to audio process */
                if (p_m_txmix && p_m_b_index>=0 && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT) {
                        PDEBUG(DEBUG_BCHANNEL, "for sending CR_MESSAGE_REQ, we reset txmix from txmix=%d.\n", p_m_txmix);
-                       ph_control(p_m_mISDNport, this, p_mISDNport->b_socket[p_m_b_index], DSP_MIX_OFF, 0, "DSP-TXMIX", 0);
+                       ph_control(p_m_mISDNport, this, p_mISDNport->b_sock[p_m_b_index].fd, DSP_MIX_OFF, 0, "DSP-TXMIX", 0);
                }
 #endif
                break;
@@ -1732,131 +1778,68 @@ int PmISDN::message_epoint(unsigned int epoint_id, int message_id, union paramet
        return(0);
 }
 
+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);
+               }
+       }
+}
 
-/*
- * main loop for processing messages from mISDN
- */
-int mISDN_handler(void)
+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);
                        }
                }
+               mISDNport = mISDNport->next;
+       }
+       return 0;
+}
 
-#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
+/* l2 establish timer fires */
+static int l2establish_timeout(struct lcr_timer *timer, void *instance, int i)
+{
+       struct mISDNport *mISDNport = (struct mISDNport *)instance;
 
-               /* layer 2 establish timer */
-               if (mISDNport->l2establish) {
-                       if (now-mISDNport->l2establish > 5) {
-                               mISDNport->l2establish = 0;
-                               if (!mISDNport->gsm && mISDNport->l2hold && (mISDNport->ptp || !mISDNport->ntmode)) {
+       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 */
+       }
 
-//                                     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);
-                               }
-                       }
-               }
+       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;
 
-               mISDNport = mISDNport->next;
+               /* 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);
        }
 
-       /* if we received at least one b-frame, we will return 1 */
-       return(work);
+       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)
diff --git a/mISDN.h b/mISDN.h
index cbebcac..1a7d377 100644 (file)
--- a/mISDN.h
+++ b/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);
diff --git a/macro.h b/macro.h
index 9e4bcd1..d97c41f 100644 (file)
--- a/macro.h
+++ b/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);
 }
diff --git a/main.c b/main.c
index da21c23..b70ed05 100644 (file)
--- a/main.c
+++ b/main.c
 
 #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())
-                       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())) {
+               /* must be processed after all queues, so they are empty */
+               if (select_main(1, NULL, NULL, NULL))
                        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
 
diff --git a/main.h b/main.h
index 0dc82d4..9b750e1 100644 (file)
--- a/main.h
+++ b/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
index 403253d..e2f01ec 100644 (file)
--- a/message.c
+++ b/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;
+}
+
index 63abc65..a7f15b7 100644 (file)
--- a/message.h
+++ b/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);
 
 
index f58d7f9..eff38ce 100644 (file)
--- a/options.c
+++ b/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"
index 5998bc6..e88175b 100644 (file)
--- a/port.cpp
+++ b/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)
+{
+}
 
diff --git a/port.h b/port.h
index 5e8eba9..d71771f 100644 (file)
--- a/port.h
+++ b/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);
diff --git a/route.c b/route.c
index 126424f..a448f39 100644 (file)
--- a/route.c
+++ b/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(&current_time, NULL);
+                                       now_ll = current_time.tv_sec * MICRO_SECONDS + current_time.tv_usec;
+                               }
+                               timeout = now_ll + (cond->integer_value * MICRO_SECONDS);
                                istrue = 1;
                                break;
 
@@ -2166,10 +2182,10 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
 
                        cond = cond->next;
                }
-               if (timeout>now_d && match==1) /* the matching rule with timeout in the future */
-               if (e_match_timeout<1 || timeout<e_match_timeout) { /* first timeout or lower */
+               if (timeout>now_ll && match==1) /* the matching rule with timeout in the future */
+               if (match_timeout == 0 || timeout < match_timeout) { /* first timeout or lower */
                        /* set timeout in the furture */
-                       e_match_timeout = timeout;
+                       match_timeout = timeout;
                        e_match_to_action = rule->action_first;
                        e_match_to_extdialing = e_dialinginfo.id + dialing_required;
                        match = 0; /* matches in the future */
@@ -2177,7 +2193,7 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
                if (match == 1) {
                        /* matching, we return first action */
                        action = rule->action_first;
-                       e_match_timeout = 0; /* no timeout */
+                       match_timeout = 0; /* no timeout */
                        e_match_to_action = NULL;
                        e_extdialing = e_dialinginfo.id + dialing_required;
                        break;
@@ -2188,6 +2204,11 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
                }
                rule = rule->next;
        }
+       if (match_timeout == 0)
+               unsched_timer(&e_match_timeout); /* no timeout */
+       else {
+               schedule_timer(&e_match_timeout, match_timeout / 1000000, match_timeout % 1000000);
+       }
        return(action);
 }
 
diff --git a/select.c b/select.c
new file mode 100644 (file)
index 0000000..ba9b563
--- /dev/null
+++ b/select.c
@@ -0,0 +1,434 @@
+/* based on code from OpenBSC */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include "macro.h"
+#include "select.h"
+
+static int maxfd = 0;
+static int unregistered;
+static struct lcr_fd *fd_first = NULL;
+static struct timeval *nearest_timer(struct timeval *select_timer, int *work);
+static int next_work(void);
+
+int _register_fd(struct lcr_fd *fd, int when, int (*cb)(struct lcr_fd *fd, unsigned int what, void *instance, int index), void *instance, int index, const char *func)
+{
+       int flags;
+
+       if (fd->inuse)
+               FATAL("FD that is registered in function %s is already in use\n", func);
+//     printf("registering fd %d  %s\n", fd->fd, func);
+
+       /* make FD nonblocking */
+       flags = fcntl(fd->fd, F_GETFL);
+       if (flags < 0)
+               FATAL("Failed to F_GETFL\n");
+       flags |= O_NONBLOCK;
+       flags = fcntl(fd->fd, F_SETFL, flags);
+       if (flags < 0)
+               FATAL("Failed to F_SETFL O_NONBLOCK\n");
+
+       /* Register FD */
+       if (fd->fd > maxfd)
+               maxfd = fd->fd;
+
+       /* append to list */
+       fd->inuse = 1;
+       fd->when = when;
+       fd->cb = cb;
+       fd->cb_instance = instance;
+       fd->cb_index = index;
+       fd->next = fd_first;
+       fd_first = fd;
+
+       return 0;
+}
+
+void _unregister_fd(struct lcr_fd *fd, const char *func)
+{
+       struct lcr_fd **lcr_fdp;
+
+       /* find pointer to fd */
+       lcr_fdp = &fd_first;
+       while(*lcr_fdp) {
+               if (*lcr_fdp == fd)
+                       break;
+               lcr_fdp = &((*lcr_fdp)->next);
+       }
+       if (!*lcr_fdp) {
+               FATAL("FD unregistered in function %s not in list\n", func);
+       }
+
+       /* remove fd from list */
+       fd->inuse = 0;
+       *lcr_fdp = fd->next;
+       unregistered = 1;
+}
+
+
+int select_main(int polling, int *global_change, void (*lock)(void), void (*unlock)(void))
+{
+       struct lcr_fd *lcr_fd;
+       fd_set readset, writeset, exceptset;
+       int work = 0, temp, rc;
+       struct timeval no_time = {0, 0};
+       struct timeval select_timer, *timer;
+
+       /* goto again;
+        *
+        * this ensures that select is only called until:
+        * - no work event exists
+        * - and no timeout occurred
+        *
+        * if no future timeout exists, select will wait infinit.
+        */
+
+again:
+       /* process all work events */
+       if (next_work()) {
+               work = 1;
+               goto again;
+       }
+
+       /* process timer events and get timeout for next timer event */
+       temp = 0;
+       timer = nearest_timer(&select_timer, &temp);
+       if (temp) {
+               work = 1;
+               goto again;
+       }
+       if (polling)
+               timer = &no_time;
+#warning TESTING
+       if (!timer)
+               printf("wait till infinity ..."); fflush(stdout);
+
+       FD_ZERO(&readset);
+       FD_ZERO(&writeset);
+       FD_ZERO(&exceptset);
+
+       /* prepare read and write fdsets */
+       lcr_fd = fd_first;
+       while(lcr_fd) {
+               if (lcr_fd->when & LCR_FD_READ)
+                       FD_SET(lcr_fd->fd, &readset);
+               if (lcr_fd->when & LCR_FD_WRITE)
+                       FD_SET(lcr_fd->fd, &writeset);
+               if (lcr_fd->when & LCR_FD_EXCEPT)
+                       FD_SET(lcr_fd->fd, &exceptset);
+               lcr_fd = lcr_fd->next;
+       }
+
+       if (unlock)
+               unlock();
+       rc = select(maxfd+1, &readset, &writeset, &exceptset, timer);
+       if (lock)
+               lock();
+#warning TESTING
+       if (!timer)
+               printf("interrupted.\n");
+       if (rc < 0)
+               return 0;
+       if (global_change && *global_change) {
+               *global_change = 0;
+               return 1;
+       }
+
+       /* fire timers */
+#if 0
+       bsc_update_timers();
+#endif
+
+       /* call registered callback functions */
+restart:
+       unregistered = 0;
+       lcr_fd = fd_first;
+       while(lcr_fd) {
+               int flags = 0;
+
+               if (FD_ISSET(lcr_fd->fd, &readset)) {
+                       flags |= LCR_FD_READ;
+                       FD_CLR(lcr_fd->fd, &readset);
+               }
+               if (FD_ISSET(lcr_fd->fd, &writeset)) {
+                       flags |= LCR_FD_WRITE;
+                       FD_CLR(lcr_fd->fd, &writeset);
+               }
+               if (FD_ISSET(lcr_fd->fd, &exceptset)) {
+                       flags |= LCR_FD_EXCEPT;
+                       FD_CLR(lcr_fd->fd, &exceptset);
+               }
+               if (flags) {
+                       work = 1;
+                       lcr_fd->cb(lcr_fd, flags, lcr_fd->cb_instance, lcr_fd->cb_index);
+                       if (unregistered)
+                               goto restart;
+                       return 1;
+               }
+               lcr_fd = lcr_fd->next;
+       }
+       return work;
+}
+
+
+static struct lcr_timer *timer_first = NULL;
+
+int _add_timer(struct lcr_timer *timer, int (*cb)(struct lcr_timer *timer, void *instance, int index), void *instance, int index, const char *func)
+{
+       if (timer->inuse) {
+               FATAL("timer that is registered in function %s is already in use\n", func);
+       }
+
+#if 0
+       struct lcr_timer *test = timer_first;
+       while(test) {
+               if (test == timer)
+                       FATAL("Timer already in list %s\n", func);
+               test = test->next;
+       }
+#endif
+
+       timer->inuse = 1;
+       timer->active = 0;
+       timer->timeout.tv_sec = 0;
+       timer->timeout.tv_usec = 0;
+       timer->cb = cb;
+       timer->cb_instance = instance;
+       timer->cb_index = index;
+       timer->next = timer_first;
+       timer_first = timer;
+
+       return 0;
+}
+
+void _del_timer(struct lcr_timer *timer, const char *func)
+{
+       struct lcr_timer **lcr_timerp;
+
+       /* find pointer to timer */
+       lcr_timerp = &timer_first;
+       while(*lcr_timerp) {
+               if (*lcr_timerp == timer)
+                       break;
+               lcr_timerp = &((*lcr_timerp)->next);
+       }
+       if (!*lcr_timerp) {
+               FATAL("timer deleted in function %s not in list\n", func);
+       }
+
+       /* remove timer from list */
+       timer->inuse = 0;
+       *lcr_timerp = timer->next;
+}
+
+void schedule_timer(struct lcr_timer *timer, int seconds, int microseconds)
+{
+       struct timeval current_time;
+
+       if (!timer->inuse) {
+               FATAL("Timer not added\n");
+       }
+
+       gettimeofday(&current_time, NULL);
+       unsigned long long currentTime = current_time.tv_sec * MICRO_SECONDS + current_time.tv_usec;
+       currentTime += seconds * MICRO_SECONDS + microseconds;
+       timer->timeout.tv_sec = currentTime / MICRO_SECONDS;
+       timer->timeout.tv_usec = currentTime % MICRO_SECONDS;
+       timer->active = 1;
+}
+
+void unsched_timer(struct lcr_timer *timer)
+{
+       timer->active = 0;
+}
+
+/* if a timeout is reached, process timer, if not, return timer value for select */
+static struct timeval *nearest_timer(struct timeval *select_timer, int *work)
+{
+       struct timeval current;
+       struct timeval *nearest = NULL;
+       struct lcr_timer *lcr_timer, *lcr_nearest = NULL;
+
+       /* find nearest timer, or NULL, if no timer active */
+       lcr_timer = timer_first;
+       while(lcr_timer) {
+               if (lcr_timer->active && (!nearest || TIME_SMALLER(&lcr_timer->timeout, nearest))) {
+                       nearest = &lcr_timer->timeout;
+                       lcr_nearest = lcr_timer;
+               }
+               lcr_timer = lcr_timer->next;
+       }
+
+       select_timer->tv_sec = 0;
+       select_timer->tv_usec = 0;
+
+       if (!nearest)
+               return NULL; /* wait until infinity */
+
+       gettimeofday(&current, NULL);
+       unsigned long long nearestTime = nearest->tv_sec * MICRO_SECONDS + nearest->tv_usec;
+       unsigned long long currentTime = current.tv_sec * MICRO_SECONDS + current.tv_usec;
+
+       if (nearestTime > currentTime) {
+               select_timer->tv_sec = (nearestTime - currentTime) / MICRO_SECONDS;
+               select_timer->tv_usec = (nearestTime - currentTime) % MICRO_SECONDS;
+               return select_timer;
+       } else {
+               lcr_nearest->active = 0;
+               (*lcr_nearest->cb)(lcr_nearest, lcr_nearest->cb_instance, lcr_nearest->cb_index);
+               /* don't wait so we can process the queues, indicate "work=1" */
+               select_timer->tv_sec = 0;
+               select_timer->tv_usec = 0;
+               *work = 1;
+               return select_timer;
+       }
+}
+
+
+static struct lcr_work *work_first = NULL; /* chain of work */
+static struct lcr_work *first_event = NULL, *last_event = NULL; /* chain of active events */
+
+#ifdef DEBUG_WORK
+void show_chain(const char *func)
+{
+       struct lcr_work *work = first_event;
+       printf("chain:%s\n", func);
+       while(work) {
+               printf("%p - %p - %p\n", work->prev_event, work, work->next_event);
+               work = work->next_event;
+       }
+}
+#endif
+
+int _add_work(struct lcr_work *work, int (*cb)(struct lcr_work *work, void *instance, int index), void *instance, int index, const char *func)
+{
+       if (work->inuse) {
+               FATAL("work that is registered in function %s is already in use\n", func);
+       }
+
+#ifdef DEBUG_WORK
+       printf("add work %p from function %s\n", work, func);
+       show_chain("before add");
+#endif
+       work->inuse = 1;
+       work->active = 0;
+       work->cb = cb;
+       work->cb_instance = instance;
+       work->cb_index = index;
+       work->next = work_first;
+       work_first = work;
+#ifdef DEBUG_WORK
+       show_chain("after add");
+#endif
+
+       return 0;
+}
+
+void _del_work(struct lcr_work *work, const char *func)
+{
+       struct lcr_work **lcr_workp;
+
+#ifdef DEBUG_WORK
+       show_chain("before detach");
+#endif
+       if (work->active) {
+               /* first event removed */
+               if (!work->prev_event)
+                       first_event = work->next_event;
+               else
+                       work->prev_event->next_event = work->next_event;
+               /* last event removed */
+               if (!work->next_event)
+                       last_event = work->prev_event;
+               else
+                       work->next_event->prev_event = work->prev_event;
+       }
+#ifdef DEBUG_WORK
+       show_chain("after detach");
+#endif
+
+       /* find pointer to work */
+       lcr_workp = &work_first;
+       while(*lcr_workp) {
+               if (*lcr_workp == work)
+                       break;
+               lcr_workp = &((*lcr_workp)->next);
+       }
+       if (!*lcr_workp) {
+               FATAL("work deleted by '%s' not in list\n", func);
+       }
+
+       /* remove work from list */
+       work->inuse = 0;
+       *lcr_workp = work->next;
+#ifdef DEBUG_WORK
+       show_chain("after delete");
+#endif
+}
+
+void trigger_work(struct lcr_work *work)
+{
+       if (!work->inuse) {
+               FATAL("Work not added\n");
+       }
+
+       /* event already triggered */
+       if (work->active)
+               return;
+
+#ifdef DEBUG_WORK
+       show_chain("before trigger");
+#endif
+       /* append to tail of chain */
+       if (last_event)
+               last_event->next_event = work;
+       work->prev_event = last_event;
+       work->next_event = NULL;
+       last_event = work;
+       if (!first_event)
+               first_event = work;
+#ifdef DEBUG_WORK
+       show_chain("after trigger");
+#endif
+
+       work->active = 1;
+}
+
+/* get first work and remove from event chain */
+static int next_work(void)
+{
+       struct lcr_work *lcr_work;
+
+       if (!first_event)
+               return 0;
+
+#ifdef DEBUG_WORK
+       show_chain("before next_work");
+#endif
+       if (!first_event->inuse) {
+               FATAL("Work not added\n");
+       }
+
+       /* detach from event chain */
+       lcr_work = first_event;
+       first_event = lcr_work->next_event;
+       if (!first_event)
+               last_event = NULL;
+       else
+               first_event->prev_event = NULL;
+
+#ifdef DEBUG_WORK
+       show_chain("after next_work");
+#endif
+       lcr_work->active = 0;
+
+       (*lcr_work->cb)(lcr_work, lcr_work->cb_instance, lcr_work->cb_index);
+
+       return 1;
+}
+
diff --git a/select.h b/select.h
new file mode 100644 (file)
index 0000000..c4e1418
--- /dev/null
+++ b/select.h
@@ -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);
+
+
index a33f626..b67b91f 100644 (file)
@@ -20,14 +20,15 @@ int sock = -1;
 struct sockaddr_un sock_address;
 
 struct admin_list *admin_first = NULL;
+static struct lcr_fd admin_fd;
+
+int admin_handle(struct lcr_fd *fd, unsigned int what, void *instance, int index);
 
 /*
  * initialize admin socket 
  */
 int admin_init(void)
 {
-       unsigned int on = 1;
-
        /* open and bind socket */
        if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
                PERROR("Failed to create admin socket. (errno=%d)\n", errno);
@@ -55,14 +56,9 @@ int admin_init(void)
                PERROR("Failed to listen to socket \"%s\". (errno=%d)\n", sock_address.sun_path, errno);
                return(-1);
        }
-       if (ioctl(sock, FIONBIO, (unsigned char *)(&on)) < 0) {
-               close(sock);
-               unlink(socket_name);
-               fhuse--;
-               sock = -1;
-               PERROR("Failed to set socket \"%s\" into non-blocking mode. (errno=%d)\n", sock_address.sun_path, errno);
-               return(-1);
-       }
+       memset(&admin_fd, 0, sizeof(admin_fd));
+       admin_fd.fd = sock;
+       register_fd(&admin_fd, LCR_FD_READ | LCR_FD_EXCEPT, admin_handle, NULL, 0);
        if (chmod(socket_name, options.socketrights) < 0) {
                PERROR("Failed to change socket rights to %d. (errno=%d)\n", options.socketrights, errno);
        }
@@ -86,6 +82,7 @@ void free_connection(struct admin_list *admin)
        class Join *join, *joinnext;
        struct mISDNport *mISDNport;
        int i, ii;
+       struct admin_list **adminp;
 
        /* free remote joins */
        if (admin->remote_name[0]) {
@@ -107,7 +104,7 @@ void free_connection(struct admin_list *admin)
                        while(i < ii) {
                                if (mISDNport->b_remote_id[i] == admin->sock) {