diff --git a/.gitignore b/.gitignore index c53d07d8a9..2480b83823 100644 --- a/.gitignore +++ b/.gitignore @@ -46,45 +46,47 @@ core.* !/w32/Console/FreeSwitchConsole.vcproj.user !/w32/Setup/inno_setup/vcredist_x64.exe !/w32/Setup/inno_setup/vcredist_x86.exe -/.version -/AUTHORS -/COPYING -/ChangeLog -/Makefile -/Makefile.in -/NEWS -/README -/TAGS +.version +AUTHORS +COPYING +ChangeLog +Makefile +Makefile.in +NEWS +README +TAGS aclocal.m4 autom4te.cache -/build/Makefile -/build/Makefile.in -/build/config/compile -/build/config/config.guess -/build/config/depcomp -/build/config/install-sh -/build/config/ltmain.sh -/build/config/missing -/build/freeswitch.pc -/build/getlib.sh -/build/getsounds.sh -/build/modmake.rules +build/Makefile +build/Makefile.in +build/config/compile +build/config/config.guess +build/config/depcomp +build/config/install-sh +build/config/ltmain.sh +build/config/missing +build/freeswitch.pc +build/getlib.sh +build/getsounds.sh +build/modmake.rules +build/getg729.sh config.cache config.log config.status -/configure +configure configure.lineno -/freeswitch -/fs_cli -/fs_encode -/fs_ivrd -/libtool -/modules.conf -/quiet_libtool -/tone2wav -/scripts/fsxs -/scripts/gentls_cert -/a.out.dSYM +freeswitch +fs_cli +fs_encode +fs_ivrd +libtool +noreg +modules.conf +quiet_libtool +tone2wav +scripts/fsxs +scripts/gentls_cert +a.out.dSYM src/mod/applications/mod_easyroute/Makefile src/mod/applications/mod_lcr/Makefile src/mod/applications/mod_nibblebill/Makefile @@ -102,6 +104,7 @@ src/mod/say/mod_say_th/Makefile src/mod/say/mod_say_zh/Makefile libs/curl/lib/ca-bundle.h libs/g729/ +libs/fsg729-*-installer src/mod/codecs/mod_com_g729/ src/mod/languages/mod_lua/mod_lua_wrap.cpp.orig src/mod/languages/mod_perl/mod_perl_wrap.cpp.orig diff --git a/build/getg729.sh.in b/build/getg729.sh.in new file mode 100755 index 0000000000..c8a7227425 --- /dev/null +++ b/build/getg729.sh.in @@ -0,0 +1,34 @@ +#!/bin/sh + +TAR=@TAR@ +ZCAT=@ZCAT@ +WGET=@WGET@ +CURL=@CURL@ + +if [ -f "$WGET" ] ; then + DOWNLOAD_CMD=$WGET +else + if [ -f "$CURL" ] ; then + DOWNLOAD_CMD="$CURL -O" + fi +fi + +base=http://files.freeswitch.org/g729/ +tarfile=$1 +url=`echo $tarfile | grep "://"` + +if [ ! -z $url ] ; then + base=$tarfile/ + tarfile=$2 +fi + +if [ ! -f $tarfile ] ; then + $DOWNLOAD_CMD $base$tarfile + if [ ! -f $tarfile ] ; then + echo cannot find $tarfile + exit 1 + fi +fi + +exit 0 + diff --git a/build/modules.conf.in b/build/modules.conf.in index 8d3dfaa85a..63a0ab491e 100644 --- a/build/modules.conf.in +++ b/build/modules.conf.in @@ -42,6 +42,7 @@ codecs/mod_amr #codecs/mod_silk #codecs/mod_codec2 codecs/mod_g729 +#codecs/mod_com_g729 codecs/mod_h26x codecs/mod_bv codecs/mod_ilbc diff --git a/conf/autoload_configs/switch.conf.xml b/conf/autoload_configs/switch.conf.xml index 44893b931a..95c43331e4 100644 --- a/conf/autoload_configs/switch.conf.xml +++ b/conf/autoload_configs/switch.conf.xml @@ -94,6 +94,8 @@ + + diff --git a/conf/jingle_profiles/client.xml b/conf/jingle_profiles/client.xml index 66c34929a3..cac70692e8 100644 --- a/conf/jingle_profiles/client.xml +++ b/conf/jingle_profiles/client.xml @@ -24,7 +24,7 @@ - + diff --git a/configure.in b/configure.in index d91cf11419..a0c9418751 100644 --- a/configure.in +++ b/configure.in @@ -730,6 +730,8 @@ AC_PATH_PROGS(WGET, wget) AC_PATH_PROGS(CURL, curl) GETLIB="cd $switch_srcdir/libs && ${SHELL} $switch_builddir/build/getlib.sh" AC_SUBST(GETLIB) +GETG729="cd $switch_srcdir/libs && ${SHELL} $switch_builddir/build/getg729.sh" +AC_SUBST(GETG729) GETSOUNDS="${SHELL} $switch_builddir/build/getsounds.sh" AC_SUBST(GETSOUNDS) @@ -916,6 +918,7 @@ AC_CONFIG_FILES([Makefile src/mod/applications/mod_osp/Makefile src/mod/applications/mod_stress/Makefile src/mod/applications/mod_hash/Makefile + src/mod/codecs/mod_com_g729/Makefile src/mod/endpoints/mod_portaudio/Makefile src/mod/endpoints/mod_skinny/Makefile src/mod/endpoints/mod_skypopen/Makefile @@ -930,6 +933,7 @@ AC_CONFIG_FILES([Makefile src/include/switch_am_config.h build/getsounds.sh build/getlib.sh + build/getg729.sh build/freeswitch.pc build/modmake.rules libs/xmlrpc-c/include/xmlrpc-c/config.h @@ -1023,6 +1027,7 @@ AC_OUTPUT ## ## Registering for ClueCon ## +if ! test -f noreg ; then echo "" echo "" echo $ECHO_N "Registering you for ClueCon http://www.cluecon.com $ECHO_C" 1>&6 @@ -1040,6 +1045,7 @@ sleep 1 AC_MSG_RESULT([ See you in August. ;-)]) sleep 2 echo "" +fi ## ## Configuration summary diff --git a/src/include/private/switch_core_pvt.h b/src/include/private/switch_core_pvt.h index 05cd24d230..f8c6a794b9 100644 --- a/src/include/private/switch_core_pvt.h +++ b/src/include/private/switch_core_pvt.h @@ -236,6 +236,7 @@ struct switch_runtime { char *odbc_dsn; char *odbc_user; char *odbc_pass; + char *dbname; uint32_t debug_level; uint32_t runlevel; uint32_t tipping_point; diff --git a/src/include/switch_core.h b/src/include/switch_core.h index 69b06420a3..984b54fac7 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -2227,6 +2227,11 @@ SWITCH_DECLARE(const char *) switch_core_banner(void); SWITCH_DECLARE(switch_bool_t) switch_core_session_in_thread(switch_core_session_t *session); SWITCH_DECLARE(uint32_t) switch_default_ptime(const char *name, uint32_t number); +SWITCH_DECLARE(switch_status_t) switch_core_add_registration(const char *user, const char *realm, const char *token, const char *url, uint32_t expires, + const char *network_ip, const char *network_port, const char *network_proto); +SWITCH_DECLARE(switch_status_t) switch_core_del_registration(const char *user, const char *realm, const char *token); +SWITCH_DECLARE(switch_status_t) switch_core_expire_registration(int force); + SWITCH_END_EXTERN_C #endif /* For Emacs: diff --git a/src/mod/Makefile.am b/src/mod/Makefile.am index e655cf7f05..5af782d12d 100644 --- a/src/mod/Makefile.am +++ b/src/mod/Makefile.am @@ -21,7 +21,7 @@ $(OUR_MODULES) $(OUR_CLEAN_MODULES) $(OUR_INSTALL_MODULES) $(OUR_UNINSTALL_MODUL fi ; \ fi ; \ if test -z "$$target" ; then target="all" ; fi ; \ - if ! test -f $$moddir/$$modname.c && ! test -f $$moddir/$$modname.cpp ; \ + if ! test -f $$moddir/$$modname.c && ! test -f $$moddir/$$modname.cpp && test $$modname != "mod_com_g729" ; \ then echo ; echo "WARNING $$modname is not a valid FreeSWITCH module dir, skipping it..." ; else \ echo ;\ echo making $$target $$modname ;\ @@ -35,6 +35,9 @@ $(OUR_MODULES) $(OUR_CLEAN_MODULES) $(OUR_INSTALL_MODULES) $(OUR_UNINSTALL_MODUL fi; \ test -z "$$fail" ; +mod_com_g729-activate: + cd $(switch_builddir)/src/mod/codecs/mod_com_g729 && $(MAKE) $(AM_MAKEFLAGS) activate + .DEFAULT: @if test -z "`echo $@ | grep all`"; then $(MAKE) $(AM_MAKEFLAGS) $@-all ; else echo Unknown target `echo $@ | sed -e 's|-all||'`; exit 1; fi diff --git a/src/mod/applications/mod_callcenter/mod_callcenter.c b/src/mod/applications/mod_callcenter/mod_callcenter.c index 61305bbbb5..9d9feed0aa 100644 --- a/src/mod/applications/mod_callcenter/mod_callcenter.c +++ b/src/mod/applications/mod_callcenter/mod_callcenter.c @@ -1384,6 +1384,8 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "cc_agent", "%s", h->agent_name); switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "cc_agent_type", "%s", h->agent_type); switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "ignore_early_media", "true"); + /* Force loopback to remain live, if not, the loop will detect the actual channel to gone */ + switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "loopback_bowout", "false"); t_agent_called = switch_epoch_time_now(NULL); dialstr = switch_mprintf("%s", h->originate_string); @@ -2080,6 +2082,32 @@ void *SWITCH_THREAD_FUNC cc_member_thread_run(switch_thread_t *thread, void *obj return NULL; } +struct moh_dtmf_helper { + const char *queue_name; + char dtmf; +}; + +static switch_status_t moh_on_dtmf(switch_core_session_t *session, void *input, switch_input_type_t itype, void *buf, unsigned int buflen) { + struct moh_dtmf_helper *h = (struct moh_dtmf_helper *) buf; + + switch (itype) { + case SWITCH_INPUT_TYPE_DTMF: + { + /* Just laywork for people who want to get some DTMF actions */ + switch_dtmf_t *dtmf = (switch_dtmf_t *) input; + if (strchr("#", dtmf->digit)) { + h->dtmf = dtmf->digit; + return SWITCH_STATUS_BREAK; + } + } + break; + default: + break; + } + + return SWITCH_STATUS_SUCCESS; +} + #define CC_DESC "callcenter" #define CC_USAGE "queue_name" @@ -2226,8 +2254,6 @@ SWITCH_STANDARD_APP(callcenter_function) switch_thread_create(&thread, thd_attr, cc_member_thread_run, h, h->pool); /* Playback MOH */ - /* TODO Add DTMF callback support */ - /* TODO add MOH infitite loop */ if (cc_moh_override) { cur_moh = switch_core_session_strdup(member_session, cc_moh_override); } else { @@ -2237,6 +2263,12 @@ SWITCH_STANDARD_APP(callcenter_function) while (switch_channel_ready(member_channel)) { switch_input_args_t args = { 0 }; + struct moh_dtmf_helper ht; + + ht.dtmf = '\0'; + args.input_callback = moh_on_dtmf; + args.buf = (void *) &ht; + args.buflen = sizeof(h); /* An agent was found, time to exit and let the bridge do it job */ if ((agent_uuid = switch_channel_get_variable(member_channel, "cc_agent_uuid"))) { @@ -2260,6 +2292,8 @@ SWITCH_STANDARD_APP(callcenter_function) switch_ivr_collect_digits_callback(session, &args, 0, 0); } + switch_yield(1000); + } /* Stop Member Thread */ diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c index f34042a54f..030cb8e867 100644 --- a/src/mod/applications/mod_commands/mod_commands.c +++ b/src/mod/applications/mod_commands/mod_commands.c @@ -45,6 +45,149 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load); SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_commands_shutdown); SWITCH_MODULE_DEFINITION(mod_commands, mod_commands_load, mod_commands_shutdown, NULL); + +struct cb_helper { + uint32_t row_process; + switch_stream_handle_t *stream; +}; + +static int url_callback(void *pArg, int argc, char **argv, char **columnNames) +{ + struct cb_helper *cb = (struct cb_helper *) pArg; + + cb->row_process++; + + if (!zstr(argv[0])) { + cb->stream->write_function(cb->stream, "%s,", argv[0]); + } + + return 0; +} + +static switch_status_t select_url(const char *user, + const char *domain, + const char *concat, + const char *exclude_contact, + switch_stream_handle_t *stream) +{ + struct cb_helper cb; + char *sql, *errmsg = NULL; + switch_core_flag_t cflags = switch_core_flags(); + switch_cache_db_handle_t *db = NULL; + + if (!(cflags & SCF_USE_SQL)) { + stream->write_function(stream, "-ERR SQL DISABLED NO DATA AVAILABLE!\n"); + return SWITCH_STATUS_SUCCESS; + } + + if (switch_core_db_handle(&db) != SWITCH_STATUS_SUCCESS) { + stream->write_function(stream, "%s", "-ERR Databse Error!\n"); + return SWITCH_STATUS_SUCCESS; + } + + cb.row_process = 0; + cb.stream = stream; + + if (exclude_contact) { + sql = switch_mprintf("select url, '%q' " + "from registrations where user='%q' and realm='%q' " + "and url not like '%%%s%%'", (concat != NULL) ? concat : "", user, domain, exclude_contact); + } else { + sql = switch_mprintf("select url, '%q' " + "from registrations where user='%q' and realm='%q'", + (concat != NULL) ? concat : "", user, domain); + } + + switch_assert(sql); + switch_cache_db_execute_sql_callback(db, sql, url_callback, &cb, &errmsg); + + if (errmsg) { + stream->write_function(stream, "-ERR SQL Error [%s]\n", errmsg); + free(errmsg); + errmsg = NULL; + } + + switch_safe_free(sql); + + if (db) { + switch_cache_db_release_db_handle(&db); + } + + return SWITCH_STATUS_SUCCESS; +} + +SWITCH_STANDARD_API(reg_url_function) +{ + char *data; + char *user = NULL; + char *domain = NULL, *dup_domain = NULL; + char *concat = NULL; + const char *exclude_contact = NULL; + char *reply = "error/facility_not_subscribed"; + switch_stream_handle_t mystream = { 0 }; + + + if (!cmd) { + stream->write_function(stream, "%s", ""); + return SWITCH_STATUS_SUCCESS; + } + + if (session) { + switch_channel_t *channel = switch_core_session_get_channel(session); + exclude_contact = switch_channel_get_variable(channel, "sip_exclude_contact"); + } + + + data = strdup(cmd); + switch_assert(data); + + user = data; + + if ((domain = strchr(user, '@'))) { + *domain++ = '\0'; + if ((concat = strchr(domain, '/'))) { + *concat++ = '\0'; + } + } else { + if ((concat = strchr(user, '/'))) { + *concat++ = '\0'; + } + } + + if (zstr(domain)) { + dup_domain = switch_core_get_variable_dup("domain"); + domain = dup_domain; + } + + if (!user) goto end; + + + SWITCH_STANDARD_STREAM(mystream); + switch_assert(mystream.data); + + select_url(user, domain, concat, exclude_contact, &mystream); + reply = mystream.data; + + + end: + + if (zstr(reply)) { + reply = "error/user_not_registered"; + } else if (end_of(reply) == ',') { + end_of(reply) = '\0'; + } + + stream->write_function(stream, "%s", reply); + reply = NULL; + + switch_safe_free(mystream.data); + + switch_safe_free(data); + switch_safe_free(dup_domain); + + return SWITCH_STATUS_SUCCESS; +} + SWITCH_STANDARD_API(banner_function) { stream->write_function(stream, "%s", switch_core_banner()); @@ -3738,6 +3881,14 @@ SWITCH_STANDARD_API(show_function) as = argv[3]; } } + } else if (!strcasecmp(command, "registrations")) { + sprintf(sql, "select * from registrations where hostname='%s'", hostname); + if (argv[1] && !strcasecmp(argv[1], "count")) { + holder.justcount = 1; + if (argv[3] && !strcasecmp(argv[2], "as")) { + as = argv[3]; + } + } } else if (!strcasecmp(command, "channels") && argv[1] && !strcasecmp(argv[1], "like")) { if (argv[2]) { char *p; @@ -4890,6 +5041,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load) SWITCH_ADD_API(commands_api_interface, "tone_detect", "Start Tone Detection on a channel", tone_detect_session_function, TONE_DETECT_SYNTAX); SWITCH_ADD_API(commands_api_interface, "unload", "Unload Module", unload_function, UNLOAD_SYNTAX); SWITCH_ADD_API(commands_api_interface, "unsched_api", "Unschedule an api command", unsched_api_function, UNSCHED_SYNTAX); + SWITCH_ADD_API(commands_api_interface, "reg_url", "", reg_url_function, "@"); SWITCH_ADD_API(commands_api_interface, "url_decode", "url decode a string", url_decode_function, ""); SWITCH_ADD_API(commands_api_interface, "url_encode", "url encode a string", url_encode_function, ""); SWITCH_ADD_API(commands_api_interface, "user_data", "find user data", user_data_function, "@ [var|param|attr] "); @@ -5000,6 +5152,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load) switch_console_set_complete("add show management"); switch_console_set_complete("add show modules"); switch_console_set_complete("add show nat_map"); + switch_console_set_complete("add show registrations"); switch_console_set_complete("add show say"); switch_console_set_complete("add show timer"); switch_console_set_complete("add shutdown"); diff --git a/src/mod/asr_tts/mod_tts_commandline/mod_tts_commandline.c b/src/mod/asr_tts/mod_tts_commandline/mod_tts_commandline.c index 6b261f1d96..0f3bc41f14 100644 --- a/src/mod/asr_tts/mod_tts_commandline/mod_tts_commandline.c +++ b/src/mod/asr_tts/mod_tts_commandline/mod_tts_commandline.c @@ -120,6 +120,11 @@ static switch_status_t tts_commandline_speech_close(switch_speech_handle_t *sh, tts_commandline_t *info = (tts_commandline_t *) sh->private_info; assert(info != NULL); + if (switch_test_flag(info->fh, SWITCH_FILE_OPEN)) { + switch_core_file_close(info->fh); + unlink(info->file); + } + return SWITCH_STATUS_SUCCESS; } @@ -130,6 +135,11 @@ static switch_status_t tts_commandline_speech_feed_tts(switch_speech_handle_t *s assert(info != NULL); + if (switch_test_flag(info->fh, SWITCH_FILE_OPEN)) { + switch_core_file_close(info->fh); + unlink(info->file); + } + message = switch_core_strdup(sh->memory_pool, globals.command); tmp = switch_util_quote_shell_arg(text); @@ -152,7 +162,7 @@ static switch_status_t tts_commandline_speech_feed_tts(switch_speech_handle_t *s } if (switch_core_file_open(info->fh, info->file, 0, //number_of_channels, - 0, //samples_per_second, + info->rate, //samples_per_second, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to open file: %s\n", info->file); return SWITCH_STATUS_FALSE; @@ -171,11 +181,14 @@ static switch_status_t tts_commandline_speech_read_tts(switch_speech_handle_t *s assert(info != NULL); if (switch_core_file_read(info->fh, data, &my_datalen) != SWITCH_STATUS_SUCCESS) { - *datalen = my_datalen * 2; + switch_core_file_close(info->fh); + unlink(info->file); return SWITCH_STATUS_FALSE; } *datalen = my_datalen * 2; if (datalen == 0) { + switch_core_file_close(info->fh); + unlink(info->file); return SWITCH_STATUS_BREAK; } else { return SWITCH_STATUS_SUCCESS; diff --git a/src/mod/codecs/mod_com_g729/Makefile.am b/src/mod/codecs/mod_com_g729/Makefile.am new file mode 100644 index 0000000000..7b631386d3 --- /dev/null +++ b/src/mod/codecs/mod_com_g729/Makefile.am @@ -0,0 +1,39 @@ +include $(top_srcdir)/build/modmake.rulesam + +MODNAME=mod_com_g729 +VERSION=193 + +if ISLINUX + +G729INSTALLER = $(top_srcdir)/libs/fsg729-$(VERSION)-installer +LICSERVER=/usr/sbin/freeswitch_licence_server +VALIDATOR=$(bindir)/validator +MOD=$(moddir)/mod_com_g729.so +BUILT_SOURCES = $(G729INSTALLER) + +install: $(LICSERVER) $(VALIDATOR) $(MOD) + +$(LICSERVER) $(VALIDATOR) $(MOD): $(G729INSTALLER) + $(SHELL) $(G729INSTALLER) $(bindir) $(moddir) nobanner + $(ECHO) + $(ECHO) + $(ECHO) Now you can activate your license by running $(MAKE) mod_com_g729-activate + $(ECHO) + $(ECHO) + +$(G729INSTALLER): + rm -f $(top_srcdir)/libs/fsg729-*-installer* + $(GETG729) fsg729-$(VERSION)-installer + chmod 755 $(G729INSTALLER) + +clean: + rm -f $(top_srcdir)/libs/fsg729-*-installer* + rm -rf /tmp/fsg729 + +activate: $(LICSERVER) $(VALIDATOR) $(MOD) + $(VALIDATOR) + +uninstall: clean + rm -f $(LICSERVER) $(VALIDATOR) $(MOD) + +endif diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 2a2ec63221..4853dff3bf 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -1366,7 +1366,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi if (s && !strcmp(s, "off")) { s = NULL; } - switch_rtp_debug_jitter_buffer(tech_pvt->rtp_session, s); + status = switch_rtp_debug_jitter_buffer(tech_pvt->rtp_session, s); goto end; } @@ -3314,6 +3314,7 @@ static int contact_callback(void *pArg, int argc, char **argv, char **columnName return 0; } + static int sql2str_callback(void *pArg, int argc, char **argv, char **columnNames) { struct cb_helper_sql2str *cbt = (struct cb_helper_sql2str *) pArg; diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c index 631cbdb14b..5109e0bc72 100644 --- a/src/mod/endpoints/mod_sofia/sofia_reg.c +++ b/src/mod/endpoints/mod_sofia/sofia_reg.c @@ -877,6 +877,7 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand const char *agent = "unknown"; const char *pres_on_reg = NULL; int send_pres = 0; + int is_tls = 0, is_tcp = 0; delete_subs = sofia_test_pflag(profile, PFLAG_DEL_SUBS_ON_REG); @@ -944,8 +945,6 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand char *path_encoded = NULL; int path_encoded_len = 0; const char *proto = "sip"; - int is_tls = 0, is_tcp = 0; - if (switch_stristr("transport=tls", sip->sip_contact->m_url->url_params)) { is_tls += 1; @@ -1292,6 +1291,8 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand char guess_ip4[256]; const char *username = "unknown"; const char *realm = reg_host; + char *url = NULL; + char *contact = NULL; if (auth_params) { username = switch_event_get_header(auth_params, "sip_auth_username"); @@ -1327,7 +1328,15 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand switch_find_local_ip(guess_ip4, sizeof(guess_ip4), NULL, AF_INET); + contact = sofia_glue_get_url_from_contact(contact_str, 1); + url = switch_mprintf("sofia/%q/sip:%q", profile->name, sofia_glue_strip_proto(contact)); + switch_core_add_registration(to_user, reg_host, call_id, url, (long) switch_epoch_time_now(NULL) + (long) exptime + 60, + network_ip, network_port_c, is_tls ? "tls" : is_tcp ? "tcp" : "udp"); + + switch_safe_free(url); + switch_safe_free(contact); + sql = switch_mprintf("insert into sip_registrations " "(call_id,sip_user,sip_host,presence_hosts,contact,status,rpid,expires," "user_agent,server_user,server_host,profile_name,hostname,network_ip,network_port,sip_username,sip_realm," @@ -1534,6 +1543,8 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand } } } else { + switch_core_del_registration(to_user, reg_host, call_id); + if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_UNREGISTER) == SWITCH_STATUS_SUCCESS) { switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile-name", profile->name); switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "from-user", to_user); diff --git a/src/mod/event_handlers/mod_event_socket/mod_event_socket.c b/src/mod/event_handlers/mod_event_socket/mod_event_socket.c index 1462e4ec54..2bb1d453a0 100644 --- a/src/mod/event_handlers/mod_event_socket/mod_event_socket.c +++ b/src/mod/event_handlers/mod_event_socket/mod_event_socket.c @@ -1783,6 +1783,7 @@ static switch_status_t parse_command(listener_t *listener, switch_event_t **even switch_mutex_lock(listener->filter_mutex); if (!listener->filters) { switch_event_create_plain(&listener->filters, SWITCH_EVENT_CLONE); + switch_clear_flag(listener->filters, EF_UNIQ_HEADERS); } if (!strcasecmp(header_name, "delete") && header_val) { diff --git a/src/switch_channel.c b/src/switch_channel.c index f750496323..9e3064b625 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -184,7 +184,7 @@ struct switch_callstate_table { const char *name; switch_channel_callstate_t callstate; }; -static struct switch_callstate_table STATE_CHART[] = { +static struct switch_callstate_table CALLSTATE_CHART[] = { {"DOWN", CCS_DOWN}, {"DIALING", CCS_DIALING}, {"RINGING", CCS_RINGING}, @@ -228,9 +228,9 @@ SWITCH_DECLARE(const char *) switch_channel_callstate2str(switch_channel_callsta uint8_t x; const char *str = "UNKNOWN"; - for (x = 0; x < (sizeof(STATE_CHART) / sizeof(struct switch_cause_table)) - 1; x++) { - if (STATE_CHART[x].callstate == callstate) { - str = STATE_CHART[x].name; + for (x = 0; x < (sizeof(CALLSTATE_CHART) / sizeof(struct switch_cause_table)) - 1; x++) { + if (CALLSTATE_CHART[x].callstate == callstate) { + str = CALLSTATE_CHART[x].name; break; } } @@ -238,6 +238,7 @@ SWITCH_DECLARE(const char *) switch_channel_callstate2str(switch_channel_callsta return str; } + SWITCH_DECLARE(switch_call_cause_t) switch_channel_str2callstate(const char *str) { uint8_t x; @@ -246,9 +247,9 @@ SWITCH_DECLARE(switch_call_cause_t) switch_channel_str2callstate(const char *str if (*str > 47 && *str < 58) { callstate = atoi(str); } else { - for (x = 0; x < (sizeof(STATE_CHART) / sizeof(struct switch_callstate_table)) - 1 && STATE_CHART[x].name; x++) { - if (!strcasecmp(STATE_CHART[x].name, str)) { - callstate = STATE_CHART[x].callstate; + for (x = 0; x < (sizeof(CALLSTATE_CHART) / sizeof(struct switch_callstate_table)) - 1 && CALLSTATE_CHART[x].name; x++) { + if (!strcasecmp(CALLSTATE_CHART[x].name, str)) { + callstate = CALLSTATE_CHART[x].callstate; break; } } @@ -1606,6 +1607,7 @@ static const char *state_names[] = { "CS_HANGUP", "CS_REPORTING", "CS_DESTROY", + "CS_NONE", NULL }; diff --git a/src/switch_core.c b/src/switch_core.c index 0eb51ccab3..66731b61c8 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -1298,6 +1298,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_init(switch_core_flag_t flags, switc runtime.default_dtmf_duration = SWITCH_DEFAULT_DTMF_DURATION; runtime.min_dtmf_duration = SWITCH_MIN_DTMF_DURATION; runtime.odbc_dbtype = DBTYPE_DEFAULT; + runtime.dbname = NULL; /* INIT APR and Create the pool context */ if (apr_initialize() != SWITCH_STATUS_SUCCESS) { @@ -1641,6 +1642,8 @@ static void switch_load_core_config(const char *file) switch_rtp_set_start_port((switch_port_t) atoi(val)); } else if (!strcasecmp(var, "rtp-end-port") && !zstr(val)) { switch_rtp_set_end_port((switch_port_t) atoi(val)); + } else if (!strcasecmp(var, "core-db-name") && !zstr(val)) { + runtime.dbname = switch_core_strdup(runtime.memory_pool, val); } else if (!strcasecmp(var, "core-db-dsn") && !zstr(val)) { if (switch_odbc_available()) { runtime.odbc_dsn = switch_core_strdup(runtime.memory_pool, val); diff --git a/src/switch_core_io.c b/src/switch_core_io.c index decb587ef7..4e1c7075b5 100644 --- a/src/switch_core_io.c +++ b/src/switch_core_io.c @@ -318,11 +318,24 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi switch_codec_t *use_codec = read_frame->codec; if (do_bugs) { switch_thread_rwlock_wrlock(session->bug_rwlock); + if (!session->bugs) { + do_bugs = 0; + switch_thread_rwlock_unlock(session->bug_rwlock); + goto done; + } + if (!switch_core_codec_ready(&session->bug_codec)) { switch_core_codec_copy(read_frame->codec, &session->bug_codec, NULL); } use_codec = &session->bug_codec; switch_thread_rwlock_unlock(session->bug_rwlock); + + switch_thread_rwlock_wrlock(session->bug_rwlock); + if (!session->bugs) { + do_bugs = 0; + } + switch_thread_rwlock_unlock(session->bug_rwlock); + if (!do_bugs) goto done; } if (switch_test_flag(read_frame, SFF_PLC)) { diff --git a/src/switch_core_sqldb.c b/src/switch_core_sqldb.c index 73890a1e4f..f135e9586d 100644 --- a/src/switch_core_sqldb.c +++ b/src/switch_core_sqldb.c @@ -74,7 +74,11 @@ SWITCH_DECLARE(switch_status_t) _switch_core_db_handle(switch_cache_db_handle_t r = _switch_cache_db_get_db_handle(dbh, SCDB_TYPE_ODBC, &options, file, func, line); } else { - options.core_db_options.db_path = SWITCH_CORE_DB; + if (runtime.dbname) { + options.core_db_options.db_path = runtime.dbname; + } else { + options.core_db_options.db_path = SWITCH_CORE_DB; + } r = _switch_cache_db_get_db_handle(dbh, SCDB_TYPE_CORE_DB, &options, file, func, line); } @@ -87,6 +91,7 @@ SWITCH_DECLARE(switch_status_t) _switch_core_db_handle(switch_cache_db_handle_t #define SQL_CACHE_TIMEOUT 120 +#define SQL_REG_TIMEOUT 15 static void sql_close(time_t prune) { @@ -906,7 +911,7 @@ SWITCH_DECLARE(switch_bool_t) switch_cache_db_test_reactive(switch_cache_db_hand static void *SWITCH_THREAD_FUNC switch_core_sql_db_thread(switch_thread_t *thread, void *obj) { - int sec = 0; + int sec = 0, reg_sec = 0;; sql_manager.db_thread_running = 1; @@ -916,6 +921,11 @@ static void *SWITCH_THREAD_FUNC switch_core_sql_db_thread(switch_thread_t *threa wake_thread(0); sec = 0; } + + if (++reg_sec == SQL_REG_TIMEOUT) { + switch_core_expire_registration(0); + reg_sec = 0; + } switch_yield(1000000); } @@ -1616,6 +1626,108 @@ static char create_nat_sql[] = " hostname VARCHAR(256)\n" ");\n"; + +static char create_registrations_sql[] = + "CREATE TABLE registrations (\n" + " reg_user VARCHAR(256),\n" + " realm VARCHAR(256),\n" + " token VARCHAR(256),\n" + " url TEXT,\n" + " expires INTEGER,\n" + " network_ip VARCHAR(256),\n" + " network_port VARCHAR(256),\n" + " network_proto VARCHAR(256),\n" + " hostname VARCHAR(256)\n" + ");\n" + "create index regindex1 on registrations (reg_user,realm,hostname);\n"; + + +SWITCH_DECLARE(switch_status_t) switch_core_add_registration(const char *user, const char *realm, const char *token, const char *url, uint32_t expires, + const char *network_ip, const char *network_port, const char *network_proto) +{ + switch_cache_db_handle_t *dbh; + char *sql; + + if (switch_core_db_handle(&dbh) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB!\n"); + return SWITCH_STATUS_FALSE; + } + + sql = switch_mprintf("delete from registrations where hostname='%q' and (url='%q' or token='%q')", switch_core_get_hostname(), url, switch_str_nil(token)); + switch_cache_db_execute_sql(dbh, sql, NULL); + free(sql); + + sql = switch_mprintf("insert into registrations (reg_user,realm,token,url,expires,network_ip,network_port,network_proto,hostname) " + "values ('%q','%q','%q','%q',%ld,'%q','%q','%q','%q')", + switch_str_nil(user), + switch_str_nil(realm), + switch_str_nil(token), + switch_str_nil(url), + expires, + switch_str_nil(network_ip), + switch_str_nil(network_port), + switch_str_nil(network_proto), + switch_core_get_hostname() + ); + + switch_cache_db_execute_sql(dbh, sql, NULL); + switch_cache_db_release_db_handle(&dbh); + + free(sql); + + return SWITCH_STATUS_SUCCESS; +} + +SWITCH_DECLARE(switch_status_t) switch_core_del_registration(const char *user, const char *realm, const char *token) +{ + + switch_cache_db_handle_t *dbh; + char *sql; + + if (switch_core_db_handle(&dbh) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB!\n"); + return SWITCH_STATUS_FALSE; + } + + sql = switch_mprintf("delete from registrations where reg_user='%q' and realm='%q' and hostname='%q'", user, realm, switch_core_get_hostname()); + + switch_cache_db_execute_sql(dbh, sql, NULL); + switch_cache_db_release_db_handle(&dbh); + + free(sql); + + return SWITCH_STATUS_SUCCESS; +} + +SWITCH_DECLARE(switch_status_t) switch_core_expire_registration(int force) +{ + + switch_cache_db_handle_t *dbh; + char *sql; + switch_time_t now; + + if (switch_core_db_handle(&dbh) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB!\n"); + return SWITCH_STATUS_FALSE; + } + + now = switch_epoch_time_now(NULL); + + if (force) { + sql = switch_mprintf("delete from registrations where hostname='%q'", switch_core_get_hostname()); + } else { + sql = switch_mprintf("delete from registrations where expires <= %ld and hostname='%q'", now, switch_core_get_hostname()); + } + + switch_cache_db_execute_sql(dbh, sql, NULL); + switch_cache_db_release_db_handle(&dbh); + + free(sql); + + return SWITCH_STATUS_SUCCESS; + +} + switch_status_t switch_core_sqldb_start(switch_memory_pool_t *pool, switch_bool_t manage) { switch_threadattr_t *thd_attr; @@ -1690,6 +1802,8 @@ switch_status_t switch_core_sqldb_start(switch_memory_pool_t *pool, switch_bool_ switch_cache_db_test_reactive(dbh, "select hostname from complete", "DROP TABLE complete", create_complete_sql); switch_cache_db_test_reactive(dbh, "select hostname from aliases", "DROP TABLE aliases", create_alias_sql); switch_cache_db_test_reactive(dbh, "select hostname from nat", "DROP TABLE nat", create_nat_sql); + switch_cache_db_test_reactive(dbh, "delete from registrations where reg_user='' or network_proto='tcp' or network_proto='tls'", + "DROP TABLE registrations", create_registrations_sql); switch (dbh->type) { @@ -1706,6 +1820,8 @@ switch_status_t switch_core_sqldb_start(switch_memory_pool_t *pool, switch_bool_ } switch_cache_db_test_reactive(dbh, "select ikey from interfaces", "DROP TABLE interfaces", create_interfaces_sql); switch_cache_db_test_reactive(dbh, "select hostname from tasks", "DROP TABLE tasks", create_tasks_sql); + switch_cache_db_test_reactive(dbh, "delete from registrations where reg_user='' or network_proto='tcp' or network_proto='tls'", + "DROP TABLE registrations", create_registrations_sql); if (runtime.odbc_dbtype == DBTYPE_DEFAULT) { switch_cache_db_execute_sql(dbh, "begin;delete from channels where hostname='';delete from channels where hostname='';commit;", &err); diff --git a/src/switch_rtp.c b/src/switch_rtp.c index 4df867aa64..faa79e35a2 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -1875,7 +1875,7 @@ static void jb_logger(const char *file, const char *func, int line, int level, c SWITCH_DECLARE(switch_status_t) switch_rtp_debug_jitter_buffer(switch_rtp_t *rtp_session, const char *name) { - if (!switch_rtp_ready(rtp_session)) { + if (!switch_rtp_ready(rtp_session) || !rtp_session->jb) { return SWITCH_STATUS_FALSE; } @@ -2808,7 +2808,8 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ goto end; } - if (bytes && !switch_test_flag(rtp_session, SWITCH_RTP_FLAG_PROXY_MEDIA) && !switch_test_flag(rtp_session, SWITCH_RTP_FLAG_UDPTL) && + if (bytes && rtp_session->recv_msg.header.version == 2 && + !switch_test_flag(rtp_session, SWITCH_RTP_FLAG_PROXY_MEDIA) && !switch_test_flag(rtp_session, SWITCH_RTP_FLAG_UDPTL) && rtp_session->recv_msg.header.pt != 13 && rtp_session->recv_msg.header.pt != rtp_session->recv_te && (!rtp_session->cng_pt || rtp_session->recv_msg.header.pt != rtp_session->cng_pt) &&