From baade7996195589adedfb22210ff82bd9aaf20fc Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Fri, 15 Jan 2010 21:28:33 +0100 Subject: Test fix for lcr and dtmf. modified: chan_lcr.c --- chan_lcr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/chan_lcr.c b/chan_lcr.c index e50847c..61905bf 100644 --- a/chan_lcr.c +++ b/chan_lcr.c @@ -1292,6 +1292,8 @@ int receive_message(int message_type, unsigned int ref, union parameter *param) /* store new ref */ call->ref = ref; call->ref_was_assigned = 1; + /* set dtmf (default, use option 'n' to disable */ + call->dsp_dtmf = 1; /* send pending setup info */ if (call->state == CHAN_LCR_STATE_OUT_PREPARE) send_setup_to_lcr(call); -- cgit v1.2.3-55-g7522 From 043714d9d457d5461b0a46680e1501c0736e2586 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Fri, 15 Jan 2010 21:50:35 +0100 Subject: New version 1.7 modified: Makefile.in modified: README modified: configure modified: configure.ac --- Makefile.in | 8 ++++---- README | 6 ++++++ configure | 20 ++++++++++---------- configure.ac | 4 ++-- 4 files changed, 22 insertions(+), 16 deletions(-) diff --git a/Makefile.in b/Makefile.in index efdabb3..1bf2262 100644 --- a/Makefile.in +++ b/Makefile.in @@ -293,15 +293,15 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ - echo ' cd $(srcdir) && $(AUTOMAKE) --gnu '; \ - cd $(srcdir) && $(AUTOMAKE) --gnu \ + echo ' cd $(srcdir) && $(AUTOMAKE) --foreign '; \ + cd $(srcdir) && $(AUTOMAKE) --foreign \ && exit 0; \ exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ cd $(top_srcdir) && \ - $(AUTOMAKE) --gnu Makefile + $(AUTOMAKE) --foreign Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ diff --git a/README b/README index 354c912..fc9bd4b 100644 --- a/README +++ b/README @@ -526,5 +526,11 @@ Changes after Version 1.6 -> New option for chan_lcr: 'k' -> New dialing parameter for LCR: keypad - Keep up with current OpenBSC API +- Fixed DTMF detection option with chan_lcr + +New release Version 1.7 + +Changes after Version 1.7 + diff --git a/configure b/configure index d9875f8..9340f73 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.63 for lcr 1.6. +# Generated by GNU Autoconf 2.63 for lcr 1.7. # # Report bugs to . # @@ -596,8 +596,8 @@ SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME='lcr' PACKAGE_TARNAME='lcr' -PACKAGE_VERSION='1.6' -PACKAGE_STRING='lcr 1.6' +PACKAGE_VERSION='1.7' +PACKAGE_STRING='lcr 1.7' PACKAGE_BUGREPORT='andreas@eversberg.eu' ac_unique_file="main.c" @@ -1303,7 +1303,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures lcr 1.6 to adapt to many kinds of systems. +\`configure' configures lcr 1.7 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1369,7 +1369,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of lcr 1.6:";; + short | recursive ) echo "Configuration of lcr 1.7:";; esac cat <<\_ACEOF @@ -1471,7 +1471,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -lcr configure 1.6 +lcr configure 1.7 generated by GNU Autoconf 2.63 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, @@ -1485,7 +1485,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by lcr $as_me 1.6, which was +It was created by lcr $as_me 1.7, which was generated by GNU Autoconf 2.63. Invocation command line was $ $0 $@ @@ -4043,7 +4043,7 @@ fi # Define the identity of the package. PACKAGE=lcr - VERSION=1.6 + VERSION=1.7 cat >>confdefs.h <<_ACEOF @@ -10181,7 +10181,7 @@ exec 6>&1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by lcr $as_me 1.6, which was +This file was extended by lcr $as_me 1.7, which was generated by GNU Autoconf 2.63. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -10244,7 +10244,7 @@ Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_version="\\ -lcr config.status 1.6 +lcr config.status 1.7 configured by $0, generated by GNU Autoconf 2.63, with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" diff --git a/configure.ac b/configure.ac index 494b352..d138e16 100644 --- a/configure.ac +++ b/configure.ac @@ -24,7 +24,7 @@ dnl Boston, MA 02110-1301, USA. dnl This keeps being the first instruction. dnl Change the 2nd argument if the version increases dnl 1st + 2nd argument is used for distribution package name -AC_INIT(lcr, 1.6, andreas@eversberg.eu) +AC_INIT(lcr, 1.7, andreas@eversberg.eu) AC_PREREQ(2.59) AC_CONFIG_SRCDIR([main.c]) AM_CONFIG_HEADER(config.h) @@ -32,7 +32,7 @@ AM_CONFIG_HEADER(config.h) # fix warnings from autoconf + automake AC_GNU_SOURCE # AC_USE_SYSTEM_EXTENSIONS -AM_INIT_AUTOMAKE(lcr,1.6) +AM_INIT_AUTOMAKE(lcr,1.7) -- cgit v1.2.3-55-g7522 From 473d6569efcad130f9a5044b182b75a1c07a1eee Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Fri, 15 Jan 2010 21:55:25 +0100 Subject: Added new option to interface.conf: "nonotify" to disable notify messages. modified: README modified: dss1.cpp modified: interface.c modified: interface.h modified: mISDN.cpp modified: mISDN.h --- README | 1 + dss1.cpp | 7 +++++++ interface.c | 25 +++++++++++++++++++++++-- interface.h | 1 + mISDN.cpp | 21 ++++++++++++++------- mISDN.h | 2 +- 6 files changed, 47 insertions(+), 10 deletions(-) diff --git a/README b/README index fc9bd4b..c495bd7 100644 --- a/README +++ b/README @@ -531,6 +531,7 @@ Changes after Version 1.6 New release Version 1.7 Changes after Version 1.7 +- Added new option to interface.conf: "nonotify" to disable notify messages. diff --git a/dss1.cpp b/dss1.cpp index e318aa3..75ff448 100644 --- a/dss1.cpp +++ b/dss1.cpp @@ -2240,6 +2240,13 @@ void Pdss1::message_notify(unsigned int epoint_id, int message_id, union paramet int notify; int plan = 0, type = -1, present = 0; + if (p_m_mISDNport->ifport->nonotify) { + l1l2l3_trace_header(p_m_mISDNport, this, L3_NOTIFY_REQ, DIRECTION_OUT); + add_trace("info", NULL, "blocked by config"); + end_trace(); + return; + } + // printf("if = %d\n", param->notifyinfo.notify); if (param->notifyinfo.notify>INFO_NOTIFY_NONE) notify = param->notifyinfo.notify & 0x7f; diff --git a/interface.c b/interface.c index 0b72061..a4bac2d 100644 --- a/interface.c +++ b/interface.c @@ -916,6 +916,22 @@ static int inter_gsm(struct interface *interface, char *filename, int line, char return(0); #endif } +static int inter_nonotify(struct interface *interface, char *filename, int line, char *parameter, char *value) +{ + struct interface_port *ifport; + + /* port in chain ? */ + if (!interface->ifport) { + SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter); + return(-1); + } + /* goto end of chain */ + ifport = interface->ifport; + while(ifport->next) + ifport = ifport->next; + ifport->nonotify = 1; + return(0); +} #ifdef WITH_SS5 static int inter_ss5(struct interface *interface, char *filename, int line, char *parameter, char *value) { @@ -1097,7 +1113,12 @@ struct interface_param interface_param[] = { {"gsm", &inter_gsm, "", "Sets up GSM interface for using OpenBSC.\n" "This interface must be a loopback interface. The second loopback interface\n" - "must be assigned to OpenBSC"}, + "must be assigned to OpenBSC."}, + + {"nonotify", &inter_nonotify, "", + "Prevents sending notify messages to this interface. A call placed on hold will\n" + "Not affect the remote end (phone or telcom switch).\n" + "This parameter must follow a 'port' parameter."}, #ifdef WITH_SS5 {"ccitt5", &inter_ss5, "[ [feature ...]]", @@ -1430,7 +1451,7 @@ void load_port(struct interface_port *ifport) struct mISDNport *mISDNport; /* open new port */ - mISDNport = mISDNport_open(ifport->portnum, ifport->portname, ifport->ptp, ifport->nt, ifport->tespecial, ifport->l1hold, ifport->l2hold, ifport->interface, ifport->gsm, ifport->ss5); + mISDNport = mISDNport_open(ifport); if (mISDNport) { /* link port */ ifport->mISDNport = mISDNport; diff --git a/interface.h b/interface.h index 508a33e..7dce3ad 100644 --- a/interface.h +++ b/interface.h @@ -67,6 +67,7 @@ struct interface_port { // int tout_park; int dialmax; /* maximum number of digits to dial */ char tones_dir[128]; + int nonotify; /* blocks outgoing notify messages */ }; struct interface_msn { diff --git a/mISDN.cpp b/mISDN.cpp index ce885d9..e531b14 100644 --- a/mISDN.cpp +++ b/mISDN.cpp @@ -2045,10 +2045,17 @@ int mISDN_getportbyname(int sock, int cnt, char *portname) /* * global function to add a new card (port) */ -struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt, int te_special, int l1hold, int l2hold, struct interface *interface, int gsm, unsigned int ss5) +struct mISDNport *mISDNport_open(struct interface_port *ifport) { int ret; struct mISDNport *mISDNport, **mISDNportp; + int port = ifport->portnum; + int ptp = ifport->ptp; + int force_nt = ifport->nt; + int l1hold = ifport->l1hold; + int l2hold = ifport->l2hold; + int gsm = ifport->gsm; + int ss5 = ifport->ss5; int i, cnt; int pri, bri, pots; int nt, te; @@ -2068,12 +2075,12 @@ struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt return(NULL); } if (port < 0) { - port = mISDN_getportbyname(mISDNsocket, cnt, portname); + port = mISDN_getportbyname(mISDNsocket, cnt, ifport->portname); if (port < 0) { if (gsm) - PERROR_RUNTIME("Port name '%s' not found, did you load loopback interface for GSM?.\n", portname); + PERROR_RUNTIME("Port name '%s' not found, did you load loopback interface for GSM?.\n", ifport->portname); else - PERROR_RUNTIME("Port name '%s' not found, use 'misdn_info' tool to list all existing ports.\n", portname); + PERROR_RUNTIME("Port name '%s' not found, use 'misdn_info' tool to list all existing ports.\n", ifport->portname); return(NULL); } // note: 'port' has still the port number @@ -2275,7 +2282,7 @@ struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt mqueue_purge(&mISDNport->upqueue); PERROR_RUNTIME("open_layer3() failed for port %d\n", port); start_trace(port, - interface, + ifport->interface, NULL, NULL, DIRECTION_NONE, @@ -2292,7 +2299,7 @@ struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt mISDNport->b_num = devinfo.nrbchan; mISDNport->portnum = port; mISDNport->ntmode = nt; - mISDNport->tespecial = te_special; + mISDNport->tespecial = ifport->tespecial; mISDNport->pri = pri; mISDNport->ptp = ptp; mISDNport->l1hold = l1hold; @@ -2322,7 +2329,7 @@ struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt PDEBUG(DEBUG_BCHANNEL, "using 'mISDN_dsp.o' module\n"); start_trace(mISDNport->portnum, - interface, + ifport->interface, NULL, NULL, DIRECTION_NONE, diff --git a/mISDN.h b/mISDN.h index f8d2341..cbebcac 100644 --- a/mISDN.h +++ b/mISDN.h @@ -92,7 +92,7 @@ calls with no bchannel (call waiting, call on hold). int mISDN_initialize(void); void mISDN_deinitialize(void); int mISDN_getportbyname(int sock, int cnt, char *portname); -struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt, int te_special, int l1hold, int l2hold, struct interface *interface, int gsm, unsigned int ss5); +struct mISDNport *mISDNport_open(struct interface_port *ifport); void mISDNport_static(struct mISDNport *mISDNport); void mISDNport_close_all(void); void mISDNport_close(struct mISDNport *mISDNport); -- cgit v1.2.3-55-g7522 From b0bd74e35e935aa976b68c594def4e8d2c22ef95 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sat, 16 Jan 2010 11:20:23 +0100 Subject: Replaced polling loop for LCR and chan_lcr with select based event loop. Now LCR and chan_lcr will not use any CPU until there is work to do. --- Makefile.am | 7 +- Makefile.in | 43 +++-- README | 2 + action.cpp | 56 +++--- action_vbox.cpp | 98 +++++----- apppbx.cpp | 375 +++++++++++++++++++++----------------- apppbx.h | 27 +-- bchannel.c | 124 ++++++------- bchannel.h | 2 +- chan_lcr.c | 473 ++++++++++++++++++++++++++---------------------- chan_lcr.h | 2 + crypt.cpp | 60 ++++--- crypt.h | 2 +- dss1.cpp | 98 +++++----- dss1.h | 2 +- endpoint.cpp | 23 +-- endpoint.h | 2 +- endpointapp.cpp | 5 - endpointapp.h | 1 - gsm.cpp | 147 +++++++++------ gsm.h | 3 +- join.cpp | 9 - join.h | 1 - joinpbx.cpp | 49 ++--- joinpbx.h | 3 +- joinremote.cpp | 11 -- joinremote.h | 1 - lcradmin.c | 1 + mISDN.cpp | 544 +++++++++++++++++++++++++++++++------------------------- mISDN.h | 18 +- macro.h | 4 +- main.c | 257 +++----------------------- main.h | 6 +- message.c | 80 +++++++++ message.h | 10 +- options.c | 10 +- port.cpp | 27 ++- port.h | 3 +- route.c | 35 +++- select.c | 434 ++++++++++++++++++++++++++++++++++++++++++++ select.h | 62 +++++++ socket_server.c | 194 ++++++++------------ socket_server.h | 2 +- ss5.cpp | 97 +++++----- ss5.h | 4 +- trace.c | 9 +- vbox.cpp | 204 +++++++++++---------- vbox.h | 7 +- 48 files changed, 2103 insertions(+), 1531 deletions(-) create mode 100644 select.c create mode 100644 select.h diff --git a/Makefile.am b/Makefile.am index bce48d1..17f9a29 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 \ diff --git a/Makefile.in b/Makefile.in index 1bf2262..1a2bd77 100644 --- a/Makefile.in +++ b/Makefile.in @@ -61,7 +61,8 @@ am_chan_lcr_so_OBJECTS = chan_lcr_so_OBJECTS = $(am_chan_lcr_so_OBJECTS) @ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@chan_lcr_so_DEPENDENCIES = \ @ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@ chan_lcr.po bchannel.po \ -@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@ options.po callerid.po +@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@ options.po callerid.po \ +@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@ select.po am_genextension_OBJECTS = genext.$(OBJEXT) options.$(OBJEXT) \ extension.$(OBJEXT) genextension_OBJECTS = $(am_genextension_OBJECTS) @@ -78,28 +79,28 @@ genwave_LDADD = $(LDADD) am__lcr_SOURCES_DIST = gsm_audio.c gsm.cpp gsm_conf.c \ openbsc/src/bsc_init.c openbsc/src/vty_interface.c \ openbsc/src/vty_interface_layer3.c ss5.cpp ss5_encode.c \ - ss5_decode.c action.cpp mISDN.cpp tones.c action_efi.cpp \ - crypt.cpp mail.c trace.c action_vbox.cpp dss1.cpp main.c \ - vbox.cpp alawulaw.c endpoint.cpp interface.c message.c \ - apppbx.cpp endpointapp.cpp join.cpp options.c extension.c \ - joinpbx.cpp port.cpp callerid.c joinremote.cpp route.c cause.c \ - socket_server.c + ss5_decode.c select.c action.cpp mISDN.cpp tones.c \ + action_efi.cpp crypt.cpp mail.c trace.c action_vbox.cpp \ + dss1.cpp main.c vbox.cpp alawulaw.c endpoint.cpp interface.c \ + message.c apppbx.cpp endpointapp.cpp join.cpp options.c \ + extension.c joinpbx.cpp port.cpp callerid.c joinremote.cpp \ + route.c cause.c socket_server.c @ENABLE_GSM_TRUE@am__objects_1 = gsm_audio.$(OBJEXT) gsm.$(OBJEXT) \ @ENABLE_GSM_TRUE@ gsm_conf.$(OBJEXT) bsc_init.$(OBJEXT) \ @ENABLE_GSM_TRUE@ vty_interface.$(OBJEXT) \ @ENABLE_GSM_TRUE@ vty_interface_layer3.$(OBJEXT) @ENABLE_SS5_TRUE@am__objects_2 = ss5.$(OBJEXT) ss5_encode.$(OBJEXT) \ @ENABLE_SS5_TRUE@ ss5_decode.$(OBJEXT) -am_lcr_OBJECTS = $(am__objects_1) $(am__objects_2) action.$(OBJEXT) \ - mISDN.$(OBJEXT) tones.$(OBJEXT) action_efi.$(OBJEXT) \ - crypt.$(OBJEXT) mail.$(OBJEXT) trace.$(OBJEXT) \ - action_vbox.$(OBJEXT) dss1.$(OBJEXT) main.$(OBJEXT) \ - vbox.$(OBJEXT) alawulaw.$(OBJEXT) endpoint.$(OBJEXT) \ - interface.$(OBJEXT) message.$(OBJEXT) apppbx.$(OBJEXT) \ - endpointapp.$(OBJEXT) join.$(OBJEXT) options.$(OBJEXT) \ - extension.$(OBJEXT) joinpbx.$(OBJEXT) port.$(OBJEXT) \ - callerid.$(OBJEXT) joinremote.$(OBJEXT) route.$(OBJEXT) \ - cause.$(OBJEXT) socket_server.$(OBJEXT) +am_lcr_OBJECTS = $(am__objects_1) $(am__objects_2) select.$(OBJEXT) \ + action.$(OBJEXT) mISDN.$(OBJEXT) tones.$(OBJEXT) \ + action_efi.$(OBJEXT) crypt.$(OBJEXT) mail.$(OBJEXT) \ + trace.$(OBJEXT) action_vbox.$(OBJEXT) dss1.$(OBJEXT) \ + main.$(OBJEXT) vbox.$(OBJEXT) alawulaw.$(OBJEXT) \ + endpoint.$(OBJEXT) interface.$(OBJEXT) message.$(OBJEXT) \ + apppbx.$(OBJEXT) endpointapp.$(OBJEXT) join.$(OBJEXT) \ + options.$(OBJEXT) extension.$(OBJEXT) joinpbx.$(OBJEXT) \ + port.$(OBJEXT) callerid.$(OBJEXT) joinremote.$(OBJEXT) \ + route.$(OBJEXT) cause.$(OBJEXT) socket_server.$(OBJEXT) lcr_OBJECTS = $(am_lcr_OBJECTS) am__DEPENDENCIES_1 = @ENABLE_GSM_TRUE@am__DEPENDENCIES_2 = /usr/lib/libgsm.a \ @@ -258,9 +259,9 @@ INSTALLATION_DEFINES = \ @ENABLE_SS5_TRUE@SS5_SOURCE = ss5.cpp ss5_encode.c ss5_decode.c @ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@chan_lcr_so_SOURCES = @ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@chan_lcr_so_LDFLAGS = -shared -@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@chan_lcr_so_LDADD = chan_lcr.po bchannel.po options.po callerid.po +@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@chan_lcr_so_LDADD = chan_lcr.po bchannel.po options.po callerid.po select.po INCLUDES = $(all_includes) $(GSM_INCLUDE) $(SS5_INCLUDE) -Wall -I/usr/include/mISDNuser $(INSTALLATION_DEFINES) -lcr_SOURCES = $(GSM_SOURCE) $(SS5_SOURCE) action.cpp mISDN.cpp tones.c \ +lcr_SOURCES = $(GSM_SOURCE) $(SS5_SOURCE) select.c action.cpp mISDN.cpp tones.c \ action_efi.cpp crypt.cpp mail.c trace.c \ action_vbox.cpp dss1.cpp main.c \ vbox.cpp alawulaw.c endpoint.cpp interface.c message.c \ @@ -446,6 +447,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/options.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/port.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/route.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/select.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket_server.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss5.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss5_decode.Po@am__quote@ @@ -819,6 +821,9 @@ uninstall-am: uninstall-binPROGRAMS uninstall-info-am \ @ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@options.po: options.c options.h @ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@ $(CC) $(INCLUDES) -D_GNU_SOURCE -fPIC -c options.c -o options.po +@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@select.po: select.c select.h +@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@ $(CC) $(INCLUDES) -D_GNU_SOURCE -fPIC -c select.c -o select.po + @ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@install-exec-hook: @ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@ mkdir -p $(astmoddir) @ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@ $(INSTALL) -d $(astmoddir) diff --git a/README b/README index c495bd7..2515150 100644 --- 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. diff --git a/action.cpp b/action.cpp index d720dbe..bf7c23d 100644 --- a/action.cpp +++ b/action.cpp @@ -644,16 +644,16 @@ void EndpointAppPBX::action_dialing_login(void) e_ruleset = NULL; e_rule = NULL; e_action = &action_password; - e_match_timeout = 0; + unsched_timer(&e_match_timeout); e_match_to_action = NULL; e_dialinginfo.id[0] = '\0'; e_extdialing = strchr(e_dialinginfo.id, '\0'); /* set timeout */ - e_password_timeout = now+20; + schedule_timer(&e_password_timeout, 20, 0); /* do dialing */ - process_dialing(); + process_dialing(0); } else { /* make call state */ new_state(EPOINT_STATE_IN_OVERLAP); @@ -945,7 +945,7 @@ void EndpointAppPBX::_action_redial_reply(int in) SCPY(e_dialinginfo.id, last); e_extdialing = e_dialinginfo.id; e_action = NULL; - process_dialing(); + process_dialing(0); return; } e_extdialing[0] = '\0'; @@ -1039,10 +1039,10 @@ void EndpointAppPBX::action_dialing_powerdial(void) /* do dialing */ SCPY(e_dialinginfo.id, e_ext.last_out[0]); - e_powerdialing = -1; /* indicates the existence of powerdialing but no redial time given */ + e_powerdial_on = 1; /* indicates the existence of powerdialing but no redial time given */ e_powercount = 0; e_action = NULL; - process_dialing(); + process_dialing(0); } @@ -1144,7 +1144,7 @@ void EndpointAppPBX::action_hangup_callback(void) end_trace(); /* set time to callback */ - e_callback = now_d + delay; + schedule_timer(&e_callback_timeout, delay, 0); } @@ -1197,7 +1197,7 @@ void EndpointAppPBX::action_dialing_abbrev(void) SCPY(e_dialinginfo.id, phone); e_extdialing = e_dialinginfo.id; e_action = NULL; - process_dialing(); + process_dialing(0); } @@ -1701,7 +1701,7 @@ void EndpointAppPBX::_action_goto_menu(int mode) /* do dialing with new ruleset */ e_action = NULL; - process_dialing(); + process_dialing(0); } /* process dialing goto @@ -1839,7 +1839,7 @@ void EndpointAppPBX::action_dialing_help(void) e_extdialing = e_dialinginfo.id+strlen(numbering->prefix); PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s selected a new menu '%s' dialing: %s\n", ea_endpoint->ep_serial, e_ext.number, numb_actions[numbering->action], e_dialinginfo.id); nesting?: - process_dialing(); + process_dialing(0); return; } @@ -2098,11 +2098,16 @@ void EndpointAppPBX::action_dialing_password_wr(void) * depending on the detected prefix, subfunctions above (action_*) will be * calles. */ -void EndpointAppPBX::process_dialing(void) +void EndpointAppPBX::process_dialing(int timeout) { struct port_list *portlist = ea_endpoint->ep_portlist; struct lcr_msg *message; struct route_param *rparam; + struct timeval current_time; + + /* set if timeout is active, or if timeout value was given due to timeout action */ + if (e_action_timeout.active) + timeout = 1; //#warning Due to HANG-BUG somewhere here, I added some HANG-BUG-DEBUGGING output that cannot be disabled. after bug has been found, this will be removed. //PDEBUG(~0, "HANG-BUG-DEBUGGING: entered porcess_dialing\n"); @@ -2111,8 +2116,8 @@ void EndpointAppPBX::process_dialing(void) if (!portlist) { portlist_error: PDEBUG(DEBUG_EPOINT, "EPOINT(%d): note: dialing call requires exactly one port object to process dialing. this case could happen due to a parked call. we end dialing here.\n", ea_endpoint->ep_serial, e_ext.number); - e_action_timeout = 0; - e_match_timeout = 0; + unsched_timer(&e_action_timeout); + unsched_timer(&e_match_timeout); return; } if (portlist->next) { @@ -2127,15 +2132,15 @@ void EndpointAppPBX::process_dialing(void) new_state(EPOINT_STATE_OUT_DISCONNECT); message_disconnect_port(portlist, CAUSE_UNSPECIFIED, LOCATION_PRIVATE_LOCAL, ""); set_tone(portlist, "cause_3f"); - e_action_timeout = 0; - e_match_timeout = 0; + unsched_timer(&e_action_timeout); + unsched_timer(&e_match_timeout); goto end; } //PDEBUG(~0, "HANG-BUG-DEBUGGING: before action-timeout processing\n"); /* process timeout */ - if (e_action && e_action_timeout) { /* e_action may be NULL, but e_action_timeout may still be set and must be ignored */ - e_action_timeout = 0; + if (e_action && timeout) { /* e_action may be NULL, but e_action_timeout may still be set and must be ignored */ + unsched_timer(&e_action_timeout); if (e_state == EPOINT_STATE_CONNECT) { PDEBUG(DEBUG_ROUTE|DEBUG_EPOINT, "EPOINT(%d): action timed out, but we already have connected, so we stop timer and continue.\n", ea_endpoint->ep_serial); goto end; @@ -2163,7 +2168,7 @@ void EndpointAppPBX::process_dialing(void) if (e_state!=EPOINT_STATE_IN_SETUP && e_state!=EPOINT_STATE_IN_OVERLAP) { PDEBUG(DEBUG_EPOINT, "EPOINT(%d): we are not in incoming setup/overlap state, so we ignore init/dialing process.\n", ea_endpoint->ep_serial, e_rule_nesting); - e_match_timeout = 0; + unsched_timer(&e_match_timeout); goto end; } @@ -2176,8 +2181,8 @@ void EndpointAppPBX::process_dialing(void) e_dialinginfo.id[0] = '\0'; e_action = NUMB_ACTION_MENU; e_menu = 0; - process_dialing(); - e_match_timeout = 0; + process_dialing(0); + unsched_timer(&e_match_timeout); goto end; } /* invalid dialing */ @@ -2194,7 +2199,7 @@ void EndpointAppPBX::process_dialing(void) } new_state(EPOINT_STATE_OUT_DISCONNECT); set_tone(portlist,"cause_1c"); - e_match_timeout = 0; + unsched_timer(&e_match_timeout); goto end; } #endif @@ -2230,10 +2235,11 @@ void EndpointAppPBX::process_dialing(void) goto process_action; } - if (e_match_timeout && now_d>=e_match_timeout) { + gettimeofday(¤t_time, NULL); + if (timeout && TIME_SMALLER(&e_match_timeout.timeout, ¤t_time)) { /* return timeout rule */ PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal '%s' dialing: '%s', timeout in ruleset '%s'\n", ea_endpoint->ep_serial, e_ext.number, e_dialinginfo.id, e_ruleset->name); - e_match_timeout = 0; + unsched_timer(&e_match_timeout); e_action = e_match_to_action; e_extdialing = e_match_to_extdialing; trace_header("ROUTING (timeout)", DIRECTION_NONE); @@ -2272,9 +2278,9 @@ void EndpointAppPBX::process_dialing(void) action_timeout: /* set timeout */ - e_action_timeout = 0; + unsched_timer(&e_action_timeout); if (e_action->timeout) { - e_action_timeout = now_d + e_action->timeout; + schedule_timer(&e_action_timeout, e_action->timeout, 0); PDEBUG(DEBUG_ROUTE|DEBUG_EPOINT, "EPOINT(%d): action has a timeout of %d secods.\n", ea_endpoint->ep_serial, e_action->timeout); } diff --git a/action_vbox.cpp b/action_vbox.cpp index e325c0f..120bfa6 100644 --- a/action_vbox.cpp +++ b/action_vbox.cpp @@ -101,7 +101,7 @@ void EndpointAppPBX::action_init_vbox_play(void) e_vbox_state = VBOX_STATE_MENU; SCPY(e_vbox_display, (char *)((language)?"druecke 2 f. wiedergabe":"press 2 to play")); - e_vbox_display_refresh = 1; + schedule_timer(&e_vbox_refresh, 0, 0); set_tone_vbox("menu"); e_vbox_menu = -1; @@ -112,7 +112,7 @@ void EndpointAppPBX::action_init_vbox_play(void) if (e_vbox_index_num == 0) { e_vbox_state = VBOX_STATE_NOTHING; SCPY(e_vbox_display, (char *)((language)?"keine Anrufe":"no calls")); - e_vbox_display_refresh = 1; + schedule_timer(&e_vbox_refresh, 0, 0); set_tone_vbox("nothing"); } } @@ -232,6 +232,8 @@ void EndpointAppPBX::action_dialing_vbox_play(void) int language = e_ext.vbox_language; struct port_list *portlist; class Port *port; + time_t current_time; + struct tm *current_tm; portlist = ea_endpoint->ep_portlist; @@ -242,7 +244,7 @@ void EndpointAppPBX::action_dialing_vbox_play(void) PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing digit: %c\n", ea_endpoint->ep_serial, e_extdialing[0]); - e_vbox_display_refresh = 1; + schedule_timer(&e_vbox_refresh, 0, 0); if (e_vbox_state == VBOX_STATE_RECORD_RECORD) { if (e_extdialing[0] == '1' || e_extdialing[0] == '0') { @@ -280,10 +282,10 @@ void EndpointAppPBX::action_dialing_vbox_play(void) PDEBUG(DEBUG_EPOINT, "EPOINT(%d) play recoding.\n", ea_endpoint->ep_serial); /* play announcement */ e_vbox_counter = 0; - e_vbox_counter_last = 0; e_vbox_counter_max = 0; e_vbox_speed = 1; e_vbox_state = VBOX_STATE_RECORD_PLAY; + schedule_timer(&e_vbox_refresh, 0, 0); if (e_ext.vbox_language) SCPY(e_vbox_display, "Wied., 1=stop %s"); else @@ -396,10 +398,12 @@ void EndpointAppPBX::action_dialing_vbox_play(void) e_vbox_state = VBOX_STATE_CALLINFO_INTRO; SPRINT(e_vbox_display, "#%d", e_vbox_play+1); vbox_index_read(e_vbox_play); - if (e_vbox_index_mon!=now_tm->tm_mon || e_vbox_index_year!=now_tm->tm_year) { + time(¤t_time); + current_tm = localtime(¤t_time); + if (e_vbox_index_mon!=current_tm->tm_mon || e_vbox_index_year!=current_tm->tm_year) { UPRINT(strchr(e_vbox_display,'\0'), " %s", (language)?months_german[e_vbox_index_mon]:months_english[e_vbox_index_mon]); } - if (e_vbox_index_mday!=now_tm->tm_mday || e_vbox_index_mon!=now_tm->tm_mon || e_vbox_index_year!=now_tm->tm_year) { + if (e_vbox_index_mday!=current_tm->tm_mday || e_vbox_index_mon!=current_tm->tm_mon || e_vbox_index_year!=current_tm->tm_year) { UPRINT(strchr(e_vbox_display,'\0'), " %d", e_vbox_index_mday); } UPRINT(strchr(e_vbox_display,'\0'), " %02d:%02d", e_vbox_index_hour, e_vbox_index_min); @@ -419,10 +423,10 @@ void EndpointAppPBX::action_dialing_vbox_play(void) PDEBUG(DEBUG_EPOINT, "EPOINT(%d) play call #%d. abborting announcement and starting with playback\n", ea_endpoint->ep_serial, e_vbox_play+1); /* the callinfo is played, so we start with the call */ e_vbox_counter = 0; - e_vbox_counter_last = 0; e_vbox_counter_max = 0; e_vbox_speed = 1; e_vbox_state = VBOX_STATE_PLAY; + schedule_timer(&e_vbox_refresh, 0, 0); SPRINT(e_vbox_display, "#%d %%s", e_vbox_play+1); if (e_ext.vbox_display == VBOX_DISPLAY_DETAILED) UPRINT(strchr(e_vbox_display,'\0'), " (%s)", e_vbox_index_callerid); @@ -558,7 +562,7 @@ void EndpointAppPBX::action_dialing_vbox_play(void) SPRINT(e_dialinginfo.id, "extern:%s", e_vbox_index_callerid); e_extdialing = e_dialinginfo.id; e_action = NULL; - process_dialing(); + process_dialing(0); return; } break; @@ -600,31 +604,35 @@ void EndpointAppPBX::action_dialing_vbox_play(void) /* * this handler is called by Epoint::handler(), whenever the action is NUMB_ACTION_VBOX_PLAY */ -void EndpointAppPBX::vbox_handler(void) +int vbox_refresh(struct lcr_timer *timer, void *instance, int index) { - /* refresh if counter changes */ - if (e_vbox_state==VBOX_STATE_PLAY || e_vbox_state==VBOX_STATE_RECORD_PLAY) - if (e_vbox_counter != e_vbox_counter_last) { - e_vbox_counter_last = e_vbox_counter; - e_vbox_display_refresh = 1; - } + class EndpointAppPBX *ea = (class EndpointAppPBX *)instance; - /* refresh display, if required (include counter) */ - if (e_vbox_display_refresh && e_ext.vbox_display!=VBOX_DISPLAY_OFF) { - char counter[32]; - struct lcr_msg *message; - - 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(¤t_time); + current_tm = localtime(¤t_time); + if (e_vbox_index_mday==current_tm->tm_mday && e_vbox_index_mon==current_tm->tm_mon && e_vbox_index_year==current_tm->tm_year) goto skip_day_month; e_vbox_state = VBOX_STATE_CALLINFO_MONTH; //german day if (e_ext.vbox_language) @@ -764,37 +776,37 @@ void EndpointAppPBX::vbox_message_eof(void) } else { /* the callinfo is played, so we start with the call */ e_vbox_counter = 0; - e_vbox_counter_last = 0; e_vbox_counter_max = 0; e_vbox_speed = 1; e_vbox_state = VBOX_STATE_PLAY; + schedule_timer(&e_vbox_refresh, 0, 0); SPRINT(e_vbox_display, "#%d %%s", e_vbox_play); if (e_ext.vbox_display == VBOX_DISPLAY_DETAILED) UPRINT(strchr(e_vbox_display,'\0'), " (%s)", e_vbox_index_callerid); - e_vbox_display_refresh = 1; + schedule_timer(&e_vbox_refresh, 0, 0); set_play_vbox(e_vbox_index_file, 0); } break; case VBOX_STATE_RECORD_ASK: set_tone_vbox("record_ask"); - e_vbox_display_refresh = 1; + schedule_timer(&e_vbox_refresh, 0, 0); break; case VBOX_STATE_STORE_ASK: set_tone_vbox("store_ask"); - e_vbox_display_refresh = 1; + schedule_timer(&e_vbox_refresh, 0, 0); break; case VBOX_STATE_DELETE_ASK: set_tone_vbox("delete_ask"); - e_vbox_display_refresh = 1; + schedule_timer(&e_vbox_refresh, 0, 0); break; case VBOX_STATE_RECORD_PLAY: e_vbox_state = VBOX_STATE_RECORD_ASK; SCPY(e_vbox_display, (char *)((language)?"1=Aufn. 2=Wied. 3=nein":"1=record 2=play 3=no")); - e_vbox_display_refresh = 1; + schedule_timer(&e_vbox_refresh, 0, 0); set_tone_vbox("record_ask"); break; @@ -803,12 +815,12 @@ void EndpointAppPBX::vbox_message_eof(void) if (e_vbox_index_num == 0) { /* nothing to play */ e_vbox_state = VBOX_STATE_MENU; SCPY(e_vbox_display, (char *)((language)?"keine Anrufe":"no calls")); - e_vbox_display_refresh = 1; + schedule_timer(&e_vbox_refresh, 0, 0); set_tone_vbox("nothing"); } else { e_vbox_state = VBOX_STATE_MENU; SCPY(e_vbox_display, (char *)((language)?"druecke 2 f. wiedergabe":"press 2 to play")); - e_vbox_display_refresh = 1; + schedule_timer(&e_vbox_refresh, 0, 0); set_tone_vbox("menu"); } break; diff --git a/apppbx.cpp b/apppbx.cpp index 9858207..46b1f62 100644 --- a/apppbx.cpp +++ b/apppbx.cpp @@ -14,6 +14,15 @@ class EndpointAppPBX *apppbx_first = NULL; +int action_timeout(struct lcr_timer *timer, void *instance, int index); +int match_timeout(struct lcr_timer *timer, void *instance, int index); +int redial_timeout(struct lcr_timer *timer, void *instance, int index); +int powerdial_timeout(struct lcr_timer *timer, void *instance, int index); +int cfnr_timeout(struct lcr_timer *timer, void *instance, int index); +int cfnr_call_timeout(struct lcr_timer *timer, void *instance, int index); +int password_timeout(struct lcr_timer *timer, void *instance, int index); +int callback_timeout(struct lcr_timer *timer, void *instance, int index); + /* * EndpointAppPBX constructor */ @@ -21,6 +30,28 @@ EndpointAppPBX::EndpointAppPBX(class Endpoint *epoint, int origin) : EndpointApp { class EndpointAppPBX **apppointer; + memset(&e_crypt_handler, 0, sizeof(e_crypt_handler)); + add_timer(&e_crypt_handler, crypt_handler, this, 0); + memset(&e_vbox_refresh, 0, sizeof(e_vbox_refresh)); + add_timer(&e_vbox_refresh, vbox_refresh, this, 0); + memset(&e_action_timeout, 0, sizeof(e_action_timeout)); + add_timer(&e_action_timeout, action_timeout, this, 0); + memset(&e_match_timeout, 0, sizeof(e_match_timeout)); + add_timer(&e_match_timeout, match_timeout, this, 0); + memset(&e_redial_timeout, 0, sizeof(e_redial_timeout)); + add_timer(&e_redial_timeout, redial_timeout, this, 0); + memset(&e_powerdial_timeout, 0, sizeof(e_powerdial_timeout)); + add_timer(&e_powerdial_timeout, powerdial_timeout, this, 0); + memset(&e_cfnr_timeout, 0, sizeof(e_cfnr_timeout)); + add_timer(&e_cfnr_timeout, cfnr_timeout, this, 0); + memset(&e_cfnr_call_timeout, 0, sizeof(e_cfnr_call_timeout)); + add_timer(&e_cfnr_call_timeout, cfnr_call_timeout, this, 0); + memset(&e_callback_timeout, 0, sizeof(e_callback_timeout)); + add_timer(&e_callback_timeout, callback_timeout, this, 0); + memset(&e_password_timeout, 0, sizeof(e_password_timeout)); + add_timer(&e_password_timeout, password_timeout, this, 0); + e_powerdial_on = 0; + /* add application to chain */ next = NULL; apppointer = &apppbx_first; @@ -48,8 +79,6 @@ EndpointAppPBX::EndpointAppPBX(class Endpoint *epoint, int origin) : EndpointApp e_rule = e_ruleset->rule_first; e_rule_nesting = 0; e_action = NULL; - e_action_timeout = 0; - e_match_timeout = 0; e_match_to_action = NULL; e_select = 0; e_extdialing = e_dialinginfo.id; @@ -58,13 +87,10 @@ EndpointAppPBX::EndpointAppPBX(class Endpoint *epoint, int origin) : EndpointApp e_hold = 0; // e_join_tone[0] = e_hold_tone[0] = '\0'; e_join_pattern /*= e_hold_pattern*/ = 0; - e_redial = 0; e_tone[0] = '\0'; e_adminid = 0; // will be set, if call was initiated via admin socket - e_powerdialing = 0; e_powerdelay = 0; e_powerlimit = 0; - e_callback = 0; e_cbdialing[0] = '\0'; e_cbcaller[0] = '\0'; e_cbto[0] = '\0'; @@ -74,9 +100,6 @@ EndpointAppPBX::EndpointAppPBX(class Endpoint *epoint, int origin) : EndpointApp e_dtmf_time = 0; e_dtmf_last = 0; e_enablekeypad = 0; - e_cfnr_release = 0; - e_cfnr_call = 0; - e_password_timeout = 0; e_multipoint_cause = 0; e_multipoint_location = 0; e_dialing_queue[0] = '\0'; @@ -107,6 +130,17 @@ EndpointAppPBX::~EndpointAppPBX(void) { class EndpointAppPBX *temp, **tempp; + del_timer(&e_crypt_handler); + del_timer(&e_vbox_refresh); + del_timer(&e_action_timeout); + del_timer(&e_match_timeout); + del_timer(&e_redial_timeout); + del_timer(&e_powerdial_timeout); + del_timer(&e_cfnr_timeout); + del_timer(&e_cfnr_call_timeout); + del_timer(&e_callback_timeout); + del_timer(&e_password_timeout); + /* detach */ temp =apppbx_first; tempp = &apppbx_first; @@ -211,7 +245,7 @@ void EndpointAppPBX::release(int release, int joinlocation, int joincause, int p } /* if callback is enabled, call back with the given caller id */ - if (e_callback) { + if (e_callback_timeout.active) { /* reset some stuff */ new_state(EPOINT_STATE_IDLE); memset(&e_connectinfo, 0, sizeof(struct connect_info)); @@ -221,8 +255,10 @@ void EndpointAppPBX::release(int release, int joinlocation, int joincause, int p if (e_ruleset) e_rule = e_ruleset->rule_first; e_action = NULL; - e_action_timeout = 0; - e_match_timeout = 0; + unsched_timer(&e_action_timeout); + unsched_timer(&e_match_timeout); + unsched_timer(&e_cfnr_timeout); + unsched_timer(&e_cfnr_call_timeout); e_match_to_action = NULL; //e_select = 0; e_extdialing = e_dialinginfo.id; @@ -231,8 +267,6 @@ void EndpointAppPBX::release(int release, int joinlocation, int joincause, int p e_dtmf_time = 0; e_dtmf_last = 0; e_enablekeypad = 0; - e_cfnr_release = 0; - e_cfnr_call = 0; e_multipoint_cause = 0; e_multipoint_location = 0; e_dialing_queue[0] = '\0'; @@ -273,7 +307,8 @@ void EndpointAppPBX::release(int release, int joinlocation, int joincause, int p } PDEBUG(DEBUG_EPOINT, "EPOINT(%d) do pending release of epoint itself.\n", ea_endpoint->ep_serial); - ea_endpoint->ep_use--; /* when e_lock is 0, the endpoint will be deleted */ + if (--ea_endpoint->ep_use <= 0) /* when e_lock is 0, the endpoint will be deleted */ + trigger_work(&ea_endpoint->ep_delete); return; } } @@ -901,7 +936,7 @@ void EndpointAppPBX::out_setup(void) p = e_ext.cfnr; if (*p) { /* when cfnr is done, out_setup() will setup the call */ - if (e_cfnr_call) { + if (e_cfnr_call_timeout.active) { /* present to forwarded party */ if (e_ext.anon_ignore && e_callerinfo.id[0]) { e_callerinfo.present = INFO_PRESENT_ALLOWED; @@ -909,8 +944,8 @@ void EndpointAppPBX::out_setup(void) goto cfnr_only; } if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH)) { - e_cfnr_release = now + e_ext.cfnr_delay; - e_cfnr_call = now + e_ext.cfnr_delay + 1; /* call one second after release */ + schedule_timer(&e_cfnr_timeout, e_ext.cfnr_delay, 0); + schedule_timer(&e_cfnr_call_timeout, e_ext.cfnr_delay + 1, 0); /* call one second after release */ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) setting time for call-forward-busy to %s with delay %ld.\n", ea_endpoint->ep_serial, e_ext.cfnr, e_ext.cfnr_delay); } } @@ -1218,163 +1253,157 @@ void EndpointAppPBX::out_setup(void) } +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, ¶m->connectinfo, sizeof(e_callerinfo)); if(portlist) { message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT); @@ -2860,6 +2900,7 @@ void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type, message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH); message->param.audiopath = 1; message_put(message); + time(&now); e_start = now; } @@ -2869,18 +2910,19 @@ void EndpointAppPBX::join_disconnect_release(int message_type, union parameter * char cause[16]; struct lcr_msg *message; struct port_list *portlist = NULL; + time_t now; /* be sure that we are active */ notify_active(); e_tx_state = NOTIFY_STATE_ACTIVE; - /* we are powerdialing, if e_powerdialing is set and limit is not exceeded if given */ - if (e_powerdialing && ((e_powercount+1)ep_serial, param->setup.dialinginfo.id); memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo)); return; @@ -3525,7 +3568,7 @@ reject: message_put(message); /* beeing paranoid, we make call update */ - joinpbx->j_updatebridge = 1; + trigger_work(&joinpbx->j_updatebridge); if (options.deb & DEBUG_EPOINT) { class Join *debug_c = join_first; @@ -3703,7 +3746,7 @@ void EndpointAppPBX::join_join(void) PDEBUG(DEBUG_EPOINT, "EPOINT(%d)d-join completely removed!\n"); /* mixer must update */ - our_joinpbx->j_updatebridge = 1; /* update mixer flag */ + trigger_work(&our_joinpbx->j_updatebridge); /* we send a retrieve to that endpoint */ // mixer will update the hold-state of the join and send it to the endpoints is changes diff --git a/apppbx.h b/apppbx.h index 78355b5..b10a119 100644 --- 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); diff --git a/bchannel.c b/bchannel.c index fd3e33d..9e878fe 100644 --- a/bchannel.c +++ b/bchannel.c @@ -50,6 +50,7 @@ #include "message.h" #include "lcrsocket.h" #include "cause.h" +#include "select.h" #include "bchannel.h" #include "chan_lcr.h" #include "callerid.h" @@ -73,7 +74,7 @@ int bchannel_initialize(void) { init_af_isdn(); - return(0); + return 0; } void bchannel_deinitialize(void) @@ -123,6 +124,7 @@ static void ph_control_block(int sock, unsigned int c1, void *c2, int c2_len, ch CERROR(NULL, NULL, "Failed to send to socket %d\n", sock); } +static int bchannel_handle(struct lcr_fd *fd, unsigned int what, void *instance, int index); /* * create stack @@ -130,12 +132,11 @@ static void ph_control_block(int sock, unsigned int c1, void *c2, int c2_len, ch int bchannel_create(struct bchannel *bchannel, int mode) { int ret; - unsigned int on = 1; struct sockaddr_mISDN addr; if (bchannel->b_sock > -1) { CERROR(bchannel->call, NULL, "Socket already created for handle 0x%x\n", bchannel->handle); - return(0); + return 0; } /* open socket */ @@ -160,18 +161,14 @@ int bchannel_create(struct bchannel *bchannel, int mode) } if (bchannel->b_sock < 0) { CERROR(bchannel->call, NULL, "Failed to open bchannel-socket for handle 0x%x with mISDN-DSP layer. Did you load mISDN_dsp.ko?\n", bchannel->handle); - return(0); - } - - /* set nonblocking io */ - ret = ioctl(bchannel->b_sock, FIONBIO, &on); - if (ret < 0) { - CERROR(bchannel->call, NULL, "Failed to set bchannel-socket handle 0x%x into nonblocking IO\n", bchannel->handle); - close(bchannel->b_sock); - bchannel->b_sock = -1; - return(0); + return 0; } + /* register fd */ + memset(&bchannel->lcr_fd, 0, sizeof(bchannel->lcr_fd)); + bchannel->lcr_fd.fd = bchannel->b_sock; + register_fd(&bchannel->lcr_fd, LCR_FD_READ | LCR_FD_EXCEPT, bchannel_handle, bchannel, 0); + /* bind socket to bchannel */ addr.family = AF_ISDN; addr.dev = (bchannel->handle>>8); @@ -179,11 +176,12 @@ int bchannel_create(struct bchannel *bchannel, int mode) ret = bind(bchannel->b_sock, (struct sockaddr *)&addr, sizeof(addr)); if (ret < 0) { CERROR(bchannel->call, NULL, "Failed to bind bchannel-socket for handle 0x%x with mISDN-DSP layer. (port %d, channel %d) Did you load mISDN_dsp.ko?\n", bchannel->handle, addr.dev, addr.channel); + unregister_fd(&bchannel->lcr_fd); close(bchannel->b_sock); bchannel->b_sock = -1; - return(0); + return 0; } - return(1); + return 1; } @@ -264,6 +262,7 @@ static void bchannel_activated(struct bchannel *bchannel) void bchannel_destroy(struct bchannel *bchannel) { if (bchannel->b_sock > -1) { + unregister_fd(&bchannel->lcr_fd); close(bchannel->b_sock); bchannel->b_sock = -1; } @@ -517,63 +516,54 @@ void bchannel_gain(struct bchannel *bchannel, int gain, int tx) /* * main loop for processing messages from mISDN */ -int bchannel_handle(void) +static int bchannel_handle(struct lcr_fd *fd, unsigned int what, void *instance, int index) { - int ret, work = 0; - struct bchannel *bchannel; + struct bchannel *bchannel = (struct bchannel *)instance; + int ret; unsigned char buffer[2048+MISDN_HEADER_LEN]; struct mISDNhead *hh = (struct mISDNhead *)buffer; - /* process all bchannels */ - bchannel = bchannel_first; - while(bchannel) { - /* handle message from bchannel */ - if (bchannel->b_sock > -1) { - ret = recv(bchannel->b_sock, buffer, sizeof(buffer), 0); - if (ret >= (int)MISDN_HEADER_LEN) { - work = 1; - switch(hh->prim) { - /* we don't care about confirms, we use rx data to sync tx */ - case PH_DATA_CNF: - break; - - /* 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) diff --git a/bchannel.h b/bchannel.h index f7b3860..2b03444 100644 --- a/bchannel.h +++ b/bchannel.h @@ -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); diff --git a/chan_lcr.c b/chan_lcr.c index 61905bf..d0993b7 100644 --- a/chan_lcr.c +++ b/chan_lcr.c @@ -167,6 +167,7 @@ it is called from ast_channel process which has already locked ast_channel. #include "callerid.h" #include "lcrsocket.h" #include "cause.h" +#include "select.h" #include "bchannel.h" #include "options.h" #include "chan_lcr.h" @@ -198,11 +199,22 @@ static char *desc = "Channel driver for mISDN/LCR Support (Bri/Pri)"; pthread_t chan_tid; ast_mutex_t chan_lock; /* global lock */ ast_mutex_t log_lock; /* logging log */ +/* global_change: + * used to indicate change in file descriptors, so select function's result may + * be obsolete. + */ +int global_change = 0; +int wake_global = 0; +int wake_pipe[2]; +struct lcr_fd wake_fd; + int quit; int glob_channel = 0; int lcr_sock = -1; +struct lcr_fd socket_fd; +struct lcr_timer socket_retry; struct admin_list { struct admin_list *next; @@ -259,7 +271,7 @@ struct chan_call *find_call_ref(unsigned int ref) break; call = call->next; } - return(call); + return call; } void free_call(struct chan_call *call) @@ -289,6 +301,7 @@ void free_call(struct chan_call *call) ast_dsp_free(call->dsp); CDEBUG(call, NULL, "Call instance freed.\n"); free(call); + global_change = 1; return; } temp = &((*temp)->next); @@ -309,11 +322,11 @@ struct chan_call *alloc_call(void) if (pipe((*callp)->pipe) < 0) { CERROR(*callp, NULL, "Failed to create pipe.\n"); free_call(*callp); - return(NULL); + return NULL; } fcntl((*callp)->pipe[0], F_SETFL, O_NONBLOCK); CDEBUG(*callp, NULL, "Call instance allocated.\n"); - return(*callp); + return *callp; } unsigned short new_bridge_id(void) @@ -334,7 +347,7 @@ unsigned short new_bridge_id(void) id++; } CDEBUG(NULL, NULL, "New bridge ID %d.\n", id); - return(id); + return id; } /* @@ -364,8 +377,14 @@ int send_message(int message_type, unsigned int ref, union parameter *param) admin->msg.u.msg.type = message_type; admin->msg.u.msg.ref = ref; memcpy(&admin->msg.u.msg.param, param, sizeof(union parameter)); + socket_fd.when |= LCR_FD_WRITE; + if (!wake_global) { + wake_global = 1; + char byte = 0; + write(wake_pipe[1], &byte, 1); + } - return(0); + return 0; } /* @@ -923,8 +942,15 @@ static void lcr_in_proceeding(struct chan_call *call, int message_type, union pa /* change state */ call->state = CHAN_LCR_STATE_OUT_PROCEEDING; /* queue event for asterisk */ - if (call->ast && call->pbx_started) + if (call->ast && call->pbx_started) { + if (!wake_global) { + wake_global = 1; + char byte = 0; + write(wake_pipe[1], &byte, 1); + } strncat(call->queue_string, "P", sizeof(call->queue_string)-1); + } + } /* @@ -937,8 +963,14 @@ static void lcr_in_alerting(struct chan_call *call, int message_type, union para /* change state */ call->state = CHAN_LCR_STATE_OUT_ALERTING; /* queue event to asterisk */ - if (call->ast && call->pbx_started) + if (call->ast && call->pbx_started) { + if (!wake_global) { + wake_global = 1; + char byte = 0; + write(wake_pipe[1], &byte, 1); + } strncat(call->queue_string, "R", sizeof(call->queue_string)-1); + } } /* @@ -962,8 +994,14 @@ static void lcr_in_connect(struct chan_call *call, int message_type, union param /* copy connectinfo */ memcpy(&call->connectinfo, ¶m->connectinfo, sizeof(struct connect_info)); /* queue event to asterisk */ - if (call->ast && call->pbx_started) + if (call->ast && call->pbx_started) { + if (!wake_global) { + wake_global = 1; + char byte = 0; + write(wake_pipe[1], &byte, 1); + } strncat(call->queue_string, "N", sizeof(call->queue_string)-1); + } } /* @@ -997,9 +1035,14 @@ static void lcr_in_disconnect(struct chan_call *call, int message_type, union pa /* queue release asterisk */ if (ast) { ast->hangupcause = call->cause; - if (call->pbx_started) + if (call->pbx_started) { + if (!wake_global) { + wake_global = 1; + char byte = 0; + write(wake_pipe[1], &byte, 1); + } strcpy(call->queue_string, "H"); // overwrite other indications - else { + } else { ast_hangup(ast); // call will be destroyed here } } @@ -1026,9 +1069,14 @@ static void lcr_in_release(struct chan_call *call, int message_type, union param /* if we have an asterisk instance, queue hangup, else we are done */ if (ast) { ast->hangupcause = call->cause; - if (call->pbx_started) + if (call->pbx_started) { + if (!wake_global) { + wake_global = 1; + char byte = 0; + write(wake_pipe[1], &byte, 1); + } strcpy(call->queue_string, "H"); - else { + } else { ast_hangup(ast); // call will be destroyed here } } else { @@ -1064,8 +1112,14 @@ static void lcr_in_information(struct chan_call *call, int message_type, union p } /* queue digits */ - if (call->state == CHAN_LCR_STATE_IN_DIALING && param->information.id[0]) + if (call->state == CHAN_LCR_STATE_IN_DIALING && param->information.id[0]) { + if (!wake_global) { + wake_global = 1; + char byte = 0; + write(wake_pipe[1], &byte, 1); + } strncat(call->queue_string, param->information.id, sizeof(call->queue_string)-1); + } /* use bridge to forware message not supported by asterisk */ if (call->state == CHAN_LCR_STATE_CONNECT) { @@ -1134,8 +1188,14 @@ static void lcr_in_pattern(struct chan_call *call, int message_type, union param send_message(MESSAGE_BCHANNEL, call->ref, &newparam); } /* queue PROGRESS, because tones are available */ - if (call->ast && call->pbx_started) + if (call->ast && call->pbx_started) { + if (!wake_global) { + wake_global = 1; + char byte = 0; + write(wake_pipe[1], &byte, 1); + } strncat(call->queue_string, "T", sizeof(call->queue_string)-1); + } } /* @@ -1159,6 +1219,11 @@ void lcr_in_dtmf(struct chan_call *call, int val) CDEBUG(call, call->ast, "Recognised DTMF digit '%c'.\n", val); digit[0] = val; digit[1] = '\0'; + if (!wake_global) { + wake_global = 1; + char byte = 0; + write(wake_pipe[1], &byte, 1); + } strncat(call->queue_string, digit, sizeof(call->queue_string)-1); } @@ -1180,13 +1245,13 @@ int receive_message(int message_type, unsigned int ref, union parameter *param) CDEBUG(NULL, NULL, "Received BCHANNEL_ASSIGN message. (handle=%08lx) for ref %d\n", param->bchannel.handle, ref); if ((bchannel = find_bchannel_handle(param->bchannel.handle))) { CERROR(NULL, NULL, "bchannel handle %x already assigned.\n", (int)param->bchannel.handle); - return(-1); + return -1; } /* create bchannel */ bchannel = alloc_bchannel(param->bchannel.handle); if (!bchannel) { CERROR(NULL, NULL, "alloc bchannel handle %x failed.\n", (int)param->bchannel.handle); - return(-1); + return -1; } /* configure channel */ @@ -1242,7 +1307,7 @@ int receive_message(int message_type, unsigned int ref, union parameter *param) CDEBUG(NULL, NULL, "Received BCHANNEL_REMOVE message. (handle=%08lx)\n", param->bchannel.handle); if (!(bchannel = find_bchannel_handle(param->bchannel.handle))) { CERROR(NULL, NULL, "Bchannel handle %x not assigned.\n", (int)param->bchannel.handle); - return(-1); + return -1; } /* unklink from call and destroy bchannel */ free_bchannel(bchannel); @@ -1257,7 +1322,7 @@ int receive_message(int message_type, unsigned int ref, union parameter *param) default: CDEBUG(NULL, NULL, "Received unknown bchannel message %d.\n", param->bchannel.type); } - return(0); + return 0; } /* handle new ref */ @@ -1267,7 +1332,7 @@ int receive_message(int message_type, unsigned int ref, union parameter *param) CDEBUG(NULL, NULL, "Received new ref by LCR, due to incomming call. (ref=%ld)\n", ref); if (!ref || find_call_ref(ref)) { CERROR(NULL, NULL, "Illegal new ref %ld received.\n", ref); - return(-1); + return -1; } /* allocate new call instance */ call = alloc_call(); @@ -1287,7 +1352,7 @@ int receive_message(int message_type, unsigned int ref, union parameter *param) /* send release, if ref does not exist */ CDEBUG(NULL, NULL, "No call found, that requests a ref.\n"); send_release_and_import(call, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL); - return(0); + return 0; } /* store new ref */ call->ref = ref; @@ -1306,22 +1371,22 @@ int receive_message(int message_type, unsigned int ref, union parameter *param) send_release_and_import(call, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL); /* free call */ free_call(call); - return(0); + return 0; } } - return(0); + return 0; } /* check ref */ if (!ref) { CERROR(NULL, NULL, "Received message %d without ref.\n", message_type); - return(-1); + return -1; } call = find_call_ref(ref); if (!call) { /* ignore ref that is not used (anymore) */ CDEBUG(NULL, NULL, "Message %d from LCR ignored, because no call instance found.\n", message_type); - return(0); + return 0; } /* handle messages */ @@ -1382,7 +1447,7 @@ int receive_message(int message_type, unsigned int ref, union parameter *param) CDEBUG(call, call->ast, "Message %d from LCR unhandled.\n", message_type); break; } - return(0); + return 0; } /* @@ -1415,6 +1480,11 @@ again: goto again; } CDEBUG(call, call->ast, "Queue call release, because Asterisk channel is running.\n"); + if (!wake_global) { + wake_global = 1; + char byte = 0; + write(wake_pipe[1], &byte, 1); + } strcpy(call->queue_string, "H"); call = call->next; } @@ -1424,69 +1494,74 @@ again: free_bchannel(bchannel_first); } +void close_socket(void); /* asterisk handler * warning! not thread safe * returns -1 for socket error, 0 for no work, 1 for work */ -int handle_socket(void) +static int handle_socket(struct lcr_fd *fd, unsigned int what, void *instance, int index) { - int work = 0; int len; struct admin_list *admin; struct admin_message msg; - /* read from socket */ - len = read(lcr_sock, &msg, sizeof(msg)); - if (len == 0) { - CERROR(NULL, NULL, "Socket closed.\n"); - return(-1); // socket closed - } - if (len > 0) { - if (len != sizeof(msg)) { - CERROR(NULL, NULL, "Socket short read. (len %d)\n", len); - return(-1); // socket error + if ((what & LCR_FD_READ)) { + /* read from socket */ + len = read(lcr_sock, &msg, sizeof(msg)); + if (len == 0) { + CERROR(NULL, NULL, "Socket closed.\n"); + error: + CERROR(NULL, NULL, "Handling of socket failed - closing for some seconds.\n"); + close_socket(); + release_all_calls(); + schedule_timer(&socket_retry, SOCKET_RETRY_TIMER, 0); + return 0; } - if (msg.message != ADMIN_MESSAGE) { - CERROR(NULL, NULL, "Socket received illegal message %d.\n", msg.message); - return(-1); - } - receive_message(msg.u.msg.type, msg.u.msg.ref, &msg.u.msg.param); - work = 1; - } else { - if (errno != EWOULDBLOCK) { + if (len > 0) { + if (len != sizeof(msg)) { + CERROR(NULL, NULL, "Socket short read. (len %d)\n", len); + goto error; + } + if (msg.message != ADMIN_MESSAGE) { + CERROR(NULL, NULL, "Socket received illegal message %d.\n", msg.message); + goto error; + } + receive_message(msg.u.msg.type, msg.u.msg.ref, &msg.u.msg.param); + } else { CERROR(NULL, NULL, "Socket failed (errno %d).\n", errno); - return(-1); + goto error; } } - /* write to socket */ - if (!admin_first) - return(work); - admin = admin_first; - len = write(lcr_sock, &admin->msg, sizeof(msg)); - if (len == 0) { - CERROR(NULL, NULL, "Socket closed.\n"); - return(-1); // socket closed - } - if (len > 0) { - if (len != sizeof(msg)) { - CERROR(NULL, NULL, "Socket short write. (len %d)\n", len); - return(-1); // socket error + if ((what & LCR_FD_WRITE)) { + /* write to socket */ + if (!admin_first) { + socket_fd.when &= ~LCR_FD_WRITE; + return 0; } - /* free head */ - admin_first = admin->next; - free(admin); - - work = 1; - } else { - if (errno != EWOULDBLOCK) { + admin = admin_first; + len = write(lcr_sock, &admin->msg, sizeof(msg)); + if (len == 0) { + CERROR(NULL, NULL, "Socket closed.\n"); + goto error; + } + if (len > 0) { + if (len != sizeof(msg)) { + CERROR(NULL, NULL, "Socket short write. (len %d)\n", len); + goto error; + } + /* free head */ + admin_first = admin->next; + free(admin); + global_change = 1; + } else { CERROR(NULL, NULL, "Socket failed (errno %d).\n", errno); - return(-1); + goto error; } } - return(work); + return 0; } /* @@ -1494,16 +1569,14 @@ int handle_socket(void) */ int open_socket(void) { - int ret; int conn; struct sockaddr_un sock_address; - unsigned int on = 1; union parameter param; /* open socket */ if ((lcr_sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { CERROR(NULL, NULL, "Failed to create socket.\n"); - return(lcr_sock); + return lcr_sock; } /* set socket address and name */ @@ -1516,29 +1589,28 @@ int open_socket(void) close(lcr_sock); lcr_sock = -1; CDEBUG(NULL, NULL, "Failed to connect to socket '%s'. Is LCR running?\n", sock_address.sun_path); - return(conn); + return conn; } - /* set non-blocking io */ - if ((ret = ioctl(lcr_sock, FIONBIO, (unsigned char *)(&on))) < 0) { - close(lcr_sock); - lcr_sock = -1; - CERROR(NULL, NULL, "Failed to set socket into non-blocking IO.\n"); - return(ret); - } + /* register socket fd */ + memset(&socket_fd, 0, sizeof(socket_fd)); + socket_fd.fd = lcr_sock; + register_fd(&socket_fd, LCR_FD_READ | LCR_FD_EXCEPT, handle_socket, NULL, 0); /* enque hello message */ memset(¶m, 0, sizeof(param)); strcpy(param.hello.application, "asterisk"); send_message(MESSAGE_HELLO, 0, ¶m); - return(lcr_sock); + return lcr_sock; } void close_socket(void) { struct admin_list *admin, *temp; - + + unregister_fd(&socket_fd); + /* flush pending messages */ admin = admin_first; while(admin) { @@ -1552,13 +1624,24 @@ void close_socket(void) if (lcr_sock >= 0) close(lcr_sock); lcr_sock = -1; + global_change = 1; } /* sending queue to asterisk */ -static int queue_send(void) +static int wake_event(struct lcr_fd *fd, unsigned int what, void *instance, int index) +{ + char byte; + + read(wake_pipe[0], &byte, 1); + + wake_global = 0; + + return 0; +} + +static void handle_queue() { - int work = 0; struct chan_call *call; struct ast_channel *ast; struct ast_frame fr; @@ -1569,156 +1652,124 @@ static int queue_send(void) p = call->queue_string; ast = call->ast; if (*p && ast) { - /* there is something to queue */ - if (!ast_channel_trylock(ast)) { /* succeed */ - while(*p) { - switch (*p) { - case 'T': - CDEBUG(call, ast, "Sending queued PROGRESS to Asterisk.\n"); - ast_queue_control(ast, AST_CONTROL_PROGRESS); - break; - case 'P': - CDEBUG(call, ast, "Sending queued PROCEEDING to Asterisk.\n"); - ast_queue_control(ast, AST_CONTROL_PROCEEDING); - break; - case 'R': - CDEBUG(call, ast, "Sending queued RINGING to Asterisk.\n"); - ast_queue_control(ast, AST_CONTROL_RINGING); - ast_setstate(ast, AST_STATE_RINGING); - break; - case 'N': - CDEBUG(call, ast, "Sending queued ANSWER to Asterisk.\n"); - ast_queue_control(ast, AST_CONTROL_ANSWER); - break; - case 'H': - CDEBUG(call, ast, "Sending queued HANGUP to Asterisk.\n"); - ast_queue_hangup(ast); - break; - case '1': case '2': case '3': case 'A': - case '4': case '5': case '6': case 'B': - case '7': case '8': case '9': case 'C': - case '*': case '0': case '#': case 'D': - CDEBUG(call, ast, "Sending queued digit '%c' to Asterisk.\n", *p); - /* send digit to asterisk */ - memset(&fr, 0, sizeof(fr)); - - #ifdef LCR_FOR_ASTERISK - fr.frametype = AST_FRAME_DTMF_BEGIN; - #endif - - #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(¶m, 0, sizeof(union parameter)); - if (lcr_sock < 0) - time(&retry); + /* open socket the first time */ + handle_retry(NULL, NULL, 0); ast_mutex_lock(&chan_lock); while(!quit) { - work = 0; - - if (lcr_sock > 0) { - /* handle socket */ - ret = handle_socket(); - if (ret < 0) { - CERROR(NULL, NULL, "Handling of socket failed - closing for some seconds.\n"); - close_socket(); - release_all_calls(); - time(&retry); - } - if (ret) - work = 1; - } else { - time(&now); - if (retry && now-retry > 5) { - CDEBUG(NULL, NULL, "Retry to open socket.\n"); - retry = 0; - if (open_socket() < 0) { - time(&retry); - } - work = 1; - } - - } - - /* handle mISDN */ - ret = bchannel_handle(); - if (ret) - work = 1; - - /* handle messages to asterisk */ - ret = queue_send(); - if (ret) - work = 1; - - /* delay if no work done */ - if (!work) { - ast_mutex_unlock(&chan_lock); - - #ifdef LCR_FOR_ASTERISK - usleep(30000); - #endif - - #ifdef LCR_FOR_CALLWEAVER - usleep(20000); - #endif - - ast_mutex_lock(&chan_lock); - } + handle_queue(); + select_main(0, &global_change, lock_chan, unlock_chan); } close_socket(); + 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); diff --git a/chan_lcr.h b/chan_lcr.h index 5905ea1..3a64593 100644 --- a/chan_lcr.h +++ b/chan_lcr.h @@ -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, ...); diff --git a/crypt.cpp b/crypt.cpp index 44e901c..125b516 100644 --- 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_sece_crypt_timeout_sec) if (ea->e_crypt_timeout_sece_crypt_timeout_sec==current_time.tv_sec && ea->e_crypt_timeout_usece_crypt_timeout_sec = 0; + ea->e_crypt_timeout_usec = 0; + ea->cryptman_message(CT_TIMEOUT, NULL, 0); } + + /* trigger until state is 0 */ + if (ea->e_crypt_state != CM_ST_NULL) + schedule_timer(&ea->e_crypt_handler, 0, 100000); + + return 0; } @@ -679,6 +690,7 @@ void EndpointAppPBX::cr_activate(int message, unsigned char *param, int len) unsigned char buf[128] = ""; unsigned char msg; unsigned char bogomips[4], ran[4]; + struct timeval current_time; /* activate listener */ cryptman_msg2crengine(CR_LISTEN_REQ, NULL, 0); @@ -686,7 +698,8 @@ void EndpointAppPBX::cr_activate(int message, unsigned char *param, int len) msg = CMSG_IDENT; CM_ADDINF(CM_INFO_MESSAGE, 1, &msg); /* random number element */ - srandom(now_tv.tv_sec ^ now_tv.tv_usec ^ random()); + gettimeofday(¤t_time, NULL); + srandom(current_time.tv_sec ^ current_time.tv_usec ^ random()); e_crypt_random = random(); ran[0] = e_crypt_random >> 24; ran[1] = e_crypt_random >> 16; @@ -1484,6 +1497,8 @@ void EndpointAppPBX::cryptman_msg2user(int msg, const char *text) void EndpointAppPBX::cryptman_state(int state) { PDEBUG(DEBUG_CRYPT, "Changing state from %s to %s\n", statename(e_crypt_state), statename(state)); + if (state != CM_ST_NULL && e_crypt_state == CM_ST_NULL) + schedule_timer(&e_crypt_handler, 0, 100000); e_crypt_state = state; } @@ -1492,9 +1507,12 @@ void EndpointAppPBX::cryptman_state(int state) */ void EndpointAppPBX::cryptman_timeout(int secs) { + struct timeval current_time; + + gettimeofday(¤t_time, NULL); if (secs) { - e_crypt_timeout_sec = now_tv.tv_sec+secs; - e_crypt_timeout_usec = now_tv.tv_usec; + e_crypt_timeout_sec = current_time.tv_sec+secs; + e_crypt_timeout_usec = current_time.tv_usec; PDEBUG(DEBUG_CRYPT, "Changing timeout to %d seconds\n", secs); } else { e_crypt_timeout_sec = 0; diff --git a/crypt.h b/crypt.h index f5a030c..5659082 100644 --- 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); diff --git a/dss1.cpp b/dss1.cpp index 75ff448..4a96e28 100644 --- 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(¤t_time); + enc_ie_date(l3m, current_time, p_settings.no_seconds); } end_trace(); /* finally send message */ @@ -2552,7 +2556,7 @@ if (/* ||*/ p_state==PORT_STATE_OUT_SETUP) { end_trace(); p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_RELEASE_COMPLETE, p_m_d_l3id, l3m); new_state(PORT_STATE_RELEASE); - p_m_delete = 1; + trigger_work(&p_m_d_delete); return; } diff --git a/dss1.h b/dss1.h index 6683a52..f2486ab 100644 --- 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 */ diff --git a/endpoint.cpp b/endpoint.cpp index 28ea12f..cda79c2 100644 --- a/endpoint.cpp +++ b/endpoint.cpp @@ -33,6 +33,7 @@ class Endpoint *find_epoint_id(unsigned int epoint_id) return(NULL); } +int delete_endpoint(struct lcr_work *work, void *instance, int index); /* * endpoint constructor (link with either port or join id) @@ -48,6 +49,8 @@ Endpoint::Endpoint(unsigned int port_id, unsigned int join_id) ep_portlist = NULL; ep_app = NULL; + memset(&ep_delete, 0, sizeof(ep_delete)); + add_work(&ep_delete, delete_endpoint, this, 0); ep_use = 1; /* add endpoint to chain */ @@ -125,6 +128,8 @@ Endpoint::~Endpoint(void) FATAL("Endpoint not in Endpoint's list.\n"); *tempp = next; + del_work(&ep_delete); + /* free */ PDEBUG(DEBUG_EPOINT, "removed endpoint %d.\n", ep_serial); } @@ -183,17 +188,13 @@ void Endpoint::free_portlist(struct port_list *portlist) } -/* handler for endpoint - */ -int Endpoint::handler(void) +int delete_endpoint(struct lcr_work *work, void *instance, int index) { - if (ep_use <= 0) { - delete this; - return(-1); - } + class Endpoint *ep = (class Endpoint *)instance; - /* call application handler */ - if (ep_app) - return(ep_app->handler()); - return(0); + if (ep->ep_use <= 0) + delete ep; + + return 0; } + diff --git a/endpoint.h b/endpoint.h index 963b5dd..a3080bc 100644 --- a/endpoint.h +++ b/endpoint.h @@ -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 */ diff --git a/endpointapp.cpp b/endpointapp.cpp index a3c6f56..158b3d6 100644 --- a/endpointapp.cpp +++ b/endpointapp.cpp @@ -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) diff --git a/endpointapp.h b/endpointapp.h index a330a63..a24faae 100644 --- a/endpointapp.h +++ b/endpointapp.h @@ -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 --- 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 --- 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; diff --git a/join.cpp b/join.cpp index b1a06bb..5dcbde2 100644 --- 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 --- 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 */ diff --git a/joinpbx.cpp b/joinpbx.cpp index d3640b1..4b06540 100644 --- a/joinpbx.cpp +++ b/joinpbx.cpp @@ -202,6 +202,7 @@ void joinpbx_debug(class JoinPBX *joinpbx, const char *function) PDEBUG(DEBUG_JOIN, "end\n"); } +int update_bridge(struct lcr_work *work, void *instance, int index); /* * constructor for a new join @@ -223,11 +224,12 @@ JoinPBX::JoinPBX(class Endpoint *epoint) : Join() j_dialed[0] = '\0'; j_todial[0] = '\0'; j_pid = getpid(); - j_updatebridge = 0; j_partyline = 0; j_partyline_jingle = 0; j_multicause = 0; j_multilocation = 0; + memset(&j_updatebridge, 0, sizeof(j_updatebridge)); + add_work(&j_updatebridge, update_bridge, this, 0); /* initialize a relation only to the calling interface */ relation = j_relation = (struct join_relation *)MALLOC(sizeof(struct join_relation)); @@ -258,12 +260,23 @@ JoinPBX::~JoinPBX() cmemuse--; relation = rtemp; } + + del_work(&j_updatebridge); } /* bridge sets the audio flow of all bchannels assiociated to 'this' join * also it changes and notifies active/hold/conference states */ +int update_bridge(struct lcr_work *work, void *instance, int index) +{ + class JoinPBX *joinpbx = (class JoinPBX *)instance; + + joinpbx->bridge(); + + return 0; +} + void JoinPBX::bridge(void) { struct join_relation *relation; @@ -453,7 +466,7 @@ int JoinPBX::release(struct join_relation *relation, int location, int cause) /* remove from bridge */ if (relation->channel_state != 0) { relation->channel_state = 0; - j_updatebridge = 1; /* update bridge flag */ + trigger_work(&j_updatebridge); // note: if join is not released, bridge must be updated } @@ -677,7 +690,7 @@ void JoinPBX::message_epoint(unsigned int epoint_id, int message_type, union par SPRINT(message->param.connectinfo.id, "%d", j_partyline); message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN; message_put(message); - j_updatebridge = 1; /* update bridge flag */ + trigger_work(&j_updatebridge); if (j_partyline_jingle) play_jingle(1); break; @@ -686,7 +699,7 @@ void JoinPBX::message_epoint(unsigned int epoint_id, int message_type, union par PDEBUG(DEBUG_JOIN, "join received channel message: %d.\n", param->audiopath); if (relation->channel_state != param->audiopath) { relation->channel_state = param->audiopath; - j_updatebridge = 1; /* update bridge flag */ + trigger_work(&j_updatebridge); if (options.deb & DEBUG_JOIN) joinpbx_debug(this, "Join::message_epoint{after setting new channel state}"); } @@ -721,7 +734,7 @@ void JoinPBX::message_epoint(unsigned int epoint_id, int message_type, union par PDEBUG(DEBUG_JOIN, "join received channel message: %d.\n", param->audiopath); if (relation->channel_state != param->audiopath) { relation->channel_state = param->audiopath; - j_updatebridge = 1; /* update bridge flag */ + trigger_work(&j_updatebridge); if (options.deb & DEBUG_JOIN) joinpbx_debug(this, "Join::message_epoint{after setting new channel state}"); } @@ -739,7 +752,7 @@ void JoinPBX::message_epoint(unsigned int epoint_id, int message_type, union par new_state = track_notify(relation->rx_state, param->notifyinfo.notify); if (new_state != relation->rx_state) { relation->rx_state = new_state; - j_updatebridge = 1; + trigger_work(&j_updatebridge); if (options.deb & DEBUG_JOIN) joinpbx_debug(this, "Join::message_epoint{after setting new rx state}"); } @@ -895,30 +908,6 @@ void JoinPBX::message_epoint(unsigned int epoint_id, int message_type, union par } -/* join process is called from the main loop - * it processes the current calling state. - * returns 0 if join nothing was done - */ -int JoinPBX::handler(void) -{ -// struct join_relation *relation; -// char dialing[32][32]; -// int port[32]; -// int found; -// int i, j; -// char *p; - - /* the bridge must be updated */ - if (j_updatebridge) { - bridge(); - j_updatebridge = 0; - return(1); - } - - return(0); -} - - int track_notify(int oldstate, int notify) { int newstate = oldstate; diff --git a/joinpbx.h b/joinpbx.h index 18e38c0..7c05eee 100644 --- 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 */ diff --git a/joinremote.cpp b/joinremote.cpp index a4f9380..167bbce 100644 --- a/joinremote.cpp +++ b/joinremote.cpp @@ -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 */ diff --git a/joinremote.h b/joinremote.h index b837da6..1582133 100644 --- a/joinremote.h +++ b/joinremote.h @@ -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]; diff --git a/lcradmin.c b/lcradmin.c index 222700b..0b6d627 100644 --- a/lcradmin.c +++ b/lcradmin.c @@ -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" diff --git a/mISDN.cpp b/mISDN.cpp index e531b14..3e7751e 100644 --- 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(¤t_time, NULL); if (p_m_last_tv_sec) { - elapsed = 8000 * (now_tv.tv_sec - p_m_last_tv_sec) - + 8 * (now_tv.tv_usec/1000 - p_m_last_tv_msec); - } else { - /* set clock of first process ever in this instance */ - p_m_last_tv_sec = now_tv.tv_sec; - p_m_last_tv_msec = now_tv.tv_usec/1000; + elapsed = 8000 * (current_time.tv_sec - p_m_last_tv_sec) + + 8 * (current_time.tv_usec/1000 - p_m_last_tv_msec); } - /* process only if we have a minimum of samples, to make packets not too small */ - if (elapsed >= ISDN_TRANSMIT - && p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE) { - /* set clock of last process! */ - p_m_last_tv_sec = now_tv.tv_sec; - p_m_last_tv_msec = now_tv.tv_usec/1000; + /* set clock of last process! */ + p_m_last_tv_sec = current_time.tv_sec; + p_m_last_tv_msec = current_time.tv_usec/1000; + /* process only if we have samples and we are active */ + if (elapsed && p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE) { /* update load */ if (elapsed < p_m_load) p_m_load -= elapsed; @@ -1237,7 +1274,7 @@ int PmISDN::handler(void) /* to send data, tone must be on */ if ((p_tone_name[0] || p_m_crypt_msg_loops || p_m_inband_send_on) /* what tones? */ - && (p_m_load < ISDN_LOAD) /* enough load? */ + && (p_m_load < ISDN_LOAD) /* not too much load? */ && (p_state==PORT_STATE_CONNECT || p_m_mISDNport->tones || p_m_inband_send_on)) { /* connected or inband-tones? */ int tosend = ISDN_LOAD - p_m_load, length; unsigned char buf[MISDN_HEADER_LEN+tosend]; @@ -1267,6 +1304,8 @@ int PmISDN::handler(void) /* next loop */ p_m_crypt_msg_current = 0; p_m_crypt_msg_loops--; + if (!p_m_crypt_msg_loops) + update_rxoff(); // puts("eine loop weniger"); } @@ -1283,32 +1322,34 @@ int PmISDN::handler(void) if (ISDN_LOAD - p_m_load - tosend > 0) { frm->prim = PH_DATA_REQ; frm->id = 0; - ret = sendto(p_m_mISDNport->b_socket[p_m_b_index], buf, MISDN_HEADER_LEN+ISDN_LOAD-p_m_load-tosend, 0, NULL, 0); + ret = sendto(p_m_mISDNport->b_sock[p_m_b_index].fd, buf, MISDN_HEADER_LEN+ISDN_LOAD-p_m_load-tosend, 0, NULL, 0); if (ret <= 0) - PERROR("Failed to send to socket %d (samples = %d)\n", p_m_mISDNport->b_socket[p_m_b_index], ISDN_LOAD-p_m_load-tosend); + PERROR("Failed to send to socket %d (samples = %d)\n", p_m_mISDNport->b_sock[p_m_b_index].fd, ISDN_LOAD-p_m_load-tosend); p_m_load += ISDN_LOAD - p_m_load - tosend; } } } - // NOTE: deletion is done by the child class - - /* handle timeouts */ - if (p_m_timeout) { - if (p_m_timer+p_m_timeout < now_d) { - PDEBUG(DEBUG_ISDN, "(%s) timeout after %d seconds detected (state=%d).\n", p_name, p_m_timeout, p_state); - p_m_timeout = 0; - /* send timeout to endpoint */ - message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_TIMEOUT); - message->param.state = p_state; - message_put(message); - return(1); - } + if (p_tone_name[0] || p_m_crypt_msg_loops || p_m_inband_send_on || p_m_load) { + schedule_timer(&p_m_loadtimer, 0, ISDN_TRANSMIT*125); } - - return(0); /* nothing done */ } +/* handle timeouts */ +static int mISDN_timeout(struct lcr_timer *timer, void *instance, int i) +{ + class PmISDN *isdnport = (class PmISDN *)instance; + struct lcr_msg *message; + + PDEBUG(DEBUG_ISDN, "(%s) timeout after %d seconds detected (state=%d).\n", isdnport->p_name, isdnport->p_m_timeout.timeout.tv_sec, isdnport->p_state); + /* send timeout to endpoint */ + message = message_create(isdnport->p_serial, ACTIVE_EPOINT(isdnport->p_epointlist), PORT_TO_EPOINT, MESSAGE_TIMEOUT); + message->param.state = isdnport->p_state; + message_put(message); + + return 0; +} + /* * whenever we get audio data from bchannel, we process it here @@ -1466,7 +1507,7 @@ void PmISDN::set_echotest(int echo) PDEBUG(DEBUG_ISDN, "we set echo to echo=%d.\n", p_m_echo); if (p_m_b_channel) if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE) - ph_control(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], p_m_echo?DSP_ECHO_ON:DSP_ECHO_OFF, 0, "DSP-ECHO", p_m_echo); + ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, p_m_echo?DSP_ECHO_ON:DSP_ECHO_OFF, 0, "DSP-ECHO", p_m_echo); } } @@ -1509,7 +1550,7 @@ void PmISDN::set_tone(const char *dir, const char *tone) if (p_m_b_index > -1) if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT) { PDEBUG(DEBUG_ISDN, "we reset tone from id=%d to OFF.\n", p_m_tone); - ph_control(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], DSP_TONE_PATT_OFF, 0, "DSP-TONE", 0); + ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, DSP_TONE_PATT_OFF, 0, "DSP-TONE", 0); } p_m_tone = 0; Port::set_tone(dir, tone); @@ -1581,7 +1622,7 @@ void PmISDN::set_tone(const char *dir, const char *tone) PDEBUG(DEBUG_ISDN, "we set tone to id=%d.\n", p_m_tone); if (p_m_b_index > -1) if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT) - ph_control(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], p_m_tone?DSP_TONE_PATT_ON:DSP_TONE_PATT_OFF, p_m_tone, "DSP-TONE", p_m_tone); + ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, p_m_tone?DSP_TONE_PATT_ON:DSP_TONE_PATT_OFF, p_m_tone, "DSP-TONE", p_m_tone); } /* turn user-space tones off in cases of no tone OR dsp tone */ Port::set_tone("",NULL); @@ -1600,7 +1641,7 @@ void PmISDN::message_mISDNsignal(unsigned int epoint_id, int message_id, union p PDEBUG(DEBUG_BCHANNEL, "we change tx-volume to shift=%d.\n", p_m_tx_gain); if (p_m_b_index > -1) if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT) - ph_control(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], DSP_VOL_CHANGE_TX, p_m_tx_gain, "DSP-TX_GAIN", p_m_tx_gain); + ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, DSP_VOL_CHANGE_TX, p_m_tx_gain, "DSP-TX_GAIN", p_m_tx_gain); } else PDEBUG(DEBUG_BCHANNEL, "we already have tx-volume shift=%d.\n", p_m_rx_gain); if (p_m_rx_gain != param->mISDNsignal.rx_gain) { @@ -1608,7 +1649,7 @@ void PmISDN::message_mISDNsignal(unsigned int epoint_id, int message_id, union p PDEBUG(DEBUG_BCHANNEL, "we change rx-volume to shift=%d.\n", p_m_rx_gain); if (p_m_b_index > -1) if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT) - ph_control(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], DSP_VOL_CHANGE_RX, p_m_rx_gain, "DSP-RX_GAIN", p_m_rx_gain); + ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, DSP_VOL_CHANGE_RX, p_m_rx_gain, "DSP-RX_GAIN", p_m_rx_gain); } else PDEBUG(DEBUG_BCHANNEL, "we already have rx-volume shift=%d.\n", p_m_rx_gain); break; @@ -1624,6 +1665,7 @@ void PmISDN::message_mISDNsignal(unsigned int epoint_id, int message_id, union p if (p_m_joindata != param->mISDNsignal.joindata) { p_m_joindata = param->mISDNsignal.joindata; PDEBUG(DEBUG_BCHANNEL, "we change to joindata=%d.\n", p_m_joindata); + update_rxoff(); } else PDEBUG(DEBUG_BCHANNEL, "we already have joindata=%d.\n", p_m_joindata); break; @@ -1634,7 +1676,7 @@ void PmISDN::message_mISDNsignal(unsigned int epoint_id, int message_id, union p PDEBUG(DEBUG_BCHANNEL, "we change delay mode to delay=%d.\n", p_m_delay); if (p_m_b_index > -1) if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT) - ph_control(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], p_m_delay?DSP_DELAY:DSP_JITTER, p_m_delay, "DSP-DELAY", p_m_delay); + ph_control(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, p_m_delay?DSP_DELAY:DSP_JITTER, p_m_delay, "DSP-DELAY", p_m_delay); } else PDEBUG(DEBUG_BCHANNEL, "we already have delay=%d.\n", p_m_delay); break; @@ -1665,7 +1707,7 @@ void PmISDN::message_crypt(unsigned int epoint_id, int message_id, union paramet PDEBUG(DEBUG_BCHANNEL, "we set encryption to crypt=%d. (0 means OFF)\n", p_m_crypt); if (p_m_b_index > -1) if (p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT) - ph_control_block(p_m_mISDNport, this, p_m_mISDNport->b_socket[p_m_b_index], p_m_crypt?DSP_BF_ENABLE_KEY:DSP_BF_DISABLE, p_m_crypt_key, p_m_crypt_key_len, "DSP-CRYPT", p_m_crypt_key_len); + ph_control_block(p_m_mISDNport, this, p_m_mISDNport->b_sock[p_m_b_index].fd, p_m_crypt?DSP_BF_ENABLE_KEY:DSP_BF_DISABLE, p_m_crypt_key, p_m_crypt_key_len, "DSP-CRYPT", p_m_crypt_key_len); break; case CC_DACT_REQ: /* deactivate session encryption */ @@ -1675,11 +1717,13 @@ void PmISDN::message_crypt(unsigned int epoint_id, int message_id, union paramet case CR_LISTEN_REQ: /* start listening to messages */ p_m_crypt_listen = 1; + update_rxoff(); p_m_crypt_listen_state = 0; break; case CR_UNLISTEN_REQ: /* stop listening to messages */ p_m_crypt_listen = 0; + update_rxoff(); break; case CR_MESSAGE_REQ: /* send message */ @@ -1690,11 +1734,13 @@ void PmISDN::message_crypt(unsigned int epoint_id, int message_id, union paramet } p_m_crypt_msg_current = 0; /* reset */ p_m_crypt_msg_loops = 6; /* enable */ + update_rxoff(); + update_load(); #if 0 /* disable txmix, or we get corrupt data due to audio process */ if (p_m_txmix && p_m_b_index>=0 && p_m_mISDNport->b_mode[p_m_b_index] == B_MODE_TRANSPARENT) { PDEBUG(DEBUG_BCHANNEL, "for sending CR_MESSAGE_REQ, we reset txmix from txmix=%d.\n", p_m_txmix); - ph_control(p_m_mISDNport, this, p_mISDNport->b_socket[p_m_b_index], DSP_MIX_OFF, 0, "DSP-TXMIX", 0); + ph_control(p_m_mISDNport, this, p_mISDNport->b_sock[p_m_b_index].fd, DSP_MIX_OFF, 0, "DSP-TXMIX", 0); } #endif break; @@ -1732,131 +1778,68 @@ int PmISDN::message_epoint(unsigned int epoint_id, int message_id, union paramet return(0); } +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 --- 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 --- 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 --- a/main.c +++ b/main.c @@ -11,19 +11,14 @@ #include "main.h" -MESSAGES +//MESSAGES -double now_d, last_d; -time_t now; -struct tm *now_tm; struct timeval now_tv; struct timezone now_tz; #define GET_NOW() \ { \ gettimeofday(&now_tv, &now_tz); \ now_d = ((double)(now_tv.tv_usec))/1000000 + now_tv.tv_sec; \ - now = now_tv.tv_sec; \ - now_tm = localtime(&now); \ } FILE *debug_fp = NULL; @@ -49,22 +44,21 @@ int classuse = 0; int fduse = 0; int fhuse = 0; -const char *debug_prefix = NULL; int debug_count = 0; int last_debug = 0; int debug_newline = 1; int nooutput = 0; -void debug_usleep(int msec, const char *file, int line, int hour, int min, int sec) -{ - usleep(msec); -} - void debug(const char *function, int line, const char *prefix, char *buffer) { + time_t now; + struct tm *now_tm; + /* if we have a new debug count, we add a mark */ if (last_debug != debug_count) { last_debug = debug_count; + time(&now); + now_tm = localtime(&now); if (!nooutput) printf("\033[34m--------------------- %04d.%02d.%02d %02d:%02d:%02d %06d\033[36m\n", now_tm->tm_year+1900, now_tm->tm_mon+1, now_tm->tm_mday, now_tm->tm_hour, now_tm->tm_min, now_tm->tm_sec, debug_count%1000000); if (debug_fp) @@ -110,7 +104,7 @@ void _printdebug(const char *function, int line, unsigned int mask, const char * buffer[sizeof(buffer)-1]=0; va_end(args); - debug(function, line, debug_prefix, buffer); + debug(function, line, "DEBUG", buffer); pthread_mutex_unlock(&mutexd); } @@ -167,21 +161,18 @@ void sighandler(int sigset) */ int main(int argc, char *argv[]) { +#ifdef WITH_GSM + double now_d, last_d; + int all_idle; +#endif int ret = -1; int lockfd = -1; /* file lock */ struct lcr_msg *message; - class Port *port; - class Endpoint *epoint; - class Join *join; int i; - int all_idle; - char prefix_string[64]; struct sched_param schedp; - const char *debug_prefix = "alloc"; int created_mutexd = 0,/* created_mutext = 0,*/ created_mutexe = 0, created_lock = 0, created_signal = 0, created_debug = 0, created_misdn = 0; - int idletime = 0, idlecheck = 0; char tracetext[256], lock[128]; #if 0 @@ -192,9 +183,6 @@ int main(int argc, char *argv[]) /* lock LCR process */ // pthread_mutex_lock(&mutex_lcr); - /* current time */ - GET_NOW(); - /* show version */ printf("\n** %s Version %s\n\n", NAME, VERSION_STRING); @@ -437,15 +425,20 @@ int main(int argc, char *argv[]) signal(SIGPIPE,sighandler); created_signal = 1; + /* init message */ + init_message(); + /*** main loop ***/ SPRINT(tracetext, "%s %s started, waiting for calls...", NAME, VERSION_STRING); start_trace(-1, NULL, NULL, NULL, 0, 0, 0, tracetext); printf("%s\n", tracetext); end_trace(); - GET_NOW(); quit = 0; +#ifdef WITH_GSM + GET_NOW(); +#endif while(!quit) { - +#ifdef WITH_GSM last_d = now_d; GET_NOW(); if (now_d-last_d > 1.0) { @@ -454,165 +447,19 @@ int main(int argc, char *argv[]) /* all loops must be counted from the beginning since nodes might get freed during handler */ all_idle = 1; -//#warning debugging usleep crash -// debug_usleep(1, __FILE__, __LINE__, now_tm->tm_hour, now_tm->tm_min, now_tm->tm_sec); - - /* handle mISDN messages from kernel */ - debug_prefix = "ISDN"; - if (mISDN_handler()) - 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 --- 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 diff --git a/message.c b/message.c index 403253d..e2f01ec 100644 --- 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; +} + diff --git a/message.h b/message.h index 63abc65..a7f15b7 100644 --- 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); diff --git a/options.c b/options.c index f58d7f9..eff38ce 100644 --- 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 +#include +#include +#include +#include #include "macro.h" #include "extension.h" #include "options.h" diff --git a/port.cpp b/port.cpp index 5998bc6..e88175b 100644 --- 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 --- 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 --- 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(¤t_time, NULL); + now_ll = current_time.tv_sec * MICRO_SECONDS + current_time.tv_usec; + } + timeout = now_ll + (cond->integer_value * MICRO_SECONDS); istrue = 1; break; @@ -2166,10 +2182,10 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset) cond = cond->next; } - if (timeout>now_d && match==1) /* the matching rule with timeout in the future */ - if (e_match_timeout<1 || timeoutnow_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 index 0000000..ba9b563 --- /dev/null +++ b/select.c @@ -0,0 +1,434 @@ +/* based on code from OpenBSC */ + +#include +#include +#include +#include +#include +#include +#include +#include "macro.h" +#include "select.h" + +static int maxfd = 0; +static int unregistered; +static struct lcr_fd *fd_first = NULL; +static struct timeval *nearest_timer(struct timeval *select_timer, int *work); +static int next_work(void); + +int _register_fd(struct lcr_fd *fd, int when, int (*cb)(struct lcr_fd *fd, unsigned int what, void *instance, int index), void *instance, int index, const char *func) +{ + int flags; + + if (fd->inuse) + FATAL("FD that is registered in function %s is already in use\n", func); +// printf("registering fd %d %s\n", fd->fd, func); + + /* make FD nonblocking */ + flags = fcntl(fd->fd, F_GETFL); + if (flags < 0) + FATAL("Failed to F_GETFL\n"); + flags |= O_NONBLOCK; + flags = fcntl(fd->fd, F_SETFL, flags); + if (flags < 0) + FATAL("Failed to F_SETFL O_NONBLOCK\n"); + + /* Register FD */ + if (fd->fd > maxfd) + maxfd = fd->fd; + + /* append to list */ + fd->inuse = 1; + fd->when = when; + fd->cb = cb; + fd->cb_instance = instance; + fd->cb_index = index; + fd->next = fd_first; + fd_first = fd; + + return 0; +} + +void _unregister_fd(struct lcr_fd *fd, const char *func) +{ + struct lcr_fd **lcr_fdp; + + /* find pointer to fd */ + lcr_fdp = &fd_first; + while(*lcr_fdp) { + if (*lcr_fdp == fd) + break; + lcr_fdp = &((*lcr_fdp)->next); + } + if (!*lcr_fdp) { + FATAL("FD unregistered in function %s not in list\n", func); + } + + /* remove fd from list */ + fd->inuse = 0; + *lcr_fdp = fd->next; + unregistered = 1; +} + + +int select_main(int polling, int *global_change, void (*lock)(void), void (*unlock)(void)) +{ + struct lcr_fd *lcr_fd; + fd_set readset, writeset, exceptset; + int work = 0, temp, rc; + struct timeval no_time = {0, 0}; + struct timeval select_timer, *timer; + + /* goto again; + * + * this ensures that select is only called until: + * - no work event exists + * - and no timeout occurred + * + * if no future timeout exists, select will wait infinit. + */ + +again: + /* process all work events */ + if (next_work()) { + work = 1; + goto again; + } + + /* process timer events and get timeout for next timer event */ + temp = 0; + timer = nearest_timer(&select_timer, &temp); + if (temp) { + work = 1; + goto again; + } + if (polling) + timer = &no_time; +#warning TESTING + if (!timer) + printf("wait till infinity ..."); fflush(stdout); + + FD_ZERO(&readset); + FD_ZERO(&writeset); + FD_ZERO(&exceptset); + + /* prepare read and write fdsets */ + lcr_fd = fd_first; + while(lcr_fd) { + if (lcr_fd->when & LCR_FD_READ) + FD_SET(lcr_fd->fd, &readset); + if (lcr_fd->when & LCR_FD_WRITE) + FD_SET(lcr_fd->fd, &writeset); + if (lcr_fd->when & LCR_FD_EXCEPT) + FD_SET(lcr_fd->fd, &exceptset); + lcr_fd = lcr_fd->next; + } + + if (unlock) + unlock(); + rc = select(maxfd+1, &readset, &writeset, &exceptset, timer); + if (lock) + lock(); +#warning TESTING + if (!timer) + printf("interrupted.\n"); + if (rc < 0) + return 0; + if (global_change && *global_change) { + *global_change = 0; + return 1; + } + + /* fire timers */ +#if 0 + bsc_update_timers(); +#endif + + /* call registered callback functions */ +restart: + unregistered = 0; + lcr_fd = fd_first; + while(lcr_fd) { + int flags = 0; + + if (FD_ISSET(lcr_fd->fd, &readset)) { + flags |= LCR_FD_READ; + FD_CLR(lcr_fd->fd, &readset); + } + if (FD_ISSET(lcr_fd->fd, &writeset)) { + flags |= LCR_FD_WRITE; + FD_CLR(lcr_fd->fd, &writeset); + } + if (FD_ISSET(lcr_fd->fd, &exceptset)) { + flags |= LCR_FD_EXCEPT; + FD_CLR(lcr_fd->fd, &exceptset); + } + if (flags) { + work = 1; + lcr_fd->cb(lcr_fd, flags, lcr_fd->cb_instance, lcr_fd->cb_index); + if (unregistered) + goto restart; + return 1; + } + lcr_fd = lcr_fd->next; + } + return work; +} + + +static struct lcr_timer *timer_first = NULL; + +int _add_timer(struct lcr_timer *timer, int (*cb)(struct lcr_timer *timer, void *instance, int index), void *instance, int index, const char *func) +{ + if (timer->inuse) { + FATAL("timer that is registered in function %s is already in use\n", func); + } + +#if 0 + struct lcr_timer *test = timer_first; + while(test) { + if (test == timer) + FATAL("Timer already in list %s\n", func); + test = test->next; + } +#endif + + timer->inuse = 1; + timer->active = 0; + timer->timeout.tv_sec = 0; + timer->timeout.tv_usec = 0; + timer->cb = cb; + timer->cb_instance = instance; + timer->cb_index = index; + timer->next = timer_first; + timer_first = timer; + + return 0; +} + +void _del_timer(struct lcr_timer *timer, const char *func) +{ + struct lcr_timer **lcr_timerp; + + /* find pointer to timer */ + lcr_timerp = &timer_first; + while(*lcr_timerp) { + if (*lcr_timerp == timer) + break; + lcr_timerp = &((*lcr_timerp)->next); + } + if (!*lcr_timerp) { + FATAL("timer deleted in function %s not in list\n", func); + } + + /* remove timer from list */ + timer->inuse = 0; + *lcr_timerp = timer->next; +} + +void schedule_timer(struct lcr_timer *timer, int seconds, int microseconds) +{ + struct timeval current_time; + + if (!timer->inuse) { + FATAL("Timer not added\n"); + } + + gettimeofday(¤t_time, NULL); + unsigned long long currentTime = current_time.tv_sec * MICRO_SECONDS + current_time.tv_usec; + currentTime += seconds * MICRO_SECONDS + microseconds; + timer->timeout.tv_sec = currentTime / MICRO_SECONDS; + timer->timeout.tv_usec = currentTime % MICRO_SECONDS; + timer->active = 1; +} + +void unsched_timer(struct lcr_timer *timer) +{ + timer->active = 0; +} + +/* if a timeout is reached, process timer, if not, return timer value for select */ +static struct timeval *nearest_timer(struct timeval *select_timer, int *work) +{ + struct timeval current; + struct timeval *nearest = NULL; + struct lcr_timer *lcr_timer, *lcr_nearest = NULL; + + /* find nearest timer, or NULL, if no timer active */ + lcr_timer = timer_first; + while(lcr_timer) { + if (lcr_timer->active && (!nearest || TIME_SMALLER(&lcr_timer->timeout, nearest))) { + nearest = &lcr_timer->timeout; + lcr_nearest = lcr_timer; + } + lcr_timer = lcr_timer->next; + } + + select_timer->tv_sec = 0; + select_timer->tv_usec = 0; + + if (!nearest) + return NULL; /* wait until infinity */ + + gettimeofday(¤t, NULL); + unsigned long long nearestTime = nearest->tv_sec * MICRO_SECONDS + nearest->tv_usec; + unsigned long long currentTime = current.tv_sec * MICRO_SECONDS + current.tv_usec; + + if (nearestTime > currentTime) { + select_timer->tv_sec = (nearestTime - currentTime) / MICRO_SECONDS; + select_timer->tv_usec = (nearestTime - currentTime) % MICRO_SECONDS; + return select_timer; + } else { + lcr_nearest->active = 0; + (*lcr_nearest->cb)(lcr_nearest, lcr_nearest->cb_instance, lcr_nearest->cb_index); + /* don't wait so we can process the queues, indicate "work=1" */ + select_timer->tv_sec = 0; + select_timer->tv_usec = 0; + *work = 1; + return select_timer; + } +} + + +static struct lcr_work *work_first = NULL; /* chain of work */ +static struct lcr_work *first_event = NULL, *last_event = NULL; /* chain of active events */ + +#ifdef DEBUG_WORK +void show_chain(const char *func) +{ + struct lcr_work *work = first_event; + printf("chain:%s\n", func); + while(work) { + printf("%p - %p - %p\n", work->prev_event, work, work->next_event); + work = work->next_event; + } +} +#endif + +int _add_work(struct lcr_work *work, int (*cb)(struct lcr_work *work, void *instance, int index), void *instance, int index, const char *func) +{ + if (work->inuse) { + FATAL("work that is registered in function %s is already in use\n", func); + } + +#ifdef DEBUG_WORK + printf("add work %p from function %s\n", work, func); + show_chain("before add"); +#endif + work->inuse = 1; + work->active = 0; + work->cb = cb; + work->cb_instance = instance; + work->cb_index = index; + work->next = work_first; + work_first = work; +#ifdef DEBUG_WORK + show_chain("after add"); +#endif + + return 0; +} + +void _del_work(struct lcr_work *work, const char *func) +{ + struct lcr_work **lcr_workp; + +#ifdef DEBUG_WORK + show_chain("before detach"); +#endif + if (work->active) { + /* first event removed */ + if (!work->prev_event) + first_event = work->next_event; + else + work->prev_event->next_event = work->next_event; + /* last event removed */ + if (!work->next_event) + last_event = work->prev_event; + else + work->next_event->prev_event = work->prev_event; + } +#ifdef DEBUG_WORK + show_chain("after detach"); +#endif + + /* find pointer to work */ + lcr_workp = &work_first; + while(*lcr_workp) { + if (*lcr_workp == work) + break; + lcr_workp = &((*lcr_workp)->next); + } + if (!*lcr_workp) { + FATAL("work deleted by '%s' not in list\n", func); + } + + /* remove work from list */ + work->inuse = 0; + *lcr_workp = work->next; +#ifdef DEBUG_WORK + show_chain("after delete"); +#endif +} + +void trigger_work(struct lcr_work *work) +{ + if (!work->inuse) { + FATAL("Work not added\n"); + } + + /* event already triggered */ + if (work->active) + return; + +#ifdef DEBUG_WORK + show_chain("before trigger"); +#endif + /* append to tail of chain */ + if (last_event) + last_event->next_event = work; + work->prev_event = last_event; + work->next_event = NULL; + last_event = work; + if (!first_event) + first_event = work; +#ifdef DEBUG_WORK + show_chain("after trigger"); +#endif + + work->active = 1; +} + +/* get first work and remove from event chain */ +static int next_work(void) +{ + struct lcr_work *lcr_work; + + if (!first_event) + return 0; + +#ifdef DEBUG_WORK + show_chain("before next_work"); +#endif + if (!first_event->inuse) { + FATAL("Work not added\n"); + } + + /* detach from event chain */ + lcr_work = first_event; + first_event = lcr_work->next_event; + if (!first_event) + last_event = NULL; + else + first_event->prev_event = NULL; + +#ifdef DEBUG_WORK + show_chain("after next_work"); +#endif + lcr_work->active = 0; + + (*lcr_work->cb)(lcr_work, lcr_work->cb_instance, lcr_work->cb_index); + + return 1; +} + diff --git a/select.h b/select.h new file mode 100644 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); + + diff --git a/socket_server.c b/socket_server.c index a33f626..b67b91f 100644 --- a/socket_server.c +++ b/socket_server.c @@ -20,14 +20,15 @@ int sock = -1; struct sockaddr_un sock_address; struct admin_list *admin_first = NULL; +static struct lcr_fd admin_fd; + +int admin_handle(struct lcr_fd *fd, unsigned int what, void *instance, int index); /* * initialize admin socket */ int admin_init(void) { - unsigned int on = 1; - /* open and bind socket */ if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { PERROR("Failed to create admin socket. (errno=%d)\n", errno); @@ -55,14 +56,9 @@ int admin_init(void) PERROR("Failed to listen to socket \"%s\". (errno=%d)\n", sock_address.sun_path, errno); return(-1); } - if (ioctl(sock, FIONBIO, (unsigned char *)(&on)) < 0) { - close(sock); - unlink(socket_name); - fhuse--; - sock = -1; - PERROR("Failed to set socket \"%s\" into non-blocking mode. (errno=%d)\n", sock_address.sun_path, errno); - return(-1); - } + memset(&admin_fd, 0, sizeof(admin_fd)); + admin_fd.fd = sock; + register_fd(&admin_fd, LCR_FD_READ | LCR_FD_EXCEPT, admin_handle, NULL, 0); if (chmod(socket_name, options.socketrights) < 0) { PERROR("Failed to change socket rights to %d. (errno=%d)\n", options.socketrights, errno); } @@ -86,6 +82,7 @@ void free_connection(struct admin_list *admin) class Join *join, *joinnext; struct mISDNport *mISDNport; int i, ii; + struct admin_list **adminp; /* free remote joins */ if (admin->remote_name[0]) { @@ -107,7 +104,7 @@ void free_connection(struct admin_list *admin) while(i < ii) { if (mISDNport->b_remote_id[i] == admin->sock) { mISDNport->b_state[i] = B_STATE_IDLE; - mISDNport->b_timer[i] = 0; + unsched_timer(&mISDNport->b_timer[i]); mISDNport->b_remote_id[i] = 0; mISDNport->b_remote_ref[i] = 0; } @@ -131,22 +128,28 @@ void free_connection(struct admin_list *admin) } if (admin->sock >= 0) { + unregister_fd(&admin->fd); close(admin->sock); fhuse--; } -// printf("new\n", response); response = admin->response; while (response) { -//#warning -// printf("%x\n", response); temp = response->next; FREE(response, 0); memuse--; response = (struct admin_queue *)temp; } -// printf("new2\n", response); + + adminp = &admin_first; + while(*adminp) { + if (*adminp == admin) + break; + adminp = &((*adminp)->next); + } + if (*adminp) + *adminp = (*adminp)->next; + FREE(admin, 0); -// printf("new3\n", response); memuse--; } @@ -160,13 +163,13 @@ void admin_cleanup(void) admin = admin_first; while(admin) { -//printf("clean\n"); next = admin->next; free_connection(admin); admin = next; } if (sock >= 0) { + unregister_fd(&admin_fd); close(sock); fhuse--; } @@ -206,7 +209,6 @@ int admin_interface(struct admin_queue **responsep) /* attach to response chain */ *responsep = response; responsep = &response->next; - return(0); } @@ -274,7 +276,7 @@ int admin_route(struct admin_queue **responsep) } } else if (apppbx->e_state != EPOINT_STATE_CONNECT) { release: - apppbx->e_callback = 0; + unsched_timer(&apppbx->e_callback_timeout); apppbx->e_action = NULL; apppbx->release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); start_trace(-1, @@ -288,7 +290,7 @@ int admin_route(struct admin_queue **responsep) end_trace(); } - apppbx->e_action_timeout = 0; + unsched_timer(&apppbx->e_action_timeout); apppbx->e_rule = NULL; apppbx->e_ruleset = NULL; @@ -309,7 +311,6 @@ int admin_route(struct admin_queue **responsep) /* attach to response chain */ *responsep = response; responsep = &response->next; - return(0); } @@ -486,7 +487,7 @@ int admin_release(struct admin_queue **responsep, char *message) goto out; } - apppbx->e_callback = 0; + unsched_timer(&apppbx->e_callback_timeout); apppbx->release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); out: @@ -518,7 +519,6 @@ int admin_call(struct admin_list *admin, struct admin_message *msg) apppbx->e_callerinfo.present = INFO_PRESENT_RESTRICTED; apppbx->e_callerinfo.screen = INFO_SCREEN_NETWORK; -//printf("hh=%d\n", apppbx->e_capainfo.hlc); apppbx->e_capainfo.bearer_capa = msg->u.call.bc_capa; apppbx->e_capainfo.bearer_mode = msg->u.call.bc_mode; @@ -569,7 +569,6 @@ void admin_call_response(int adminid, int message, const char *connected, int ca response->num = 1; /* message */ response->am[0].message = message; -// printf("MESSAGE: %d\n", message); SCPY(response->am[0].u.call.callerid, connected); response->am[0].u.call.cause = cause; @@ -579,6 +578,7 @@ void admin_call_response(int adminid, int message, const char *connected, int ca /* attach to response chain */ *responsep = response; responsep = &response->next; + admin->fd.when |= LCR_FD_WRITE; } @@ -722,7 +722,7 @@ int admin_message_from_join(int remote_id, unsigned int ref, int message_type, u (*responsep)->am[0].u.msg.type = message_type; (*responsep)->am[0].u.msg.ref = ref; memcpy(&(*responsep)->am[0].u.msg.param, param, sizeof(union parameter)); - + admin->fd.when |= LCR_FD_WRITE; return(0); } @@ -732,7 +732,6 @@ int admin_message_from_join(int remote_id, unsigned int ref, int message_type, u */ int admin_state(struct admin_queue **responsep) { - class Port *port; class EndpointAppPBX *apppbx; class Join *join; @@ -745,6 +744,8 @@ int admin_state(struct admin_queue **responsep) int anybusy; struct admin_queue *response; struct admin_list *admin; + struct tm *now_tm; + time_t now; /* create state response */ response = (struct admin_queue *)MALLOC(sizeof(struct admin_queue)+sizeof(admin_message)); @@ -755,6 +756,8 @@ int admin_state(struct admin_queue **responsep) /* version */ SCPY(response->am[0].u.s.version_string, VERSION_STRING); /* time */ + time(&now); + now_tm = localtime(&now); memcpy(&response->am[0].u.s.tm, now_tm, sizeof(struct tm)); /* log file */ SCPY(response->am[0].u.s.logfile, options.log); @@ -1064,68 +1067,54 @@ int sockserial = 1; // must start with 1, because 0 is used if no serial is set /* * handle admin socket (non blocking) */ -int admin_handle(void) +int admin_handle_con(struct lcr_fd *fd, unsigned int what, void *instance, int index); + +int admin_handle(struct lcr_fd *fd, unsigned int what, void *instance, int index) { - struct admin_list *admin, **adminp; - void *temp; - struct admin_message msg; - int len; int new_sock; socklen_t sock_len = sizeof(sock_address); - unsigned int on = 1; - int work = 0; /* if work was done */ - struct Endpoint *epoint; - - if (sock < 0) - return(0); + struct admin_list *admin; /* check for new incoming connections */ if ((new_sock = accept(sock, (struct sockaddr *)&sock_address, &sock_len)) >= 0) { - work = 1; /* insert new socket */ admin = (struct admin_list *)MALLOC(sizeof(struct admin_list)); - if (ioctl(new_sock, FIONBIO, (unsigned char *)(&on)) >= 0) { -//#warning -// PERROR("DEBUG incoming socket %d, serial=%d\n", new_sock, sockserial); - memuse++; - fhuse++; - admin->sockserial = sockserial++; - admin->next = admin_first; - admin_first = admin; - admin->sock = new_sock; - } else { - close(new_sock); - FREE(admin, sizeof(struct admin_list)); - } + memuse++; + fhuse++; + admin->sockserial = sockserial++; + admin->next = admin_first; + admin_first = admin; + admin->sock = new_sock; + admin->fd.fd = new_sock; + register_fd(&admin->fd, LCR_FD_READ | LCR_FD_EXCEPT, admin_handle_con, admin, 0); } else { if (errno != EWOULDBLOCK) { PERROR("Failed to accept connection from socket \"%s\". (errno=%d) Closing socket.\n", sock_address.sun_path, errno); admin_cleanup(); - return(1); + return 0; } } - /* loop all current socket connections */ - admin = admin_first; - adminp = &admin_first; - while(admin) { + return 0; +} + +int admin_handle_con(struct lcr_fd *fd, unsigned int what, void *instance, int index) +{ + struct admin_list *admin = (struct admin_list *)instance; + void *temp; + struct admin_message msg; + int len; + struct Endpoint *epoint; + + if ((what & LCR_FD_READ)) { /* read command */ len = read(admin->sock, &msg, sizeof(msg)); if (len < 0) { - if (errno != EWOULDBLOCK) { - work = 1; - brokenpipe: - PDEBUG(DEBUG_LOG, "Broken pipe on socket %d. (errno=%d).\n", admin->sock, errno); - *adminp = admin->next; - free_connection(admin); - admin = *adminp; - continue; - } - goto send_data; + brokenpipe: + PDEBUG(DEBUG_LOG, "Broken pipe on socket %d. (errno=%d).\n", admin->sock, errno); + free_connection(admin); + return 0; } - work = 1; -//#warning -//PERROR("DEBUG socket %d got data. serial=%d\n", admin->sock, admin->sockserial); if (len == 0) { end: @@ -1138,28 +1127,19 @@ int admin_handle(void) } } -//#warning -//PERROR("DEBUG socket %d closed by remote.\n", admin->sock); - *adminp = admin->next; free_connection(admin); - admin = *adminp; -//PERROR("DEBUG (admin_first=%x)\n", admin_first); - continue; + return 0; } if (len != sizeof(msg)) { PERROR("Short/long read on socket %d. (len=%d != size=%d).\n", admin->sock, len, sizeof(msg)); - *adminp = admin->next; free_connection(admin); - admin = *adminp; - continue; + return 0; } /* process socket command */ if (admin->response && msg.message != ADMIN_MESSAGE) { PERROR("Data from socket %d while sending response.\n", admin->sock); - *adminp = admin->next; free_connection(admin); - admin = *adminp; - continue; + return 0; } switch (msg.message) { case ADMIN_REQUEST_CMD_INTERFACE: @@ -1167,6 +1147,7 @@ int admin_handle(void) PERROR("Failed to create dial response for socket %d.\n", admin->sock); goto response_error; } + admin->fd.when |= LCR_FD_WRITE; break; case ADMIN_REQUEST_CMD_ROUTE: @@ -1174,6 +1155,7 @@ int admin_handle(void) PERROR("Failed to create dial response for socket %d.\n", admin->sock); goto response_error; } + admin->fd.when |= LCR_FD_WRITE; break; case ADMIN_REQUEST_CMD_DIAL: @@ -1181,6 +1163,7 @@ int admin_handle(void) PERROR("Failed to create dial response for socket %d.\n", admin->sock); goto response_error; } + admin->fd.when |= LCR_FD_WRITE; break; case ADMIN_REQUEST_CMD_RELEASE: @@ -1188,6 +1171,7 @@ int admin_handle(void) PERROR("Failed to create release response for socket %d.\n", admin->sock); goto response_error; } + admin->fd.when |= LCR_FD_WRITE; break; case ADMIN_REQUEST_STATE: @@ -1195,6 +1179,7 @@ int admin_handle(void) PERROR("Failed to create state response for socket %d.\n", admin->sock); goto response_error; } + admin->fd.when |= LCR_FD_WRITE; break; case ADMIN_TRACE_REQUEST: @@ -1202,6 +1187,7 @@ int admin_handle(void) PERROR("Failed to create trace response for socket %d.\n", admin->sock); goto response_error; } + admin->fd.when |= LCR_FD_WRITE; break; case ADMIN_REQUEST_CMD_BLOCK: @@ -1209,6 +1195,7 @@ int admin_handle(void) PERROR("Failed to create block response for socket %d.\n", admin->sock); goto response_error; } + admin->fd.when |= LCR_FD_WRITE; break; case ADMIN_MESSAGE: @@ -1216,71 +1203,46 @@ int admin_handle(void) PERROR("Failed to deliver message for socket %d.\n", admin->sock); goto response_error; } -#if 0 -#warning DEBUGGING -{ - struct admin_queue *response; - printf("Chain: "); - response = admin->response; - while(response) { - printf("%c", '0'+response->am[0].message); - response=response->next; - } - printf("\n"); -} -#endif break; case ADMIN_CALL_SETUP: if (admin_call(admin, &msg) < 0) { PERROR("Failed to create call for socket %d.\n", admin->sock); response_error: - *adminp = admin->next; free_connection(admin); - admin = *adminp; - continue; + return 0; } break; default: PERROR("Invalid message %d from socket %d.\n", msg.message, admin->sock); - *adminp = admin->next; free_connection(admin); - admin = *adminp; - continue; + return 0; } + } + + if ((what & LCR_FD_WRITE)) { /* write queue */ - send_data: if (admin->response) { -//#warning -//PERROR("DEBUG socket %d sending data.\n", admin->sock); len = write(admin->sock, ((unsigned char *)(admin->response->am))+admin->response->offset, sizeof(struct admin_message)*(admin->response->num)-admin->response->offset); if (len < 0) { - if (errno != EWOULDBLOCK) { - work = 1; - goto brokenpipe; - } - goto next; + goto brokenpipe; } - work = 1; if (len == 0) goto end; if (len < (int)(sizeof(struct admin_message)*(admin->response->num) - admin->response->offset)) { admin->response->offset+=len; - goto next; + return 0; } else { temp = admin->response; admin->response = admin->response->next; FREE(temp, 0); memuse--; } - } - /* done with socket instance */ - next: - adminp = &admin->next; - admin = admin->next; + } else + admin->fd.when &= ~LCR_FD_WRITE; } - return(work); + return 0; } diff --git a/socket_server.h b/socket_server.h index 4177139..b3ea89a 100644 --- a/socket_server.h +++ b/socket_server.h @@ -21,6 +21,7 @@ struct admin_queue { struct admin_list { struct admin_list *next; int sock; + struct lcr_fd fd; int sockserial; char remote_name[32]; /* socket is connected remote application */ struct admin_trace_req trace; /* stores trace, if detail != 0 */ @@ -31,7 +32,6 @@ struct admin_list { extern struct admin_list *admin_first; int admin_init(void); void admin_cleanup(void); -int admin_handle(void); void admin_call_response(int adminid, int message, const char *connected, int cause, int location, int notify); int admin_message_to_join(struct admin_message *msg, int remote_id); int admin_message_from_join(int remote_id, unsigned int ref, int message_type, union parameter *param); diff --git a/ss5.cpp b/ss5.cpp index 259b647..09f97eb 100644 --- a/ss5.cpp +++ b/ss5.cpp @@ -333,6 +333,7 @@ class Pss5 *ss5_hunt_line(struct mISDNport *mISDNport) return NULL; } +int queue_event(struct lcr_work *work, void *instance, int index); /* * constructor @@ -352,8 +353,8 @@ Pss5::Pss5(int type, struct mISDNport *mISDNport, char *portname, struct port_se //p_m_s_decoder_buffer; p_m_s_sample_nr = 0; p_m_s_recog = 0; - p_m_s_timer = 0.0; - p_m_s_timer_fn = NULL; + memset(&p_m_s_queue, 0, sizeof(p_m_s_queue)); + add_work(&p_m_s_queue, queue_event, this, 0); p_m_s_answer = 0; p_m_s_busy_flash = 0; p_m_s_clear_back = 0; @@ -372,6 +373,7 @@ Pss5::Pss5(int type, struct mISDNport *mISDNport, char *portname, struct port_se */ Pss5::~Pss5() { + del_work(&p_m_s_queue); } @@ -383,7 +385,47 @@ void Pss5::_new_ss5_state(int state, const char *func, int line) PDEBUG(DEBUG_SS5, "%s(%s:%d): changing SS5 state from %s to %s\n", p_name, func, line, ss5_state_name[p_m_s_state], ss5_state_name[state]); p_m_s_state = state; p_m_s_signal = SS5_SIGNAL_NULL; + + if (p_m_s_state == SS5_STATE_IDLE && (p_m_s_answer || p_m_s_busy_flash || p_m_s_clear_back)) + trigger_work(&p_m_s_queue); } + +int queue_event(struct lcr_work *work, void *instance, int index) +{ + class Pss5 *ss5port = (class Pss5 *)instance; + + if (ss5port->p_m_s_state == SS5_STATE_IDLE) { + /* if answer signal is queued */ + if (ss5port->p_m_s_answer) { + ss5port->p_m_s_answer = 0; + /* start answer */ + ss5_trace_header(ss5port->p_m_mISDNport, ss5port, SS5_ANSWER_REQ, ss5port->p_m_b_channel); + end_trace(); + ss5port->start_signal(SS5_STATE_ANSWER); + } + + /* if busy-flash signal is queued */ + if (ss5port->p_m_s_busy_flash) { + ss5port->p_m_s_busy_flash = 0; + /* start busy-flash */ + ss5_trace_header(ss5port->p_m_mISDNport, ss5port, SS5_BUSY_FLASH_REQ, ss5port->p_m_b_channel); + end_trace(); + ss5port->start_signal(SS5_STATE_BUSY_FLASH); + } + + /* if clear-back signal is queued */ + if (ss5port->p_m_s_clear_back) { + ss5port->p_m_s_clear_back = 0; + /* start clear-back */ + ss5_trace_header(ss5port->p_m_mISDNport, ss5port, SS5_CLEAR_BACK_REQ, ss5port->p_m_b_channel); + end_trace(); + ss5port->start_signal(SS5_STATE_CLEAR_BACK); + } + } + + return 0; +} + void Pss5::_new_ss5_signal(int signal, const char *func, int line) { if (p_m_s_signal) @@ -1606,8 +1648,6 @@ void Pss5::do_release(int cause, int location) { struct lcr_msg *message; - p_m_s_timer = 0.0; - /* sending release to endpoint */ while(p_epointlist) { message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE); @@ -1672,52 +1712,6 @@ void Pss5::do_setup(char *dial, int complete) } -/* - * handler - */ -int Pss5::handler(void) -{ - int ret; - - if ((ret = PmISDN::handler())) - return(ret); - - /* handle timer */ - if (p_m_s_timer && p_m_s_timer < now) { - p_m_s_timer = 0.0; - (this->*(p_m_s_timer_fn))(); - } - - /* if answer signal is queued */ - if (p_m_s_answer && p_m_s_state == SS5_STATE_IDLE) { - p_m_s_answer = 0; - /* start answer */ - ss5_trace_header(p_m_mISDNport, this, SS5_ANSWER_REQ, p_m_b_channel); - end_trace(); - start_signal(SS5_STATE_ANSWER); - } - - /* if busy-flash signal is queued */ - if (p_m_s_busy_flash && p_m_s_state == SS5_STATE_IDLE) { - p_m_s_busy_flash = 0; - /* start busy-flash */ - ss5_trace_header(p_m_mISDNport, this, SS5_BUSY_FLASH_REQ, p_m_b_channel); - end_trace(); - start_signal(SS5_STATE_BUSY_FLASH); - } - - /* if clear-back signal is queued */ - if (p_m_s_clear_back && p_m_s_state == SS5_STATE_IDLE) { - p_m_s_clear_back = 0; - /* start clear-back */ - ss5_trace_header(p_m_mISDNport, this, SS5_CLEAR_BACK_REQ, p_m_b_channel); - end_trace(); - start_signal(SS5_STATE_CLEAR_BACK); - } - - return(0); -} - /* * handles all messages from endpoint @@ -1917,6 +1911,7 @@ void Pss5::message_connect(unsigned int epoint_id, int message_id, union paramet if (p_state != PORT_STATE_CONNECT) { new_state(PORT_STATE_CONNECT); p_m_s_answer = 1; + trigger_work(&p_m_s_queue); } set_tone("", NULL); @@ -1937,8 +1932,6 @@ if (0 || p_type==PORT_TYPE_SS5_OUT) { /* outgoing exchange */ start_signal(SS5_STATE_CLEAR_BACK); new_state(PORT_STATE_OUT_DISCONNECT); -// p_m_s_timer_fn = &Pss5::register_timeout; -// p_m_s_timer = now + 30.0; } /* MESSAGE_RELEASE */ diff --git a/ss5.h b/ss5.h index b1cc215..8a0c20d 100644 --- a/ss5.h +++ b/ss5.h @@ -25,7 +25,6 @@ class Pss5 : public PmISDN public: Pss5(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel, int exclusive, int mode); ~Pss5(); - int handler(void); int message_epoint(unsigned int epoint_id, int message, union parameter *param); void set_tone(const char *dir, const char *name); @@ -43,8 +42,7 @@ class Pss5 : public PmISDN unsigned char p_m_s_delay_mute[400/SS5_DECODER_NPOINTS]; /* 40 ms delay on mute, so a 'chirp' can be heared */ int p_m_s_sample_nr; /* decoder's sample number, counter */ int p_m_s_recog; /* sample counter to wait for signal recognition time */ - double p_m_s_timer; - void (Pss5::*p_m_s_timer_fn)(void); + struct lcr_work p_m_s_queue; int p_m_s_answer; /* queued signal */ int p_m_s_busy_flash; /* queued signal */ int p_m_s_clear_back; /* queued signal */ diff --git a/trace.c b/trace.c index 73686ff..b8dc001 100644 --- a/trace.c +++ b/trace.c @@ -22,6 +22,8 @@ static const char *spaces = " "; */ void _start_trace(const char *__file, int __line, int port, struct interface *interface, const char *caller, const char *dialing, int direction, int category, int serial, const char *name) { + struct timeval current_time; + if (trace.name[0]) PERROR("trace already started (name=%s) in file %s line %d\n", trace.name, __file, __line); memset(&trace, 0, sizeof(struct trace)); @@ -39,8 +41,9 @@ void _start_trace(const char *__file, int __line, int port, struct interface *in SCPY(trace.name, name); if (!trace.name[0]) SCPY(trace.name, ""); - trace.sec = now_tv.tv_sec; - trace.usec = now_tv.tv_usec; + gettimeofday(¤t_time, NULL); + trace.sec = current_time.tv_sec; + trace.usec = current_time.tv_usec; } @@ -270,7 +273,7 @@ void _end_trace(const char *__file, int __line) if (string) { /* process debug */ if (options.deb) - debug(NULL, 0, "trace", string); + debug(NULL, 0, "TRACE", string); /* process log */ if (options.log[0]) { fp = fopen(options.log, "a"); diff --git a/vbox.cpp b/vbox.cpp index 84d679e..6eb0ce2 100644 --- a/vbox.cpp +++ b/vbox.cpp @@ -17,6 +17,9 @@ /* note: recording log is written at endpoint */ +int announce_timer(struct lcr_timer *timer, void *instance, int index); +int record_timeout(struct lcr_timer *timer, void *instance, int index); + /* * initialize vbox port */ @@ -26,8 +29,11 @@ VBoxPort::VBoxPort(int type, struct port_settings *settings) : Port(type, "vbox" p_vbox_announce_fh = -1; p_vbox_audio_start = 0; p_vbox_audio_transferred = 0; - p_vbox_record_start = 0; p_vbox_record_limit = 0; + memset(&p_vbox_announce_timer, 0, sizeof(p_vbox_announce_timer)); + add_timer(&p_vbox_announce_timer, announce_timer, this, 0); + memset(&p_vbox_record_timeout, 0, sizeof(p_vbox_record_timeout)); + add_timer(&p_vbox_record_timeout, record_timeout, this, 0); } @@ -36,6 +42,8 @@ VBoxPort::VBoxPort(int type, struct port_settings *settings) : Port(type, "vbox" */ VBoxPort::~VBoxPort() { + del_timer(&p_vbox_announce_timer); + del_timer(&p_vbox_record_timeout); if (p_vbox_announce_fh >= 0) { close(p_vbox_announce_fh); p_vbox_announce_fh = -1; @@ -58,119 +66,130 @@ static void vbox_trace_header(class VBoxPort *vbox, const char *message, int dir } -/* - * handler of vbox - */ -int VBoxPort::handler(void) +int record_timeout(struct lcr_timer *timer, void *instance, int index) +{ + class VBoxPort *vboxport = (class VBoxPort *)instance; + struct lcr_msg *message; + + while(vboxport->p_epointlist) { + /* send release */ + message = message_create(vboxport->p_serial, vboxport->p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE); + message->param.disconnectinfo.cause = 16; + message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL; + message_put(message); + vbox_trace_header(vboxport, "RELEASE from VBox (recoding limit reached)", DIRECTION_IN); + add_trace("cause", "value", "%d", message->param.disconnectinfo.cause); + add_trace("cause", "location", "%d", message->param.disconnectinfo.location); + end_trace(); + /* remove epoint */ + vboxport->free_epointlist(vboxport->p_epointlist); + } + /* recording is close during destruction */ + delete vboxport; + return 0; +} + +int announce_timer(struct lcr_timer *timer, void *instance, int index) +{ + class VBoxPort *vboxport = (class VBoxPort *)instance; + + /* port my self destruct here */ + vboxport->send_announcement(); + + return 0; +} + +void VBoxPort::send_announcement(void) { struct lcr_msg *message; unsigned int tosend; unsigned char buffer[ISDN_TRANSMIT]; - time_t currenttime; class Endpoint *epoint; - int ret; - - if ((ret = Port::handler())) - return(ret); - - if (p_vbox_record_start && p_vbox_record_limit) { - time(¤ttime); - if (currenttime > (p_vbox_record_limit+p_vbox_record_start)) { - while(p_epointlist) { - /* send release */ - message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE); - message->param.disconnectinfo.cause = 16; - message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL; - message_put(message); - vbox_trace_header(this, "RELEASE from VBox (recoding limit reached)", DIRECTION_IN); - add_trace("cause", "value", "%d", message->param.disconnectinfo.cause); - add_trace("cause", "location", "%d", message->param.disconnectinfo.location); - end_trace(); - /* remove epoint */ - free_epointlist(p_epointlist); - } - /* recording is close during destruction */ - delete this; - return(-1); /* must return because port is gone */ - } - } + int temp; + struct timeval current_time; + long long now; + + /* don't restart timer, if announcement is played */ + if (p_vbox_announce_fh < 0) + return; + + gettimeofday(¤t_time, NULL); + now = current_time.tv_sec * MICRO_SECONDS + current_time.tv_usec; /* set time the first time */ - if (p_vbox_audio_start < 1) { - p_vbox_audio_start = now_d; - return(0); - } + if (!p_vbox_audio_start) + p_vbox_audio_start = now - ISDN_TRANSMIT; /* calculate the number of bytes */ - tosend = (unsigned int)((now_d-p_vbox_audio_start)*8000) - p_vbox_audio_transferred; + tosend = (unsigned int)(now - p_vbox_audio_start) - p_vbox_audio_transferred; - /* wait for more */ - if (tosend < sizeof(buffer)) - return(0); - tosend = sizeof(buffer); + /* schedule next event */ + temp = ISDN_TRANSMIT + ISDN_TRANSMIT - tosend; + if (temp < 0) + temp = 0; + schedule_timer(&p_vbox_announce_timer, 0, temp*125); + + if (tosend > sizeof(buffer)) + tosend = sizeof(buffer); /* add the number of samples elapsed */ p_vbox_audio_transferred += tosend; /* if announcement is currently played, send audio data */ - if (p_vbox_announce_fh >=0) { - tosend = read_tone(p_vbox_announce_fh, buffer, p_vbox_announce_codec, tosend, p_vbox_announce_size, &p_vbox_announce_left, 1); - if (tosend <= 0) { - /* end of file */ - close(p_vbox_announce_fh); - p_vbox_announce_fh = -1; - fhuse--; - - time(¤ttime); - p_vbox_record_start = currenttime; - - /* connect if not already */ - epoint = find_epoint_id(ACTIVE_EPOINT(p_epointlist)); - if (epoint) { - /* if we sent our announcement during ringing, we must now connect */ - if (p_vbox_ext.vbox_free) { - /* send connect message */ - message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_CONNECT); - memcpy(&message->param.connectinfo, &p_connectinfo, sizeof(struct connect_info)); - message_put(message); - vbox_trace_header(this, "CONNECT from VBox (announcement is over)", DIRECTION_IN); - end_trace(); - new_state(PORT_STATE_CONNECT); - } - } + tosend = read_tone(p_vbox_announce_fh, buffer, p_vbox_announce_codec, tosend, p_vbox_announce_size, &p_vbox_announce_left, 1); + if (tosend <= 0) { + /* end of file */ + close(p_vbox_announce_fh); + p_vbox_announce_fh = -1; + fhuse--; - /* start recording, if not already */ - if (p_vbox_mode == VBOX_MODE_NORMAL) { - /* recording start */ - open_record(p_vbox_ext.vbox_codec, 2, 0, p_vbox_ext.number, p_vbox_ext.anon_ignore, p_vbox_ext.vbox_email, p_vbox_ext.vbox_email_file); - vbox_trace_header(this, "RECORDING (announcement is over)", DIRECTION_IN); - end_trace(); - } else // else!! - if (p_vbox_mode == VBOX_MODE_ANNOUNCEMENT) { - /* send release */ - message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE); - message->param.disconnectinfo.cause = 16; - message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL; + if (p_vbox_record_limit) + schedule_timer(&p_vbox_record_timeout, p_vbox_record_limit, 0); + + /* connect if not already */ + epoint = find_epoint_id(ACTIVE_EPOINT(p_epointlist)); + if (epoint) { + /* if we sent our announcement during ringing, we must now connect */ + if (p_vbox_ext.vbox_free) { + /* send connect message */ + message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_CONNECT); + memcpy(&message->param.connectinfo, &p_connectinfo, sizeof(struct connect_info)); message_put(message); - vbox_trace_header(this, "RELEASE from VBox (after annoucement)", DIRECTION_IN); - add_trace("cause", "value", "%d", message->param.disconnectinfo.cause); - add_trace("cause", "location", "%d", message->param.disconnectinfo.location); + vbox_trace_header(this, "CONNECT from VBox (announcement is over)", DIRECTION_IN); end_trace(); - /* recording is close during destruction */ - delete this; - return(-1); /* must return because port is gone */ + new_state(PORT_STATE_CONNECT); } - } else { - if (p_record) - record(buffer, tosend, 0); // from down - message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_DATA); - message->param.data.len = tosend; - memcpy(message->param.data.data, buffer, tosend); + } + + /* start recording, if not already */ + if (p_vbox_mode == VBOX_MODE_NORMAL) { + /* recording start */ + open_record(p_vbox_ext.vbox_codec, 2, 0, p_vbox_ext.number, p_vbox_ext.anon_ignore, p_vbox_ext.vbox_email, p_vbox_ext.vbox_email_file); + vbox_trace_header(this, "RECORDING (announcement is over)", DIRECTION_IN); + end_trace(); + } else // else!! + if (p_vbox_mode == VBOX_MODE_ANNOUNCEMENT) { + /* send release */ + message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE); + message->param.disconnectinfo.cause = 16; + message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL; message_put(message); + vbox_trace_header(this, "RELEASE from VBox (after annoucement)", DIRECTION_IN); + add_trace("cause", "value", "%d", message->param.disconnectinfo.cause); + add_trace("cause", "location", "%d", message->param.disconnectinfo.location); + end_trace(); + /* recording is close during destruction */ + delete this; + return; /* must return because port is gone */ } + } else { + if (p_record) + record(buffer, tosend, 0); // from down + message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_DATA); + message->param.data.len = tosend; + memcpy(message->param.data.data, buffer, tosend); + message_put(message); } - - return(1); } @@ -288,6 +307,7 @@ int VBoxPort::message_epoint(unsigned int epoint_id, int message_id, union param /* play the announcement */ if ((p_vbox_announce_fh = open_tone(filename, &p_vbox_announce_codec, &p_vbox_announce_size, &p_vbox_announce_left)) >= 0) { fhuse++; + schedule_timer(&p_vbox_announce_timer, 0, 300000); } vbox_trace_header(this, "ANNOUNCEMENT", DIRECTION_OUT); add_trace("file", "name", "%s", filename); diff --git a/vbox.h b/vbox.h index b07ab5b..ac9ccfb 100644 --- a/vbox.h +++ b/vbox.h @@ -16,7 +16,7 @@ class VBoxPort : public Port VBoxPort(int type, struct port_settings *settings); ~VBoxPort(); int message_epoint(unsigned int epoint_id, int message, union parameter *param); - int handler(void); + void send_announcement(void); private: struct EndpointAppPBX *p_vbox_apppbx; /* pbx application */ @@ -29,9 +29,10 @@ class VBoxPort : public Port signed int p_vbox_announce_left; /* the number of bytes left of announcement sample */ signed int p_vbox_announce_size; /* size of current announcement (in bytes) */ int p_vbox_mode; /* type of recording VBOX_MODE_* */ - double p_vbox_audio_start; /* time stamp of starting of audio (<1 == not yet started) */ + long long p_vbox_audio_start; /* time stamp of starting of audio (0 == not yet started) */ unsigned int p_vbox_audio_transferred; /* number of samples sent to endpoint */ - signed int p_vbox_record_start; /* start for recording */ + struct lcr_timer p_vbox_announce_timer; /* timer for sending announcement */ + struct lcr_timer p_vbox_record_timeout; /* timer for recording limit */ signed int p_vbox_record_limit; /* limit for recording */ struct extension p_vbox_ext; /* save settings of extension */ -- cgit v1.2.3-55-g7522 From fa7af7ab195346b11a0bb401050d7c06f4a3ffaa Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sat, 16 Jan 2010 11:30:15 +0100 Subject: new file: checkout-branch.sh --- checkout-branch.sh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 checkout-branch.sh diff --git a/checkout-branch.sh b/checkout-branch.sh new file mode 100644 index 0000000..cdb9ab4 --- /dev/null +++ b/checkout-branch.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +#checks out the given branch + +if [ "$1" = "" ] ; then + echo "please provide one of the branch names:" + git branch -a + exit +fi + +git checkout -b $1 origin/$1 +git config branch.$1.remote origin +git config branch.$1.merge refs/heads/$1 + -- cgit v1.2.3-55-g7522 From 76c5d82d4cbdd9d75e6b6db9e51eb22d10fb44bd Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sat, 16 Jan 2010 11:42:46 +0100 Subject: Added "release" action and timeout to "execute" action. modified: README modified: action.cpp modified: apppbx.cpp modified: apppbx.h modified: dss1.cpp modified: mISDN.cpp modified: message.h modified: route.c modified: route.h modified: socket_server.c --- README | 1 + action.cpp | 56 +++++++++++++++++++++++++++++++++++++++++++++++++------- apppbx.cpp | 33 +++++++++++++++++---------------- apppbx.h | 3 ++- dss1.cpp | 31 ++++++++++++++++--------------- mISDN.cpp | 8 +++++++- message.h | 1 + route.c | 6 +++++- route.h | 19 ++++++++++--------- socket_server.c | 6 +++--- 10 files changed, 111 insertions(+), 53 deletions(-) diff --git a/README b/README index 2515150..bc747c2 100644 --- a/README +++ b/README @@ -534,6 +534,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. +- Added "release" action and timeout to "execute" action. diff --git a/action.cpp b/action.cpp index bf7c23d..aa83304 100644 --- a/action.cpp +++ b/action.cpp @@ -135,7 +135,7 @@ void EndpointAppPBX::action_dialing_internal(void) trace_header("ACTION extension (extension doesn't exist)", DIRECTION_NONE); add_trace("extension", NULL, dialinginfo.id); end_trace(); - release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0, 0); + release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0, 0, 0); new_state(EPOINT_STATE_OUT_DISCONNECT); message_disconnect_port(portlist, CAUSE_UNALLOCATED, LOCATION_PRIVATE_LOCAL, ""); set_tone(portlist, "cause_86"); @@ -147,7 +147,7 @@ void EndpointAppPBX::action_dialing_internal(void) add_trace("extension", NULL, dialinginfo.id); end_trace(); new_state(EPOINT_STATE_OUT_DISCONNECT); - release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0, 0); + release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0, 0, 0); message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, ""); set_tone(portlist, "cause_81"); return; @@ -273,7 +273,7 @@ void EndpointAppPBX::action_dialing_external(void) if (e_ext.rights < 2) { trace_header("ACTION extern (calling denied)", DIRECTION_NONE); end_trace(); - release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_REJECTED, 0, 0); + release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_REJECTED, 0, 0, 0); set_tone(portlist, "cause_82"); denied: message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, ""); @@ -288,7 +288,7 @@ void EndpointAppPBX::action_dialing_external(void) if (e_ext.rights < 3) { trace_header("ACTION extern (national calls denied)", DIRECTION_NONE); end_trace(); - release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_REJECTED, 0, 0); + release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_REJECTED, 0, 0, 0); set_tone(portlist, "cause_83"); goto denied; } @@ -300,7 +300,7 @@ void EndpointAppPBX::action_dialing_external(void) if (e_ext.rights < 4) { trace_header("ACTION extern (international calls denied)", DIRECTION_NONE); end_trace(); - release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_REJECTED, 0, 0); + release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_REJECTED, 0, 0, 0); set_tone(portlist, "cause_84"); goto denied; } @@ -1780,6 +1780,48 @@ void EndpointAppPBX::action_dialing_disconnect(void) } +/* + * process dialing release + */ +void EndpointAppPBX::action_dialing_release(void) +{ + struct route_param *rparam; + int cause = CAUSE_NORMAL; /* normal call clearing */ + int location = LOCATION_PRIVATE_LOCAL; + char cause_string[256] = "", display[84] = ""; + + /* check cause parameter */ + if ((rparam = routeparam(e_action, PARAM_CAUSE))) { + cause = rparam->integer_value; + PDEBUG(DEBUG_EPOINT, "EPOINT(%d): 'cause' is given: %d\n", ea_endpoint->ep_serial, cause); + } + if ((rparam = routeparam(e_action, PARAM_LOCATION))) { + location = rparam->integer_value; + PDEBUG(DEBUG_EPOINT, "EPOINT(%d): 'location' is given: %d\n", ea_endpoint->ep_serial, location); + } + + + /* use cause as sample, if not given later */ + SPRINT(cause_string, "cause_%02x", cause); + + /* check display */ + if ((rparam = routeparam(e_action, PARAM_DISPLAY))) { + SCPY(display, rparam->string_value); + PDEBUG(DEBUG_EPOINT, "EPOINT(%d): 'display' is given: %s\n", ea_endpoint->ep_serial, display); + } + + /* disconnect only if connect parameter is not given */ + trace_header("ACTION release", DIRECTION_NONE); + add_trace("cause", "value", "%d", cause); + add_trace("cause", "location", "%d", location); + if (display[0]) + add_trace("display", NULL, "%s", display); + end_trace(); + e_action = NULL; + release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, location, cause, 1); + return; +} + /* * process dialing help */ @@ -2148,10 +2190,10 @@ void EndpointAppPBX::process_dialing(int timeout) if (e_action->index == ACTION_DISCONNECT || e_state == EPOINT_STATE_OUT_DISCONNECT) { /* release after disconnect */ - release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); + release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); goto end; } - release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0, 0); + release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0, 0, 0); e_action = e_action->next; if (!e_action) { /* nothing more, so we release */ diff --git a/apppbx.cpp b/apppbx.cpp index 46b1f62..f630dbf 100644 --- a/apppbx.cpp +++ b/apppbx.cpp @@ -201,7 +201,7 @@ void EndpointAppPBX::new_state(int state) /* release join and port (as specified) */ -void EndpointAppPBX::release(int release, int joinlocation, int joincause, int portlocation, int portcause) +void EndpointAppPBX::release(int release, int joinlocation, int joincause, int portlocation, int portcause, int force) { struct port_list *portlist; struct lcr_msg *message; @@ -238,6 +238,7 @@ void EndpointAppPBX::release(int release, int joinlocation, int joincause, int p message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE); message->param.disconnectinfo.cause = portcause; message->param.disconnectinfo.location = portlocation; + message->param.disconnectinfo.force = force; // set, if port should release imediately message_put(message); logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT); } @@ -879,7 +880,7 @@ void EndpointAppPBX::out_setup(void) } if (atemp) { PERROR("EPOINT(%d) noknocking and currently a call\n", ea_endpoint->ep_serial); - release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_BUSY, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYSPE_ join, port */ + release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_BUSY, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYSPE_ join, port */ return; /* must exit here */ } } @@ -892,7 +893,7 @@ void EndpointAppPBX::out_setup(void) // if (!read_extension(&e_ext, exten)) if (!read_extension(&e_ext, e_dialinginfo.id)) { PDEBUG(DEBUG_EPOINT, "EPOINT(%d) extension %s not configured\n", ea_endpoint->ep_serial, e_dialinginfo.id); - release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_OUTOFORDER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */ + release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_OUTOFORDER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */ return; /* must exit here */ } @@ -1156,7 +1157,7 @@ void EndpointAppPBX::out_setup(void) end_trace(); if (!ea_endpoint->ep_join_id) break; - release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */ + release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */ return; /* must exit here */ } break; @@ -1245,7 +1246,7 @@ void EndpointAppPBX::out_setup(void) end_trace(); if (!ea_endpoint->ep_join_id) break; - release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOCHANNEL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */ + release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOCHANNEL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */ return; /* must exit here */ } break; @@ -1424,7 +1425,7 @@ void EndpointAppPBX::hookflash(void) port->set_echotest(0); } if (ea_endpoint->ep_join_id) { - release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */ + release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */ } e_ruleset = ruleset_main; if (e_ruleset) @@ -2237,7 +2238,7 @@ void EndpointAppPBX::port_disconnect_release(struct port_list *portlist, int mes } if (message_type == MESSAGE_RELEASE) ea_endpoint->free_portlist(portlist); - release(RELEASE_ALL, location, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, callcause, portcause */ + release(RELEASE_ALL, location, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, callcause, portcause */ return; /* must exit here */ } @@ -2254,7 +2255,7 @@ void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, add_trace("state", NULL, "outgoing setup/dialing"); end_trace(); /* no user responding */ - release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); + release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); return; /* must exit here */ case PORT_STATE_IN_SETUP: @@ -2269,7 +2270,7 @@ void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, end_trace(); param->disconnectinfo.cause = CAUSE_NOUSER; /* no user responding */ param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL; - release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); + release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); return; /* must exit here */ case PORT_STATE_IN_PROCEEDING: @@ -2283,7 +2284,7 @@ void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, end_trace(); param->disconnectinfo.cause = CAUSE_NOANSWER; /* no answer */ param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL; - release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOANSWER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); + release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOANSWER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); return; /* must exit here */ case PORT_STATE_CONNECT: @@ -2291,7 +2292,7 @@ void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, end_trace(); param->disconnectinfo.cause = CAUSE_NORMAL; /* normal */ param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL; - release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); + release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); return; /* must exit here */ case PORT_STATE_IN_ALERTING: @@ -2305,7 +2306,7 @@ void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, add_trace("state", NULL, "disconnect"); end_trace(); PDEBUG(DEBUG_EPOINT, "EPOINT(%d) in this special case, we release due to disconnect timeout.\n", ea_endpoint->ep_serial); - release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); + release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); return; /* must exit here */ default: @@ -2323,7 +2324,7 @@ void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, ""); portlist = portlist->next; } - release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */ + release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */ } /* port MESSAGE_NOTIFY */ @@ -2919,7 +2920,7 @@ void EndpointAppPBX::join_disconnect_release(int message_type, union parameter * /* we are powerdialing, if e_powerdial_on is set and limit is not exceeded if given */ if (e_powerdial_on && ((e_powercount+1)ep_portlist) { /* or no port */ process_hangup(param->disconnectinfo.cause, param->disconnectinfo.location); - release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, param->disconnectinfo.cause); /* RELEASE_TYPE, join, port */ + release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, param->disconnectinfo.cause, 0); /* RELEASE_TYPE, join, port */ return; /* must exit here */ } /* save cause */ @@ -2992,7 +2993,7 @@ void EndpointAppPBX::join_disconnect_release(int message_type, union parameter * || !e_join_pattern) { /* no patterns */ PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have own cause or we have no patterns. (own_cause=%d pattern=%d)\n", ea_endpoint->ep_serial, e_ext.own_cause, e_join_pattern); if (message_type != MESSAGE_RELEASE) - release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */ + release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */ e_join_pattern = 0; } else { /* else we enable audio */ message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH); diff --git a/apppbx.h b/apppbx.h index b10a119..8d2cb07 100644 --- a/apppbx.h +++ b/apppbx.h @@ -224,7 +224,7 @@ class EndpointAppPBX : public EndpointApp /* epoint */ void new_state(int state); - void release(int release, int joinlocation, int joincause, int portlocation, int portcause); + void release(int release, int joinlocation, int joincause, int portlocation, int portcause, int force); void notify_active(void); void keypad_function(char digit); void set_tone(struct port_list *portlist, const char *tone); @@ -288,6 +288,7 @@ class EndpointAppPBX : public EndpointApp void action_dialing_goto(void); void action_dialing_menu(void); void action_dialing_disconnect(void); + void action_dialing_release(void); void action_dialing_help(void); void action_dialing_deflect(void); void action_dialing_setforward(void); diff --git a/dss1.cpp b/dss1.cpp index 4a96e28..3bcf410 100644 --- a/dss1.cpp +++ b/dss1.cpp @@ -2607,45 +2607,46 @@ void Pdss1::message_release(unsigned int epoint_id, int message_id, union parame char *p = NULL; /* - * we may only release during incoming disconnect state. - * this means that the endpoint doesnt require audio anymore + * if we are on incoming call setup, we may reject by sending a release_complete + * also on outgoing call setup, we send a release complete, BUT this is not conform. (i don't know any other way) */ - if (p_state == PORT_STATE_IN_DISCONNECT - || p_state == PORT_STATE_OUT_DISCONNECT) { - /* sending release */ + if (p_state==PORT_STATE_IN_SETUP + || p_state==PORT_STATE_OUT_SETUP) { +//#warning remove me +//PDEBUG(DEBUG_LOG, "JOLLY sending release complete %d\n", p_serial); + /* sending release complete */ l3m = create_l3msg(); l1l2l3_trace_header(p_m_mISDNport, this, L3_RELEASE_REQ, DIRECTION_OUT); /* send cause */ enc_ie_cause(l3m, (p_m_mISDNport->locally && param->disconnectinfo.location==LOCATION_PRIVATE_LOCAL)?LOCATION_PRIVATE_LOCAL:param->disconnectinfo.location, param->disconnectinfo.cause); end_trace(); - p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_RELEASE, p_m_d_l3id, l3m); + p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_RELEASE_COMPLETE, p_m_d_l3id, l3m); new_state(PORT_STATE_RELEASE); /* remove epoint */ free_epointid(epoint_id); // wait for callref to be released return; - } /* - * if we are on incoming call setup, we may reject by sending a release_complete - * also on outgoing call setup, we send a release complete, BUT this is not conform. (i don't know any other way) + * we may only release during incoming disconnect state. + * this means that the endpoint doesnt require audio anymore */ - if (p_state==PORT_STATE_IN_SETUP - || p_state==PORT_STATE_OUT_SETUP) { -//#warning remove me -//PDEBUG(DEBUG_LOG, "JOLLY sending release complete %d\n", p_serial); - /* sending release complete */ + if (p_state == PORT_STATE_IN_DISCONNECT + || p_state == PORT_STATE_OUT_DISCONNECT + || param->disconnectinfo.force) { + /* sending release */ l3m = create_l3msg(); l1l2l3_trace_header(p_m_mISDNport, this, L3_RELEASE_REQ, DIRECTION_OUT); /* send cause */ enc_ie_cause(l3m, (p_m_mISDNport->locally && param->disconnectinfo.location==LOCATION_PRIVATE_LOCAL)?LOCATION_PRIVATE_LOCAL:param->disconnectinfo.location, param->disconnectinfo.cause); end_trace(); - p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_RELEASE_COMPLETE, p_m_d_l3id, l3m); + p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_RELEASE, p_m_d_l3id, l3m); new_state(PORT_STATE_RELEASE); /* remove epoint */ free_epointid(epoint_id); // wait for callref to be released return; + } #if 0 diff --git a/mISDN.cpp b/mISDN.cpp index 3e7751e..035b78b 100644 --- a/mISDN.cpp +++ b/mISDN.cpp @@ -1834,8 +1834,11 @@ static int mISDN_upqueue(struct lcr_fd *fd, unsigned int what, void *instance, i char byte; /* unset global semaphore */ - read(fd->fd, &byte, 1); upqueue_avail = 0; + // with a very small incident, upqueue_avail may be set by mISDN thread and + // another byte may be sent to the pipe, which causes a call to this function + // again with nothing in the upqueue. this is no problem. + read(fd->fd, &byte, 1); /* process all ports */ mISDNport = mISDNport_first; @@ -2060,6 +2063,9 @@ int do_layer3(struct mlayer3 *ml3, unsigned int cmd, unsigned int pid, struct l3 l3m->pid = pid; mqueue_tail(&mISDNport->upqueue, mb); if (!upqueue_avail) { + // multiple threads may cause multiple calls of this section, but this + // results only in multiple processing of the upqueue read. + // this is no problem. upqueue_avail = 1; char byte = 0; write(upqueue_pipe[1], &byte, 1); diff --git a/message.h b/message.h index a7f15b7..3c775cc 100644 --- a/message.h +++ b/message.h @@ -199,6 +199,7 @@ struct disconnect_info { int cause; /* reason for disconnect */ int location; /* disconnect location */ char display[84]; /* optional display information */ + int force; /* special flag to release imediately */ }; /* call-info structure REDIR */ diff --git a/route.c b/route.c index a448f39..959b584 100644 --- a/route.c +++ b/route.c @@ -342,6 +342,10 @@ struct action_defs action_defs[] = { "disconnect", NULL, &EndpointAppPBX::action_dialing_disconnect, NULL, PARAM_CONNECT | PARAM_CAUSE | PARAM_LOCATION | PARAM_SAMPLE | PARAM_DISPLAY, "Caller gets disconnected optionally with given cause and given sample and given display text."}, + { ACTION_RELEASE, + "release", NULL, &EndpointAppPBX::action_dialing_release, NULL, + PARAM_CONNECT | PARAM_CAUSE | PARAM_LOCATION | PARAM_DISPLAY, + "Same as 'disconnect', but using RELEASE message on ISDN."}, { ACTION_DEFLECT, "deflect", NULL, &EndpointAppPBX::action_dialing_deflect, NULL, PARAM_DEST, @@ -354,7 +358,7 @@ struct action_defs action_defs[] = { // "The call forward is set within the telephone network of the external line."}, { ACTION_EXECUTE, "execute", &EndpointAppPBX::action_init_execute, NULL, &EndpointAppPBX::action_hangup_execute, - PARAM_CONNECT | PARAM_EXECUTE | PARAM_PARAM | PARAM_ON, + PARAM_CONNECT | PARAM_EXECUTE | PARAM_PARAM | PARAM_ON | PARAM_TIMEOUT, "Executes the given script file. The file must terminate quickly, because it will halt the PBX."}, { ACTION_FILE, "file", NULL, NULL, &EndpointAppPBX::action_hangup_file, diff --git a/route.h b/route.h index 3530ef4..dca5a4e 100644 --- a/route.h +++ b/route.h @@ -174,15 +174,16 @@ enum { /* defines when a statement should be executed */ #define ACTION_GOTO 20 #define ACTION_MENU 21 #define ACTION_DISCONNECT 22 -#define ACTION_DEFLECT 23 -#define ACTION_SETFORWARD 24 -#define ACTION_EXECUTE 25 -#define ACTION_FILE 26 -#define ACTION_PICK 27 -#define ACTION_PASSWORD 28 -#define ACTION_PASSWORD_WRITE 29 -#define ACTION_NOTHING 30 -#define ACTION_EFI 31 +#define ACTION_RELEASE 23 +#define ACTION_DEFLECT 24 +#define ACTION_SETFORWARD 25 +#define ACTION_EXECUTE 26 +#define ACTION_FILE 27 +#define ACTION_PICK 28 +#define ACTION_PASSWORD 29 +#define ACTION_PASSWORD_WRITE 30 +#define ACTION_NOTHING 31 +#define ACTION_EFI 32 struct route_cond { /* an item */ struct route_cond *next; /* next entry */ diff --git a/socket_server.c b/socket_server.c index b67b91f..3083085 100644 --- a/socket_server.c +++ b/socket_server.c @@ -278,7 +278,7 @@ int admin_route(struct admin_queue **responsep) release: unsched_timer(&apppbx->e_callback_timeout); apppbx->e_action = NULL; - apppbx->release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); + apppbx->release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); start_trace(-1, NULL, numberrize_callerinfo(apppbx->e_callerinfo.id, apppbx->e_callerinfo.ntype, options.national, options.international), @@ -488,7 +488,7 @@ int admin_release(struct admin_queue **responsep, char *message) } unsched_timer(&apppbx->e_callback_timeout); - apppbx->release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); + apppbx->release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); out: /* attach to response chain */ @@ -1123,7 +1123,7 @@ int admin_handle_con(struct lcr_fd *fd, unsigned int what, void *instance, int i epoint = find_epoint_id(admin->epointid); if (epoint) { ((class DEFAULT_ENDPOINT_APP *)epoint->ep_app)-> - release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); + release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); } } -- cgit v1.2.3-55-g7522 From 34b17bad86b02fae864505ae5fe7055a2bd63290 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sun, 24 Jan 2010 14:22:34 +0100 Subject: Added queue buffer for chan_lcr sending faxes without interruption. Use options "t:q250" for disabling mISDN_dsp and adding a 250ms delay. modified: README modified: bchannel.c modified: bchannel.h modified: chan_lcr.c modified: chan_lcr.h modified: select.c --- README | 2 ++ bchannel.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- bchannel.h | 16 +++++++++++- chan_lcr.c | 14 +++++++++-- chan_lcr.h | 2 +- select.c | 12 ++++----- 6 files changed, 115 insertions(+), 13 deletions(-) diff --git a/README b/README index bc747c2..07c26ac 100644 --- a/README +++ b/README @@ -535,6 +535,8 @@ Changes after Version 1.7 - Replaced polling main loop by event driven "select()" loop. - Also replaced polling main loop by event driven "select()" loop on chan_lcr. - Added "release" action and timeout to "execute" action. +- Added queue buffer for chan_lcr sending faxes without interruption. + -> Use options "t:q250" for disabling mISDN_dsp and adding a 250ms delay. diff --git a/bchannel.c b/bchannel.c index 9e878fe..51423a1 100644 --- a/bchannel.c +++ b/bchannel.c @@ -54,6 +54,7 @@ #include "bchannel.h" #include "chan_lcr.h" #include "callerid.h" +#include "options.h" #ifndef ISDN_PID_L4_B_USER @@ -69,6 +70,7 @@ enum { BSTATE_DEACTIVATING, }; +static void bchannel_send_queue(struct bchannel *bchannel); int bchannel_initialize(void) { @@ -129,7 +131,7 @@ static int bchannel_handle(struct lcr_fd *fd, unsigned int what, void *instance, /* * create stack */ -int bchannel_create(struct bchannel *bchannel, int mode) +int bchannel_create(struct bchannel *bchannel, int mode, int queue) { int ret; struct sockaddr_mISDN addr; @@ -140,7 +142,7 @@ int bchannel_create(struct bchannel *bchannel, int mode) } /* open socket */ - bchannel->b_mode = mode; + bchannel->b_mode = (mode & 3); switch(bchannel->b_mode) { case 0: CDEBUG(bchannel->call, NULL, "Open DSP audio\n"); @@ -181,6 +183,19 @@ int bchannel_create(struct bchannel *bchannel, int mode) bchannel->b_sock = -1; return 0; } + + /* queue */ + if (bchannel->b_mode == 1 && queue) { + bchannel->nodsp_queue_out = 0; + bchannel->nodsp_queue_in = queue * 8; + if (bchannel->nodsp_queue_in > QUEUE_BUFFER_MAX-1) + bchannel->nodsp_queue_in = QUEUE_BUFFER_MAX-1; + bchannel->nodsp_queue = bchannel->nodsp_queue_in; /* store initial load */ + memset(&bchannel->nodsp_queue_buffer, (options.law=='a')?0x2a:0xff, QUEUE_BUFFER_SIZE); + bchannel->queue_sent = 0; + } else + bchannel->nodsp_queue = 0; + return 1; } @@ -399,6 +414,7 @@ void bchannel_transmit(struct bchannel *bchannel, unsigned char *data, int len) struct mISDNhead *frm = (struct mISDNhead *)buff; int ret; int i; + int space, in; if (bchannel->b_state != BSTATE_ACTIVE) return; @@ -425,12 +441,68 @@ void bchannel_transmit(struct bchannel *bchannel, unsigned char *data, int len) break; } frm->id = 0; +#ifdef SEAMLESS_TEST + unsigned char test_tone[8] = {0x2a, 0x24, 0xb4, 0x24, 0x2a, 0x25, 0xb5, 0x25}; + p = buff + MISDN_HEADER_LEN; + for (i = 0; i < len; i++) + *p++ = test_tone[(bchannel->test + i) & 7]; + bchannel->test = (bchannel->test + len) & 7; +#endif + if (bchannel->nodsp_queue) { + space = (bchannel->nodsp_queue_out - bchannel->nodsp_queue_in) & (QUEUE_BUFFER_SIZE - 1); + if (len > space) { + CERROR(bchannel->call, NULL, "Queue buffer overflow.\n"); + return; + } + p = buff + MISDN_HEADER_LEN; + in = bchannel->nodsp_queue_in; + for (i = 0; i < len; i++) { + bchannel->nodsp_queue_buffer[in] = *p++; + in = (in + 1) & (QUEUE_BUFFER_SIZE - 1); + } + bchannel->nodsp_queue_in = in; + if (bchannel->queue_sent == 0) /* if there is no pending data */ + bchannel_send_queue(bchannel); + return; + } ret = sendto(bchannel->b_sock, buff, MISDN_HEADER_LEN+len, 0, NULL, 0); if (ret < 0) CERROR(bchannel->call, NULL, "Failed to send to socket %d\n", bchannel->b_sock); } +/* + * in case of a send queue, we send from that queue rather directly + */ +static void bchannel_send_queue(struct bchannel *bchannel) +{ + unsigned char buff[1024 + MISDN_HEADER_LEN], *p = buff + MISDN_HEADER_LEN; + struct mISDNhead *frm = (struct mISDNhead *)buff; + int ret; + int i; + int len, out; + + len = (bchannel->nodsp_queue_in - bchannel->nodsp_queue_out) & (QUEUE_BUFFER_SIZE - 1); + if (len == 0) + return; /* mISDN driver received all load */ + if (len > 1024) + len = 1024; + frm->prim = PH_DATA_REQ; + frm->id = 0; + out = bchannel->nodsp_queue_out; + for (i = 0; i < len; i++) { + *p++ = bchannel->nodsp_queue_buffer[out]; + out = (out + 1) & (QUEUE_BUFFER_SIZE - 1); + } + bchannel->nodsp_queue_out = out; + ret = sendto(bchannel->b_sock, buff, MISDN_HEADER_LEN+len, 0, NULL, 0); + if (ret < 0) + CERROR(bchannel->call, NULL, "Failed to send to socket %d\n", bchannel->b_sock); + else + bchannel->queue_sent = 1; +} + + /* * join bchannel */ @@ -526,8 +598,12 @@ static int bchannel_handle(struct lcr_fd *fd, unsigned int what, void *instance, 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 */ + /* after a confim, we can send more from queue */ case PH_DATA_CNF: + if (bchannel->nodsp_queue) { + bchannel->queue_sent = 0; + bchannel_send_queue(bchannel); + } break; /* we receive audio data, we respond to it AND we send tones */ diff --git a/bchannel.h b/bchannel.h index 2b03444..55ce323 100644 --- a/bchannel.h +++ b/bchannel.h @@ -9,6 +9,11 @@ ** ** \*****************************************************************************/ +/* this test produces a test tone to test gaps in audio stream */ +//#define SEAMLESS_TEST + +#define QUEUE_BUFFER_SIZE 8192 /* must be the power of two */ +#define QUEUE_BUFFER_MAX 4096 /* half of size */ struct bchannel { struct bchannel *next; @@ -31,6 +36,15 @@ struct bchannel { int b_dtmf; int b_bf_len; unsigned char b_bf_key[128]; + int nodsp_queue; /* enables nodsp_queue_buffer */ + unsigned char nodsp_queue_buffer[QUEUE_BUFFER_SIZE]; + /* buffer for seamless transmission */ + unsigned int nodsp_queue_in, nodsp_queue_out; + /* in and out pointers */ + int queue_sent; /* data for mISDN was not confrmed yet */ +#ifdef SEAMLESS_TEST + int test; +#endif }; @@ -40,7 +54,7 @@ extern pid_t bchannel_pid; int bchannel_initialize(void); void bchannel_deinitialize(void); void bchannel_destroy(struct bchannel *bchannel); -int bchannel_create(struct bchannel *channel, int mode); +int bchannel_create(struct bchannel *channel, int mode, int queue); void bchannel_activate(struct bchannel *channel, int activate); void bchannel_transmit(struct bchannel *channel, unsigned char *data, int len); void bchannel_join(struct bchannel *channel, unsigned short id); diff --git a/chan_lcr.c b/chan_lcr.c index d0993b7..0013f2f 100644 --- a/chan_lcr.c +++ b/chan_lcr.c @@ -496,6 +496,14 @@ void apply_opt(struct chan_call *call, char *data) if (!call->nodsp) call->nodsp = 1; break; + case 'q': + if (opt[1] == '\0') { + CERROR(call, call->ast, "Option 'q' (queue) expects parameter.\n", opt); + break; + } + CDEBUG(call, call->ast, "Option 'q' (queue).\n"); + call->nodsp_queue = atoi(opt+1); + break; case 'e': if (opt[1] == '\0') { CERROR(call, call->ast, "Option 'e' (echo cancel) expects parameter.\n", opt); @@ -591,7 +599,7 @@ void apply_opt(struct chan_call *call, char *data) /* re-open, if bchannel is created */ if (call->bchannel && call->bchannel->b_sock > -1) { bchannel_destroy(call->bchannel); - if (bchannel_create(call->bchannel, ((call->nodsp || call->faxdetect > 0)?1:0) + ((call->hdlc)?2:0))) + if (bchannel_create(call->bchannel, ((call->nodsp || call->faxdetect > 0)?1:0) + ((call->hdlc)?2:0), call->nodsp_queue)) bchannel_activate(call->bchannel, 1); } } @@ -1287,7 +1295,7 @@ int receive_message(int message_type, unsigned int ref, union parameter *param) bchannel_join(bchannel, call->bridge_id); } /* create only, if call exists, othewhise it bchannel is freed below... */ - if (bchannel_create(bchannel, ((call->nodsp || call->faxdetect > 0)?1:0) + ((call->hdlc)?2:0))) + if (bchannel_create(bchannel, ((call->nodsp || call->faxdetect > 0)?1:0) + ((call->hdlc)?2:0), call->nodsp_queue)) bchannel_activate(bchannel, 1); } /* acknowledge */ @@ -2802,6 +2810,8 @@ int load_module(void) " n - Don't detect dtmf tones on called channel.\n" " h - Force data call (HDLC).\n" " t - Disable mISDN_dsp features (required for fax application).\n" + " q - Add queue to make fax stream seamless (required for fax app).\n" + " Use queue size in miliseconds for optarg. (try 250)\n" " f - Adding fax detection. It it timeouts, mISDN_dsp is used.\n" " Use time to detect for optarg.\n" " c - Make crypted outgoing call, optarg is keyindex.\n" diff --git a/chan_lcr.h b/chan_lcr.h index 3a64593..e7ea0f5 100644 --- a/chan_lcr.h +++ b/chan_lcr.h @@ -71,7 +71,7 @@ struct chan_call { int bf_len; /* blowfish crypt key */ struct ast_dsp *dsp; /* ast dsp processor for fax/tone detection */ struct ast_trans_pvt *trans; /* Codec translation path as fax/tone detection requires slin */ - int nodsp, hdlc, faxdetect; + int nodsp, nodsp_queue, hdlc, faxdetect; /* flags for bchannel mode */ char queue_string[64]; /* queue for asterisk */ diff --git a/select.c b/select.c index ba9b563..8763739 100644 --- a/select.c +++ b/select.c @@ -104,9 +104,9 @@ again: } if (polling) timer = &no_time; -#warning TESTING - if (!timer) - printf("wait till infinity ..."); fflush(stdout); +//#warning TESTING +// if (!timer) +// printf("wait till infinity ..."); fflush(stdout); FD_ZERO(&readset); FD_ZERO(&writeset); @@ -129,9 +129,9 @@ again: rc = select(maxfd+1, &readset, &writeset, &exceptset, timer); if (lock) lock(); -#warning TESTING - if (!timer) - printf("interrupted.\n"); +//#warning TESTING +// if (!timer) +// printf("interrupted.\n"); if (rc < 0) return 0; if (global_change && *global_change) { -- cgit v1.2.3-55-g7522 From 8fb861ef9ece9f4bd68ef79a77625ec23c27aef1 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sun, 24 Jan 2010 19:41:32 +0100 Subject: - Fixed HLC (higher layer capability) modification to LCR routing. - Fixed chan_lcr fax queue buffer. Added LCR_TRANSFERCAPABILITY environment. -> use options "n:t:q250" for sending/receiving faxes with asterisk and chan_lcr. modified: README modified: action.cpp modified: bchannel.c modified: chan_lcr.c modified: route.c modified: route.h --- README | 2 ++ action.cpp | 4 +++ bchannel.c | 9 +++-- chan_lcr.c | 10 ++++++ route.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- route.h | 2 ++ 6 files changed, 130 insertions(+), 8 deletions(-) diff --git a/README b/README index 07c26ac..9b8aae1 100644 --- a/README +++ b/README @@ -537,6 +537,8 @@ Changes after Version 1.7 - Added "release" action and timeout to "execute" action. - Added queue buffer for chan_lcr sending faxes without interruption. -> Use options "t:q250" for disabling mISDN_dsp and adding a 250ms delay. +- Fixed HLC (higher layer capability) modification to LCR routing. +- Fixed chan_lcr fax queue buffer. Added LCR_TRANSFERCAPABILITY environment. diff --git a/action.cpp b/action.cpp index aa83304..62f63ed 100644 --- a/action.cpp +++ b/action.cpp @@ -111,6 +111,8 @@ void EndpointAppPBX::action_dialing_internal(void) capainfo.bearer_mode = INFO_BMODE_PACKET; } capainfo.bearer_info1 = INFO_INFO1_NONE; + capainfo.hlc = INFO_HLC_NONE; + capainfo.exthlc = INFO_HLC_NONE; } if ((rparam = routeparam(e_action, PARAM_BMODE))) { capainfo.bearer_mode = rparam->integer_value; @@ -237,6 +239,8 @@ void EndpointAppPBX::action_dialing_external(void) capainfo.bearer_mode = INFO_BMODE_PACKET; } capainfo.bearer_info1 = INFO_INFO1_NONE; + capainfo.hlc = INFO_HLC_NONE; + capainfo.exthlc = INFO_HLC_NONE; } if ((rparam = routeparam(e_action, PARAM_BMODE))) { capainfo.bearer_mode = rparam->integer_value; diff --git a/bchannel.c b/bchannel.c index 51423a1..b6107b6 100644 --- a/bchannel.c +++ b/bchannel.c @@ -449,9 +449,9 @@ void bchannel_transmit(struct bchannel *bchannel, unsigned char *data, int len) bchannel->test = (bchannel->test + len) & 7; #endif if (bchannel->nodsp_queue) { - space = (bchannel->nodsp_queue_out - bchannel->nodsp_queue_in) & (QUEUE_BUFFER_SIZE - 1); + space = (bchannel->nodsp_queue_out - bchannel->nodsp_queue_in - 1) & (QUEUE_BUFFER_SIZE - 1); if (len > space) { - CERROR(bchannel->call, NULL, "Queue buffer overflow.\n"); + CERROR(bchannel->call, NULL, "Queue buffer overflow, space is %d, len is %d.\n", space, len); return; } p = buff + MISDN_HEADER_LEN; @@ -485,6 +485,11 @@ static void bchannel_send_queue(struct bchannel *bchannel) len = (bchannel->nodsp_queue_in - bchannel->nodsp_queue_out) & (QUEUE_BUFFER_SIZE - 1); if (len == 0) return; /* mISDN driver received all load */ +#if 0 + printf("%4d:(%s|%s)\n", bchannel->nodsp_queue_out, + "----------------------------------------------------------------"+64-len/(8192/64), + " "+len/(8192/64)); +#endif if (len > 1024) len = 1024; frm->prim = PH_DATA_REQ; diff --git a/chan_lcr.c b/chan_lcr.c index 0013f2f..040f921 100644 --- a/chan_lcr.c +++ b/chan_lcr.c @@ -612,6 +612,7 @@ static void send_setup_to_lcr(struct chan_call *call) { union parameter newparam; struct ast_channel *ast = call->ast; + const char *tmp; if (!call->ast || !call->ref) return; @@ -664,6 +665,9 @@ static void send_setup_to_lcr(struct chan_call *call) default: newparam.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN; } + tmp = pbx_builtin_getvar_helper(ast, "LCR_TRANSFERCAPABILITY"); + if (tmp && *tmp) + ast->transfercapability = atoi(tmp); newparam.setup.capainfo.bearer_capa = ast->transfercapability; newparam.setup.capainfo.bearer_mode = INFO_BMODE_CIRCUIT; if (call->hdlc) @@ -2823,6 +2827,12 @@ int load_module(void) " vt - txgain control\n" " Volume changes at factor 2 ^ optarg.\n" " k - use keypad to dial this call.\n" + "\n" + "set LCR_TRANSFERCAPABILITY to the numerical bearer capabilty in order to alter caller's capability\n" + " -> use 16 for fax (3.1k audio)\n" + "\n" + "To send a fax, you need to set LCR_TRANSFERCAPABILITY environment to 16, also you need to set\n" + "options: \"n:t:q250\" for seamless audio transmission.\n" ); diff --git a/route.c b/route.c index 959b584..aaa5606 100644 --- a/route.c +++ b/route.c @@ -68,8 +68,8 @@ struct cond_defs cond_defs[] = { "capability=speech|audio|video|digital-restricted|digital-unrestricted|digital-unrestricted-tones[,...]", "Matches the given bearer capability(s)."}, { "infolayer1", MATCH_INFOLAYER1, COND_TYPE_INTEGER, "infolayer1=[,...]", "Matches the given information layer 1. (2=u-Law, 3=a-law, see info layer 1 in bearer capability.)"}, - { "hlc", MATCH_HLC, COND_TYPE_INTEGER, - "hlc=[,...]", "Matches the high layer capability(s)."}, + { "hlc", MATCH_HLC, COND_TYPE_HLC, + "hlc=telephony|faxg2g3|faxg4|teletex1|teletex2|teletex3|videotex1|videotex2|telex|mhs|osi|maintenance|management|audiovisual[,...]", "Matches the high layer capability(s)."}, { "file", MATCH_FILE, COND_TYPE_STRING, "file=[,...]", "Mathes is the given file exists and if the first character is '1'."}, { "execute", MATCH_EXECUTE, COND_TYPE_STRING, @@ -126,11 +126,11 @@ struct param_defs param_defs[] = { "infolayer1", PARAM_TYPE_INTEGER, "infolayer1=", "Alter the layer 1 information of a call. Use 3 for ALAW or 2 for uLAW."}, { PARAM_HLC, - "hlc", PARAM_TYPE_INTEGER, - "hlc=", "Alter the HLC identification. Use 1 for telephony or omit."}, + "hlc", PARAM_TYPE_HLC, + "hlc=telephony|faxg2g3|faxg4|teletex1|teletex2|teletex3|videotex1|videotex2|telex|mhs|osi|maintenance|management|audiovisual", "Alter the HLC identification."}, { PARAM_EXTHLC, - "exthlc", PARAM_TYPE_INTEGER, - "exthlc=", "Alter extended HLC value. (Mainenance only, don't use it.)"}, + "exthlc", PARAM_TYPE_HLC, + "exthlc=", "Alter extended HLC value, see hlc. (Mainenance only, don't use it.)"}, { PARAM_PRESENT, "present", PARAM_TYPE_YESNO, "present=yes|no", "Allow or restrict caller ID regardless what the caller wants."}, @@ -1252,6 +1252,43 @@ struct route_ruleset *ruleset_parse(void) cond->value_type = VALUE_TYPE_INTEGER; break; + /* parse service value */ + case COND_TYPE_HLC: + if (!strncasecmp("telephony", p, 9)) + cond->integer_value = INFO_HLC_TELEPHONY; + else if (!strncasecmp("faxg2g3", p, 7)) + cond->integer_value = INFO_HLC_FAXG2G3; + else if (!strncasecmp("faxg4", p, 5)) + cond->integer_value = INFO_HLC_FAXG4; + else if (!strncasecmp("teletex1", p, 8)) + cond->integer_value = INFO_HLC_TELETEX1; + else if (!strncasecmp("teletex2", p, 8)) + cond->integer_value = INFO_HLC_TELETEX2; + else if (!strncasecmp("teletex3", p, 8)) + cond->integer_value = INFO_HLC_TELETEX3; + else if (!strncasecmp("videotex1", p, 9)) + cond->integer_value = INFO_HLC_VIDEOTEX1; + else if (!strncasecmp("videotex2", p, 9)) + cond->integer_value = INFO_HLC_VIDEOTEX2; + else if (!strncasecmp("telex", p, 5)) + cond->integer_value = INFO_HLC_TELEX; + else if (!strncasecmp("mhs", p, 3)) + cond->integer_value = INFO_HLC_MHS; + else if (!strncasecmp("osi", p, 3)) + cond->integer_value = INFO_HLC_OSI; + else if (!strncasecmp("maintenance", p, 11)) + cond->integer_value = INFO_HLC_MAINTENANCE; + else if (!strncasecmp("management", p, 10)) + cond->integer_value = INFO_HLC_MANAGEMENT; + else if (!strncasecmp("audiovisual", p, 11)) + cond->integer_value = INFO_HLC_AUDIOVISUAL; + else { + SPRINT(failure, "Given HLC type is invalid or misspelled."); + goto parse_error; + } + cond->value_type = VALUE_TYPE_INTEGER; + break; + /* parse interface attribute : */ case COND_TYPE_IFATTR: key[0] = key_to[0] = '\0'; @@ -1536,6 +1573,7 @@ struct route_ruleset *ruleset_parse(void) case PARAM_TYPE_CALLERIDTYPE: case PARAM_TYPE_CAPABILITY: case PARAM_TYPE_BMODE: + case PARAM_TYPE_HLC: case PARAM_TYPE_DIVERSION: case PARAM_TYPE_DESTIN: case PARAM_TYPE_TYPE: @@ -1627,6 +1665,67 @@ struct route_ruleset *ruleset_parse(void) SPRINT(failure, "Bchannel mode '%s' unknown.", key); goto parse_error; } + if (param_defs[index].type == PARAM_TYPE_HLC) { + param->value_type = VALUE_TYPE_INTEGER; + if (!strcasecmp(key, "telephony")) { + param->integer_value = INFO_HLC_TELEPHONY; + break; + } + if (!strcasecmp(key, "faxg2g3")) { + param->integer_value = INFO_HLC_FAXG2G3; + break; + } + if (!strcasecmp(key, "faxg4")) { + param->integer_value = INFO_HLC_FAXG4; + break; + } + if (!strcasecmp(key, "teletex1")) { + param->integer_value = INFO_HLC_TELETEX1; + break; + } + if (!strcasecmp(key, "teletex2")) { + param->integer_value = INFO_HLC_TELETEX2; + break; + } + if (!strcasecmp(key, "teletex3")) { + param->integer_value = INFO_HLC_TELETEX3; + break; + } + if (!strcasecmp(key, "videotex1")) { + param->integer_value = INFO_HLC_VIDEOTEX1; + break; + } + if (!strcasecmp(key, "videotex2")) { + param->integer_value = INFO_HLC_VIDEOTEX2; + break; + } + if (!strcasecmp(key, "telex")) { + param->integer_value = INFO_HLC_TELEX; + break; + } + if (!strcasecmp(key, "mhs")) { + param->integer_value = INFO_HLC_MHS; + break; + } + if (!strcasecmp(key, "osi")) { + param->integer_value = INFO_HLC_OSI; + break; + } + if (!strcasecmp(key, "maintenance")) { + param->integer_value = INFO_HLC_MAINTENANCE; + break; + } + if (!strcasecmp(key, "management")) { + param->integer_value = INFO_HLC_MANAGEMENT; + break; + } + if (!strcasecmp(key, "audiovisual")) { + param->integer_value = INFO_HLC_AUDIOVISUAL; + break; + } + SPRINT(failure, "HLC type '%s' unknown.", key); + goto parse_error; + } if (param_defs[index].type == PARAM_TYPE_DIVERSION) { param->value_type = VALUE_TYPE_INTEGER; if (!strcasecmp(key, "cfu")) { diff --git a/route.h b/route.h index dca5a4e..1606410 100644 --- a/route.h +++ b/route.h @@ -32,6 +32,7 @@ enum { /* how to parse text file during startup */ COND_TYPE_IP, COND_TYPE_CAPABILITY, COND_TYPE_BMODE, + COND_TYPE_HLC, COND_TYPE_IFATTR, }; @@ -84,6 +85,7 @@ enum { /* how to parse text file during startup */ PARAM_TYPE_YESNO, PARAM_TYPE_CAPABILITY, PARAM_TYPE_BMODE, + PARAM_TYPE_HLC, PARAM_TYPE_DIVERSION, PARAM_TYPE_DESTIN, PARAM_TYPE_PORTS, -- cgit v1.2.3-55-g7522 From ce460a94e6371173c4ce063229276b6d32f47abd Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sat, 30 Jan 2010 11:59:07 +0100 Subject: register_fd() bugfix. --- gsm.cpp | 2 +- mISDN.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gsm.cpp b/gsm.cpp index 3358329..9ffcc4c 100644 --- a/gsm.cpp +++ b/gsm.cpp @@ -176,7 +176,7 @@ int Pgsm::bchannel_open(int index) bchannel_close(); return(ret); } - memset(&p_m_g_gsm_b_fd, 0, sizeof(p_m_g_gsm_b_fd.fd)); + memset(&p_m_g_gsm_b_fd, 0, sizeof(p_m_g_gsm_b_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); diff --git a/mISDN.cpp b/mISDN.cpp index 035b78b..7be3d4f 100644 --- a/mISDN.cpp +++ b/mISDN.cpp @@ -82,7 +82,7 @@ int mISDN_initialize(void) if (pipe(upqueue_pipe) < 0) FATAL("Failed to open pipe\n"); - memset(&upqueue_fd, 0, sizeof(upqueue_fd.fd)); + memset(&upqueue_fd, 0, sizeof(upqueue_fd)); upqueue_fd.fd = upqueue_pipe[0]; register_fd(&upqueue_fd, LCR_FD_READ, mISDN_upqueue, NULL, 0); -- cgit v1.2.3-55-g7522 From 0c65074b5b88b2da2390078d0fab6c72f228709d Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Thu, 11 Mar 2010 14:07:20 +0100 Subject: Fixed compiler warnings when compiling with gcc 4.3.4. Fixed names of moved include files (OpenBSC). modified: Makefile.am modified: Makefile.in modified: README modified: chan_lcr.c modified: configure modified: configure.ac modified: genrc.c modified: gentones.c modified: genwave.c modified: gsm.cpp modified: mISDN.cpp modified: main.c modified: port.cpp modified: tones.c modified: trace.c --- Makefile.am | 4 ++-- Makefile.in | 12 ++++++------ README | 3 +++ chan_lcr.c | 4 +++- configure | 4 ++-- configure.ac | 2 +- genrc.c | 15 ++++++++------- gentones.c | 21 +++++++++++---------- genwave.c | 7 ++++--- gsm.cpp | 4 ++-- mISDN.cpp | 6 ++++-- main.c | 3 ++- port.cpp | 25 ++++++++++++++----------- tones.c | 13 +++++++------ trace.c | 3 ++- 15 files changed, 71 insertions(+), 55 deletions(-) diff --git a/Makefile.am b/Makefile.am index 17f9a29..2125468 100644 --- a/Makefile.am +++ b/Makefile.am @@ -45,11 +45,11 @@ INSTALLATION_DEFINES = \ if ENABLE_GSM -GSM_INCLUDE = -DWITH_GSM -I./openbsc/include +GSM_INCLUDE = -DWITH_GSM -I./openbsc/include -I./libosmocore/include GSM_SOURCE = gsm_audio.c gsm.cpp gsm_conf.c openbsc/src/bsc_init.c openbsc/src/vty_interface.c openbsc/src/vty_interface_layer3.c -GSM_LIB = /usr/lib/libgsm.a ./openbsc/src/libbsc.a ./openbsc/src/libmsc.a ./openbsc/src/libvty.a -ldbi -lcrypt +GSM_LIB = /usr/lib/libgsm.a ./openbsc/src/libbsc.a ./openbsc/src/libmsc.a ./openbsc/src/libvty.a -L./libosmocore/src/ -losmocore -ldbi -lcrypt #gsm_audio.po: gsm_audio.c gsm_audio.h # $(CC) -D_GNU_SOURCE -fPIC -c gsm_audio.c -o gsm_audio.po diff --git a/Makefile.in b/Makefile.in index 1a2bd77..e45b8a0 100644 --- a/Makefile.in +++ b/Makefile.in @@ -249,9 +249,9 @@ INSTALLATION_DEFINES = \ -DLOG_DIR="\"$(LOGdir)\"" \ -DEXTENSION_DATA="\"$(EXTENSIONdir)\"" -@ENABLE_GSM_TRUE@GSM_INCLUDE = -DWITH_GSM -I./openbsc/include +@ENABLE_GSM_TRUE@GSM_INCLUDE = -DWITH_GSM -I./openbsc/include -I./libosmocore/include @ENABLE_GSM_TRUE@GSM_SOURCE = gsm_audio.c gsm.cpp gsm_conf.c openbsc/src/bsc_init.c openbsc/src/vty_interface.c openbsc/src/vty_interface_layer3.c -@ENABLE_GSM_TRUE@GSM_LIB = /usr/lib/libgsm.a ./openbsc/src/libbsc.a ./openbsc/src/libmsc.a ./openbsc/src/libvty.a -ldbi -lcrypt +@ENABLE_GSM_TRUE@GSM_LIB = /usr/lib/libgsm.a ./openbsc/src/libbsc.a ./openbsc/src/libmsc.a ./openbsc/src/libvty.a -L./libosmocore/src/ -losmocore -ldbi -lcrypt #gsm_audio.po: gsm_audio.c gsm_audio.h # $(CC) -D_GNU_SOURCE -fPIC -c gsm_audio.c -o gsm_audio.po @@ -294,15 +294,15 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ - echo ' cd $(srcdir) && $(AUTOMAKE) --foreign '; \ - cd $(srcdir) && $(AUTOMAKE) --foreign \ + echo ' cd $(srcdir) && $(AUTOMAKE) --gnu '; \ + cd $(srcdir) && $(AUTOMAKE) --gnu \ && exit 0; \ exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ cd $(top_srcdir) && \ - $(AUTOMAKE) --foreign Makefile + $(AUTOMAKE) --gnu Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ diff --git a/README b/README index 9b8aae1..e6bd449 100644 --- a/README +++ b/README @@ -539,6 +539,9 @@ Changes after Version 1.7 -> Use options "t:q250" for disabling mISDN_dsp and adding a 250ms delay. - Fixed HLC (higher layer capability) modification to LCR routing. - Fixed chan_lcr fax queue buffer. Added LCR_TRANSFERCAPABILITY environment. +- Fixed compiler warnings when compiling with gcc 4.3.4. + + diff --git a/chan_lcr.c b/chan_lcr.c index 040f921..6a953a2 100644 --- a/chan_lcr.c +++ b/chan_lcr.c @@ -2356,9 +2356,11 @@ static int lcr_indicate(struct ast_channel *ast, int cond, const void *data, siz break; #ifdef AST_CONTROL_SRCUPDATE case AST_CONTROL_SRCUPDATE: +#else + case 20: +#endif CDEBUG(call, ast, "Received AST_CONTROL_SRCUPDATE from Asterisk.\n"); break; -#endif default: CERROR(call, ast, "Received indicate from Asterisk with unknown condition %d.\n", cond); res = -1; diff --git a/configure b/configure index 9340f73..62e9cd7 100755 --- a/configure +++ b/configure @@ -6297,9 +6297,9 @@ else if test "x$with_gsm" != xcheck ; then { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -{ { $as_echo "$as_me:$LINENO: error: --with-gsm was given, but openbsc/include/openbsc/gsm_data.h was not found! Pleas link OpenBSC source directory to LCR source directory: ln -s path_to_openbsc/openbsc/ . +{ { $as_echo "$as_me:$LINENO: error: --with-gsm was given, but openbsc/include/openbsc/gsm_data.h was not found! Pleas link OpenBSC and libosmocore source directory to LCR source directory: ln -s path_to_openbsc/openbsc/ openbsc ; ln -s patch_to_libosmocore osmocore See \`config.log' for more details." >&5 -$as_echo "$as_me: error: --with-gsm was given, but openbsc/include/openbsc/gsm_data.h was not found! Pleas link OpenBSC source directory to LCR source directory: ln -s path_to_openbsc/openbsc/ . +$as_echo "$as_me: error: --with-gsm was given, but openbsc/include/openbsc/gsm_data.h was not found! Pleas link OpenBSC and libosmocore source directory to LCR source directory: ln -s path_to_openbsc/openbsc/ openbsc ; ln -s patch_to_libosmocore osmocore See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; }; } fi diff --git a/configure.ac b/configure.ac index d138e16..cc7cc9b 100644 --- a/configure.ac +++ b/configure.ac @@ -108,7 +108,7 @@ AS_IF([test "x$with_gsm" != xno], [with_gsm="yes"], [if test "x$with_gsm" != xcheck ; then AC_MSG_FAILURE( - [--with-gsm was given, but openbsc/include/openbsc/gsm_data.h was not found! Pleas link OpenBSC source directory to LCR source directory: ln -s path_to_openbsc/openbsc/ .]) + [--with-gsm was given, but openbsc/include/openbsc/gsm_data.h was not found! Pleas link OpenBSC and libosmocore source directory to LCR source directory: ln -s path_to_openbsc/openbsc/ openbsc ; ln -s patch_to_libosmocore osmocore]) fi ]) ]) diff --git a/genrc.c b/genrc.c index 3e349f4..1d5a076 100644 --- a/genrc.c +++ b/genrc.c @@ -39,6 +39,7 @@ int main(void) FILE *fp; int i = 0, j, jj, n; char input[256], file[256]; + int ret; printf("\n\nThis program generates a script, which is used to start/stop/restart mISDN\n"); printf("driver. Please select card only once. Mode and options are given by LCR.\n"); @@ -52,7 +53,7 @@ int main(void) } do { printf("\nSelect driver number[1-n] (or enter 'done'): "); fflush(stdout); - scanf("%s", input); + ret = scanf("%s", input); } while (atoi(input) <= 0 && !!strcmp(input, "done")); type[i] = atoi(input); i++; @@ -66,22 +67,22 @@ int main(void) } printf("\nEnter LAW audio mode. For a-LAW (default), just enter 0. For u-LAW enter 1.\n[0..n | 0xn]: "); fflush(stdout); - scanf("%s", input); + ret = scanf("%s", input); lawopt = strtoul(input, NULL, 0); printf("\nEnter debugging flags of mISDN core. For no debug, just enter 0.\n[0..n | 0xn]: "); fflush(stdout); - scanf("%s", input); + ret = scanf("%s", input); coredebug = strtoul(input, NULL, 0); printf("\nEnter debugging flags of cards. For no debug, just enter 0.\n[0..n | 0xn]: "); fflush(stdout); - scanf("%s", input); + ret = scanf("%s", input); carddebug = strtoul(input, NULL, 0); printf("\nEnter dsp debugging flags of driver. For no debug, just enter 0.\n[0..n | 0xn]: "); fflush(stdout); - scanf("%s", input); + ret = scanf("%s", input); dspdebug = strtoul(input, NULL, 0); n = i; printf("\nWhere do you like to load the modules from, enter 0 for default, 1 for\n'/usr/local/lcr/modules/' or the full path.\n[0 | 1 | ]: "); fflush(stdout); - scanf("%s", input); + ret = scanf("%s", input); if (!strcmp(input, "0")) SCPY(input, ""); if (!strcmp(input, "1")) @@ -90,7 +91,7 @@ int main(void) SCAT(input, "/"); printf("\n\nFinally tell me where to write the mISDN rc file.\nEnter the name 'mISDN' for current directory.\nYou may want to say '/usr/local/lcr/mISDN' or '/etc/rc.d/mISDN'\n: "); fflush(stdout); - scanf("%s", file); + ret = scanf("%s", file); if (!(fp=fopen(file, "w"))) { fprintf(stderr, "\nError: Failed to open '%s', try again.\n", file); exit(EXIT_FAILURE); diff --git a/gentones.c b/gentones.c index 6cdaf37..aaac659 100644 --- a/gentones.c +++ b/gentones.c @@ -150,9 +150,10 @@ void write_wav(FILE *fp, char *wav, char law) short sample, sample2; signed int size, chunk; int gotfmt = 0, gotdata = 0; + int ret; if ((wfp=fopen(wav,"r"))) { - fread(buffer,8,1,wfp); + ret=fread(buffer,8,1,wfp); size=(buffer[4]) + (buffer[5]<<8) + (buffer[6]<<16) + (buffer[7]<<24); if (!!strncmp((char *)buffer, "RIFF", 4)) { fclose(wfp); @@ -160,7 +161,7 @@ void write_wav(FILE *fp, char *wav, char law) return; } printf("%c%c%c%c size=%d\n",buffer[0],buffer[1],buffer[2],buffer[3],size); - fread(buffer,4,1,wfp); + ret=fread(buffer,4,1,wfp); size -= 4; if (!!strncmp((char *)buffer, "WAVE", 4)) { fclose(wfp); @@ -173,7 +174,7 @@ void write_wav(FILE *fp, char *wav, char law) fprintf(stderr, "Error: Remaining file size %d not large enough for next chunk.\n",size); return; } - fread(buffer,8,1,wfp); + ret=fread(buffer,8,1,wfp); chunk=(buffer[4]) + (buffer[5]<<8) + (buffer[6]<<16) + (buffer[7]<<24); //printf("DEBUG: size(%d) - (8+chunk(%d) = size(%d)\n", size, chunk, size-chunk-8); size -= (8+chunk); @@ -189,7 +190,7 @@ void write_wav(FILE *fp, char *wav, char law) fprintf(stderr, "Error: Fmt chunk illegal size.\n"); return; } - fread(buffer, chunk, 1, wfp); + ret=fread(buffer, chunk, 1, wfp); fmt = (struct fmt *)buffer; if (fmt->channels<1 || fmt->channels>2) { fclose(wfp); @@ -221,7 +222,7 @@ void write_wav(FILE *fp, char *wav, char law) i=0; if (bytes==2 && channels==1) { while(i (signed int)sizeof(buffer)) { - fread(buffer, sizeof(buffer), 1, wfp); + ret=fread(buffer, sizeof(buffer), 1, wfp); chunk -= sizeof(buffer); } if (chunk) - fread(buffer, chunk, 1, wfp); + ret=fread(buffer, chunk, 1, wfp); } } diff --git a/genwave.c b/genwave.c index 8f32076..685b5fa 100644 --- a/genwave.c +++ b/genwave.c @@ -100,6 +100,7 @@ void write_law(FILE *fp, char *name, char law) unsigned int i; short sample; unsigned int size, wsize; + int ret; if ((lfp=fopen(name,"r"))) { /* get size */ @@ -125,18 +126,18 @@ void write_law(FILE *fp, char *name, char law) fmt.data_rate = 16000; fmt.bytes_sample = 2; fmt.bits_sample = 16; - fwrite(&fmt, sizeof(fmt), 1, fp); + ret = fwrite(&fmt, sizeof(fmt), 1, fp); /* data */ fprintf(fp, "data%c%c%c%c", (char)(size&0xff), (char)((size>>8)&0xff), (char)((size>>16)&0xff), (char)(size>>24)); i = 0; while(i < size) { - fread(buffer, 1, 1, lfp); + ret = fread(buffer, 1, 1, lfp); if (law == 'a') sample = isdn_audio_alaw_to_s16[*buffer]; else sample = isdn_audio_ulaw_to_s16[*buffer]; - fwrite(&sample, 2, 1, fp); + ret = fwrite(&sample, 2, 1, fp); i+=2; } diff --git a/gsm.cpp b/gsm.cpp index 9ffcc4c..b2bdd6b 100644 --- a/gsm.cpp +++ b/gsm.cpp @@ -18,10 +18,10 @@ extern "C" { #include #include -#include +#include #include #include -#include +#include #include #include struct gsm_network *bsc_gsmnet = 0; diff --git a/mISDN.cpp b/mISDN.cpp index 7be3d4f..f5f8717 100644 --- a/mISDN.cpp +++ b/mISDN.cpp @@ -1832,13 +1832,14 @@ static int mISDN_upqueue(struct lcr_fd *fd, unsigned int what, void *instance, i struct mbuffer *mb; struct l3_msg *l3m; char byte; + int ret; /* unset global semaphore */ upqueue_avail = 0; // with a very small incident, upqueue_avail may be set by mISDN thread and // another byte may be sent to the pipe, which causes a call to this function // again with nothing in the upqueue. this is no problem. - read(fd->fd, &byte, 1); + ret = read(fd->fd, &byte, 1); /* process all ports */ mISDNport = mISDNport_first; @@ -2068,7 +2069,8 @@ int do_layer3(struct mlayer3 *ml3, unsigned int cmd, unsigned int pid, struct l3 // this is no problem. upqueue_avail = 1; char byte = 0; - write(upqueue_pipe[1], &byte, 1); + int ret; + ret = write(upqueue_pipe[1], &byte, 1); } return 0; } diff --git a/main.c b/main.c index b70ed05..b425abe 100644 --- a/main.c +++ b/main.c @@ -242,8 +242,9 @@ int main(int argc, char *argv[]) /* query available isdn ports */ if (!(strcasecmp(argv[1],"query"))) { + int rc; fprintf(stderr, "-> Using 'misdn_info'\n"); - system("misdn_info"); + rc = system("misdn_info"); ret = 0; goto free; } diff --git a/port.cpp b/port.cpp index e88175b..a083fa2 100644 --- a/port.cpp +++ b/port.cpp @@ -647,6 +647,7 @@ int Port::open_record(int type, int vbox, int skip, char *extension, int anon_ig char filename[256]; time_t now; struct tm *now_tm; + int ret; if (!extension) { PERROR("Port(%d) not an extension\n", p_serial); @@ -711,7 +712,7 @@ int Port::open_record(int type, int vbox, int skip, char *extension, int anon_ig case CODEC_MONO: case CODEC_STEREO: case CODEC_8BIT: - fwrite(dummyheader, sizeof(dummyheader), 1, p_record); + ret = fwrite(dummyheader, sizeof(dummyheader), 1, p_record); break; case CODEC_LAW: @@ -739,6 +740,7 @@ void Port::close_record(int beep, int mute) char *p; struct caller_info callerinfo; const char *valid_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890_.-!$%&/()=+*;~"; + int ret; if (!p_record) return; @@ -801,7 +803,7 @@ void Port::close_record(int beep, int mute) } i = 0; while(i < beep) { - fwrite(beep_mono, sizeof(beep_mono), 1, p_record); + ret = fwrite(beep_mono, sizeof(beep_mono), 1, p_record); i += sizeof(beep_mono); p_record_length += sizeof(beep_mono); } @@ -861,7 +863,7 @@ void Port::close_record(int beep, int mute) fmt.bits_sample = 8; /* one channel */ break; } - fwrite(&fmt, sizeof(fmt), 1, p_record); + ret = fwrite(&fmt, sizeof(fmt), 1, p_record); /* data */ fprintf(p_record, "data%c%c%c%c", (unsigned char)(size&0xff), (unsigned char)((size>>8)&0xff), (unsigned char)((size>>16)&0xff), (unsigned char)(size>>24)); @@ -939,6 +941,7 @@ void Port::record(unsigned char *data, int length, int dir_fromup) signed short *s; int free, i, ii; signed int sample; + int ret; /* no recording */ if (!p_record || !length) @@ -988,7 +991,7 @@ same_again: p_record_buffer_readp = (p_record_buffer_readp + 1) & RECORD_BUFFER_MASK; i++; } - fwrite(write_buffer, 512, 1, p_record); + ret = fwrite(write_buffer, 512, 1, p_record); p_record_length += 512; break; @@ -1011,7 +1014,7 @@ same_again: i++; } } - fwrite(write_buffer, 1024, 1, p_record); + ret = fwrite(write_buffer, 1024, 1, p_record); p_record_length += 1024; break; @@ -1023,7 +1026,7 @@ same_again: p_record_buffer_readp = (p_record_buffer_readp + 1) & RECORD_BUFFER_MASK; i++; } - fwrite(write_buffer, 512, 1, p_record); + ret = fwrite(write_buffer, 512, 1, p_record); p_record_length += 512; break; @@ -1035,7 +1038,7 @@ same_again: p_record_buffer_readp = (p_record_buffer_readp + 1) & RECORD_BUFFER_MASK; i++; } - fwrite(write_buffer, 256, 1, p_record); + ret = fwrite(write_buffer, 256, 1, p_record); p_record_length += 256; break; } @@ -1075,7 +1078,7 @@ different_again: *s++ = sample; i++; } - fwrite(write_buffer, ii<<1, 1, p_record); + ret = fwrite(write_buffer, ii<<1, 1, p_record); p_record_length += (ii<<1); break; @@ -1098,7 +1101,7 @@ different_again: i++; } } - fwrite(write_buffer, ii<<2, 1, p_record); + ret = fwrite(write_buffer, ii<<2, 1, p_record); p_record_length += (ii<<2); break; @@ -1114,7 +1117,7 @@ different_again: *d++ = (sample+0x8000) >> 8; i++; } - fwrite(write_buffer, ii, 1, p_record); + ret = fwrite(write_buffer, ii, 1, p_record); p_record_length += ii; break; @@ -1130,7 +1133,7 @@ different_again: *d++ = audio_s16_to_law[sample & 0xffff]; i++; } - fwrite(write_buffer, ii, 1, p_record); + ret = fwrite(write_buffer, ii, 1, p_record); p_record_length += ii; break; } diff --git a/tones.c b/tones.c index 93d04e9..ad69011 100644 --- a/tones.c +++ b/tones.c @@ -48,6 +48,7 @@ int open_tone(char *file, int *codec, signed int *length, signed int *left) int linksize; int l; char *p; + int ret; /* try to open the law file */ @@ -104,7 +105,7 @@ int open_tone(char *file, int *codec, signed int *length, signed int *left) SPRINT(filename, "%s.wav", file); if ((fh = open(filename, O_RDONLY)) >= 0) { /* get wave header */ - read(fh, buffer, 8); + ret = read(fh, buffer, 8); size=(buffer[4]) + (buffer[5]<<8) + (buffer[6]<<16) + (buffer[7]<<24); if (!!strncmp((char *)buffer, "RIFF", 4)) { close(fh); @@ -113,7 +114,7 @@ int open_tone(char *file, int *codec, signed int *length, signed int *left) return(-1); } // printf("%c%c%c%c size=%ld\n",buffer[0],buffer[1],buffer[2],buffer[3],size); - read(fh, buffer, 4); + ret = read(fh, buffer, 4); size -= 4; if (!!strncmp((char *)buffer, "WAVE", 4)) { close(fh); @@ -128,7 +129,7 @@ int open_tone(char *file, int *codec, signed int *length, signed int *left) PERROR("Remaining file size %ld not large enough for next chunk.\n",size); return(-1); } - read(fh, buffer, 8); + ret = read(fh, buffer, 8); chunk=(buffer[4]) + (buffer[5]<<8) + (buffer[6]<<16) + (buffer[7]<<24); size -= (8+chunk); // printf("%c%c%c%c length=%d\n",buffer[0],buffer[1],buffer[2],buffer[3],chunk); @@ -145,7 +146,7 @@ int open_tone(char *file, int *codec, signed int *length, signed int *left) PERROR("File %s Fmt chunk illegal size.\n", filename); return(-1); } - read(fh, buffer, chunk); + ret = read(fh, buffer, chunk); fmt = (struct fmt *)buffer; if (fmt->channels<1 || fmt->channels>2) { close(fh); @@ -211,11 +212,11 @@ int open_tone(char *file, int *codec, signed int *length, signed int *left) } else { // PDEBUG(DEBUG_PORT, "Unknown chunk '%c%c%c%c'\n",buffer[0],buffer[1],buffer[2],buffer[3]); while(chunk > sizeof(buffer)) { - read(fh, buffer, sizeof(buffer)); + ret = read(fh, buffer, sizeof(buffer)); chunk -= sizeof(buffer); } if (chunk) - read(fh, buffer, chunk); + ret = read(fh, buffer, chunk); } } diff --git a/trace.c b/trace.c index b8dc001..9d192da 100644 --- a/trace.c +++ b/trace.c @@ -264,6 +264,7 @@ void _end_trace(const char *__file, int __line) FILE *fp; struct admin_list *admin; struct admin_queue *response, **responsep; /* response pointer */ + int ret; if (!trace.name[0]) PERROR("trace not started in file %s line %d\n", __file, __line); @@ -278,7 +279,7 @@ void _end_trace(const char *__file, int __line) if (options.log[0]) { fp = fopen(options.log, "a"); if (fp) { - fwrite(string, strlen(string), 1, fp); + ret = fwrite(string, strlen(string), 1, fp); fclose(fp); } } -- cgit v1.2.3-55-g7522 From c4fcb0668c607cb0135444274ff62572cf6111c4 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Thu, 11 Mar 2010 16:27:28 +0100 Subject: Fixed includes to latest mISDNuser structures. modified: Makefile.am modified: Makefile.in modified: README modified: bchannel.c modified: dss1.cpp modified: mISDN.cpp modified: main.h --- Makefile.am | 2 +- Makefile.in | 2 +- README | 2 +- bchannel.c | 8 +++----- dss1.cpp | 2 +- mISDN.cpp | 12 ++++-------- main.h | 2 +- 7 files changed, 12 insertions(+), 18 deletions(-) diff --git a/Makefile.am b/Makefile.am index 2125468..b56560b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -95,7 +95,7 @@ install-exec-hook: $(INSTALL) chan_lcr.so $(astmoddir) endif -INCLUDES = $(all_includes) $(GSM_INCLUDE) $(SS5_INCLUDE) -Wall -I/usr/include/mISDNuser $(INSTALLATION_DEFINES) +INCLUDES = $(all_includes) $(GSM_INCLUDE) $(SS5_INCLUDE) -Wall $(INSTALLATION_DEFINES) lcr_SOURCES = $(GSM_SOURCE) $(SS5_SOURCE) select.c action.cpp mISDN.cpp tones.c \ action_efi.cpp crypt.cpp mail.c trace.c \ diff --git a/Makefile.in b/Makefile.in index e45b8a0..6bd502b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -260,7 +260,7 @@ INSTALLATION_DEFINES = \ @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 select.po -INCLUDES = $(all_includes) $(GSM_INCLUDE) $(SS5_INCLUDE) -Wall -I/usr/include/mISDNuser $(INSTALLATION_DEFINES) +INCLUDES = $(all_includes) $(GSM_INCLUDE) $(SS5_INCLUDE) -Wall $(INSTALLATION_DEFINES) 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 \ diff --git a/README b/README index e6bd449..12dd1f3 100644 --- a/README +++ b/README @@ -540,7 +540,7 @@ Changes after Version 1.7 - Fixed HLC (higher layer capability) modification to LCR routing. - Fixed chan_lcr fax queue buffer. Added LCR_TRANSFERCAPABILITY environment. - Fixed compiler warnings when compiling with gcc 4.3.4. - +- Fixed includes to latest mISDNuser structures. diff --git a/bchannel.c b/bchannel.c index b6107b6..f49572b 100644 --- a/bchannel.c +++ b/bchannel.c @@ -25,9 +25,9 @@ #include #include -#define AF_COMPATIBILITY_FUNC 1 -#define MISDN_OLD_AF_COMPATIBILITY 1 -#include +#include +int __af_isdn = MISDN_AF_ISDN; +#include #define HAVE_ATTRIBUTE_always_inline 1 #define HAVE_ARPA_INET_H 1 @@ -74,8 +74,6 @@ static void bchannel_send_queue(struct bchannel *bchannel); int bchannel_initialize(void) { - init_af_isdn(); - return 0; } diff --git a/dss1.cpp b/dss1.cpp index 3bcf410..d1430dc 100644 --- a/dss1.cpp +++ b/dss1.cpp @@ -15,7 +15,7 @@ //#include extern "C" { } -#include +#include extern unsigned int mt_assign_pid; #include "ie.cpp" diff --git a/mISDN.cpp b/mISDN.cpp index f5f8717..dc6be83 100644 --- a/mISDN.cpp +++ b/mISDN.cpp @@ -12,11 +12,9 @@ #include "main.h" #include "myisdn.h" -extern "C" { -#define MISDN_OLD_AF_COMPATIBILITY 1 -#include -} -#include +#include +int __af_isdn = MISDN_AF_ISDN; +#include #undef offsetof #ifdef __compiler_offsetof @@ -56,12 +54,10 @@ int mISDN_initialize(void) { char filename[256]; - init_af_isdn(); - /* try to open raw socket to check kernel */ mISDNsocket = socket(PF_ISDN, SOCK_RAW, ISDN_P_BASE); if (mISDNsocket < 0) { - fprintf(stderr, "Cannot open mISDN due to '%s'. (Does your Kernel support socket based mISDN?)\n", strerror(errno)); + fprintf(stderr, "Cannot open mISDN due to '%s'. (Does your Kernel support socket based mISDN? Protocol family is %d.)\n", strerror(errno), PF_ISDN); return(-1); } diff --git a/main.h b/main.h index 9b750e1..7f34911 100644 --- a/main.h +++ b/main.h @@ -131,7 +131,7 @@ void debug(const char *function, int line, const char *prefix, char *buffer); #ifdef __cplusplus extern "C" { #endif -#include +#include #ifdef __cplusplus } #endif -- cgit v1.2.3-55-g7522 From 2732c3ce40d8e0b3875b5a0c933c98f27c8cbae9 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Wed, 17 Mar 2010 08:31:07 +0100 Subject: Fixed output problems of error messages while parsing options.conf / gsm.conf. modified: Makefile.in modified: bchannel.c modified: chan_lcr.c modified: genext.c modified: gsm.cpp modified: gsm.h modified: gsm_conf.c modified: lcradmin.c modified: main.c modified: options.c modified: options.h --- Makefile.in | 8 ++++---- bchannel.c | 2 +- chan_lcr.c | 3 ++- genext.c | 3 ++- gsm.cpp | 11 +++++------ gsm.h | 3 +-- gsm_conf.c | 26 ++++++++++++-------------- lcradmin.c | 4 ++-- main.c | 3 ++- options.c | 36 ++++++++++++++++++------------------ options.h | 4 +--- 11 files changed, 50 insertions(+), 53 deletions(-) diff --git a/Makefile.in b/Makefile.in index 6bd502b..099f47c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -294,15 +294,15 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ - echo ' cd $(srcdir) && $(AUTOMAKE) --gnu '; \ - cd $(srcdir) && $(AUTOMAKE) --gnu \ + echo ' cd $(srcdir) && $(AUTOMAKE) --foreign '; \ + cd $(srcdir) && $(AUTOMAKE) --foreign \ && exit 0; \ exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ cd $(top_srcdir) && \ - $(AUTOMAKE) --gnu Makefile + $(AUTOMAKE) --foreign Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ diff --git a/bchannel.c b/bchannel.c index f49572b..baa8434 100644 --- a/bchannel.c +++ b/bchannel.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include int __af_isdn = MISDN_AF_ISDN; diff --git a/chan_lcr.c b/chan_lcr.c index 6a953a2..72bca9f 100644 --- a/chan_lcr.c +++ b/chan_lcr.c @@ -2748,13 +2748,14 @@ static int lcr_config_exec(struct ast_channel *ast, void *data, char **argv) int load_module(void) { u_short i; + char options_error[256]; for (i = 0; i < 256; i++) { flip_bits[i] = (i>>7) | ((i>>5)&2) | ((i>>3)&4) | ((i>>1)&8) | (i<<7) | ((i&2)<<5) | ((i&4)<<3) | ((i&8)<<1); } - if (read_options() == 0) { + if (read_options(options_error) == 0) { CERROR(NULL, NULL, "%s", options_error); #ifdef LCR_FOR_ASTERISK diff --git a/genext.c b/genext.c index 486af09..4d34bbe 100644 --- a/genext.c +++ b/genext.c @@ -52,8 +52,9 @@ int main(int argc, char *argv[]) struct extension ext; char pathname[256]; FILE *fp; + char options_error[256]; - if (!read_options()) { + if (!read_options(options_error)) { PERROR("%s", options_error); return(-1); } diff --git a/gsm.cpp b/gsm.cpp index b2bdd6b..b378df6 100644 --- a/gsm.cpp +++ b/gsm.cpp @@ -44,12 +44,9 @@ static struct timer_list db_sync_timer; #include "gsm_audio.h" -#undef AF_ISDN -#undef PF_ISDN -extern int AF_ISDN; -#define PF_ISDN AF_ISDN } +#include struct lcr_gsm *gsm = NULL; @@ -1607,6 +1604,8 @@ int gsm_init(void) char hlr[128], cfg[128], filename[128]; mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; int pcapfd, rc; + char conf_error[128] = ""; + debug_init(); tall_bsc_ctx = talloc_named_const(NULL, 1, "openbsc"); @@ -1632,8 +1631,8 @@ int gsm_init(void) gsm->gsm_sock = -1; /* parse options */ - if (!gsm_conf(&gsm->conf)) { - PERROR("%s", gsm_conf_error); + if (!gsm_conf(&gsm->conf, conf_error)) { + PERROR("%s", conf_error); return gsm_exit(-EINVAL); } diff --git a/gsm.h b/gsm.h index 6c09fa8..4959e00 100644 --- a/gsm.h +++ b/gsm.h @@ -76,8 +76,7 @@ class Pgsm : public PmISDN int message_epoint(unsigned int epoint_id, int message_id, union parameter *param); }; -extern char *gsm_conf_error; -int gsm_conf(struct gsm_conf *gsm_conf); +int gsm_conf(struct gsm_conf *gsm_conf, char *conf_error); int handle_gsm(void); int gsm_exit(int rc); int gsm_init(void); diff --git a/gsm_conf.c b/gsm_conf.c index 560d9b3..f5af15a 100644 --- a/gsm_conf.c +++ b/gsm_conf.c @@ -12,13 +12,11 @@ #include "main.h" -char *gsm_conf_error = (char *)""; - /* read options * * read options from options.conf */ -int gsm_conf(struct gsm_conf *gsm_conf) +int gsm_conf(struct gsm_conf *gsm_conf, char *conf_error) { FILE *fp=NULL; char filename[128]; @@ -42,7 +40,7 @@ int gsm_conf(struct gsm_conf *gsm_conf) SPRINT(filename, "%s/gsm.conf", CONFIG_DATA); if (!(fp=fopen(filename,"r"))) { - SPRINT(gsm_conf_error, "Cannot open %s\n",filename); + UPRINT(conf_error, "Cannot open %s\n",filename); return(0); } @@ -63,7 +61,7 @@ int gsm_conf(struct gsm_conf *gsm_conf) i=0; /* read option */ while(*p > 32) { if (i+1 >= sizeof(option)) { - SPRINT(gsm_conf_error, "Error in %s (line %d): option too long.\n",filename,line); + UPRINT(conf_error, "Error in %s (line %d): option too long.\n",filename,line); goto error; } option[i+1] = '\0'; @@ -82,7 +80,7 @@ int gsm_conf(struct gsm_conf *gsm_conf) i=0; /* read param */ while(*p > 32) { if (i+1 >= sizeof(params[pnum])) { - SPRINT(gsm_conf_error, "Error in %s (line %d): param too long.\n",filename,line); + UPRINT(conf_error, "Error in %s (line %d): param too long.\n",filename,line); goto error; } params[pnum][i+1] = '\0'; @@ -102,7 +100,7 @@ int gsm_conf(struct gsm_conf *gsm_conf) /* check option */ if (!strcmp(option,"debug")) { if (params[0][0]==0) { - SPRINT(gsm_conf_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line,option); + UPRINT(conf_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line,option); goto error; } SCPY(gsm_conf->debug, params[0]); @@ -110,7 +108,7 @@ int gsm_conf(struct gsm_conf *gsm_conf) } else if (!strcmp(option,"interface-bsc")) { if (params[0][0]==0) { - SPRINT(gsm_conf_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option); + UPRINT(conf_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option); goto error; } SCPY(gsm_conf->interface_bsc, params[0]); @@ -118,7 +116,7 @@ int gsm_conf(struct gsm_conf *gsm_conf) } else if (!strcmp(option,"interface-lcr")) { if (params[0][0]==0) { - SPRINT(gsm_conf_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option); + UPRINT(conf_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option); goto error; } SCPY(gsm_conf->interface_lcr, params[0]); @@ -126,7 +124,7 @@ int gsm_conf(struct gsm_conf *gsm_conf) } else if (!strcmp(option,"config")) { if (params[0][0]==0) { - SPRINT(gsm_conf_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option); + UPRINT(conf_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option); goto error; } SCPY(gsm_conf->openbsc_cfg, params[0]); @@ -134,14 +132,14 @@ int gsm_conf(struct gsm_conf *gsm_conf) } else if (!strcmp(option,"hlr")) { if (params[0][0]==0) { - SPRINT(gsm_conf_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option); + UPRINT(conf_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option); goto error; } SCPY(gsm_conf->hlr, params[0]); } else if (!strcmp(option,"reject-cause")) { - SPRINT(gsm_conf_error, "Option '%s' in gsm.conf has moved to openbsc.cfg", option); + UPRINT(conf_error, "Option '%s' in gsm.conf has moved to openbsc.cfg", option); goto error; } else if (!strcmp(option,"allow-all")) { @@ -156,12 +154,12 @@ int gsm_conf(struct gsm_conf *gsm_conf) } else if (!strcmp(option,"pcapfile")) { if (params[0][0]==0) { - SPRINT(gsm_conf_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option); + UPRINT(conf_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option); goto error; } SCPY(gsm_conf->pcapfile, params[0]); } else { - SPRINT(gsm_conf_error, "Error in %s (line %d): wrong option keyword %s.\n", filename,line,option); + UPRINT(conf_error, "Error in %s (line %d): wrong option keyword %s.\n", filename,line,option); goto error; } } diff --git a/lcradmin.c b/lcradmin.c index 0b6d627..c7691ee 100644 --- a/lcradmin.c +++ b/lcradmin.c @@ -1680,7 +1680,7 @@ int main(int argc, char *argv[]) int sock, conn; struct sockaddr_un sock_address; const char *ret = "invalid mode"; - + char options_error[256]; /* show options */ if (argc <= 1) { @@ -1756,7 +1756,7 @@ int main(int argc, char *argv[]) goto usage; } - if (read_options() == 0) { + if (read_options(options_error) == 0) { exit(EXIT_FAILURE); } diff --git a/main.c b/main.c index b425abe..9d7f834 100644 --- a/main.c +++ b/main.c @@ -174,6 +174,7 @@ int main(int argc, char *argv[]) created_lock = 0, created_signal = 0, created_debug = 0, created_misdn = 0; char tracetext[256], lock[128]; + char options_error[256]; #if 0 /* init fdset */ @@ -250,7 +251,7 @@ int main(int argc, char *argv[]) } /* read options */ - if (read_options() == 0) { + if (read_options(options_error) == 0) { PERROR("%s", options_error); goto free; } diff --git a/options.c b/options.c index eff38ce..1cadbe5 100644 --- a/options.c +++ b/options.c @@ -44,7 +44,7 @@ char options_error[256]; * * read options from options.conf */ -int read_options(void) +int read_options(char *options_error) { FILE *fp=NULL; char filename[128]; @@ -57,7 +57,7 @@ int read_options(void) SPRINT(filename, "%s/options.conf", CONFIG_DATA); if (!(fp=fopen(filename,"r"))) { - SPRINT(options_error, "Cannot open %s\n",filename); + UPRINT(options_error, "Cannot open %s\n",filename); return(0); } @@ -80,7 +80,7 @@ int read_options(void) i=0; /* read option */ while(*p > 32) { if (i+1 >= sizeof(option)) { - SPRINT(options_error, "Error in %s (line %d): option too long.\n",filename,line); + UPRINT(options_error, "Error in %s (line %d): option too long.\n",filename,line); goto error; } option[i+1] = '\0'; @@ -98,7 +98,7 @@ int read_options(void) i=0; /* read param */ while(*p > 31) { if (i+1 >= sizeof(param)) { - SPRINT(options_error, "Error in %s (line %d): param too long.\n",filename,line); + UPRINT(options_error, "Error in %s (line %d): param too long.\n",filename,line); goto error; } param[i+1] = '\0'; @@ -110,12 +110,12 @@ int read_options(void) /* check option */ if (!strcmp(option,"nt_if") || !strcmp(option,"te_if")) { - SPRINT(options_error, "Error in %s (line %d): obsolete option %s. Use multiple 'port' options to define ports to use.\n",filename,line,option); + UPRINT(options_error, "Error in %s (line %d): obsolete option %s. Use multiple 'port' options to define ports to use.\n",filename,line,option); goto error; } else if (!strcmp(option,"debug")) { if (param[0]==0) { - SPRINT(options_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line,option); + UPRINT(options_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line,option); goto error; } options.deb = strtol(param, NULL, 0); @@ -123,7 +123,7 @@ int read_options(void) } else if (!strcmp(option,"log")) { if (param[0]==0) { - SPRINT(options_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option); + UPRINT(options_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option); goto error; } SCPY(options.log, param); @@ -139,7 +139,7 @@ int read_options(void) } else if (!strcmp(option,"tones_dir")) { if (param[0]==0) { - SPRINT(options_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line,option); + UPRINT(options_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line,option); goto error; } if (param[strlen(param)-1] == '/') @@ -149,7 +149,7 @@ int read_options(void) } else if (!strcmp(option,"fetch_tones")) { if (param[0]==0) { - SPRINT(options_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line,option); + UPRINT(options_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line,option); goto error; } if (param[strlen(param)-1] == '/') @@ -173,24 +173,24 @@ int read_options(void) } else if (!strcmp(option,"dsptones")) { - SPRINT(options_error, "Error in %s (line %d): parameter 'dsptones' is obsolete. Just define the tones (american,german,oldgerman) at 'tones_dir' option.\n",filename,line,option); + UPRINT(options_error, "Error in %s (line %d): parameter 'dsptones' is obsolete. Just define the tones (american,german,oldgerman) at 'tones_dir' option.\n",filename,line); goto error; } else if (!strcmp(option,"schedule")) { options.schedule = atoi(param); if (options.schedule < 0) { - SPRINT(options_error, "Error in %s (line %d): parameter for option %s must be at least '0'.\n", filename,line,option); + UPRINT(options_error, "Error in %s (line %d): parameter for option %s must be at least '0'.\n", filename,line,option); goto error; } if (options.schedule > 99) { - SPRINT(options_error, "Error in %s (line %d): parameter for option %s must be '99' or less.\n", filename,line,option); + UPRINT(options_error, "Error in %s (line %d): parameter for option %s must be '99' or less.\n", filename,line,option); goto error; } } else if (!strcmp(option,"email")) { if (param[0]==0) { - SPRINT(options_error, "Error in %s (line %d): parameter for option %s missing.\n", filename,line,option); + UPRINT(options_error, "Error in %s (line %d): parameter for option %s missing.\n", filename,line,option); goto error; } SCPY(options.email, param); @@ -198,7 +198,7 @@ int read_options(void) } else if (!strcmp(option,"lock")) { if (param[0]==0) { - SPRINT(options_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line,option); + UPRINT(options_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line,option); goto error; } if (param[strlen(param)-1] == '/') @@ -212,7 +212,7 @@ int read_options(void) if (*endptr != '\0') { struct passwd * pwd = getpwnam(param); if (pwd == NULL) { - SPRINT(options_error, "Error in %s (line %d): no such user: %s.\n",filename,line,param); + UPRINT(options_error, "Error in %s (line %d): no such user: %s.\n",filename,line,param); goto error; } options.socketuser = pwd->pw_uid; @@ -224,7 +224,7 @@ int read_options(void) if (*endptr != '\0') { struct group * grp = getgrnam(param); if (grp == NULL) { - SPRINT(options_error, "Error in %s (line %d): no such group: %s.\n",filename,line,param); + UPRINT(options_error, "Error in %s (line %d): no such group: %s.\n",filename,line,param); goto error; } options.socketgroup = grp->gr_gid; @@ -236,13 +236,13 @@ int read_options(void) if (!strcmp(option,"gsm")) { options.gsm = 1; } else { - SPRINT(options_error, "Error in %s (line %d): wrong option keyword %s.\n", filename,line,option); + UPRINT(options_error, "Error in %s (line %d): wrong option keyword %s.\n", filename,line,option); goto error; } } if (!options.tones_dir[0]) { - SPRINT(options_error, "Error in %s (line %d): option 'tones_dir' with parameter missing.\n", filename); + UPRINT(options_error, "Error in %s (line %d): option 'tones_dir' with parameter missing.\n", filename,line); goto error; } if (fp) fclose(fp); diff --git a/options.h b/options.h index ecf8244..1a256e2 100644 --- a/options.h +++ b/options.h @@ -34,9 +34,7 @@ struct options { extern struct options options; -extern char options_error[256]; - -int read_options(void); +int read_options(char *options_error); #ifdef __cplusplus } -- cgit v1.2.3-55-g7522 From 882882e0e2f6c451c4b9a5aa8209aa60352049c9 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Wed, 17 Mar 2010 10:43:04 +0100 Subject: Added 'polling' option to options.conf. This is usefull to test if select loop causes problems and does not wake when it is required. If lcr seems not to wake up, try using 'polling' to disable select timer and use polling instead. --- default/options.conf | 3 +++ main.c | 6 +++++- options.c | 6 +++++- options.h | 1 + todo.txt | 2 +- 5 files changed, 15 insertions(+), 3 deletions(-) diff --git a/default/options.conf b/default/options.conf index 64d0f27..e0e93a0 100644 --- a/default/options.conf +++ b/default/options.conf @@ -117,3 +117,6 @@ # #gsm +# Enable polling in main loop. +# This feature is temporarily for test purpose. Don't enable it +#polling diff --git a/main.c b/main.c index 9d7f834..e2d3f13 100644 --- a/main.c +++ b/main.c @@ -460,7 +460,11 @@ int main(int argc, char *argv[]) usleep(10000); } #else - select_main(0, NULL, NULL, NULL); + if (options.polling) + if (!select_main(1, NULL, NULL, NULL)) + usleep(10000); + else + select_main(0, NULL, NULL, NULL); #endif } SPRINT(tracetext, "%s terminated", NAME); diff --git a/options.c b/options.c index 1cadbe5..88f6424 100644 --- a/options.c +++ b/options.c @@ -35,7 +35,8 @@ struct options options = { 0700, /* rights of lcr admin socket */ -1, /* socket user (-1= no change) */ -1, /* socket group (-1= no change) */ - 0 /* enable gsm */ + 0, /* enable gsm */ + 1 /* use polling of main loop */ }; char options_error[256]; @@ -235,6 +236,9 @@ int read_options(char *options_error) } else if (!strcmp(option,"gsm")) { options.gsm = 1; + } else + if (!strcmp(option,"polling")) { + options.polling = 1; } else { UPRINT(options_error, "Error in %s (line %d): wrong option keyword %s.\n", filename,line,option); goto error; diff --git a/options.h b/options.h index 1a256e2..c13ee2c 100644 --- a/options.h +++ b/options.h @@ -30,6 +30,7 @@ struct options { int socketuser; /* socket chown to this user */ int socketgroup; /* socket chgrp to this group */ int gsm; /* enable gsm support */ + int polling; }; extern struct options options; diff --git a/todo.txt b/todo.txt index c6b6993..896a0d0 100644 --- a/todo.txt +++ b/todo.txt @@ -15,5 +15,5 @@ doku: - neuen partyline-param dokumentieren - aufzeichnung der ansage mit 0 ohne beep beenden - gain, pipeline, crypt - +- polling -- cgit v1.2.3-55-g7522 From e664caf22f8d83f9b4f42cc3b98ea0e55ab9b090 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Thu, 18 Mar 2010 09:13:38 +0100 Subject: Fix NULL pointer audio frame problem. The problem occurred when IAX protocol sends silence frame. Thanx to Peter for finding the problem and providing patch. --- bchannel.c | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/bchannel.c b/bchannel.c index baa8434..5793795 100644 --- a/bchannel.c +++ b/bchannel.c @@ -418,26 +418,29 @@ void bchannel_transmit(struct bchannel *bchannel, unsigned char *data, int len) return; if (len > 1024 || len < 1) return; - switch(bchannel->b_mode) { - case 0: - for (i = 0; i < len; i++) - *p++ = flip_bits[*data++]; - frm->prim = DL_DATA_REQ; - break; - case 1: - for (i = 0; i < len; i++) - *p++ = flip_bits[*data++]; - frm->prim = PH_DATA_REQ; - break; - case 2: - memcpy(p, data, len); - frm->prim = DL_DATA_REQ; - break; - case 3: - memcpy(p, data, len); - frm->prim = PH_DATA_REQ; - break; - } + if (data) { + switch(bchannel->b_mode) { + case 0: + for (i = 0; i < len; i++) + *p++ = flip_bits[*data++]; + frm->prim = DL_DATA_REQ; + break; + case 1: + for (i = 0; i < len; i++) + *p++ = flip_bits[*data++]; + frm->prim = PH_DATA_REQ; + break; + case 2: + memcpy(p, data, len); + frm->prim = DL_DATA_REQ; + break; + case 3: + memcpy(p, data, len); + frm->prim = PH_DATA_REQ; + break; + } + } else + memset(p, flip_bits[(options.law=='a')?0x2a:0xff], len); frm->id = 0; #ifdef SEAMLESS_TEST unsigned char test_tone[8] = {0x2a, 0x24, 0xb4, 0x24, 0x2a, 0x25, 0xb5, 0x25}; -- cgit v1.2.3-55-g7522 From ea95ae63671c5330ece87b2986bfdfbd70d73814 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Thu, 18 Mar 2010 09:17:34 +0100 Subject: Update of README --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index 12dd1f3..91a00a5 100644 --- a/README +++ b/README @@ -541,7 +541,7 @@ Changes after Version 1.7 - Fixed chan_lcr fax queue buffer. Added LCR_TRANSFERCAPABILITY environment. - Fixed compiler warnings when compiling with gcc 4.3.4. - Fixed includes to latest mISDNuser structures. - +- Fix by Peter: NULL pointer issue in asterisk frame. -- cgit v1.2.3-55-g7522