[commit] r4823 - in freeswitch/branches/mikej/sofiasip-upgrade: . build libs/libdingaling/src libs/srtp src src/include src/mod src/mod/codecs/mod_g729 src/mod/endpoints/mod_dingaling src/mod/endpoints/mod_sofia src/mod/say/mod_say_en
Author: mikej Date: Sun Apr 1 15:42:32 2007 New Revision: 4823 Added: freeswitch/branches/mikej/sofiasip-upgrade/build/fixautomake.sh - copied unchanged from r4822, /freeswitch/trunk/build/fixautomake.sh freeswitch/branches/mikej/sofiasip-upgrade/build/turbo_build.sh - copied unchanged from r4822, /freeswitch/trunk/build/turbo_build.sh freeswitch/branches/mikej/sofiasip-upgrade/src/mod/endpoints/mod_sofia/mod_sofia.h - copied unchanged from r4822, /freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.h freeswitch/branches/mikej/sofiasip-upgrade/src/mod/endpoints/mod_sofia/sofia.c - copied unchanged from r4822, /freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia.c freeswitch/branches/mikej/sofiasip-upgrade/src/mod/endpoints/mod_sofia/sofia_glue.c - copied unchanged from r4822, /freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_glue.c freeswitch/branches/mikej/sofiasip-upgrade/src/mod/endpoints/mod_sofia/sofia_presence.c - copied unchanged from r4822, /freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_presence.c freeswitch/branches/mikej/sofiasip-upgrade/src/mod/endpoints/mod_sofia/sofia_reg.c - copied unchanged from r4822, /freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_reg.c Modified: freeswitch/branches/mikej/sofiasip-upgrade/Makefile.am freeswitch/branches/mikej/sofiasip-upgrade/bootstrap.sh freeswitch/branches/mikej/sofiasip-upgrade/build/modmake.rules.in freeswitch/branches/mikej/sofiasip-upgrade/configure.in freeswitch/branches/mikej/sofiasip-upgrade/libs/libdingaling/src/libdingaling.c freeswitch/branches/mikej/sofiasip-upgrade/libs/libdingaling/src/libdingaling.h freeswitch/branches/mikej/sofiasip-upgrade/libs/srtp/configure.in freeswitch/branches/mikej/sofiasip-upgrade/src/include/switch_channel.h freeswitch/branches/mikej/sofiasip-upgrade/src/include/switch_types.h freeswitch/branches/mikej/sofiasip-upgrade/src/include/switch_utils.h freeswitch/branches/mikej/sofiasip-upgrade/src/mod/Makefile.am freeswitch/branches/mikej/sofiasip-upgrade/src/mod/codecs/mod_g729/mod_g729.c freeswitch/branches/mikej/sofiasip-upgrade/src/mod/endpoints/mod_dingaling/Makefile freeswitch/branches/mikej/sofiasip-upgrade/src/mod/endpoints/mod_dingaling/mod_dingaling.c freeswitch/branches/mikej/sofiasip-upgrade/src/mod/endpoints/mod_sofia/Makefile freeswitch/branches/mikej/sofiasip-upgrade/src/mod/endpoints/mod_sofia/mod_sofia.c freeswitch/branches/mikej/sofiasip-upgrade/src/mod/endpoints/mod_sofia/mod_sofia.vcproj freeswitch/branches/mikej/sofiasip-upgrade/src/mod/say/mod_say_en/mod_say_en.c freeswitch/branches/mikej/sofiasip-upgrade/src/switch_channel.c freeswitch/branches/mikej/sofiasip-upgrade/src/switch_core.c freeswitch/branches/mikej/sofiasip-upgrade/src/switch_core_io.c freeswitch/branches/mikej/sofiasip-upgrade/src/switch_core_session.c freeswitch/branches/mikej/sofiasip-upgrade/src/switch_core_sqldb.c freeswitch/branches/mikej/sofiasip-upgrade/src/switch_event.c freeswitch/branches/mikej/sofiasip-upgrade/src/switch_ivr.c freeswitch/branches/mikej/sofiasip-upgrade/src/switch_ivr_async.c freeswitch/branches/mikej/sofiasip-upgrade/src/switch_ivr_bridge.c Log: merged changes from trunk revisions 4806-4822. Modified: freeswitch/branches/mikej/sofiasip-upgrade/Makefile.am ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/Makefile.am (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/Makefile.am Sun Apr 1 15:42:32 2007 @@ -10,13 +10,6 @@ BASE = $(switch_srcdir) OSARCH=`uname -s` -LIBTOOL=`if test -z "$(VERBOSE)" ; then echo $(SHELL) $(switch_builddir)/quiet_libtool ;else echo $(switch_builddir)/libtool; fi;` -#LIBS+=> core.log || error="yes";if test -n "$(VERBOSE)" -o "$$error" = "yes";then cat core.log;fi;if test "$$error" = "yes";then exit 1;fi - -LTINSTALL = $(LIBTOOL) --mode=install $(INSTALL) -TOUCH_TARGET=if test -f "$@" ; then touch "$@" ; fi ; -AM_MAKEFLAGS=`test -n "$(VERBOSE)" || echo -s` - if CRASHPROT AM_CFLAGS += -DCRASH_PROT endif @@ -147,15 +140,13 @@ touch .version src/include/switch_version.h: $(top_srcdir)/src/include/switch_version.h.in .version $(libfreeswitch_la_SOURCES) $(library_include_HEADERS) - @if test ! -f .noversion ; then \ - force=0 ; \ - version=`svnversion . -n || echo hacked` ; \ - oldversion=`cat .version 2>/dev/null || echo "0"` ; \ - test ! -f src/include/switch_version.h || grep "@SVN_VERSION@" src/include/switch_version.h && force=1 ; \ - if test "$$oldversion" != "$$version" || test $$force = 1 ; then \ - cat src/include/switch_version.h.in | sed "s/@SVN_VERSION@/$$version/g" > src/include/switch_version.h ; \ - echo $$version > .version ; \ - fi ; \ + @force=0 ; \ + version=`svnversion . -n || echo hacked` ; \ + oldversion=`cat .version 2>/dev/null || echo "0"` ; \ + test ! -f src/include/switch_version.h || grep "@SVN_VERSION@" src/include/switch_version.h && force=1 ; \ + if test "$$oldversion" != "$$version" || test $$force = 1 ; then \ + cat src/include/switch_version.h.in | sed "s/@SVN_VERSION@/$$version/g" > src/include/switch_version.h ; \ + echo $$version > .version ; \ fi ; update: Modified: freeswitch/branches/mikej/sofiasip-upgrade/bootstrap.sh ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/bootstrap.sh (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/bootstrap.sh Sun Apr 1 15:42:32 2007 @@ -68,8 +68,12 @@ IFS=.; set $lt_version; IFS=' ' lt_status="good" -if test "$1" -lt "2"; then - if test "$2" -lt "5" -o "$2" = "5" -a "$3" -lt "14" ; then +a=$[$1+0] +b=$[$2+0] +c=$[$3+0] + +if test "$a" -lt "2"; then + if test "$b" -lt "5" -o "$b" = "5" -a "$c" -lt "14" ; then lt_status="bad" fi else @@ -85,7 +89,6 @@ exit 1 fi - echo "Entering directory ${LIBDIR}/apr" cd ${LIBDIR}/apr Modified: freeswitch/branches/mikej/sofiasip-upgrade/build/modmake.rules.in ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/build/modmake.rules.in (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/build/modmake.rules.in Sun Apr 1 15:42:32 2007 @@ -9,7 +9,7 @@ SHELL=@SHELL@ INSTALL=@INSTALL@ GETLIB=@GETLIB@ -LIBTOOL=$(switch_builddir)/libtool +LIBTOOL=@LIBTOOL@ LTINSTALL=$(LIBTOOL) --mode=install $(INSTALL) LTUNINSTALL=$(LIBTOOL) --mode=uninstall rm -f CCLD = $(CC) @@ -46,7 +46,7 @@ CSOURCEFILE=$(MODNAME).c CXXSOURCEFILE=$(MODNAME).cpp -TOUCH_TARGET=if test -f "$@" ; then touch "$@" ; fi ; +TOUCH_TARGET=@TOUCH_TARGET@ #MAKE_OPTS = `if test -z "$(VERBOSE)" ; then $(MAKE) --help | grep silent | grep "\-s" 2>&1 >/dev/null && echo -s;fi` MAKE_OPTS = `test -n "$(VERBOSE)" || echo -s` Modified: freeswitch/branches/mikej/sofiasip-upgrade/configure.in ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/configure.in (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/configure.in Sun Apr 1 15:42:32 2007 @@ -327,6 +327,15 @@ AM_CONDITIONAL(ISMAC, [test `uname -s` = Darwin]) AM_CONDITIONAL(IS64BITLINUX, [test `uname -m` = x86_64]) +#some vars to sub into the Makefile.am's +#LIBS+=> core.log || error="yes";if test -n "$(VERBOSE)" -o "$$error" = "yes";then cat core.log;fi;if test "$$error" = "yes";then exit 1;fi +LIBTOOL='`if test -z "$(VERBOSE)" ; then echo $(SHELL) $(switch_builddir)/quiet_libtool ;else echo $(switch_builddir)/libtool; fi;`' +TOUCH_TARGET='if test -f "$@";then touch "$@";fi;' +AM_MAKEFLAGS='`test -n "$(VERBOSE)" || echo -s`' +AC_SUBST(LIBTOOL) +AC_SUBST(TOUCH_TARGET) +AC_SUBST(AM_MAKEFLAGS) + # Run configure in all the subdirs AC_CONFIG_SUBDIRS(libs/srtp) AC_CONFIG_SUBDIRS(libs/sqlite) Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/libdingaling/src/libdingaling.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/libdingaling/src/libdingaling.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/libdingaling/src/libdingaling.c Sun Apr 1 15:42:32 2007 @@ -761,6 +761,11 @@ from = buf; } + if (ldl_test_flag(handle, LDL_FLAG_COMPONENT) && ldl_jid_domcmp(from, to)) { + globals.logger(DL_LOG_ERR, "Refusal to send presence from and to the same domain in component mode [%s][%s]\n", from, to); + return; + } + if ((pres = iks_new("presence"))) { iks_insert_attrib(pres, "xmlns", "jabber:client"); if (from) { Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/libdingaling/src/libdingaling.h ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/libdingaling/src/libdingaling.h (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/libdingaling/src/libdingaling.h Sun Apr 1 15:42:32 2007 @@ -180,6 +180,55 @@ #define ldl_yield(ms) apr_sleep(ms * 10); apr_thread_yield(); /*! + \brief Test for a common domain in 2 jid + \param id_a the first id + \param id_b the second id + \return 1 if the domains match 0 if they dont or -1 if either id is invalid + \note the id may or may not contain a user and/or resource +*/ +static inline int ldl_jid_domcmp(char *id_a, char *id_b) +{ + char *id_a_host, *id_b_host, *id_a_r, *id_b_r; + + if ((id_a_host = strchr(id_a, '@'))) { + id_a_host++; + } else { + id_a_host = id_a; + } + + if ((id_b_host = strchr(id_b, '@'))) { + id_b_host++; + } else { + id_b_host = id_b; + } + + if (id_a_host && id_b_host) { + int id_a_len = 0, id_b_len = 0, len = 0; + + if ((id_a_r = strchr(id_a_host, '/'))) { + id_a_len = id_a_r - id_a_host; + } else { + id_a_len = strlen(id_a_host); + } + + if ((id_b_r = strchr(id_b_host, '/'))) { + id_b_len = id_b_r - id_b_host; + } else { + id_b_len = strlen(id_b_host); + } + + if (id_a_len > id_b_len) { + len = id_b_len; + } else { + len = id_a_len; + } + printf("[%s][%s][%d]\n", id_a_host, id_b_host, len); + return strncasecmp(id_a_host, id_b_host, len) ? 0 : 1; + } + return -1; +} + +/*! \brief Test for the existance of a flag on an arbitary object \param obj the object to test \param flag the or'd list of flags to test Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/srtp/configure.in ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/srtp/configure.in (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/srtp/configure.in Sun Apr 1 15:42:32 2007 @@ -134,7 +134,6 @@ AC_HEADER_STDC AC_CHECK_HEADERS(stdlib.h) AC_CHECK_HEADERS(unistd.h) -AC_CHECK_HEADERS(byteswap.h) AC_CHECK_HEADERS(stdint.h) AC_CHECK_HEADERS(sys/uio.h) AC_CHECK_HEADERS(inttypes.h) @@ -142,6 +141,18 @@ AC_CHECK_HEADERS(machine/types.h) AC_CHECK_HEADERS(sys/int_types.h) +AC_LINK_IFELSE(AC_LANG_PROGRAM([ +#include <inttypes.h> +#include <byteswap.h> +],[ +uint64_t y = 0x1122334455667788LL; +bswap_64(y); +]),byteswap_cv_bswap_64_usable=yes,byteswap_cv_bswap_64_usable=no) + +if test "x${byteswap_cv_bswap_64_usable}" = "xyes" ; then +AC_DEFINE([HAVE_BYTESWAP_H],1,[define if you have a usable bswap_64 in byteswap.h]) +fi + dnl socket() and friends AC_CHECK_HEADERS(sys/socket.h netinet/in.h arpa/inet.h) AC_CHECK_HEADERS(windows.h, [AC_CHECK_HEADERS(winsock2.h)]) Modified: freeswitch/branches/mikej/sofiasip-upgrade/src/include/switch_channel.h ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/src/include/switch_channel.h (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/src/include/switch_channel.h Sun Apr 1 15:42:32 2007 @@ -259,6 +259,22 @@ SWITCH_DECLARE(void) switch_channel_set_flag(switch_channel_t *channel, switch_channel_flag_t flags); /*! + \brief Set given flag(s) on a given channel's bridge partner + \param channel channel to derive the partner channel to set flag(s) on + \param flags or'd list of flags to set + \return true if the flag was set +*/ +SWITCH_DECLARE(switch_bool_t) switch_channel_set_flag_partner(switch_channel_t *channel, switch_channel_flag_t flags); + +/*! + \brief Clears given flag(s) on a given channel's bridge partner + \param channel channel to derive the partner channel to clear flag(s) from + \param flags the flags to clear + \return true if the flag was cleared +*/ +SWITCH_DECLARE(switch_bool_t) switch_channel_clear_flag_partner(switch_channel_t *channel, switch_channel_flag_t flags); + +/*! \brief Set given flag(s) on a given channel to be applied on the next state change \param channel channel on which to set flag(s) \param flags or'd list of flags to set Modified: freeswitch/branches/mikej/sofiasip-upgrade/src/include/switch_types.h ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/src/include/switch_types.h (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/src/include/switch_types.h Sun Apr 1 15:42:32 2007 @@ -96,6 +96,7 @@ #endif #define SWITCH_URL_SEPARATOR "://" #define SWITCH_ENDPOINT_DISPOSITION_VARIABLE "endpoint_disposition" +#define SWITCH_HOLD_MUSIC_VARIABLE "hold_music" #define SWITCH_EXPORT_VARS_VARIABLE "export_vars" #define SWITCH_R_SDP_VARIABLE "switch_r_sdp" #define SWITCH_L_SDP_VARIABLE "switch_l_sdp" @@ -168,6 +169,7 @@ SMF_ECHO_ALEG = (1 << 1), SMF_ECHO_BLEG = (1 << 2), SMF_FORCE = (1 << 3), + SMF_LOOP = (1 << 4) } switch_media_flag_t; typedef enum { @@ -529,6 +531,8 @@ CF_REPEAT_STATE = (1 << 16) - Tell the state machine to repeat a state CF_GEN_RINGBACK = (1 << 17) - Channel is generating it's own ringback CF_RING_READY = (1 << 18) - Channel is ready to send ringback +CF_BREAK = (1 << 19) - Channel should stop what it's doing +CF_BROADCAST = (1 << 20) - Channel is broadcasting </pre> */ @@ -551,7 +555,9 @@ CF_EVENT_PARSE = (1 << 15), CF_REPEAT_STATE = (1 << 16), CF_GEN_RINGBACK = (1 << 17), - CF_RING_READY = (1 << 18) + CF_RING_READY = (1 << 18), + CF_BREAK = (1 << 19), + CF_BROADCAST = (1 << 20) } switch_channel_flag_t; Modified: freeswitch/branches/mikej/sofiasip-upgrade/src/include/switch_utils.h ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/src/include/switch_utils.h (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/src/include/switch_utils.h Sun Apr 1 15:42:32 2007 @@ -180,6 +180,60 @@ */ #define switch_safe_free(it) if (it) {free(it);it=NULL;} + +/*! + \brief Test if one string is inside another with extra case checking + \param s the inner string + \param q the big string + \return SWITCH_TRUE or SWITCH_FALSE +*/ +static inline switch_bool_t switch_strstr(char *s, char *q) +{ + char *p, *S = NULL, *Q = NULL; + switch_bool_t tf = SWITCH_FALSE; + + if (strstr(s, q)) { + return SWITCH_TRUE; + } + + S = strdup(s); + + assert(S != NULL); + + for (p = S; p && *p; p++) { + *p = (char)toupper(*p); + } + + if (strstr(S, q)) { + tf = SWITCH_TRUE; + goto done; + } + + Q = strdup(q); + assert(Q != NULL); + + for (p = Q; p && *p; p++) { + *p = (char)toupper(*p); + } + + if (strstr(s, Q)) { + tf = SWITCH_TRUE; + goto done; + } + + if (strstr(S, Q)) { + tf = SWITCH_TRUE; + goto done; + } + + done: + switch_safe_free(S); + switch_safe_free(Q); + + return tf; +} + + /*! \brief Test for NULL or zero length string \param s the string to test Modified: freeswitch/branches/mikej/sofiasip-upgrade/src/mod/Makefile.am ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/src/mod/Makefile.am (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/src/mod/Makefile.am Sun Apr 1 15:42:32 2007 @@ -6,8 +6,6 @@ else our_clean_modules="$(MODULES)" ; fi ; MOD_NAME=`echo $$i | sed -e 's|^.*/||'` MOD_DIR=`if test -d $(switch_srcdir)/src/mod/$$i ; then echo $(switch_srcdir)/src/mod/$$i ; else echo $$i ; fi;` -AM_MAKEFLAGS = `test -n "$(VERBOSE)" || echo -s` -#AM_MAKEFLAGS = `if test -z "$(VERBOSE)" ; then $(MAKE) --help | grep silent | grep "\-s" 2>&1 >/dev/null && echo -s;fi` all: @$(CONF_MODULES) \ Modified: freeswitch/branches/mikej/sofiasip-upgrade/src/mod/codecs/mod_g729/mod_g729.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/src/mod/codecs/mod_g729/mod_g729.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/src/mod/codecs/mod_g729/mod_g729.c Sun Apr 1 15:42:32 2007 @@ -154,10 +154,9 @@ } - if (encoded_data_len % 2 == 0) { - - if (encoded_data_len % 12 == 0) { + + if (encoded_data_len == 2 || encoded_data_len % 12 == 0) { return SWITCH_STATUS_BREAK; //divisor = 12; //plen = 10; Modified: freeswitch/branches/mikej/sofiasip-upgrade/src/mod/endpoints/mod_dingaling/Makefile ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/src/mod/endpoints/mod_dingaling/Makefile (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/src/mod/endpoints/mod_dingaling/Makefile Sun Apr 1 15:42:32 2007 @@ -1,13 +1,20 @@ BASE=../../../.. -DING_DIR=$(BASE)/libs/libdingaling -DINGLA=$(DING_DIR)/libdingaling.la +LOCAL_CFLAGS = `$(BASE)/libs/apr/apr-1-config --cflags --cppflags --includes` +LOCAL_CFLAGS += `$(BASE)/libs/apr-util/apu-1-config --includes` -LOCAL_CFLAGS=-I$(DING_DIR)/src -LOCAL_LIBADD=$(DINGLA) +IKS_DIR=$(BASE)/libs/iksemel +IKS_LA=$(IKS_DIR)/src/libiksemel.la +DING_DIR=$(BASE)/libs/libdingaling +LOCAL_CFLAGS += -I$(DING_DIR)/src -I$(BASE)/libs/iksemel/include +LOCAL_OBJS=$(DING_DIR)/src/libdingaling.o $(DING_DIR)/src/sha1.o $(IKS_LA) include $(BASE)/build/modmake.rules -$(DINGLA): $(DING_DIR) $(DING_DIR)/.update - cd $(DING_DIR) && $(MAKE) - $(TOUCH_TARGET) +$(IKS_LA): $(IKS_DIR) $(IKS_DIR)/.update + @cd $(IKS_DIR) && $(MAKE) + @$(TOUCH_TARGET) + + + + Modified: freeswitch/branches/mikej/sofiasip-upgrade/src/mod/endpoints/mod_dingaling/mod_dingaling.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/src/mod/endpoints/mod_dingaling/mod_dingaling.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/src/mod/endpoints/mod_dingaling/mod_dingaling.c Sun Apr 1 15:42:32 2007 @@ -2167,28 +2167,31 @@ break; case LDL_SIGNAL_SUBSCRIBE: + if (profile->user_flags & LDL_FLAG_COMPONENT && ldl_jid_domcmp(from, to)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Attempt to add presence from/to our own domain [%s][%s]\n", from, to); + } else { + if ((sql = switch_mprintf("delete from subscriptions where sub_from='%q' and sub_to='%q';\n" + "insert into subscriptions values('%q','%q','%q','%q');\n", from, to, from, to, msg, subject))) { + execute_sql(profile->dbname, sql, profile->mutex); + switch_core_db_free(sql); + } - if ((sql = switch_mprintf("delete from subscriptions where sub_from='%q' and sub_to='%q';\n" - "insert into subscriptions values('%q','%q','%q','%q');\n", from, to, from, to, msg, subject))) { - execute_sql(profile->dbname, sql, profile->mutex); - switch_core_db_free(sql); - } - - if (is_special(to)) { - ldl_handle_send_presence(profile->handle, to, from, NULL, NULL, "Click To Call"); - } + if (is_special(to)) { + ldl_handle_send_presence(profile->handle, to, from, NULL, NULL, "Click To Call"); + } #if 0 - if (is_special(to)) { - if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) { - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", MDL_CHAT_PROTO); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->login); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s", to); - //switch_event_add_header(event, SWITCH_STACK_BOTTOM, "rpid", "unknown"); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "Click To Call"); - switch_event_fire(&event); + if (is_special(to)) { + if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) { + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", MDL_CHAT_PROTO); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->login); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s", to); + //switch_event_add_header(event, SWITCH_STACK_BOTTOM, "rpid", "unknown"); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "Click To Call"); + switch_event_fire(&event); + } } - } #endif + } break; case LDL_SIGNAL_ROSTER: if (switch_event_create(&event, SWITCH_EVENT_ROSTER) == SWITCH_STATUS_SUCCESS) { Modified: freeswitch/branches/mikej/sofiasip-upgrade/src/mod/endpoints/mod_sofia/Makefile ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/src/mod/endpoints/mod_sofia/Makefile (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/src/mod/endpoints/mod_sofia/Makefile Sun Apr 1 15:42:32 2007 @@ -12,6 +12,7 @@ LOCAL_CFLAGS += -I$(SOFIAUA_DIR)/soa -I$(SOFIAUA_DIR)/sresolv LOCAL_CFLAGS += -I$(SOFIAUA_DIR)/stun -I$(SOFIAUA_DIR)/su LOCAL_CFLAGS += -I$(SOFIAUA_DIR)/tport -I$(SOFIAUA_DIR)/url +LOCAL_OBJS=sofia.o sofia_glue.o sofia_presence.o sofia_reg.o SOFIALA=$(SOFIAUA_DIR)/libsofia-sip-ua.la Modified: freeswitch/branches/mikej/sofiasip-upgrade/src/mod/endpoints/mod_sofia/mod_sofia.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/src/mod/endpoints/mod_sofia/mod_sofia.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/src/mod/endpoints/mod_sofia/mod_sofia.c Sun Apr 1 15:42:32 2007 @@ -36,5745 +36,947 @@ /* Best viewed in a 160 x 60 VT100 Terminal or so the line below at least fits across your screen*/ /*************************************************************************************************************************************************************/ +#include "mod_sofia.h" -/*Defines etc..*/ -/*************************************************************************************************************************************************************/ -#define HAVE_APR -#include <switch.h> -static const switch_state_handler_table_t noop_state_handler = { 0 }; -struct outbound_reg; -typedef struct outbound_reg outbound_reg_t; - -struct sofia_profile; -typedef struct sofia_profile sofia_profile_t; -#define NUA_MAGIC_T sofia_profile_t - -struct sofia_private { - char uuid[SWITCH_UUID_FORMATTED_LENGTH + 1]; - outbound_reg_t *gateway; -}; - -typedef struct sofia_private sofia_private_t; - -struct private_object; -typedef struct private_object private_object_t; -#define NUA_HMAGIC_T sofia_private_t - -#define MY_EVENT_REGISTER "sofia::register" -#define MY_EVENT_EXPIRE "sofia::expire" -#define MULTICAST_EVENT "multicast::event" -#define SOFIA_REPLACES_HEADER "_sofia_replaces_" -#define SOFIA_USER_AGENT "FreeSWITCH(mod_sofia)" -#define SOFIA_CHAT_PROTO "sip" -#define SOFIA_SIP_HEADER_PREFIX "sip_h_" -#define SOFIA_SIP_HEADER_PREFIX_T "~sip_h_" -#define SOFIA_DEFAULT_PORT "5060" - -#include <sofia-sip/nua.h> -#include <sofia-sip/sip_status.h> -#include <sofia-sip/sdp.h> -#include <sofia-sip/sip_protos.h> -#include <sofia-sip/auth_module.h> -#include <sofia-sip/su_md5.h> -#include <sofia-sip/su_log.h> -#include <sofia-sip/nea.h> -#include <sofia-sip/msg_addr.h> - -extern su_log_t tport_log[]; +struct mod_sofia_globals mod_sofia_globals; static switch_frame_t silence_frame = { 0 }; static char silence_data[13] = ""; -static char reg_sql[] = - "CREATE TABLE sip_registrations (\n" - " user VARCHAR(255),\n" - " host VARCHAR(255),\n" - " contact VARCHAR(1024),\n" " status VARCHAR(255),\n" " rpid VARCHAR(255),\n" " expires INTEGER(8)" ");\n"; - - -static char sub_sql[] = - "CREATE TABLE sip_subscriptions (\n" - " proto VARCHAR(255),\n" - " user VARCHAR(255),\n" - " host VARCHAR(255),\n" - " sub_to_user VARCHAR(255),\n" - " sub_to_host VARCHAR(255),\n" - " event VARCHAR(255),\n" - " contact VARCHAR(1024),\n" - " call_id VARCHAR(255),\n" " full_from VARCHAR(255),\n" " full_via VARCHAR(255),\n" " expires INTEGER(8)" ");\n"; - - -static char auth_sql[] = - "CREATE TABLE sip_authentication (\n" - " user VARCHAR(255),\n" - " host VARCHAR(255),\n" " passwd VARCHAR(255),\n" " nonce VARCHAR(255),\n" " expires INTEGER(8)" - ");\n"; - -static const char modname[] = "mod_sofia"; #define STRLEN 15 static switch_memory_pool_t *module_pool = NULL; -#define set_param(ptr,val) if (ptr) {free(ptr) ; ptr = NULL;} if (val) {ptr = strdup(val);} -#define set_anchor(t,m) if (t->Anchor) {delete t->Anchor;} t->Anchor = new SipMessage(m); - - -/* Local Structures */ -/*************************************************************************************************************************************************************/ -struct sip_alias_node { - char *url; - nua_t *nua; - struct sip_alias_node *next; -}; - -typedef struct sip_alias_node sip_alias_node_t; - -typedef enum { - PFLAG_AUTH_CALLS = (1 << 0), - PFLAG_BLIND_REG = (1 << 1), - PFLAG_AUTH_ALL = (1 << 2), - PFLAG_FULL_ID = (1 << 3), - PFLAG_PRESENCE = (1 << 4), - PFLAG_PASS_RFC2833 = (1 << 5), - PFLAG_DISABLE_TRANSCODING = (1 << 6) -} PFLAGS; - -typedef enum { - TFLAG_IO = (1 << 0), - TFLAG_CHANGE_MEDIA = (1 << 1), - TFLAG_OUTBOUND = (1 << 2), - TFLAG_READING = (1 << 3), - TFLAG_WRITING = (1 << 4), - TFLAG_HUP = (1 << 5), - TFLAG_RTP = (1 << 6), - TFLAG_BYE = (1 << 7), - TFLAG_ANS = (1 << 8), - TFLAG_EARLY_MEDIA = (1 << 9), - TFLAG_SECURE = (1 << 10), - TFLAG_VAD_IN = (1 << 11), - TFLAG_VAD_OUT = (1 << 12), - TFLAG_VAD = (1 << 13), - TFLAG_TIMER = (1 << 14), - TFLAG_READY = (1 << 15), - TFLAG_REINVITE = (1 << 16), - TFLAG_REFER = (1 << 17), - TFLAG_NOHUP = (1 << 18), - TFLAG_XFER = (1 << 19), - TFLAG_NOMEDIA = (1 << 20), - TFLAG_BUGGY_2833 = (1 << 21), - TFLAG_SIP_HOLD = (1 << 22), - TFLAG_INB_NOMEDIA = (1 << 23), - TFLAG_LATE_NEGOTIATION = (1 << 24) -} TFLAGS; - -static struct { - switch_hash_t *profile_hash; - switch_hash_t *gateway_hash; - switch_mutex_t *hash_mutex; - uint32_t callid; - int32_t running; - switch_mutex_t *mutex; - char guess_ip[80]; -} globals; - -typedef enum { - REG_FLAG_AUTHED = (1 << 0), -} reg_flags_t; - -typedef enum { - REG_STATE_UNREGED, - REG_STATE_TRYING, - REG_STATE_REGISTER, - REG_STATE_REGED, - REG_STATE_FAILED, - REG_STATE_EXPIRED -} reg_state_t; - -struct outbound_reg { - sofia_private_t *sofia_private; - nua_handle_t *nh; - sofia_profile_t *profile; - char *name; - char *register_scheme; - char *register_realm; - char *register_username; - char *register_password; - char *register_from; - char *register_contact; - char *register_to; - char *register_proxy; - char *register_context; - char *expires_str; - uint32_t freq; - time_t expires; - time_t retry; - uint32_t flags; - reg_state_t state; - switch_memory_pool_t *pool; - struct outbound_reg *next; -}; - - -struct sofia_profile { - int debug; - char *name; - char *dbname; - char *dialplan; - char *context; - char *extrtpip; - char *rtpip; - char *sipip; - char *extsipip; - char *username; - char *url; - char *bindurl; - char *sipdomain; - char *timer_name; - int sip_port; - char *codec_string; - int running; - int codec_ms; - int dtmf_duration; - unsigned int flags; - unsigned int pflags; - uint32_t max_calls; - uint32_t nonce_ttl; - nua_t *nua; - switch_memory_pool_t *pool; - su_root_t *s_root; - sip_alias_node_t *aliases; - switch_payload_t te; - switch_payload_t cng_pt; - uint32_t codec_flags; - switch_mutex_t *ireg_mutex; - switch_mutex_t *gateway_mutex; - outbound_reg_t *gateways; - su_home_t *home; - switch_hash_t *profile_hash; - switch_hash_t *chat_hash; -}; - - -struct private_object { - sofia_private_t *sofia_private; - uint32_t flags; - switch_payload_t agreed_pt; - switch_core_session_t *session; - switch_frame_t read_frame; - char *codec_order[SWITCH_MAX_CODECS]; - int codec_order_last; - const switch_codec_implementation_t *codecs[SWITCH_MAX_CODECS]; - int num_codecs; - switch_codec_t read_codec; - switch_codec_t write_codec; - uint32_t codec_ms; - switch_caller_profile_t *caller_profile; - uint32_t timestamp_send; - //int32_t timestamp_recv; - switch_rtp_t *rtp_session; - int ssrc; - //switch_time_t last_read; - sofia_profile_t *profile; - char *local_sdp_audio_ip; - switch_port_t local_sdp_audio_port; - char *remote_sdp_audio_ip; - switch_port_t remote_sdp_audio_port; - char *adv_sdp_audio_ip; - switch_port_t adv_sdp_audio_port; - char *proxy_sdp_audio_ip; - switch_port_t proxy_sdp_audio_port; - char *from_uri; - char *to_uri; - char *from_address; - char *to_address; - char *callid; - char *far_end_contact; - char *contact_url; - char *from_str; - char *rm_encoding; - char *rm_fmtp; - char *fmtp_out; - char *remote_sdp_str; - char *local_sdp_str; - char *dest; - char *dest_to; - char *key; - char *xferto; - char *kick; - char *origin; - char *hash_key; - char *chat_from; - char *chat_to; - char *e_dest; - char *call_id; - unsigned long rm_rate; - switch_payload_t pt; - switch_mutex_t *flag_mutex; - switch_payload_t te; - switch_payload_t bte; - switch_payload_t cng_pt; - switch_payload_t bcng_pt; - nua_handle_t *nh; - nua_handle_t *nh2; - su_home_t *home; - sip_contact_t *contact; -}; - -/* Function Prototypes */ -/*************************************************************************************************************************************************************/ static switch_status_t sofia_on_init(switch_core_session_t *session); -static switch_status_t sofia_on_hangup(switch_core_session_t *session); static switch_status_t sofia_on_loopback(switch_core_session_t *session); - static switch_status_t sofia_on_transmit(switch_core_session_t *session); - static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session, switch_caller_profile_t *outbound_profile, switch_core_session_t **new_session, switch_memory_pool_t **pool); - static switch_status_t sofia_read_frame(switch_core_session_t *session, switch_frame_t **frame, int timeout, switch_io_flag_t flags, int stream_id); - static switch_status_t sofia_write_frame(switch_core_session_t *session, switch_frame_t *frame, int timeout, switch_io_flag_t flags, int stream_id); - -static switch_status_t config_sofia(int reload); - static switch_status_t sofia_kill_channel(switch_core_session_t *session, int sig); -static switch_status_t activate_rtp(private_object_t * tech_pvt); - -static void deactivate_rtp(private_object_t * tech_pvt); - -static void set_local_sdp(private_object_t * tech_pvt, char *ip, uint32_t port, char *sr, int force); - -static void tech_set_codecs(private_object_t * tech_pvt); -static void attach_private(switch_core_session_t *session, sofia_profile_t * profile, private_object_t * tech_pvt, const char *channame); - -static void terminate_session(switch_core_session_t **session, switch_call_cause_t cause, int line); - -static switch_status_t tech_choose_port(private_object_t * tech_pvt); - -static switch_status_t do_invite(switch_core_session_t *session); - -static uint8_t negotiate_sdp(switch_core_session_t *session, sdp_session_t * sdp); - -static char *get_auth_data(char *dbname, char *nonce, char *npassword, size_t len, switch_mutex_t * mutex); - -static void establish_presence(sofia_profile_t * profile); - -static void sip_i_state(int status, - char const *phrase, - nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]); - - -static void sip_i_refer(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, switch_core_session_t *session, sip_t const *sip, tagi_t tags[]); - -static void sip_i_info(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, switch_core_session_t *session, sip_t const *sip, tagi_t tags[]); +/* BODY OF THE MODULE */ +/*************************************************************************************************************************************************************/ -static void sip_i_invite(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]); -static void sip_i_register(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]); +/* + State methods they get called when the state changes to the specific state + returning SWITCH_STATUS_SUCCESS tells the core to execute the standard state method next + so if you fully implement the state you can return SWITCH_STATUS_FALSE to skip it. +*/ +static switch_status_t sofia_on_init(switch_core_session_t *session) +{ + private_object_t *tech_pvt; + switch_channel_t *channel = NULL; -static void event_callback(nua_event_t event, - int status, - char const *phrase, - nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]); + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + tech_pvt = (private_object_t *) switch_core_session_get_private(session); + assert(tech_pvt != NULL); -static void *SWITCH_THREAD_FUNC profile_thread_run(switch_thread_t * thread, void *obj); + tech_pvt->read_frame.buflen = SWITCH_RTP_MAX_BUF_LEN; -static void launch_profile_thread(sofia_profile_t * profile); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SOFIA INIT\n"); + if (switch_channel_test_flag(channel, CF_NOMEDIA)) { + switch_set_flag_locked(tech_pvt, TFLAG_NOMEDIA); + sofia_glue_tech_absorb_sdp(tech_pvt); + } -static switch_status_t chat_send(char *proto, char *from, char *to, char *subject, char *body, char *hint); + if (switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) { + if (sofia_glue_do_invite(session) != SWITCH_STATUS_SUCCESS) { + return SWITCH_STATUS_FALSE; + } + } -/* BODY OF THE MODULE */ -/*************************************************************************************************************************************************************/ + /* Move Channel's State Machine to RING */ + switch_channel_set_state(channel, CS_RING); + return SWITCH_STATUS_SUCCESS; +} -typedef enum { - AUTH_OK, - AUTH_FORBIDDEN, - AUTH_STALE, -} auth_res_t; +static switch_status_t sofia_on_ring(switch_core_session_t *session) +{ + switch_channel_t *channel = NULL; + private_object_t *tech_pvt = NULL; + channel = switch_core_session_get_channel(session); + assert(channel != NULL); -static sofia_profile_t *find_profile(char *key) -{ - static sofia_profile_t *profile; + tech_pvt = (private_object_t *) switch_core_session_get_private(session); + assert(tech_pvt != NULL); - switch_mutex_lock(globals.hash_mutex); - profile = (sofia_profile_t *) switch_core_hash_find(globals.profile_hash, key); - switch_mutex_unlock(globals.hash_mutex); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SOFIA RING\n"); - return profile; + return SWITCH_STATUS_SUCCESS; } -static void add_profile(char *key, sofia_profile_t * profile) -{ - switch_mutex_lock(globals.hash_mutex); - switch_core_hash_insert(globals.profile_hash, key, profile); - switch_mutex_unlock(globals.hash_mutex); -} -static outbound_reg_t *find_gateway(char *key) +static switch_status_t sofia_on_execute(switch_core_session_t *session) { - outbound_reg_t *gateway; + switch_channel_t *channel = NULL; + private_object_t *tech_pvt = NULL; - switch_mutex_lock(globals.hash_mutex); - gateway = (outbound_reg_t *) switch_core_hash_find(globals.gateway_hash, key); - switch_mutex_unlock(globals.hash_mutex); + channel = switch_core_session_get_channel(session); + assert(channel != NULL); - return gateway; -} + tech_pvt = (private_object_t *) switch_core_session_get_private(session); + assert(tech_pvt != NULL); -static void add_gateway(char *key, outbound_reg_t * gateway) -{ - switch_mutex_lock(globals.hash_mutex); - switch_core_hash_insert(globals.gateway_hash, key, gateway); - switch_mutex_unlock(globals.hash_mutex); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SOFIA EXECUTE\n"); + + return SWITCH_STATUS_SUCCESS; } -static char *get_url_from_contact(char *buf, uint8_t to_dup) +// map QSIG cause codes to SIP from RFC4497 section 8.4.1 +static int hangup_cause_to_sip(switch_call_cause_t cause) { - char *url = NULL, *e; - - if ((url = strchr(buf, '<')) && (e = strchr(url, '>'))) { - url++; - if (to_dup) { - url = strdup(url); - e = strchr(url, '>'); - } - - *e = '\0'; + switch (cause) { + case SWITCH_CAUSE_NO_ROUTE_TRANSIT_NET: + case SWITCH_CAUSE_NO_ROUTE_DESTINATION: + return 404; + case SWITCH_CAUSE_USER_BUSY: + return 486; + case SWITCH_CAUSE_NO_USER_RESPONSE: + return 408; + case SWITCH_CAUSE_NO_ANSWER: + return 480; + case SWITCH_CAUSE_SUBSCRIBER_ABSENT: + return 480; + case SWITCH_CAUSE_CALL_REJECTED: + return 603; + case SWITCH_CAUSE_NUMBER_CHANGED: + case SWITCH_CAUSE_REDIRECTION_TO_NEW_DESTINATION: + return 410; + case SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER: + return 502; + case SWITCH_CAUSE_INVALID_NUMBER_FORMAT: + return 484; + case SWITCH_CAUSE_FACILITY_REJECTED: + return 501; + case SWITCH_CAUSE_NORMAL_UNSPECIFIED: + return 480; + case SWITCH_CAUSE_REQUESTED_CHAN_UNAVAIL: + case SWITCH_CAUSE_NORMAL_CIRCUIT_CONGESTION: + case SWITCH_CAUSE_NETWORK_OUT_OF_ORDER: + case SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE: + case SWITCH_CAUSE_SWITCH_CONGESTION: + return 503; + case SWITCH_CAUSE_OUTGOING_CALL_BARRED: + case SWITCH_CAUSE_INCOMING_CALL_BARRED: + case SWITCH_CAUSE_BEARERCAPABILITY_NOTAUTH: + return 403; + case SWITCH_CAUSE_BEARERCAPABILITY_NOTAVAIL: + return 503; + case SWITCH_CAUSE_BEARERCAPABILITY_NOTIMPL: + return 488; + case SWITCH_CAUSE_FACILITY_NOT_IMPLEMENTED: + case SWITCH_CAUSE_SERVICE_NOT_IMPLEMENTED: + return 501; + case SWITCH_CAUSE_INCOMPATIBLE_DESTINATION: + return 503; + case SWITCH_CAUSE_RECOVERY_ON_TIMER_EXPIRE: + return 504; + case SWITCH_CAUSE_ORIGINATOR_CANCEL: + return 487; + default: + return 480; } - return url; } - -static auth_res_t parse_auth(sofia_profile_t * profile, sip_authorization_t const *authorization, const char *regstr, char *np, size_t nplen) +switch_status_t sofia_on_hangup(switch_core_session_t *session) { - int indexnum; - const char *cur; - su_md5_t ctx; - char uridigest[2 * SU_MD5_DIGEST_SIZE + 1]; - char bigdigest[2 * SU_MD5_DIGEST_SIZE + 1]; - char *nonce, *uri, *qop, *cnonce, *nc, *response, *input = NULL, *input2 = NULL; - auth_res_t ret = AUTH_FORBIDDEN; - char *npassword = NULL; - int cnt = 0; - nonce = uri = qop = cnonce = nc = response = NULL; - - if (authorization->au_params) { - for (indexnum = 0; (cur = authorization->au_params[indexnum]); indexnum++) { - char *var, *val, *p, *work; - var = val = work = NULL; - if ((work = strdup(cur))) { - var = work; - if ((val = strchr(var, '='))) { - *val++ = '\0'; - while (*val == '"') { - *val++ = '\0'; - } - if ((p = strchr(val, '"'))) { - *p = '\0'; - } + switch_core_session_t *a_session; + private_object_t *tech_pvt; + switch_channel_t *channel = NULL; + switch_call_cause_t cause; + int sip_cause; - if (!strcasecmp(var, "nonce")) { - nonce = strdup(val); - cnt++; - } else if (!strcasecmp(var, "uri")) { - uri = strdup(val); - cnt++; - } else if (!strcasecmp(var, "qop")) { - qop = strdup(val); - cnt++; - } else if (!strcasecmp(var, "cnonce")) { - cnonce = strdup(val); - cnt++; - } else if (!strcasecmp(var, "response")) { - response = strdup(val); - cnt++; - } else if (!strcasecmp(var, "nc")) { - nc = strdup(val); - cnt++; - } - } + channel = switch_core_session_get_channel(session); + assert(channel != NULL); - free(work); - } - } - } + tech_pvt = (private_object_t *) switch_core_session_get_private(session); + assert(tech_pvt != NULL); - if (cnt != 6) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Authorization header!\n"); - goto end; - } + cause = switch_channel_get_cause(channel); + sip_cause = hangup_cause_to_sip(cause); - if (switch_strlen_zero(np)) { - if (!get_auth_data(profile->dbname, nonce, np, nplen, profile->ireg_mutex)) { - ret = AUTH_STALE; - goto end; - } - } + sofia_glue_deactivate_rtp(tech_pvt); - npassword = np; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Channel %s hanging up, cause: %s\n", + switch_channel_get_name(channel), switch_channel_cause2str(cause)); - if ((input = switch_mprintf("%s:%q", regstr, uri))) { - su_md5_init(&ctx); - su_md5_strupdate(&ctx, input); - su_md5_hexdigest(&ctx, uridigest); - su_md5_deinit(&ctx); + if (tech_pvt->hash_key) { + switch_core_hash_delete(tech_pvt->profile->chat_hash, tech_pvt->hash_key); } - if ((input2 = switch_mprintf("%q:%q:%q:%q:%q:%q", npassword, nonce, nc, cnonce, qop, uridigest))) { - memset(&ctx, 0, sizeof(ctx)); - su_md5_init(&ctx); - su_md5_strupdate(&ctx, input2); - su_md5_hexdigest(&ctx, bigdigest); - su_md5_deinit(&ctx); + if (tech_pvt->kick && (a_session = switch_core_session_locate(tech_pvt->kick))) { + switch_channel_t *a_channel = switch_core_session_get_channel(a_session); + switch_channel_hangup(a_channel, switch_channel_get_cause(channel)); + switch_core_session_rwunlock(a_session); + } - if (!strcasecmp(bigdigest, response)) { - ret = AUTH_OK; - } else { - ret = AUTH_FORBIDDEN; + if (tech_pvt->nh) { + if (!switch_test_flag(tech_pvt, TFLAG_BYE)) { + if (switch_test_flag(tech_pvt, TFLAG_ANS)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sending BYE to %s\n", switch_channel_get_name(channel)); + nua_bye(tech_pvt->nh, TAG_END()); + } else { + if (!switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Responding to INVITE with: %d\n", sip_cause); + nua_respond(tech_pvt->nh, sip_cause, NULL, TAG_END()); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sending CANCEL to %s\n", switch_channel_get_name(channel)); + nua_cancel(tech_pvt->nh, TAG_END()); + } + } + switch_set_flag_locked(tech_pvt, TFLAG_BYE); } } - end: - switch_safe_free(input); - switch_safe_free(input2); - switch_safe_free(nonce); - switch_safe_free(uri); - switch_safe_free(qop); - switch_safe_free(cnonce); - switch_safe_free(nc); - switch_safe_free(response); - - return ret; - -} - - -static void execute_sql(char *dbname, char *sql, switch_mutex_t * mutex) -{ - switch_core_db_t *db; + switch_clear_flag_locked(tech_pvt, TFLAG_IO); - if (mutex) { - switch_mutex_lock(mutex); + if (tech_pvt->home) { + su_home_unref(tech_pvt->home); + tech_pvt->home = NULL; } - if (!(db = switch_core_db_open_file(dbname))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", dbname); - goto end; + if (tech_pvt->sofia_private) { + *tech_pvt->sofia_private->uuid = '\0'; } - switch_core_db_persistant_execute(db, sql, 25); - switch_core_db_close(db); - end: - if (mutex) { - switch_mutex_unlock(mutex); - } + return SWITCH_STATUS_SUCCESS; } - -struct callback_t { - char *val; - switch_size_t len; - int matches; -}; - -static int find_callback(void *pArg, int argc, char **argv, char **columnNames) +static switch_status_t sofia_on_loopback(switch_core_session_t *session) { - struct callback_t *cbt = (struct callback_t *) pArg; - - switch_copy_string(cbt->val, argv[0], cbt->len); - cbt->matches++; - return 0; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SOFIA LOOPBACK\n"); + return SWITCH_STATUS_SUCCESS; } -static int del_callback(void *pArg, int argc, char **argv, char **columnNames) +static switch_status_t sofia_on_transmit(switch_core_session_t *session) { - switch_event_t *s_event; - - if (argc >= 3) { - if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_EXPIRE) == SWITCH_STATUS_SUCCESS) { - switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "profile-name", "%s", argv[0]); - switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "user", "%s", argv[1]); - switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "host", "%s", argv[2]); - switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "contact", "%s", argv[3]); - switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "expires", "%s", argv[4]); - switch_event_fire(&s_event); - } - } - return 0; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SOFIA TRANSMIT\n"); + return SWITCH_STATUS_SUCCESS; } -static void check_expire(switch_core_db_t *db, sofia_profile_t * profile, time_t now) +static switch_status_t sofia_answer_channel(switch_core_session_t *session) { - char sql[1024]; - char *errmsg; + private_object_t *tech_pvt; + switch_channel_t *channel = NULL; + switch_status_t status; - if (!db) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname); - return; - } + assert(session != NULL); - switch_mutex_lock(profile->ireg_mutex); - snprintf(sql, sizeof(sql), "select '%s',* from sip_registrations where expires > 0 and expires < %ld", profile->name, (long) now); - switch_core_db_exec(db, sql, del_callback, NULL, &errmsg); - - if (errmsg) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQL ERR [%s][%s]\n", sql, errmsg); - switch_safe_free(errmsg); - errmsg = NULL; - } + channel = switch_core_session_get_channel(session); + assert(channel != NULL); - snprintf(sql, sizeof(sql), "delete from sip_registrations where expires > 0 and expires < %ld", (long) now); - switch_core_db_persistant_execute(db, sql, 1000); - snprintf(sql, sizeof(sql), "delete from sip_authentication where expires > 0 and expires < %ld", (long) now); - switch_core_db_persistant_execute(db, sql, 1000); - snprintf(sql, sizeof(sql), "delete from sip_subscriptions where expires > 0 and expires < %ld", (long) now); - switch_core_db_persistant_execute(db, sql, 1000); + tech_pvt = (private_object_t *) switch_core_session_get_private(session); + assert(tech_pvt != NULL); - switch_mutex_unlock(profile->ireg_mutex); + if (!switch_test_flag(tech_pvt, TFLAG_ANS) && !switch_channel_test_flag(channel, CF_OUTBOUND)) { + switch_set_flag_locked(tech_pvt, TFLAG_ANS); -} + if (switch_channel_test_flag(channel, CF_NOMEDIA)) { + char *sdp = NULL; + switch_set_flag_locked(tech_pvt, TFLAG_NOMEDIA); + if ((sdp = switch_channel_get_variable(channel, SWITCH_B_SDP_VARIABLE))) { + tech_pvt->local_sdp_str = switch_core_session_strdup(session, sdp); + } + } else { + if (switch_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION)) { + char *r_sdp = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE); + if (sofia_glue_tech_media(tech_pvt, r_sdp) != SWITCH_STATUS_SUCCESS) { + switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "CODEC NEGOTIATION ERROR"); + nua_respond(tech_pvt->nh, SIP_488_NOT_ACCEPTABLE, TAG_END()); + return SWITCH_STATUS_FALSE; + } + switch_clear_flag_locked(tech_pvt, TFLAG_LATE_NEGOTIATION); + } -static char *find_reg_url(sofia_profile_t * profile, const char *user, const char *host, char *val, switch_size_t len) -{ - char *errmsg; - struct callback_t cbt = { 0 }; - switch_core_db_t *db; - - if (!user) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Called with null user!\n"); - return NULL; - } - - if (!(db = switch_core_db_open_file(profile->dbname))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname); - return NULL; - } - - cbt.val = val; - cbt.len = len; - switch_mutex_lock(profile->ireg_mutex); - if (host) { - snprintf(val, len, "select contact from sip_registrations where user='%s' and host='%s'", user, host); - } else { - snprintf(val, len, "select contact from sip_registrations where user='%s'", user); - } + if ((status = sofia_glue_tech_choose_port(tech_pvt)) != SWITCH_STATUS_SUCCESS) { + return status; + } - switch_core_db_exec(db, val, find_callback, &cbt, &errmsg); + sofia_glue_set_local_sdp(tech_pvt, NULL, 0, NULL, 0); + sofia_glue_activate_rtp(tech_pvt); - if (errmsg) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQL ERR [%s][%s]\n", val, errmsg); - switch_safe_free(errmsg); - errmsg = NULL; + if (tech_pvt->nh) { + if (tech_pvt->local_sdp_str) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Local SDP %s:\n%s\n", switch_channel_get_name(channel), + tech_pvt->local_sdp_str); + } + } + } + nua_respond(tech_pvt->nh, SIP_200_OK, + SIPTAG_CONTACT_STR(tech_pvt->profile->url), + SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str), SOATAG_AUDIO_AUX("cn telephone-event"), NUTAG_INCLUDE_EXTRA_SDP(1), TAG_END()); } - switch_mutex_unlock(profile->ireg_mutex); - - switch_core_db_close(db); - if (cbt.matches) { - return val; - } else { - return NULL; - } + return SWITCH_STATUS_SUCCESS; } -static void set_local_sdp(private_object_t * tech_pvt, char *ip, uint32_t port, char *sr, int force) +static switch_status_t sofia_read_frame(switch_core_session_t *session, switch_frame_t **frame, int timeout, switch_io_flag_t flags, int stream_id) { - char buf[2048]; - switch_time_t now = switch_time_now(); - int ptime = 0; - int rate = 0; + private_object_t *tech_pvt = NULL; + switch_channel_t *channel = NULL; + int payload = 0; - if (!force && !ip && !sr && switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) { - return; - } + channel = switch_core_session_get_channel(session); + assert(channel != NULL); - if (!ip) { - if (!(ip = tech_pvt->adv_sdp_audio_ip)) { - ip = tech_pvt->proxy_sdp_audio_ip; - } - } - if (!port) { - if (!(port = tech_pvt->adv_sdp_audio_port)) { - port = tech_pvt->proxy_sdp_audio_port; - } - } - if (!sr) { - sr = "sendrecv"; + tech_pvt = (private_object_t *) switch_core_session_get_private(session); + assert(tech_pvt != NULL); + + if (switch_test_flag(tech_pvt, TFLAG_HUP)) { + return SWITCH_STATUS_FALSE; } - snprintf(buf, sizeof(buf), - "v=0\n" - "o=FreeSWITCH %d%" SWITCH_TIME_T_FMT " %d%" SWITCH_TIME_T_FMT " IN IP4 %s\n" - "s=FreeSWITCH\n" "c=IN IP4 %s\n" "t=0 0\n" "a=%s\n" "m=audio %d RTP/AVP", port, now, port, now, ip, ip, sr, port); - - if (tech_pvt->rm_encoding) { - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %d", tech_pvt->pt); - } else if (tech_pvt->num_codecs) { - int i; - for (i = 0; i < tech_pvt->num_codecs; i++) { - const switch_codec_implementation_t *imp = tech_pvt->codecs[i]; - - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %d", imp->ianacode); - if (!ptime) { - ptime = imp->microseconds_per_frame / 1000; - } + while (!(tech_pvt->read_codec.implementation && switch_rtp_ready(tech_pvt->rtp_session))) { + if (switch_channel_ready(channel)) { + switch_yield(10000); + } else { + return SWITCH_STATUS_GENERR; } } - if (tech_pvt->te > 95) { - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %d", tech_pvt->te); - } - if (tech_pvt->cng_pt) { - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %d", tech_pvt->cng_pt); + tech_pvt->read_frame.datalen = 0; + switch_set_flag_locked(tech_pvt, TFLAG_READING); + +#if 0 + if (tech_pvt->last_read) { + elapsed = (unsigned int) ((switch_time_now() - tech_pvt->last_read) / 1000); + if (elapsed > 60000) { + return SWITCH_STATUS_TIMEOUT; + } } +#endif - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "\n"); - if (tech_pvt->rm_encoding) { - rate = tech_pvt->rm_rate; - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=rtpmap:%d %s/%ld\n", tech_pvt->pt, tech_pvt->rm_encoding, tech_pvt->rm_rate); - if (tech_pvt->fmtp_out) { - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=fmtp:%d %s\n", tech_pvt->pt, tech_pvt->fmtp_out); - } - if (tech_pvt->read_codec.implementation && !ptime) { - ptime = tech_pvt->read_codec.implementation->microseconds_per_frame / 1000; + if (switch_test_flag(tech_pvt, TFLAG_IO)) { + switch_status_t status; + + if (!switch_test_flag(tech_pvt, TFLAG_RTP)) { + return SWITCH_STATUS_GENERR; } - } else if (tech_pvt->num_codecs) { - int i; - for (i = 0; i < tech_pvt->num_codecs; i++) { - const switch_codec_implementation_t *imp = tech_pvt->codecs[i]; - uint32_t rfc_3551_sucks = imp->samples_per_second; + assert(tech_pvt->rtp_session != NULL); + tech_pvt->read_frame.datalen = 0; - if (!rate) { - rate = imp->samples_per_second; - } - if (ptime && ptime != imp->microseconds_per_frame / 1000) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "ptime %u != advertised ptime %u\n", imp->microseconds_per_frame / 1000, ptime); - } - if (rfc_3551_sucks && imp->ianacode == 9) { - rfc_3551_sucks = 8000; - } + while (switch_test_flag(tech_pvt, TFLAG_IO) && tech_pvt->read_frame.datalen == 0) { + tech_pvt->read_frame.flags = SFF_NONE; - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=rtpmap:%d %s/%d\n", imp->ianacode, imp->iananame, rfc_3551_sucks); - if (imp->fmtp) { - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=fmtp:%d %s\n", imp->ianacode, imp->fmtp); + status = switch_rtp_zerocopy_read_frame(tech_pvt->rtp_session, &tech_pvt->read_frame); + if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) { + return SWITCH_STATUS_FALSE; } - } - } - - if (tech_pvt->te > 95) { - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=rtpmap:%d telephone-event/8000\na=fmtp:%d 0-16\n", tech_pvt->te, tech_pvt->te); - } - if (tech_pvt->cng_pt) { - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=rtpmap:%d CN/%d\n", tech_pvt->cng_pt, rate); - if (!tech_pvt->rm_encoding) { - tech_pvt->cng_pt = 0; - } - } - if (ptime) { - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=ptime:%d\n", ptime); - } - tech_pvt->local_sdp_str = switch_core_session_strdup(tech_pvt->session, buf); -} -static void tech_set_codecs(private_object_t * tech_pvt) -{ - switch_channel_t *channel; - char *abs, *codec_string = NULL; - char *ocodec = NULL; - if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) { - return; - } + payload = tech_pvt->read_frame.payload; - if (tech_pvt->num_codecs) { - return; - } +#if 0 + elapsed = (unsigned int) ((switch_time_now() - started) / 1000); - assert(tech_pvt->session != NULL); + if (timeout > -1) { + if (elapsed >= (unsigned int) timeout) { + return SWITCH_STATUS_BREAK; + } + } - channel = switch_core_session_get_channel(tech_pvt->session); - assert(channel != NULL); + elapsed = (unsigned int) ((switch_time_now() - last_act) / 1000); + if (elapsed >= hard_timeout) { + return SWITCH_STATUS_BREAK; + } +#endif + if (switch_rtp_has_dtmf(tech_pvt->rtp_session)) { + char dtmf[128]; + switch_rtp_dequeue_dtmf(tech_pvt->rtp_session, dtmf, sizeof(dtmf)); + switch_channel_queue_dtmf(channel, dtmf); + } - if ((abs = switch_channel_get_variable(channel, "absolute_codec_string"))) { - codec_string = abs; - } else { - if (!(codec_string = switch_channel_get_variable(channel, "codec_string"))) { - if (tech_pvt->profile->codec_string) { - codec_string = tech_pvt->profile->codec_string; - } - } + if (tech_pvt->read_frame.datalen > 0) { + size_t bytes = 0; + int frames = 1; - if ((ocodec = switch_channel_get_variable(channel, SWITCH_ORIGINATOR_CODEC_VARIABLE))) { - if (!codec_string || (tech_pvt->profile->pflags & PFLAG_DISABLE_TRANSCODING)) { - codec_string = ocodec; - } else { - if (!(codec_string = switch_core_session_sprintf(tech_pvt->session, "%s,%s", ocodec, codec_string))) { - codec_string = ocodec; + if (!switch_test_flag((&tech_pvt->read_frame), SFF_CNG)) { + if ((bytes = tech_pvt->read_codec.implementation->encoded_bytes_per_frame)) { + frames = (tech_pvt->read_frame.datalen / bytes); + } + tech_pvt->read_frame.samples = (int) (frames * tech_pvt->read_codec.implementation->samples_per_frame); } + break; } } } - if (codec_string) { - char *tmp_codec_string; - if ((tmp_codec_string = switch_core_session_strdup(tech_pvt->session, codec_string))) { - tech_pvt->codec_order_last = switch_separate_string(tmp_codec_string, ',', tech_pvt->codec_order, SWITCH_MAX_CODECS); - tech_pvt->num_codecs = - switch_loadable_module_get_codecs_sorted(tech_pvt->codecs, SWITCH_MAX_CODECS, tech_pvt->codec_order, tech_pvt->codec_order_last); - } - } else { - tech_pvt->num_codecs = - switch_loadable_module_get_codecs(switch_core_session_get_pool(tech_pvt->session), tech_pvt->codecs, - sizeof(tech_pvt->codecs) / sizeof(tech_pvt->codecs[0])); + switch_clear_flag_locked(tech_pvt, TFLAG_READING); + + if (tech_pvt->read_frame.datalen == 0) { + *frame = NULL; + return SWITCH_STATUS_GENERR; } + *frame = &tech_pvt->read_frame; + + return SWITCH_STATUS_SUCCESS; } -static void attach_private(switch_core_session_t *session, sofia_profile_t * profile, private_object_t * tech_pvt, const char *channame) +static switch_status_t sofia_write_frame(switch_core_session_t *session, switch_frame_t *frame, int timeout, switch_io_flag_t flags, int stream_id) { - switch_channel_t *channel; - char name[256]; - - assert(session != NULL); - assert(profile != NULL); - assert(tech_pvt != NULL); + private_object_t *tech_pvt; + switch_channel_t *channel = NULL; + switch_status_t status = SWITCH_STATUS_SUCCESS; + int bytes = 0, samples = 0, frames = 0; - switch_core_session_add_stream(session, NULL); channel = switch_core_session_get_channel(session); + assert(channel != NULL); - //switch_channel_set_flag(channel, CF_ACCEPT_CNG); + tech_pvt = (private_object_t *) switch_core_session_get_private(session); + assert(tech_pvt != NULL); - switch_mutex_init(&tech_pvt->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session)); - switch_mutex_lock(tech_pvt->flag_mutex); - tech_pvt->flags = profile->flags; - switch_mutex_unlock(tech_pvt->flag_mutex); - tech_pvt->profile = profile; - if (tech_pvt->bte) { - tech_pvt->te = tech_pvt->bte; - } else if (!tech_pvt->te) { - tech_pvt->te = profile->te; + while (!(tech_pvt->read_codec.implementation && switch_rtp_ready(tech_pvt->rtp_session))) { + if (switch_channel_ready(channel)) { + switch_yield(10000); + } else { + return SWITCH_STATUS_GENERR; + } } - if (tech_pvt->bcng_pt) { - tech_pvt->cng_pt = tech_pvt->bcng_pt; - } else if (!tech_pvt->cng_pt) { - tech_pvt->cng_pt = profile->cng_pt; + if (switch_test_flag(tech_pvt, TFLAG_HUP)) { + return SWITCH_STATUS_FALSE; } - tech_pvt->session = session; - tech_pvt->home = su_home_new(sizeof(*tech_pvt->home)); + if (!switch_test_flag(tech_pvt, TFLAG_RTP)) { + return SWITCH_STATUS_GENERR; + } - switch_core_session_set_private(session, tech_pvt); + if (!switch_test_flag(tech_pvt, TFLAG_IO)) { + return SWITCH_STATUS_SUCCESS; + } + switch_set_flag_locked(tech_pvt, TFLAG_WRITING); - snprintf(name, sizeof(name), "sofia/%s/%s", profile->name, channame); - switch_channel_set_name(channel, name); - //tech_set_codecs(tech_pvt); + if (!switch_test_flag(frame, SFF_CNG)) { + if (tech_pvt->read_codec.implementation->encoded_bytes_per_frame) { + bytes = tech_pvt->read_codec.implementation->encoded_bytes_per_frame; + frames = ((int) frame->datalen / bytes); + } else + frames = 1; -} + samples = frames * tech_pvt->read_codec.implementation->samples_per_frame; + } +#if 0 + printf("%s %s->%s send %d bytes %d samples in %d frames ts=%d\n", + switch_channel_get_name(channel), + tech_pvt->local_sdp_audio_ip, tech_pvt->remote_sdp_audio_ip, frame->datalen, samples, frames, tech_pvt->timestamp_send); +#endif -static void terminate_session(switch_core_session_t **session, switch_call_cause_t cause, int line) -{ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Term called from line: %d\n", line); - if (*session) { - switch_channel_t *channel = switch_core_session_get_channel(*session); - struct private_object *tech_pvt = NULL; - unsigned running = switch_core_session_running(*session); - tech_pvt = switch_core_session_get_private(*session); + tech_pvt->timestamp_send += samples; + //switch_rtp_write_frame(tech_pvt->rtp_session, frame, tech_pvt->timestamp_send); + switch_rtp_write_frame(tech_pvt->rtp_session, frame, 0); - if (running) { - switch_channel_hangup(channel, cause); - } else { - if (tech_pvt) { - sofia_on_hangup(*session); - } - if (session && *session) { - switch_core_session_destroy(session); - } - } - } + switch_clear_flag_locked(tech_pvt, TFLAG_WRITING); + return status; } -static switch_status_t sofia_ext_address_lookup(char **ip, switch_port_t *port, char *sourceip, switch_memory_pool_t *pool) +static switch_status_t sofia_kill_channel(switch_core_session_t *session, int sig) { - char *error; + private_object_t *tech_pvt; + switch_channel_t *channel = NULL; - if (!sourceip) { - return SWITCH_STATUS_FALSE; - } + channel = switch_core_session_get_channel(session); + assert(channel != NULL); - if (!strncasecmp(sourceip, "stun:", 5)) { - char *stun_ip = sourceip + 5; - if (!stun_ip) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Stun Failed! NO STUN SERVER\n"); - return SWITCH_STATUS_FALSE; + tech_pvt = (private_object_t *) switch_core_session_get_private(session); + assert(tech_pvt != NULL); + + + switch (sig) { + case SWITCH_SIG_BREAK: + if (switch_rtp_ready(tech_pvt->rtp_session)) { + switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_BREAK); } - if (switch_stun_lookup(ip, port, stun_ip, SWITCH_STUN_DEFAULT_PORT, &error, pool) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Stun Failed! %s:%d [%s]\n", stun_ip, SWITCH_STUN_DEFAULT_PORT, error); - return SWITCH_STATUS_FALSE; + break; + case SWITCH_SIG_KILL: + default: + switch_clear_flag_locked(tech_pvt, TFLAG_IO); + switch_set_flag_locked(tech_pvt, TFLAG_HUP); + + if (switch_rtp_ready(tech_pvt->rtp_session)) { + switch_rtp_kill_socket(tech_pvt->rtp_session); } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Stun Success [%s]:[%d]\n", *ip, *port); - } else { - *ip = sourceip; + break; } + return SWITCH_STATUS_SUCCESS; -} +} -static switch_status_t tech_choose_port(private_object_t * tech_pvt) +static switch_status_t sofia_waitfor_read(switch_core_session_t *session, int ms, int stream_id) { - char *ip = tech_pvt->profile->rtpip; - switch_channel_t *channel; - switch_port_t sdp_port; - char tmp[50]; - - channel = switch_core_session_get_channel(tech_pvt->session); - - if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA) || tech_pvt->adv_sdp_audio_port) { - return SWITCH_STATUS_SUCCESS; - } - - tech_pvt->local_sdp_audio_ip = ip; - tech_pvt->local_sdp_audio_port = switch_rtp_request_port(); - sdp_port = tech_pvt->local_sdp_audio_port; - - if (tech_pvt->profile->extrtpip) { - if (sofia_ext_address_lookup(&ip, &sdp_port, tech_pvt->profile->extrtpip, switch_core_session_get_pool(tech_pvt->session)) != - SWITCH_STATUS_SUCCESS) { - terminate_session(&tech_pvt->session, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__); - return SWITCH_STATUS_FALSE; - } - } - - tech_pvt->adv_sdp_audio_ip = switch_core_session_strdup(tech_pvt->session, ip); - tech_pvt->adv_sdp_audio_port = sdp_port; + private_object_t *tech_pvt; + switch_channel_t *channel = NULL; - snprintf(tmp, sizeof(tmp), "%d", sdp_port); - switch_channel_set_variable(channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE, tech_pvt->adv_sdp_audio_ip); - switch_channel_set_variable(channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE, tmp); + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + tech_pvt = (private_object_t *) switch_core_session_get_private(session); + assert(tech_pvt != NULL); return SWITCH_STATUS_SUCCESS; } -static switch_status_t do_invite(switch_core_session_t *session) + +static switch_status_t sofia_waitfor_write(switch_core_session_t *session, int ms, int stream_id) { - char rpid[1024] = { 0 }; - char alert_info[1024] = { 0 }; - char max_forwards[8] = { 0 }; - char *alertbuf; - char *forwardbuf; - int forwardval; private_object_t *tech_pvt; switch_channel_t *channel = NULL; - switch_caller_profile_t *caller_profile; - char *cid_name, *cid_num; - char *e_dest = NULL; - const char *holdstr = ""; - switch_stream_handle_t stream = { 0 }; - switch_hash_index_t *hi; - void *vval; - char *extra_headers = NULL; - const void *vvar; - switch_status_t status = SWITCH_STATUS_FALSE; - char *rep; channel = switch_core_session_get_channel(session); assert(channel != NULL); - rep = switch_channel_get_variable(channel, SOFIA_REPLACES_HEADER); - tech_pvt = (private_object_t *) switch_core_session_get_private(session); assert(tech_pvt != NULL); - caller_profile = switch_channel_get_caller_profile(channel); - - cid_name = (char *) caller_profile->caller_id_name; - cid_num = (char *) caller_profile->caller_id_number; - tech_set_codecs(tech_pvt); - - if (!tech_pvt->from_str) { - tech_pvt->from_str = switch_core_session_sprintf(tech_pvt->session, "\"%s\" <sip:%s@%s>", - cid_name, - cid_num, tech_pvt->profile->extsipip ? tech_pvt->profile->extsipip : tech_pvt->profile->sipip); - - } + return SWITCH_STATUS_SUCCESS; - if (!tech_pvt->from_str) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n"); - return SWITCH_STATUS_FALSE; - } +} +static switch_status_t sofia_send_dtmf(switch_core_session_t *session, char *digits) +{ + private_object_t *tech_pvt; + tech_pvt = (private_object_t *) switch_core_session_get_private(session); + assert(tech_pvt != NULL); + return switch_rtp_queue_rfc2833(tech_pvt->rtp_session, + digits, tech_pvt->profile->dtmf_duration * (tech_pvt->read_codec.implementation->samples_per_second / 1000)); - if ((alertbuf = switch_channel_get_variable(channel, "alert_info"))) { - snprintf(alert_info, sizeof(alert_info) - 1, "Alert-Info: %s", alertbuf); - } +} - if ((forwardbuf = switch_channel_get_variable(channel, SWITCH_MAX_FORWARDS_VARIABLE))) { - forwardval = atoi(forwardbuf) - 1; - snprintf(max_forwards, sizeof(max_forwards) - 1, "%d", forwardval); - } +static switch_status_t sofia_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg) +{ + switch_channel_t *channel; + private_object_t *tech_pvt; + switch_status_t status; - if (tech_choose_port(tech_pvt) != SWITCH_STATUS_SUCCESS) { - return status; - } + channel = switch_core_session_get_channel(session); + assert(channel != NULL); - set_local_sdp(tech_pvt, NULL, 0, NULL, 0); + tech_pvt = (private_object_t *) switch_core_session_get_private(session); + assert(tech_pvt != NULL); - switch_set_flag_locked(tech_pvt, TFLAG_READY); - // forge a RPID for now KHR -- Should wrap this in an if statement so it can be turned on and off - if (switch_test_flag(caller_profile, SWITCH_CPF_SCREEN)) { - const char *priv = "off"; - const char *screen = "no"; - if (switch_test_flag(caller_profile, SWITCH_CPF_HIDE_NAME)) { - priv = "name"; - if (switch_test_flag(caller_profile, SWITCH_CPF_HIDE_NUMBER)) { - priv = "yes"; - } - } else if (switch_test_flag(caller_profile, SWITCH_CPF_HIDE_NUMBER)) { - priv = "yes"; - } - if (switch_test_flag(caller_profile, SWITCH_CPF_SCREEN)) { - screen = "yes"; - } - - snprintf(rpid, sizeof(rpid) - 1, "Remote-Party-ID: %s;party=calling;screen=%s;privacy=%s", tech_pvt->from_str, screen, priv); - - } - - if (!tech_pvt->nh) { - char *url = get_url_from_contact(tech_pvt->dest, 1); - tech_pvt->nh = nua_handle(tech_pvt->profile->nua, NULL, - NUTAG_URL(url), - SIPTAG_TO_STR(tech_pvt->dest_to), SIPTAG_FROM_STR(tech_pvt->from_str), SIPTAG_CONTACT_STR(tech_pvt->profile->url), - TAG_END()); - switch_safe_free(url); - - if (!(tech_pvt->sofia_private = malloc(sizeof(*tech_pvt->sofia_private)))) { - abort(); - } - memset(tech_pvt->sofia_private, 0, sizeof(*tech_pvt->sofia_private)); - switch_copy_string(tech_pvt->sofia_private->uuid, switch_core_session_get_uuid(session), sizeof(tech_pvt->sofia_private->uuid)); - nua_handle_bind(tech_pvt->nh, tech_pvt->sofia_private); - - } - - - if (tech_pvt->e_dest && (e_dest = strdup(tech_pvt->e_dest))) { - char *user = e_dest, *host = NULL; - char hash_key[256] = ""; - - if ((host = strchr(user, '@'))) { - *host++ = '\0'; - } - snprintf(hash_key, sizeof(hash_key), "%s%s%s", user, host, cid_num); - - tech_pvt->chat_from = tech_pvt->from_str; - tech_pvt->chat_to = tech_pvt->dest; - tech_pvt->hash_key = switch_core_session_strdup(tech_pvt->session, hash_key); - switch_core_hash_insert(tech_pvt->profile->chat_hash, tech_pvt->hash_key, tech_pvt); - free(e_dest); - } - - holdstr = switch_test_flag(tech_pvt, TFLAG_SIP_HOLD) ? "*" : ""; - - - SWITCH_STANDARD_STREAM(stream); - for (hi = switch_channel_variable_first(channel, switch_core_session_get_pool(tech_pvt->session)); hi; hi = switch_hash_next(hi)) { - switch_hash_this(hi, &vvar, NULL, &vval); - if (vvar && vval) { - const char *name = vvar; - char *value = (char *) vval; - - if (!strncasecmp(name, SOFIA_SIP_HEADER_PREFIX, strlen(SOFIA_SIP_HEADER_PREFIX))) { - const char *hname = name + strlen(SOFIA_SIP_HEADER_PREFIX); - stream.write_function(&stream, "%s: %s\r\n", hname, value); - } - } - } - - if (stream.data) { - extra_headers = stream.data; - } - - nua_invite(tech_pvt->nh, - TAG_IF(!switch_strlen_zero(rpid), SIPTAG_HEADER_STR(rpid)), - TAG_IF(!switch_strlen_zero(alert_info), SIPTAG_HEADER_STR(alert_info)), - TAG_IF(!switch_strlen_zero(extra_headers), SIPTAG_HEADER_STR(extra_headers)), - TAG_IF(!switch_strlen_zero(max_forwards), SIPTAG_MAX_FORWARDS_STR(max_forwards)), - //SIPTAG_CONTACT_STR(tech_pvt->profile->url), - SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str), - SOATAG_RTP_SORT(SOA_RTP_SORT_REMOTE), - SOATAG_RTP_SELECT(SOA_RTP_SELECT_ALL), TAG_IF(rep, SIPTAG_REPLACES_STR(rep)), SOATAG_HOLD(holdstr), TAG_END()); - - switch_safe_free(stream.data); - - return SWITCH_STATUS_SUCCESS; - -} - - - -static void do_xfer_invite(switch_core_session_t *session) -{ - char rpid[1024]; - private_object_t *tech_pvt; - switch_channel_t *channel = NULL; - switch_caller_profile_t *caller_profile; - - channel = switch_core_session_get_channel(session); - assert(channel != NULL); - - tech_pvt = (private_object_t *) switch_core_session_get_private(session); - assert(tech_pvt != NULL); - - caller_profile = switch_channel_get_caller_profile(channel); - - - - if ((tech_pvt->from_str = switch_core_session_sprintf(session, "\"%s\" <sip:%s@%s>", - (char *) caller_profile->caller_id_name, - (char *) caller_profile->caller_id_number, - tech_pvt->profile->extsipip ? tech_pvt->profile->extsipip : tech_pvt->profile->sipip))) { - - char *rep = switch_channel_get_variable(channel, SOFIA_REPLACES_HEADER); - - tech_pvt->nh2 = nua_handle(tech_pvt->profile->nua, NULL, - SIPTAG_TO_STR(tech_pvt->dest), SIPTAG_FROM_STR(tech_pvt->from_str), SIPTAG_CONTACT_STR(tech_pvt->profile->url), - TAG_END()); - - - nua_handle_bind(tech_pvt->nh2, tech_pvt->sofia_private); - - nua_invite(tech_pvt->nh2, - TAG_IF(rpid, SIPTAG_HEADER_STR(rpid)), - SIPTAG_CONTACT_STR(tech_pvt->profile->url), - SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str), - SOATAG_RTP_SORT(SOA_RTP_SORT_REMOTE), SOATAG_RTP_SELECT(SOA_RTP_SELECT_ALL), TAG_IF(rep, SIPTAG_REPLACES_STR(rep)), TAG_END()); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n"); - } - -} - -static void tech_absorb_sdp(private_object_t * tech_pvt) -{ - switch_channel_t *channel; - char *sdp_str; - - channel = switch_core_session_get_channel(tech_pvt->session); - assert(channel != NULL); - - if ((sdp_str = switch_channel_get_variable(channel, SWITCH_B_SDP_VARIABLE))) { - sdp_parser_t *parser; - sdp_session_t *sdp; - sdp_media_t *m; - sdp_connection_t *connection; - - if ((parser = sdp_parse(tech_pvt->home, sdp_str, (int) strlen(sdp_str), 0))) { - if ((sdp = sdp_session(parser))) { - for (m = sdp->sdp_media; m; m = m->m_next) { - if (m->m_type != sdp_media_audio) { - continue; - } - - connection = sdp->sdp_connection; - if (m->m_connections) { - connection = m->m_connections; - } - - if (connection) { - tech_pvt->proxy_sdp_audio_ip = switch_core_session_strdup(tech_pvt->session, connection->c_address); - } - tech_pvt->proxy_sdp_audio_port = (switch_port_t) m->m_port; - if (tech_pvt->proxy_sdp_audio_ip && tech_pvt->proxy_sdp_audio_port) { - break; - } - } - } - sdp_parser_free(parser); - } - tech_pvt->local_sdp_str = switch_core_session_strdup(tech_pvt->session, sdp_str); - } -} - -/* - State methods they get called when the state changes to the specific state - returning SWITCH_STATUS_SUCCESS tells the core to execute the standard state method next - so if you fully implement the state you can return SWITCH_STATUS_FALSE to skip it. -*/ -static switch_status_t sofia_on_init(switch_core_session_t *session) -{ - private_object_t *tech_pvt; - switch_channel_t *channel = NULL; - - channel = switch_core_session_get_channel(session); - assert(channel != NULL); - - tech_pvt = (private_object_t *) switch_core_session_get_private(session); - assert(tech_pvt != NULL); - - tech_pvt->read_frame.buflen = SWITCH_RTP_MAX_BUF_LEN; - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SOFIA INIT\n"); - if (switch_channel_test_flag(channel, CF_NOMEDIA)) { - switch_set_flag_locked(tech_pvt, TFLAG_NOMEDIA); - tech_absorb_sdp(tech_pvt); - } - - if (switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) { - if (do_invite(session) != SWITCH_STATUS_SUCCESS) { - return SWITCH_STATUS_FALSE; - } - } - - /* Move Channel's State Machine to RING */ - switch_channel_set_state(channel, CS_RING); - return SWITCH_STATUS_SUCCESS; -} - -static switch_status_t sofia_on_ring(switch_core_session_t *session) -{ - switch_channel_t *channel = NULL; - private_object_t *tech_pvt = NULL; - - channel = switch_core_session_get_channel(session); - assert(channel != NULL); - - tech_pvt = (private_object_t *) switch_core_session_get_private(session); - assert(tech_pvt != NULL); - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SOFIA RING\n"); - - return SWITCH_STATUS_SUCCESS; -} - - -static switch_status_t sofia_on_execute(switch_core_session_t *session) -{ - switch_channel_t *channel = NULL; - private_object_t *tech_pvt = NULL; - - channel = switch_core_session_get_channel(session); - assert(channel != NULL); - - tech_pvt = (private_object_t *) switch_core_session_get_private(session); - assert(tech_pvt != NULL); - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SOFIA EXECUTE\n"); - - return SWITCH_STATUS_SUCCESS; -} - -// map QSIG cause codes to SIP from RFC4497 section 8.4.1 -static int hangup_cause_to_sip(switch_call_cause_t cause) -{ - switch (cause) { - case SWITCH_CAUSE_NO_ROUTE_TRANSIT_NET: - case SWITCH_CAUSE_NO_ROUTE_DESTINATION: - return 404; - case SWITCH_CAUSE_USER_BUSY: - return 486; - case SWITCH_CAUSE_NO_USER_RESPONSE: - return 408; - case SWITCH_CAUSE_NO_ANSWER: - return 480; - case SWITCH_CAUSE_SUBSCRIBER_ABSENT: - return 480; - case SWITCH_CAUSE_CALL_REJECTED: - return 603; - case SWITCH_CAUSE_NUMBER_CHANGED: - case SWITCH_CAUSE_REDIRECTION_TO_NEW_DESTINATION: - return 410; - case SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER: - return 502; - case SWITCH_CAUSE_INVALID_NUMBER_FORMAT: - return 484; - case SWITCH_CAUSE_FACILITY_REJECTED: - return 501; - case SWITCH_CAUSE_NORMAL_UNSPECIFIED: - return 480; - case SWITCH_CAUSE_REQUESTED_CHAN_UNAVAIL: - case SWITCH_CAUSE_NORMAL_CIRCUIT_CONGESTION: - case SWITCH_CAUSE_NETWORK_OUT_OF_ORDER: - case SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE: - case SWITCH_CAUSE_SWITCH_CONGESTION: - return 503; - case SWITCH_CAUSE_OUTGOING_CALL_BARRED: - case SWITCH_CAUSE_INCOMING_CALL_BARRED: - case SWITCH_CAUSE_BEARERCAPABILITY_NOTAUTH: - return 403; - case SWITCH_CAUSE_BEARERCAPABILITY_NOTAVAIL: - return 503; - case SWITCH_CAUSE_BEARERCAPABILITY_NOTIMPL: - return 488; - case SWITCH_CAUSE_FACILITY_NOT_IMPLEMENTED: - case SWITCH_CAUSE_SERVICE_NOT_IMPLEMENTED: - return 501; - case SWITCH_CAUSE_INCOMPATIBLE_DESTINATION: - return 503; - case SWITCH_CAUSE_RECOVERY_ON_TIMER_EXPIRE: - return 504; - case SWITCH_CAUSE_ORIGINATOR_CANCEL: - return 487; - default: - return 480; - } - -} - -static switch_status_t sofia_on_hangup(switch_core_session_t *session) -{ - switch_core_session_t *a_session; - private_object_t *tech_pvt; - switch_channel_t *channel = NULL; - switch_call_cause_t cause; - int sip_cause; - - channel = switch_core_session_get_channel(session); - assert(channel != NULL); - - tech_pvt = (private_object_t *) switch_core_session_get_private(session); - assert(tech_pvt != NULL); - - cause = switch_channel_get_cause(channel); - sip_cause = hangup_cause_to_sip(cause); - - deactivate_rtp(tech_pvt); - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Channel %s hanging up, cause: %s\n", - switch_channel_get_name(channel), switch_channel_cause2str(cause)); - - if (tech_pvt->hash_key) { - switch_core_hash_delete(tech_pvt->profile->chat_hash, tech_pvt->hash_key); - } - - if (tech_pvt->kick && (a_session = switch_core_session_locate(tech_pvt->kick))) { - switch_channel_t *a_channel = switch_core_session_get_channel(a_session); - switch_channel_hangup(a_channel, switch_channel_get_cause(channel)); - switch_core_session_rwunlock(a_session); - } - - if (tech_pvt->nh) { - if (!switch_test_flag(tech_pvt, TFLAG_BYE)) { - if (switch_test_flag(tech_pvt, TFLAG_ANS)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sending BYE to %s\n", switch_channel_get_name(channel)); - nua_bye(tech_pvt->nh, TAG_END()); - } else { - if (!switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Responding to INVITE with: %d\n", sip_cause); - nua_respond(tech_pvt->nh, sip_cause, NULL, TAG_END()); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sending CANCEL to %s\n", switch_channel_get_name(channel)); - nua_cancel(tech_pvt->nh, TAG_END()); - } - } - switch_set_flag_locked(tech_pvt, TFLAG_BYE); - } - } - - switch_clear_flag_locked(tech_pvt, TFLAG_IO); - - if (tech_pvt->home) { - su_home_unref(tech_pvt->home); - tech_pvt->home = NULL; - } - - if (tech_pvt->sofia_private) { - *tech_pvt->sofia_private->uuid = '\0'; - } - - return SWITCH_STATUS_SUCCESS; -} - -static switch_status_t sofia_on_loopback(switch_core_session_t *session) -{ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SOFIA LOOPBACK\n"); - return SWITCH_STATUS_SUCCESS; -} - -static switch_status_t sofia_on_transmit(switch_core_session_t *session) -{ - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SOFIA TRANSMIT\n"); - return SWITCH_STATUS_SUCCESS; -} - -static void deactivate_rtp(private_object_t * tech_pvt) -{ - int loops = 0; //, sock = -1; - if (switch_rtp_ready(tech_pvt->rtp_session)) { - while (loops < 10 && (switch_test_flag(tech_pvt, TFLAG_READING) || switch_test_flag(tech_pvt, TFLAG_WRITING))) { - switch_yield(10000); - loops++; - } - switch_rtp_destroy(&tech_pvt->rtp_session); - } -} - -static switch_status_t tech_set_codec(private_object_t * tech_pvt, int force) -{ - switch_channel_t *channel; - - if (tech_pvt->read_codec.implementation) { - if (!force) { - return SWITCH_STATUS_SUCCESS; - } - if (strcasecmp(tech_pvt->read_codec.implementation->iananame, tech_pvt->rm_encoding) || - tech_pvt->read_codec.implementation->samples_per_second != tech_pvt->rm_rate) { - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Changing Codec from %s to %s\n", - tech_pvt->read_codec.implementation->iananame, tech_pvt->rm_encoding); - switch_core_codec_destroy(&tech_pvt->read_codec); - switch_core_codec_destroy(&tech_pvt->write_codec); - switch_core_session_reset(tech_pvt->session); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Already using %s\n", tech_pvt->read_codec.implementation->iananame); - return SWITCH_STATUS_SUCCESS; - } - } - - channel = switch_core_session_get_channel(tech_pvt->session); - assert(channel != NULL); - - if (!tech_pvt->rm_encoding) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec with no name?\n"); - terminate_session(&tech_pvt->session, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__); - return SWITCH_STATUS_FALSE; - } - - if (switch_core_codec_init(&tech_pvt->read_codec, - tech_pvt->rm_encoding, - tech_pvt->rm_fmtp, - tech_pvt->rm_rate, - tech_pvt->codec_ms, - 1, - SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE | tech_pvt->profile->codec_flags, - NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n"); - terminate_session(&tech_pvt->session, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__); - return SWITCH_STATUS_FALSE; - } else { - if (switch_core_codec_init(&tech_pvt->write_codec, - tech_pvt->rm_encoding, - tech_pvt->rm_fmtp, - tech_pvt->rm_rate, - tech_pvt->codec_ms, - 1, - SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE | tech_pvt->profile->codec_flags, - NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n"); - terminate_session(&tech_pvt->session, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__); - return SWITCH_STATUS_FALSE; - } else { - int ms; - tech_pvt->read_frame.rate = tech_pvt->rm_rate; - ms = tech_pvt->write_codec.implementation->microseconds_per_frame / 1000; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set Codec %s %s/%ld %d ms\n", - switch_channel_get_name(channel), tech_pvt->rm_encoding, tech_pvt->rm_rate, tech_pvt->codec_ms); - tech_pvt->read_frame.codec = &tech_pvt->read_codec; - - switch_core_session_set_read_codec(tech_pvt->session, &tech_pvt->read_codec); - switch_core_session_set_write_codec(tech_pvt->session, &tech_pvt->write_codec); - tech_pvt->fmtp_out = switch_core_session_strdup(tech_pvt->session, tech_pvt->write_codec.fmtp_out); - } - } - return SWITCH_STATUS_SUCCESS; -} - - -static switch_status_t activate_rtp(private_object_t * tech_pvt) -{ - int bw, ms; - switch_channel_t *channel; - const char *err = NULL; - char *val = NULL; - switch_rtp_flag_t flags; - switch_status_t status; - char tmp[50]; - assert(tech_pvt != NULL); - - channel = switch_core_session_get_channel(tech_pvt->session); - assert(channel != NULL); - - if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) { - return SWITCH_STATUS_SUCCESS; - } - - if (switch_rtp_ready(tech_pvt->rtp_session) && !switch_test_flag(tech_pvt, TFLAG_REINVITE)) { - return SWITCH_STATUS_SUCCESS; - } - - if ((status = tech_set_codec(tech_pvt, 0)) != SWITCH_STATUS_SUCCESS) { - return status; - } - - bw = tech_pvt->read_codec.implementation->bits_per_second; - ms = tech_pvt->read_codec.implementation->microseconds_per_frame; - - flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_RAW_WRITE | SWITCH_RTP_FLAG_AUTOADJ | SWITCH_RTP_FLAG_DATAWAIT); - - if (switch_test_flag(tech_pvt, TFLAG_BUGGY_2833)) { - flags |= SWITCH_RTP_FLAG_BUGGY_2833; - } - - if ((tech_pvt->profile->pflags & PFLAG_PASS_RFC2833) - || ((val = switch_channel_get_variable(channel, "pass_rfc2833")) && switch_true(val))) { - flags |= SWITCH_RTP_FLAG_PASS_RFC2833; - } - - if (tech_pvt->cng_pt) { - flags |= SWITCH_RTP_FLAG_AUTO_CNG; - } - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "RTP [%s] %s:%d->%s:%d codec: %u ms: %d\n", - switch_channel_get_name(channel), - tech_pvt->local_sdp_audio_ip, - tech_pvt->local_sdp_audio_port, - tech_pvt->remote_sdp_audio_ip, - tech_pvt->remote_sdp_audio_port, tech_pvt->agreed_pt, tech_pvt->read_codec.implementation->microseconds_per_frame / 1000); - - snprintf(tmp, sizeof(tmp), "%d", tech_pvt->remote_sdp_audio_port); - switch_channel_set_variable(channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE, tech_pvt->adv_sdp_audio_ip); - switch_channel_set_variable(channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE, tmp); - - if (tech_pvt->rtp_session && switch_test_flag(tech_pvt, TFLAG_REINVITE)) { - switch_clear_flag_locked(tech_pvt, TFLAG_REINVITE); - - if (switch_rtp_set_remote_address(tech_pvt->rtp_session, tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port, &err) != - SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "RTP REPORTS ERROR: [%s]\n", err); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "RTP CHANGING DEST TO: [%s:%d]\n", - tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port); - /* Reactivate the NAT buster flag. */ - switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_AUTOADJ); - } - return SWITCH_STATUS_SUCCESS; - } - - tech_pvt->rtp_session = switch_rtp_new(tech_pvt->local_sdp_audio_ip, - tech_pvt->local_sdp_audio_port, - tech_pvt->remote_sdp_audio_ip, - tech_pvt->remote_sdp_audio_port, - tech_pvt->agreed_pt, - tech_pvt->read_codec.implementation->samples_per_frame, - tech_pvt->codec_ms * 1000, - (switch_rtp_flag_t) flags, - NULL, tech_pvt->profile->timer_name, &err, switch_core_session_get_pool(tech_pvt->session)); - - if (switch_rtp_ready(tech_pvt->rtp_session)) { - uint8_t vad_in = switch_test_flag(tech_pvt, TFLAG_VAD_IN) ? 1 : 0; - uint8_t vad_out = switch_test_flag(tech_pvt, TFLAG_VAD_OUT) ? 1 : 0; - uint8_t inb = switch_test_flag(tech_pvt, TFLAG_OUTBOUND) ? 0 : 1; - - tech_pvt->ssrc = switch_rtp_get_ssrc(tech_pvt->rtp_session); - switch_set_flag_locked(tech_pvt, TFLAG_RTP); - switch_set_flag_locked(tech_pvt, TFLAG_IO); - - if ((vad_in && inb) || (vad_out && !inb)) { - switch_rtp_enable_vad(tech_pvt->rtp_session, tech_pvt->session, &tech_pvt->read_codec, SWITCH_VAD_FLAG_TALKING); - switch_set_flag_locked(tech_pvt, TFLAG_VAD); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "RTP Engage VAD for %s ( %s %s )\n", - switch_channel_get_name(switch_core_session_get_channel(tech_pvt->session)), vad_in ? "in" : "", vad_out ? "out" : ""); - } - - if (tech_pvt->te) { - switch_rtp_set_telephony_event(tech_pvt->rtp_session, tech_pvt->te); - } - if (tech_pvt->cng_pt) { - switch_rtp_set_cng_pt(tech_pvt->rtp_session, tech_pvt->cng_pt); - } - - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "RTP REPORTS ERROR: [%s]\n", err); - terminate_session(&tech_pvt->session, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__); - switch_clear_flag_locked(tech_pvt, TFLAG_IO); - return SWITCH_STATUS_FALSE; - } - - switch_set_flag_locked(tech_pvt, TFLAG_IO); - return SWITCH_STATUS_SUCCESS; -} - -static switch_status_t tech_media(private_object_t * tech_pvt, char *r_sdp) -{ - sdp_parser_t *parser = sdp_parse(tech_pvt->home, r_sdp, (int) strlen(r_sdp), 0); - sdp_session_t *sdp; - uint8_t match = 0; - switch_channel_t *channel = switch_core_session_get_channel(tech_pvt->session); - - assert(tech_pvt != NULL); - - if (switch_strlen_zero(r_sdp)) { - return SWITCH_STATUS_FALSE; - } - - if (tech_pvt->num_codecs) { - if ((sdp = sdp_session(parser))) { - match = negotiate_sdp(tech_pvt->session, sdp); - } - } - - if (parser) { - sdp_parser_free(parser); - } - - if (match) { - if (tech_choose_port(tech_pvt) != SWITCH_STATUS_SUCCESS) { - return SWITCH_STATUS_FALSE; - } - activate_rtp(tech_pvt); - switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "EARLY MEDIA"); - switch_set_flag_locked(tech_pvt, TFLAG_EARLY_MEDIA); - switch_channel_mark_pre_answered(channel); - return SWITCH_STATUS_SUCCESS; - } - - return SWITCH_STATUS_FALSE; -} - - - -static switch_status_t sofia_answer_channel(switch_core_session_t *session) -{ - private_object_t *tech_pvt; - switch_channel_t *channel = NULL; - switch_status_t status; - - assert(session != NULL); - - channel = switch_core_session_get_channel(session); - assert(channel != NULL); - - tech_pvt = (private_object_t *) switch_core_session_get_private(session); - assert(tech_pvt != NULL); - - if (!switch_test_flag(tech_pvt, TFLAG_ANS) && !switch_channel_test_flag(channel, CF_OUTBOUND)) { - switch_set_flag_locked(tech_pvt, TFLAG_ANS); - - if (switch_channel_test_flag(channel, CF_NOMEDIA)) { - char *sdp = NULL; - switch_set_flag_locked(tech_pvt, TFLAG_NOMEDIA); - if ((sdp = switch_channel_get_variable(channel, SWITCH_B_SDP_VARIABLE))) { - tech_pvt->local_sdp_str = switch_core_session_strdup(session, sdp); - } - } else { - if (switch_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION)) { - char *r_sdp = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE); - if (tech_media(tech_pvt, r_sdp) != SWITCH_STATUS_SUCCESS) { - switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "CODEC NEGOTIATION ERROR"); - nua_respond(tech_pvt->nh, SIP_488_NOT_ACCEPTABLE, TAG_END()); - return SWITCH_STATUS_FALSE; - } - switch_clear_flag_locked(tech_pvt, TFLAG_LATE_NEGOTIATION); - } - - if ((status = tech_choose_port(tech_pvt)) != SWITCH_STATUS_SUCCESS) { - return status; - } - - set_local_sdp(tech_pvt, NULL, 0, NULL, 0); - activate_rtp(tech_pvt); - - if (tech_pvt->nh) { - if (tech_pvt->local_sdp_str) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Local SDP %s:\n%s\n", switch_channel_get_name(channel), - tech_pvt->local_sdp_str); - } - } - } - nua_respond(tech_pvt->nh, SIP_200_OK, - SIPTAG_CONTACT_STR(tech_pvt->profile->url), - SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str), SOATAG_AUDIO_AUX("cn telephone-event"), NUTAG_INCLUDE_EXTRA_SDP(1), TAG_END()); - } - - return SWITCH_STATUS_SUCCESS; -} - - -static switch_status_t sofia_read_frame(switch_core_session_t *session, switch_frame_t **frame, int timeout, switch_io_flag_t flags, int stream_id) -{ - private_object_t *tech_pvt = NULL; - switch_channel_t *channel = NULL; - int payload = 0; - - channel = switch_core_session_get_channel(session); - assert(channel != NULL); - - tech_pvt = (private_object_t *) switch_core_session_get_private(session); - assert(tech_pvt != NULL); - - if (switch_test_flag(tech_pvt, TFLAG_HUP)) { - return SWITCH_STATUS_FALSE; - } - - while (!(tech_pvt->read_codec.implementation && switch_rtp_ready(tech_pvt->rtp_session))) { - if (switch_channel_ready(channel)) { - switch_yield(10000); - } else { - return SWITCH_STATUS_GENERR; - } - } - - - tech_pvt->read_frame.datalen = 0; - switch_set_flag_locked(tech_pvt, TFLAG_READING); - -#if 0 - if (tech_pvt->last_read) { - elapsed = (unsigned int) ((switch_time_now() - tech_pvt->last_read) / 1000); - if (elapsed > 60000) { - return SWITCH_STATUS_TIMEOUT; - } - } -#endif - - - if (switch_test_flag(tech_pvt, TFLAG_IO)) { - switch_status_t status; - - if (!switch_test_flag(tech_pvt, TFLAG_RTP)) { - return SWITCH_STATUS_GENERR; - } - - assert(tech_pvt->rtp_session != NULL); - tech_pvt->read_frame.datalen = 0; - - - while (switch_test_flag(tech_pvt, TFLAG_IO) && tech_pvt->read_frame.datalen == 0) { - tech_pvt->read_frame.flags = SFF_NONE; - - status = switch_rtp_zerocopy_read_frame(tech_pvt->rtp_session, &tech_pvt->read_frame); - if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) { - return SWITCH_STATUS_FALSE; - } - - - - payload = tech_pvt->read_frame.payload; - -#if 0 - elapsed = (unsigned int) ((switch_time_now() - started) / 1000); - - if (timeout > -1) { - if (elapsed >= (unsigned int) timeout) { - return SWITCH_STATUS_BREAK; - } - } - - elapsed = (unsigned int) ((switch_time_now() - last_act) / 1000); - if (elapsed >= hard_timeout) { - return SWITCH_STATUS_BREAK; - } -#endif - if (switch_rtp_has_dtmf(tech_pvt->rtp_session)) { - char dtmf[128]; - switch_rtp_dequeue_dtmf(tech_pvt->rtp_session, dtmf, sizeof(dtmf)); - switch_channel_queue_dtmf(channel, dtmf); - } - - - if (tech_pvt->read_frame.datalen > 0) { - size_t bytes = 0; - int frames = 1; - - if (!switch_test_flag((&tech_pvt->read_frame), SFF_CNG)) { - if ((bytes = tech_pvt->read_codec.implementation->encoded_bytes_per_frame)) { - frames = (tech_pvt->read_frame.datalen / bytes); - } - tech_pvt->read_frame.samples = (int) (frames * tech_pvt->read_codec.implementation->samples_per_frame); - } - break; - } - } - } - - switch_clear_flag_locked(tech_pvt, TFLAG_READING); - - if (tech_pvt->read_frame.datalen == 0) { - *frame = NULL; - return SWITCH_STATUS_GENERR; - } - - *frame = &tech_pvt->read_frame; - - return SWITCH_STATUS_SUCCESS; -} - - -static switch_status_t sofia_write_frame(switch_core_session_t *session, switch_frame_t *frame, int timeout, switch_io_flag_t flags, int stream_id) -{ - private_object_t *tech_pvt; - switch_channel_t *channel = NULL; - switch_status_t status = SWITCH_STATUS_SUCCESS; - int bytes = 0, samples = 0, frames = 0; - - channel = switch_core_session_get_channel(session); - assert(channel != NULL); - - tech_pvt = (private_object_t *) switch_core_session_get_private(session); - assert(tech_pvt != NULL); - - while (!(tech_pvt->read_codec.implementation && switch_rtp_ready(tech_pvt->rtp_session))) { - if (switch_channel_ready(channel)) { - switch_yield(10000); - } else { - return SWITCH_STATUS_GENERR; - } - } - - if (switch_test_flag(tech_pvt, TFLAG_HUP)) { - return SWITCH_STATUS_FALSE; - } - - if (!switch_test_flag(tech_pvt, TFLAG_RTP)) { - return SWITCH_STATUS_GENERR; - } - - if (!switch_test_flag(tech_pvt, TFLAG_IO)) { - return SWITCH_STATUS_SUCCESS; - } - - switch_set_flag_locked(tech_pvt, TFLAG_WRITING); - - if (!switch_test_flag(frame, SFF_CNG)) { - if (tech_pvt->read_codec.implementation->encoded_bytes_per_frame) { - bytes = tech_pvt->read_codec.implementation->encoded_bytes_per_frame; - frames = ((int) frame->datalen / bytes); - } else - frames = 1; - - samples = frames * tech_pvt->read_codec.implementation->samples_per_frame; - } -#if 0 - printf("%s %s->%s send %d bytes %d samples in %d frames ts=%d\n", - switch_channel_get_name(channel), - tech_pvt->local_sdp_audio_ip, tech_pvt->remote_sdp_audio_ip, frame->datalen, samples, frames, tech_pvt->timestamp_send); -#endif - - tech_pvt->timestamp_send += samples; - //switch_rtp_write_frame(tech_pvt->rtp_session, frame, tech_pvt->timestamp_send); - switch_rtp_write_frame(tech_pvt->rtp_session, frame, 0); - - switch_clear_flag_locked(tech_pvt, TFLAG_WRITING); - return status; -} - - - -static switch_status_t sofia_kill_channel(switch_core_session_t *session, int sig) -{ - private_object_t *tech_pvt; - switch_channel_t *channel = NULL; - - channel = switch_core_session_get_channel(session); - assert(channel != NULL); - - tech_pvt = (private_object_t *) switch_core_session_get_private(session); - assert(tech_pvt != NULL); - - - switch (sig) { - case SWITCH_SIG_BREAK: - if (switch_rtp_ready(tech_pvt->rtp_session)) { - switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_BREAK); - } - break; - case SWITCH_SIG_KILL: - default: - switch_clear_flag_locked(tech_pvt, TFLAG_IO); - switch_set_flag_locked(tech_pvt, TFLAG_HUP); - - if (switch_rtp_ready(tech_pvt->rtp_session)) { - switch_rtp_kill_socket(tech_pvt->rtp_session); - } - break; - } - - return SWITCH_STATUS_SUCCESS; - -} - -static switch_status_t sofia_waitfor_read(switch_core_session_t *session, int ms, int stream_id) -{ - private_object_t *tech_pvt; - switch_channel_t *channel = NULL; - - channel = switch_core_session_get_channel(session); - assert(channel != NULL); - - tech_pvt = (private_object_t *) switch_core_session_get_private(session); - assert(tech_pvt != NULL); - - return SWITCH_STATUS_SUCCESS; -} - - -static switch_status_t sofia_waitfor_write(switch_core_session_t *session, int ms, int stream_id) -{ - private_object_t *tech_pvt; - switch_channel_t *channel = NULL; - - channel = switch_core_session_get_channel(session); - assert(channel != NULL); - - tech_pvt = (private_object_t *) switch_core_session_get_private(session); - assert(tech_pvt != NULL); - - return SWITCH_STATUS_SUCCESS; - -} - -static switch_status_t sofia_send_dtmf(switch_core_session_t *session, char *digits) -{ - private_object_t *tech_pvt; - - tech_pvt = (private_object_t *) switch_core_session_get_private(session); - assert(tech_pvt != NULL); - - return switch_rtp_queue_rfc2833(tech_pvt->rtp_session, - digits, tech_pvt->profile->dtmf_duration * (tech_pvt->read_codec.implementation->samples_per_second / 1000)); - -} - -static switch_status_t sofia_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg) -{ - switch_channel_t *channel; - private_object_t *tech_pvt; - switch_status_t status; - - channel = switch_core_session_get_channel(session); - assert(channel != NULL); - - tech_pvt = (private_object_t *) switch_core_session_get_private(session); - assert(tech_pvt != NULL); - - - switch (msg->message_id) { - case SWITCH_MESSAGE_INDICATE_NOMEDIA:{ - char *uuid; - switch_core_session_t *other_session; - switch_channel_t *other_channel; - char *ip = NULL, *port = NULL; - - switch_set_flag_locked(tech_pvt, TFLAG_NOMEDIA); - tech_pvt->local_sdp_str = NULL; - if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE)) - && (other_session = switch_core_session_locate(uuid))) { - other_channel = switch_core_session_get_channel(other_session); - ip = switch_channel_get_variable(other_channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE); - port = switch_channel_get_variable(other_channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE); - switch_core_session_rwunlock(other_session); - if (ip && port) { - set_local_sdp(tech_pvt, ip, atoi(port), NULL, 1); - } - } - if (!tech_pvt->local_sdp_str) { - tech_absorb_sdp(tech_pvt); - } - do_invite(session); - } - break; - case SWITCH_MESSAGE_INDICATE_MEDIA:{ - switch_clear_flag_locked(tech_pvt, TFLAG_NOMEDIA); - tech_pvt->local_sdp_str = NULL; - if (!switch_rtp_ready(tech_pvt->rtp_session)) { - tech_set_codecs(tech_pvt); - if ((status = tech_choose_port(tech_pvt)) != SWITCH_STATUS_SUCCESS) { - return status; - } - } - set_local_sdp(tech_pvt, NULL, 0, NULL, 1); - do_invite(session); - while (!switch_rtp_ready(tech_pvt->rtp_session) && switch_channel_get_state(channel) < CS_HANGUP) { - switch_yield(1000); - } - } - break; - - case SWITCH_MESSAGE_INDICATE_HOLD:{ - switch_set_flag_locked(tech_pvt, TFLAG_SIP_HOLD); - do_invite(session); - } - break; - - case SWITCH_MESSAGE_INDICATE_UNHOLD:{ - switch_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD); - do_invite(session); - } - break; - case SWITCH_MESSAGE_INDICATE_BRIDGE: - - if (switch_test_flag(tech_pvt, TFLAG_XFER)) { - switch_clear_flag_locked(tech_pvt, TFLAG_XFER); - if (msg->pointer_arg) { - switch_core_session_t *a_session, *b_session = msg->pointer_arg; - - if ((a_session = switch_core_session_locate(tech_pvt->xferto))) { - private_object_t *a_tech_pvt = switch_core_session_get_private(a_session); - private_object_t *b_tech_pvt = switch_core_session_get_private(b_session); - - switch_set_flag_locked(a_tech_pvt, TFLAG_REINVITE); - a_tech_pvt->remote_sdp_audio_ip = switch_core_session_strdup(a_session, b_tech_pvt->remote_sdp_audio_ip); - a_tech_pvt->remote_sdp_audio_port = b_tech_pvt->remote_sdp_audio_port; - a_tech_pvt->local_sdp_audio_ip = switch_core_session_strdup(a_session, b_tech_pvt->local_sdp_audio_ip); - a_tech_pvt->local_sdp_audio_port = b_tech_pvt->local_sdp_audio_port; - activate_rtp(a_tech_pvt); - - b_tech_pvt->kick = switch_core_session_strdup(b_session, tech_pvt->xferto); - switch_core_session_rwunlock(a_session); - } - - - msg->pointer_arg = NULL; - return SWITCH_STATUS_FALSE; - } - } - if (tech_pvt->rtp_session && switch_test_flag(tech_pvt, TFLAG_TIMER)) { - switch_rtp_clear_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_USE_TIMER); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "De-activate timed RTP!\n"); - } - break; - case SWITCH_MESSAGE_INDICATE_UNBRIDGE: - if (tech_pvt->rtp_session && switch_test_flag(tech_pvt, TFLAG_TIMER)) { - switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_USE_TIMER); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Re-activate timed RTP!\n"); - } - break; - case SWITCH_MESSAGE_INDICATE_REDIRECT: - if (msg->string_arg) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Re-directing to %s\n", msg->string_arg); - nua_respond(tech_pvt->nh, SIP_302_MOVED_TEMPORARILY, SIPTAG_CONTACT_STR(msg->string_arg), TAG_END()); - } - break; - case SWITCH_MESSAGE_INDICATE_RINGING: - nua_respond(tech_pvt->nh, SIP_180_RINGING, SIPTAG_CONTACT_STR(tech_pvt->profile->url), TAG_END()); - break; - case SWITCH_MESSAGE_INDICATE_PROGRESS:{ - if (!switch_test_flag(tech_pvt, TFLAG_ANS)) { - switch_set_flag_locked(tech_pvt, TFLAG_EARLY_MEDIA); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Asked to send early media by %s\n", msg->from); - - /* Transmit 183 Progress with SDP */ - if (switch_channel_test_flag(channel, CF_NOMEDIA)) { - char *sdp = NULL; - switch_set_flag_locked(tech_pvt, TFLAG_NOMEDIA); - if ((sdp = switch_channel_get_variable(channel, SWITCH_B_SDP_VARIABLE))) { - tech_pvt->local_sdp_str = switch_core_session_strdup(session, sdp); - } - } else { - if (switch_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION)) { - char *r_sdp = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE); - if (tech_media(tech_pvt, r_sdp) != SWITCH_STATUS_SUCCESS) { - switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "CODEC NEGOTIATION ERROR"); - nua_respond(tech_pvt->nh, SIP_488_NOT_ACCEPTABLE, TAG_END()); - return SWITCH_STATUS_FALSE; - } - switch_clear_flag_locked(tech_pvt, TFLAG_LATE_NEGOTIATION); - } - - if ((status = tech_choose_port(tech_pvt)) != SWITCH_STATUS_SUCCESS) { - return status; - } - set_local_sdp(tech_pvt, NULL, 0, NULL, 0); - activate_rtp(tech_pvt); - if (tech_pvt->local_sdp_str) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Ring SDP:\n%s\n", tech_pvt->local_sdp_str); - } - } - - nua_respond(tech_pvt->nh, - SIP_183_SESSION_PROGRESS, - SIPTAG_CONTACT_STR(tech_pvt->profile->url), - SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str), SOATAG_AUDIO_AUX("cn telephone-event"), TAG_END()); - } - } - break; - default: - break; - } - - return SWITCH_STATUS_SUCCESS; -} - -static switch_status_t sofia_receive_event(switch_core_session_t *session, switch_event_t *event) -{ - switch_channel_t *channel; - struct private_object *tech_pvt; - char *body; - nua_handle_t *msg_nh; - - channel = switch_core_session_get_channel(session); - assert(channel != NULL); - - tech_pvt = switch_core_session_get_private(session); - assert(tech_pvt != NULL); - - - if (!(body = switch_event_get_body(event))) { - body = ""; - } - - if (tech_pvt->hash_key) { - msg_nh = nua_handle(tech_pvt->profile->nua, NULL, - SIPTAG_FROM_STR(tech_pvt->chat_from), - NUTAG_URL(tech_pvt->chat_to), SIPTAG_TO_STR(tech_pvt->chat_to), SIPTAG_CONTACT_STR(tech_pvt->profile->url), TAG_END()); - - nua_message(msg_nh, SIPTAG_CONTENT_TYPE_STR("text/html"), SIPTAG_PAYLOAD_STR(body), TAG_END()); - } - - return SWITCH_STATUS_SUCCESS; -} - -static const switch_io_routines_t sofia_io_routines = { - /*.outgoing_channel */ sofia_outgoing_channel, - /*.answer_channel */ sofia_answer_channel, - /*.read_frame */ sofia_read_frame, - /*.write_frame */ sofia_write_frame, - /*.kill_channel */ sofia_kill_channel, - /*.waitfor_read */ sofia_waitfor_read, - /*.waitfor_read */ sofia_waitfor_write, - /*.send_dtmf */ sofia_send_dtmf, - /*.receive_message */ sofia_receive_message, - /*.receive_event */ sofia_receive_event -}; - -static const switch_state_handler_table_t sofia_event_handlers = { - /*.on_init */ sofia_on_init, - /*.on_ring */ sofia_on_ring, - /*.on_execute */ sofia_on_execute, - /*.on_hangup */ sofia_on_hangup, - /*.on_loopback */ sofia_on_loopback, - /*.on_transmit */ sofia_on_transmit -}; - -static const switch_endpoint_interface_t sofia_endpoint_interface = { - /*.interface_name */ "sofia", - /*.io_routines */ &sofia_io_routines, - /*.event_handlers */ &sofia_event_handlers, - /*.private */ NULL, - /*.next */ NULL -}; - -static const switch_chat_interface_t sofia_chat_interface = { - /*.name */ SOFIA_CHAT_PROTO, - /*.chat_send */ chat_send, - -}; - -static switch_status_t sofia_manage(char *relative_oid, switch_management_action_t action, char *data, switch_size_t datalen) -{ - return SWITCH_STATUS_SUCCESS; -} - -static const switch_management_interface_t sofia_management_interface = { - /*.relative_oid */ "1", - /*.management_function */ sofia_manage -}; - -static const switch_loadable_module_interface_t sofia_module_interface = { - /*.module_name */ modname, - /*.endpoint_interface */ &sofia_endpoint_interface, - /*.timer_interface */ NULL, - /*.dialplan_interface */ NULL, - /*.codec_interface */ NULL, - /*.application_interface */ NULL, - /*.api_interface */ NULL, - /*.file_interface */ NULL, - /*.speech_interface */ NULL, - /*.directory_interface */ NULL, - /*.chat_interface */ &sofia_chat_interface, - /*.say_interface */ NULL, - /*.asr_interface */ NULL, - /*.management_interface */ &sofia_management_interface -}; - - -static void logger(void *logarg, char const *fmt, va_list ap) -{ - char *data = NULL; - - if (fmt) { -#ifdef HAVE_VASPRINTF - int ret; - ret = vasprintf(&data, fmt, ap); - if ((ret == -1) || !data) { - return; - } -#else - data = (char *) malloc(2048); - if (data) { - vsnprintf(data, 2048, fmt, ap); - } else { - return; - } -#endif - } - if (data) { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_CONSOLE, (char *) "%s", data); - free(data); - } -} - - -static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session, - switch_caller_profile_t *outbound_profile, switch_core_session_t **new_session, - switch_memory_pool_t **pool) -{ - switch_call_cause_t cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; - switch_core_session_t *nsession; - char *data, *profile_name, *dest; - sofia_profile_t *profile; - switch_caller_profile_t *caller_profile = NULL; - private_object_t *tech_pvt = NULL; - switch_channel_t *nchannel; - char *host, *dest_to; - - *new_session = NULL; - - if (!(nsession = switch_core_session_request(&sofia_endpoint_interface, pool))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error Creating Session\n"); - goto done; - } - - if (!(tech_pvt = (struct private_object *) switch_core_session_alloc(nsession, sizeof(*tech_pvt)))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error Creating Session\n"); - terminate_session(&nsession, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__); - goto done; - } - - data = switch_core_session_strdup(nsession, outbound_profile->destination_number); - profile_name = data; - - if (!strncasecmp(profile_name, "gateway", 7)) { - char *gw; - outbound_reg_t *gateway_ptr; - - - if (!(gw = strchr(profile_name, '/'))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid URL\n"); - terminate_session(&nsession, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__); - cause = SWITCH_CAUSE_INVALID_NUMBER_FORMAT; - goto done; - } - - *gw++ = '\0'; - - if (!(dest = strchr(gw, '/'))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid URL\n"); - terminate_session(&nsession, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__); - cause = SWITCH_CAUSE_INVALID_NUMBER_FORMAT; - goto done; - } - - *dest++ = '\0'; - - if (!(gateway_ptr = find_gateway(gw))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Gateway\n"); - terminate_session(&nsession, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__); - cause = SWITCH_CAUSE_INVALID_NUMBER_FORMAT; - goto done; - } - - profile = gateway_ptr->profile; - tech_pvt->from_str = switch_core_session_strdup(nsession, gateway_ptr->register_from); - if (!strchr(dest, '@')) { - tech_pvt->dest = switch_core_session_sprintf(nsession, "sip:%s@%s", dest, gateway_ptr->register_proxy + 4); - } else { - tech_pvt->dest = switch_core_session_sprintf(nsession, "sip:%s", dest); - } - } else { - if (!(dest = strchr(profile_name, '/'))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid URL\n"); - terminate_session(&nsession, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__); - cause = SWITCH_CAUSE_INVALID_NUMBER_FORMAT; - goto done; - } - *dest++ = '\0'; - - if (!(profile = find_profile(profile_name))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Profile\n"); - terminate_session(&nsession, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__); - cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; - goto done; - } - - if ((dest_to = strchr(dest, '^'))) { - *dest_to++ = '\0'; - tech_pvt->dest_to = switch_core_session_alloc(nsession, strlen(dest_to) + 5); - snprintf(tech_pvt->dest_to, strlen(dest_to) + 5, "sip:%s", dest_to); - } - - if ((host = strchr(dest, '%'))) { - char buf[128]; - *host = '@'; - tech_pvt->e_dest = switch_core_session_strdup(nsession, dest); - *host++ = '\0'; - if (find_reg_url(profile, dest, host, buf, sizeof(buf))) { - tech_pvt->dest = switch_core_session_strdup(nsession, buf); - - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot locate registered user %s@%s\n", dest, host); - cause = SWITCH_CAUSE_NO_ROUTE_DESTINATION; - terminate_session(&nsession, cause, __LINE__); - goto done; - } - } else if (!strchr(dest, '@')) { - char buf[128]; - tech_pvt->e_dest = switch_core_session_strdup(nsession, dest); - if (find_reg_url(profile, dest, profile_name, buf, sizeof(buf))) { - tech_pvt->dest = switch_core_session_strdup(nsession, buf); - - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot locate registered user %s@%s\n", dest, profile_name); - cause = SWITCH_CAUSE_NO_ROUTE_DESTINATION; - terminate_session(&nsession, cause, __LINE__); - goto done; - } - } else { - tech_pvt->dest = switch_core_session_alloc(nsession, strlen(dest) + 5); - snprintf(tech_pvt->dest, strlen(dest) + 5, "sip:%s", dest); - } - } - - if (!tech_pvt->dest_to) { - tech_pvt->dest_to = tech_pvt->dest; - } - - attach_private(nsession, profile, tech_pvt, dest); - - nchannel = switch_core_session_get_channel(nsession); - caller_profile = switch_caller_profile_clone(nsession, outbound_profile); - switch_channel_set_caller_profile(nchannel, caller_profile); - switch_channel_set_flag(nchannel, CF_OUTBOUND); - switch_set_flag_locked(tech_pvt, TFLAG_OUTBOUND); - switch_channel_set_state(nchannel, CS_INIT); - *new_session = nsession; - cause = SWITCH_CAUSE_SUCCESS; - if (session) { - //char *val; - //switch_channel_t *channel = switch_core_session_get_channel(session); - switch_ivr_transfer_variable(session, nsession, SOFIA_REPLACES_HEADER); - switch_ivr_transfer_variable(session, nsession, SOFIA_SIP_HEADER_PREFIX_T); - if (switch_core_session_compare(session, nsession)) { - /* It's another sofia channel! so lets cache what they use as a pt for telephone event so - we can keep it the same - */ - private_object_t *ctech_pvt; - ctech_pvt = switch_core_session_get_private(session); - assert(ctech_pvt != NULL); - tech_pvt->bte = ctech_pvt->te; - tech_pvt->bcng_pt = ctech_pvt->cng_pt; - } - } - - done: - return cause; -} - - -static uint8_t negotiate_sdp(switch_core_session_t *session, sdp_session_t * sdp) -{ - uint8_t match = 0; - switch_payload_t te = 0, cng_pt = 0; - private_object_t *tech_pvt; - sdp_media_t *m; - sdp_attribute_t *a; - switch_channel_t *channel; - int ptime = 0, dptime = 0; - - tech_pvt = switch_core_session_get_private(session); - assert(tech_pvt != NULL); - - channel = switch_core_session_get_channel(session); - - if ((tech_pvt->origin = switch_core_session_strdup(session, (char *) sdp->sdp_origin->o_username))) { - if (strstr(tech_pvt->origin, "CiscoSystemsSIP-GW-UserAgent")) { - switch_set_flag_locked(tech_pvt, TFLAG_BUGGY_2833); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Activate Buggy RFC2833 Mode!\n"); - } - } - - for (a = sdp->sdp_attributes; a; a = a->a_next) { - if (!strcasecmp(a->a_name, "sendonly")) { - switch_set_flag_locked(tech_pvt, TFLAG_SIP_HOLD); - } else if (!strcasecmp(a->a_name, "sendrecv")) { - switch_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD); - } else if (!strcasecmp(a->a_name, "ptime")) { - dptime = atoi(a->a_value); - } - } - - for (m = sdp->sdp_media; m; m = m->m_next) { - sdp_connection_t *connection; - - ptime = dptime; - for (a = m->m_attributes; a; a = a->a_next) { - if (!strcasecmp(a->a_name, "ptime") && a->a_value) { - ptime = atoi(a->a_value); - } - } - - if (m->m_type == sdp_media_audio) { - sdp_rtpmap_t *map; - - connection = sdp->sdp_connection; - if (m->m_connections) { - connection = m->m_connections; - } - - if (!connection) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find a c= line in the sdp at media or session level!\n"); - match = 0; - break; - } - - for (map = m->m_rtpmaps; map; map = map->rm_next) { - int32_t i; - const switch_codec_implementation_t *mimp = NULL, *near_match = NULL; - const char *rm_encoding; - - - if (!(rm_encoding = map->rm_encoding)) { - rm_encoding = ""; - } - - if (!te && !strcasecmp(rm_encoding, "telephone-event")) { - te = tech_pvt->te = (switch_payload_t) map->rm_pt; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set 2833 dtmf payload to %u\n", te); - if (tech_pvt->rtp_session) { - switch_rtp_set_telephony_event(tech_pvt->rtp_session, tech_pvt->te); - } - } - - if (!cng_pt && !strcasecmp(rm_encoding, "CN")) { - cng_pt = tech_pvt->cng_pt = (switch_payload_t) map->rm_pt; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set comfort noise payload to %u\n", cng_pt); - if (tech_pvt->rtp_session) { - switch_rtp_set_cng_pt(tech_pvt->rtp_session, tech_pvt->cng_pt); - switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_AUTO_CNG); - } - } - - if (match) { - if (te && cng_pt) { - break; - } - continue; - } - - for (i = 0; i < tech_pvt->num_codecs; i++) { - const switch_codec_implementation_t *imp = tech_pvt->codecs[i]; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Codec Compare [%s:%d]/[%s:%d]\n", - rm_encoding, map->rm_pt, imp->iananame, imp->ianacode); - if (map->rm_pt < 96) { - match = (map->rm_pt == imp->ianacode) ? 1 : 0; - } else { - match = strcasecmp(rm_encoding, imp->iananame) ? 0 : 1; - } - - if (match && (map->rm_rate == imp->samples_per_second)) { - if (ptime && ptime * 1000 != imp->microseconds_per_frame) { - near_match = imp; - match = 0; - continue; - } - mimp = imp; - break; - } else { - match = 0; - } - } - - if (!match && near_match) { - const switch_codec_implementation_t *search[1]; - char *prefs[1]; - char tmp[80]; - int num; - - snprintf(tmp, sizeof(tmp), "%s@%uk@%ui", near_match->iananame, near_match->samples_per_second, ptime); - - prefs[0] = tmp; - num = switch_loadable_module_get_codecs_sorted(search, 1, prefs, 1); - - if (num) { - mimp = search[0]; - } else { - mimp = near_match; - } - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Substituting codec %s@%ums\n", - mimp->iananame, mimp->microseconds_per_frame / 1000); - match = 1; - } - - if (mimp) { - if ((tech_pvt->rm_encoding = switch_core_session_strdup(session, (char *) rm_encoding))) { - char tmp[50]; - tech_pvt->pt = (switch_payload_t) map->rm_pt; - tech_pvt->rm_rate = map->rm_rate; - tech_pvt->codec_ms = mimp->microseconds_per_frame / 1000; - tech_pvt->remote_sdp_audio_ip = switch_core_session_strdup(session, (char *) connection->c_address); - tech_pvt->rm_fmtp = switch_core_session_strdup(session, (char *) map->rm_fmtp); - tech_pvt->remote_sdp_audio_port = (switch_port_t) m->m_port; - tech_pvt->agreed_pt = (switch_payload_t) map->rm_pt; - snprintf(tmp, sizeof(tmp), "%d", tech_pvt->remote_sdp_audio_port); - switch_channel_set_variable(channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, tech_pvt->remote_sdp_audio_ip); - switch_channel_set_variable(channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp); - } else { - match = 0; - } - } - - if (match) { - if (tech_set_codec(tech_pvt, 1) != SWITCH_STATUS_SUCCESS) { - match = 0; - } - } - } - } - } - - return match; -} - -// map sip responses to QSIG cause codes ala RFC4497 section 8.4.4 -static switch_call_cause_t sip_cause_to_freeswitch(int status) -{ - switch (status) { - case 200: - return SWITCH_CAUSE_NORMAL_CLEARING; - case 401: - case 402: - case 403: - case 407: - case 603: - return SWITCH_CAUSE_CALL_REJECTED; - case 404: - case 485: - case 604: - return SWITCH_CAUSE_NO_ROUTE_DESTINATION; - case 408: - case 504: - return SWITCH_CAUSE_RECOVERY_ON_TIMER_EXPIRE; - case 410: - return SWITCH_CAUSE_NUMBER_CHANGED; - case 413: - case 414: - case 416: - case 420: - case 421: - case 423: - case 505: - case 513: - return SWITCH_CAUSE_INTERWORKING; - case 480: - return SWITCH_CAUSE_NO_USER_RESPONSE; - case 400: - case 481: - case 500: - case 503: - return SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE; - case 486: - case 600: - return SWITCH_CAUSE_USER_BUSY; - case 484: - return SWITCH_CAUSE_INVALID_NUMBER_FORMAT; - case 488: - case 606: - return SWITCH_CAUSE_BEARERCAPABILITY_NOTIMPL; - case 502: - return SWITCH_CAUSE_NETWORK_OUT_OF_ORDER; - case 405: - return SWITCH_CAUSE_SERVICE_UNAVAILABLE; - case 406: - case 415: - case 501: - return SWITCH_CAUSE_SERVICE_NOT_IMPLEMENTED; - case 482: - case 483: - return SWITCH_CAUSE_EXCHANGE_ROUTING_ERROR; - case 487: - return SWITCH_CAUSE_ORIGINATOR_CANCEL; - - default: - return SWITCH_CAUSE_NORMAL_UNSPECIFIED; - - } -} - - -static void set_hash_key(char *hash_key, int32_t len, sip_t const *sip) -{ - - snprintf(hash_key, len, "%s%s%s", (char *) sip->sip_from->a_url->url_user, (char *) sip->sip_from->a_url->url_host, - (char *) sip->sip_to->a_url->url_user); - - -#if 0 - /* nicer one we cant use in both directions >=0 */ - snprintf(hash_key, len, "%s%s%s%s%s%s", - (char *) sip->sip_to->a_url->url_user, - (char *) sip->sip_to->a_url->url_host, - (char *) sip->sip_to->a_url->url_params, - (char *) sip->sip_from->a_url->url_user, (char *) sip->sip_from->a_url->url_host, (char *) sip->sip_from->a_url->url_params); -#endif - -} - -static void set_chat_hash(private_object_t * tech_pvt, sip_t const *sip) -{ - char hash_key[256] = ""; - char buf[512]; - - if (tech_pvt->hash_key || !sip || !sip->sip_from || !sip->sip_from->a_url || !sip->sip_from->a_url->url_user || !sip->sip_from->a_url->url_host) { - return; - } - - if (find_reg_url(tech_pvt->profile, sip->sip_from->a_url->url_user, sip->sip_from->a_url->url_host, buf, sizeof(buf))) { - tech_pvt->chat_from = sip_header_as_string(tech_pvt->home, (const sip_header_t *) sip->sip_to); - tech_pvt->chat_to = switch_core_session_strdup(tech_pvt->session, buf); - set_hash_key(hash_key, sizeof(hash_key), sip); - } else { - return; - } - - tech_pvt->hash_key = switch_core_session_strdup(tech_pvt->session, hash_key); - switch_core_hash_insert(tech_pvt->profile->chat_hash, tech_pvt->hash_key, tech_pvt); - -} - - -static void sip_i_message(int status, - char const *phrase, - nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]) -{ - if (sip) { - sip_from_t const *from = sip->sip_from; - char *from_user = NULL; - char *from_host = NULL; - sip_to_t const *to = sip->sip_to; - char *to_user = NULL; - char *to_host = NULL; - sip_subject_t const *sip_subject = sip->sip_subject; - sip_payload_t *payload = sip->sip_payload; - const char *subject = "n/a"; - char *msg = NULL; - - if (sip->sip_content_type) { - if (strstr((char *) sip->sip_content_type->c_subtype, "composing")) { - return; - } - } - - if (from) { - from_user = (char *) from->a_url->url_user; - from_host = (char *) from->a_url->url_host; - } - - if (to) { - to_user = (char *) to->a_url->url_user; - to_host = (char *) to->a_url->url_host; - } - - - if (!to_user) { - return; - } - - if (payload) { - msg = payload->pl_data; - } - - if (sip_subject) { - subject = sip_subject->g_value; - } - - if (nh) { - char hash_key[512]; - private_object_t *tech_pvt; - switch_channel_t *channel; - switch_event_t *event; - char *to_addr; - char *from_addr; - char *p; - char *full_from; - char proto[512] = SOFIA_CHAT_PROTO; - - full_from = sip_header_as_string(profile->home, (void *) sip->sip_from); - - if ((p = strchr(to_user, '+'))) { - switch_copy_string(proto, to_user, sizeof(proto)); - p = strchr(proto, '+'); - *p++ = '\0'; - - if ((to_addr = strdup(p))) { - if ((p = strchr(to_addr, '+'))) { - *p = '@'; - } - } - - } else { - to_addr = switch_mprintf("%s@%s", to_user, to_host); - } - - from_addr = switch_mprintf("%s@%s", from_user, from_host); - - - set_hash_key(hash_key, sizeof(hash_key), sip); - if ((tech_pvt = (private_object_t *) switch_core_hash_find(profile->chat_hash, hash_key))) { - channel = switch_core_session_get_channel(tech_pvt->session); - if (switch_event_create(&event, SWITCH_EVENT_MESSAGE) == SWITCH_STATUS_SUCCESS) { - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s", tech_pvt->hash_key); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "to", "%s", to_addr); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "subject", "SIMPLE MESSAGE"); - if (msg) { - switch_event_add_body(event, "%s", msg); - } - if (switch_core_session_queue_event(tech_pvt->session, &event) != SWITCH_STATUS_SUCCESS) { - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "delivery-failure", "true"); - switch_event_fire(&event); - } - } - } else { - switch_chat_interface_t *ci; - - if ((ci = switch_loadable_module_get_chat_interface(proto))) { - ci->chat_send(SOFIA_CHAT_PROTO, from_addr, to_addr, "", msg, full_from); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Chat Interface [%s]!\n", proto ? proto : "(none)"); - } - - } - switch_safe_free(to_addr); - switch_safe_free(from_addr); - if (full_from) { - su_free(profile->home, full_from); - } - } - - } -} - -static void pass_sdp(private_object_t * tech_pvt, char *sdp) -{ - char *val; - switch_channel_t *channel; - switch_core_session_t *other_session; - switch_channel_t *other_channel; - - channel = switch_core_session_get_channel(tech_pvt->session); - assert(channel != NULL); - - if ((val = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE)) - && (other_session = switch_core_session_locate(val))) { - other_channel = switch_core_session_get_channel(other_session); - assert(other_channel != NULL); - switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, sdp); - - if (!switch_test_flag(tech_pvt, TFLAG_CHANGE_MEDIA) && (switch_channel_test_flag(other_channel, CF_OUTBOUND) && - //switch_channel_test_flag(other_channel, CF_NOMEDIA) && - switch_channel_test_flag(channel, CF_OUTBOUND) && - switch_channel_test_flag(channel, CF_NOMEDIA))) { - switch_ivr_nomedia(val, SMF_FORCE); - switch_set_flag_locked(tech_pvt, TFLAG_CHANGE_MEDIA); - } - - switch_core_session_rwunlock(other_session); - } -} - -static void sip_i_state(int status, - char const *phrase, - nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]) -{ - const char *l_sdp = NULL, *r_sdp = NULL; - int offer_recv = 0, answer_recv = 0, offer_sent = 0, answer_sent = 0; - int ss_state = nua_callstate_init; - switch_channel_t *channel = NULL; - private_object_t *tech_pvt = NULL; - switch_core_session_t *session = NULL; - const char *replaces_str = NULL; - char *uuid; - switch_core_session_t *other_session = NULL; - switch_channel_t *other_channel = NULL; - char st[80] = ""; - - - if (sofia_private) { - if (!switch_strlen_zero(sofia_private->uuid)) { - if (!(session = switch_core_session_locate(sofia_private->uuid))) { - /* too late */ - return; - } - } - } - - - tl_gets(tags, - NUTAG_CALLSTATE_REF(ss_state), - NUTAG_OFFER_RECV_REF(offer_recv), - NUTAG_ANSWER_RECV_REF(answer_recv), - NUTAG_OFFER_SENT_REF(offer_sent), - NUTAG_ANSWER_SENT_REF(answer_sent), - SIPTAG_REPLACES_STR_REF(replaces_str), SOATAG_LOCAL_SDP_STR_REF(l_sdp), SOATAG_REMOTE_SDP_STR_REF(r_sdp), TAG_END()); - - if (session) { - channel = switch_core_session_get_channel(session); - assert(channel != NULL); - - tech_pvt = switch_core_session_get_private(session); - assert(tech_pvt != NULL); - assert(tech_pvt->nh != NULL); - - if (switch_channel_test_flag(channel, CF_NOMEDIA)) { - switch_set_flag(tech_pvt, TFLAG_NOMEDIA); - } - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Channel %s entering state [%s]\n", - switch_channel_get_name(channel), nua_callstate_name(ss_state)); - - if (r_sdp) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Remote SDP:\n%s\n", r_sdp); - tech_pvt->remote_sdp_str = switch_core_session_strdup(session, r_sdp); - switch_channel_set_variable(channel, SWITCH_R_SDP_VARIABLE, r_sdp); - pass_sdp(tech_pvt, (char *) r_sdp); - - } - } - - if (status == 988) { - goto done; - } - - switch ((enum nua_callstate) ss_state) { - case nua_callstate_init: - break; - case nua_callstate_authenticating: - break; - case nua_callstate_calling: - break; - case nua_callstate_proceeding: - if (channel) { - if (status == 180) { - switch_channel_mark_ring_ready(channel); - if (!switch_channel_test_flag(channel, CF_GEN_RINGBACK)) { - if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) { - if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE)) - && (other_session = switch_core_session_locate(uuid))) { - switch_core_session_message_t msg; - msg.message_id = SWITCH_MESSAGE_INDICATE_RINGING; - msg.from = __FILE__; - switch_core_session_receive_message(other_session, &msg); - switch_core_session_rwunlock(other_session); - } - - } else { - switch_core_session_queue_indication(session, SWITCH_MESSAGE_INDICATE_RINGING); - } - } - } - - if (r_sdp) { - if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) { - switch_set_flag_locked(tech_pvt, TFLAG_EARLY_MEDIA); - switch_channel_mark_pre_answered(channel); - if (!switch_channel_test_flag(channel, CF_GEN_RINGBACK) && (uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE)) - && (other_session = switch_core_session_locate(uuid))) { - other_channel = switch_core_session_get_channel(other_session); - if (!switch_channel_get_variable(other_channel, SWITCH_B_SDP_VARIABLE)) { - switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, r_sdp); - } - - switch_channel_pre_answer(other_channel); - switch_core_session_rwunlock(other_session); - } - goto done; - } else { - if (switch_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION)) { - switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "DELAYED NEGOTIATION"); - } else { - if (tech_media(tech_pvt, (char *) r_sdp) != SWITCH_STATUS_SUCCESS) { - switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "CODEC NEGOTIATION ERROR"); - nua_respond(nh, SIP_488_NOT_ACCEPTABLE, TAG_END()); - } - } - goto done; - } - } - } - break; - case nua_callstate_completing: - nua_ack(nh, TAG_END()); - break; - case nua_callstate_received: - - if (session && switch_core_session_running(session)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Re-Entering Call State Received!\n"); - goto done; - } - - if (channel) { - if (r_sdp) { - if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) { - switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "RECEIVED_NOMEDIA"); - switch_channel_set_state(channel, CS_INIT); - switch_set_flag_locked(tech_pvt, TFLAG_READY); - switch_core_session_thread_launch(session); - goto done; - } else { - sdp_parser_t *parser = sdp_parse(tech_pvt->home, r_sdp, (int) strlen(r_sdp), 0); - sdp_session_t *sdp; - uint8_t match = 0; - - if (tech_pvt->num_codecs) { - if ((sdp = sdp_session(parser))) { - match = negotiate_sdp(session, sdp); - } - } - - if (parser) { - sdp_parser_free(parser); - } - - if (match) { - nua_handle_t *bnh; - sip_replaces_t *replaces; - switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "RECEIVED"); - switch_channel_set_state(channel, CS_INIT); - switch_set_flag_locked(tech_pvt, TFLAG_READY); - - switch_core_session_thread_launch(session); - - if (replaces_str && (replaces = sip_replaces_make(tech_pvt->home, replaces_str)) - && (bnh = nua_handle_by_replaces(nua, replaces))) { - sofia_private_t *b_private; - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Processing Replaces Attended Transfer\n"); - while (switch_channel_get_state(channel) < CS_EXECUTE) { - switch_yield(10000); - } - - if ((b_private = nua_handle_magic(bnh))) { - char *br_b = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE); - char *br_a = b_private->uuid; - - if (br_b) { - switch_ivr_uuid_bridge(br_a, br_b); - switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER"); - switch_channel_hangup(channel, SWITCH_CAUSE_ATTENDED_TRANSFER); - } else { - switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER_ERROR"); - switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); - } - } else { - switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER_ERROR"); - switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); - } - nua_handle_unref(bnh); - } - goto done; - } - - switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "NO CODECS"); - nua_respond(nh, SIP_488_NOT_ACCEPTABLE, TAG_END()); - } - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Invite with no SDP activating no-media-mode\n"); - switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "RECEIVED_NOSDP"); - - switch_set_flag(tech_pvt, TFLAG_LATE_NEGOTIATION); - switch_set_flag_locked(tech_pvt, TFLAG_NOMEDIA); - switch_channel_set_flag(channel, CF_NOMEDIA); - switch_channel_set_state(channel, CS_INIT); - switch_set_flag_locked(tech_pvt, TFLAG_READY); - switch_core_session_thread_launch(session); - goto done; - } - } - - break; - case nua_callstate_early: - break; - case nua_callstate_completed: - if (tech_pvt && r_sdp) { - if (r_sdp) { - if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) { - goto done; - } else { - sdp_parser_t *parser = sdp_parse(tech_pvt->home, r_sdp, (int) strlen(r_sdp), 0); - sdp_session_t *sdp; - uint8_t match = 0; - - if (tech_pvt->num_codecs) { - if ((sdp = sdp_session(parser))) { - match = negotiate_sdp(session, sdp); - } - } - if (match) { - if (tech_choose_port(tech_pvt) != SWITCH_STATUS_SUCCESS) { - goto done; - } - set_local_sdp(tech_pvt, NULL, 0, NULL, 0); - switch_set_flag_locked(tech_pvt, TFLAG_REINVITE); - activate_rtp(tech_pvt); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Processing Reinvite\n"); - if (parser) { - sdp_parser_free(parser); - } - } - } - } - } - break; - case nua_callstate_ready: - if (tech_pvt && nh == tech_pvt->nh2) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Cheater Reinvite!\n"); - switch_set_flag_locked(tech_pvt, TFLAG_REINVITE); - tech_pvt->nh = tech_pvt->nh2; - tech_pvt->nh2 = NULL; - if (tech_choose_port(tech_pvt) == SWITCH_STATUS_SUCCESS) { - activate_rtp(tech_pvt); - } - goto done; - } - - if (channel) { - if (switch_test_flag(tech_pvt, TFLAG_EARLY_MEDIA)) { - switch_set_flag_locked(tech_pvt, TFLAG_ANS); - switch_channel_mark_answered(channel); - if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE)) - && (other_session = switch_core_session_locate(uuid))) { - other_channel = switch_core_session_get_channel(other_session); - switch_channel_answer(other_channel); - switch_core_session_rwunlock(other_session); - } - goto done; - } - - if (!r_sdp) { - r_sdp = (const char *) switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE); - } - if (r_sdp) { - if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) { - switch_set_flag_locked(tech_pvt, TFLAG_ANS); - switch_channel_mark_answered(channel); - if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE)) - && (other_session = switch_core_session_locate(uuid))) { - other_channel = switch_core_session_get_channel(other_session); - if (!switch_channel_get_variable(other_channel, SWITCH_B_SDP_VARIABLE)) { - switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, r_sdp); - } - switch_channel_answer(other_channel); - switch_core_session_rwunlock(other_session); - } - goto done; - } else { - sdp_parser_t *parser = sdp_parse(tech_pvt->home, r_sdp, (int) strlen(r_sdp), 0); - sdp_session_t *sdp; - uint8_t match = 0; - - if (tech_pvt->num_codecs) { - if ((sdp = sdp_session(parser))) { - match = negotiate_sdp(session, sdp); - } - } - - if (parser) { - sdp_parser_free(parser); - } - - - if (match) { - switch_set_flag_locked(tech_pvt, TFLAG_ANS); - if (tech_choose_port(tech_pvt) == SWITCH_STATUS_SUCCESS) { - activate_rtp(tech_pvt); - switch_channel_mark_answered(channel); - goto done; - } - } - - switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "NO CODECS"); - nua_respond(nh, SIP_488_NOT_ACCEPTABLE, TAG_END()); - } - } - - } - - break; - case nua_callstate_terminating: - break; - case nua_callstate_terminated: - if (session) { - if (!switch_test_flag(tech_pvt, TFLAG_BYE)) { - - switch_set_flag_locked(tech_pvt, TFLAG_BYE); - if (switch_test_flag(tech_pvt, TFLAG_NOHUP)) { - switch_clear_flag_locked(tech_pvt, TFLAG_NOHUP); - } else { - snprintf(st, sizeof(st), "%d", status); - switch_channel_set_variable(channel, "sip_term_status", st); - terminate_session(&session, sip_cause_to_freeswitch(status), __LINE__); - } - } - - if (tech_pvt->sofia_private) { - free(tech_pvt->sofia_private); - tech_pvt->sofia_private = NULL; - } - tech_pvt->nh = NULL; - } else if (sofia_private) { - free(sofia_private); - } - - if (nh) { - nua_handle_bind(nh, NULL); - nua_handle_destroy(nh); - } - break; - } - - done: - - if (session) { - switch_core_session_rwunlock(session); - } -} - - -static char *get_auth_data(char *dbname, char *nonce, char *npassword, size_t len, switch_mutex_t * mutex) -{ - switch_core_db_t *db; - switch_core_db_stmt_t *stmt; - char *sql = NULL, *ret = NULL; - - if (mutex) { - switch_mutex_lock(mutex); - } - - if (!dbname) { - goto end; - } - - if (!(db = switch_core_db_open_file(dbname))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", dbname); - goto end; - } - - sql = switch_mprintf("select passwd from sip_authentication where nonce='%q'", nonce); - if (switch_core_db_prepare(db, sql, -1, &stmt, 0)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Statement Error!\n"); - goto fail; - } else { - int running = 1; - int colcount; - - while (running < 5000) { - int result = switch_core_db_step(stmt); - - if (result == SWITCH_CORE_DB_ROW) { - if ((colcount = switch_core_db_column_count(stmt))) { - switch_copy_string(npassword, (char *) switch_core_db_column_text(stmt, 0), len); - ret = npassword; - } - break; - } else if (result == SWITCH_CORE_DB_BUSY) { - running++; - switch_yield(1000); - continue; - } - break; - } - - switch_core_db_finalize(stmt); - } - - - fail: - - switch_core_db_close(db); - - end: - if (mutex) { - switch_mutex_unlock(mutex); - } - - if (sql) { - switch_safe_free(sql); - } - - return ret; -} - - -typedef enum { - REG_REGISTER, - REG_INVITE -} sofia_regtype_t; - -static uint8_t handle_register(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sip_t const *sip, sofia_regtype_t regtype, char *key, - uint32_t keylen) -{ - sip_from_t const *from = NULL; - sip_expires_t const *expires = NULL; - sip_authorization_t const *authorization = NULL; - sip_contact_t const *contact = NULL; - switch_xml_t domain, xml, user, param, xparams; - char params[1024] = ""; - char *sql; - switch_event_t *s_event; - const char *from_user = NULL; - const char *from_host = NULL; - char contact_str[1024] = ""; - char buf[512]; - const char *passwd = NULL; - const char *a1_hash = NULL; - uint8_t stale = 0, ret = 0, forbidden = 0; - auth_res_t auth_res; - long exptime = 60; - switch_event_t *event; - const char *rpid = "unknown"; - const char *display = "\"user\""; - - /* all callers must confirm that sip, sip->sip_request and sip->sip_contact are not NULL */ - assert(sip != NULL && sip->sip_contact != NULL && sip->sip_request != NULL); - - expires = sip->sip_expires; - authorization = sip->sip_authorization; - contact = sip->sip_contact; - from = sip->sip_from; - - if (from) { - from_user = from->a_url->url_user; - from_host = from->a_url->url_host; - } - - if (!from_user || !from_host) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can not do authorization without a complete from header\n"); - nua_respond(nh, SIP_500_INTERNAL_SERVER_ERROR, TAG_END()); - return 1; - } - - if (contact->m_url) { - const char *port = contact->m_url->url_port; - display = contact->m_display; - - if (switch_strlen_zero(display)) { - if (from) { - display = from->a_display; - if (switch_strlen_zero(display)) { - display = "\"user\""; - } - } - } - - if (!port) { - port = SOFIA_DEFAULT_PORT; - } - - if (contact->m_url->url_params) { - snprintf(contact_str, sizeof(contact_str), "%s <sip:%s@%s:%s;%s>", - display, contact->m_url->url_user, contact->m_url->url_host, port, contact->m_url->url_params); - } else { - snprintf(contact_str, sizeof(contact_str), "%s <sip:%s@%s:%s>", display, contact->m_url->url_user, contact->m_url->url_host, port); - } - } - - if (expires) { - exptime = expires->ex_delta; - } else if (contact->m_expires) { - exptime = atol(contact->m_expires); - } - - if (regtype == REG_REGISTER) { - authorization = sip->sip_authorization; - } else if (regtype == REG_INVITE) { - authorization = sip->sip_proxy_authorization; - } - - if ((profile->pflags & PFLAG_BLIND_REG)) { - goto reg; - } - - if (authorization) { - if ((auth_res = parse_auth(profile, authorization, sip->sip_request->rq_method_name, key, keylen)) == AUTH_STALE) { - stale = 1; - } - - if (auth_res != AUTH_OK && !stale) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "send %s for [%s@%s]\n", forbidden ? "forbidden" : "challange", from_user, from_host); - if (auth_res == AUTH_FORBIDDEN) { - nua_respond(nh, SIP_403_FORBIDDEN, NUTAG_WITH_THIS(nua), TAG_END()); - } else { - nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS(nua), TAG_END()); - } - return 1; - } - } - - if (!authorization || stale) { - snprintf(params, sizeof(params), "from_user=%s&from_host=%s&contact=%s", from_user, from_host, contact_str); - - - if (switch_xml_locate("directory", "domain", "name", from_host, &xml, &domain, params) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "can't find domain for [%s@%s]\n", from_user, from_host); - nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS(nua), SIPTAG_CONTACT(contact), TAG_END()); - return 1; - } - - if (!(user = switch_xml_find_child(domain, "user", "id", from_user))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "can't find user [%s@%s]\n", from_user, from_host); - nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS(nua), SIPTAG_CONTACT(contact), TAG_END()); - switch_xml_free(xml); - return 1; - } - - if (!(xparams = switch_xml_child(user, "params"))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "can't find params for user [%s@%s]\n", from_user, from_host); - nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS(nua), SIPTAG_CONTACT(contact), TAG_END()); - switch_xml_free(xml); - return 1; - } - - - for (param = switch_xml_child(xparams, "param"); param; param = param->next) { - const char *var = switch_xml_attr_soft(param, "name"); - const char *val = switch_xml_attr_soft(param, "value"); - - if (!strcasecmp(var, "password")) { - passwd = val; - } - - if (!strcasecmp(var, "a1-hash")) { - a1_hash = val; - } - } - - if (passwd || a1_hash) { - switch_uuid_t uuid; - char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1]; - char *sql, *auth_str; - - su_md5_t ctx; - char hexdigest[2 * SU_MD5_DIGEST_SIZE + 1]; - char *input; - - if (!a1_hash) { - input = switch_mprintf("%s:%s:%s", from_user, from_host, passwd); - su_md5_init(&ctx); - su_md5_strupdate(&ctx, input); - su_md5_hexdigest(&ctx, hexdigest); - su_md5_deinit(&ctx); - switch_safe_free(input); - - switch_uuid_get(&uuid); - switch_uuid_format(uuid_str, &uuid); - a1_hash = hexdigest; - } - - sql = switch_mprintf("delete from sip_authentication where user='%q' and host='%q';\n" - "insert into sip_authentication values('%q','%q','%q','%q', %ld)", - from_user, from_host, from_user, from_host, a1_hash, uuid_str, time(NULL) + profile->nonce_ttl); - auth_str = - switch_mprintf("Digest realm=\"%q\", nonce=\"%q\",%s algorithm=MD5, qop=\"auth\"", from_host, uuid_str, stale ? " stale=\"true\"," : ""); - - - if (regtype == REG_REGISTER) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Requesting Registration from: [%s@%s]\n", from_user, from_host); - nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS(nua), SIPTAG_WWW_AUTHENTICATE_STR(auth_str), TAG_END()); - } else if (regtype == REG_INVITE) { - nua_respond(nh, SIP_407_PROXY_AUTH_REQUIRED, NUTAG_WITH_THIS(nua), SIPTAG_PROXY_AUTHENTICATE_STR(auth_str), TAG_END()); - - } - - execute_sql(profile->dbname, sql, profile->ireg_mutex); - switch_safe_free(sql); - switch_safe_free(auth_str); - ret = 1; - } else { - ret = 0; - } - - switch_xml_free(xml); - - if (ret) { - return ret; - } - } - reg: - - if (exptime) { - if (!find_reg_url(profile, from_user, from_host, buf, sizeof(buf))) { - sql = switch_mprintf("insert into sip_registrations values ('%q','%q','%q','Registered', '%q', %ld)", - from_user, from_host, contact_str, rpid, (long) time(NULL) + (long) exptime * 2); - - } else { - sql = - switch_mprintf - ("update sip_registrations set contact='%q', expires=%ld, rpid='%q' where user='%q' and host='%q'", - contact_str, (long) time(NULL) + (long) exptime * 2, rpid, from_user, from_host); - - } - - if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_REGISTER) == SWITCH_STATUS_SUCCESS) { - switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "profile-name", "%s", profile->name); - switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "from-user", "%s", from_user); - switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "from-host", "%s", from_host); - switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "contact", "%s", contact_str); - switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "rpid", "%s", rpid); - switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "expires", "%ld", (long) exptime); - switch_event_fire(&s_event); - } - - if (sql) { - execute_sql(profile->dbname, sql, profile->ireg_mutex); - switch_safe_free(sql); - sql = NULL; - } - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, - "Register:\nFrom: [%s@%s]\nContact: [%s]\nExpires: [%ld]\n", from_user, from_host, contact_str, (long) exptime); - - - if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) { - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", "sip"); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "rpid", "%s", rpid); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host); - - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "Registered"); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_type", "presence"); - switch_event_fire(&event); - } - } else { - if ((sql = switch_mprintf("delete from sip_subscriptions where user='%q' and host='%q'", from_user, from_host))) { - execute_sql(profile->dbname, sql, profile->ireg_mutex); - switch_safe_free(sql); - sql = NULL; - } - if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_OUT) == SWITCH_STATUS_SUCCESS) { - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", "sip"); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s+%s@%s", SOFIA_CHAT_PROTO, from_user, from_host); - - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "unavailable"); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "rpid", "%s", rpid); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_type", "presence"); - switch_event_fire(&event); - } - } - - - if (switch_event_create(&event, SWITCH_EVENT_ROSTER) == SWITCH_STATUS_SUCCESS) { - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", "sip"); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host); - switch_event_fire(&event); - } - - if (regtype == REG_REGISTER) { - nua_respond(nh, SIP_200_OK, SIPTAG_CONTACT(contact), NUTAG_WITH_THIS(nua), TAG_END()); - return 1; - } - - return 0; -} - - -static int sub_reg_callback(void *pArg, int argc, char **argv, char **columnNames) -{ - sofia_profile_t *profile = (sofia_profile_t *) pArg; - //char *proto = argv[0]; - char *user = argv[1]; - char *host = argv[2]; - switch_event_t *event; - char *status = NULL; - if (switch_strlen_zero(status)) { - status = "Available"; - } - if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) { - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", user, host); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "%s", status); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_type", "presence"); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_subtype", "probe"); - switch_event_fire(&event); - } - - return 0; -} - -static int resub_callback(void *pArg, int argc, char **argv, char **columnNames) -{ - sofia_profile_t *profile = (sofia_profile_t *) pArg; - char *user = argv[0]; - char *host = argv[1]; - char *status = argv[2]; - char *rpid = argv[3]; - char *proto = argv[4]; - switch_event_t *event; - - if (switch_strlen_zero(proto)) { - proto = NULL; - } - - if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) { - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", "%s", proto ? proto : SOFIA_CHAT_PROTO); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", user, host); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "%s", status); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "rpid", "%s", rpid); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_type", "presence"); - switch_event_fire(&event); - } - - return 0; -} - -static int sub_callback(void *pArg, int argc, char **argv, char **columnNames) -{ - sofia_profile_t *profile = (sofia_profile_t *) pArg; - char *pl; - char *id, *note; - uint32_t in = atoi(argv[0]); - char *status = argv[1]; - char *rpid = argv[2]; - char *proto = argv[3]; - char *user = argv[4]; - char *host = argv[5]; - char *sub_to_user = argv[6]; - char *sub_to_host = argv[7]; - char *event = argv[8]; - char *contact = argv[9]; - char *callid = argv[10]; - char *full_from = argv[11]; - char *full_via = argv[12]; - nua_handle_t *nh; - char *to; - char *open; - char *tmp; - - if (!rpid) { - rpid = "unknown"; - } - - if (in) { - note = switch_mprintf("<dm:note>%s</dm:note>", status); - open = "open"; - } else { - note = NULL; - open = "closed"; - } - - if (!strcasecmp(sub_to_host, host)) { - /* same host */ - id = switch_mprintf("sip:%s+%s@%s", proto, sub_to_user, sub_to_host); - } else if (strcasecmp(proto, SOFIA_CHAT_PROTO)) { - /*encapsulate */ - id = switch_mprintf("sip:%s+%s+%s@%s", proto, sub_to_user, sub_to_host, host); - } else { - id = switch_mprintf("sip:%s@%s", sub_to_user, sub_to_host); - } - - to = switch_mprintf("sip:%s@%s", user, host); - pl = switch_mprintf("<?xml version='1.0' encoding='UTF-8'?>\r\n" - "<presence xmlns='urn:ietf:params:xml:ns:pidf'\r\n" - "xmlns:dm='urn:ietf:params:xml:ns:pidf:data-model'\r\n" - "xmlns:rpid='urn:ietf:params:xml:ns:pidf:rpid'\r\n" - "xmlns:c='urn:ietf:params:xml:ns:pidf:cipid'\r\n" - "entity='pres:%s'>\r\n" - "<tuple id='t6a5ed77e'>\r\n" - "<status>\r\n" - "<basic>%s</basic>\r\n" - "</status>\r\n" - "</tuple>\r\n" - "<dm:person id='p06360c4a'>\r\n" - "<rpid:activities>\r\n" "<rpid:%s/>\r\n" "</rpid:activities>%s</dm:person>\r\n" "</presence>", id, open, rpid, note); - - - - nh = nua_handle(profile->nua, NULL, TAG_END()); - tmp = contact; - contact = get_url_from_contact(tmp, 0); - - nua_notify(nh, - NUTAG_URL(contact), - SIPTAG_TO_STR(full_from), - SIPTAG_FROM_STR(id), - SIPTAG_CONTACT_STR(profile->url), - SIPTAG_CALL_ID_STR(callid), - SIPTAG_VIA_STR(full_via), - SIPTAG_SUBSCRIPTION_STATE_STR("active;expires=3600"), - SIPTAG_EVENT_STR(event), SIPTAG_CONTENT_TYPE_STR("application/pidf+xml"), SIPTAG_PAYLOAD_STR(pl), TAG_END()); - - switch_safe_free(id); - switch_safe_free(note); - switch_safe_free(pl); - switch_safe_free(to); - - return 0; -} - -static void sip_i_subscribe(int status, - char const *phrase, - nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]) -{ - if (sip) { - long exp, exp_raw; - sip_to_t const *to = sip->sip_to; - sip_from_t const *from = sip->sip_from; - sip_contact_t const *contact = sip->sip_contact; - char *from_user = NULL; - char *from_host = NULL; - char *to_user = NULL; - char *to_host = NULL; - char *sql, *event = NULL; - char *proto = "sip"; - char *d_user = NULL; - char *contact_str = ""; - char *call_id = NULL; - char *to_str = NULL; - char *full_from = NULL; - char *full_via = NULL; - switch_core_db_t *db; - char *errmsg; - char *sstr; - const char *display = "\"user\""; - switch_event_t *sevent; - - if (contact) { - char *port = (char *) contact->m_url->url_port; - - display = contact->m_display; - - if (switch_strlen_zero(display)) { - if (from) { - display = from->a_display; - if (switch_strlen_zero(display)) { - display = "\"user\""; - } - } - } else { - display = "\"user\""; - } - - if (!port) { - port = SOFIA_DEFAULT_PORT; - } - - if (contact->m_url->url_params) { - contact_str = switch_mprintf("%s <sip:%s@%s:%s;%s>", - display, contact->m_url->url_user, contact->m_url->url_host, port, contact->m_url->url_params); - } else { - contact_str = switch_mprintf("%s <sip:%s@%s:%s>", display, contact->m_url->url_user, contact->m_url->url_host, port); - } - } - - if (to) { - to_str = switch_mprintf("sip:%s@%s", to->a_url->url_user, to->a_url->url_host); //, to->a_url->url_port); - } - - if (to) { - to_user = (char *) to->a_url->url_user; - to_host = (char *) to->a_url->url_host; - } - - - if (strstr(to_user, "ext+") || strstr(to_user, "user+") || strstr(to_user, "conf+")) { - char proto[80]; - char *p; - - switch_copy_string(proto, to_user, sizeof(proto)); - if ((p = strchr(proto, '+'))) { - *p = '\0'; - } - - if (switch_event_create(&sevent, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) { - switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO); - switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "login", "%s", profile->name); - switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "from", "%s@%s", to_user, to_host); - switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "rpid", "unknown"); - switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "status", "Click To Call"); - switch_event_fire(&sevent); - } - } - - if (strchr(to_user, '+')) { - char *h; - if ((proto = (d_user = strdup(to_user)))) { - if ((to_user = strchr(d_user, '+'))) { - *to_user++ = '\0'; - if ((h = strchr(to_user, '+')) || (h = strchr(to_user, '@'))) { - *h++ = '\0'; - to_host = h; - } - } - } - - if (!(proto && to_user && to_host)) { - nua_respond(nh, SIP_404_NOT_FOUND, NUTAG_WITH_THIS(nua), TAG_END()); - goto end; - } - } - - call_id = sip_header_as_string(profile->home, (void *) sip->sip_call_id); - event = sip_header_as_string(profile->home, (void *) sip->sip_event); - full_from = sip_header_as_string(profile->home, (void *) sip->sip_from); - full_via = sip_header_as_string(profile->home, (void *) sip->sip_via); - - exp_raw = (sip->sip_expires ? sip->sip_expires->ex_delta : 3600); - exp = (long) time(NULL) + exp_raw; - - if (sip && sip->sip_from) { - from_user = (char *) sip->sip_from->a_url->url_user; - from_host = (char *) sip->sip_from->a_url->url_host; - } else { - from_user = "n/a"; - from_host = "n/a"; - } - - if ((sql = switch_mprintf("delete from sip_subscriptions where " - "proto='%q' and user='%q' and host='%q' and sub_to_user='%q' and sub_to_host='%q' and event='%q';\n" - "insert into sip_subscriptions values ('%q','%q','%q','%q','%q','%q','%q','%q','%q','%q',%ld)", - proto, - from_user, - from_host, - to_user, - to_host, event, proto, from_user, from_host, to_user, to_host, event, contact_str, call_id, full_from, full_via, exp))) { - execute_sql(profile->dbname, sql, profile->ireg_mutex); - switch_safe_free(sql); - } - - sstr = switch_mprintf("active;expires=%ld", exp_raw); - - nua_respond(nh, SIP_202_ACCEPTED, - NUTAG_WITH_THIS(nua), - SIPTAG_SUBSCRIPTION_STATE_STR(sstr), SIPTAG_FROM(sip->sip_to), SIPTAG_TO(sip->sip_from), SIPTAG_CONTACT_STR(to_str), TAG_END()); - - - - switch_safe_free(sstr); - - if (!(db = switch_core_db_open_file(profile->dbname))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname); - goto end; - } - if ((sql = switch_mprintf("select * from sip_subscriptions where user='%q' and host='%q'", to_user, to_host, to_user, to_host))) { - switch_mutex_lock(profile->ireg_mutex); - switch_core_db_exec(db, sql, sub_reg_callback, profile, &errmsg); - switch_mutex_unlock(profile->ireg_mutex); - switch_safe_free(sql); - } - switch_core_db_close(db); - end: - - if (event) { - su_free(profile->home, event); - } - if (call_id) { - su_free(profile->home, call_id); - } - if (full_from) { - su_free(profile->home, full_from); - } - if (full_via) { - su_free(profile->home, full_via); - } - - switch_safe_free(d_user); - switch_safe_free(to_str); - switch_safe_free(contact_str); - } -} - -static void sip_r_subscribe(int status, - char const *phrase, - nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]) -{ - -} - - -/*---------------------------------------*/ -static void sip_i_refer(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, switch_core_session_t *session, sip_t const *sip, tagi_t tags[]) -{ - /* Incoming refer */ - sip_from_t const *from; - sip_to_t const *to; - sip_refer_to_t const *refer_to; - private_object_t *tech_pvt = NULL; - char *etmp = NULL, *exten = NULL; - switch_channel_t *channel_a = NULL, *channel_b = NULL; - - tech_pvt = switch_core_session_get_private(session); - channel_a = switch_core_session_get_channel(session); - - if (!sip->sip_cseq || !(etmp = switch_mprintf("refer;id=%u", sip->sip_cseq->cs_seq))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n"); - goto done; - } - - - if (switch_channel_test_flag(channel_a, CF_NOMEDIA)) { - nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"), - NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden"), SIPTAG_EVENT_STR(etmp), TAG_END()); - goto done; - } - - from = sip->sip_from; - to = sip->sip_to; - - if ((refer_to = sip->sip_refer_to)) { - if (profile->pflags & PFLAG_FULL_ID) { - exten = switch_mprintf("%s@%s", (char *) refer_to->r_url->url_user, (char *) refer_to->r_url->url_host); - } else { - exten = (char *) refer_to->r_url->url_user; - } - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Process REFER to [%s@%s]\n", exten, (char *) refer_to->r_url->url_host); - - if (refer_to->r_url->url_headers) { - sip_replaces_t *replaces; - nua_handle_t *bnh; - char *rep; - - if ((rep = strchr(refer_to->r_url->url_headers, '='))) { - char *br_a = NULL, *br_b = NULL; - char *buf; - rep++; - - - - if ((buf = switch_core_session_alloc(session, strlen(rep) + 1))) { - rep = url_unescape(buf, (const char *) rep); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Replaces: [%s]\n", rep); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n"); - goto done; - } - if ((replaces = sip_replaces_make(tech_pvt->home, rep)) - && (bnh = nua_handle_by_replaces(nua, replaces))) { - sofia_private_t *b_private = NULL; - private_object_t *b_tech_pvt = NULL; - switch_core_session_t *b_session = NULL; - - switch_channel_set_variable(channel_a, SOFIA_REPLACES_HEADER, rep); - if ((b_private = nua_handle_magic(bnh))) { - if (!(b_session = switch_core_session_locate(b_private->uuid))) { - goto done; - } - b_tech_pvt = (private_object_t *) switch_core_session_get_private(b_session); - channel_b = switch_core_session_get_channel(b_session); - - br_a = switch_channel_get_variable(channel_a, SWITCH_SIGNAL_BOND_VARIABLE); - br_b = switch_channel_get_variable(channel_b, SWITCH_SIGNAL_BOND_VARIABLE); - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Attended Transfer [%s][%s]\n", br_a, br_b); - - if (br_a && br_b) { - switch_ivr_uuid_bridge(br_a, br_b); - switch_channel_set_variable(channel_b, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER"); - switch_set_flag_locked(tech_pvt, TFLAG_BYE); - switch_set_flag_locked(b_tech_pvt, TFLAG_BYE); - nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"), - NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"), SIPTAG_EVENT_STR(etmp), TAG_END()); - - } else { - if (!br_a && !br_b) { - switch_set_flag_locked(tech_pvt, TFLAG_NOHUP); - switch_set_flag_locked(b_tech_pvt, TFLAG_XFER); - b_tech_pvt->xferto = switch_core_session_strdup(b_session, switch_core_session_get_uuid(session)); - } else if (!br_a && br_b) { - switch_core_session_t *br_b_session; - - if ((br_b_session = switch_core_session_locate(br_b))) { - private_object_t *br_b_tech_pvt = switch_core_session_get_private(br_b_session); - switch_channel_t *br_b_channel = switch_core_session_get_channel(br_b_session); - - switch_set_flag_locked(tech_pvt, TFLAG_NOHUP); - - switch_channel_clear_state_handler(br_b_channel, NULL); - switch_channel_set_state_flag(br_b_channel, CF_TRANSFER); - switch_channel_set_state(br_b_channel, CS_TRANSMIT); - - switch_set_flag_locked(tech_pvt, TFLAG_REINVITE); - tech_pvt->local_sdp_audio_ip = switch_core_session_strdup(session, b_tech_pvt->local_sdp_audio_ip); - tech_pvt->local_sdp_audio_port = b_tech_pvt->local_sdp_audio_port; - - tech_pvt->remote_sdp_audio_ip = switch_core_session_strdup(session, br_b_tech_pvt->remote_sdp_audio_ip); - tech_pvt->remote_sdp_audio_port = br_b_tech_pvt->remote_sdp_audio_port; - activate_rtp(tech_pvt); - - br_b_tech_pvt->kick = switch_core_session_strdup(br_b_session, switch_core_session_get_uuid(session)); - - - switch_core_session_rwunlock(br_b_session); - } - - switch_channel_hangup(channel_b, SWITCH_CAUSE_ATTENDED_TRANSFER); - } - switch_set_flag_locked(tech_pvt, TFLAG_BYE); - nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"), - NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"), SIPTAG_EVENT_STR(etmp), TAG_END()); - - } - if (b_session) { - switch_core_session_rwunlock(b_session); - } - } - nua_handle_unref(bnh); - } else { /* the other channel is on a different box, we have to go find them */ - if (exten && (br_a = switch_channel_get_variable(channel_a, SWITCH_SIGNAL_BOND_VARIABLE))) { - switch_core_session_t *a_session; - switch_channel_t *channel = switch_core_session_get_channel(session); - - if ((a_session = switch_core_session_locate(br_a))) { - switch_core_session_t *tsession; - switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING; - uint32_t timeout = 60; - char *tuuid_str; - - channel = switch_core_session_get_channel(a_session); - - exten = switch_mprintf("sofia/%s/%s@%s:%s", - profile->name, - (char *) refer_to->r_url->url_user, (char *) refer_to->r_url->url_host, refer_to->r_url->url_port); - - switch_channel_set_variable(channel, SOFIA_REPLACES_HEADER, rep); - - if (switch_ivr_originate(a_session, - &tsession, &cause, exten, timeout, &noop_state_handler, NULL, NULL, NULL) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot Create Outgoing Channel! [%s]\n", exten); - nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"), - NUTAG_SUBSTATE(nua_substate_terminated), - SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden"), SIPTAG_EVENT_STR(etmp), TAG_END()); - goto done; - } - - switch_core_session_rwunlock(a_session); - tuuid_str = switch_core_session_get_uuid(tsession); - switch_ivr_uuid_bridge(br_a, tuuid_str); - switch_channel_set_variable(channel_a, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER"); - switch_set_flag_locked(tech_pvt, TFLAG_BYE); - nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"), - NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"), SIPTAG_EVENT_STR(etmp), TAG_END()); - } else { - goto error; - } - - } else { - error: - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Transfer! [%s]\n", br_a); - switch_channel_set_variable(channel_a, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER_ERROR"); - nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"), - NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden"), SIPTAG_EVENT_STR(etmp), - TAG_END()); - } - } - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot parse Replaces!\n"); - } - goto done; - } - - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing Refer-To\n"); - goto done; - } - - if (exten) { - switch_channel_t *channel = switch_core_session_get_channel(session); - char *br; - - if ((br = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))) { - switch_core_session_t *b_session; - - if ((b_session = switch_core_session_locate(br))) { - switch_channel_set_variable(channel, "TRANSFER_FALLBACK", from->a_user); - switch_ivr_session_transfer(b_session, exten, profile->dialplan, profile->context); - switch_core_session_rwunlock(b_session); - } - - switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "BLIND_TRANSFER"); - - /* - nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"), - NUTAG_SUBSTATE(nua_substate_terminated), - SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"), - SIPTAG_EVENT_STR(etmp), - TAG_END()); - */ - } else { - exten = switch_mprintf("sip:%s@%s:%s", (char *) refer_to->r_url->url_user, (char *) refer_to->r_url->url_host, refer_to->r_url->url_port); - tech_pvt->dest = switch_core_session_strdup(session, exten); - - - switch_set_flag_locked(tech_pvt, TFLAG_NOHUP); - - /* - nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"), - NUTAG_SUBSTATE(nua_substate_terminated), - SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"), - SIPTAG_EVENT_STR(etmp), - TAG_END()); - */ - do_xfer_invite(session); - - } - } - - done: - if (exten && strchr(exten, '@')) { - switch_safe_free(exten); - } - if (etmp) { - switch_safe_free(etmp); - } - - -} - - -static void sip_i_publish(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]) -{ - if (sip) { - sip_from_t const *from = sip->sip_from; - char *from_user = NULL; - char *from_host = NULL; - char *rpid = "unknown"; - sip_payload_t *payload = sip->sip_payload; - char *event_type; - - if (from) { - from_user = (char *) from->a_url->url_user; - from_host = (char *) from->a_url->url_host; - } - - if (payload) { - switch_xml_t xml, note, person, tuple, status, basic, act; - switch_event_t *event; - uint8_t in = 0; - char *sql; - - if ((xml = switch_xml_parse_str(payload->pl_data, strlen(payload->pl_data)))) { - char *status_txt = "", *note_txt = ""; - - if ((tuple = switch_xml_child(xml, "tuple")) && (status = switch_xml_child(tuple, "status")) - && (basic = switch_xml_child(status, "basic"))) { - status_txt = basic->txt; - } - - if ((person = switch_xml_child(xml, "dm:person")) && (note = switch_xml_child(person, "dm:note"))) { - note_txt = note->txt; - } - - if (person && (act = switch_xml_child(person, "rpid:activities"))) { - if ((rpid = strchr(act->child->name, ':'))) { - rpid++; - } else { - rpid = act->child->name; - } - } - - if (!strcasecmp(status_txt, "open")) { - if (switch_strlen_zero(note_txt)) { - note_txt = "Available"; - } - in = 1; - } else if (!strcasecmp(status_txt, "closed")) { - if (switch_strlen_zero(note_txt)) { - note_txt = "Unavailable"; - } - } - - if ((sql = - switch_mprintf("update sip_registrations set status='%q',rpid='%q' where user='%q' and host='%q'", - note_txt, rpid, from_user, from_host))) { - execute_sql(profile->dbname, sql, profile->ireg_mutex); - switch_safe_free(sql); - } - - event_type = sip_header_as_string(profile->home, (void *) sip->sip_event); - - if (in) { - if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) { - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "rpid", "%s", rpid); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host); - - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "%s", note_txt); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_type", "%s", event_type); - switch_event_fire(&event); - } - } else { - if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_OUT) == SWITCH_STATUS_SUCCESS) { - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "rpid", "%s", rpid); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host); - - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_type", "%s", event_type); - switch_event_fire(&event); - } - } - - if (event_type) { - su_free(profile->home, event_type); - } - - switch_xml_free(xml); - } - - } - - } - - nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END()); - -} - -static void sip_i_info(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, switch_core_session_t *session, sip_t const *sip, tagi_t tags[]) -{ - - //placeholder for string searching - char *signal_ptr; - - //Try and find signal information in the payload - signal_ptr = strstr(sip->sip_payload->pl_data, "Signal="); - - //See if we found a match - if (signal_ptr) { - struct private_object *tech_pvt = NULL; - switch_channel_t *channel = NULL; - char dtmf_digit[2] = { 0, 0 }; - - //Get the channel - channel = switch_core_session_get_channel(session); - - //Barf if we didn't get it - assert(channel != NULL); - - //make sure we have our privates - tech_pvt = switch_core_session_get_private(session); - - //Barf if we didn't get it - assert(tech_pvt != NULL); - - //move signal_ptr where we need it (right past Signal=) - signal_ptr = signal_ptr + 7; - - //put the digit somewhere we can muck with - strncpy(dtmf_digit, signal_ptr, 1); - - //queue it up - switch_channel_queue_dtmf(channel, dtmf_digit); - - //print debug info - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "INFO DTMF(%s)\n", dtmf_digit); - - } else { //unknown info type - sip_from_t const *from; - - from = sip->sip_from; - - //print in the logs if something comes through we don't understand - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Unknown INFO Recieved: %s%s" URL_PRINT_FORMAT "[%s]\n", - from->a_display ? from->a_display : "", from->a_display ? " " : "", URL_PRINT_ARGS(from->a_url), sip->sip_payload->pl_data); - } - - return; -} - - -#define url_set_chanvars(session, url, varprefix) _url_set_chanvars(session, url, #varprefix "_user", #varprefix "_host", #varprefix "_port", #varprefix "_uri") -static const char *_url_set_chanvars(switch_core_session_t *session, url_t * url, const char *user_var, - const char *host_var, const char *port_var, const char *uri_var) -{ - const char *user = NULL, *host = NULL, *port = NULL; - char *uri = NULL; - switch_channel_t *channel = switch_core_session_get_channel(session); - - if (url) { - user = url->url_user; - host = url->url_host; - port = url->url_port; - } - - if (user) { - switch_channel_set_variable(channel, user_var, user); - } - - if (!port) { - port = SOFIA_DEFAULT_PORT; - } - - switch_channel_set_variable(channel, port_var, port); - if (host) { - if (user) { - uri = switch_core_session_sprintf(session, "%s@%s:%s", user, host, port); - } else { - uri = switch_core_session_sprintf(session, "%s:%s", host, port); - } - switch_channel_set_variable_nodup(channel, uri_var, uri); - switch_channel_set_variable(channel, host_var, host); - } - - return uri; -} - -static void process_rpid(sip_unknown_t * un, private_object_t * tech_pvt) -{ - int argc, x, screen = 1; - char *mydata, *argv[10] = { 0 }; - if (!switch_strlen_zero(un->un_value)) { - if ((mydata = strdup(un->un_value))) { - argc = switch_separate_string(mydata, ';', argv, (sizeof(argv) / sizeof(argv[0]))); - - // Do We really need this at this time - // clid_uri = argv[0]; - - for (x = 1; x < argc && argv[x]; x++) { - // we dont need to do anything with party yet we should only be seeing party=calling here anyway - // maybe thats a dangerous assumption bit oh well yell at me later - // if (!strncasecmp(argv[x], "party", 5)) { - // party = argv[x]; - // } else - if (!strncasecmp(argv[x], "privacy=", 8)) { - char *arg = argv[x] + 9; - - if (!strcasecmp(arg, "yes")) { - switch_set_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NAME | SWITCH_CPF_HIDE_NUMBER); - } else if (!strcasecmp(arg, "full")) { - switch_set_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NAME | SWITCH_CPF_HIDE_NUMBER); - } else if (!strcasecmp(arg, "name")) { - switch_set_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NAME); - } else if (!strcasecmp(arg, "number")) { - switch_set_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NUMBER); - } else { - switch_clear_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NAME); - switch_clear_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NUMBER); - } - - } else if (!strncasecmp(argv[x], "screen=", 7) && screen > 0) { - char *arg = argv[x] + 8; - if (!strcasecmp(arg, "no")) { - screen = 0; - switch_clear_flag(tech_pvt->caller_profile, SWITCH_CPF_SCREEN); - } - } - } - free(mydata); - } - } -} - -static void sip_i_invite(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]) -{ - switch_core_session_t *session = NULL; - char key[128] = ""; - sip_unknown_t *un; - private_object_t *tech_pvt = NULL; - switch_channel_t *channel = NULL; - const char *channel_name = NULL; - const char *displayname = NULL; - const char *destination_number = NULL; - const char *from_user = NULL, *from_host = NULL; - const char *context = NULL; - char network_ip[80]; - - if (!sip || !sip->sip_request || !sip->sip_request->rq_method_name) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Received an invalid packet!\n"); - nua_respond(nh, SIP_500_INTERNAL_SERVER_ERROR, TAG_END()); - return; - } - - - if (!(sip->sip_contact && sip->sip_contact->m_url)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NO CONTACT!\n"); - nua_respond(nh, 400, "Missing Contact Header", TAG_END()); - return; - } - - if ((profile->pflags & PFLAG_AUTH_CALLS)) { - if (handle_register(nua, profile, nh, sip, REG_INVITE, key, sizeof(key))) { - return; - } - } - - if (!(session = switch_core_session_request(&sofia_endpoint_interface, NULL))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Session Alloc Failed!\n"); - nua_respond(nh, SIP_503_SERVICE_UNAVAILABLE, TAG_END()); - return; - } - - if (!(tech_pvt = (private_object_t *) switch_core_session_alloc(session, sizeof(private_object_t)))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Hey where is my memory pool?\n"); - nua_respond(nh, SIP_503_SERVICE_UNAVAILABLE, TAG_END()); - terminate_session(&session, SWITCH_CAUSE_SWITCH_CONGESTION, __LINE__); - return; - } - - if (!switch_strlen_zero(key)) { - tech_pvt->key = switch_core_session_strdup(session, key); - } - - get_addr(network_ip, sizeof(network_ip), &((struct sockaddr_in *) msg_addrinfo(nua_current_request(nua))->ai_addr)->sin_addr); - - channel = switch_core_session_get_channel(session); - - if (sip->sip_from && sip->sip_from->a_url) { - from_user = sip->sip_from->a_url->url_user; - from_host = sip->sip_from->a_url->url_host; - channel_name = url_set_chanvars(session, sip->sip_from->a_url, sip_from); - - if (!switch_strlen_zero(from_user)) { - if (*from_user == '+') { - switch_channel_set_variable(channel, "sip_from_user_stripped", (const char *) (from_user + 1)); - } else { - switch_channel_set_variable(channel, "sip_from_user_stripped", from_user); - } - } - - if (!switch_strlen_zero(sip->sip_from->a_display)) { - char *tmp; - tmp = switch_core_session_strdup(session, sip->sip_from->a_display); - if (*tmp == '"') { - char *p; - - tmp++; - if ((p = strchr(tmp, '"'))) { - *p = '\0'; - } - } - displayname = tmp; - } else { - displayname = switch_strlen_zero(from_user) ? "unkonwn" : from_user; - } - } - - if (sip->sip_request->rq_url) { - const char *req_uri = url_set_chanvars(session, sip->sip_request->rq_url, sip_req); - if (profile->pflags & PFLAG_FULL_ID) { - destination_number = req_uri; - } else { - destination_number = sip->sip_request->rq_url->url_user; - } - } - - if (sip->sip_to && sip->sip_to->a_url) { - url_set_chanvars(session, sip->sip_to->a_url, sip_to); - } - - if (sip->sip_contact && sip->sip_contact->m_url) { - const char *contact_uri = url_set_chanvars(session, sip->sip_contact->m_url, sip_contact); - if (!channel_name) { - channel_name = contact_uri; - } - } - - attach_private(session, profile, tech_pvt, channel_name); - tech_set_codecs(tech_pvt); - - switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "INBOUND CALL"); - set_chat_hash(tech_pvt, sip); - - if (switch_test_flag(tech_pvt, TFLAG_INB_NOMEDIA)) { - switch_set_flag_locked(tech_pvt, TFLAG_NOMEDIA); - switch_channel_set_flag(channel, CF_NOMEDIA); - } - - if (!tech_pvt->call_id && sip->sip_call_id && sip->sip_call_id->i_id) { - tech_pvt->call_id = switch_core_session_strdup(session, sip->sip_call_id->i_id); - switch_channel_set_variable(channel, "sip_call_id", tech_pvt->call_id); - } - - if (sip->sip_via) { - if (sip->sip_via->v_host) { - switch_channel_set_variable(channel, "sip_via_host", sip->sip_via->v_host); - } - if (sip->sip_via->v_port) { - switch_channel_set_variable(channel, "sip_via_port", sip->sip_via->v_port); - } - if (sip->sip_via->v_rport) { - switch_channel_set_variable(channel, "sip_via_rport", sip->sip_via->v_rport); - } - } - - if (sip->sip_max_forwards) { - char max_forwards[32]; - snprintf(max_forwards, sizeof(max_forwards), "%lu", sip->sip_max_forwards->mf_count); - switch_channel_set_variable(channel, SWITCH_MAX_FORWARDS_VARIABLE, max_forwards); - } - - - if (sip->sip_request->rq_url) { - outbound_reg_t *gateway; - char *from_key = switch_core_session_sprintf(session, "sip:%s@%s", - (char *) sip->sip_request->rq_url->url_user, - (char *) sip->sip_request->rq_url->url_host); - - if ((gateway = find_gateway(from_key))) { - context = gateway->register_context; - switch_channel_set_variable(channel, "sip_gateway", gateway->name); - } - } - - - if (!context) { - if (profile->context && !strcasecmp(profile->context, "_domain_")) { - context = from_host; - } else { - context = profile->context; - } - } - - tech_pvt->caller_profile = switch_caller_profile_new(switch_core_session_get_pool(session), - from_user, - profile->dialplan, - displayname, from_user, network_ip, NULL, NULL, NULL, modname, context, destination_number); - - if (tech_pvt->caller_profile) { - - /* Loop thru unknown Headers Here so we can do something with them */ - for (un = sip->sip_unknown; un; un = un->un_next) { - if (!strncasecmp(un->un_name, "Alert-Info", 10)) { - if (!switch_strlen_zero(un->un_value)) { - switch_channel_set_variable(channel, "alert_info", un->un_value); - } - } else if (!strncasecmp(un->un_name, "Remote-Party-ID", 15)) { - process_rpid(un, tech_pvt); - } else if (!strncasecmp(un->un_name, "X-", 2)) { - if (!switch_strlen_zero(un->un_value)) { - char *new_name; - if ((new_name = switch_mprintf("%s%s", SOFIA_SIP_HEADER_PREFIX, un->un_name))) { - switch_channel_set_variable(channel, new_name, un->un_value); - free(new_name); - } - } - } - } - - switch_channel_set_caller_profile(channel, tech_pvt->caller_profile); - } - - if (!(tech_pvt->sofia_private = malloc(sizeof(*tech_pvt->sofia_private)))) { - abort(); - } - memset(tech_pvt->sofia_private, 0, sizeof(*tech_pvt->sofia_private)); - switch_copy_string(tech_pvt->sofia_private->uuid, switch_core_session_get_uuid(session), sizeof(tech_pvt->sofia_private->uuid)); - nua_handle_bind(nh, tech_pvt->sofia_private); - tech_pvt->nh = nh; -} - -static void sip_i_register(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]) -{ - char key[128] = ""; - - if (!sip || !sip->sip_request || !sip->sip_request->rq_method_name) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Received an invalid packet!\n"); - nua_respond(nh, SIP_500_INTERNAL_SERVER_ERROR, TAG_END()); - return; - } - - if (!(sip->sip_contact && sip->sip_contact->m_url)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NO CONTACT!\n"); - nua_respond(nh, 400, "Missing Contact Header", TAG_END()); - return; - } - - handle_register(nua, profile, nh, sip, REG_REGISTER, key, sizeof(key)); -} - - -static void sip_i_options(int status, - char const *phrase, - nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]) -{ - nua_respond(nh, SIP_200_OK, - //SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str), - //SOATAG_AUDIO_AUX("cn telephone-event"), - //NUTAG_INCLUDE_EXTRA_SDP(1), - TAG_END()); -} - - -static void sip_r_register(int status, - char const *phrase, - nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]) -{ - if (sofia_private && sofia_private->gateway) { - switch (status) { - case 200: - if (sip && sip->sip_contact && sip->sip_contact->m_expires) { - char *new_expires = (char *) sip->sip_contact->m_expires; - uint32_t expi = (uint32_t) atoi(new_expires); - - if (expi != sofia_private->gateway->freq) { - sofia_private->gateway->freq = expi; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, - "Changing expire time to %d by request of proxy %s\n", expi, sofia_private->gateway->register_proxy); - } - - } - sofia_private->gateway->state = REG_STATE_REGISTER; - break; - case 100: - break; - default: - sofia_private->gateway->state = REG_STATE_FAILED; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Registration Failed with status %d\n", status); - break; - } - } -} - -static void sip_r_challenge(int status, - char const *phrase, - nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, switch_core_session_t *session, sip_t const *sip, tagi_t tags[]) -{ - outbound_reg_t *gateway = NULL; - sip_www_authenticate_t const *authenticate = NULL; - char const *realm = NULL; - char *p = NULL, *duprealm = NULL, *qrealm = NULL; - char const *scheme = NULL; - int indexnum; - char *cur; - char authentication[256] = ""; - int ss_state; - - if (session) { - private_object_t *tech_pvt; - if ((tech_pvt = switch_core_session_get_private(session)) && switch_test_flag(tech_pvt, TFLAG_REFER)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "received reply from refer\n"); - return; - } - } - - - if (sip->sip_www_authenticate) { - authenticate = sip->sip_www_authenticate; - } else if (sip->sip_proxy_authenticate) { - authenticate = sip->sip_proxy_authenticate; - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Missing Authenticate Header!\n"); - return; - } - scheme = (char const *) authenticate->au_scheme; - if (authenticate->au_params) { - for (indexnum = 0; (cur = (char *) authenticate->au_params[indexnum]); indexnum++) { - if ((realm = strstr(cur, "realm="))) { - realm += 6; - break; - } - } - } - - if (!(scheme && realm)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No scheme and realm!\n"); - return; - } - - if (profile) { - outbound_reg_t *gateway_ptr; - - if ((duprealm = strdup(realm))) { - qrealm = duprealm; - - while (*qrealm && *qrealm == '"') { - qrealm++; - } - - if ((p = strchr(qrealm, '"'))) { - *p = '\0'; - } - - if (sip->sip_from) { - char *from_key = switch_mprintf("sip:%s@%s", - (char *) sip->sip_from->a_url->url_user, - (char *) sip->sip_from->a_url->url_host); - - if (!(gateway = find_gateway(from_key))) { - gateway = find_gateway(qrealm); - } - - switch_safe_free(from_key); - } - - if (!gateway) { - for (gateway_ptr = profile->gateways; gateway_ptr; gateway_ptr = gateway_ptr->next) { - if (scheme && qrealm && !strcasecmp(gateway_ptr->register_scheme, scheme) - && !strcasecmp(gateway_ptr->register_realm, qrealm)) { - gateway = gateway_ptr; - break; - } - } - } - - if (!gateway) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No Match for Scheme [%s] Realm [%s]\n", scheme, qrealm); - return; - } - switch_safe_free(duprealm); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n"); - return; - } - } - - snprintf(authentication, sizeof(authentication), "%s:%s:%s:%s", scheme, realm, gateway->register_username, gateway->register_password); - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Authenticating '%s' with '%s'.\n", profile->username, authentication); - - - ss_state = nua_callstate_authenticating; - - tl_gets(tags, NUTAG_CALLSTATE_REF(ss_state), SIPTAG_WWW_AUTHENTICATE_REF(authenticate), TAG_END()); - - nua_authenticate(nh, SIPTAG_EXPIRES_STR(gateway->expires_str), NUTAG_AUTH(authentication), TAG_END()); - -} - -static void event_callback(nua_event_t event, - int status, - char const *phrase, - nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]) -{ - struct private_object *tech_pvt = NULL; - auth_res_t auth_res = AUTH_FORBIDDEN; - switch_core_session_t *session = NULL; - switch_channel_t *channel = NULL; - - if (sofia_private) { - if (!switch_strlen_zero(sofia_private->uuid)) { - - if ((session = switch_core_session_locate(sofia_private->uuid))) { - tech_pvt = switch_core_session_get_private(session); - channel = switch_core_session_get_channel(tech_pvt->session); - if (switch_channel_test_flag(channel, CF_NOMEDIA)) { - switch_set_flag(tech_pvt, TFLAG_NOMEDIA); - } - if (!tech_pvt->call_id && sip && sip->sip_call_id && sip->sip_call_id->i_id) { - tech_pvt->call_id = switch_core_session_strdup(session, (char *) sip->sip_call_id->i_id); - switch_channel_set_variable(channel, "sip_call_id", tech_pvt->call_id); - } - } else { - /* too late */ - return; - } - } - } - - - if (status != 100 && status != 200) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "event [%s] status [%d][%s] session: %s\n", - nua_event_name(event), status, phrase, session ? switch_channel_get_name(channel) : "n/a"); - } - - if ((profile->pflags & PFLAG_AUTH_ALL) && tech_pvt && tech_pvt->key && sip) { - sip_authorization_t const *authorization = NULL; - - if (sip->sip_authorization) { - authorization = sip->sip_authorization; - } else if (sip->sip_proxy_authorization) { - authorization = sip->sip_proxy_authorization; - } - - if (authorization) { - auth_res = parse_auth(profile, authorization, (char *) sip->sip_request->rq_method_name, tech_pvt->key, strlen(tech_pvt->key)); - } - - if (auth_res != AUTH_OK) { - switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); - nua_respond(nh, SIP_401_UNAUTHORIZED, TAG_END()); - goto done; - } - - if (channel) { - switch_channel_set_variable(channel, "sip_authorized", "true"); - } - } - - if (sip && (status == 401 || status == 407)) { - sip_r_challenge(status, phrase, nua, profile, nh, session, sip, tags); - goto done; - } + switch (msg->message_id) { + case SWITCH_MESSAGE_INDICATE_NOMEDIA:{ + char *uuid; + switch_core_session_t *other_session; + switch_channel_t *other_channel; + char *ip = NULL, *port = NULL; - switch (event) { - case nua_r_shutdown: - case nua_r_get_params: - case nua_r_invite: - case nua_r_unregister: - case nua_r_options: - case nua_i_fork: - case nua_r_info: - case nua_r_bye: - case nua_i_bye: - case nua_r_unsubscribe: - case nua_r_publish: - case nua_r_message: - case nua_r_notify: - case nua_i_notify: - case nua_i_cancel: - case nua_i_error: - case nua_i_active: - case nua_i_ack: - case nua_i_terminated: - case nua_r_set_params: - break; - case nua_r_register: - sip_r_register(status, phrase, nua, profile, nh, sofia_private, sip, tags); - break; - case nua_i_options: - sip_i_options(status, phrase, nua, profile, nh, sofia_private, sip, tags); - break; - case nua_i_invite: - if (!session) { - sip_i_invite(nua, profile, nh, sofia_private, sip, tags); - } - break; - case nua_i_publish: - sip_i_publish(nua, profile, nh, sofia_private, sip, tags); - break; - case nua_i_register: - sip_i_register(nua, profile, nh, sofia_private, sip, tags); - break; - case nua_i_prack: - break; - case nua_i_state: - sip_i_state(status, phrase, nua, profile, nh, sofia_private, sip, tags); - break; - case nua_i_message: - sip_i_message(status, phrase, nua, profile, nh, sofia_private, sip, tags); - break; - case nua_i_info: - sip_i_info(nua, profile, nh, session, sip, tags); - break; - case nua_r_refer: - break; - case nua_i_refer: - if (session) { - sip_i_refer(nua, profile, nh, session, sip, tags); - } - break; - case nua_r_subscribe: - sip_r_subscribe(status, phrase, nua, profile, nh, sofia_private, sip, tags); - break; - case nua_i_subscribe: - sip_i_subscribe(status, phrase, nua, profile, nh, sofia_private, sip, tags); - break; - default: - if (status > 100) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s: unknown event %d: %03d %s\n", nua_event_name(event), event, status, phrase); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s: unknown event %d\n", nua_event_name(event), event); + switch_set_flag_locked(tech_pvt, TFLAG_NOMEDIA); + tech_pvt->local_sdp_str = NULL; + if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE)) + && (other_session = switch_core_session_locate(uuid))) { + other_channel = switch_core_session_get_channel(other_session); + ip = switch_channel_get_variable(other_channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE); + port = switch_channel_get_variable(other_channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE); + switch_core_session_rwunlock(other_session); + if (ip && port) { + sofia_glue_set_local_sdp(tech_pvt, ip, atoi(port), NULL, 1); + } + } + if (!tech_pvt->local_sdp_str) { + sofia_glue_tech_absorb_sdp(tech_pvt); + } + sofia_glue_do_invite(session); } break; - } - - done: - - if (session) { - switch_core_session_rwunlock(session); - } -} - - -static void unreg(sofia_profile_t * profile) -{ - outbound_reg_t *gateway_ptr; - for (gateway_ptr = profile->gateways; gateway_ptr; gateway_ptr = gateway_ptr->next) { - if (gateway_ptr->sofia_private) { - free(gateway_ptr->sofia_private); - nua_handle_bind(gateway_ptr->nh, NULL); - gateway_ptr->sofia_private = NULL; - } - nua_handle_destroy(gateway_ptr->nh); - } -} - -static void check_gateway(sofia_profile_t * profile, time_t now) -{ - outbound_reg_t *gateway_ptr; - for (gateway_ptr = profile->gateways; gateway_ptr; gateway_ptr = gateway_ptr->next) { - int ss_state = nua_callstate_authenticating; - reg_state_t ostate = gateway_ptr->state; - - switch (ostate) { - case REG_STATE_REGISTER: - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "registered %s\n", gateway_ptr->name); - gateway_ptr->expires = now + gateway_ptr->freq; - gateway_ptr->state = REG_STATE_REGED; - break; - case REG_STATE_UNREGED: - if ((gateway_ptr->nh = nua_handle(gateway_ptr->profile->nua, NULL, - NUTAG_URL(gateway_ptr->register_proxy), - SIPTAG_TO_STR(gateway_ptr->register_to), - NUTAG_CALLSTATE_REF(ss_state), SIPTAG_FROM_STR(gateway_ptr->register_from), TAG_END()))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "registering %s\n", gateway_ptr->name); - - if (!(gateway_ptr->sofia_private = malloc(sizeof(*gateway_ptr->sofia_private)))) { - abort(); + case SWITCH_MESSAGE_INDICATE_MEDIA:{ + switch_clear_flag_locked(tech_pvt, TFLAG_NOMEDIA); + tech_pvt->local_sdp_str = NULL; + if (!switch_rtp_ready(tech_pvt->rtp_session)) { + sofia_glue_sofia_glue_tech_set_codecs(tech_pvt); + if ((status = sofia_glue_tech_choose_port(tech_pvt)) != SWITCH_STATUS_SUCCESS) { + return status; } - memset(gateway_ptr->sofia_private, 0, sizeof(*gateway_ptr->sofia_private)); - - gateway_ptr->sofia_private->gateway = gateway_ptr; - nua_handle_bind(gateway_ptr->nh, gateway_ptr->sofia_private); - - nua_register(gateway_ptr->nh, - SIPTAG_FROM_STR(gateway_ptr->register_from), - SIPTAG_CONTACT_STR(gateway_ptr->register_contact), - SIPTAG_EXPIRES_STR(gateway_ptr->expires_str), - NUTAG_REGISTRAR(gateway_ptr->register_proxy), - NUTAG_OUTBOUND("no-options-keepalive"), NUTAG_OUTBOUND("no-validate"), NUTAG_KEEPALIVE(0), TAG_NULL()); - gateway_ptr->retry = now + 10; - gateway_ptr->state = REG_STATE_TRYING; - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error registering %s\n", gateway_ptr->name); - gateway_ptr->state = REG_STATE_FAILED; - } - break; - - case REG_STATE_TRYING: - if (gateway_ptr->retry && now >= gateway_ptr->retry) { - gateway_ptr->state = REG_STATE_UNREGED; - gateway_ptr->retry = 0; } - break; - default: - if (now >= gateway_ptr->expires) { - gateway_ptr->state = REG_STATE_UNREGED; + sofia_glue_set_local_sdp(tech_pvt, NULL, 0, NULL, 1); + sofia_glue_do_invite(session); + while (!switch_rtp_ready(tech_pvt->rtp_session) && switch_channel_get_state(channel) < CS_HANGUP) { + switch_yield(1000); } - break; - } - } - -} - -#define IREG_SECONDS 30 -#define GATEWAY_SECONDS 1 -static void *SWITCH_THREAD_FUNC profile_thread_run(switch_thread_t * thread, void *obj) -{ - sofia_profile_t *profile = (sofia_profile_t *) obj; - switch_memory_pool_t *pool; - sip_alias_node_t *node; - uint32_t ireg_loops = 0; - uint32_t gateway_loops = 0; - switch_core_db_t *db; - switch_event_t *s_event; - - profile->s_root = su_root_create(NULL); - profile->home = su_home_new(sizeof(*profile->home)); - - profile->nua = nua_create(profile->s_root, /* Event loop */ - event_callback, /* Callback for processing events */ - profile, /* Additional data to pass to callback */ - NUTAG_URL(profile->bindurl), NTATAG_UDP_MTU(65536), TAG_END()); /* Last tag should always finish the sequence */ - - nua_set_params(profile->nua, - //NUTAG_EARLY_MEDIA(1), - NUTAG_AUTOANSWER(0), - NUTAG_AUTOALERT(0), - NUTAG_ALLOW("REGISTER"), - NUTAG_ALLOW("REFER"), - NUTAG_ALLOW("INFO"), - TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW("PUBLISH")), - TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW("NOTIFY")), - TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW("SUBSCRIBE")), - TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ENABLEMESSAGE(1)), - TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW_EVENTS("presence")), - TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW_EVENTS("presence.winfo")), - SIPTAG_SUPPORTED_STR("100rel, precondition"), SIPTAG_USER_AGENT_STR(SOFIA_USER_AGENT), TAG_END()); - - - for (node = profile->aliases; node; node = node->next) { - node->nua = nua_create(profile->s_root, /* Event loop */ - event_callback, /* Callback for processing events */ - profile, /* Additional data to pass to callback */ - NUTAG_URL(node->url), TAG_END()); /* Last tag should always finish the sequence */ - - nua_set_params(node->nua, - NUTAG_EARLY_MEDIA(1), - NUTAG_AUTOANSWER(0), - NUTAG_AUTOALERT(0), - NUTAG_ALLOW("REGISTER"), - NUTAG_ALLOW("REFER"), - NUTAG_ALLOW("INFO"), - TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW("PUBLISH")), - TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ENABLEMESSAGE(1)), - SIPTAG_SUPPORTED_STR("100rel, precondition"), SIPTAG_USER_AGENT_STR(SOFIA_USER_AGENT), TAG_END()); - - } - - - if ((db = switch_core_db_open_file(profile->dbname))) { - switch_core_db_test_reactive(db, "select contact from sip_registrations", reg_sql); - switch_core_db_test_reactive(db, "select contact from sip_subscriptions", sub_sql); - switch_core_db_test_reactive(db, "select * from sip_authentication", auth_sql); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot Open SQL Database!\n"); - return NULL; - } - - - switch_mutex_init(&profile->ireg_mutex, SWITCH_MUTEX_NESTED, profile->pool); - switch_mutex_init(&profile->gateway_mutex, SWITCH_MUTEX_NESTED, profile->pool); - - ireg_loops = IREG_SECONDS; - gateway_loops = GATEWAY_SECONDS; - - if (switch_event_create(&s_event, SWITCH_EVENT_PUBLISH) == SWITCH_STATUS_SUCCESS) { - switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "service", "_sip._udp"); - switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "port", "%d", profile->sip_port); - switch_event_fire(&s_event); - } - - if (switch_event_create(&s_event, SWITCH_EVENT_PUBLISH) == SWITCH_STATUS_SUCCESS) { - switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "service", "_sip._tcp"); - switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "port", "%d", profile->sip_port); - switch_event_fire(&s_event); - } - - if (switch_event_create(&s_event, SWITCH_EVENT_PUBLISH) == SWITCH_STATUS_SUCCESS) { - switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "service", "_sip._sctp"); - switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "port", "%d", profile->sip_port); - switch_event_fire(&s_event); - } - - add_profile(profile->name, profile); - - if (profile->pflags & PFLAG_PRESENCE) { - establish_presence(profile); - } - - while (globals.running == 1) { - if (++ireg_loops >= IREG_SECONDS) { - check_expire(db, profile, time(NULL)); - ireg_loops = 0; } + break; - if (++gateway_loops >= GATEWAY_SECONDS) { - check_gateway(profile, time(NULL)); - gateway_loops = 0; + case SWITCH_MESSAGE_INDICATE_HOLD:{ + switch_set_flag_locked(tech_pvt, TFLAG_SIP_HOLD); + sofia_glue_do_invite(session); } + break; - su_root_step(profile->s_root, 1000); - } - - switch_core_db_close(db); - unreg(profile); - su_home_unref(profile->home); - - - if (switch_event_create(&s_event, SWITCH_EVENT_UNPUBLISH) == SWITCH_STATUS_SUCCESS) { - switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "service", "_sip._udp"); - switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "port", "%d", profile->sip_port); - switch_event_fire(&s_event); - } - - su_root_destroy(profile->s_root); - pool = profile->pool; - switch_core_destroy_memory_pool(&pool); - switch_mutex_lock(globals.mutex); - globals.running = 0; - switch_mutex_unlock(globals.mutex); - - return NULL; -} - -static void launch_profile_thread(sofia_profile_t * profile) -{ - switch_thread_t *thread; - switch_threadattr_t *thd_attr = NULL; - - switch_threadattr_create(&thd_attr, profile->pool); - switch_threadattr_detach_set(thd_attr, 1); - switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE); - switch_thread_create(&thread, thd_attr, profile_thread_run, profile, profile->pool); -} - - - -static switch_status_t config_sofia(int reload) -{ - char *cf = "sofia.conf"; - switch_xml_t cfg, xml = NULL, xprofile, param, settings, profiles, gateway_tag, gateways_tag; - switch_status_t status = SWITCH_STATUS_SUCCESS; - sofia_profile_t *profile = NULL; - char url[512] = ""; - switch_mutex_lock(globals.mutex); - globals.running = 1; - switch_mutex_unlock(globals.mutex); - - if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open of %s failed\n", cf); - status = SWITCH_STATUS_FALSE; - goto done; - } - - if ((settings = switch_xml_child(cfg, "global_settings"))) { - for (param = switch_xml_child(settings, "param"); param; param = param->next) { - char *var = (char *) switch_xml_attr_soft(param, "name"); - char *val = (char *) switch_xml_attr_soft(param, "value"); - if (!strcasecmp(var, "log-level")) { - su_log_set_level(NULL, atoi(val)); - } else if (!strcasecmp(var, "log-level-trace")) { - su_log_set_level(tport_log, atoi(val)); - } + case SWITCH_MESSAGE_INDICATE_UNHOLD:{ + switch_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD); + sofia_glue_do_invite(session); } - } - - if ((profiles = switch_xml_child(cfg, "profiles"))) { - for (xprofile = switch_xml_child(profiles, "profile"); xprofile; xprofile = xprofile->next) { - if (!(settings = switch_xml_child(xprofile, "settings"))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No Settings, check the new config!\n"); - } else { - char *xprofilename = (char *) switch_xml_attr_soft(xprofile, "name"); - switch_memory_pool_t *pool = NULL; - - - /* Setup the pool */ - if ((status = switch_core_new_memory_pool(&pool)) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n"); - goto done; - } - - if (!(profile = (sofia_profile_t *) switch_core_alloc(pool, sizeof(*profile)))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n"); - goto done; - } - - if (!xprofilename) { - xprofilename = "unnamed"; - } - - profile->pool = pool; - - profile->name = switch_core_strdup(profile->pool, xprofilename); - snprintf(url, sizeof(url), "sofia_reg_%s", xprofilename); - profile->dbname = switch_core_strdup(profile->pool, url); - switch_core_hash_init(&profile->chat_hash, profile->pool); - - profile->dtmf_duration = 100; - profile->codec_ms = 20; - - for (param = switch_xml_child(settings, "param"); param; param = param->next) { - char *var = (char *) switch_xml_attr_soft(param, "name"); - char *val = (char *) switch_xml_attr_soft(param, "value"); - - if (!strcasecmp(var, "debug")) { - profile->debug = atoi(val); - } else if (!strcasecmp(var, "use-rtp-timer") && switch_true(val)) { - switch_set_flag(profile, TFLAG_TIMER); - } else if (!strcasecmp(var, "inbound-no-media") && switch_true(val)) { - switch_set_flag(profile, TFLAG_INB_NOMEDIA); - } else if (!strcasecmp(var, "inbound-late-negotiation") && switch_true(val)) { - switch_set_flag(profile, TFLAG_LATE_NEGOTIATION); - } else if (!strcasecmp(var, "rfc2833-pt")) { - profile->te = (switch_payload_t) atoi(val); - } else if (!strcasecmp(var, "cng-pt")) { - profile->cng_pt = (switch_payload_t) atoi(val); - } else if (!strcasecmp(var, "sip-port")) { - profile->sip_port = atoi(val); - } else if (!strcasecmp(var, "vad")) { - if (!strcasecmp(val, "in")) { - switch_set_flag(profile, TFLAG_VAD_IN); - } else if (!strcasecmp(val, "out")) { - switch_set_flag(profile, TFLAG_VAD_OUT); - } else if (!strcasecmp(val, "both")) { - switch_set_flag(profile, TFLAG_VAD_IN); - switch_set_flag(profile, TFLAG_VAD_OUT); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invald option %s for VAD\n", val); - } - } else if (!strcasecmp(var, "ext-rtp-ip")) { - profile->extrtpip = switch_core_strdup(profile->pool, strcasecmp(val, "auto") ? val : globals.guess_ip); - } else if (!strcasecmp(var, "rtp-ip")) { - profile->rtpip = switch_core_strdup(profile->pool, strcasecmp(val, "auto") ? val : globals.guess_ip); - } else if (!strcasecmp(var, "sip-ip")) { - profile->sipip = switch_core_strdup(profile->pool, strcasecmp(val, "auto") ? val : globals.guess_ip); - } else if (!strcasecmp(var, "ext-sip-ip")) { - if (!strcasecmp(val, "auto")) { - profile->extsipip = switch_core_strdup(profile->pool, globals.guess_ip); - } else { - char *ip = NULL; - switch_port_t port = 0; - if (sofia_ext_address_lookup(&ip, &port, val, profile->pool) == SWITCH_STATUS_SUCCESS) { - - if (ip) { - profile->extsipip = switch_core_strdup(profile->pool, ip); - } - } - } - - } else if (!strcasecmp(var, "sip-domain")) { - profile->sipdomain = switch_core_strdup(profile->pool, val); - } else if (!strcasecmp(var, "rtp-timer-name")) { - profile->timer_name = switch_core_strdup(profile->pool, val); - } else if (!strcasecmp(var, "manage-presence")) { - if (switch_true(val)) { - profile->pflags |= PFLAG_PRESENCE; - } - } else if (!strcasecmp(var, "pass-rfc2833")) { - if (switch_true(val)) { - profile->pflags |= PFLAG_PASS_RFC2833; - } - } else if (!strcasecmp(var, "disable-transcoding")) { - if (switch_true(val)) { - profile->pflags |= PFLAG_DISABLE_TRANSCODING; - } - } else if (!strcasecmp(var, "auth-calls")) { - if (switch_true(val)) { - profile->pflags |= PFLAG_AUTH_CALLS; - } - } else if (!strcasecmp(var, "nonce-ttl")) { - profile->nonce_ttl = atoi(val); - } else if (!strcasecmp(var, "accept-blind-reg")) { - if (switch_true(val)) { - profile->pflags |= PFLAG_BLIND_REG; - } - } else if (!strcasecmp(var, "auth-all-packets")) { - if (switch_true(val)) { - profile->pflags |= PFLAG_AUTH_ALL; - } - } else if (!strcasecmp(var, "full-id-in-dialplan")) { - if (switch_true(val)) { - profile->pflags |= PFLAG_FULL_ID; - } - } else if (!strcasecmp(var, "bitpacking")) { - if (!strcasecmp(val, "aal2")) { - profile->codec_flags = SWITCH_CODEC_FLAG_AAL2; - } - } else if (!strcasecmp(var, "username")) { - profile->username = switch_core_strdup(profile->pool, val); - } else if (!strcasecmp(var, "context")) { - profile->context = switch_core_strdup(profile->pool, val); - } else if (!strcasecmp(var, "alias")) { - sip_alias_node_t *node; - if ((node = switch_core_alloc(profile->pool, sizeof(*node)))) { - if ((node->url = switch_core_strdup(profile->pool, val))) { - node->next = profile->aliases; - profile->aliases = node; - } - } - } else if (!strcasecmp(var, "dialplan")) { - profile->dialplan = switch_core_strdup(profile->pool, val); - } else if (!strcasecmp(var, "max-calls")) { - profile->max_calls = atoi(val); - } else if (!strcasecmp(var, "codec-prefs")) { - profile->codec_string = switch_core_strdup(profile->pool, val); - } else if (!strcasecmp(var, "codec-ms")) { - profile->codec_ms = atoi(val); - } else if (!strcasecmp(var, "dtmf-duration")) { - int dur = atoi(val); - if (dur > 10 && dur < 8000) { - profile->dtmf_duration = dur; - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Duration out of bounds!\n"); - } - } - } - - if (!profile->cng_pt) { - profile->cng_pt = SWITCH_RTP_CNG_PAYLOAD; - } - - if (!profile->sipip) { - profile->sipip = switch_core_strdup(profile->pool, globals.guess_ip); - } - - if (!profile->rtpip) { - profile->rtpip = switch_core_strdup(profile->pool, globals.guess_ip); - } - - if (profile->nonce_ttl < 60) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Setting nonce TTL to 60 seconds\n"); - profile->nonce_ttl = 60; - } - - if (switch_test_flag(profile, TFLAG_TIMER) && !profile->timer_name) { - profile->timer_name = switch_core_strdup(profile->pool, "soft"); - } - - if (!profile->username) { - profile->username = switch_core_strdup(profile->pool, "FreeSWITCH"); - } + break; + case SWITCH_MESSAGE_INDICATE_BRIDGE: - if (!profile->rtpip) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Setting ip to '127.0.0.1'\n"); - profile->rtpip = switch_core_strdup(profile->pool, "127.0.0.1"); - } + if (switch_test_flag(tech_pvt, TFLAG_XFER)) { + switch_clear_flag_locked(tech_pvt, TFLAG_XFER); + if (msg->pointer_arg) { + switch_core_session_t *a_session, *b_session = msg->pointer_arg; - if (!profile->sip_port) { - profile->sip_port = atoi(SOFIA_DEFAULT_PORT); - } + if ((a_session = switch_core_session_locate(tech_pvt->xferto))) { + private_object_t *a_tech_pvt = switch_core_session_get_private(a_session); + private_object_t *b_tech_pvt = switch_core_session_get_private(b_session); - if (!profile->dialplan) { - profile->dialplan = switch_core_strdup(profile->pool, "XML"); - } + switch_set_flag_locked(a_tech_pvt, TFLAG_REINVITE); + a_tech_pvt->remote_sdp_audio_ip = switch_core_session_strdup(a_session, b_tech_pvt->remote_sdp_audio_ip); + a_tech_pvt->remote_sdp_audio_port = b_tech_pvt->remote_sdp_audio_port; + a_tech_pvt->local_sdp_audio_ip = switch_core_session_strdup(a_session, b_tech_pvt->local_sdp_audio_ip); + a_tech_pvt->local_sdp_audio_port = b_tech_pvt->local_sdp_audio_port; + sofia_glue_activate_rtp(a_tech_pvt); - if (!profile->sipdomain) { - profile->sipdomain = switch_core_strdup(profile->pool, profile->sipip); - } - if (profile->extsipip) { - profile->url = switch_core_sprintf(profile->pool, "sip:mod_sofia@%s:%d", profile->extsipip, profile->sip_port); - profile->bindurl = switch_core_sprintf(profile->pool, "%s;maddr=%s", profile->url, profile->sipip); - } else { - profile->url = switch_core_sprintf(profile->pool, "sip:mod_sofia@%s:%d", profile->sipip, profile->sip_port); - profile->bindurl = profile->url; - } - } - if (profile) { - if ((gateways_tag = switch_xml_child(xprofile, "registrations"))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, - "The <registrations> syntax has been discontinued, please see the new syntax in the default configuration examples\n"); + b_tech_pvt->kick = switch_core_session_strdup(b_session, tech_pvt->xferto); + switch_core_session_rwunlock(a_session); } - if ((gateways_tag = switch_xml_child(xprofile, "gateways"))) { - for (gateway_tag = switch_xml_child(gateways_tag, "gateway"); gateway_tag; gateway_tag = gateway_tag->next) { - char *name = (char *) switch_xml_attr_soft(gateway_tag, "name"); - outbound_reg_t *gateway; - - if (switch_strlen_zero(name)) { - name = "anonymous"; - } - - if ((gateway = switch_core_alloc(profile->pool, sizeof(*gateway)))) { - char *scheme = "Digest", - *realm = NULL, - *username = NULL, *password = NULL, *extension = NULL, *proxy = NULL, *context = "default", *expire_seconds = "3600"; - - gateway->pool = profile->pool; - gateway->profile = profile; - gateway->name = switch_core_strdup(gateway->pool, name); - gateway->freq = 0; - - - for (param = switch_xml_child(gateway_tag, "param"); param; param = param->next) { - char *var = (char *) switch_xml_attr_soft(param, "name"); - char *val = (char *) switch_xml_attr_soft(param, "value"); - - if (!strcmp(var, "scheme")) { - scheme = val; - } else if (!strcmp(var, "realm")) { - realm = val; - } else if (!strcmp(var, "username")) { - username = val; - } else if (!strcmp(var, "password")) { - password = val; - } else if (!strcmp(var, "extension")) { - extension = val; - } else if (!strcmp(var, "proxy")) { - proxy = val; - } else if (!strcmp(var, "context")) { - context = val; - } else if (!strcmp(var, "expire-seconds")) { - expire_seconds = val; - } - } - - if (switch_strlen_zero(realm)) { - realm = name; - } - - if (switch_strlen_zero(username)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ERROR: username param is REQUIRED!\n"); - switch_xml_free(xml); - goto skip; - } - - if (switch_strlen_zero(password)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ERROR: password param is REQUIRED!\n"); - switch_xml_free(xml); - goto skip; - } - - if (switch_strlen_zero(extension)) { - extension = username; - } - - if (switch_strlen_zero(proxy)) { - proxy = realm; - } - - gateway->register_scheme = switch_core_strdup(gateway->pool, scheme); - gateway->register_context = switch_core_strdup(gateway->pool, context); - gateway->register_realm = switch_core_strdup(gateway->pool, realm); - gateway->register_username = switch_core_strdup(gateway->pool, username); - gateway->register_password = switch_core_strdup(gateway->pool, password); - gateway->register_from = switch_core_sprintf(gateway->pool, "sip:%s@%s", username, realm); - gateway->register_contact = switch_core_sprintf(gateway->pool, "sip:%s@%s:%d", extension, profile->sipip, profile->sip_port); - - if (!strncasecmp(proxy, "sip:", 4)) { - gateway->register_proxy = switch_core_strdup(gateway->pool, proxy); - gateway->register_to = switch_core_sprintf(gateway->pool, "sip:%s@%s", username, proxy + 4); - } else { - gateway->register_proxy = switch_core_sprintf(gateway->pool, "sip:%s", proxy); - gateway->register_to = switch_core_sprintf(gateway->pool, "sip:%s@%s", username, proxy); - } - - gateway->expires_str = switch_core_strdup(gateway->pool, expire_seconds); - - if ((gateway->freq = atoi(gateway->expires_str)) < 5) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, - "Invalid Freq: %d. Setting Register-Frequency to 3600\n", gateway->freq); - gateway->freq = 3600; - } - gateway->freq -= 2; - - gateway->next = profile->gateways; - profile->gateways = gateway; - - if (find_gateway(gateway->name)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Ignoring duplicate gateway '%s'\n", gateway->name); - } else if (find_gateway(gateway->register_from)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Ignoring duplicate uri '%s'\n", gateway->register_from); - } else if (find_gateway(gateway->register_contact)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Ignoring duplicate contact '%s'\n", gateway->register_from); - } else { - add_gateway(gateway->name, gateway); - add_gateway(gateway->register_from, gateway); - add_gateway(gateway->register_contact, gateway); - } - } - - skip: - assert(gateway_tag); - } - } - if (profile->sipip) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Started Profile %s [%s]\n", profile->name, url); - launch_profile_thread(profile); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Unable to start Profile %s due to no configured sip-ip\n", profile->name); - } - profile = NULL; + msg->pointer_arg = NULL; + return SWITCH_STATUS_FALSE; } } - } - done: - if (xml) { - switch_xml_free(xml); - } - - return status; - -} - -static void event_handler(switch_event_t *event) -{ - char *subclass, *sql; - - if ((subclass = switch_event_get_header(event, "orig-event-subclass")) && !strcasecmp(subclass, MY_EVENT_REGISTER)) { - char *from_user = switch_event_get_header(event, "orig-from-user"); - char *from_host = switch_event_get_header(event, "orig-from-host"); - char *contact_str = switch_event_get_header(event, "orig-contact"); - char *exp_str = switch_event_get_header(event, "orig-expires"); - char *rpid = switch_event_get_header(event, "orig-rpid"); - long expires = (long) time(NULL) + atol(exp_str); - char *profile_name = switch_event_get_header(event, "orig-profile-name"); - sofia_profile_t *profile; - char buf[512]; - - if (!rpid) { - rpid = "unknown"; - } - - if (!profile_name || !(profile = find_profile(profile_name))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Profile\n"); - return; - } - - - if (!find_reg_url(profile, from_user, from_host, buf, sizeof(buf))) { - sql = switch_mprintf("insert into sip_registrations values ('%q','%q','%q','Regestered', '%q', %ld)", - from_user, from_host, contact_str, rpid, expires); - } else { - sql = - switch_mprintf - ("update sip_registrations set contact='%q', rpid='%q', expires=%ld where user='%q' and host='%q'", - contact_str, rpid, expires, from_user, from_host); - - } - - if (sql) { - execute_sql(profile->dbname, sql, profile->ireg_mutex); - switch_safe_free(sql); - sql = NULL; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Propagating registration for %s@%s->%s\n", from_user, from_host, contact_str); - - } - - } -} - - -static switch_status_t chat_send(char *proto, char *from, char *to, char *subject, char *body, char *hint) -{ - char buf[256]; - char *user, *host; - sofia_profile_t *profile; - char *ffrom = NULL; - nua_handle_t *msg_nh; - char *contact; - - if (to && (user = strdup(to))) { - if ((host = strchr(user, '@'))) { - *host++ = '\0'; + if (tech_pvt->rtp_session && switch_test_flag(tech_pvt, TFLAG_TIMER)) { + switch_rtp_clear_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_USE_TIMER); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "De-activate timed RTP!\n"); } - - if (!host || !(profile = find_profile(host))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, - "Chat proto [%s]\nfrom [%s]\nto [%s]\n%s\nInvalid Profile %s\n", proto, from, to, - body ? body : "[no body]", host ? host : "NULL"); - return SWITCH_STATUS_FALSE; + break; + case SWITCH_MESSAGE_INDICATE_UNBRIDGE: + if (tech_pvt->rtp_session && switch_test_flag(tech_pvt, TFLAG_TIMER)) { + switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_USE_TIMER); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Re-activate timed RTP!\n"); } - - if (!find_reg_url(profile, user, host, buf, sizeof(buf))) { - return SWITCH_STATUS_FALSE; + break; + case SWITCH_MESSAGE_INDICATE_REDIRECT: + if (msg->string_arg) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Re-directing to %s\n", msg->string_arg); + nua_respond(tech_pvt->nh, SIP_302_MOVED_TEMPORARILY, SIPTAG_CONTACT_STR(msg->string_arg), TAG_END()); } + break; + case SWITCH_MESSAGE_INDICATE_RINGING: + nua_respond(tech_pvt->nh, SIP_180_RINGING, SIPTAG_CONTACT_STR(tech_pvt->profile->url), TAG_END()); + break; + case SWITCH_MESSAGE_INDICATE_PROGRESS:{ + if (!switch_test_flag(tech_pvt, TFLAG_ANS)) { + switch_set_flag_locked(tech_pvt, TFLAG_EARLY_MEDIA); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Asked to send early media by %s\n", msg->from); - if (!strcmp(proto, SOFIA_CHAT_PROTO)) { - from = hint; - } else { - char *fp, *p, *fu = NULL; + /* Transmit 183 Progress with SDP */ + if (switch_channel_test_flag(channel, CF_NOMEDIA)) { + char *sdp = NULL; + switch_set_flag_locked(tech_pvt, TFLAG_NOMEDIA); + if ((sdp = switch_channel_get_variable(channel, SWITCH_B_SDP_VARIABLE))) { + tech_pvt->local_sdp_str = switch_core_session_strdup(session, sdp); + } + } else { + if (switch_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION)) { + char *r_sdp = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE); + if (sofia_glue_tech_media(tech_pvt, r_sdp) != SWITCH_STATUS_SUCCESS) { + switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "CODEC NEGOTIATION ERROR"); + nua_respond(tech_pvt->nh, SIP_488_NOT_ACCEPTABLE, TAG_END()); + return SWITCH_STATUS_FALSE; + } + switch_clear_flag_locked(tech_pvt, TFLAG_LATE_NEGOTIATION); + } - if (!(fp = strdup(from))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n"); - return SWITCH_STATUS_FALSE; - } + if ((status = sofia_glue_tech_choose_port(tech_pvt)) != SWITCH_STATUS_SUCCESS) { + return status; + } + sofia_glue_set_local_sdp(tech_pvt, NULL, 0, NULL, 0); + sofia_glue_activate_rtp(tech_pvt); + if (tech_pvt->local_sdp_str) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Ring SDP:\n%s\n", tech_pvt->local_sdp_str); + } + } - if ((p = strchr(fp, '@'))) { - *p = '\0'; - fu = strdup(fp); - *p = '+'; + nua_respond(tech_pvt->nh, + SIP_183_SESSION_PROGRESS, + SIPTAG_CONTACT_STR(tech_pvt->profile->url), + SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str), SOATAG_AUDIO_AUX("cn telephone-event"), TAG_END()); } - - ffrom = switch_mprintf("\"%s\" <sip:%s+%s@%s>", fu, proto, fp, profile->name); - from = ffrom; - switch_safe_free(fu); - switch_safe_free(fp); } - - contact = get_url_from_contact(buf, 1); - msg_nh = nua_handle(profile->nua, NULL, SIPTAG_FROM_STR(from), NUTAG_URL(contact), SIPTAG_TO_STR(buf), // if this cries, add contact here too, change the 1 to 0 and omit the safe_free - SIPTAG_CONTACT_STR(profile->url), TAG_END()); - - switch_safe_free(contact); - - - nua_message(msg_nh, SIPTAG_CONTENT_TYPE_STR("text/html"), SIPTAG_PAYLOAD_STR(body), TAG_END()); - - - switch_safe_free(ffrom); - free(user); + break; + default: + break; } return SWITCH_STATUS_SUCCESS; } -static void cancel_presence(void) +static switch_status_t sofia_receive_event(switch_core_session_t *session, switch_event_t *event) { - char *sql, *errmsg = NULL; - switch_core_db_t *db; - sofia_profile_t *profile; - switch_hash_index_t *hi; - void *val; + switch_channel_t *channel; + struct private_object *tech_pvt; + char *body; + nua_handle_t *msg_nh; - if ((sql = switch_mprintf("select 0,'unavailable','unavailable',* from sip_subscriptions where event='presence'"))) { - switch_mutex_lock(globals.hash_mutex); - for (hi = switch_hash_first(switch_hash_pool_get(globals.profile_hash), globals.profile_hash); hi; hi = switch_hash_next(hi)) { - switch_hash_this(hi, NULL, NULL, &val); - profile = (sofia_profile_t *) val; - if (!(profile->pflags & PFLAG_PRESENCE)) { - continue; - } + channel = switch_core_session_get_channel(session); + assert(channel != NULL); - if (!(db = switch_core_db_open_file(profile->dbname))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname); - continue; - } - switch_mutex_lock(profile->ireg_mutex); - switch_core_db_exec(db, sql, sub_callback, profile, &errmsg); - switch_mutex_unlock(profile->ireg_mutex); - switch_core_db_close(db); - } - switch_safe_free(sql); - } - switch_mutex_unlock(globals.hash_mutex); -} + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); -static void establish_presence(sofia_profile_t * profile) -{ - char *sql, *errmsg = NULL; - switch_core_db_t *db; - if (!(db = switch_core_db_open_file(profile->dbname))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname); - return; + if (!(body = switch_event_get_body(event))) { + body = ""; } - if ((sql = switch_mprintf("select user,host,'Registered','unknown','' from sip_registrations"))) { - switch_mutex_lock(profile->ireg_mutex); - switch_core_db_exec(db, sql, resub_callback, profile, &errmsg); - switch_mutex_unlock(profile->ireg_mutex); - switch_safe_free(sql); - } + if (tech_pvt->hash_key) { + msg_nh = nua_handle(tech_pvt->profile->nua, NULL, + SIPTAG_FROM_STR(tech_pvt->chat_from), + NUTAG_URL(tech_pvt->chat_to), SIPTAG_TO_STR(tech_pvt->chat_to), SIPTAG_CONTACT_STR(tech_pvt->profile->url), TAG_END()); - if ((sql = switch_mprintf("select sub_to_user,sub_to_host,'Online','unknown',proto from sip_subscriptions " - "where proto='ext' or proto='user' or proto='conf'"))) { - switch_mutex_lock(profile->ireg_mutex); - switch_core_db_exec(db, sql, resub_callback, profile, &errmsg); - switch_mutex_unlock(profile->ireg_mutex); - switch_safe_free(sql); + nua_message(msg_nh, SIPTAG_CONTENT_TYPE_STR("text/html"), SIPTAG_PAYLOAD_STR(body), TAG_END()); } - switch_core_db_close(db); - + return SWITCH_STATUS_SUCCESS; } +static const switch_io_routines_t sofia_io_routines = { + /*.outgoing_channel */ sofia_outgoing_channel, + /*.answer_channel */ sofia_answer_channel, + /*.read_frame */ sofia_read_frame, + /*.write_frame */ sofia_write_frame, + /*.kill_channel */ sofia_kill_channel, + /*.waitfor_read */ sofia_waitfor_read, + /*.waitfor_read */ sofia_waitfor_write, + /*.send_dtmf */ sofia_send_dtmf, + /*.receive_message */ sofia_receive_message, + /*.receive_event */ sofia_receive_event +}; + +static const switch_state_handler_table_t sofia_event_handlers = { + /*.on_init */ sofia_on_init, + /*.on_ring */ sofia_on_ring, + /*.on_execute */ sofia_on_execute, + /*.on_hangup */ sofia_on_hangup, + /*.on_loopback */ sofia_on_loopback, + /*.on_transmit */ sofia_on_transmit +}; +const switch_endpoint_interface_t sofia_endpoint_interface = { + /*.interface_name */ "sofia", + /*.io_routines */ &sofia_io_routines, + /*.event_handlers */ &sofia_event_handlers, + /*.private */ NULL, + /*.next */ NULL +}; -static char *translate_rpid(char *in, char *ext) -{ - char *r = NULL; +static const switch_chat_interface_t sofia_chat_interface = { + /*.name */ SOFIA_CHAT_PROTO, + /*.sofia_presence_chat_send */ sofia_presence_chat_send, - if (in && (strstr(in, "null") || strstr(in, "NULL"))) { - in = NULL; - } +}; - if (!in) { - in = ext; - } +static switch_status_t sofia_manage(char *relative_oid, switch_management_action_t action, char *data, switch_size_t datalen) +{ + return SWITCH_STATUS_SUCCESS; +} - if (!in) { - return NULL; - } +static const switch_management_interface_t sofia_management_interface = { + /*.relative_oid */ "1", + /*.management_function */ sofia_manage +}; - if (!strcasecmp(in, "dnd")) { - r = "busy"; - } +static const switch_loadable_module_interface_t sofia_module_interface = { + /*.module_name */ modname, + /*.endpoint_interface */ &sofia_endpoint_interface, + /*.timer_interface */ NULL, + /*.dialplan_interface */ NULL, + /*.codec_interface */ NULL, + /*.application_interface */ NULL, + /*.api_interface */ NULL, + /*.file_interface */ NULL, + /*.speech_interface */ NULL, + /*.directory_interface */ NULL, + /*.chat_interface */ &sofia_chat_interface, + /*.say_interface */ NULL, + /*.asr_interface */ NULL, + /*.management_interface */ &sofia_management_interface +}; - if (ext && !strcasecmp(ext, "away")) { - r = "idle"; - } - return r; -} -static void pres_event_handler(switch_event_t *event) +static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session, + switch_caller_profile_t *outbound_profile, switch_core_session_t **new_session, + switch_memory_pool_t **pool) { + switch_call_cause_t cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; + switch_core_session_t *nsession; + char *data, *profile_name, *dest; sofia_profile_t *profile; - switch_hash_index_t *hi; - void *val; - char *from = switch_event_get_header(event, "from"); - char *proto = switch_event_get_header(event, "proto"); - char *rpid = switch_event_get_header(event, "rpid"); - char *status = switch_event_get_header(event, "status"); - char *event_type = switch_event_get_header(event, "event_type"); - //char *event_subtype = switch_event_get_header(event, "event_subtype"); - char *sql = NULL; - char *euser = NULL, *user = NULL, *host = NULL; - char *errmsg; - switch_core_db_t *db; - + switch_caller_profile_t *caller_profile = NULL; + private_object_t *tech_pvt = NULL; + switch_channel_t *nchannel; + char *host, *dest_to; - if (rpid && !strcasecmp(rpid, "n/a")) { - rpid = NULL; - } + *new_session = NULL; - if (status && !strcasecmp(status, "n/a")) { - status = NULL; + if (!(nsession = switch_core_session_request(&sofia_endpoint_interface, pool))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error Creating Session\n"); + goto done; } - if (rpid) { - rpid = translate_rpid(rpid, status); + if (!(tech_pvt = (struct private_object *) switch_core_session_alloc(nsession, sizeof(*tech_pvt)))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error Creating Session\n"); + sofia_glue_terminate_session(&nsession, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__); + goto done; } - if (!status) { - status = "Available"; - - if (rpid) { - if (!strcasecmp(rpid, "busy")) { - status = "Busy"; - } else if (!strcasecmp(rpid, "unavailable")) { - status = "Idle"; - } else if (!strcasecmp(rpid, "away")) { - status = "Idle"; - } - } - } + data = switch_core_session_strdup(nsession, outbound_profile->destination_number); + profile_name = data; - if (!rpid) { - rpid = "unknown"; - } + if (!strncasecmp(profile_name, "gateway", 7)) { + char *gw; + outbound_reg_t *gateway_ptr; - if (event->event_id == SWITCH_EVENT_ROSTER) { - if (from) { - sql = switch_mprintf("select 1,'%q','%q',* from sip_subscriptions where event='presence' and full_from like '%%%q%%'", status, rpid, from); - } else { - sql = switch_mprintf("select 1,'%q','%q',* from sip_subscriptions where event='presence'", status, rpid); + if (!(gw = strchr(profile_name, '/'))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid URL\n"); + sofia_glue_terminate_session(&nsession, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__); + cause = SWITCH_CAUSE_INVALID_NUMBER_FORMAT; + goto done; } - switch_mutex_lock(globals.hash_mutex); - for (hi = switch_hash_first(switch_hash_pool_get(globals.profile_hash), globals.profile_hash); hi; hi = switch_hash_next(hi)) { - switch_hash_this(hi, NULL, NULL, &val); - profile = (sofia_profile_t *) val; - if (!(profile->pflags & PFLAG_PRESENCE)) { - continue; - } - - if (sql) { - if (!(db = switch_core_db_open_file(profile->dbname))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname); - continue; - } - switch_mutex_lock(profile->ireg_mutex); - switch_core_db_exec(db, sql, sub_callback, profile, &errmsg); - switch_mutex_unlock(profile->ireg_mutex); - switch_core_db_close(db); - } + *gw++ = '\0'; + if (!(dest = strchr(gw, '/'))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid URL\n"); + sofia_glue_terminate_session(&nsession, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__); + cause = SWITCH_CAUSE_INVALID_NUMBER_FORMAT; + goto done; } - switch_mutex_unlock(globals.hash_mutex); - - return; - } - if (switch_strlen_zero(event_type)) { - event_type = "presence"; - } + *dest++ = '\0'; - if ((user = strdup(from))) { - if ((host = strchr(user, '@'))) { - char *p; - *host++ = '\0'; - if ((p = strchr(host, '/'))) { - *p = '\0'; - } - } else { - switch_safe_free(user); - return; + if (!(gateway_ptr = sofia_reg_find_gateway(gw))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Gateway\n"); + sofia_glue_terminate_session(&nsession, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__); + cause = SWITCH_CAUSE_INVALID_NUMBER_FORMAT; + goto done; } - if ((euser = strchr(user, '+'))) { - euser++; + + profile = gateway_ptr->profile; + tech_pvt->from_str = switch_core_session_strdup(nsession, gateway_ptr->register_from); + if (!strchr(dest, '@')) { + tech_pvt->dest = switch_core_session_sprintf(nsession, "sip:%s@%s", dest, gateway_ptr->register_proxy + 4); } else { - euser = user; + tech_pvt->dest = switch_core_session_sprintf(nsession, "sip:%s", dest); } - } else { - return; - } + if (!(dest = strchr(profile_name, '/'))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid URL\n"); + sofia_glue_terminate_session(&nsession, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__); + cause = SWITCH_CAUSE_INVALID_NUMBER_FORMAT; + goto done; + } + *dest++ = '\0'; + if (!(profile = sofia_glue_find_profile(profile_name))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Profile\n"); + sofia_glue_terminate_session(&nsession, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__); + cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; + goto done; + } - switch (event->event_id) { - case SWITCH_EVENT_PRESENCE_PROBE: - if (proto) { - switch_core_db_t *db = NULL; - char *to = switch_event_get_header(event, "to"); - char *user, *euser, *host, *p; + if ((dest_to = strchr(dest, '^'))) { + *dest_to++ = '\0'; + tech_pvt->dest_to = switch_core_session_alloc(nsession, strlen(dest_to) + 5); + snprintf(tech_pvt->dest_to, strlen(dest_to) + 5, "sip:%s", dest_to); + } - if (!to || !(user = strdup(to))) { - return; - } + if ((host = strchr(dest, '%'))) { + char buf[128]; + *host = '@'; + tech_pvt->e_dest = switch_core_session_strdup(nsession, dest); + *host++ = '\0'; + if (sofia_reg_find_reg_url(profile, dest, host, buf, sizeof(buf))) { + tech_pvt->dest = switch_core_session_strdup(nsession, buf); - if ((host = strchr(user, '@'))) { - *host++ = '\0'; - } - euser = user; - if ((p = strchr(euser, '+'))) { - euser = (p + 1); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot locate registered user %s@%s\n", dest, host); + cause = SWITCH_CAUSE_NO_ROUTE_DESTINATION; + sofia_glue_terminate_session(&nsession, cause, __LINE__); + goto done; } + } else if (!strchr(dest, '@')) { + char buf[128]; + tech_pvt->e_dest = switch_core_session_strdup(nsession, dest); + if (sofia_reg_find_reg_url(profile, dest, profile_name, buf, sizeof(buf))) { + tech_pvt->dest = switch_core_session_strdup(nsession, buf); - if (euser && host && - (sql = - switch_mprintf("select user,host,status,rpid,'' from sip_registrations where user='%q' and host='%q'", - euser, host)) && (profile = find_profile(host))) { - if (!(db = switch_core_db_open_file(profile->dbname))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname); - switch_safe_free(user); - switch_safe_free(sql); - return; - } - - switch_mutex_lock(profile->ireg_mutex); - switch_core_db_exec(db, sql, resub_callback, profile, &errmsg); - switch_mutex_unlock(profile->ireg_mutex); - switch_safe_free(sql); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot locate registered user %s@%s\n", dest, profile_name); + cause = SWITCH_CAUSE_NO_ROUTE_DESTINATION; + sofia_glue_terminate_session(&nsession, cause, __LINE__); + goto done; } - switch_safe_free(user); - switch_core_db_close(db); + } else { + tech_pvt->dest = switch_core_session_alloc(nsession, strlen(dest) + 5); + snprintf(tech_pvt->dest, strlen(dest) + 5, "sip:%s", dest); } - return; - case SWITCH_EVENT_PRESENCE_IN: - sql = - switch_mprintf - ("select 1,'%q','%q',* from sip_subscriptions where proto='%q' and event='%q' and sub_to_user='%q' and sub_to_host='%q'", - status, rpid, proto, event_type, euser, host); - break; - case SWITCH_EVENT_PRESENCE_OUT: - sql = - switch_mprintf - ("select 0,'%q','%q',* from sip_subscriptions where proto='%q' and event='%q' and sub_to_user='%q' and sub_to_host='%q'", - status, rpid, proto, event_type, euser, host); - break; - default: - break; } - switch_mutex_lock(globals.hash_mutex); - for (hi = switch_hash_first(switch_hash_pool_get(globals.profile_hash), globals.profile_hash); hi; hi = switch_hash_next(hi)) { - switch_hash_this(hi, NULL, NULL, &val); - profile = (sofia_profile_t *) val; - if (!(profile->pflags & PFLAG_PRESENCE)) { - continue; - } + if (!tech_pvt->dest_to) { + tech_pvt->dest_to = tech_pvt->dest; + } - if (sql) { - if (!(db = switch_core_db_open_file(profile->dbname))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname); - continue; - } - switch_mutex_lock(profile->ireg_mutex); - switch_core_db_exec(db, sql, sub_callback, profile, &errmsg); - switch_mutex_unlock(profile->ireg_mutex); + sofia_glue_attach_private(nsession, profile, tech_pvt, dest); - switch_core_db_close(db); + nchannel = switch_core_session_get_channel(nsession); + caller_profile = switch_caller_profile_clone(nsession, outbound_profile); + switch_channel_set_caller_profile(nchannel, caller_profile); + switch_channel_set_flag(nchannel, CF_OUTBOUND); + switch_set_flag_locked(tech_pvt, TFLAG_OUTBOUND); + switch_channel_set_state(nchannel, CS_INIT); + *new_session = nsession; + cause = SWITCH_CAUSE_SUCCESS; + if (session) { + //char *val; + //switch_channel_t *channel = switch_core_session_get_channel(session); + switch_ivr_transfer_variable(session, nsession, SOFIA_REPLACES_HEADER); + switch_ivr_transfer_variable(session, nsession, SOFIA_SIP_HEADER_PREFIX_T); + if (switch_core_session_compare(session, nsession)) { + /* It's another sofia channel! so lets cache what they use as a pt for telephone event so + we can keep it the same + */ + private_object_t *ctech_pvt; + ctech_pvt = switch_core_session_get_private(session); + assert(ctech_pvt != NULL); + tech_pvt->bte = ctech_pvt->te; + tech_pvt->bcng_pt = ctech_pvt->cng_pt; } } - switch_mutex_unlock(globals.hash_mutex); - switch_safe_free(sql); - switch_safe_free(user); + done: + return cause; } - SWITCH_MOD_DECLARE(switch_status_t) switch_module_load(const switch_loadable_module_interface_t **module_interface, char *filename) { @@ -5789,43 +991,39 @@ return SWITCH_STATUS_TERM; } - memset(&globals, 0, sizeof(globals)); - switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, module_pool); + memset(&mod_sofia_globals, 0, sizeof(mod_sofia_globals)); + switch_mutex_init(&mod_sofia_globals.mutex, SWITCH_MUTEX_NESTED, module_pool); - switch_find_local_ip(globals.guess_ip, sizeof(globals.guess_ip), AF_INET); + switch_find_local_ip(mod_sofia_globals.guess_ip, sizeof(mod_sofia_globals.guess_ip), AF_INET); if (switch_event_bind((char *) modname, SWITCH_EVENT_CUSTOM, MULTICAST_EVENT, event_handler, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n"); return SWITCH_STATUS_TERM; } - su_init(); - su_log_redirect(NULL, logger, NULL); - su_log_redirect(tport_log, logger, NULL); - - switch_core_hash_init(&globals.profile_hash, module_pool); - switch_core_hash_init(&globals.gateway_hash, module_pool); - switch_mutex_init(&globals.hash_mutex, SWITCH_MUTEX_NESTED, module_pool); + switch_core_hash_init(&mod_sofia_globals.profile_hash, module_pool); + switch_core_hash_init(&mod_sofia_globals.gateway_hash, module_pool); + switch_mutex_init(&mod_sofia_globals.hash_mutex, SWITCH_MUTEX_NESTED, module_pool); config_sofia(0); - if (switch_event_bind((char *) modname, SWITCH_EVENT_PRESENCE_IN, SWITCH_EVENT_SUBCLASS_ANY, pres_event_handler, NULL) != SWITCH_STATUS_SUCCESS) { + if (switch_event_bind((char *) modname, SWITCH_EVENT_PRESENCE_IN, SWITCH_EVENT_SUBCLASS_ANY, sofia_presence_event_handler, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n"); return SWITCH_STATUS_GENERR; } - if (switch_event_bind((char *) modname, SWITCH_EVENT_PRESENCE_OUT, SWITCH_EVENT_SUBCLASS_ANY, pres_event_handler, NULL) != SWITCH_STATUS_SUCCESS) { + if (switch_event_bind((char *) modname, SWITCH_EVENT_PRESENCE_OUT, SWITCH_EVENT_SUBCLASS_ANY, sofia_presence_event_handler, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n"); return SWITCH_STATUS_GENERR; } - if (switch_event_bind((char *) modname, SWITCH_EVENT_PRESENCE_PROBE, SWITCH_EVENT_SUBCLASS_ANY, pres_event_handler, NULL) != SWITCH_STATUS_SUCCESS) { + if (switch_event_bind((char *) modname, SWITCH_EVENT_PRESENCE_PROBE, SWITCH_EVENT_SUBCLASS_ANY, sofia_presence_event_handler, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n"); return SWITCH_STATUS_GENERR; } - if (switch_event_bind((char *) modname, SWITCH_EVENT_ROSTER, SWITCH_EVENT_SUBCLASS_ANY, pres_event_handler, NULL) != SWITCH_STATUS_SUCCESS) { + if (switch_event_bind((char *) modname, SWITCH_EVENT_ROSTER, SWITCH_EVENT_SUBCLASS_ANY, sofia_presence_event_handler, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n"); return SWITCH_STATUS_GENERR; } @@ -5841,15 +1039,15 @@ SWITCH_MOD_DECLARE(switch_status_t) switch_module_shutdown(void) { - cancel_presence(); + sofia_presence_cancel(); - switch_mutex_lock(globals.mutex); - if (globals.running == 1) { - globals.running = -1; + switch_mutex_lock(mod_sofia_globals.mutex); + if (mod_sofia_globals.running == 1) { + mod_sofia_globals.running = -1; } - switch_mutex_unlock(globals.mutex); + switch_mutex_unlock(mod_sofia_globals.mutex); - while (globals.running) { + while (mod_sofia_globals.running) { switch_yield(1000); } @@ -5868,3 +1066,4 @@ * For VIM: * vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab: */ + Modified: freeswitch/branches/mikej/sofiasip-upgrade/src/mod/endpoints/mod_sofia/mod_sofia.vcproj ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/src/mod/endpoints/mod_sofia/mod_sofia.vcproj (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/src/mod/endpoints/mod_sofia/mod_sofia.vcproj Sun Apr 1 15:42:32 2007 @@ -194,16 +194,19 @@ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > - <File - RelativePath=".\mod_sofia.c" - > - </File> + <File RelativePath=".\mod_sofia.c"></File> + <File RelativePath=".\sofia_reg.c"></File> + <File RelativePath=".\sofia_glue.c"></File> + <File RelativePath=".\sofia_presence.c"></File> + <File RelativePath=".\sofia.c"></File> + </Filter> <Filter Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > + <File RelativePath=".\mod_sofia.h"></File> </Filter> <Filter Name="Resource Files" Modified: freeswitch/branches/mikej/sofiasip-upgrade/src/mod/say/mod_say_en/mod_say_en.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/src/mod/say/mod_say_en/mod_say_en.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/src/mod/say/mod_say_en/mod_say_en.c Sun Apr 1 15:42:32 2007 @@ -510,9 +510,15 @@ return SWITCH_STATUS_FALSE; } +static const switch_say_interface_t es_say_interface = { + /*.name */ "es", + /*.say_function */ en_say, +}; + static const switch_say_interface_t en_say_interface = { /*.name */ "en", /*.say_function */ en_say, + /*.next */ &es_say_interface }; static switch_loadable_module_interface_t say_en_module_interface = { Modified: freeswitch/branches/mikej/sofiasip-upgrade/src/switch_channel.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/src/switch_channel.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/src/switch_channel.c Sun Apr 1 15:42:32 2007 @@ -396,6 +396,42 @@ return switch_test_flag(channel, flags) ? 1 : 0; } +SWITCH_DECLARE(switch_bool_t) switch_channel_set_flag_partner(switch_channel_t *channel, switch_channel_flag_t flags) +{ + char *uuid; + + assert(channel != NULL); + + if ((uuid = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE))) { + switch_core_session_t *session; + if ((session = switch_core_session_locate(uuid))) { + switch_channel_set_flag(switch_core_session_get_channel(session), flags); + switch_core_session_rwunlock(session); + return SWITCH_TRUE; + } + } + + return SWITCH_FALSE; +} + +SWITCH_DECLARE(switch_bool_t) switch_channel_clear_flag_partner(switch_channel_t *channel, switch_channel_flag_t flags) +{ + char *uuid; + + assert(channel != NULL); + + if ((uuid = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE))) { + switch_core_session_t *session; + if ((session = switch_core_session_locate(uuid))) { + switch_channel_clear_flag(switch_core_session_get_channel(session), flags); + switch_core_session_rwunlock(session); + return SWITCH_TRUE; + } + } + + return SWITCH_FALSE; +} + SWITCH_DECLARE(void) switch_channel_set_flag(switch_channel_t *channel, switch_channel_flag_t flags) { assert(channel != NULL); @@ -431,9 +467,20 @@ SWITCH_DECLARE(uint8_t) switch_channel_ready(switch_channel_t *channel) { + uint8_t ret = 0; + assert(channel != NULL); + + if (!channel->hangup_cause && channel->state > CS_RING && channel->state < CS_HANGUP && !switch_test_flag(channel, CF_TRANSFER)) { + ret++; + } + + if (switch_test_flag(channel, CF_BREAK)) { + switch_clear_flag_locked(channel, CF_BREAK); + ret = (uint8_t) 0; + } - return (!channel->hangup_cause && channel->state > CS_RING && channel->state < CS_HANGUP && !switch_test_flag(channel, CF_TRANSFER)) ? 1 : 0; + return ret; } static const char *state_names[] = { Modified: freeswitch/branches/mikej/sofiasip-upgrade/src/switch_core.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/src/switch_core.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/src/switch_core.c Sun Apr 1 15:42:32 2007 @@ -482,6 +482,7 @@ assert(runtime.memory_pool != NULL); switch_log_init(runtime.memory_pool); switch_event_init(runtime.memory_pool); + switch_core_sqldb_start(runtime.memory_pool); switch_rtp_init(runtime.memory_pool); runtime.running = 1; Modified: freeswitch/branches/mikej/sofiasip-upgrade/src/switch_core_io.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/src/switch_core_io.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/src/switch_core_io.c Sun Apr 1 15:42:32 2007 @@ -133,6 +133,15 @@ case SWITCH_STATUS_NOOP: status = SWITCH_STATUS_SUCCESS; break; + case SWITCH_STATUS_BREAK: + memset(session->raw_read_frame.data, 255, read_frame->codec->implementation->bytes_per_frame); + session->raw_read_frame.datalen = read_frame->codec->implementation->bytes_per_frame; + session->raw_read_frame.samples = session->raw_read_frame.datalen / sizeof(int16_t); + session->raw_read_frame.timestamp = read_frame->timestamp; + session->raw_read_frame.rate = read_frame->rate; + read_frame = &session->raw_read_frame; + status = SWITCH_STATUS_SUCCESS; + break; default: switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Codec %s decoder error!\n", session->read_codec->codec_interface->interface_name); goto done; Modified: freeswitch/branches/mikej/sofiasip-upgrade/src/switch_core_session.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/src/switch_core_session.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/src/switch_core_session.c Sun Apr 1 15:42:32 2007 @@ -599,6 +599,7 @@ switch_channel_dequeue_dtmf(channel, buf, sizeof(buf)); } + switch_channel_clear_flag(channel, CF_BREAK); } Modified: freeswitch/branches/mikej/sofiasip-upgrade/src/switch_core_sqldb.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/src/switch_core_sqldb.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/src/switch_core_sqldb.c Sun Apr 1 15:42:32 2007 @@ -39,6 +39,7 @@ switch_core_db_t *event_db; switch_queue_t *sql_queue; switch_memory_pool_t *memory_pool; + int thread_running; } runtime; static switch_status_t switch_core_db_persistant_execute_trans(switch_core_db_t *db, char *sql, uint32_t retries) @@ -159,9 +160,8 @@ if (!runtime.event_db) { runtime.event_db = switch_core_db_handle(); } - switch_queue_create(&runtime.sql_queue, SWITCH_SQL_QUEUE_LEN, runtime.memory_pool); - + runtime.thread_running = 1; for (;;) { if (switch_queue_trypop(runtime.sql_queue, &pop) == SWITCH_STATUS_SUCCESS) { @@ -398,11 +398,15 @@ } } + switch_queue_create(&runtime.sql_queue, SWITCH_SQL_QUEUE_LEN, runtime.memory_pool); + switch_threadattr_create(&thd_attr, runtime.memory_pool); switch_threadattr_detach_set(thd_attr, 1); switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE); switch_thread_create(&thread, thd_attr, switch_core_sql_thread, NULL, runtime.memory_pool); - + while (!runtime.thread_running) { + switch_yield(10000); + } } void switch_core_sqldb_stop(void) Modified: freeswitch/branches/mikej/sofiasip-upgrade/src/switch_event.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/src/switch_event.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/src/switch_event.c Sun Apr 1 15:42:32 2007 @@ -398,13 +398,14 @@ switch_threadattr_detach_set(thd_attr, 1); assert(pool != NULL); - RUNTIME_POOL = pool; - + THRUNTIME_POOL = RUNTIME_POOL = pool; + /* if (switch_core_new_memory_pool(&THRUNTIME_POOL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Could not allocate memory pool\n"); return SWITCH_STATUS_MEMERR; } + */ /* if (switch_core_new_memory_pool(&BPOOL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Could not allocate memory pool\n"); Modified: freeswitch/branches/mikej/sofiasip-upgrade/src/switch_ivr.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/src/switch_ivr.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/src/switch_ivr.c Sun Apr 1 15:42:32 2007 @@ -108,11 +108,25 @@ const switch_application_interface_t *application_interface; char *app_name = switch_event_get_header(event, "execute-app-name"); char *app_arg = switch_event_get_header(event, "execute-app-arg"); + char *loop_h = switch_event_get_header(event, "loops"); + int loops = 0; + + if (loop_h) { + loops = atoi(loop_h); + } if (app_name && app_arg) { if ((application_interface = switch_loadable_module_get_application_interface(app_name))) { if (application_interface->application_function) { - application_interface->application_function(session, app_arg); + int x; + switch_channel_set_flag(channel, CF_BROADCAST); + for (x = 0; x < loops || loops < 0; x++) { + application_interface->application_function(session, app_arg); + if (!switch_channel_test_flag(channel, CF_BROADCAST)) { + break; + } + } + switch_channel_clear_flag(channel, CF_BROADCAST); } } } Modified: freeswitch/branches/mikej/sofiasip-upgrade/src/switch_ivr_async.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/src/switch_ivr_async.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/src/switch_ivr_async.c Sun Apr 1 15:42:32 2007 @@ -737,8 +737,13 @@ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "call-command", "execute"); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "execute-app-name", "%s", app); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "execute-app-arg", "%s", path); + if ((flags & SMF_LOOP)) { + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "loops", "%d", -1); + } + switch_core_session_queue_private_event(other_session, &event); } + switch_core_session_rwunlock(other_session); master = other_session; other_session = NULL; @@ -749,6 +754,9 @@ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "call-command", "execute"); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "execute-app-name", "%s", app); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "execute-app-arg", "%s", path); + if ((flags & SMF_LOOP)) { + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "loops", "%d", -1); + } switch_core_session_queue_private_event(session, &event); } master = session; Modified: freeswitch/branches/mikej/sofiasip-upgrade/src/switch_ivr_bridge.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/src/switch_ivr_bridge.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/src/switch_ivr_bridge.c Sun Apr 1 15:42:32 2007 @@ -81,11 +81,22 @@ switch_channel_set_flag(chan_a, CF_BRIDGED); - while (switch_channel_ready(chan_a) && data->running > 0 && his_thread->running > 0) { - switch_channel_state_t b_state = switch_channel_get_state(chan_b); + for (;;) { + switch_channel_state_t b_state; switch_status_t status; switch_event_t *event; + if (!(data->running > 0 && his_thread->running > 0)) { + break; + } + + /* if you really want to make sure it's not ready, test it twice because it might be just a break */ + if (!switch_channel_ready(chan_a) && !switch_channel_ready(chan_a)) { + break; + } + + b_state = switch_channel_get_state(chan_b); + switch (b_state) { case CS_HANGUP: case CS_DONE:
participants (1)
-
Freeswitch SVN