[Freeswitch-svn] [commit] r8099 - freeswitch/branches/cseket/src/mod/endpoints/mod_sofia
Freeswitch SVN
cseket at freeswitch.org
Sat Apr 12 12:59:26 EDT 2008
Author: cseket
Date: Sat Apr 12 12:59:25 2008
New Revision: 8099
Added:
freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/sofia.c
- copied, changed from r5617, /freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia.c
Log:
add 'auto' sip-port, which means bind to any free port, choosen by the os
Copied: freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/sofia.c (from r5617, /freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia.c)
==============================================================================
--- /freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia.c (original)
+++ freeswitch/branches/cseket/src/mod/endpoints/mod_sofia/sofia.c Sat Apr 12 12:59:25 2008
@@ -28,38 +28,186 @@
* Paul D. Tinsley <pdt at jackhammer.org>
* Bret McDanel <trixter AT 0xdecafbad.com>
* Marcel Barbulescu <marcelbarbulescu at gmail.com>
+ * Norman Brandinger
*
*
* sofia.c -- SOFIA SIP Endpoint (sofia code)
*
*/
#include "mod_sofia.h"
+#include "sofia-sip/msg_parser.h"
+#include "sofia-sip/sip_extra.h"
+#include "sofia-sip/tport_tag.h"
+
extern su_log_t tport_log[];
+extern su_log_t iptsec_log[];
+extern su_log_t nea_log[];
+extern su_log_t nta_log[];
+extern su_log_t nth_client_log[];
+extern su_log_t nth_server_log[];
+extern su_log_t nua_log[];
+extern su_log_t soa_log[];
+extern su_log_t sresolv_log[];
+extern su_log_t stun_log[];
+
+static void set_variable_sip_param(switch_channel_t *channel, char *header_type, sip_param_t const *params);
+
+static void sofia_info_send_sipfrag(switch_core_session_t *aleg, switch_core_session_t *bleg);
static void sofia_handle_sip_i_state(switch_core_session_t *session, 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 sofia_handle_sip_r_invite(switch_core_session_t *session, 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[]);
+
+void sofia_handle_sip_r_notify(switch_core_session_t *session, 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 (status >= 300 && sip) {
+ const char *call_id = sip->sip_call_id->i_id;
+ char *sql;
+ switch_core_hash_delete(profile->sub_hash, call_id);
+
+ sql = switch_mprintf("delete from sip_subscriptions where call_id='%q'", call_id);
+ switch_assert(sql != NULL);
+ sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
+ nua_handle_destroy(nh);
+ }
+}
+
+void sofia_handle_sip_i_notify(switch_core_session_t *session, 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[])
+{
+ switch_channel_t *channel = NULL;
+
+ /* make sure we have a proper event */
+ if (!sip || !sip->sip_event) {
+ goto error;
+ }
+
+ /* Automatically return a 200 OK for Event: keep-alive */
+ if (!strcasecmp(sip->sip_event->o_type, "keep-alive")) {
+ nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END());
+ return;
+ }
+
+ /* make sure we have a proper "talk" event */
+ if (!session || strcasecmp(sip->sip_event->o_type, "talk")) {
+ goto error;
+ }
+
+ channel = switch_core_session_get_channel(session);
+ switch_assert(channel != NULL);
+ if (!switch_channel_test_flag(channel, CF_OUTBOUND)) {
+ switch_channel_answer(channel);
+ switch_channel_set_variable(channel, "auto_answer_destination", switch_channel_get_variable(channel, "destination_number"));
+ switch_ivr_session_transfer(session, "auto_answer", NULL , NULL);
+ nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END());
+ return;
+ }
+
+error:
+ nua_respond(nh, 481, "Subscription Does Not Exist", NUTAG_WITH_THIS(nua), TAG_END());
+ return;
+}
+
+void sofia_handle_sip_i_bye(switch_core_session_t *session, 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 *tmp;
+ switch_channel_t *channel;
+
+ if (!session) return;
+
+ channel = switch_core_session_get_channel(session);
+
+
+ if (sip->sip_reason && sip->sip_reason->re_protocol &&
+ (!strcasecmp(sip->sip_reason->re_protocol, "Q.850") || !strcasecmp(sip->sip_reason->re_protocol, "FreeSWITCH")) &&
+ sip->sip_reason->re_cause) {
+ private_object_t *tech_pvt = switch_core_session_get_private(session);
+ tech_pvt->q850_cause = atoi(sip->sip_reason->re_cause);
+ }
+
+ if (sip->sip_user_agent && !switch_strlen_zero(sip->sip_user_agent->g_string)){
+ switch_channel_set_variable(channel, "sip_user_agent", sip->sip_user_agent->g_string);
+ }
+ if ((tmp = sofia_glue_get_unknown_header(sip, "rtp-txstat"))) {
+ switch_channel_set_variable(channel, "sip_rtp_txstat", tmp);
+ }
+ if ((tmp = sofia_glue_get_unknown_header(sip, "rtp-rxstat"))) {
+ switch_channel_set_variable(channel, "sip_rtp_rxstat", tmp);
+ }
+ return;
+}
+
+void sofia_handle_sip_r_message(int status, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip)
+{
+ if (status == 503) {
+ const char *user = NULL, *host = NULL;
+ char *sql;
+
+ if (sip->sip_to && sip->sip_to->a_url) {
+ user = sip->sip_to->a_url->url_user;
+ host = sip->sip_to->a_url->url_host;
+
+ sql = switch_mprintf("delete from sip_registrations where sip_user='%q' and sip_host='%q'", user, host);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Deleting registration for %s@%s\n", user, host);
+ sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
+ }
+ }
+
+ nua_handle_destroy(nh);
+}
+
void sofia_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[])
+ 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;
+ sofia_gateway_t *gateway = NULL;
if (sofia_private) {
- if (!switch_strlen_zero(sofia_private->uuid)) {
-
+ if ((gateway = sofia_private->gateway)) {
+ if (switch_thread_rwlock_tryrdlock(gateway->profile->rwlock) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Profile %s is locked\n", gateway->profile->name);
+ return;
+ }
+ } else 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 (!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);
+ 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 (tech_pvt->gateway_name) {
+ gateway = sofia_reg_find_gateway(tech_pvt->gateway_name);
+ }
} else {
/* too late */
return;
@@ -72,6 +220,15 @@
nua_event_name(event), status, phrase, session ? switch_channel_get_name(channel) : "n/a");
}
+ if (session) {
+ switch_core_session_signal_lock(session);
+
+ if (channel && switch_channel_get_state(channel) >= CS_HANGUP) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Channel is already hungup.\n");
+ goto done;
+ }
+ }
+
if ((profile->pflags & PFLAG_AUTH_ALL) && tech_pvt && tech_pvt->key && sip) {
sip_authorization_t const *authorization = NULL;
@@ -84,8 +241,8 @@
if (authorization) {
char network_ip[80];
get_addr(network_ip, sizeof(network_ip), &((struct sockaddr_in *) msg_addrinfo(nua_current_request(nua))->ai_addr)->sin_addr);
- auth_res = sofia_reg_parse_auth(profile, authorization,
- (char *) sip->sip_request->rq_method_name, tech_pvt->key, strlen(tech_pvt->key), network_ip, NULL);
+ auth_res = sofia_reg_parse_auth(profile, authorization, sip,
+ (char *) sip->sip_request->rq_method_name, tech_pvt->key, strlen(tech_pvt->key), network_ip, NULL, 0, REG_INVITE, NULL);
}
if (auth_res != AUTH_OK) {
@@ -100,7 +257,7 @@
}
if (sip && (status == 401 || status == 407)) {
- sofia_reg_handle_sip_r_challenge(status, phrase, nua, profile, nh, session, sip, tags);
+ sofia_reg_handle_sip_r_challenge(status, phrase, nua, profile, nh, session, gateway, sip, tags);
goto done;
}
@@ -112,38 +269,23 @@
break;
case nua_r_message:
- {
- if (status == 503) {
- const char *user = NULL, *host = NULL;
- char *sql;
-
- if (sip->sip_to && sip->sip_to->a_url) {
- user = sip->sip_to->a_url->url_user;
- host = sip->sip_to->a_url->url_host;
-
- sql = switch_mprintf("delete from sip_registrations where user='%q' and host='%q'", user, host);
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Deleting registration for %s@%s\n", user, host);
- sofia_glue_execute_sql(profile, SWITCH_TRUE, sql, NULL);
- switch_safe_free(sql);
- }
- }
-
- nua_handle_destroy(nh);
-
- }
+ sofia_handle_sip_r_message(status, profile, nh, sip);
break;
- case nua_r_get_params:
case nua_r_invite:
+ sofia_handle_sip_r_invite(session, status, phrase, nua, profile, nh, sofia_private, sip, tags);
+ break;
+ case nua_r_get_params:
case nua_r_unregister:
case nua_r_options:
case nua_i_fork:
case nua_r_info:
case nua_r_bye:
+ break;
case nua_i_bye:
+ sofia_handle_sip_i_bye(session, status, phrase, nua, profile, nh, sofia_private, sip, tags);
+ break;
case nua_r_unsubscribe:
case nua_r_publish:
- case nua_r_notify:
- case nua_i_notify:
case nua_i_cancel:
case nua_i_error:
case nua_i_active:
@@ -151,6 +293,12 @@
case nua_i_terminated:
case nua_r_set_params:
break;
+ case nua_r_notify:
+ sofia_handle_sip_r_notify(session, status, phrase, nua, profile, nh, sofia_private, sip, tags);
+ break;
+ case nua_i_notify:
+ sofia_handle_sip_i_notify(session, status, phrase, nua, profile, nh, sofia_private, sip, tags);
+ break;
case nua_r_register:
sofia_reg_handle_sip_r_register(status, phrase, nua, profile, nh, sofia_private, sip, tags);
break;
@@ -203,13 +351,16 @@
done:
+ if (gateway) {
+ sofia_reg_release_gateway(gateway);
+ }
+
if (session) {
+ switch_core_session_signal_unlock(session);
switch_core_session_rwunlock(session);
-
}
}
-
void event_handler(switch_event_t *event)
{
char *subclass, *sql;
@@ -220,10 +371,15 @@
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 *call_id = switch_event_get_header(event, "orig-call-id");
+ char *user_agent = switch_event_get_header(event, "user-agent");
+ long expires = (long) switch_timestamp(NULL);
char *profile_name = switch_event_get_header(event, "orig-profile-name");
sofia_profile_t *profile = NULL;
- char buf[512];
+
+ if (exp_str) {
+ expires += atol(exp_str);
+ }
if (!rpid) {
rpid = "unknown";
@@ -233,26 +389,24 @@
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Profile\n");
return;
}
-
-
- if (!sofia_reg_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);
+ if (sofia_test_pflag(profile, PFLAG_MULTIREG)) {
+ sql = switch_mprintf("delete from sip_registrations where call_id='%q'", call_id);
} 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);
-
+ sql = switch_mprintf("delete from sip_registrations where sip_user='%q' and sip_host='%q'", from_user, from_host);
}
+ switch_mutex_lock(profile->ireg_mutex);
+ sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
+
+ sql = switch_mprintf("insert into sip_registrations values ('%q', '%q','%q','%q','Registered', '%q', %ld, '%q')",
+ call_id, from_user, from_host, contact_str, rpid, expires, user_agent);
+
if (sql) {
- sofia_glue_execute_sql(profile, SWITCH_FALSE, sql, profile->ireg_mutex);
- switch_safe_free(sql);
- sql = NULL;
+ sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Propagating registration for %s@%s->%s\n", from_user, from_host, contact_str);
-
}
+ switch_mutex_unlock(profile->ireg_mutex);
+
if (profile) {
sofia_glue_release_profile(profile);
@@ -260,17 +414,85 @@
}
}
+void *SWITCH_THREAD_FUNC sofia_profile_worker_thread_run(switch_thread_t *thread, void *obj)
+{
+ sofia_profile_t *profile = (sofia_profile_t *) obj;
+ uint32_t ireg_loops = 0;
+ uint32_t gateway_loops = 0;
+ int loops = 0;
+ uint32_t qsize;
+
+ ireg_loops = IREG_SECONDS;
+ gateway_loops = GATEWAY_SECONDS;
+
+ sofia_set_pflag_locked(profile, PFLAG_WORKER_RUNNING);
+
+ switch_queue_create(&profile->sql_queue, 500000, profile->pool);
+
+ qsize = switch_queue_size(profile->sql_queue);
+
+ while ((mod_sofia_globals.running == 1 && sofia_test_pflag(profile, PFLAG_RUNNING)) || qsize) {
+ if (qsize) {
+ void *pop;
+ switch_mutex_lock(profile->ireg_mutex);
+ while (switch_queue_trypop(profile->sql_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) {
+ sofia_glue_actually_execute_sql(profile, SWITCH_TRUE, (char *) pop, NULL);
+ free(pop);
+ }
+ switch_mutex_unlock(profile->ireg_mutex);
+ }
+
+ if (++loops >= 100) {
+ if (++ireg_loops >= IREG_SECONDS) {
+ sofia_reg_check_expire(profile, switch_timestamp(NULL));
+ ireg_loops = 0;
+ }
+
+ if (++gateway_loops >= GATEWAY_SECONDS) {
+ sofia_reg_check_gateway(profile, switch_timestamp(NULL));
+ gateway_loops = 0;
+ }
+ loops = 0;
+ }
+
+ switch_yield(10000);
+ qsize = switch_queue_size(profile->sql_queue);
+ }
+
+ sofia_clear_pflag_locked(profile, PFLAG_WORKER_RUNNING);
+
+ return NULL;
+}
+
+
+void launch_sofia_worker_thread(sofia_profile_t *profile)
+{
+ switch_thread_t *thread;
+ switch_threadattr_t *thd_attr = NULL;
+ int x = 0;
+
+ switch_threadattr_create(&thd_attr, profile->pool);
+ switch_threadattr_detach_set(thd_attr, 1);
+ switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
+ switch_threadattr_priority_increase(thd_attr);
+ switch_thread_create(&thread, thd_attr, sofia_profile_worker_thread_run, profile, profile->pool);
+ while(!sofia_test_pflag(profile, PFLAG_WORKER_RUNNING)) {
+ switch_yield(100000);
+ if (++x >= 100) {
+ break;
+ }
+ }
+}
void *SWITCH_THREAD_FUNC sofia_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_event_t *s_event;
-
+ int tportlog = 0;
+
switch_mutex_lock(mod_sofia_globals.mutex);
mod_sofia_globals.threads++;
switch_mutex_unlock(mod_sofia_globals.mutex);
@@ -286,11 +508,20 @@
goto end;
}
+ if (switch_test_flag(profile, TFLAG_TPORT_LOG)) {
+ tportlog = 1;
+ }
profile->nua = nua_create(profile->s_root, /* Event loop */
- sofia_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 */
+ sofia_event_callback, /* Callback for processing events */
+ profile, /* Additional data to pass to callback */
+ NUTAG_URL(profile->bindurl),
+ TAG_IF(sofia_test_pflag(profile, PFLAG_TLS), NUTAG_SIPS_URL(profile->tls_bindurl)),
+ TAG_IF(sofia_test_pflag(profile, PFLAG_TLS), NUTAG_CERTIFICATE_DIR(profile->tls_cert_dir)),
+ TAG_IF(sofia_test_pflag(profile, PFLAG_TLS), TPTAG_TLS_VERSION(profile->tls_version)),
+ NTATAG_UDP_MTU(65536),
+ TAG_IF(tportlog, TPTAG_LOG(1)),
+ TAG_END()); /* Last tag should always finish the sequence */
if (!profile->nua) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Creating SIP UA for profile: %s\n", profile->name);
@@ -298,62 +529,72 @@
goto end;
}
-
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Created agent for %s\n", profile->name);
nua_set_params(profile->nua,
- //NUTAG_EARLY_MEDIA(1),
+ NUTAG_APPL_METHOD("OPTIONS"),
+ NUTAG_APPL_METHOD("NOTIFY"),
+ NUTAG_APPL_METHOD("INFO"),
NUTAG_AUTOANSWER(0),
NUTAG_AUTOALERT(0),
- NUTAG_ALLOW("REGISTER"),
- NUTAG_ALLOW("REFER"),
+ TAG_IF((profile->mflags & MFLAG_REGISTER), NUTAG_ALLOW("REGISTER")),
+ TAG_IF((profile->mflags & MFLAG_REFER), NUTAG_ALLOW("REFER")),
NUTAG_ALLOW("INFO"),
+ NUTAG_ALLOW("NOTIFY"),
+ NUTAG_ALLOW_EVENTS("talk"),
+ NUTAG_SESSION_TIMER(profile->session_timeout),
+ NTATAG_MAX_PROCEEDING(profile->max_proceeding),
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("dialog")),
+ TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW_EVENTS("call-info")),
+ TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW_EVENTS("sla")),
+ TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW_EVENTS("include-session-description")),
TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW_EVENTS("presence.winfo")),
TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW_EVENTS("message-summary")),
- SIPTAG_SUPPORTED_STR("100rel, precondition"), SIPTAG_USER_AGENT_STR(SOFIA_USER_AGENT), TAG_END());
+ SIPTAG_SUPPORTED_STR("100rel, precondition, timer"), SIPTAG_USER_AGENT_STR(profile->user_agent), TAG_END());
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set params for %s\n", profile->name);
for (node = profile->aliases; node; node = node->next) {
node->nua = nua_create(profile->s_root, /* Event loop */
- sofia_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 */
+ sofia_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_APPL_METHOD("OPTIONS"),
NUTAG_EARLY_MEDIA(1),
NUTAG_AUTOANSWER(0),
NUTAG_AUTOALERT(0),
- NUTAG_ALLOW("REGISTER"),
- NUTAG_ALLOW("REFER"),
+ TAG_IF((profile->mflags & MFLAG_REGISTER), NUTAG_ALLOW("REGISTER")),
+ TAG_IF((profile->mflags & MFLAG_REFER), 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());
-
+ SIPTAG_SUPPORTED_STR("100rel, precondition"), SIPTAG_USER_AGENT_STR(profile->user_agent), TAG_END());
}
-
-
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "activated db for %s\n", profile->name);
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,_sip._tcp,_sip._sctp");
+ switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "service", "_sip._udp,_sip._tcp,_sip._sctp%s",
+ (sofia_test_pflag(profile, PFLAG_TLS)) ? ",_sips._tcp" : "");
+
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "port", "%d", profile->sip_port);
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "module_name", "%s", "mod_sofia");
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "profile_name", "%s", profile->name);
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "profile_uri", "%s", profile->url);
+
+ if (sofia_test_pflag(profile, PFLAG_TLS)) {
+ switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "tls_port", "%d", profile->tls_sip_port);
+ switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "profile_tls_uri", "%s", profile->tls_url);
+ }
switch_event_fire(&s_event);
}
@@ -365,46 +606,55 @@
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Starting thread for %s\n", profile->name);
- profile->started = time(NULL);
- switch_yield(1000000);
+ profile->started = switch_timestamp(NULL);
sofia_set_pflag_locked(profile, PFLAG_RUNNING);
-
- while (mod_sofia_globals.running == 1 && sofia_test_pflag(profile, PFLAG_RUNNING)) {
- if (++ireg_loops >= IREG_SECONDS) {
- sofia_reg_check_expire(profile, time(NULL));
- ireg_loops = 0;
- }
+ launch_sofia_worker_thread(profile);
- if (++gateway_loops >= GATEWAY_SECONDS) {
- sofia_reg_check_gateway(profile, time(NULL));
- gateway_loops = 0;
- }
+ switch_yield(1000000);
+ while (mod_sofia_globals.running == 1 && sofia_test_pflag(profile, PFLAG_RUNNING) && sofia_test_pflag(profile, PFLAG_WORKER_RUNNING)) {
su_root_step(profile->s_root, 1000);
}
-
- //sofia_reg_check_expire(profile, 0);
- //sofia_reg_check_gateway(profile, 0);
-
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Write lock %s\n", profile->name);
switch_thread_rwlock_wrlock(profile->rwlock);
sofia_reg_unregister(profile);
nua_shutdown(profile->nua);
+ su_root_run(profile->s_root);
+ sofia_clear_pflag_locked(profile, PFLAG_RUNNING);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "waiting for worker thread\n");
- su_root_run(profile->s_root);
+ while(sofia_test_pflag(profile, PFLAG_WORKER_RUNNING)) {
+ switch_yield(100000);
+ }
+
+ while(profile->inuse) {
+ switch_yield(100000);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "waiting for %d session(s)\n", profile->inuse);
+ }
nua_destroy(profile->nua);
+ switch_mutex_lock(profile->ireg_mutex);
+ switch_mutex_unlock(profile->ireg_mutex);
+ switch_mutex_lock(profile->flag_mutex);
+ switch_mutex_unlock(profile->flag_mutex);
if (switch_event_create(&s_event, SWITCH_EVENT_UNPUBLISH) == SWITCH_STATUS_SUCCESS) {
- switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "service", "_sip._udp,_sip._tcp,_sip._sctp");
+ switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "service", "_sip._udp,_sip._tcp,_sip._sctp%s",
+ (sofia_test_pflag(profile, PFLAG_TLS)) ? ",_sips._tcp" : "");
+
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "port", "%d", profile->sip_port);
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "module_name", "%s", "mod_sofia");
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "profile_name", "%s", profile->name);
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "profile_uri", "%s", profile->url);
+
+ if (sofia_test_pflag(profile, PFLAG_TLS)) {
+ switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "tls_port", "%d", profile->tls_sip_port);
+ switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "profile_tls_uri", "%s", profile->tls_url);
+ }
switch_event_fire(&s_event);
}
@@ -413,8 +663,9 @@
su_root_destroy(profile->s_root);
pool = profile->pool;
-
sofia_glue_del_profile(profile);
+ switch_core_hash_destroy(&profile->chat_hash);
+ switch_core_hash_destroy(&profile->sub_hash);
switch_thread_rwlock_unlock(profile->rwlock);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Write unlock %s\n", profile->name);
@@ -422,13 +673,10 @@
if (sofia_test_pflag(profile, PFLAG_RESPAWN)) {
config_sofia(1, profile->name);
}
-
- switch_core_destroy_memory_pool(&pool);
-
- end:
+ switch_core_destroy_memory_pool(&pool);
-
+ end:
switch_mutex_lock(mod_sofia_globals.mutex);
mod_sofia_globals.threads--;
switch_mutex_unlock(mod_sofia_globals.mutex);
@@ -444,9 +692,12 @@
switch_threadattr_create(&thd_attr, profile->pool);
switch_threadattr_detach_set(thd_attr, 1);
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
+ switch_threadattr_priority_increase(thd_attr);
switch_thread_create(&thread, thd_attr, sofia_profile_thread_run, profile, profile->pool);
}
+
+
static void logger(void *logarg, char const *fmt, va_list ap)
{
char *data = NULL;
@@ -473,7 +724,6 @@
}
}
-
static void parse_gateways(sofia_profile_t *profile, switch_xml_t gateways_tag)
{
switch_xml_t gateway_tag, param;
@@ -487,6 +737,14 @@
name = "anonymous";
}
+ switch_mutex_lock(mod_sofia_globals.hash_mutex);
+ if ((gp = switch_core_hash_find(mod_sofia_globals.gateway_hash, name))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Ignoring duplicate gateway '%s'\n", name);
+ switch_mutex_unlock(mod_sofia_globals.hash_mutex);
+ goto skip;
+ }
+ switch_mutex_unlock(mod_sofia_globals.hash_mutex);
+
if ((gateway = switch_core_alloc(profile->pool, sizeof(*gateway)))) {
char *register_str = "true", *scheme = "Digest",
*realm = NULL,
@@ -498,8 +756,14 @@
*context = "default",
*expire_seconds = "3600",
*retry_seconds = "30",
- *from_domain = "";
-
+ *from_user = "",
+ *from_domain = "",
+ *register_proxy = NULL,
+ *contact_params = NULL,
+ *params = NULL,
+ *register_transport = NULL;
+
+ gateway->register_transport = SOFIA_TRANSPORT_UDP;
gateway->pool = profile->pool;
gateway->profile = profile;
gateway->name = switch_core_strdup(gateway->pool, name);
@@ -532,8 +796,23 @@
expire_seconds = val;
} else if (!strcmp(var, "retry-seconds")) {
retry_seconds = val;
+ } else if (!strcmp(var, "from-user")) {
+ from_user = val;
} else if (!strcmp(var, "from-domain")) {
from_domain = val;
+ } else if (!strcmp(var, "register-proxy")) {
+ register_proxy = val;
+ } else if (!strcmp(var, "contact-params")) {
+ contact_params = val;
+ } else if (!strcmp(var, "register-transport")) {
+ sofia_transport_t transport = sofia_glue_str2transport(val);
+
+ if (transport == SOFIA_TRANSPORT_UNKNOWN || (!sofia_test_pflag(profile, PFLAG_TLS) && sofia_glue_transport_has_tls(transport))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ERROR: unsupported transport\n");
+ goto skip;
+ }
+
+ gateway->register_transport = transport;
}
}
@@ -551,6 +830,10 @@
goto skip;
}
+ if (switch_strlen_zero(from_user)) {
+ from_user = username;
+ }
+
if (switch_strlen_zero(extension)) {
extension = username;
}
@@ -567,6 +850,10 @@
from_domain = realm;
}
+ if (switch_strlen_zero(register_proxy)) {
+ register_proxy = proxy;
+ }
+
gateway->retry_seconds = atoi(retry_seconds);
if (gateway->retry_seconds < 10) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "INVALID: retry_seconds correcting the value to 30\n");
@@ -580,10 +867,23 @@
if (switch_true(caller_id_in_from)) {
switch_set_flag(gateway, REG_FLAG_CALLERID);
}
- gateway->register_from = switch_core_sprintf(gateway->pool, "sip:%s@%s", username, from_domain);
- gateway->register_contact = switch_core_sprintf(gateway->pool, "sip:%s@%s:%d", extension,
- profile->extsipip ? profile->extsipip : profile->sipip, profile->sip_port);
-
+ register_transport = (char *)sofia_glue_transport2str(gateway->register_transport);
+ if (contact_params) {
+ if (*contact_params == ';') {
+ params = switch_core_sprintf(gateway->pool, "%s&transport=%s", contact_params, register_transport);
+ } else {
+ params = switch_core_sprintf(gateway->pool, ";%s&transport=%s", contact_params, register_transport);
+ }
+ } else {
+ params = switch_core_sprintf(gateway->pool, ";transport=%s", register_transport);
+ }
+
+ gateway->register_url = switch_core_sprintf(gateway->pool, "sip:%s;transport=%s", register_proxy, register_transport);
+ gateway->register_from = switch_core_sprintf(gateway->pool, "<sip:%s@%s;transport=%s>", from_user, from_domain, register_transport);
+ gateway->register_contact = switch_core_sprintf(gateway->pool, "<sip:%s@%s:%d%s>", extension,
+ profile->extsipip ? profile->extsipip : profile->sipip,
+ sofia_glue_transport_has_tls(gateway->register_transport) ? profile->tls_sip_port : profile->sip_port, params);
+
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);
@@ -596,35 +896,45 @@
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);
+ "Invalid Freq: %d. Setting Register-Frequency to 3600\n", gateway->freq);
gateway->freq = 3600;
}
gateway->freq -= 2;
- if ((gp = sofia_reg_find_gateway(gateway->name))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Ignoring duplicate gateway '%s'\n", gateway->name);
- sofia_reg_release_gateway(gp);
- } else if ((gp=sofia_reg_find_gateway(gateway->register_from))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Ignoring duplicate uri '%s'\n", gateway->register_from);
- sofia_reg_release_gateway(gp);
- } else if ((gp=sofia_reg_find_gateway(gateway->register_contact))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Ignoring duplicate contact '%s'\n", gateway->register_contact);
- sofia_reg_release_gateway(gp);
- } else {
- gateway->next = profile->gateways;
- profile->gateways = gateway;
- sofia_reg_add_gateway(gateway->name, gateway);
- sofia_reg_add_gateway(gateway->register_from, gateway);
- sofia_reg_add_gateway(gateway->register_contact, gateway);
- }
+ gateway->next = profile->gateways;
+ profile->gateways = gateway;
+ sofia_reg_add_gateway(gateway->name, gateway);
}
skip:
- assert(gateway_tag);
+ switch_assert(gateway_tag);
}
+}
+
+static void parse_domain_tag(sofia_profile_t *profile, switch_xml_t x_domain_tag, const char *dname, const char *parse, const char *alias)
+{
+
+ if (switch_true(alias)) {
+ if (sofia_glue_add_profile(switch_core_strdup(profile->pool, dname), profile) == SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Adding Alias [%s] for profile [%s]\n", dname, profile->name);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Adding Alias [%s] for profile [%s] (name in use)\n",
+ dname, profile->name);
+ }
+ }
+
+ if (switch_true(parse)) {
+ switch_xml_t ut, gateways_tag;
+ for (ut = switch_xml_child(x_domain_tag, "user"); ut; ut = ut->next) {
+ if (((gateways_tag = switch_xml_child(ut, "gateways")))) {
+ parse_gateways(profile, gateways_tag);
+ }
+ }
+ }
}
+
switch_status_t config_sofia(int reload, char *profile_name)
{
char *cf = "sofia.conf";
@@ -633,14 +943,19 @@
sofia_profile_t *profile = NULL;
char url[512] = "";
int profile_found = 0;
-
+ switch_event_t *params = NULL;;
+
if (!reload) {
su_init();
+ if (sip_update_default_mclass(sip_extend_mclass(NULL)) < 0) {
+ su_deinit();
+ return SWITCH_STATUS_FALSE;
+ }
+
su_log_redirect(NULL, logger, NULL);
su_log_redirect(tport_log, logger, NULL);
}
-
if (!switch_strlen_zero(profile_name) && (profile = sofia_glue_find_profile(profile_name))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Profile [%s] Already exists.\n", switch_str_nil(profile_name));
status = SWITCH_STATUS_FALSE;
@@ -648,9 +963,11 @@
return status;
}
- snprintf(url, sizeof(url), "profile=%s", switch_str_nil(profile_name));
-
- if (!(xml = switch_xml_open_cfg(cf, &cfg, url))) {
+ switch_event_create(¶ms, SWITCH_EVENT_MESSAGE);
+ switch_assert(params);
+ switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "profile", profile_name);
+
+ if (!(xml = switch_xml_open_cfg(cf, &cfg, params))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open of %s failed\n", cf);
status = SWITCH_STATUS_FALSE;
goto done;
@@ -662,8 +979,6 @@
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));
}
}
}
@@ -674,12 +989,13 @@
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");
+ char *xprofiledomain = (char *) switch_xml_attr(xprofile, "domain");
switch_memory_pool_t *pool = NULL;
if (!xprofilename) {
xprofilename = "unnamed";
}
-
+
if (profile_name) {
if (strcasecmp(profile_name, xprofilename)) {
continue;
@@ -687,7 +1003,7 @@
profile_found = 1;
}
}
-
+
/* 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");
@@ -699,20 +1015,27 @@
goto done;
}
-
-
profile->pool = pool;
+ profile->user_agent = SOFIA_USER_AGENT;
profile->name = switch_core_strdup(profile->pool, xprofilename);
- snprintf(url, sizeof(url), "sofia_reg_%s", xprofilename);
-
+ switch_snprintf(url, sizeof(url), "sofia_reg_%s", xprofilename);
+
+ if (xprofiledomain) {
+ profile->domain_name = switch_core_strdup(profile->pool, xprofiledomain);
+ } else {
+ profile->domain_name = profile->name;
+ }
+
profile->dbname = switch_core_strdup(profile->pool, url);
switch_core_hash_init(&profile->chat_hash, profile->pool);
+ switch_core_hash_init(&profile->sub_hash, profile->pool);
switch_thread_rwlock_create(&profile->rwlock, profile->pool);
switch_mutex_init(&profile->flag_mutex, SWITCH_MUTEX_NESTED, profile->pool);
profile->dtmf_duration = 100;
- profile->codec_ms = 20;
-
+ profile->tls_version = 0;
+ profile->mflags = MFLAG_REFER | MFLAG_REGISTER;
+
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");
@@ -721,31 +1044,47 @@
profile->debug = atoi(val);
} else if (!strcasecmp(var, "use-rtp-timer") && switch_true(val)) {
switch_set_flag(profile, TFLAG_TIMER);
-
- } else if (!strcasecmp(var, "odbc-dsn")) {
+ } else if (!strcasecmp(var, "sip-trace") && switch_true(val)) {
+ switch_set_flag(profile, TFLAG_TPORT_LOG);
+ } else if (!strcasecmp(var, "odbc-dsn") && !switch_strlen_zero(val)) {
#ifdef SWITCH_HAVE_ODBC
profile->odbc_dsn = switch_core_strdup(profile->pool, val);
if ((profile->odbc_user = strchr(profile->odbc_dsn, ':'))) {
*profile->odbc_user++ = '\0';
+ if ((profile->odbc_pass = strchr(profile->odbc_user, ':'))) {
+ *profile->odbc_pass++ = '\0';
+ }
}
- if ((profile->odbc_pass = strchr(profile->odbc_user, ':'))) {
- *profile->odbc_pass++ = '\0';
- }
-
+
#else
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ODBC IS NOT AVAILABLE!\n");
#endif
-
+ } else if (!strcasecmp(var, "user-agent-string")) {
+ profile->user_agent = switch_core_strdup(profile->pool, val);;
+ } else if (!strcasecmp(var, "dtmf-type")) {
+ if (!strcasecmp(val, "rfc2833")) {
+ profile->dtmf_type = DTMF_2833;
+ } else if (!strcasecmp(val, "info")) {
+ profile->dtmf_type = DTMF_INFO;
+ } else {
+ profile->dtmf_type = DTMF_NONE;
+ }
+ } else if (!strcasecmp(var, "record-template")) {
+ profile->record_template = switch_core_strdup(profile->pool, val);;
} else if (!strcasecmp(var, "inbound-no-media") && switch_true(val)) {
switch_set_flag(profile, TFLAG_INB_NOMEDIA);
+ } else if (!strcasecmp(var, "inbound-bypass-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, "inbound-proxy-media") && switch_true(val)) {
+ switch_set_flag(profile, TFLAG_PROXY_MEDIA);
} 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);
+ profile->sip_port = strcasecmp(val, "auto") ? atoi(val) : 0;
} else if (!strcasecmp(var, "vad")) {
if (!strcasecmp(val, "in")) {
switch_set_flag(profile, TFLAG_VAD_IN);
@@ -767,16 +1106,16 @@
if (!strcasecmp(val, "auto")) {
profile->extsipip = switch_core_strdup(profile->pool, mod_sofia_globals.guess_ip);
} else {
- char *ip = NULL;
+ char *ip = mod_sofia_globals.guess_ip;
switch_port_t port = 0;
if (sofia_glue_ext_address_lookup(&ip, &port, val, profile->pool) == SWITCH_STATUS_SUCCESS) {
-
- if (ip) {
- profile->extsipip = switch_core_strdup(profile->pool, ip);
- }
+ profile->extsipip = switch_core_strdup(profile->pool, ip);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to get external ip.\n");
}
}
-
+ } else if (!strcasecmp(var, "force-register-domain")) {
+ profile->reg_domain = switch_core_strdup(profile->pool, val);
} else if (!strcasecmp(var, "bind-params")) {
profile->bind_params = switch_core_strdup(profile->pool, val);
} else if (!strcasecmp(var, "sip-domain")) {
@@ -785,14 +1124,54 @@
profile->timer_name = switch_core_strdup(profile->pool, val);
} else if (!strcasecmp(var, "hold-music")) {
profile->hold_music = switch_core_strdup(profile->pool, val);
+ } else if (!strcasecmp(var, "session-timeout")) {
+ int v_session_timeout = atoi(val);
+ if (v_session_timeout >= 0) {
+ profile->session_timeout = v_session_timeout;
+ }
+ } else if (!strcasecmp(var, "max-proceeding")) {
+ int v_max_proceeding = atoi(val);
+ if (v_max_proceeding >= 0) {
+ profile->max_proceeding = v_max_proceeding;
+ }
+ } else if (!strcasecmp(var, "rtp-timeout-sec")) {
+ int v = atoi(val);
+ if (v >= 0) {
+ profile->rtp_timeout_sec = v;
+ }
+ } else if (!strcasecmp(var, "rtp-hold-timeout-sec")) {
+ int v = atoi(val);
+ if (v >= 0) {
+ profile->rtp_hold_timeout_sec = v;
+ }
+ } else if (!strcasecmp(var, "disable-transfer") && switch_true(val)) {
+ profile->mflags &= ~MFLAG_REFER;
+ } else if (!strcasecmp(var, "disable-register") && switch_true(val)) {
+ profile->mflags &= ~MFLAG_REGISTER;
} else if (!strcasecmp(var, "manage-presence")) {
if (switch_true(val)) {
profile->pflags |= PFLAG_PRESENCE;
}
+ } else if (!strcasecmp(var, "require-secure-rtp")) {
+ if (switch_true(val)) {
+ profile->pflags |= PFLAG_SECURE;
+ }
+ } else if (!strcasecmp(var, "multiple-registrations")) {
+ if (switch_true(val)) {
+ profile->pflags |= PFLAG_MULTIREG;
+ }
+ } else if (!strcasecmp(var, "supress-cng")) {
+ if (switch_true(val)) {
+ profile->pflags |= PFLAG_SUPRESS_CNG;
+ }
} else if (!strcasecmp(var, "NDLB-to-in-200-contact")) {
if (switch_true(val)) {
profile->ndlb |= PFLAG_NDLB_TO_IN_200_CONTACT;
}
+ } else if (!strcasecmp(var, "NDLB-broken-auth-hash")) {
+ if (switch_true(val)) {
+ profile->ndlb |= PFLAG_NDLB_BROKEN_AUTH_HASH;
+ }
} else if (!strcasecmp(var, "pass-rfc2833")) {
if (switch_true(val)) {
profile->pflags |= PFLAG_PASS_RFC2833;
@@ -819,6 +1198,10 @@
if (switch_true(val)) {
profile->pflags |= PFLAG_BLIND_REG;
}
+ } else if (!strcasecmp(var, "accept-blind-auth")) {
+ if (switch_true(val)) {
+ profile->pflags |= PFLAG_BLIND_AUTH;
+ }
} else if (!strcasecmp(var, "auth-all-packets")) {
if (switch_true(val)) {
profile->pflags |= PFLAG_AUTH_ALL;
@@ -827,6 +1210,10 @@
if (switch_true(val)) {
profile->pflags |= PFLAG_FULL_ID;
}
+ } else if (!strcasecmp(var, "inbound-reg-force-matching-username")) {
+ if (switch_true(val)) {
+ profile->pflags |= PFLAG_CHECKUSER;
+ }
} else if (!strcasecmp(var, "bitpacking")) {
if (!strcasecmp(val, "aal2")) {
profile->codec_flags = SWITCH_CODEC_FLAG_AAL2;
@@ -835,6 +1222,18 @@
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, "apply-inbound-acl")) {
+ if (profile->acl_count < SOFIA_MAX_ACL) {
+ profile->acl[profile->acl_count++] = switch_core_strdup(profile->pool, val);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Max acl records of %d reached\n", SOFIA_MAX_ACL);
+ }
+ } else if (!strcasecmp(var, "apply-register-acl")) {
+ if (profile->reg_acl_count < SOFIA_MAX_ACL) {
+ profile->reg_acl[profile->reg_acl_count++] = switch_core_strdup(profile->pool, val);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Max acl records of %d reached\n", SOFIA_MAX_ACL);
+ }
} else if (!strcasecmp(var, "alias")) {
sip_alias_node_t *node;
if ((node = switch_core_alloc(profile->pool, sizeof(*node)))) {
@@ -849,8 +1248,6 @@
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) {
@@ -858,7 +1255,28 @@
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Duration out of bounds!\n");
}
- }
+
+ /*
+ * handle TLS params #1
+ */
+ } else if (!strcasecmp(var, "tls")) {
+ if (switch_true(val)) {
+ sofia_set_pflag(profile, PFLAG_TLS);
+ }
+ } else if (!strcasecmp(var, "tls-bind-params")) {
+ profile->tls_bind_params = switch_core_strdup(profile->pool, val);
+ } else if (!strcasecmp(var, "tls-sip-port")) {
+ profile->tls_sip_port = atoi(val);
+ } else if (!strcasecmp(var, "tls-cert-dir")) {
+ profile->tls_cert_dir = switch_core_strdup(profile->pool, val);
+ } else if (!strcasecmp(var, "tls-version")) {
+
+ if (!strcasecmp(val, "tlsv1")) {
+ profile->tls_version = 1;
+ } else {
+ profile->tls_version = 0;
+ }
+ }
}
if (!profile->cng_pt) {
@@ -891,10 +1309,6 @@
profile->rtpip = switch_core_strdup(profile->pool, "127.0.0.1");
}
- if (!profile->sip_port) {
- profile->sip_port = atoi(SOFIA_DEFAULT_PORT);
- }
-
if (!profile->dialplan) {
profile->dialplan = switch_core_strdup(profile->pool, "XML");
}
@@ -903,18 +1317,51 @@
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);
+ if (!profile->sip_port) {
+ profile->url = switch_core_sprintf(profile->pool, "sip:mod_sofia@%s:*", profile->extsipip);
+ } else {
+ 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);
+ if (!profile->sip_port) {
+ profile->url = switch_core_sprintf(profile->pool, "sip:mod_sofia@%s:*", 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->bind_params) {
- char *url = profile->bindurl;
- profile->bindurl = switch_core_sprintf(profile->pool, "%s;%s", url, profile->bind_params);
+ char *bindurl = profile->bindurl;
+ profile->bindurl = switch_core_sprintf(profile->pool, "%s;%s", bindurl, profile->bind_params);
+ }
+
+ /*
+ * handle TLS params #2
+ */
+ if (sofia_test_pflag(profile, PFLAG_TLS)) {
+ if (!profile->tls_sip_port) {
+ profile->tls_sip_port = atoi(SOFIA_DEFAULT_TLS_PORT);
+ }
+
+ if (profile->extsipip) {
+ profile->tls_url = switch_core_sprintf(profile->pool, "sip:mod_sofia@%s:%d", profile->extsipip, profile->tls_sip_port);
+ profile->tls_bindurl = switch_core_sprintf(profile->pool, "sips:mod_sofia@%s:%d;maddr=%s", profile->extsipip, profile->tls_sip_port, profile->sipip);
+ } else {
+ profile->tls_url = switch_core_sprintf(profile->pool, "sip:mod_sofia@%s:%d", profile->sipip, profile->tls_sip_port);
+ profile->tls_bindurl = switch_core_sprintf(profile->pool, "sips:mod_sofia@%s:%d", profile->sipip, profile->tls_sip_port);
+ }
+
+ if (profile->tls_bind_params) {
+ char *tls_bindurl = profile->tls_bindurl;
+ profile->tls_bindurl = switch_core_sprintf(profile->pool, "%s;%s", tls_bindurl, profile->tls_bind_params);
+ }
+
+ if (!profile->tls_cert_dir) {
+ profile->tls_cert_dir = switch_core_sprintf(profile->pool, "%s/ssl", SWITCH_GLOBAL_dirs.conf_dir);
+ }
}
-
}
if (profile) {
switch_xml_t aliases_tag, alias_tag;
@@ -928,26 +1375,29 @@
if ((domains_tag = switch_xml_child(xprofile, "domains"))) {
for (domain_tag = switch_xml_child(domains_tag, "domain"); domain_tag; domain_tag = domain_tag->next) {
- switch_xml_t droot, actual_domain_tag, ut;
- char *dname = (char *) switch_xml_attr_soft(domain_tag, "name");
- char *parse = (char *) switch_xml_attr_soft(domain_tag, "parse");
-
+ switch_xml_t droot, x_domain_tag;
+ const char *dname = switch_xml_attr_soft(domain_tag, "name");
+ const char *parse = switch_xml_attr_soft(domain_tag, "parse");
+ const char *alias = switch_xml_attr_soft(domain_tag, "alias");
+
if (!switch_strlen_zero(dname)) {
- if (switch_true(parse)) {
- if (switch_xml_locate_domain(dname, NULL, &droot, &actual_domain_tag) == SWITCH_STATUS_SUCCESS) {
- for (ut = switch_xml_child(actual_domain_tag, "user"); ut; ut = ut->next) {
- if (((gateways_tag = switch_xml_child(ut, "gateways")))) {
- parse_gateways(profile, gateways_tag);
- }
+ if (!strcasecmp(dname, "all")) {
+ switch_xml_t xml_root, x_domains;
+ if (switch_xml_locate("directory", NULL, NULL, NULL, &xml_root, &x_domains, NULL) == SWITCH_STATUS_SUCCESS) {
+ for(x_domain_tag = switch_xml_child(x_domains, "domain"); x_domain_tag; x_domain_tag = x_domain_tag->next) {
+ dname = switch_xml_attr_soft(x_domain_tag, "name");
+ parse_domain_tag(profile, x_domain_tag, dname, parse, alias);
}
- switch_xml_free(droot);
+ switch_xml_free(xml_root);
}
+ } else if (switch_xml_locate_domain(dname, NULL, &droot, &x_domain_tag) == SWITCH_STATUS_SUCCESS) {
+ parse_domain_tag(profile, x_domain_tag, dname, parse, alias);
+ switch_xml_free(droot);
}
- sofia_glue_add_profile(switch_core_strdup(profile->pool, dname), profile);
}
}
}
-
+
if ((aliases_tag = switch_xml_child(xprofile, "aliases"))) {
for (alias_tag = switch_xml_child(aliases_tag, "alias"); alias_tag; alias_tag = alias_tag->next) {
char *aname = (char *) switch_xml_attr_soft(alias_tag, "name");
@@ -957,13 +1407,12 @@
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Adding Alias [%s] for profile [%s]\n", aname, profile->name);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Adding Alias [%s] for profile [%s] (name in use)\n",
- aname, profile->name);
+ aname, profile->name);
}
}
}
}
-
if (profile->sipip) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Started Profile %s [%s]\n", profile->name, url);
launch_sofia_profile_thread(profile);
@@ -978,6 +1427,9 @@
}
}
done:
+
+ switch_event_destroy(¶ms);
+
if (xml) {
switch_xml_free(xml);
}
@@ -988,7 +1440,131 @@
}
return status;
+}
+
+static void sofia_handle_sip_r_invite(switch_core_session_t *session, 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 && session) {
+ switch_channel_t *channel = switch_core_session_get_channel(session);
+ const char *uuid;
+ switch_core_session_t *other_session;
+ private_object_t *tech_pvt = switch_core_session_get_private(session);
+
+ switch_channel_clear_flag(channel, CF_REQ_MEDIA);
+
+ if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
+
+ if (!switch_test_flag(tech_pvt, TFLAG_SENT_UPDATE)) {
+ return;
+ }
+
+ switch_clear_flag_locked(tech_pvt, TFLAG_SENT_UPDATE);
+
+ if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE)) && (other_session = switch_core_session_locate(uuid))) {
+ const char *r_sdp = NULL;
+ switch_core_session_message_t msg = { 0 };
+
+ if (sip->sip_payload && sip->sip_payload->pl_data &&
+ sip->sip_content_type && sip->sip_content_type->c_subtype && switch_stristr("sdp", sip->sip_content_type->c_subtype)) {
+ r_sdp = sip->sip_payload->pl_data;
+ }
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Passing %d %s to other leg\n", status, phrase);
+
+ msg.message_id = SWITCH_MESSAGE_INDICATE_RESPOND;
+ msg.from = __FILE__;
+ msg.numeric_arg = status;
+ msg.string_arg = switch_core_session_strdup(other_session, phrase);
+ if (r_sdp) {
+ msg.pointer_arg = switch_core_session_strdup(other_session, r_sdp);
+ msg.pointer_arg_size = strlen(r_sdp);
+ }
+ if (switch_core_session_receive_message(other_session, &msg) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Other leg is not available\n");
+ nua_respond(tech_pvt->nh, 403, "Hangup in progress", TAG_END());
+ }
+ switch_core_session_rwunlock(other_session);
+ }
+ return;
+ }
+
+ if ((status == 180 || status == 183 || status == 200)) {
+ const char *astate = "early";
+ url_t *from = NULL, *to = NULL, *contact = NULL;
+
+ if (sip->sip_to) {
+ to = sip->sip_to->a_url;
+ }
+ if (sip->sip_from) {
+ from = sip->sip_from->a_url;
+ }
+ if (sip->sip_contact) {
+ contact = sip->sip_contact->m_url;
+ }
+
+ if (status == 200) {
+ astate = "confirmed";
+ }
+ if (!switch_channel_test_flag(channel, CF_EARLY_MEDIA) && !switch_channel_test_flag(channel, CF_ANSWERED) &&
+ !switch_channel_test_flag(channel, CF_RING_READY)) {
+ const char *from_user = "", *from_host = "", *to_user = "", *to_host = "", *contact_user = "", *contact_host = "";
+ const char *user_agent = "", *call_id = "";
+ char *sql = NULL;
+
+ if (sip->sip_user_agent) {
+ user_agent = switch_str_nil(sip->sip_user_agent->g_string);
+ }
+
+ if (sip->sip_call_id) {
+ call_id = switch_str_nil(sip->sip_call_id->i_id);
+ }
+
+ if (to) {
+ from_user = switch_str_nil(to->url_user);
+ }
+
+ if (from) {
+ from_host = switch_str_nil(from->url_host);
+ to_user = switch_str_nil(from->url_user);
+ to_host = switch_str_nil(from->url_host);
+ }
+
+ if (contact) {
+ contact_user = switch_str_nil(contact->url_user);
+ contact_host = switch_str_nil(contact->url_host);
+ }
+
+ if (profile->pflags & PFLAG_PRESENCE) {
+ sql = switch_mprintf(
+ "insert into sip_dialogs values('%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q')",
+ call_id,
+ switch_core_session_get_uuid(session),
+ to_user,
+ to_host,
+ from_user,
+ from_host,
+ contact_user,
+ contact_host,
+ astate,
+ "outbound",
+ user_agent
+ );
+
+ switch_assert(sql);
+
+ sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
+ }
+ } else if (status == 200 && (profile->pflags & PFLAG_PRESENCE)) {
+ char *sql = NULL;
+ sql = switch_mprintf("update sip_dialogs set state='%s' where uuid='%s';\n", astate, switch_core_session_get_uuid(session));
+ switch_assert(sql);
+ sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
+ }
+ }
+ }
}
static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
@@ -1001,12 +1577,11 @@
switch_channel_t *channel = NULL;
private_object_t *tech_pvt = NULL;
const char *replaces_str = NULL;
- char *uuid;
+ const char *uuid;
switch_core_session_t *other_session = NULL;
switch_channel_t *other_channel = NULL;
char st[80] = "";
-
tl_gets(tags,
NUTAG_CALLSTATE_REF(ss_state),
NUTAG_OFFER_RECV_REF(offer_recv),
@@ -1017,13 +1592,9 @@
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);
-
-
+ switch_assert(tech_pvt != NULL);
+ switch_assert(tech_pvt->nh != NULL);
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));
@@ -1040,6 +1611,19 @@
goto done;
}
+ if (status == 183 && !r_sdp) {
+ status = 180;
+ }
+
+ if (channel && (status == 180 || status == 183) && switch_channel_test_flag(channel, CF_OUTBOUND)) {
+ const char *val;
+ if ((val = switch_channel_get_variable(channel, "sip_auto_answer")) && switch_true(val)) {
+ nua_notify(nh, NUTAG_NEWSUB(1), NUTAG_SUBSTATE(nua_substate_active), SIPTAG_EVENT_STR("talk"), TAG_END());
+ }
+ }
+
+ state_process:
+
switch ((enum nua_callstate) ss_state) {
case nua_callstate_init:
break;
@@ -1052,7 +1636,7 @@
if (status == 180) {
switch_channel_mark_ring_ready(channel);
if (!switch_channel_test_flag(channel, CF_GEN_RINGBACK)) {
- if (switch_channel_test_flag(channel, CF_BYPASS_MEDIA)) {
+ if (switch_channel_test_flag(channel, CF_PROXY_MODE)) {
if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))
&& (other_session = switch_core_session_locate(uuid))) {
switch_core_session_message_t msg;
@@ -1069,9 +1653,15 @@
}
if (r_sdp) {
- if (switch_channel_test_flag(channel, CF_BYPASS_MEDIA)) {
+ if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
switch_set_flag_locked(tech_pvt, TFLAG_EARLY_MEDIA);
switch_channel_mark_pre_answered(channel);
+ switch_set_flag(tech_pvt, TFLAG_SDP);
+ if (switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
+ if (sofia_glue_activate_rtp(tech_pvt, 0) != SWITCH_STATUS_SUCCESS) {
+ goto done;
+ }
+ }
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);
@@ -1084,7 +1674,9 @@
}
goto done;
} else {
- if (switch_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION)) {
+ if (switch_channel_test_flag(channel, CF_PROXY_MEDIA) && !switch_channel_test_flag(tech_pvt->channel, CF_OUTBOUND)) {
+ switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "PROXY MEDIA");
+ } else if (switch_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION) && !switch_channel_test_flag(tech_pvt->channel, CF_OUTBOUND)) {
switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "DELAYED NEGOTIATION");
} else {
if (sofia_glue_tech_media(tech_pvt, (char *) r_sdp) != SWITCH_STATUS_SUCCESS) {
@@ -1104,13 +1696,27 @@
case nua_callstate_received:
if (tech_pvt && !switch_test_flag(tech_pvt, TFLAG_SDP)) {
if (r_sdp && !switch_test_flag(tech_pvt, TFLAG_SDP)) {
- if (switch_channel_test_flag(channel, CF_BYPASS_MEDIA)) {
+ if (switch_channel_test_flag(channel, CF_PROXY_MODE)) {
switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "RECEIVED_NOMEDIA");
switch_set_flag_locked(tech_pvt, TFLAG_READY);
- switch_channel_set_state(channel, CS_INIT);
- //switch_core_session_thread_launch(session);
+ if (switch_channel_get_state(channel) == CS_NEW) {
+ switch_channel_set_state(channel, CS_INIT);
+ }
+ switch_set_flag(tech_pvt, TFLAG_SDP);
goto done;
- } else {
+ } else if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA)) {
+ switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "PROXY MEDIA");
+ switch_set_flag_locked(tech_pvt, TFLAG_READY);
+ if (switch_channel_get_state(channel) == CS_NEW) {
+ switch_channel_set_state(channel, CS_INIT);
+ }
+ } else if (switch_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION)) {
+ switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "DELAYED NEGOTIATION");
+ switch_set_flag_locked(tech_pvt, TFLAG_READY);
+ if (switch_channel_get_state(channel) == CS_NEW) {
+ switch_channel_set_state(channel, CS_INIT);
+ }
+ } else {
sdp_parser_t *parser;
sdp_session_t *sdp;
uint8_t match = 0;
@@ -1127,59 +1733,77 @@
if (match) {
nua_handle_t *bnh;
sip_replaces_t *replaces;
+ su_home_t *home = NULL;
switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "RECEIVED");
switch_set_flag_locked(tech_pvt, TFLAG_READY);
- switch_channel_set_state(channel, CS_INIT);
- //switch_core_session_thread_launch(session);
-
- if (replaces_str && (replaces = sip_replaces_make(tech_pvt->sofia_private->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);
+ if (switch_channel_get_state(channel) == CS_NEW) {
+ switch_channel_set_state(channel, CS_INIT);
+ }
+ switch_set_flag(tech_pvt, TFLAG_SDP);
+ if (replaces_str) {
+ home = su_home_new(sizeof(*home));
+ switch_assert(home != NULL);
+ if ((replaces = sip_replaces_make(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))) {
+ const 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_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
+ 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);
}
- } 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);
}
- nua_handle_unref(bnh);
+ su_home_unref(home);
+ home = NULL;
}
+
goto done;
}
switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "NO CODECS");
- nua_respond(nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
switch_channel_hangup(channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION);
}
} else {
- if (switch_channel_test_flag(channel, CF_BYPASS_MEDIA)) {
+ if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
goto done;
} else {
switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "RECEIVED_NOSDP");
- switch_set_flag(tech_pvt, TFLAG_LATE_NEGOTIATION);
+ sofia_glue_tech_choose_port(tech_pvt, 0);
sofia_glue_set_local_sdp(tech_pvt, NULL, 0, NULL, 0);
-
+ switch_channel_set_state(channel, CS_HIBERNATE);
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());
+ SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str),
+ SOATAG_REUSE_REJECTED(1),
+ SOATAG_ORDERED_USER(1),
+ SOATAG_AUDIO_AUX("cn telephone-event"),
+ NUTAG_INCLUDE_EXTRA_SDP(1),
+ TAG_END());
goto done;
}
}
+
+ } else {
+ ss_state = nua_callstate_completed;
+ goto state_process;
}
break;
@@ -1192,7 +1816,24 @@
uint8_t match = 0;
if (r_sdp) {
- if (switch_channel_test_flag(channel, CF_BYPASS_MEDIA)) {
+ if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
+ if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))
+ && (other_session = switch_core_session_locate(uuid))) {
+ switch_core_session_message_t msg = { 0 };
+
+ msg.message_id = SWITCH_MESSAGE_INDICATE_MEDIA_REDIRECT;
+ msg.from = __FILE__;
+ msg.string_arg = (char *) r_sdp;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Passing SDP to other leg.\n%s\n", r_sdp);
+ if (switch_core_session_receive_message(other_session, &msg) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Other leg is not available\n");
+ nua_respond(tech_pvt->nh, 403, "Hangup in progress", TAG_END());
+ }
+ switch_core_session_rwunlock(other_session);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Re-INVITE to a no-media channel that is not in a bridge.\n");
+ switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+ }
goto done;
} else {
if (tech_pvt->num_codecs) {
@@ -1204,12 +1845,12 @@
}
}
if (match) {
- if (sofia_glue_tech_choose_port(tech_pvt) != SWITCH_STATUS_SUCCESS) {
+ if (sofia_glue_tech_choose_port(tech_pvt, 0) != SWITCH_STATUS_SUCCESS) {
goto done;
}
sofia_glue_set_local_sdp(tech_pvt, NULL, 0, NULL, 0);
switch_set_flag_locked(tech_pvt, TFLAG_REINVITE);
- if (sofia_glue_activate_rtp(tech_pvt) != SWITCH_STATUS_SUCCESS) {
+ if (sofia_glue_activate_rtp(tech_pvt, 0) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Reinvite RTP Error!\n");
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
}
@@ -1219,17 +1860,30 @@
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
}
}
+
+
+ nua_respond(tech_pvt->nh, SIP_200_OK,
+ SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
+ SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str),
+ SOATAG_REUSE_REJECTED(1),
+ SOATAG_ORDERED_USER(1),
+ SOATAG_AUDIO_AUX("cn telephone-event"),
+ NUTAG_INCLUDE_EXTRA_SDP(1),
+ TAG_END());
}
}
break;
case nua_callstate_ready:
+ if (channel) {
+ switch_channel_clear_flag(channel, CF_REQ_MEDIA);
+ }
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 (sofia_glue_tech_choose_port(tech_pvt) == SWITCH_STATUS_SUCCESS) {
- if (sofia_glue_activate_rtp(tech_pvt) != SWITCH_STATUS_SUCCESS) {
+ if (sofia_glue_tech_choose_port(tech_pvt, 0) == SWITCH_STATUS_SUCCESS) {
+ if (sofia_glue_activate_rtp(tech_pvt, 0) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cheater Reinvite RTP Error!\n");
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
}
@@ -1240,6 +1894,7 @@
if (channel) {
if (switch_test_flag(tech_pvt, TFLAG_EARLY_MEDIA)) {
switch_set_flag_locked(tech_pvt, TFLAG_ANS);
+ switch_set_flag(tech_pvt, TFLAG_SDP);
switch_channel_mark_answered(channel);
if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))
&& (other_session = switch_core_session_locate(uuid))) {
@@ -1254,9 +1909,15 @@
r_sdp = (const char *) switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE);
}
if (r_sdp && !switch_test_flag(tech_pvt, TFLAG_SDP)) {
- if (switch_channel_test_flag(channel, CF_BYPASS_MEDIA)) {
+ if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
switch_set_flag_locked(tech_pvt, TFLAG_ANS);
+ switch_set_flag_locked(tech_pvt, TFLAG_SDP);
switch_channel_mark_answered(channel);
+ if (switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
+ if (sofia_glue_activate_rtp(tech_pvt, 0) != SWITCH_STATUS_SUCCESS) {
+ goto done;
+ }
+ }
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);
@@ -1283,27 +1944,37 @@
if (match) {
switch_set_flag_locked(tech_pvt, TFLAG_ANS);
- if (sofia_glue_tech_choose_port(tech_pvt) == SWITCH_STATUS_SUCCESS) {
- if (sofia_glue_activate_rtp(tech_pvt) == SWITCH_STATUS_SUCCESS) {
+ if (sofia_glue_tech_choose_port(tech_pvt, 0) == SWITCH_STATUS_SUCCESS) {
+ if (sofia_glue_activate_rtp(tech_pvt, 0) == SWITCH_STATUS_SUCCESS) {
switch_channel_mark_answered(channel);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "RTP Error!\n");
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
}
+ if (switch_channel_get_state(channel) == CS_HIBERNATE) {
+ switch_set_flag_locked(tech_pvt, TFLAG_READY);
+ if (switch_channel_get_state(channel) == CS_NEW) {
+ switch_channel_set_state(channel, CS_INIT);
+ }
+ switch_set_flag(tech_pvt, TFLAG_SDP);
+ }
goto done;
}
}
switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "NO CODECS");
- nua_respond(nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
switch_channel_hangup(channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION);
}
}
-
}
break;
case nua_callstate_terminating:
+ if (session) {
+ if (!switch_test_flag(tech_pvt, TFLAG_BYE)) {
+ switch_set_flag_locked(tech_pvt, TFLAG_BYE);
+ }
+ }
break;
case nua_callstate_terminated:
if (session) {
@@ -1312,27 +1983,30 @@
if (switch_test_flag(tech_pvt, TFLAG_NOHUP)) {
switch_clear_flag_locked(tech_pvt, TFLAG_NOHUP);
} else {
- snprintf(st, sizeof(st), "%d", status);
+ int cause;
+ if (tech_pvt->q850_cause) {
+ cause = tech_pvt->q850_cause;
+ } else {
+ cause = sofia_glue_sip_cause_to_freeswitch(status);
+ }
+ switch_snprintf(st, sizeof(st), "%d", status);
switch_channel_set_variable(channel, "sip_term_status", st);
- switch_channel_hangup(channel, sofia_glue_sip_cause_to_freeswitch(status));
+ switch_snprintf(st, sizeof(st), "%d", cause);
+ switch_channel_set_variable(channel, "sip_term_cause", st);
+ switch_channel_hangup(channel, cause);
}
}
if (tech_pvt->sofia_private) {
- if (tech_pvt->sofia_private->home) {
- su_home_unref(tech_pvt->sofia_private->home);
- }
- free(tech_pvt->sofia_private);
+ sofia_private = tech_pvt->sofia_private;
tech_pvt->sofia_private = NULL;
+ free(sofia_private);
}
tech_pvt->nh = NULL;
} else if (sofia_private) {
- if (sofia_private->home) {
- su_home_unref(sofia_private->home);
- }
free(sofia_private);
}
@@ -1344,11 +2018,9 @@
}
done:
-
return;
}
-
/*---------------------------------------*/
void sofia_handle_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[])
{
@@ -1356,29 +2028,44 @@
sip_from_t const *from;
sip_to_t const *to;
sip_refer_to_t const *refer_to;
- private_object_t *tech_pvt = NULL;
+ private_object_t *tech_pvt = switch_core_session_get_private(session);
char *etmp = NULL, *exten = NULL;
- switch_channel_t *channel_a = NULL, *channel_b = NULL;
+ switch_channel_t *channel_a = switch_core_session_get_channel(session);
+ switch_channel_t *channel_b = NULL;
+ su_home_t *home = NULL;
+ char *full_ref_by = NULL;
+ char *full_ref_to = NULL;
- tech_pvt = switch_core_session_get_private(session);
- channel_a = switch_core_session_get_channel(session);
+ if (!(profile->mflags & MFLAG_REFER)) {
+ nua_respond(nh, SIP_403_FORBIDDEN, NUTAG_WITH_THIS(nua), TAG_END());
+ goto done;
+ }
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_BYPASS_MEDIA)) {
- nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
+ if (switch_channel_test_flag(channel_a, CF_PROXY_MODE)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Transfer on bypass media not allowed.\n");
+ nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), 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;
+
+ home = su_home_new(sizeof(*home));
+ switch_assert(home != NULL);
+
+ if (sip->sip_referred_by) {
+ full_ref_by = sip_header_as_string(home, (void *) sip->sip_referred_by);
+ }
if ((refer_to = sip->sip_refer_to)) {
+ full_ref_to = sip_header_as_string(home, (void *) 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 {
@@ -1393,11 +2080,10 @@
char *rep;
if ((rep = strchr(refer_to->r_url->url_headers, '='))) {
- char *br_a = NULL, *br_b = NULL;
+ const char *br_a = NULL, *br_b = NULL;
char *buf;
- rep++;
-
+ rep++;
if ((buf = switch_core_session_alloc(session, strlen(rep) + 1))) {
rep = url_unescape(buf, (const char *) rep);
@@ -1406,7 +2092,8 @@
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n");
goto done;
}
- if ((replaces = sip_replaces_make(tech_pvt->sofia_private->home, rep))
+
+ if ((replaces = sip_replaces_make(home, rep))
&& (bnh = nua_handle_by_replaces(nua, replaces))) {
sofia_private_t *b_private = NULL;
private_object_t *b_tech_pvt = NULL;
@@ -1422,56 +2109,88 @@
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);
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Attended Transfer [%s][%s]\n", switch_str_nil(br_a), switch_str_nil(br_b));
if (br_a && br_b) {
- switch_ivr_uuid_bridge(br_a, br_b);
+ switch_core_session_t *new_b_session = NULL, *a_session = NULL;
+
+ switch_ivr_uuid_bridge(br_b, br_a);
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"),
+ nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), 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());
+ switch_clear_flag_locked(b_tech_pvt, TFLAG_SIP_HOLD);
+ switch_ivr_park_session(b_session);
+ new_b_session = switch_core_session_locate(br_b);
+ a_session = switch_core_session_locate(br_a);
+ sofia_info_send_sipfrag(a_session, new_b_session);
+ if (new_b_session) {
+ switch_core_session_rwunlock(new_b_session);
+ }
+ if (a_session) {
+ switch_core_session_rwunlock(a_session);
+ }
+ //switch_channel_hangup(channel_b, SWITCH_CAUSE_ATTENDED_TRANSFER);
} 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;
+ switch_set_flag_locked(tech_pvt, TFLAG_BYE);
+ nua_notify(tech_pvt->nh,
+ NUTAG_NEWSUB(1),
+ 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 {
+ switch_core_session_t *t_session;
+ switch_channel_t *hup_channel;
+ const char *ext;
+
+ if (br_a && !br_b) {
+ t_session = switch_core_session_locate(br_a);
+ hup_channel = channel_b;
+ } else {
+ private_object_t *h_tech_pvt = (private_object_t *) switch_core_session_get_private(b_session);
+ t_session = switch_core_session_locate(br_b);
+ hup_channel = channel_a;
+ switch_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
+ switch_clear_flag_locked(h_tech_pvt, TFLAG_SIP_HOLD);
+ switch_channel_hangup(channel_b, SWITCH_CAUSE_ATTENDED_TRANSFER);
+ }
- 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;
- if (sofia_glue_activate_rtp(tech_pvt) == SWITCH_STATUS_SUCCESS) {
- br_b_tech_pvt->kick = switch_core_session_strdup(br_b_session, switch_core_session_get_uuid(session));
- } else {
- switch_channel_hangup(channel_a, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+ if (t_session) {
+ switch_channel_t *t_channel = switch_core_session_get_channel(t_session);
+ ext = switch_channel_get_variable(hup_channel, "destination_number");
+
+ if (!switch_strlen_zero(full_ref_by)) {
+ switch_channel_set_variable(t_channel, SOFIA_SIP_HEADER_PREFIX "Referred-By", full_ref_by);
}
- switch_core_session_rwunlock(br_b_session);
+ if (!switch_strlen_zero(full_ref_to)) {
+ switch_channel_set_variable(t_channel, SOFIA_REFER_TO_VARIABLE, full_ref_to);
+ }
+
+ switch_ivr_session_transfer(t_session, ext, NULL, NULL);
+ nua_notify(tech_pvt->nh,
+ NUTAG_NEWSUB(1),
+ 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());
+ switch_core_session_rwunlock(t_session);
+ switch_channel_hangup(hup_channel, SWITCH_CAUSE_ATTENDED_TRANSFER);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Session to transfer to not found.\n");
+ nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), 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());
}
-
- 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);
@@ -1488,30 +2207,50 @@
switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING;
uint32_t timeout = 60;
char *tuuid_str;
+ const char *port = NULL;
+ switch_status_t status;
- channel = switch_core_session_get_channel(a_session);
+ if (refer_to && refer_to->r_url && refer_to->r_url->url_port) {
+ port = refer_to->r_url->url_port;
+ }
+ if (switch_strlen_zero(port)) {
+ port = "5060";
+ }
+ 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);
-
+ refer_to->r_url->url_user,
+ refer_to->r_url->url_host,
+ 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;
+ if (!switch_strlen_zero(full_ref_by)) {
+ switch_channel_set_variable(channel, SOFIA_SIP_HEADER_PREFIX "Referred-By", full_ref_by);
}
+ if (!switch_strlen_zero(full_ref_to)) {
+ switch_channel_set_variable(channel, SOFIA_REFER_TO_VARIABLE, full_ref_to);
+ }
+ status = switch_ivr_originate(a_session,
+ &tsession, &cause, exten, timeout, &noop_state_handler, NULL, NULL, NULL, SOF_NONE);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot Create Outgoing Channel! [%s]\n", exten);
+ nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), 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());
+
switch_core_session_rwunlock(a_session);
+
+ if (status != SWITCH_STATUS_SUCCESS) {
+ goto done;
+ }
+
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"),
+ nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), 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());
switch_core_session_rwunlock(tsession);
} else {
@@ -1522,7 +2261,7 @@
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"),
+ nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), 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());
}
@@ -1540,211 +2279,241 @@
if (exten) {
switch_channel_t *channel = switch_core_session_get_channel(session);
- char *br;
+ const 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_channel_t *b_channel = switch_core_session_get_channel(b_session);
+ switch_channel_set_variable(channel, "transfer_fallback_extension", from->a_user);
+ if (!switch_strlen_zero(full_ref_by)) {
+ switch_channel_set_variable(b_channel, SOFIA_SIP_HEADER_PREFIX "Referred-By", full_ref_by);
+ }
+ if (!switch_strlen_zero(full_ref_to)) {
+ switch_channel_set_variable(b_channel, SOFIA_REFER_TO_VARIABLE, full_ref_to);
+ }
+ switch_ivr_session_transfer(b_session, exten, NULL, NULL);
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"),
+ nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), 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());
- */
- sofia_glue_do_xfer_invite(session);
-
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot Blind Transfer 1 Legged calls\n");
+ switch_channel_set_variable(channel_a, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER_ERROR");
+ nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), 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());
}
}
done:
+ if (home) {
+ su_home_unref(home);
+ home = NULL;
+ }
+
if (exten && strchr(exten, '@')) {
switch_safe_free(exten);
}
if (etmp) {
switch_safe_free(etmp);
}
-
-
}
-
void sofia_handle_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 */
+ const char *signal_ptr;
+ const char *rec_header;
+ const char *clientcode_header;
+ switch_dtmf_t dtmf = { 0, SWITCH_DEFAULT_DTMF_DURATION };
+
+ if (session) {
+ /* Get the channel */
+ switch_channel_t *channel = switch_core_session_get_channel(session);
- //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 our private */
+ assert(switch_core_session_get_private(session));
- //Barf if we didn't get it
- assert(tech_pvt != NULL);
+ if (sip && sip->sip_content_type && sip->sip_content_type->c_type && sip->sip_content_type->c_subtype &&
+ sip->sip_payload && sip->sip_payload->pl_data) {
+ if (!strncasecmp(sip->sip_content_type->c_type, "application", 11) && !strcasecmp(sip->sip_content_type->c_subtype, "dtmf-relay")) {
+ /* Try and find signal information in the payload */
+ if ((signal_ptr = switch_stristr("Signal=", sip->sip_payload->pl_data))) {
+ /* move signal_ptr where we need it (right past Signal=) */
+ signal_ptr = signal_ptr + 7;
+ dtmf.digit = *signal_ptr;
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Bad signal\n");
+ goto fail;
+ }
- //move signal_ptr where we need it (right past Signal=)
- signal_ptr = signal_ptr + 7;
+ if ((signal_ptr = switch_stristr("Duration=", sip->sip_payload->pl_data))) {
+ int tmp;
+ signal_ptr += 9;
+ if ((tmp = atoi(signal_ptr)) <= 0) {
+ tmp = SWITCH_DEFAULT_DTMF_DURATION;
+ }
+ dtmf.duration = tmp * 8;
+ }
+ } else if (!strncasecmp(sip->sip_content_type->c_type, "application", 11) && !strcasecmp(sip->sip_content_type->c_subtype, "dtmf")) {
+ dtmf.digit = *sip->sip_payload->pl_data;
+ } else {
+ goto fail;
+ }
+
+ if (dtmf.digit) {
+ /* queue it up */
+ switch_channel_queue_dtmf(channel, &dtmf);
- //put the digit somewhere we can muck with
- strncpy(dtmf_digit, signal_ptr, 1);
+ /* print debug info */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "INFO DTMF(%c)\n", dtmf.digit);
- //queue it up
- switch_channel_queue_dtmf(channel, dtmf_digit);
+ /* Send 200 OK response */
+ nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END());
+
+ return;
+ } else {
+ goto fail;
+ }
+ }
- //print debug info
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "INFO DTMF(%s)\n", dtmf_digit);
+ if ((clientcode_header = sofia_glue_get_unknown_header(sip, "x-clientcode"))) {
+ if (!switch_strlen_zero(clientcode_header)) {
+ switch_channel_set_variable(channel, "call_clientcode", clientcode_header);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Setting CMC to %s\n", clientcode_header);
+ nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END());
+ } else {
+ goto fail;
+ }
+ return;
+ }
- } else { //unknown info type
- sip_from_t const *from;
+ if ((rec_header = sofia_glue_get_unknown_header(sip, "record"))) {
+ if (switch_strlen_zero(profile->record_template)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Record attempted but no template defined.\n");
+ nua_respond(nh, 488, "Recording not enabled", NUTAG_WITH_THIS(nua), TAG_END());
+ } else {
+ if (!strcasecmp(rec_header, "on")) {
+ char *file;
- from = sip->sip_from;
+ file = switch_channel_expand_variables(channel, profile->record_template);
+ switch_ivr_record_session(session, file, 0, NULL);
+ switch_channel_set_variable(channel, "sofia_record_file", file);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Recording %s to %s\n", switch_channel_get_name(channel), file);
+ nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END());
+ if (file != profile->record_template) {
+ free(file);
+ file = NULL;
+ }
+ } else {
+ const char *file;
- //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);
+ if ((file = switch_channel_get_variable(channel, "sofia_record_file"))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Done recording %s to %s\n", switch_channel_get_name(channel), file);
+ switch_ivr_stop_record_session(session, file);
+ nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END());
+ } else {
+ nua_respond(nh, 488, "Nothing to stop", NUTAG_WITH_THIS(nua), TAG_END());
+ }
+ }
+ }
+ return;
+ }
}
-
return;
+
+ fail:
+ nua_respond(nh, 488, "Unsupported Request", NUTAG_WITH_THIS(nua), TAG_END());
}
-#define url_set_chanvars(session, url, varprefix) _url_set_chanvars(session, url, #varprefix "_user", #varprefix "_host", #varprefix "_port", #varprefix "_uri")
+
+#define url_set_chanvars(session, url, varprefix) _url_set_chanvars(session, url, #varprefix "_user", #varprefix "_host", #varprefix "_port", #varprefix "_uri", #varprefix "_params")
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 *host_var, const char *port_var, const char *uri_var, const char *params_var)
{
const char *user = NULL, *host = NULL, *port = NULL;
char *uri = NULL;
switch_channel_t *channel = switch_core_session_get_channel(session);
+ char new_port[25] = "";
if (url) {
user = url->url_user;
host = url->url_host;
port = url->url_port;
+ if (!switch_strlen_zero(url->url_params)) {
+ switch_channel_set_variable(channel, params_var, url->url_params);
+ }
}
+ if (switch_strlen_zero(user)) {
+ user = "nobody";
+ }
+
+ if (switch_strlen_zero(host)) {
+ host = "nowhere";
+ }
+
+ check_decode(user, session);
+
if (user) {
switch_channel_set_variable(channel, user_var, user);
}
- if (!port) {
- port = SOFIA_DEFAULT_PORT;
+
+ if (port) {
+ switch_snprintf(new_port, sizeof(new_port), ":%s", 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);
+ uri = switch_core_session_sprintf(session, "%s@%s%s", user, host, new_port);
} else {
- uri = switch_core_session_sprintf(session, "%s:%s", host, port);
+ uri = switch_core_session_sprintf(session, "%s%s", host, new_port);
}
- switch_channel_set_variable_nodup(channel, uri_var, uri);
+ switch_channel_set_variable(channel, uri_var, uri);
switch_channel_set_variable(channel, host_var, host);
}
return uri;
}
-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);
- }
- }
-}
-
void sofia_handle_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;
+ sip_remote_party_id_t *rpid = NULL;
+ sip_p_asserted_identity_t *passerted = NULL;
+ sip_p_preferred_identity_t *ppreferred = NULL;
+ sip_alert_info_t *alert_info = NULL;
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 *referred_by_user = NULL, *referred_by_host = NULL;
const char *context = NULL;
+ const char *dialplan = NULL;
char network_ip[80];
switch_event_t *v_event = NULL;
uint32_t sess_count = switch_core_session_count();
uint32_t sess_max = switch_core_session_limit(0);
- int is_auth = 0;
+ int is_auth = 0, calling_myself = 0;
+ su_addrinfo_t *my_addrinfo = msg_addrinfo(nua_current_request(nua));
+
- if ((profile->soft_max && sess_count >= profile->soft_max) || sess_count >= sess_max) {
- nua_respond(nh, 480, "Maximum Calls In Progress", SIPTAG_RETRY_AFTER_STR("300"), TAG_END());
+ if (sess_count >= sess_max || !(profile->pflags & PFLAG_RUNNING)) {
+ nua_respond(nh, 503, "Maximum Calls In Progress", SIPTAG_RETRY_AFTER_STR("300"), TAG_END());
return;
}
@@ -1754,26 +2523,45 @@
return;
}
+
+ get_addr(network_ip, sizeof(network_ip), &((struct sockaddr_in *) my_addrinfo->ai_addr)->sin_addr);
- 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->acl_count) {
+ uint32_t x = 0;
+ for (x = 0 ; x < profile->acl_count; x++) {
+ if (!switch_check_network_list_ip(network_ip, profile->acl[x])) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "IP %s Rejected by acl %s\n", network_ip, profile->acl[x]);
+ nua_respond(nh, SIP_403_FORBIDDEN, TAG_END());
+ return;
+ }
+ }
}
-
- if ((profile->pflags & PFLAG_AUTH_CALLS) || sip->sip_proxy_authorization || sip->sip_authorization) {
- if (sofia_reg_handle_register(nua, profile, nh, sip, REG_INVITE, key, sizeof(key), &v_event)) {
- if (v_event) {
- switch_event_destroy(&v_event);
+
+
+ if ((profile->pflags & PFLAG_AUTH_CALLS) || (!(profile->pflags & PFLAG_BLIND_AUTH) && (sip->sip_proxy_authorization || sip->sip_authorization))) {
+ if (strcmp(network_ip, profile->sipip)) {
+ if (sofia_reg_handle_register(nua, profile, nh, sip, REG_INVITE, key, sizeof(key), &v_event)) {
+ if (v_event) {
+ switch_event_destroy(&v_event);
+ }
+ return;
}
- return;
+ } else {
+ calling_myself++;
}
is_auth++;
}
+
+
+ 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 (!sofia_endpoint_interface || !(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());
+ nua_respond(nh, 503, "Maximum Calls In Progress", SIPTAG_RETRY_AFTER_STR("300"), TAG_END());
return;
}
@@ -1789,13 +2577,15 @@
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);
+ channel = tech_pvt->channel = switch_core_session_get_channel(session);
+
if (is_auth) {
switch_channel_set_variable(channel, "sip_authorized", "true");
}
+ if (calling_myself) {
+ switch_channel_set_variable(channel, "sip_looped_call", "true");
+ }
if (v_event) {
switch_event_header_t *hp;
@@ -1803,7 +2593,6 @@
for(hp = v_event->headers; hp; hp = hp->next) {
switch_channel_set_variable(channel, hp->name, hp->value);
}
-
switch_event_destroy(&v_event);
}
@@ -1820,23 +2609,53 @@
}
}
- 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;
+ switch_channel_set_variable(channel, "sip_from_comment", sip->sip_from->a_comment);
- tmp++;
- if ((p = strchr(tmp, '"'))) {
- *p = '\0';
- }
- }
- displayname = tmp;
+ if (sip->sip_from->a_params) {
+ set_variable_sip_param(channel, "from", sip->sip_from->a_params);
+ }
+
+ switch_channel_set_variable(channel, "sofia_profile_name", profile->name);
+ switch_channel_set_variable(channel, "sofia_profile_domain_name", profile->domain_name);
+
+ if (!switch_strlen_zero(sip->sip_from->a_display)) {
+ displayname = sip->sip_from->a_display;
} else {
- displayname = switch_strlen_zero(from_user) ? "unkonwn" : from_user;
+ displayname = switch_strlen_zero(from_user) ? "unknown" : from_user;
+ }
+ }
+
+ if ((rpid = sip_remote_party_id(sip))) {
+ if (rpid->rpid_url && rpid->rpid_url->url_user) {
+ from_user = rpid->rpid_url->url_user;
+ }
+ if (!switch_strlen_zero(rpid->rpid_display)) {
+ displayname = rpid->rpid_display;
+ }
+ }
+
+ if ((passerted = sip_p_asserted_identity(sip))) {
+ if (passerted->paid_url && passerted->paid_url->url_user) {
+ from_user = passerted->paid_url->url_user;
+ }
+ if (!switch_strlen_zero(passerted->paid_display)) {
+ displayname = passerted->paid_display;
+ }
+ }
+
+ if ((ppreferred = sip_p_preferred_identity(sip))) {
+ if (ppreferred->ppid_url && ppreferred->ppid_url->url_user) {
+ from_user = ppreferred->ppid_url->url_user;
+ }
+ if (!switch_strlen_zero(ppreferred->ppid_display)) {
+ displayname = ppreferred->ppid_display;
}
}
+ if (from_user) {
+ check_decode(from_user, session);
+ }
+
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) {
@@ -1844,20 +2663,76 @@
} else {
destination_number = sip->sip_request->rq_url->url_user;
}
+ check_decode(destination_number, session);
}
if (sip->sip_to && sip->sip_to->a_url) {
- char *val;
+ const char *host, *user;
+ int port;
+ sofia_transport_t transport;
+ url_t *transport_url;
+
+ if (sip->sip_record_route && sip->sip_record_route->r_url) {
+ transport_url = sip->sip_record_route->r_url;
+ } else {
+ transport_url = sip->sip_contact->m_url;
+ }
+
+ transport = sofia_glue_url2transport(transport_url);
+ tech_pvt->transport = transport;
+
url_set_chanvars(session, sip->sip_to->a_url, sip_to);
- if ((val = switch_channel_get_variable(channel, "sip_to_uri"))) {
- tech_pvt->to_uri = switch_core_session_sprintf(session, "sip:%s", val);
+ if (switch_channel_get_variable(channel, "sip_to_uri")) {
+
+ host = switch_channel_get_variable(channel, "sip_to_host");
+ user = switch_channel_get_variable(channel, "sip_to_user");
+
+ switch_channel_set_variable(channel, "sip_to_comment", sip->sip_to->a_comment);
+
+ if (sip->sip_to->a_params) {
+ set_variable_sip_param(channel, "to", sip->sip_to->a_params);
+ }
+
+ if (sip->sip_contact->m_url->url_port) {
+ port = atoi(sip->sip_contact->m_url->url_port);
+ } else {
+ port = sofia_glue_transport_has_tls(transport) ? profile->tls_sip_port : profile->sip_port;
+ }
+
+ tech_pvt->to_uri = switch_core_session_sprintf(session, "sip:%s@%s:%d;transport=%s",
+ user, host, port, sofia_glue_transport2str(transport));
+
if (profile->ndlb & PFLAG_NDLB_TO_IN_200_CONTACT) {
- tech_pvt->reply_contact = tech_pvt->to_uri;
+ if (strchr(tech_pvt->to_uri, '>')) {
+ tech_pvt->reply_contact = tech_pvt->to_uri;
+ } else {
+ tech_pvt->reply_contact = switch_core_session_sprintf(session, "<%s>", tech_pvt->to_uri);
+ }
} else {
- tech_pvt->reply_contact = switch_core_session_strdup(session, profile->url);
+ const char *url;
+
+ if ((url = (sofia_glue_transport_has_tls(transport)) ? profile->tls_url : profile->url)) {
+ if (strchr(url, '>')) {
+ tech_pvt->reply_contact = switch_core_session_sprintf(session, "%s;transport=%s", url, sofia_glue_transport2str(transport));
+ } else {
+ tech_pvt->reply_contact = switch_core_session_sprintf(session, "<%s;transport=%s>", url, sofia_glue_transport2str(transport));
+ }
+ } else {
+ switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+ }
}
} else {
- tech_pvt->reply_contact = switch_core_session_strdup(session, profile->url);
+ const char *url;
+
+ if ((url = (sofia_glue_transport_has_tls(transport)) ? profile->tls_url : profile->url)) {
+ if (strchr(url, '>')) {
+ tech_pvt->reply_contact = switch_core_session_sprintf(session, "%s;transport=%s", url, sofia_glue_transport2str(transport));
+ } else {
+ tech_pvt->reply_contact = switch_core_session_sprintf(session, "<%s;transport=%s>", url, sofia_glue_transport2str(transport));
+ }
+ } else {
+ switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+ }
}
}
@@ -1868,14 +2743,39 @@
}
}
+ if (sip->sip_referred_by) {
+ referred_by_user = sip->sip_referred_by->b_url->url_user;
+ referred_by_host = sip->sip_referred_by->b_url->url_host;
+ channel_name = url_set_chanvars(session, sip->sip_referred_by->b_url, sip_referred_by);
+
+ check_decode(referred_by_user, session);
+
+ if (!switch_strlen_zero(referred_by_user)) {
+ if (*referred_by_user == '+') {
+ switch_channel_set_variable(channel, "sip_referred_by_user_stripped", (const char *) (referred_by_user + 1));
+ } else {
+ switch_channel_set_variable(channel, "sip_referred_by_user_stripped", referred_by_user);
+ }
+ }
+
+ switch_channel_set_variable(channel, "sip_referred_by_cid", sip->sip_referred_by->b_cid);
+
+ if (sip->sip_referred_by->b_params) {
+ set_variable_sip_param(channel, "referred_by", sip->sip_referred_by->b_params);
+ }
+ }
+
sofia_glue_attach_private(session, profile, tech_pvt, channel_name);
sofia_glue_tech_prepare_codecs(tech_pvt);
switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "INBOUND CALL");
-
if (switch_test_flag(tech_pvt, TFLAG_INB_NOMEDIA)) {
- switch_channel_set_flag(channel, CF_BYPASS_MEDIA);
+ switch_channel_set_flag(channel, CF_PROXY_MODE);
+ }
+
+ if (switch_test_flag(tech_pvt, TFLAG_PROXY_MEDIA)) {
+ switch_channel_set_flag(channel, CF_PROXY_MEDIA);
}
if (!tech_pvt->call_id && sip->sip_call_id && sip->sip_call_id->i_id) {
@@ -1886,6 +2786,10 @@
if (sip->sip_subject && sip->sip_subject->g_string) {
switch_channel_set_variable(channel, "sip_subject", sip->sip_subject->g_string);
}
+
+ if (sip->sip_user_agent && !switch_strlen_zero(sip->sip_user_agent->g_string)){
+ switch_channel_set_variable(channel, "sip_user_agent", sip->sip_user_agent->g_string);
+ }
if (sip->sip_via) {
if (sip->sip_via->v_host) {
@@ -1901,16 +2805,16 @@
if (sip->sip_max_forwards) {
char max_forwards[32];
- snprintf(max_forwards, sizeof(max_forwards), "%lu", sip->sip_max_forwards->mf_count);
+ switch_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) {
sofia_gateway_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);
+ char *from_key;
+ char *user = (char *) sip->sip_request->rq_url->url_user;
+ check_decode(user, session);
+ from_key = switch_core_session_sprintf(session, "sip:%s@%s", user, sip->sip_request->rq_url->url_host);
if ((gateway = sofia_reg_find_gateway(from_key))) {
context = gateway->register_context;
@@ -1919,6 +2823,9 @@
}
}
+ if (!context) {
+ context = switch_channel_get_variable(channel, "user_context");
+ }
if (!context) {
if (profile->context && !strcasecmp(profile->context, "_domain_")) {
@@ -1928,21 +2835,70 @@
}
}
+ if (!(dialplan = switch_channel_get_variable(channel, "inbound_dialplan"))) {
+ dialplan = profile->dialplan;
+ }
+
+ if ((alert_info = sip_alert_info(sip))) {
+ char *tmp = sip_header_as_string(profile->home, (void *) alert_info);
+ switch_channel_set_variable(channel, "alert_info", tmp);
+ su_free(profile->home, tmp);
+ }
+
+ if (sofia_test_pflag(profile, PFLAG_PRESENCE)) {
+ const char *user = switch_str_nil(sip->sip_from->a_url->url_user);
+ const char *host = switch_str_nil(sip->sip_from->a_url->url_host);
+
+ char *tmp = switch_mprintf("%s@%s", user, host);
+ switch_assert(tmp);
+ switch_channel_set_variable(channel, "presence_id", tmp);
+ free(tmp);
+ }
+
+ check_decode(displayname, session);
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);
+ dialplan,
+ displayname,
+ from_user,
+ network_ip,
+ NULL, NULL, NULL, MODNAME, context, destination_number);
if (tech_pvt->caller_profile) {
+ if (rpid) {
+ if (rpid->rpid_privacy) {
+ if (!strcasecmp(rpid->rpid_privacy, "yes")) {
+ switch_set_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NAME | SWITCH_CPF_HIDE_NUMBER);
+ } else if (!strcasecmp(rpid->rpid_privacy, "full")) {
+ switch_set_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NAME | SWITCH_CPF_HIDE_NUMBER);
+ } else if (!strcasecmp(rpid->rpid_privacy, "name")) {
+ switch_set_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NAME);
+ } else if (!strcasecmp(rpid->rpid_privacy, "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);
+ }
+ }
+
+ if (rpid->rpid_screen && !strcasecmp(rpid->rpid_screen, "no")) {
+ switch_clear_flag(tech_pvt->caller_profile, SWITCH_CPF_SCREEN);
+ }
+ }
+
/* 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 (!strncasecmp(un->un_name, "Diversion", 9)) {
+ /* Basic Diversion Support for Diversion Indication in SIP */
+ /* draft-levy-sip-diversion-08 */
if (!switch_strlen_zero(un->un_value)) {
- switch_channel_set_variable(channel, "alert_info", un->un_value);
+ char *tmp_name;
+ if ((tmp_name = switch_mprintf("%s%s", SOFIA_SIP_HEADER_PREFIX, un->un_name))) {
+ switch_channel_set_variable(channel, tmp_name, un->un_value);
+ free(tmp_name);
+ }
}
- } else if (!strncasecmp(un->un_name, "Remote-Party-ID", 15)) {
- process_rpid(un, tech_pvt);
} else if (!strncasecmp(un->un_name, "X-", 2) || !strncasecmp(un->un_name, "P-", 2)) {
if (!switch_strlen_zero(un->un_value)) {
char *new_name;
@@ -1957,33 +2913,95 @@
switch_channel_set_caller_profile(channel, tech_pvt->caller_profile);
}
- if (!(tech_pvt->sofia_private = malloc(sizeof(*tech_pvt->sofia_private)))) {
+ if (!(sofia_private = malloc(sizeof(*sofia_private)))) {
abort();
}
- memset(tech_pvt->sofia_private, 0, sizeof(*tech_pvt->sofia_private));
- tech_pvt->sofia_private->home = su_home_new(sizeof(*tech_pvt->sofia_private->home));
- sofia_presence_set_chat_hash(tech_pvt, sip);
+ memset(sofia_private, 0, sizeof(*sofia_private));
+ tech_pvt->sofia_private = sofia_private;
+
+ if ((profile->pflags & PFLAG_PRESENCE)) {
+ sofia_presence_set_chat_hash(tech_pvt, sip);
+ }
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;
- if (switch_core_session_thread_launch(session) == SWITCH_STATUS_SUCCESS) {
+ if (sip && switch_core_session_thread_launch(session) == SWITCH_STATUS_SUCCESS) {
+ const char *dialog_from_user = "", *dialog_from_host = "", *to_user = "", *to_host = "", *contact_user = "", *contact_host = "";
+ const char *user_agent = "", *call_id = "";
+ url_t *from = NULL, *to = NULL, *contact = NULL;
+ char *sql = NULL;
+
+ if (sip->sip_to) {
+ to = sip->sip_to->a_url;
+ }
+ if (sip->sip_from) {
+ from = sip->sip_from->a_url;
+ }
+ if (sip->sip_contact) {
+ contact = sip->sip_contact->m_url;
+ }
+
+ if (sip->sip_user_agent) {
+ user_agent = switch_str_nil(sip->sip_user_agent->g_string);
+ }
+
+ if (sip->sip_call_id) {
+ call_id = switch_str_nil(sip->sip_call_id->i_id);
+ }
+
+ if (to) {
+ to_user = switch_str_nil(to->url_user);
+ to_host = switch_str_nil(to->url_host);
+ }
+
+ if (from) {
+ dialog_from_user = switch_str_nil(from->url_user);
+ dialog_from_host = switch_str_nil(from->url_host);
+ }
+
+ if (contact) {
+ contact_user = switch_str_nil(contact->url_user);
+ contact_host = switch_str_nil(contact->url_host);
+ }
+
+
+ if (profile->pflags & PFLAG_PRESENCE) {
+
+ sql = switch_mprintf(
+ "insert into sip_dialogs values('%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q')",
+ call_id,
+ tech_pvt->sofia_private->uuid,
+ to_user,
+ to_host,
+ dialog_from_user,
+ dialog_from_host,
+ contact_user,
+ contact_host,
+ "confirmed",
+ "inbound",
+ user_agent
+ );
+
+ switch_assert(sql);
+ sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
+ }
+
return;
}
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "LUKE: I'm hit, but not bad.\n");
-
- switch_mutex_lock(profile->flag_mutex);
-
- profile->soft_max = sess_count - 10;
- switch_core_session_limit(profile->soft_max);
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "LUKE'S VOICE: Artoo, see what you can do with it. Hang on back there....\n"
- "Green laserfire moves past the beeping little robot as his head turns. "
- "After a few beeps and a twist of his mechanical arm,\n"
- "Artoo reduces the max sessions to %d thus, saving the switch from certian doom.\n",
- profile->soft_max);
+ if (sess_count > 110) {
+ switch_mutex_lock(profile->flag_mutex);
+ switch_core_session_limit(sess_count - 10);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "LUKE: I'm hit, but not bad.\n");
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "LUKE'S VOICE: Artoo, see what you can do with it. Hang on back there....\n"
+ "Green laserfire moves past the beeping little robot as his head turns. "
+ "After a few beeps and a twist of his mechanical arm,\n"
+ "Artoo reduces the max sessions to %d thus, saving the switch from certian doom.\n",
+ sess_count - 10);
- switch_mutex_unlock(profile->flag_mutex);
+ switch_mutex_unlock(profile->flag_mutex);
+ }
if (tech_pvt->hash_key) {
switch_core_hash_delete(tech_pvt->profile->chat_hash, tech_pvt->hash_key);
@@ -1992,7 +3010,7 @@
nua_handle_bind(nh, NULL);
free(tech_pvt->sofia_private);
switch_core_session_destroy(&session);
- nua_respond(nh, 480, "Maximum Calls In Progress", SIPTAG_RETRY_AFTER_STR("300"), TAG_END());
+ nua_respond(nh, 503, "Maximum Calls In Progress", SIPTAG_RETRY_AFTER_STR("300"), TAG_END());
}
void sofia_handle_sip_i_options(int status,
@@ -2000,13 +3018,118 @@
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),
+ NUTAG_WITH_THIS(nua),
TAG_END());
+ nua_handle_destroy(nh);
}
+static void sofia_info_send_sipfrag(switch_core_session_t *aleg, switch_core_session_t *bleg)
+{
+ private_object_t *b_tech_pvt = NULL, *a_tech_pvt = NULL;
+ char message[256] = "";
+ if (aleg && bleg) {
+ a_tech_pvt = (private_object_t *) switch_core_session_get_private(aleg);
+ b_tech_pvt = (private_object_t *) switch_core_session_get_private(bleg);
+
+ if (b_tech_pvt && a_tech_pvt && a_tech_pvt->caller_profile) {
+ switch_caller_profile_t *acp = a_tech_pvt->caller_profile;
+ if (switch_strlen_zero(acp->caller_id_name)) {
+ snprintf(message, sizeof(message), "From:\r\nTo: %s\r\n", acp->caller_id_number);
+ } else {
+ snprintf(message, sizeof(message), "From:\r\nTo: \"%s\" %s\r\n", acp->caller_id_name, acp->caller_id_number);
+ }
+ nua_info(b_tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"), SIPTAG_PAYLOAD_STR(message), TAG_END());
+ }
+ }
+}
+/*
+ * This subroutine will take the a_params of a sip_addr_s structure and spin through them.
+ * Each param will be used to create a channel variable.
+ * In the SIP RFC's, this data is called generic-param.
+ * Note that the tag-param is also included in the a_params list.
+ *
+ * From: "John Doe" <sip:5551212 at 1.2.3.4>;tag=ed23266b52cbb17eo2;ref=101;mbid=201
+ *
+ * For example, the header above will produce an a_params list with three entries
+ * tag=ed23266b52cbb17eo2
+ * ref=101
+ * mbid=201
+ *
+ * The a_params list is parsed and the lvalue is used to create the channel variable name while the
+ * rvalue is used to create the channel variable value.
+ *
+ * If no equal (=) sign is found during parsing, a channel variable name is created with the param and
+ * the value is set to NULL.
+ *
+ * Pointers are used for copying the sip_header_name for performance reasons. There are no calls to
+ * any string functions and no memory is allocated/dealocated. The only limiter is the size of the
+ * sip_header_name array.
+*/
+static void set_variable_sip_param(switch_channel_t *channel, char *header_type, sip_param_t const *params)
+{
+ char sip_header_name[128] = "";
+ char var1[] = "sip_";
+ char *cp, *sh, *sh_end, *sh_save;
+
+ /* Build the static part of the sip_header_name variable from */
+ /* the header_type. If the header type is "referred_by" then */
+ /* sip_header_name = "sip_referred_by_". */
+ sh = sip_header_name;
+ sh_end = sh + sizeof(sip_header_name) - 1;
+ for (cp=var1; *cp; cp++, sh++) {
+ *sh = *cp;
+ }
+ *sh = '\0';
+
+ /* Copy the header_type to the sip_header_name. Before copying */
+ /* each character, check that we aren't going to overflow the */
+ /* the sip_header_name buffer. We have to account for the */
+ /* trailing underscore and NULL that will be added to the end. */
+ for (cp=header_type; (*cp && (sh < (sh_end-1))); cp++, sh++) {
+ *sh = *cp;
+ }
+ *sh++ = '_';
+ *sh = '\0';
+
+ /* sh now points to the NULL at the end of the partially built */
+ /* sip_header_name variable. This is also the start of the */
+ /* variable part of the sip_header_name built from the lvalue */
+ /* of the parms data. */
+ sh_save = sh;
+
+ while (params && params[0]) {
+
+ /* Copy the params data to the sip_header_name variable until */
+ /* the end of the params string is reached, an '=' is detected */
+ /* or until the sip_header_name buffer has been exhausted. */
+ for (cp=(char *)(*params); ((*cp != '=') && *cp && (sh < sh_end)); cp++, sh++) {
+ *sh = *cp;
+ }
+
+ /* cp now points to either the end of the parms data or the */
+ /* equal (=) sign spearating the lvalue and rvalue. */
+ if (*cp == '=')
+ cp++;
+ *sh = '\0';
+ switch_channel_set_variable(channel, sip_header_name, cp);
+
+ /* Bump pointer to next param in the list. Also reset the */
+ /* sip_header_name pointer to the beginning of the dynamic area */
+ params++;
+ sh = sh_save;
+ }
+}
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
+ */
More information about the Freeswitch-svn
mailing list