freeswitch/src/mod/endpoints/mod_sofia/sofia.c

9971 lines
374 KiB
C
Raw Normal View History

/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
2014-02-05 21:02:28 +00:00
* Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthm@freeswitch.org>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthm@freeswitch.org>
* Ken Rice <krice@freeswitch.org>
* Paul D. Tinsley <pdt at jackhammer.org>
* Bret McDanel <trixter AT 0xdecafbad.com>
* Marcel Barbulescu <marcelbarbulescu@gmail.com>
* Norman Brandinger
2013-01-09 23:18:07 +00:00
* Raymond Chandler <intralanman@freeswitch.org>
* Nathan Patrick <npatrick at corp.sonic.net>
2011-12-14 19:23:54 +00:00
* Joseph Sullivan <jossulli@amazon.com>
2013-04-29 15:09:14 +00:00
* Emmanuel Schmidbauer <e.schmidbauer@gmail.com>
2013-05-17 19:39:17 +00:00
* William King <william.king@quentustech.com>
* David Knell <david.knell@telng.com>
*
* sofia.c -- SOFIA SIP Endpoint (sofia code)
*
*/
#include "mod_sofia.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[];
#ifdef HAVE_SOFIA_STUN
extern su_log_t stun_log[];
#endif
extern su_log_t su_log_default[];
2011-06-27 15:15:03 +00:00
static void config_sofia_profile_urls(sofia_profile_t * profile);
static void parse_gateways(sofia_profile_t *profile, switch_xml_t gateways_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);
void sofia_handle_sip_i_reinvite(switch_core_session_t *session,
nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip,
sofia_dispatch_event_t *de,
tagi_t tags[]);
static void set_variable_sip_param(switch_channel_t *channel, char *header_type, sip_param_t const *params);
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,
sofia_dispatch_event_t *de,
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,
sofia_dispatch_event_t *de,
tagi_t tags[]);
static void sofia_handle_sip_r_options(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,
sofia_dispatch_event_t *de, 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,
sofia_dispatch_event_t *de, tagi_t tags[])
{
2012-04-02 19:51:23 +00:00
if (status == 481 && sip && !sip->sip_retry_after && sip->sip_call_id && (!sofia_private || !sofia_private->is_call)) {
char *sql;
2012-01-26 10:46:48 +00:00
sql = switch_mprintf("delete from sip_subscriptions where call_id='%q'", sip->sip_call_id->i_id);
switch_assert(sql != NULL);
sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
nua_handle_destroy(nh);
}
2012-04-02 19:51:23 +00:00
}
#define url_set_chanvars(session, url, varprefix) _url_set_chanvars(session, url, #varprefix "_user", #varprefix "_host", #varprefix "_port", #varprefix "_uri", #varprefix "_params")
static const char *_url_set_chanvars(switch_core_session_t *session, url_t *url, const char *user_var,
const char *host_var, const char *port_var, const char *uri_var, const char *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 (!zstr(url->url_params)) {
switch_channel_set_variable(channel, params_var, url->url_params);
}
}
if (zstr(user)) {
user = "nobody";
}
if (zstr(host)) {
host = "nowhere";
}
check_decode(user, session);
if (user) {
switch_channel_set_variable(channel, user_var, user);
}
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, new_port);
} else {
uri = switch_core_session_sprintf(session, "%s%s", host, new_port);
}
switch_channel_set_variable(channel, uri_var, uri);
switch_channel_set_variable(channel, host_var, host);
}
return uri;
}
static char *strip_quotes(const char *in)
{
char *t = (char *) in;
char *r = (char *) in;
if (t && *t == '"') {
t++;
if (end_of(t) == '"') {
r = strdup(t);
end_of(r) = '\0';
}
}
return r;
}
static void extract_header_vars(sofia_profile_t *profile, sip_t const *sip,
switch_core_session_t *session, nua_handle_t *nh)
{
switch_channel_t *channel = switch_core_session_get_channel(session);
char *full;
if (sip) {
if (sip->sip_route) {
if ((full = sip_header_as_string(nh->nh_home, (void *) sip->sip_route))) {
const char *v = switch_channel_get_variable(channel, "sip_full_route");
if (!v) {
switch_channel_set_variable(channel, "sip_full_route", full);
}
su_free(nh->nh_home, full);
}
}
2011-11-15 17:26:49 +00:00
2011-11-19 23:28:32 +00:00
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
if (sip->sip_contact) {
char *c = sip_header_as_string(nh->nh_home, (void *) sip->sip_contact);
switch_channel_set_variable(channel, "sip_recover_contact", c);
su_free(nh->nh_home, c);
}
2011-11-16 15:57:15 +00:00
}
2011-11-15 17:26:49 +00:00
if (sip->sip_record_route) {
sip_record_route_t *rrp;
switch_stream_handle_t stream = { 0 };
int x = 0;
SWITCH_STANDARD_STREAM(stream);
2011-11-17 22:21:43 +00:00
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
char *tmp[128] = { 0 };
int y = 0;
2011-11-17 22:21:43 +00:00
for(rrp = sip->sip_record_route; rrp; rrp = rrp->r_next) {
char *rr = sip_header_as_string(nh->nh_home, (void *) rrp);
tmp[y++] = rr;
if (y == 127) break;
}
2011-11-17 22:21:43 +00:00
y--;
while(y >= 0) {
stream.write_function(&stream, x == 0 ? "%s" : ",%s", tmp[y]);
su_free(nh->nh_home, tmp[y]);
y--;
x++;
}
} else {
for(rrp = sip->sip_record_route; rrp; rrp = rrp->r_next) {
char *rr = sip_header_as_string(nh->nh_home, (void *) rrp);
2011-11-17 22:21:43 +00:00
stream.write_function(&stream, x == 0 ? "%s" : ",%s", rr);
su_free(nh->nh_home, rr);
2011-11-17 22:21:43 +00:00
x++;
}
2011-11-15 17:26:49 +00:00
}
2011-11-15 17:26:49 +00:00
switch_channel_set_variable(channel, "sip_invite_record_route", (char *)stream.data);
free(stream.data);
}
if (sip->sip_via) {
2011-11-15 17:26:49 +00:00
sip_via_t *vp;
switch_stream_handle_t stream = { 0 };
int x = 0;
2012-02-02 21:09:25 +00:00
SWITCH_STANDARD_STREAM(stream);
2012-02-02 21:09:25 +00:00
for(vp = sip->sip_via; vp; vp = vp->v_next) {
char *v = sip_header_as_string(nh->nh_home, (void *) vp);
2012-02-02 21:09:25 +00:00
stream.write_function(&stream, x == 0 ? "%s" : ",%s", v);
su_free(nh->nh_home, v);
2012-02-02 21:09:25 +00:00
x++;
}
2012-02-02 21:09:25 +00:00
switch_channel_set_variable(channel, "sip_full_via", (char *)stream.data);
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND || switch_stristr("TCP", (char *)stream.data)) {
switch_channel_set_variable(channel, "sip_recover_via", (char *)stream.data);
}
2012-02-02 21:09:25 +00:00
free(stream.data);
}
if (sip->sip_from) {
char *p = strip_quotes(sip->sip_from->a_display);
if (p) {
switch_channel_set_variable(channel, "sip_from_display", p);
}
if (p != sip->sip_from->a_display) free(p);
if ((full = sip_header_as_string(nh->nh_home, (void *) sip->sip_from))) {
switch_channel_set_variable(channel, "sip_full_from", full);
su_free(nh->nh_home, full);
}
}
2011-11-16 15:57:15 +00:00
if (sip->sip_to) {
char *p = strip_quotes(sip->sip_to->a_display);
if (p) {
switch_channel_set_variable(channel, "sip_to_display", p);
}
if (p != sip->sip_to->a_display) free(p);
if ((full = sip_header_as_string(nh->nh_home, (void *) sip->sip_to))) {
switch_channel_set_variable(channel, "sip_full_to", full);
su_free(nh->nh_home, full);
}
}
}
}
static void extract_vars(sofia_profile_t *profile, sip_t const *sip,
switch_core_session_t *session)
{
switch_channel_t *channel = switch_core_session_get_channel(session);
if (sip) {
if (sip->sip_from && sip->sip_from->a_url)
url_set_chanvars(session, sip->sip_from->a_url, sip_from);
if (sip->sip_request && sip->sip_request->rq_url)
url_set_chanvars(session, sip->sip_request->rq_url, sip_req);
if (sip->sip_to && sip->sip_to->a_url)
url_set_chanvars(session, sip->sip_to->a_url, sip_to);
if (sip->sip_contact && sip->sip_contact->m_url)
url_set_chanvars(session, sip->sip_contact->m_url, sip_contact);
if (sip->sip_referred_by && sip->sip_referred_by->b_url)
url_set_chanvars(session, sip->sip_referred_by->b_url, sip_referred_by);
if (sip->sip_to && sip->sip_to->a_tag) {
switch_channel_set_variable(channel, "sip_to_tag", sip->sip_to->a_tag);
}
if (sip->sip_from && sip->sip_from->a_tag) {
switch_channel_set_variable(channel, "sip_from_tag", sip->sip_from->a_tag);
}
if (sip->sip_cseq && sip->sip_cseq->cs_seq) {
char sip_cseq[40] = "";
switch_snprintf(sip_cseq, sizeof(sip_cseq), "%d", sip->sip_cseq->cs_seq);
switch_channel_set_variable(channel, "sip_cseq", sip_cseq);
}
if (sip->sip_call_id && sip->sip_call_id->i_id) {
switch_channel_set_variable(channel, "sip_call_id", sip->sip_call_id->i_id);
}
}
}
/**
* Add a specific SIP INVITE header to the channel variables, prefixed with "sip_i_"
*/
static void sofia_add_invite_header_to_chanvars(switch_channel_t *channel, nua_handle_t *nh, void *sip_header, const char *var)
{
switch_assert(channel);
switch_assert(nh);
switch_assert(var);
if (sip_header) {
char *full;
if ((full = sip_header_as_string(nh->nh_home, sip_header))) {
switch_channel_set_variable(channel, var, full);
su_free(nh->nh_home, full);
}
}
}
/**
* Deep search into the SIP message to recreate the original headers, including multiple Diversions, etc.
* Finally sets the "sip_invite_headers" to a string containing the 'original' SIP headers, except that the order may have changed.
* Multiple headers will have the original internal order, though.
*
* @param sip A sip_t struct containing the parsed message
* @param session A call session
* @param nh A NUA handle for string allocation
*/
static void sofia_parse_all_invite_headers(sip_t const *sip, switch_core_session_t *session, nua_handle_t *nh)
{
switch_channel_t *channel = switch_core_session_get_channel(session);
sip_unknown_t *un;
sip_p_asserted_identity_t *passerted;
sip_p_preferred_identity_t *ppreferred;
sip_remote_party_id_t *rpid;
sip_reply_to_t *reply_to;
sip_alert_info_t *alert_info;
if (!sip) return;
/* Add simple (unique) headers first */
sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_from, "sip_i_from");
sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_to, "sip_i_to");
sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_call_id, "sip_i_call_id");
sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_cseq, "sip_i_cseq");
sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_route, "sip_i_route");
sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_max_forwards, "sip_i_max_forwards");
sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_proxy_require, "sip_i_proxy_require");
sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_contact, "sip_i_contact");
sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_user_agent, "sip_i_user_agent");
sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_subject, "sip_i_subject");
sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_priority, "sip_i_priority");
sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_organization, "sip_i_organization");
sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_in_reply_to, "sip_i_in_reply_to");
sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_accept_encoding, "sip_i_accept_encoding");
sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_accept_language, "sip_i_accept_language");
sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_allow, "sip_i_allow");
sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_require, "sip_i_require");
sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_supported, "sip_i_supported");
sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_date, "sip_i_date");
sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_timestamp, "sip_i_timestamp");
sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_expires, "sip_i_expires");
sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_min_expires, "sip_i_min_expires");
sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_session_expires, "sip_i_session_expires");
sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_min_se, "sip_i_min_se");
sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_privacy, "sip_i_privacy");
sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_mime_version, "sip_i_mime_version");
sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_content_type, "sip_i_content_type");
sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_content_encoding, "sip_i_content_encoding");
sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_content_language, "sip_i_content_language");
sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_content_disposition, "sip_i_content_disposition");
sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_content_length, "sip_i_content_length");
/* Add all other headers - which might exist more than once */
if (sip->sip_via) {
sip_via_t *vp;
for (vp = sip->sip_via; vp; vp = vp->v_next) {
char *v = sip_header_as_string(nh->nh_home, (void *) vp);
switch_channel_add_variable_var_check(channel, "sip_i_via", v, SWITCH_FALSE, SWITCH_STACK_PUSH);
su_free(nh->nh_home, v);
}
}
if (sip->sip_record_route) {
sip_record_route_t *rrp;
for (rrp = sip->sip_record_route; rrp; rrp = rrp->r_next) {
char *rr = sip_header_as_string(nh->nh_home, (void *) rrp);
switch_channel_add_variable_var_check(channel, "sip_i_record_route", rr, SWITCH_FALSE, SWITCH_STACK_PUSH);
su_free(nh->nh_home, rr);
}
}
if (sip->sip_proxy_authorization) {
sip_proxy_authorization_t *vp;
for (vp = sip->sip_proxy_authorization; vp; vp = vp->au_next) {
char *v = sip_header_as_string(nh->nh_home, (void *) vp);
switch_channel_add_variable_var_check(channel, "sip_i_proxy_authorization", v, SWITCH_FALSE, SWITCH_STACK_PUSH);
su_free(nh->nh_home, v);
}
}
if (sip->sip_call_info) {
sip_call_info_t *vp;
for (vp = sip->sip_call_info; vp; vp = vp->ci_next) {
char *v = sip_header_as_string(nh->nh_home, (void *) vp);
switch_channel_add_variable_var_check(channel, "sip_i_call_info", v, SWITCH_FALSE, SWITCH_STACK_PUSH);
su_free(nh->nh_home, v);
}
}
if (sip->sip_accept) {
sip_accept_t *vp;
for (vp = sip->sip_accept; vp; vp = vp->ac_next) {
char *v = sip_header_as_string(nh->nh_home, (void *) vp);
switch_channel_add_variable_var_check(channel, "sip_i_accept", v, SWITCH_FALSE, SWITCH_STACK_PUSH);
su_free(nh->nh_home, v);
}
}
if (sip->sip_authorization) {
sip_authorization_t *vp;
for (vp = sip->sip_authorization; vp; vp = vp->au_next) {
char *v = sip_header_as_string(nh->nh_home, (void *) vp);
switch_channel_add_variable_var_check(channel, "sip_i_authorization", v, SWITCH_FALSE, SWITCH_STACK_PUSH);
su_free(nh->nh_home, v);
}
}
if ((alert_info = sip_alert_info(sip))) {
sip_alert_info_t *vp;
for (vp = alert_info; vp; vp = vp->ai_next) {
char *v = sip_header_as_string(nh->nh_home, (void *) vp);
switch_channel_add_variable_var_check(channel, "sip_i_alert_info", v, SWITCH_FALSE, SWITCH_STACK_PUSH);
su_free(nh->nh_home, v);
}
}
if ((passerted = sip_p_asserted_identity(sip))) {
sip_p_asserted_identity_t *vp;
for (vp = passerted; vp; vp = vp->paid_next) {
char *v = sip_header_as_string(nh->nh_home, (void *) vp);
switch_channel_add_variable_var_check(channel, "sip_i_p_asserted_identity", v, SWITCH_FALSE, SWITCH_STACK_PUSH);
su_free(nh->nh_home, v);
}
}
if ((ppreferred = sip_p_preferred_identity(sip))) {
sip_p_preferred_identity_t *vp;
for (vp = ppreferred; vp; vp = vp->ppid_next) {
char *v = sip_header_as_string(nh->nh_home, (void *) vp);
switch_channel_add_variable_var_check(channel, "sip_i_p_preferred_identity", v, SWITCH_FALSE, SWITCH_STACK_PUSH);
su_free(nh->nh_home, v);
}
}
if ((rpid = sip_remote_party_id(sip))) {
sip_remote_party_id_t *vp;
for (vp = rpid; vp; vp = vp->rpid_next) {
char *v = sip_header_as_string(nh->nh_home, (void *) vp);
switch_channel_add_variable_var_check(channel, "sip_i_remote_party_id", v, SWITCH_FALSE, SWITCH_STACK_PUSH);
su_free(nh->nh_home, v);
}
}
if ((reply_to = sip_reply_to(sip))) {
sip_reply_to_t *vp;
for (vp = reply_to; vp; vp = vp->rplyto_next) {
char *v = sip_header_as_string(nh->nh_home, (void *) vp);
switch_channel_add_variable_var_check(channel, "sip_i_reply_to", v, SWITCH_FALSE, SWITCH_STACK_PUSH);
su_free(nh->nh_home, v);
}
}
/* Loop through the unknown headers */
for (un = sip->sip_unknown; un; un = un->un_next) {
if (!zstr(un->un_name) && !zstr(un->un_value)) {
char *parsed_name;
if ((parsed_name = switch_mprintf("sip_i_%s", un->un_name))) {
char *p, *x = parsed_name;
switch_tolower_max(x);
while ((p = strchr(x, '-'))) {
*p = '_';
x = ++p;
}
switch_channel_add_variable_var_check(channel, parsed_name, un->un_value, SWITCH_FALSE, SWITCH_STACK_PUSH);
free(parsed_name);
}
}
}
}
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,
sofia_dispatch_event_t *de, tagi_t tags[])
{
switch_channel_t *channel = NULL;
private_object_t *tech_pvt = NULL;
switch_event_t *s_event = NULL;
sofia_gateway_subscription_t *gw_sub_ptr;
int sub_state;
sofia_gateway_t *gateway = NULL;
tl_gets(tags, NUTAG_SUBSTATE_REF(sub_state), TAG_END());
/* 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")) {
/* XXX MTK - is this right? in this case isn't sofia is already sending a 200 itself also? */
nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
goto end;
}
if (session) {
channel = switch_core_session_get_channel(session);
switch_assert(channel != NULL);
tech_pvt = switch_core_session_get_private(session);
switch_assert(tech_pvt != NULL);
}
if (sofia_test_pflag(profile, PFLAG_PROXY_REFER) && sip->sip_payload && sip->sip_payload->pl_data &&
sip->sip_content_type && sip->sip_content_type->c_type &&
switch_stristr("sipfrag", sip->sip_content_type->c_type)) {
switch_core_session_t *other_session;
if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
switch_core_session_message_t *msg;
msg = switch_core_session_alloc(other_session, sizeof(*msg));
MESSAGE_STAMP_FFL(msg);
msg->message_id = SWITCH_MESSAGE_INDICATE_BLIND_TRANSFER_RESPONSE;
msg->string_arg = switch_core_session_strdup(other_session, sip->sip_payload->pl_data);
msg->from = __FILE__;
switch_core_session_queue_message(other_session, msg);
switch_core_session_rwunlock(other_session);
nua_respond(nh, SIP_202_ACCEPTED, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
goto end;
}
}
/* For additional NOTIFY event packages see http://www.iana.org/assignments/sip-events. */
if (sip->sip_content_type &&
sip->sip_content_type->c_type && sip->sip_payload && sip->sip_payload->pl_data && !strcasecmp(sip->sip_event->o_type, "refer")) {
if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_NOTIFY_REFER) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "content-type", sip->sip_content_type->c_type);
switch_event_add_body(s_event, "%s", sip->sip_payload->pl_data);
}
}
/* add common headers for the NOTIFY to the switch_event and fire if it exists */
if (s_event != NULL) {
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "event-package", sip->sip_event->o_type);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "event-id", sip->sip_event->o_id);
if (sip->sip_contact && sip->sip_contact->m_url) {
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "contact", "%s@%s",
sip->sip_contact->m_url->url_user, sip->sip_contact->m_url->url_host);
}
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "from", "%s@%s", sip->sip_from->a_url->url_user, sip->sip_from->a_url->url_host);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "from-tag", sip->sip_from->a_tag);
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "to", "%s@%s", sip->sip_to->a_url->url_user, sip->sip_to->a_url->url_host);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "to-tag", sip->sip_to->a_tag);
if (sip->sip_call_id && sip->sip_call_id->i_id) {
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "call-id", sip->sip_call_id->i_id);
}
if (sip->sip_subscription_state && sip->sip_subscription_state->ss_substate) {
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "subscription-substate", sip->sip_subscription_state->ss_substate);
}
if (sip->sip_subscription_state && sip->sip_subscription_state->ss_reason) {
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "subscription-reason", sip->sip_subscription_state->ss_reason);
}
if (sip->sip_subscription_state && sip->sip_subscription_state->ss_retry_after) {
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "subscription-retry-after", sip->sip_subscription_state->ss_retry_after);
}
if (sip->sip_subscription_state && sip->sip_subscription_state->ss_expires) {
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "subscription-expires", sip->sip_subscription_state->ss_expires);
}
if (session) {
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "UniqueID", switch_core_session_get_uuid(session));
}
switch_event_fire(&s_event);
}
if (!strcasecmp(sip->sip_event->o_type, "refer")) {
if (session && channel && tech_pvt) {
if (sip->sip_payload && sip->sip_payload->pl_data) {
char *p;
int status_val = 0;
if ((p = strchr(sip->sip_payload->pl_data, ' '))) {
p++;
if (p) {
status_val = atoi(p);
}
}
if (!status_val || status_val >= 200) {
switch_channel_set_variable(channel, "sip_refer_reply", sip->sip_payload->pl_data);
if (status_val == 200) {
switch_channel_hangup(channel, SWITCH_CAUSE_BLIND_TRANSFER);
}
if ((int)tech_pvt->want_event == 9999) {
tech_pvt->want_event = 0;
}
}
}
}
nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
}
/* if no session, assume it could be an incoming notify from a gateway subscription */
if (session) {
/* make sure we have a proper "talk" event */
if (strcasecmp(sip->sip_event->o_type, "talk")) {
goto error;
}
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) {
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_MSG(de->data->e_msg), TAG_END());
goto end;
}
}
if (!sofia_private || zstr(sofia_private->gateway_name)) {
if (profile->debug) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Gateway information missing Subscription Event: %s\n",
sip->sip_event->o_type);
}
goto error;
}
if (!(gateway = sofia_reg_find_gateway(sofia_private->gateway_name))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Gateway information missing\n");
goto error;
}
/* find the corresponding gateway subscription (if any) */
if (!(gw_sub_ptr = sofia_find_gateway_subscription(gateway, sip->sip_event->o_type))) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
"Could not find gateway subscription. Gateway: %s. Subscription Event: %s\n",
gateway->name, sip->sip_event->o_type);
goto error;
}
if (!(gw_sub_ptr->state == SUB_STATE_SUBED || gw_sub_ptr->state == SUB_STATE_SUBSCRIBE)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Ignoring notify due to subscription state: %d\n", gw_sub_ptr->state);
goto error;
}
if (sip->sip_subscription_state && sip->sip_subscription_state->ss_expires) {
int delta = atoi(sip->sip_subscription_state->ss_expires);
delta /= 2;
if (delta < 1) {
delta = 1;
}
gw_sub_ptr->expires = switch_epoch_time_now(NULL) + delta;
}
/* dispatch freeswitch event */
if (switch_event_create(&s_event, SWITCH_EVENT_NOTIFY_IN) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "event", sip->sip_event->o_type);
2011-11-29 20:32:11 +00:00
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "pl_data", sip->sip_payload ? sip->sip_payload->pl_data : "");
if ( sip->sip_content_type != NULL )
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "sip_content_type", sip->sip_content_type->c_type);
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "port", "%d", gateway->profile->sip_port);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "module_name", "mod_sofia");
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile_name", gateway->profile->name);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile_uri", gateway->profile->url);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "gateway_name", gateway->name);
if ( sip->sip_call_info != NULL ) {
sip_call_info_t *call_info = sip->sip_call_info;
char *nua_hold = sip_header_as_string(nua_handle_home(nh), (void *) call_info);
size_t cur_len = strlen(nua_hold);
char *hold = strdup(nua_hold);
su_free(nua_handle_home(nh), nua_hold);
while ((call_info = call_info->ci_next) != NULL) {
char *tmp = sip_header_as_string(nua_handle_home(nh), (void *) call_info);
size_t tmp_len = strlen(tmp);
hold = realloc(hold, cur_len + tmp_len + 2);
switch_assert(hold);
strncpy(hold + cur_len, ",", 2);
strncpy(hold + cur_len + 1, tmp, tmp_len +1);
su_free(nua_handle_home(nh), tmp);
cur_len = cur_len + tmp_len + 2;
}
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM | SWITCH_STACK_NODUP, "Call-Info", hold);
}
switch_event_fire(&s_event);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "dispatched freeswitch event for message-summary NOTIFY\n");
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Failed to create event\n");
goto error;
}
goto end;
error:
if (sip && sip->sip_event && sip->sip_event->o_type && !strcasecmp(sip->sip_event->o_type, "message-summary")) {
/* unsolicited mwi, just say ok */
nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
2010-08-19 23:22:06 +00:00
if (sofia_test_pflag(profile, PFLAG_FORWARD_MWI_NOTIFY)) {
const char *mwi_status = NULL;
char network_ip[80];
uint32_t x = 0;
int acl_ok = 1;
char *last_acl = NULL;
if (sip->sip_to && sip->sip_to->a_url && sip->sip_to->a_url->url_user && sip->sip_to->a_url->url_host
&& sip->sip_payload && sip->sip_payload->pl_data ) {
sofia_glue_get_addr(de->data->e_msg, network_ip, sizeof(network_ip), NULL);
2010-08-19 23:22:06 +00:00
for (x = 0; x < profile->acl_count; x++) {
last_acl = profile->acl[x];
if (!(acl_ok = switch_check_network_list_ip(network_ip, last_acl))) {
break;
}
}
if ( acl_ok )
{
mwi_status = switch_stristr("Messages-Waiting: ", sip->sip_payload->pl_data);
if ( mwi_status ) {
2010-09-02 21:38:14 +00:00
char *mwi_stat;
2010-08-19 23:22:06 +00:00
mwi_status += strlen( "Messages-Waiting: " );
2010-09-02 21:38:14 +00:00
mwi_stat = switch_strip_whitespace( mwi_status );
2010-08-19 23:22:06 +00:00
2010-09-02 21:38:14 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
"Forwarding unsolicited MWI ( %s : %s@%s )\n",
mwi_stat, sip->sip_to->a_url->url_user, sip->sip_to->a_url->url_host );
2010-08-19 23:22:06 +00:00
if (switch_event_create(&s_event, SWITCH_EVENT_MESSAGE_WAITING) == SWITCH_STATUS_SUCCESS) {
2010-09-02 21:38:14 +00:00
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "MWI-Messages-Waiting", mwi_stat );
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM,
"MWI-Message-Account", "%s@%s", sip->sip_to->a_url->url_user, sip->sip_to->a_url->url_host );
2010-08-19 23:22:06 +00:00
switch_event_fire(&s_event);
}
2010-09-02 21:38:14 +00:00
switch_safe_free(mwi_stat);
2010-08-19 23:22:06 +00:00
}
} else {
2010-09-02 21:38:14 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Dropping unsolicited MWI ( %s@%s ) because of ACL\n",
sip->sip_to->a_url->url_user, sip->sip_to->a_url->url_host );
2010-08-19 23:22:06 +00:00
};
}
}
} else {
nua_respond(nh, 481, "Subscription Does Not Exist", NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
}
end:
if (!gateway && sub_state == nua_substate_terminated && sofia_private && sofia_private != &mod_sofia_globals.destroy_private &&
sofia_private != &mod_sofia_globals.keep_private) {
sofia_private->destroy_nh = 1;
sofia_private->destroy_me = 1;
}
if (gateway) {
sofia_reg_release_gateway(gateway);
}
}
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,
sofia_dispatch_event_t *de, tagi_t tags[])
{
const char *tmp;
switch_channel_t *channel;
private_object_t *tech_pvt;
char *extra_headers;
const char *call_info = NULL;
2011-09-26 14:03:10 +00:00
const char *vval = NULL;
#ifdef MANUAL_BYE
int cause;
char st[80] = "";
#endif
if (!session) {
return;
}
channel = switch_core_session_get_channel(session);
tech_pvt = switch_core_session_get_private(session);
#ifdef MANUAL_BYE
status = 200;
phrase = "OK";
2012-12-21 04:57:47 +00:00
if (switch_channel_test_flag(tech_pvt->channel, CF_SLA_BARGING)) {
2012-05-11 03:34:37 +00:00
const char *bargee_uuid = switch_channel_get_variable(channel, "sip_barging_uuid");
switch_core_session_t *bargee_session;
uint32_t ttl = 0;
if ((bargee_session = switch_core_session_locate(bargee_uuid))) {
//switch_channel_t *bargee_channel = switch_core_session_get_channel(bargee_session);
if ((ttl = switch_core_media_bug_count(bargee_session, "eavesdrop")) == 1) {
if (switch_core_session_check_interface(bargee_session, sofia_endpoint_interface)) {
2012-12-21 04:57:47 +00:00
switch_channel_clear_flag(switch_core_session_get_channel(bargee_session), CF_SLA_BARGE);
2012-05-11 03:34:37 +00:00
}
}
switch_core_session_rwunlock(bargee_session);
}
}
2012-12-21 04:57:47 +00:00
if (switch_channel_test_flag(tech_pvt->channel, CF_SLA_BARGE)) {
switch_core_session_t *new_session, *other_session;
const char *other_uuid = switch_channel_get_partner_uuid(tech_pvt->channel);
char *cmd = NULL;
if (!zstr(other_uuid) && (other_session = switch_core_session_locate(other_uuid))) {
switch_channel_t *other_channel = switch_core_session_get_channel(other_session);
switch_mutex_lock(profile->ireg_mutex);
if (switch_ivr_eavesdrop_pop_eavesdropper(session, &new_session) == SWITCH_STATUS_SUCCESS) {
switch_channel_t *new_channel = switch_core_session_get_channel(new_session);
const char *new_uuid = switch_core_session_get_uuid(new_session);
2013-04-05 21:41:51 +00:00
switch_caller_profile_t *cp = switch_channel_get_caller_profile(new_channel);
cp->caller_id_name = cp->orig_caller_id_name;
cp->caller_id_number = cp->orig_caller_id_number;
switch_channel_set_variable(new_channel, SWITCH_SIGNAL_BOND_VARIABLE, NULL);
switch_channel_set_flag(other_channel, CF_REDIRECT);
switch_channel_set_state(new_channel, CS_RESET);
switch_ivr_uuid_bridge(new_uuid, other_uuid);
cmd = switch_core_session_sprintf(session, "sleep:500,sofia_sla:%s inline", new_uuid);
switch_channel_clear_flag(other_channel, CF_REDIRECT);
switch_core_session_rwunlock(new_session);
}
switch_mutex_unlock(profile->ireg_mutex);
switch_core_session_rwunlock(other_session);
}
if (!zstr(cmd)) {
switch_ivr_eavesdrop_exec_all(session, "transfer", cmd);
}
}
sofia_set_flag_locked(tech_pvt, TFLAG_BYE);
call_info = switch_channel_get_variable(channel, "presence_call_info_full");
2012-03-29 16:35:57 +00:00
if (sip->sip_reason) {
char *reason_header = sip_header_as_string(nh->nh_home, (void *) sip->sip_reason);
if (!zstr(reason_header)) {
switch_channel_set_variable_partner(channel, "sip_reason", reason_header);
}
}
if (sip->sip_reason && sip->sip_reason->re_protocol && (!strcasecmp(sip->sip_reason->re_protocol, "Q.850")
|| !strcasecmp(sip->sip_reason->re_protocol, "FreeSWITCH")
2012-12-22 03:30:14 +00:00
|| !strcasecmp(sip->sip_reason->re_protocol, profile->sdp_username)) && sip->sip_reason->re_cause) {
tech_pvt->q850_cause = atoi(sip->sip_reason->re_cause);
cause = tech_pvt->q850_cause;
} else {
cause = sofia_glue_sip_cause_to_freeswitch(status);
}
if (sip->sip_content_type && sip->sip_content_type->c_type) {
switch_channel_set_variable(channel, "sip_bye_content_type", sip->sip_content_type->c_type);
}
if (sip->sip_payload && sip->sip_payload->pl_data) {
switch_channel_set_variable(channel, "sip_bye_payload", sip->sip_payload->pl_data);
}
switch_snprintf(st, sizeof(st), "%d", status);
switch_channel_set_variable(channel, "sip_term_status", st);
switch_snprintf(st, sizeof(st), "sip:%d", status);
switch_channel_set_variable(channel, SWITCH_PROTO_SPECIFIC_HANGUP_CAUSE_VARIABLE, st);
if (phrase) {
switch_channel_set_variable_partner(channel, "sip_hangup_phrase", phrase);
}
switch_snprintf(st, sizeof(st), "%d", cause);
switch_channel_set_variable(channel, "sip_term_cause", st);
extra_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_BYE_HEADER_PREFIX);
sofia_glue_set_extra_headers(session, sip, SOFIA_SIP_BYE_HEADER_PREFIX);
if (!(vval = switch_channel_get_variable(channel, "sip_copy_custom_headers")) || switch_true(vval)) {
switch_core_session_t *nsession = NULL;
switch_core_session_get_partner(session, &nsession);
if (nsession) {
switch_ivr_transfer_variable(session, nsession, SOFIA_SIP_BYE_HEADER_PREFIX_T);
switch_core_session_rwunlock(nsession);
}
}
2011-09-26 14:03:10 +00:00
switch_channel_hangup(channel, cause);
nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg),
TAG_IF(call_info, SIPTAG_CALL_INFO_STR(call_info)), TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), TAG_END());
switch_safe_free(extra_headers);
if (sofia_private) {
sofia_private->destroy_me = 1;
sofia_private->destroy_nh = 1;
}
#endif
if (sip->sip_user_agent && !zstr(sip->sip_user_agent->g_string)) {
switch_channel_set_variable(channel, "sip_user_agent", sip->sip_user_agent->g_string);
} else if (sip->sip_server && !zstr(sip->sip_server->g_string)) {
switch_channel_set_variable(channel, "sip_user_agent", sip->sip_server->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);
}
if ((tmp = sofia_glue_get_unknown_header(sip, "P-RTP-Stat"))) {
switch_channel_set_variable(channel, "sip_p_rtp_stat", tmp);
}
tech_pvt->got_bye = 1;
switch_channel_set_variable(channel, "sip_hangup_disposition", "recv_bye");
return;
}
void sofia_handle_sip_r_message(int status, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip)
{
const char *call_id;
int *mstatus;
if (!(sip && sip->sip_call_id)) {
nua_handle_destroy(nh);
return;
}
call_id = sip->sip_call_id->i_id;
switch_mutex_lock(profile->flag_mutex);
mstatus = switch_core_hash_find(profile->chat_hash, call_id);
switch_mutex_unlock(profile->flag_mutex);
if (mstatus) {
*mstatus = status;
}
}
void sofia_wait_for_reply(struct private_object *tech_pvt, nua_event_t event, uint32_t timeout)
{
time_t exp = switch_epoch_time_now(NULL) + timeout;
tech_pvt->want_event = event;
while (switch_channel_ready(tech_pvt->channel) && tech_pvt->want_event && switch_epoch_time_now(NULL) < exp) {
switch_yield(100000);
}
}
void sofia_send_callee_id(switch_core_session_t *session, const char *name, const char *number)
{
const char *uuid;
switch_core_session_t *session_b;
switch_channel_t *channel = switch_core_session_get_channel(session);
switch_caller_profile_t *caller_profile = switch_channel_get_caller_profile(channel);
2013-03-30 20:39:49 +00:00
if (switch_channel_inbound_display(channel)) {
if (zstr(name)) {
name = caller_profile->caller_id_name;
}
2013-03-30 20:39:49 +00:00
if (zstr(number)) {
number = caller_profile->caller_id_number;
}
2013-03-30 20:39:49 +00:00
if (zstr(name)) {
name = number;
}
2013-03-30 20:39:49 +00:00
if (zstr(number)) {
name = number = "UNKNOWN";
}
} else {
if (zstr(name)) {
name = caller_profile->callee_id_name;
}
2013-03-30 20:39:49 +00:00
if (zstr(number)) {
number = caller_profile->callee_id_number;
}
2013-03-30 20:39:49 +00:00
if (zstr(name)) {
name = number;
}
2013-03-30 20:39:49 +00:00
if (zstr(number)) {
number = caller_profile->destination_number;
}
}
if ((uuid = switch_channel_get_partner_uuid(channel)) && (session_b = switch_core_session_locate(uuid))) {
switch_core_session_message_t *msg;
//switch_channel_t *channel_b = switch_core_session_get_channel(session_b);
//switch_channel_set_profile_var(channel_b, "callee_id_name", name);
//switch_channel_set_profile_var(channel_b, "callee_id_number", number);
msg = switch_core_session_alloc(session_b, sizeof(*msg));
MESSAGE_STAMP_FFL(msg);
msg->message_id = SWITCH_MESSAGE_INDICATE_DISPLAY;
msg->string_array_arg[0] = switch_core_session_strdup(session_b, name);
msg->string_array_arg[1] = switch_core_session_strdup(session_b, number);
msg->from = __FILE__;
switch_core_session_queue_message(session_b, msg);
switch_core_session_rwunlock(session_b);
}
}
void sofia_update_callee_id(switch_core_session_t *session, sofia_profile_t *profile, sip_t const *sip,
switch_bool_t send)
{
switch_channel_t *channel = switch_core_session_get_channel(session);
sip_p_asserted_identity_t *passerted = NULL;
char *name = NULL;
const char *number = "unknown", *tmp;
switch_caller_profile_t *caller_profile;
char *dup = NULL;
switch_event_t *event;
const char *val;
int fs = 0, lazy = 0, att = 0;
const char *name_var = "callee_id_name";
const char *num_var = "callee_id_number";
2013-09-09 17:53:45 +00:00
if (switch_true(switch_channel_get_variable(channel, SWITCH_IGNORE_DISPLAY_UPDATES_VARIABLE)) || !sofia_test_pflag(profile, PFLAG_SEND_DISPLAY_UPDATE)) {
return;
}
2013-03-30 20:39:49 +00:00
if (switch_channel_inbound_display(channel)) {
name_var = "caller_id_name";
num_var = "caller_id_number";
}
number = (char *) switch_channel_get_variable(channel, num_var);
name = (char *) switch_channel_get_variable(channel, name_var);
2011-07-30 04:42:46 +00:00
2011-07-30 04:42:46 +00:00
if (zstr(number) && sip->sip_to) {
number = sip->sip_to->a_url->url_user;
}
if ((val = sofia_glue_get_unknown_header(sip, "X-FS-Display-Number"))) {
number = val;
fs++;
}
if ((val = sofia_glue_get_unknown_header(sip, "X-FS-Display-Name"))) {
name = (char *) val;
2011-09-29 23:00:21 +00:00
check_decode(name, session);
fs++;
}
if ((val = sofia_glue_get_unknown_header(sip, "X-FS-Lazy-Attended-Transfer"))) {
lazy = switch_true(val);
fs++;
}
if ((val = sofia_glue_get_unknown_header(sip, "X-FS-Attended-Transfer"))) {
att = switch_true(val);
fs++;
}
if (!fs) {
if ((passerted = sip_p_asserted_identity(sip))) {
if (passerted->paid_url && passerted->paid_url->url_user) {
number = passerted->paid_url->url_user;
}
if (!zstr(passerted->paid_display)) {
dup = strdup(passerted->paid_display);
if (*dup == '"') {
name = dup + 1;
} else {
name = dup;
}
if (end_of(name) == '"') {
end_of(name) = '\0';
}
}
}
}
2010-11-19 20:47:45 +00:00
if (zstr(number)) {
if ((tmp = switch_channel_get_variable(channel, num_var)) && !zstr(tmp)) {
2010-11-19 20:47:45 +00:00
number = (char *) tmp;
}
2012-08-06 15:49:48 +00:00
if (zstr(number)) {
number = "unknown";
}
2010-11-19 20:47:45 +00:00
}
if (zstr(name)) {
if ((tmp = switch_channel_get_variable(channel, name_var)) && !zstr(tmp)) {
2010-11-19 20:47:45 +00:00
name = (char *) tmp;
}
}
if (zstr(name)) {
name = (char *) number;
2010-11-19 20:47:45 +00:00
}
2012-08-06 15:49:48 +00:00
if (zstr(name) || zstr(number)) {
goto end;
}
caller_profile = switch_channel_get_caller_profile(channel);
2013-03-30 20:39:49 +00:00
if (switch_channel_inbound_display(channel)) {
if (!strcmp(caller_profile->caller_id_name, name) && !strcmp(caller_profile->caller_id_number, number)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "%s Same Caller ID \"%s\" <%s>\n", switch_channel_get_name(channel), name, number);
send = 0;
} else {
caller_profile->caller_id_name = switch_sanitize_number(switch_core_strdup(caller_profile->pool, name));
caller_profile->caller_id_number = switch_sanitize_number(switch_core_strdup(caller_profile->pool, number));
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s Update Caller ID to \"%s\" <%s>\n", switch_channel_get_name(channel), name, number);
}
} else {
if (!strcmp(caller_profile->callee_id_name, name) && !strcmp(caller_profile->callee_id_number, number)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "%s Same Callee ID \"%s\" <%s>\n", switch_channel_get_name(channel), name, number);
send = 0;
} else {
caller_profile->callee_id_name = switch_sanitize_number(switch_core_strdup(caller_profile->pool, name));
caller_profile->callee_id_number = switch_sanitize_number(switch_core_strdup(caller_profile->pool, number));
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s Update Callee ID to \"%s\" <%s>\n", switch_channel_get_name(channel), name, number);
if (lazy || (att && !switch_channel_get_partner_uuid(channel))) {
switch_channel_flip_cid(channel);
}
}
}
2011-08-02 01:59:55 +00:00
if (send) {
2011-08-01 20:43:07 +00:00
2011-08-02 01:59:55 +00:00
if (switch_event_create(&event, SWITCH_EVENT_CALL_UPDATE) == SWITCH_STATUS_SUCCESS) {
const char *uuid = switch_channel_get_partner_uuid(channel);
2011-08-02 01:59:55 +00:00
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Direction", "RECV");
if (uuid) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Bridged-To", uuid);
}
switch_channel_event_set_data(channel, event);
switch_event_fire(&event);
2011-08-01 20:43:07 +00:00
}
sofia_send_callee_id(session, NULL, NULL);
}
end:
switch_safe_free(dup);
}
2012-09-05 18:11:32 +00:00
static void tech_send_ack(nua_handle_t *nh, private_object_t *tech_pvt)
{
const char *invite_full_from = switch_channel_get_variable(tech_pvt->channel, "sip_invite_full_from");
const char *invite_full_to = switch_channel_get_variable(tech_pvt->channel, "sip_invite_full_to");
if (sofia_test_pflag(tech_pvt->profile, PFLAG_TRACK_CALLS)) {
const char *invite_full_via = switch_channel_get_variable(tech_pvt->channel, "sip_invite_full_via");
const char *invite_route_uri = switch_channel_get_variable(tech_pvt->channel, "sip_invite_route_uri");
nua_ack(nh,
2012-09-05 18:11:32 +00:00
TAG_IF(invite_full_from, SIPTAG_FROM_STR(invite_full_from)),
TAG_IF(invite_full_to, SIPTAG_TO_STR(invite_full_to)),
TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)),
TAG_IF((zstr(tech_pvt->user_via) && !zstr(invite_full_via)), SIPTAG_VIA_STR(invite_full_via)),
TAG_IF(!zstr(invite_route_uri), SIPTAG_ROUTE_STR(invite_route_uri)),
TAG_END());
2012-09-05 18:11:32 +00:00
} else {
nua_ack(nh,
2012-09-05 18:11:32 +00:00
TAG_IF(invite_full_from, SIPTAG_FROM_STR(invite_full_from)),
TAG_IF(invite_full_to, SIPTAG_TO_STR(invite_full_to)),
TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)),
2012-09-05 18:11:32 +00:00
TAG_END());
}
}
//sofia_dispatch_event_t *de
static void our_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,
sofia_dispatch_event_t *de, 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;
int locked = 0;
int check_destroy = 1;
profile->last_sip_event = switch_time_now();
2010-07-16 15:05:12 +00:00
/* sofia_private will be == &mod_sofia_globals.keep_private whenever a request is done with a new handle that has to be
freed whenever the request is done */
if (nh && sofia_private == &mod_sofia_globals.keep_private) {
if (status >= 300) {
nua_handle_bind(nh, NULL);
nua_handle_destroy(nh);
return;
}
}
if (sofia_private && sofia_private != &mod_sofia_globals.destroy_private && sofia_private != &mod_sofia_globals.keep_private) {
if (!zstr(sofia_private->gateway_name)) {
if (!(gateway = sofia_reg_find_gateway(sofia_private->gateway_name))) {
return;
}
} else if (!zstr(sofia_private->uuid)) {
2012-08-21 05:04:58 +00:00
if ((session = de->init_session)) {
de->init_session = NULL;
} else if ((session = de->session) || (session = switch_core_session_locate(sofia_private->uuid))) {
tech_pvt = switch_core_session_get_private(session);
channel = switch_core_session_get_channel(session);
if (tech_pvt) {
switch_mutex_lock(tech_pvt->sofia_mutex);
locked = 1;
} else {
if (session != de->session) switch_core_session_rwunlock(session);
return;
}
if (status >= 180 && !*sofia_private->auth_gateway_name) {
const char *gwname = switch_channel_get_variable(channel, "sip_use_gateway");
if (!zstr(gwname)) {
switch_set_string(sofia_private->auth_gateway_name, gwname);
}
}
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, 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);
}
if (channel && switch_channel_down(channel)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Channel is already hungup.\n");
goto done;
}
} else {
/* we can't find the session it must be hanging up or something else, its too late to do anything with it. */
return;
}
}
}
2011-10-18 19:07:30 +00:00
if (sofia_test_pflag(profile, PFLAG_AUTH_ALL) && tech_pvt && tech_pvt->key && sip && (event < nua_r_set_params || event > nua_r_authenticate)) {
sip_authorization_t const *authorization = NULL;
if (sip->sip_authorization) {
authorization = sip->sip_authorization;
} else if (sip->sip_proxy_authorization) {
authorization = sip->sip_proxy_authorization;
}
if (authorization) {
char network_ip[80];
int network_port;
sofia_glue_get_addr(de->data->e_msg, network_ip, sizeof(network_ip), &network_port);
auth_res = sofia_reg_parse_auth(profile, authorization, sip, de,
(char *) sip->sip_request->rq_method_name, tech_pvt->key, strlen(tech_pvt->key), network_ip, network_port, NULL, 0,
2013-07-19 17:03:46 +00:00
REG_INVITE, NULL, NULL, NULL, NULL);
}
2011-12-16 19:31:15 +00:00
if ((auth_res != AUTH_OK && auth_res != AUTH_RENEWED)) {
//switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
nua_respond(nh, SIP_401_UNAUTHORIZED, TAG_END());
goto done;
}
if (channel) {
switch_channel_set_variable(channel, "sip_authorized", "true");
}
}
if (sip && (status == 401 || status == 407)) {
sofia_reg_handle_sip_r_challenge(status, phrase, nua, profile, nh, sofia_private, session, gateway, sip, de, tags);
goto done;
}
switch (event) {
case nua_r_get_params:
case nua_i_fork:
case nua_r_info:
break;
case nua_r_bye:
case nua_r_unregister:
case nua_r_unsubscribe:
2012-08-31 22:37:58 +00:00
case nua_i_terminated:
case nua_r_publish:
case nua_i_error:
case nua_i_active:
case nua_r_set_params:
case nua_i_prack:
case nua_r_prack:
break;
2012-03-29 16:35:57 +00:00
case nua_i_cancel:
if (sip && channel) {
switch_channel_set_variable(channel, "sip_hangup_disposition", "recv_cancel");
2012-07-09 15:37:15 +00:00
if (sip->sip_reason) {
char *reason_header = sip_header_as_string(nh->nh_home, (void *) sip->sip_reason);
if (!zstr(reason_header)) {
switch_channel_set_variable_partner(channel, "sip_reason", reason_header);
}
2012-03-29 16:35:57 +00:00
}
}
break;
case nua_r_cancel:
{
if (status > 299 && nh) {
nua_handle_destroy(nh);
}
}
break;
case nua_i_ack:
{
if (channel && sip) {
if (sip->sip_to && sip->sip_to->a_tag) {
switch_channel_set_variable(channel, "sip_to_tag", sip->sip_to->a_tag);
}
if (sip->sip_from && sip->sip_from->a_tag) {
switch_channel_set_variable(channel, "sip_from_tag", sip->sip_from->a_tag);
}
if (sip->sip_cseq && sip->sip_cseq->cs_seq) {
char sip_cseq[40] = "";
switch_snprintf(sip_cseq, sizeof(sip_cseq), "%d", sip->sip_cseq->cs_seq);
switch_channel_set_variable(channel, "sip_cseq", sip_cseq);
}
if (sip->sip_call_id && sip->sip_call_id->i_id) {
switch_channel_set_variable(channel, "sip_call_id", sip->sip_call_id->i_id);
}
extract_header_vars(profile, sip, session, nh);
switch_core_recovery_track(session);
2011-07-16 07:33:39 +00:00
sofia_set_flag(tech_pvt, TFLAG_GOT_ACK);
2012-09-05 18:11:32 +00:00
if (sofia_test_flag(tech_pvt, TFLAG_PASS_ACK)) {
switch_core_session_t *other_session;
2012-09-05 18:11:32 +00:00
sofia_clear_flag(tech_pvt, TFLAG_PASS_ACK);
if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
if (switch_core_session_compare(session, other_session)) {
private_object_t *other_tech_pvt = switch_core_session_get_private(other_session);
tech_send_ack(other_tech_pvt->nh, other_tech_pvt);
}
switch_core_session_rwunlock(other_session);
}
2012-09-05 18:11:32 +00:00
}
}
}
case nua_r_ack:
2011-08-04 21:34:01 +00:00
if (channel)
switch_channel_set_flag(channel, CF_MEDIA_ACK);
break;
case nua_r_shutdown:
2011-06-20 15:07:01 +00:00
if (status >= 200) {
2011-09-06 17:53:29 +00:00
sofia_set_pflag(profile, PFLAG_SHUTDOWN);
su_root_break(profile->s_root);
2011-06-20 15:07:01 +00:00
}
break;
case nua_r_message:
sofia_handle_sip_r_message(status, profile, nh, sip);
break;
case nua_r_invite:
sofia_handle_sip_r_invite(session, status, phrase, nua, profile, nh, sofia_private, sip, de, tags);
break;
case nua_r_options:
sofia_handle_sip_r_options(session, status, phrase, nua, profile, nh, sofia_private, sip, de, tags);
break;
case nua_i_bye:
sofia_handle_sip_i_bye(session, status, phrase, nua, profile, nh, sofia_private, sip, de, tags);
break;
case nua_r_notify:
sofia_handle_sip_r_notify(session, status, phrase, nua, profile, nh, sofia_private, sip, de, tags);
break;
case nua_i_notify:
sofia_handle_sip_i_notify(session, status, phrase, nua, profile, nh, sofia_private, sip, de, tags);
break;
case nua_r_register:
sofia_reg_handle_sip_r_register(status, phrase, nua, profile, nh, sofia_private, sip, de, tags);
break;
case nua_i_options:
sofia_handle_sip_i_options(status, phrase, nua, profile, nh, sofia_private, sip, de, tags);
break;
case nua_i_invite:
if (session && sofia_private) {
2012-09-18 16:13:09 +00:00
if (sofia_private->is_call > 1) {
sofia_handle_sip_i_reinvite(session, nua, profile, nh, sofia_private, sip, de, tags);
} else {
sofia_private->is_call++;
sofia_handle_sip_i_invite(session, nua, profile, nh, sofia_private, sip, de, tags);
}
}
break;
case nua_i_publish:
sofia_presence_handle_sip_i_publish(nua, profile, nh, sofia_private, sip, de, tags);
break;
case nua_i_register:
//nua_respond(nh, SIP_200_OK, SIPTAG_CONTACT(sip->sip_contact), NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
//nua_handle_destroy(nh);
2013-01-27 05:16:26 +00:00
sofia_reg_handle_sip_i_register(nua, profile, nh, &sofia_private, sip, de, tags);
break;
case nua_i_state:
sofia_handle_sip_i_state(session, status, phrase, nua, profile, nh, sofia_private, sip, de, tags);
break;
case nua_i_message:
sofia_presence_handle_sip_i_message(status, phrase, nua, profile, nh, session, sofia_private, sip, de, tags);
break;
case nua_i_info:
sofia_handle_sip_i_info(nua, profile, nh, session, sip, de, tags);
break;
case nua_i_update:
break;
case nua_r_update:
if (session && tech_pvt && locked) {
sofia_clear_flag_locked(tech_pvt, TFLAG_UPDATING_DISPLAY);
}
break;
case nua_r_refer:
break;
case nua_i_refer:
2012-07-11 20:15:43 +00:00
if (session) {
sofia_handle_sip_i_refer(nua, profile, nh, session, sip, de, tags);
2012-07-11 20:15:43 +00:00
} else {
2012-07-11 22:25:45 +00:00
const char *req_user = NULL, *req_host = NULL, *action = NULL, *ref_by_user = NULL, *ref_to_user = NULL, *ref_to_host = NULL;
2012-07-27 20:07:11 +00:00
char *refer_to = NULL, *referred_by = NULL, *method = NULL, *full_url = NULL;
2012-08-15 16:19:11 +00:00
char *params = NULL, *iparams = NULL;
2012-07-11 20:15:43 +00:00
switch_event_t *event;
2012-07-31 19:01:56 +00:00
char *tmp;
2012-07-11 20:15:43 +00:00
if (sip->sip_refer_to) {
2012-07-11 22:25:45 +00:00
ref_to_user = sip->sip_refer_to->r_url->url_user;
ref_to_host = sip->sip_refer_to->r_url->url_host;
2012-08-15 16:19:11 +00:00
if (sip->sip_refer_to->r_url->url_params && switch_stristr("method=", sip->sip_refer_to->r_url->url_params)) {
params = su_strdup(nua_handle_home(nh), sip->sip_refer_to->r_url->url_params);
}
2012-07-19 22:03:23 +00:00
2012-08-15 16:19:11 +00:00
2013-08-21 17:00:44 +00:00
if ((refer_to = sip_header_as_string(nua_handle_home(nh), (void *) sip->sip_refer_to))) {
if ((iparams = strchr(refer_to, ';'))) {
2012-08-15 16:19:11 +00:00
*iparams++ = '\0';
2013-08-21 17:00:44 +00:00
if (!params || !switch_stristr("method=", params)) {
2012-08-15 16:19:11 +00:00
params = iparams;
}
2012-07-11 20:15:43 +00:00
}
2013-08-21 17:00:44 +00:00
if ((tmp = sofia_glue_get_url_from_contact(refer_to, 0))) {
refer_to = tmp;
}
2012-07-11 20:15:43 +00:00
}
2012-07-31 19:01:56 +00:00
if (params) {
method = switch_find_parameter(params, "method", NULL);
full_url = switch_find_parameter(params, "full_url", NULL);
}
2012-07-11 20:15:43 +00:00
}
2012-07-31 19:01:56 +00:00
if (!method) {
method = strdup("INVITE");
}
if (!strcasecmp(method, "INVITE")) {
action = "call";
} else if (!strcasecmp(method, "BYE")) {
action = "end";
} else {
action = method;
}
2012-07-11 20:15:43 +00:00
if (sip->sip_referred_by) {
referred_by = sofia_glue_get_url_from_contact(sip_header_as_string(nua_handle_home(nh), (void *) sip->sip_referred_by), 0);
ref_by_user = sip->sip_referred_by->b_url->url_user;
}
else if(sip->sip_to && sip->sip_to->a_url)
{
2012-08-05 21:45:14 +00:00
referred_by = sofia_glue_get_url_from_contact(sip_header_as_string(nua_handle_home(nh), (void *) sip->sip_to), 0);
ref_by_user = sip->sip_to->a_url->url_user;
}
2012-08-05 21:45:14 +00:00
if (sip->sip_to && sip->sip_to->a_url) {
req_user = sip->sip_to->a_url->url_user;
req_host = sip->sip_to->a_url->url_host;
2012-07-11 20:15:43 +00:00
}
if (switch_event_create(&event, SWITCH_EVENT_CALL_SETUP_REQ) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Requesting-Component", "mod_sofia");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Target-Component", req_user);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Target-Domain", req_host);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Request-Action", action);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Request-Target", "sofia/%s/%s", profile->name, refer_to);
2012-07-12 19:30:18 +00:00
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Request-Target-URI", "%s", refer_to);
2012-07-11 22:25:45 +00:00
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Request-Target-Extension", ref_to_user);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Request-Target-Domain", ref_to_host);
2012-07-27 20:07:11 +00:00
if (switch_true(full_url)) {
2012-12-04 13:46:31 +00:00
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "full_url", "true");
2012-07-27 20:07:11 +00:00
}
2012-10-02 17:22:03 +00:00
if (sip->sip_call_id && sip->sip_call_id->i_id) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Request-Call-ID", sip->sip_call_id->i_id);
}
2012-07-26 21:47:50 +00:00
if (!zstr(referred_by)) {
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Request-Sender", "sofia/%s/%s", profile->name, referred_by);
}
2012-07-11 20:15:43 +00:00
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "var_origination_caller_id_number", ref_by_user);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "var_origination_caller_id_name", ref_by_user);
switch_event_fire(&event);
}
2012-07-31 20:26:03 +00:00
if (sip) {
char *sql;
sofia_nat_parse_t np = { { 0 } };
char *contact_str;
char *proto = "sip", *orig_proto = "sip";
const char *call_id, *full_from, *full_to, *full_via, *from_user = NULL, *from_host = NULL, *to_user, *to_host, *full_agent;
char to_tag[13] = "";
char *event_str = "refer";
sip_accept_t *ap = sip->sip_accept;
char accept_header[256] = "";
2012-07-31 20:26:03 +00:00
np.fs_path = 1;
contact_str = sofia_glue_gen_contact_str(profile, sip, nh, de, &np);
2012-07-31 20:26:03 +00:00
call_id = sip->sip_call_id->i_id;
full_from = sip_header_as_string(nh->nh_home, (void *) sip->sip_from);
full_to = sip_header_as_string(nh->nh_home, (void *) sip->sip_to);
full_via = sip_header_as_string(nh->nh_home, (void *) sip->sip_via);
full_agent = sip_header_as_string(nh->nh_home, (void *) sip->sip_user_agent);
2012-07-31 20:26:03 +00:00
switch_stun_random_string(to_tag, 12, NULL);
if (sip->sip_from) {
from_user = sip->sip_from->a_url->url_user;
from_host = sip->sip_from->a_url->url_host;
} else {
from_user = "n/a";
from_host = "n/a";
}
if (sip->sip_to) {
to_user = sip->sip_to->a_url->url_user;
to_host = sip->sip_to->a_url->url_host;
} else {
to_user = "n/a";
to_host = "n/a";
}
while (ap) {
switch_snprintf(accept_header + strlen(accept_header), sizeof(accept_header) - strlen(accept_header),
"%s%s ", ap->ac_type, ap->ac_next ? "," : "");
ap = ap->ac_next;
}
2012-07-31 20:26:03 +00:00
sql = switch_mprintf("insert into sip_subscriptions "
"(proto,sip_user,sip_host,sub_to_user,sub_to_host,presence_hosts,event,contact,call_id,full_from,"
"full_via,expires,user_agent,accept,profile_name,hostname,network_port,network_ip,version,orig_proto, full_to) "
"values ('%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q',%ld,'%q','%q','%q','%q','%d','%q',-1,'%q','%q;tag=%q')",
proto, from_user, from_host, to_user, to_host, profile->presence_hosts ? profile->presence_hosts : "",
event_str, contact_str, call_id, full_from, full_via,
(long) switch_epoch_time_now(NULL) + 60,
full_agent, accept_header, profile->name, mod_sofia_globals.hostname,
2012-07-31 20:26:03 +00:00
np.network_port, np.network_ip, orig_proto, full_to, to_tag);
2012-07-31 20:26:03 +00:00
switch_assert(sql != NULL);
2012-07-31 21:35:56 +00:00
if (mod_sofia_globals.debug_presence > 0 || mod_sofia_globals.debug_sla > 0) {
2012-07-31 20:26:03 +00:00
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "%s REFER SUBSCRIBE %s@%s %s@%s\n%s\n",
profile->name, from_user, from_host, to_user, to_host, sql);
}
2012-07-31 20:26:03 +00:00
sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
sip_to_tag(nh->nh_home, sip->sip_to, to_tag);
}
2012-08-05 21:45:14 +00:00
nua_respond(nh, SIP_202_ACCEPTED, SIPTAG_TO(sip->sip_to), NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
2012-07-11 20:15:43 +00:00
switch_safe_free(method);
2012-07-27 20:07:11 +00:00
switch_safe_free(full_url);
2012-07-11 20:15:43 +00:00
}
break;
case nua_r_subscribe:
sofia_presence_handle_sip_r_subscribe(status, phrase, nua, profile, nh, sofia_private, sip, de, tags);
break;
case nua_i_subscribe:
sofia_presence_handle_sip_i_subscribe(status, phrase, nua, profile, nh, sofia_private, sip, de, tags);
2010-06-24 18:19:14 +00:00
break;
2013-01-27 05:16:26 +00:00
case nua_i_media_error:
{
if (sofia_private && sofia_private->call_id && sofia_private->network_ip && sofia_private->network_port) {
char *sql;
2013-10-17 17:39:55 +00:00
switch_event_t *event = NULL;
2013-01-27 05:16:26 +00:00
sql = switch_mprintf("delete from sip_registrations where call_id='%q' and network_ip='%q' and network_port='%q'",
sofia_private->call_id, sofia_private->network_ip, sofia_private->network_port);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "SOCKET DISCONNECT: %s %s:%s\n",
2013-01-27 05:16:26 +00:00
sofia_private->call_id, sofia_private->network_ip, sofia_private->network_port);
sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
2013-10-17 17:39:55 +00:00
switch_core_del_registration(sofia_private->user, sofia_private->realm, sofia_private->call_id);
if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "rpid", "unknown");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", profile->url);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "user-agent",
(sip && sip->sip_user_agent) ? sip->sip_user_agent->g_string : "unknown");
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", sofia_private->user, sofia_private->realm);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "status", "Unregistered");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "presence-source", "register");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
switch_event_fire(&event);
}
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, MY_EVENT_UNREGISTER) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "profile-name", profile->name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from-user", sofia_private->user);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from-host", sofia_private->realm);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-id", sofia_private->call_id);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "rpid", "unknown");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "reason", "socket-disconnection");
switch_event_fire(&event);
}
2013-01-27 05:16:26 +00:00
sofia_reg_check_socket(profile, sofia_private->call_id, sofia_private->network_ip, sofia_private->network_port);
2013-11-07 22:53:12 +00:00
nua_handle_destroy(nh);
2013-01-27 05:16:26 +00:00
}
}
break;
2010-06-24 18:19:14 +00:00
case nua_r_authenticate:
if (status >= 500) {
if (sofia_private && !zstr(sofia_private->gateway_name)) {
sofia_gateway_t *gateway = NULL;
if ((gateway = sofia_reg_find_gateway(sofia_private->gateway_name))) {
gateway->state = REG_STATE_FAILED;
gateway->failure_status = status;
sofia_reg_release_gateway(gateway);
}
2010-06-24 18:19:14 +00:00
} else {
nua_handle_destroy(nh);
}
}
break;
default:
if (status > 100) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s: unknown event %d: %03d %s\n", nua_event_name(event), event,
status, phrase);
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s: unknown event %d\n", nua_event_name(event), event);
}
break;
}
done:
if (tech_pvt && tech_pvt->want_event && event == tech_pvt->want_event) {
tech_pvt->want_event = 0;
}
2013-01-27 05:16:26 +00:00
if (sofia_private && sofia_private->call_id) {
check_destroy = 0;
}
switch (event) {
case nua_i_subscribe:
case nua_r_notify:
check_destroy = 0;
break;
case nua_i_notify:
if (sip && sip->sip_event && !strcmp(sip->sip_event->o_type, "dialog") && sip->sip_event->o_params && !strcmp(sip->sip_event->o_params[0], "sla")) {
check_destroy = 0;
}
break;
default:
break;
}
if ((sofia_private && sofia_private == &mod_sofia_globals.destroy_private)) {
nua_handle_bind(nh, NULL);
nua_handle_destroy(nh);
nh = NULL;
}
if (check_destroy) {
2011-07-15 05:23:00 +00:00
if (nh && ((sofia_private && sofia_private->destroy_nh) || !nua_handle_magic(nh))) {
if (sofia_private) {
nua_handle_bind(nh, NULL);
}
2011-07-14 05:17:05 +00:00
2012-11-06 14:51:33 +00:00
if (tech_pvt && (tech_pvt->nh == nh)) {
tech_pvt->nh = NULL;
}
nua_handle_destroy(nh);
nh = NULL;
}
}
if (sofia_private && sofia_private->destroy_me) {
if (tech_pvt) {
tech_pvt->sofia_private = NULL;
}
if (nh) {
nua_handle_bind(nh, NULL);
}
sofia_private->destroy_me = 12;
sofia_private_free(sofia_private);
}
if (gateway) {
sofia_reg_release_gateway(gateway);
}
if (locked && tech_pvt) {
switch_mutex_unlock(tech_pvt->sofia_mutex);
}
if (session && session != de->session) {
switch_core_session_rwunlock(session);
}
}
static uint32_t DE_THREAD_CNT = 0;
void *SWITCH_THREAD_FUNC sofia_msg_thread_run_once(switch_thread_t *thread, void *obj)
{
sofia_dispatch_event_t *de = (sofia_dispatch_event_t *) obj;
switch_memory_pool_t *pool = NULL;
switch_mutex_lock(mod_sofia_globals.mutex);
DE_THREAD_CNT++;
switch_mutex_unlock(mod_sofia_globals.mutex);
if (de) {
pool = de->pool;
de->pool = NULL;
sofia_process_dispatch_event(&de);
}
if (pool) {
switch_core_destroy_memory_pool(&pool);
}
switch_mutex_lock(mod_sofia_globals.mutex);
DE_THREAD_CNT--;
switch_mutex_unlock(mod_sofia_globals.mutex);
return NULL;
}
void sofia_process_dispatch_event_in_thread(sofia_dispatch_event_t **dep)
{
sofia_dispatch_event_t *de = *dep;
switch_memory_pool_t *pool;
//sofia_profile_t *profile = (*dep)->profile;
switch_thread_data_t *td;
switch_core_new_memory_pool(&pool);
*dep = NULL;
de->pool = pool;
td = switch_core_alloc(pool, sizeof(*td));
td->func = sofia_msg_thread_run_once;
td->obj = de;
switch_thread_pool_launch_thread(&td);
}
2011-11-18 23:00:30 +00:00
void sofia_process_dispatch_event(sofia_dispatch_event_t **dep)
{
2012-08-17 18:24:20 +00:00
sofia_dispatch_event_t *de = *dep;
nua_handle_t *nh = de->nh;
2011-07-01 17:27:40 +00:00
nua_t *nua = de->nua;
2011-10-03 23:53:17 +00:00
sofia_profile_t *profile = de->profile;
2012-08-16 17:09:19 +00:00
sofia_private_t *sofia_private = nua_handle_magic(de->nh);
2011-11-18 23:00:30 +00:00
*dep = NULL;
our_sofia_event_callback(de->data->e_event, de->data->e_status, de->data->e_phrase, de->nua, de->profile,
2012-08-16 17:09:19 +00:00
de->nh, sofia_private, de->sip, de, (tagi_t *) de->data->e_tags);
2011-07-15 05:23:00 +00:00
nua_destroy_event(de->event);
2011-07-14 05:17:05 +00:00
su_free(nh->nh_home, de);
2011-10-03 23:53:17 +00:00
switch_mutex_lock(profile->flag_mutex);
profile->queued_events--;
switch_mutex_unlock(profile->flag_mutex);
2012-08-16 17:09:19 +00:00
nua_handle_unref(nh);
nua_stack_unref(nua);
}
static int msg_queue_threads = 0;
//static int count = 0;
void *SWITCH_THREAD_FUNC sofia_msg_thread_run(switch_thread_t *thread, void *obj)
{
void *pop;
switch_queue_t *q = (switch_queue_t *) obj;
2012-05-03 21:31:21 +00:00
int my_id;
2012-05-03 21:31:21 +00:00
for (my_id = 0; my_id < mod_sofia_globals.msg_queue_len; my_id++) {
if (mod_sofia_globals.msg_queue_thread[my_id] == thread) {
2012-05-03 21:31:21 +00:00
break;
}
}
switch_mutex_lock(mod_sofia_globals.mutex);
msg_queue_threads++;
switch_mutex_unlock(mod_sofia_globals.mutex);
2012-05-03 21:31:21 +00:00
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "MSG Thread %d Started\n", my_id);
2012-05-03 21:31:21 +00:00
for(;;) {
if (switch_queue_pop(q, &pop) != SWITCH_STATUS_SUCCESS) {
switch_cond_next();
continue;
}
if (pop) {
sofia_dispatch_event_t *de = (sofia_dispatch_event_t *) pop;
sofia_process_dispatch_event(&de);
} else {
break;
}
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "MSG Thread Ended\n");
switch_mutex_lock(mod_sofia_globals.mutex);
msg_queue_threads--;
switch_mutex_unlock(mod_sofia_globals.mutex);
return NULL;
}
void sofia_msg_thread_start(int idx)
{
if (idx >= mod_sofia_globals.max_msg_queues ||
2012-05-03 21:31:21 +00:00
idx >= SOFIA_MAX_MSG_QUEUE || (idx < mod_sofia_globals.msg_queue_len && mod_sofia_globals.msg_queue_thread[idx])) {
return;
}
switch_mutex_lock(mod_sofia_globals.mutex);
if (idx >= mod_sofia_globals.msg_queue_len) {
int i;
mod_sofia_globals.msg_queue_len = idx + 1;
for (i = 0; i < mod_sofia_globals.msg_queue_len; i++) {
if (!mod_sofia_globals.msg_queue_thread[i]) {
switch_threadattr_t *thd_attr = NULL;
switch_threadattr_create(&thd_attr, mod_sofia_globals.pool);
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
2012-10-03 19:10:22 +00:00
//switch_threadattr_priority_set(thd_attr, SWITCH_PRI_REALTIME);
switch_thread_create(&mod_sofia_globals.msg_queue_thread[i],
thd_attr,
sofia_msg_thread_run,
mod_sofia_globals.msg_queue,
mod_sofia_globals.pool);
}
}
}
switch_mutex_unlock(mod_sofia_globals.mutex);
}
//static int foo = 0;
2012-11-29 05:12:35 +00:00
void sofia_queue_message(sofia_dispatch_event_t *de)
{
int launch = 0;
if (mod_sofia_globals.running == 0 || !mod_sofia_globals.msg_queue) {
2011-11-18 23:00:30 +00:00
sofia_process_dispatch_event(&de);
2011-06-20 15:07:01 +00:00
return;
}
if (de->profile && sofia_test_pflag(de->profile, PFLAG_THREAD_PER_REG) &&
de->data->e_event == nua_i_register && DE_THREAD_CNT < mod_sofia_globals.max_reg_threads) {
sofia_process_dispatch_event_in_thread(&de);
return;
}
if ((switch_queue_size(mod_sofia_globals.msg_queue) > (SOFIA_MSG_QUEUE_SIZE * (unsigned int)msg_queue_threads))) {
launch++;
2012-05-03 21:31:21 +00:00
}
2012-05-03 21:31:21 +00:00
if (launch) {
2012-05-03 21:31:21 +00:00
if (mod_sofia_globals.msg_queue_len < mod_sofia_globals.max_msg_queues) {
sofia_msg_thread_start(mod_sofia_globals.msg_queue_len + 1);
}
}
switch_queue_push(mod_sofia_globals.msg_queue, de);
}
static void set_call_id(private_object_t *tech_pvt, sip_t const *sip)
{
if (!tech_pvt->call_id && tech_pvt->session && tech_pvt->channel && sip && sip->sip_call_id && sip->sip_call_id->i_id) {
tech_pvt->call_id = switch_core_session_strdup(tech_pvt->session, sip->sip_call_id->i_id);
switch_channel_set_variable(tech_pvt->channel, "sip_call_id", tech_pvt->call_id);
}
}
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[])
{
sofia_dispatch_event_t *de;
int critical = (((SOFIA_MSG_QUEUE_SIZE * mod_sofia_globals.max_msg_queues) * 900) / 1000);
2012-08-21 05:04:58 +00:00
uint32_t sess_count = switch_core_session_count();
uint32_t sess_max = switch_core_session_limit(0);
2011-11-21 19:39:21 +00:00
switch(event) {
case nua_i_terminated:
if ((status == 401 || status == 407 || status == 403) && sofia_private && sofia_private->uuid) {
switch_core_session_t *session;
if ((session = switch_core_session_locate(sofia_private->uuid))) {
switch_channel_t *channel = switch_core_session_get_channel(session);
2012-09-08 21:12:35 +00:00
int end = 0;
2012-09-08 21:12:35 +00:00
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND && !switch_channel_test_flag(channel, CF_ANSWERED)) {
private_object_t *tech_pvt = switch_core_session_get_private(session);
if (status == 403) {
2012-09-19 16:47:53 +00:00
switch_channel_set_flag(channel, CF_NO_CDR);
switch_channel_hangup(channel, SWITCH_CAUSE_CALL_REJECTED);
2012-09-08 21:12:35 +00:00
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "detaching session %s\n", sofia_private->uuid);
if (!zstr(tech_pvt->call_id)) {
tech_pvt->sofia_private = NULL;
tech_pvt->nh = NULL;
sofia_set_flag(tech_pvt, TFLAG_BYE);
switch_mutex_lock(profile->flag_mutex);
switch_core_hash_insert(profile->chat_hash, tech_pvt->call_id, strdup(switch_core_session_get_uuid(session)));
switch_mutex_unlock(profile->flag_mutex);
} else {
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
}
2012-09-08 21:12:35 +00:00
}
end++;
}
switch_core_session_rwunlock(session);
if (end) {
goto end;
}
}
}
2012-09-08 21:12:35 +00:00
break;
case nua_i_invite:
case nua_i_register:
case nua_i_options:
case nua_i_notify:
case nua_i_info:
if (event == nua_i_invite) {
if (sip->sip_min_se && profile->minimum_session_expires) {
if (sip->sip_min_se->min_delta < profile->minimum_session_expires) {
2014-08-08 21:12:56 +00:00
char buf[64] = "";
switch_snprintf(buf, sizeof(buf), "Min-SE: %d", profile->minimum_session_expires);
nua_respond(nh, SIP_422_SESSION_TIMER_TOO_SMALL, SIPTAG_HEADER_STR(buf),TAG_END());
goto end;
}
}
}
if (!sofia_private) {
if (sess_count >= sess_max || !sofia_test_pflag(profile, PFLAG_RUNNING) || !switch_core_ready_inbound()) {
nua_respond(nh, 503, "Maximum Calls In Progress", SIPTAG_RETRY_AFTER_STR("300"), NUTAG_WITH_THIS(nua), TAG_END());
goto end;
}
if (switch_queue_size(mod_sofia_globals.msg_queue) > (unsigned int)critical) {
nua_respond(nh, 503, "System Busy", SIPTAG_RETRY_AFTER_STR("300"), NUTAG_WITH_THIS(nua), TAG_END());
goto end;
}
if (sofia_test_pflag(profile, PFLAG_STANDBY)) {
nua_respond(nh, 503, "System Paused", NUTAG_WITH_THIS(nua), TAG_END());
goto end;
}
}
break;
default:
break;
}
2011-10-03 23:53:17 +00:00
switch_mutex_lock(profile->flag_mutex);
profile->queued_events++;
switch_mutex_unlock(profile->flag_mutex);
2011-07-01 17:27:40 +00:00
de = su_alloc(nh->nh_home, sizeof(*de));
memset(de, 0, sizeof(*de));
nua_save_event(nua, de->event);
de->nh = nua_handle_ref(nh);
de->data = nua_event_data(de->event);
de->sip = sip_object(de->data->e_msg);
de->profile = profile;
de->nua = nua_stack_ref(nua);
if (event == nua_i_invite && !sofia_private) {
2012-08-21 05:04:58 +00:00
switch_core_session_t *session;
private_object_t *tech_pvt = NULL;
2012-08-21 05:04:58 +00:00
if (!(sofia_private = su_alloc(nh->nh_home, sizeof(*sofia_private)))) {
abort();
}
memset(sofia_private, 0, sizeof(*sofia_private));
sofia_private->is_call++;
2011-07-16 16:30:36 +00:00
sofia_private->is_static++;
nua_handle_bind(nh, sofia_private);
2012-08-21 05:04:58 +00:00
if (sip->sip_call_id && sip->sip_call_id->i_id) {
char *uuid;
switch_mutex_lock(profile->flag_mutex);
if ((uuid = (char *) switch_core_hash_find(profile->chat_hash, sip->sip_call_id->i_id))) {
switch_core_hash_delete(profile->chat_hash, sip->sip_call_id->i_id);
}
switch_mutex_unlock(profile->flag_mutex);
if (uuid) {
if ((session = switch_core_session_locate(uuid))) {
tech_pvt = switch_core_session_get_private(session);
switch_copy_string(sofia_private->uuid, switch_core_session_get_uuid(session), sizeof(sofia_private->uuid));
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Re-attaching to session %s\n", sofia_private->uuid);
de->init_session = session;
sofia_clear_flag(tech_pvt, TFLAG_BYE);
tech_pvt->sofia_private = NULL;
tech_pvt->nh = NULL;
switch_core_session_queue_signal_data(session, de);
switch_core_session_rwunlock(session);
session = NULL;
free(uuid);
uuid = NULL;
goto end;
} else {
free(uuid);
uuid = NULL;
sip = NULL;
}
}
}
if (!sip || !sip->sip_call_id || zstr(sip->sip_call_id->i_id)) {
nua_respond(nh, 503, "INVALID INVITE", TAG_END());
nua_destroy_event(de->event);
su_free(nh->nh_home, de);
switch_mutex_lock(profile->flag_mutex);
profile->queued_events--;
switch_mutex_unlock(profile->flag_mutex);
nua_handle_unref(nh);
nua_stack_unref(nua);
goto end;
}
2012-08-21 05:04:58 +00:00
if (sofia_test_pflag(profile, PFLAG_CALLID_AS_UUID)) {
session = switch_core_session_request_uuid(sofia_endpoint_interface, SWITCH_CALL_DIRECTION_INBOUND, SOF_NONE, NULL, sip->sip_call_id->i_id);
} else {
session = switch_core_session_request(sofia_endpoint_interface, SWITCH_CALL_DIRECTION_INBOUND, SOF_NONE, NULL);
}
if (session) {
const char *channel_name = NULL;
tech_pvt = sofia_glue_new_pvt(session);
if (sip->sip_from) {
channel_name = url_set_chanvars(session, sip->sip_from->a_url, sip_from);
}
if (!channel_name && sip->sip_contact && sip->sip_contact->m_url) {
channel_name = url_set_chanvars(session, sip->sip_contact->m_url, sip_contact);
}
if (sip->sip_referred_by) {
channel_name = url_set_chanvars(session, sip->sip_referred_by->b_url, sip_referred_by);
}
sofia_glue_attach_private(session, profile, tech_pvt, channel_name);
2012-08-21 05:04:58 +00:00
set_call_id(tech_pvt, sip);
2012-08-21 05:04:58 +00:00
} else {
nua_respond(nh, 503, "Maximum Calls In Progress", SIPTAG_RETRY_AFTER_STR("300"), TAG_END());
nua_destroy_event(de->event);
2012-08-21 05:04:58 +00:00
su_free(nh->nh_home, de);
2012-08-21 05:04:58 +00:00
switch_mutex_lock(profile->flag_mutex);
profile->queued_events--;
switch_mutex_unlock(profile->flag_mutex);
2012-08-21 05:04:58 +00:00
nua_handle_unref(nh);
nua_stack_unref(nua);
goto end;
}
2012-08-21 05:04:58 +00:00
if (switch_core_session_thread_launch(session) != SWITCH_STATUS_SUCCESS) {
char *uuid;
2012-08-22 22:05:25 +00:00
if (!switch_core_session_running(session) && !switch_core_session_started(session)) {
2012-08-21 05:04:58 +00:00
nua_handle_bind(nh, NULL);
sofia_private_free(sofia_private);
switch_core_session_destroy(&session);
nua_respond(nh, 503, "Maximum Calls In Progress", SIPTAG_RETRY_AFTER_STR("300"), TAG_END());
2012-08-22 22:05:25 +00:00
}
switch_mutex_lock(profile->flag_mutex);
if ((uuid = switch_core_hash_find(profile->chat_hash, tech_pvt->call_id))) {
free(uuid);
uuid = NULL;
switch_core_hash_delete(profile->chat_hash, tech_pvt->call_id);
}
switch_mutex_unlock(profile->flag_mutex);
2012-08-21 05:04:58 +00:00
goto end;
}
switch_copy_string(sofia_private->uuid, switch_core_session_get_uuid(session), sizeof(sofia_private->uuid));
de->init_session = session;
switch_core_session_queue_signal_data(session, de);
goto end;
}
if (sofia_private && sofia_private != &mod_sofia_globals.destroy_private && sofia_private != &mod_sofia_globals.keep_private) {
switch_core_session_t *session;
2012-08-17 18:24:20 +00:00
if ((session = switch_core_session_locate(sofia_private->uuid))) {
2012-08-21 05:04:58 +00:00
switch_core_session_queue_signal_data(session, de);
2012-08-17 18:24:20 +00:00
switch_core_session_rwunlock(session);
2012-08-21 05:04:58 +00:00
goto end;
}
}
sofia_queue_message(de);
2012-08-21 05:04:58 +00:00
end:
//switch_cond_next();
2012-08-21 05:04:58 +00:00
return;
}
void event_handler(switch_event_t *event)
{
char *subclass, *sql;
char *class;
switch_event_t *pevent;
/* Get Original Event Name */
class = switch_event_get_header_nil(event, "orig-event-name");
if (!strcasecmp(class, "PRESENCE_IN")) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\nGot Presence IN event via MultiCast\n");
if (switch_event_create(&pevent, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
2013-07-08 12:55:50 +00:00
switch_event_add_header_string(pevent, SWITCH_STACK_BOTTOM, "alt_event_type", switch_event_get_header_nil(event, "orig-alt_event_type"));
switch_event_add_header_string(pevent, SWITCH_STACK_BOTTOM, "answer-state", switch_event_get_header_nil(event, "orig-answer-state"));
switch_event_add_header_string(pevent, SWITCH_STACK_BOTTOM, "astate", switch_event_get_header_nil(event, "orig-astate"));
switch_event_add_header_string(pevent, SWITCH_STACK_BOTTOM, "call-direction", switch_event_get_header_nil(event, "orig-call-direction"));
switch_event_add_header_string(pevent, SWITCH_STACK_BOTTOM, "Caller-Callee-ID-Number", switch_event_get_header_nil(event, "Orig-Caller-Callee-ID-Number"));
switch_event_add_header_string(pevent, SWITCH_STACK_BOTTOM, "Caller-Caller-ID-Name", switch_event_get_header_nil(event, "Orig-Caller-Caller-ID-Name"));
switch_event_add_header_string(pevent, SWITCH_STACK_BOTTOM, "Caller-Caller-ID-Number", switch_event_get_header_nil(event, "Orig-Caller-Caller-ID-Number"));
switch_event_add_header_string(pevent, SWITCH_STACK_BOTTOM, "Caller-Destination-Number", switch_event_get_header_nil(event, "Orig-Caller-Destination-Number"));
switch_event_add_header_string(pevent, SWITCH_STACK_BOTTOM, "Caller-Direction", switch_event_get_header_nil(event, "Orig-Caller-Direction"));
switch_event_add_header_string(pevent, SWITCH_STACK_BOTTOM, "Caller-Username", switch_event_get_header_nil(event, "Orig-Caller-Username"));
switch_event_add_header_string(pevent, SWITCH_STACK_BOTTOM, "channel-state", switch_event_get_header_nil(event, "orig-channel-state"));
switch_event_add_header_string(pevent, SWITCH_STACK_BOTTOM, "force-status", switch_event_get_header_nil(event, "orig-force-status"));
switch_event_add_header_string(pevent, SWITCH_STACK_BOTTOM, "from", switch_event_get_header_nil(event, "orig-from"));
switch_event_add_header_string(pevent, SWITCH_STACK_BOTTOM, "login", switch_event_get_header_nil(event, "orig-login"));
switch_event_add_header_string(pevent, SWITCH_STACK_BOTTOM, "Other-Leg-Caller-ID-Name", switch_event_get_header_nil(event, "Orig-Other-Leg-Caller-ID-Name"));
switch_event_add_header_string(pevent, SWITCH_STACK_BOTTOM, "Other-Leg-Caller-ID-Number", switch_event_get_header_nil(event, "Orig-Other-Leg-Caller-ID-Number"));
switch_event_add_header_string(pevent, SWITCH_STACK_BOTTOM, "presence-call-direction", switch_event_get_header_nil(event, "orig-presence-call-direction"));
switch_event_add_header_string(pevent, SWITCH_STACK_BOTTOM, "presence-call-info-state", switch_event_get_header_nil(event, "orig-presence-call-info-state"));
switch_event_add_header_string(pevent, SWITCH_STACK_BOTTOM, "Presence-Privacy", switch_event_get_header_nil(event, "Orig-Presence-Privacy"));
switch_event_add_header_string(pevent, SWITCH_STACK_BOTTOM, "proto", switch_event_get_header_nil(event, "orig-proto"));
switch_event_add_header_string(pevent, SWITCH_STACK_BOTTOM, "register-source", switch_event_get_header_nil(event, "orig-register-source"));
switch_event_add_header_string(pevent, SWITCH_STACK_BOTTOM, "resub", switch_event_get_header_nil(event, "orig-resub"));
switch_event_add_header_string(pevent, SWITCH_STACK_BOTTOM, "rpid", switch_event_get_header_nil(event, "orig-rpid"));
switch_event_add_header_string(pevent, SWITCH_STACK_BOTTOM, "status", switch_event_get_header_nil(event, "orig-status"));
switch_event_add_header_string(pevent, SWITCH_STACK_BOTTOM, "Unique-ID", switch_event_get_header_nil(event, "Orig-Unique-ID"));
switch_event_add_header_string(pevent, SWITCH_STACK_BOTTOM, "variable_sip_from_user", switch_event_get_header_nil(event, "Orig-variable_sip_from_user"));
switch_event_add_header_string(pevent, SWITCH_STACK_BOTTOM, "variable_sip_to_user", switch_event_get_header_nil(event, "Orig-variable_sip_to_user"));
/* we cannot use switch_event_fire, or otherwise we'll start an endless loop */
sofia_presence_event_handler(pevent);
return;
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\nCannot inject PRESENCE_IN event\n");
return;
}
} else if (!strcasecmp(class, "MESSAGE_WAITING")) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\nGot MWI event via MultiCast\n");
if (switch_event_create(&pevent, SWITCH_EVENT_MESSAGE_WAITING) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(pevent, SWITCH_STACK_BOTTOM, "MWI-Messages-Waiting", switch_event_get_header_nil(event, "orig-MWI-Messages-Waiting"));
switch_event_add_header_string(pevent, SWITCH_STACK_BOTTOM, "MWI-Message-Account", switch_event_get_header_nil(event, "orig-MWI-Message-Account"));
switch_event_add_header_string(pevent, SWITCH_STACK_BOTTOM, "MWI-Voice-Message", switch_event_get_header_nil(event, "orig-MWI-Voice-Message"));
/* we cannot use switch_event_fire, or otherwise we'll start an endless loop */
sofia_presence_event_handler(pevent);
return;
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\nCannot inject MWI event\n");
return;
}
2013-05-03 18:13:38 +00:00
} else if ((subclass = switch_event_get_header_nil(event, "orig-event-subclass")) && !strcasecmp(subclass, MY_EVENT_UNREGISTER)) {
char *profile_name = switch_event_get_header_nil(event, "orig-profile-name");
char *from_user = switch_event_get_header_nil(event, "orig-from-user");
char *from_host = switch_event_get_header_nil(event, "orig-from-host");
char *call_id = switch_event_get_header_nil(event, "orig-call-id");
char *contact_str = switch_event_get_header_nil(event, "orig-contact");
sofia_profile_t *profile = NULL;
if (!profile_name || !(profile = sofia_glue_find_profile(profile_name))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Profile\n");
return;
}
if (sofia_test_pflag(profile, PFLAG_MULTIREG)) {
sql = switch_mprintf("delete from sip_registrations where call_id='%q'", call_id);
} else {
sql = switch_mprintf("delete from sip_registrations where sip_user='%q' and sip_host='%q'", from_user, from_host);
}
sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Expired propagated registration for %s@%s->%s\n", from_user, from_host, contact_str);
2013-05-03 18:13:38 +00:00
if (profile) {
sofia_glue_release_profile(profile);
}
} else if ((subclass = switch_event_get_header_nil(event, "orig-event-subclass")) && !strcasecmp(subclass, MY_EVENT_REGISTER)) {
char *from_user = switch_event_get_header_nil(event, "orig-from-user");
char *from_host = switch_event_get_header_nil(event, "orig-from-host");
char *to_host = switch_event_get_header_nil(event, "orig-to-host");
char *contact_str = switch_event_get_header_nil(event, "orig-contact");
char *exp_str = switch_event_get_header_nil(event, "orig-expires");
char *rpid = switch_event_get_header_nil(event, "orig-rpid");
char *call_id = switch_event_get_header_nil(event, "orig-call-id");
char *user_agent = switch_event_get_header_nil(event, "orig-user-agent");
long expires = (long) switch_epoch_time_now(NULL);
char *profile_name = switch_event_get_header_nil(event, "orig-profile-name");
char *to_user = switch_event_get_header_nil(event, "orig-to-user");
char *presence_hosts = switch_event_get_header_nil(event, "orig-presence-hosts");
char *network_ip = switch_event_get_header_nil(event, "orig-network-ip");
char *network_port = switch_event_get_header_nil(event, "orig-network-port");
char *username = switch_event_get_header_nil(event, "orig-username");
char *realm = switch_event_get_header_nil(event, "orig-realm");
char *orig_server_host = switch_event_get_header_nil(event, "orig-FreeSWITCH-IPv4");
char *orig_hostname = switch_event_get_header_nil(event, "orig-FreeSWITCH-Hostname");
char *fixed_contact_str = NULL;
sofia_profile_t *profile = NULL;
char guess_ip4[256];
char *mwi_account = NULL;
char *dup_mwi_account = NULL;
char *mwi_user = NULL;
char *mwi_host = NULL;
if ((mwi_account = switch_event_get_header_nil(event, "orig-mwi-account"))) {
dup_mwi_account = strdup(mwi_account);
switch_assert(dup_mwi_account != NULL);
switch_split_user_domain(dup_mwi_account, &mwi_user, &mwi_host);
}
if (!mwi_user) {
mwi_user = (char *) from_user;
}
if (!mwi_host) {
mwi_host = (char *) from_host;
}
if (exp_str) {
expires += atol(exp_str);
}
if (!rpid) {
rpid = "unknown";
}
if (!profile_name || !(profile = sofia_glue_find_profile(profile_name))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Profile\n");
goto end;
}
if (sofia_test_pflag(profile, PFLAG_MULTIREG)) {
sql = switch_mprintf("delete from sip_registrations where call_id='%q'", call_id);
} else {
sql = switch_mprintf("delete from sip_registrations where sip_user='%q' and sip_host='%q'", from_user, from_host);
}
if (mod_sofia_globals.rewrite_multicasted_fs_path && contact_str) {
const char *needle = ";fs_path=";
char *sptr, *eptr = NULL;
/* allocate enough room for worst-case scenario */
size_t len = strlen(contact_str) + strlen(to_host) + 14;
fixed_contact_str = malloc(len);
switch_assert(fixed_contact_str);
switch_copy_string(fixed_contact_str, contact_str, len);
if ((sptr = strstr(fixed_contact_str, needle))) {
char *origsptr = strstr(contact_str, needle);
eptr = strchr(++origsptr, ';');
} else {
sptr = strchr(fixed_contact_str, '\0') - 1;
}
switch (mod_sofia_globals.rewrite_multicasted_fs_path) {
case 1:
switch_snprintf(sptr, len - (sptr - fixed_contact_str), ";fs_path=sip:%s%s", to_host, eptr ? eptr : ">");
break;
case 2:
switch_snprintf(sptr, len - (sptr - fixed_contact_str), ";fs_path=sip:%s%s", orig_server_host, eptr ? eptr : ">");
break;
case 3:
switch_snprintf(sptr, len - (sptr - fixed_contact_str), ";fs_path=sip:%s%s", orig_hostname, eptr ? eptr : ">");
break;
default:
switch_snprintf(sptr, len - (sptr - fixed_contact_str), ";fs_path=sip:%s%s", to_host, eptr ? eptr : ">");
break;
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Rewrote contact string from '%s' to '%s'\n", contact_str, fixed_contact_str);
contact_str = fixed_contact_str;
}
sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
switch_find_local_ip(guess_ip4, sizeof(guess_ip4), NULL, AF_INET);
sql = switch_mprintf("insert into sip_registrations "
"(call_id, sip_user, sip_host, presence_hosts, contact, status, rpid, expires,"
"user_agent, server_user, server_host, profile_name, hostname, network_ip, network_port, sip_username, sip_realm,"
"mwi_user, mwi_host, orig_server_host, orig_hostname) "
"values ('%q','%q','%q','%q','%q','Registered','%q',%ld, '%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q')",
call_id, from_user, from_host, presence_hosts, contact_str, rpid, expires, user_agent, to_user, guess_ip4,
profile_name, mod_sofia_globals.hostname, network_ip, network_port, username, realm, mwi_user, mwi_host,
orig_server_host, orig_hostname);
if (sql) {
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);
}
if (profile) {
sofia_glue_release_profile(profile);
}
end:
switch_safe_free(fixed_contact_str);
switch_safe_free(dup_mwi_account);
}
}
static void sofia_perform_profile_start_failure(sofia_profile_t *profile, char *profile_name, char *file, int line)
{
int arg = 0;
switch_event_t *s_event;
if (profile) {
if (!strcasecmp(profile->shutdown_type, "true")) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Profile %s could not load! Shutting down!\n", profile->name);
switch_core_session_ctl(SCSC_SHUTDOWN, &arg);
} else if (!strcasecmp(profile->shutdown_type, "elegant")) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Profile %s could not load! Waiting for calls to finish, then shutting down!\n",
profile->name);
switch_core_session_ctl(SCSC_SHUTDOWN_ELEGANT, &arg);
} else if (!strcasecmp(profile->shutdown_type, "asap")) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Profile %s could not load! Shutting down ASAP!\n", profile->name);
switch_core_session_ctl(SCSC_SHUTDOWN_ASAP, &arg);
} else if (!strcasecmp(profile->shutdown_type, "reincarnate-now")) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Profile %s could not load! Asking for reincarnation now!\n", profile->name);
switch_core_session_ctl(SCSC_REINCARNATE_NOW, &arg);
}
}
if ((switch_event_create(&s_event, SWITCH_EVENT_FAILURE) == SWITCH_STATUS_SUCCESS)) {
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "module_name", "mod_sofia");
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile_name", profile_name);
if (profile) {
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile_uri", profile->url);
}
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "failure_message", "Profile failed to start.");
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "file", file);
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "line", "%d", line);
switch_event_fire(&s_event);
}
}
/* not a static function so that it's still visible on stacktraces */
void watchdog_triggered_abort(void) {
abort();
}
#define sofia_profile_start_failure(p, xp) sofia_perform_profile_start_failure(p, xp, __FILE__, __LINE__)
2010-09-14 21:19:03 +00:00
#define SQLLEN 1024 * 1024
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 = profile->ireg_seconds; /* Number of loop iterations done when we haven't checked for registrations */
uint32_t gateway_loops = GATEWAY_SECONDS; /* Number of loop iterations done when we haven't checked for gateways */
sofia_set_pflag_locked(profile, PFLAG_WORKER_RUNNING);
while ((mod_sofia_globals.running == 1 && sofia_test_pflag(profile, PFLAG_RUNNING))) {
if (profile->watchdog_enabled) {
uint32_t event_diff = 0, step_diff = 0, event_fail = 0, step_fail = 0;
if (profile->step_timeout) {
step_diff = (uint32_t) ((switch_time_now() - profile->last_root_step) / 1000);
if (step_diff > profile->step_timeout) {
step_fail = 1;
}
}
if (profile->event_timeout) {
event_diff = (uint32_t) ((switch_time_now() - profile->last_sip_event) / 1000);
if (event_diff > profile->event_timeout) {
event_fail = 1;
}
}
if (step_fail && profile->event_timeout && !event_fail) {
step_fail = 0;
}
if (event_fail || step_fail) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Profile %s: SIP STACK FAILURE DETECTED BY WATCHDOG!\n"
"GOODBYE CRUEL WORLD, I'M LEAVING YOU TODAY....GOODBYE, GOODBYE, GOOD BYE\n", profile->name);
switch_yield(2000000);
watchdog_triggered_abort();
}
}
2010-10-06 21:05:00 +00:00
if (!sofia_test_pflag(profile, PFLAG_STANDBY)) {
if (++ireg_loops >= (uint32_t)profile->ireg_seconds) {
time_t now = switch_epoch_time_now(NULL);
sofia_reg_check_expire(profile, now, 0);
ireg_loops = 0;
}
if (++gateway_loops >= GATEWAY_SECONDS) {
sofia_reg_check_gateway(profile, switch_epoch_time_now(NULL));
sofia_sub_check_gateway(profile, switch_epoch_time_now(NULL));
gateway_loops = 0;
2012-05-11 15:20:45 +00:00
}
}
switch_yield(1000000);
}
sofia_clear_pflag_locked(profile, PFLAG_WORKER_RUNNING);
return NULL;
}
switch_thread_t *launch_sofia_worker_thread(sofia_profile_t *profile)
{
2011-06-27 15:15:03 +00:00
switch_thread_t *thread = NULL;
switch_threadattr_t *thd_attr = NULL;
int x = 0;
2011-06-27 15:15:03 +00:00
switch_xml_t cfg = NULL, xml = NULL, xprofile = NULL, xprofiles = NULL, gateways_tag = NULL, domains_tag = NULL, domain_tag = NULL;
switch_event_t *params = NULL;
char *cf = "sofia.conf";
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Launching worker thread for %s\n", profile->name);
/* Parse gateways */
switch_event_create(&params, SWITCH_EVENT_REQUEST_PARAMS);
switch_assert(params);
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "profile", profile->name);
2011-06-27 15:15:03 +00:00
if (!(xml = switch_xml_open_cfg(cf, &cfg, params))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", cf);
goto end;
}
if ((xprofiles = switch_xml_child(cfg, "profiles"))) {
if ((xprofile = switch_xml_find_child(xprofiles, "profile", "name", profile->name))) {
if ((gateways_tag = switch_xml_child(xprofile, "gateways"))) {
parse_gateways(profile, gateways_tag);
}
if ((domains_tag = switch_xml_child(xprofile, "domains"))) {
switch_event_t *xml_params;
switch_event_create(&xml_params, SWITCH_EVENT_REQUEST_PARAMS);
switch_assert(xml_params);
switch_event_add_header_string(xml_params, SWITCH_STACK_BOTTOM, "purpose", "gateways");
switch_event_add_header_string(xml_params, SWITCH_STACK_BOTTOM, "profile", profile->name);
for (domain_tag = switch_xml_child(domains_tag, "domain"); domain_tag; domain_tag = domain_tag->next) {
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");
2011-06-27 15:15:03 +00:00
if (!zstr(dname)) {
if (!strcasecmp(dname, "all")) {
switch_xml_t xml_root, x_domains;
if (switch_xml_locate("directory", NULL, NULL, NULL, &xml_root, &x_domains, xml_params, SWITCH_FALSE) ==
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(xml_root);
}
} else if (switch_xml_locate_domain(dname, xml_params, &droot, &x_domain_tag) == SWITCH_STATUS_SUCCESS) {
parse_domain_tag(profile, x_domain_tag, dname, parse, alias);
switch_xml_free(droot);
}
}
}
2011-06-27 15:15:03 +00:00
switch_event_destroy(&xml_params);
}
}
}
switch_threadattr_create(&thd_attr, profile->pool);
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
2012-10-03 19:10:22 +00:00
//switch_threadattr_priority_set(thd_attr, SWITCH_PRI_REALTIME);
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;
}
}
2011-06-27 15:15:03 +00:00
end:
switch_event_destroy(&params);
if (xml) {
switch_xml_free(xml);
}
return thread;
}
void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t *thread, void *obj)
{
sofia_profile_t *profile = (sofia_profile_t *) obj;
2011-04-22 21:43:29 +00:00
//switch_memory_pool_t *pool;
sip_alias_node_t *node;
switch_event_t *s_event;
int use_100rel = !sofia_test_pflag(profile, PFLAG_DISABLE_100REL);
int use_timer = !sofia_test_pflag(profile, PFLAG_DISABLE_TIMER);
int use_rfc_5626 = sofia_test_pflag(profile, PFLAG_ENABLE_RFC5626);
const char *supported = NULL;
int sanity, attempts = 0;
switch_thread_t *worker_thread;
switch_status_t st;
char qname [128] = "";
switch_mutex_lock(mod_sofia_globals.mutex);
mod_sofia_globals.threads++;
switch_mutex_unlock(mod_sofia_globals.mutex);
profile->s_root = su_root_create(NULL);
//profile->home = su_home_new(sizeof(*profile->home));
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Creating agent for %s\n", profile->name);
if (!sofia_glue_init_sql(profile)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot Open SQL Database [%s]!\n", profile->name);
sofia_profile_start_failure(profile, profile->name);
sofia_glue_del_profile(profile);
goto end;
}
2014-02-12 22:26:09 +00:00
supported = switch_core_sprintf(profile->pool, "%s%s%spath, replaces", use_100rel ? "precondition, 100rel, " : "", use_timer ? "timer, " : "", use_rfc_5626 ? "outbound, " : "");
if (sofia_test_pflag(profile, PFLAG_AUTO_NAT) && switch_nat_get_type()) {
if ( (! sofia_test_pflag(profile, PFLAG_TLS) || ! profile->tls_only) && switch_nat_add_mapping(profile->sip_port, SWITCH_NAT_UDP, NULL, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Created UDP nat mapping for %s port %d\n", profile->name, profile->sip_port);
}
if (switch_nat_add_mapping(profile->sip_port, SWITCH_NAT_TCP, NULL, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Created TCP nat mapping for %s port %d\n", profile->name, profile->sip_port);
}
if (sofia_test_pflag(profile, PFLAG_TLS)
&& switch_nat_add_mapping(profile->tls_sip_port, SWITCH_NAT_TCP, NULL, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Created TCP/TLS nat mapping for %s port %d\n", profile->name, profile->tls_sip_port);
}
}
/* We have to init the verify_subjects here as during config stage profile->home isn't setup, it should be freed when profile->home is freed */
if ( (profile->tls_verify_policy & TPTLS_VERIFY_SUBJECTS_IN) && profile->tls_verify_in_subjects_str && ! profile->tls_verify_in_subjects) {
profile->tls_verify_in_subjects = su_strlst_dup_split((su_home_t *)profile->nua, profile->tls_verify_in_subjects_str, "|");
}
do {
profile->nua = nua_create(profile->s_root, /* Event loop */
sofia_event_callback, /* Callback for processing events */
profile, /* Additional data to pass to callback */
TAG_IF( ! sofia_test_pflag(profile, PFLAG_TLS) || ! profile->tls_only, NUTAG_URL(profile->bindurl)),
NTATAG_USER_VIA(1),
TPTAG_PONG2PING(1),
2014-06-20 15:23:02 +00:00
NTATAG_TCP_RPORT(0),
NTATAG_TLS_RPORT(0),
NUTAG_RETRY_AFTER_ENABLE(0),
TAG_IF(!strchr(profile->sipip, ':'),
SOATAG_AF(SOA_AF_IP4_ONLY)),
TAG_IF(strchr(profile->sipip, ':'),
SOATAG_AF(SOA_AF_IP6_ONLY)),
TAG_IF(sofia_test_pflag(profile, PFLAG_TLS),
NUTAG_SIPS_URL(profile->tls_bindurl)),
TAG_IF(profile->ws_bindurl,
NUTAG_WS_URL(profile->ws_bindurl)),
TAG_IF(profile->wss_bindurl,
NUTAG_WSS_URL(profile->wss_bindurl)),
TAG_IF(profile->tls_cert_dir,
NUTAG_CERTIFICATE_DIR(profile->tls_cert_dir)),
TAG_IF(sofia_test_pflag(profile, PFLAG_TLS) && profile->tls_passphrase,
TPTAG_TLS_PASSPHRASE(profile->tls_passphrase)),
TAG_IF(sofia_test_pflag(profile, PFLAG_TLS),
TPTAG_TLS_VERIFY_POLICY(profile->tls_verify_policy)),
TAG_IF(sofia_test_pflag(profile, PFLAG_TLS),
TPTAG_TLS_VERIFY_DEPTH(profile->tls_verify_depth)),
TAG_IF(sofia_test_pflag(profile, PFLAG_TLS),
TPTAG_TLS_VERIFY_DATE(profile->tls_verify_date)),
TAG_IF(sofia_test_pflag(profile, PFLAG_TLS) && profile->tls_verify_in_subjects,
TPTAG_TLS_VERIFY_SUBJECTS(profile->tls_verify_in_subjects)),
TAG_IF(sofia_test_pflag(profile, PFLAG_TLS),
TPTAG_TLS_CIPHERS(profile->tls_ciphers)),
TAG_IF(sofia_test_pflag(profile, PFLAG_TLS),
TPTAG_TLS_VERSION(profile->tls_version)),
TAG_IF(sofia_test_pflag(profile, PFLAG_TLS) && profile->tls_timeout,
TPTAG_TLS_TIMEOUT(profile->tls_timeout)),
TAG_IF(!strchr(profile->sipip, ':'),
NTATAG_UDP_MTU(65535)),
TAG_IF(sofia_test_pflag(profile, PFLAG_DISABLE_SRV),
NTATAG_USE_SRV(0)),
TAG_IF(sofia_test_pflag(profile, PFLAG_DISABLE_NAPTR),
NTATAG_USE_NAPTR(0)),
TAG_IF(sofia_test_pflag(profile, PFLAG_TCP_PINGPONG),
TPTAG_PINGPONG(profile->tcp_pingpong)),
TAG_IF(sofia_test_pflag(profile, PFLAG_TCP_PING2PONG),
TPTAG_PINGPONG(profile->tcp_ping2pong)),
TAG_IF(sofia_test_pflag(profile, PFLAG_DISABLE_SRV503),
NTATAG_SRV_503(0)),
TAG_IF(sofia_test_pflag(profile, PFLAG_SOCKET_TCP_KEEPALIVE),
TPTAG_SOCKET_KEEPALIVE(profile->socket_tcp_keepalive)),
TAG_IF(sofia_test_pflag(profile, PFLAG_TCP_KEEPALIVE),
TPTAG_KEEPALIVE(profile->tcp_keepalive)),
NTATAG_DEFAULT_PROXY(profile->outbound_proxy),
NTATAG_SERVER_RPORT(profile->server_rport_level),
NTATAG_CLIENT_RPORT(profile->client_rport_level),
TPTAG_LOG(sofia_test_flag(profile, TFLAG_TPORT_LOG)),
TPTAG_CAPT(sofia_test_flag(profile, TFLAG_CAPTURE) ? mod_sofia_globals.capture_server : NULL),
TAG_IF(sofia_test_pflag(profile, PFLAG_SIPCOMPACT),
NTATAG_SIPFLAGS(MSG_DO_COMPACT)),
TAG_IF(profile->timer_t1, NTATAG_SIP_T1(profile->timer_t1)),
TAG_IF(profile->timer_t1x64, NTATAG_SIP_T1X64(profile->timer_t1x64)),
TAG_IF(profile->timer_t2, NTATAG_SIP_T2(profile->timer_t2)),
TAG_IF(profile->timer_t4, NTATAG_SIP_T4(profile->timer_t4)),
SIPTAG_ACCEPT_STR("application/sdp, multipart/mixed"),
TAG_IF(sofia_test_pflag(profile, PFLAG_NO_CONNECTION_REUSE),
TPTAG_REUSE(0)),
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 (%s) ATTEMPT %d (RETRY IN %d SEC)\n",
profile->name, profile->bindurl, attempts + 1, profile->bind_attempt_interval);
if (attempts < profile->bind_attempts) {
switch_yield(1000000 * profile->bind_attempt_interval);
}
}
} while (!profile->nua && attempts++ < profile->bind_attempts);
if (!profile->nua) {
2013-03-26 20:44:22 +00:00
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Creating SIP UA for profile: %s (%s)\n"
2012-09-19 15:14:32 +00:00
"The likely causes for this are:\n" "1) Another application is already listening on the specified address.\n"
2013-03-26 20:44:22 +00:00
"2) The IP the profile is attempting to bind to is not local to this system.\n", profile->name, profile->bindurl);
sofia_profile_start_failure(profile, profile->name);
sofia_glue_del_profile(profile);
goto end;
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Created agent for %s\n", profile->name);
nua_set_params(profile->nua,
SIPTAG_ALLOW_STR("INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, INFO"),
NUTAG_AUTOANSWER(0),
NUTAG_AUTOACK(0),
NUTAG_AUTOALERT(0),
NUTAG_ENABLEMESSENGER(1),
2012-05-03 21:31:21 +00:00
NTATAG_EXTRA_100(0),
TAG_IF(sofia_test_pflag(profile, PFLAG_ALLOW_UPDATE), NUTAG_ALLOW("UPDATE")),
TAG_IF((profile->mflags & MFLAG_REGISTER), NUTAG_ALLOW("REGISTER")),
TAG_IF((profile->mflags & MFLAG_REFER), NUTAG_ALLOW("REFER")),
TAG_IF(!sofia_test_pflag(profile, PFLAG_DISABLE_100REL), NUTAG_ALLOW("PRACK")),
NUTAG_ALLOW("INFO"),
NUTAG_ALLOW("NOTIFY"),
NUTAG_ALLOW_EVENTS("talk"),
NUTAG_ALLOW_EVENTS("hold"),
2012-07-11 20:15:43 +00:00
NUTAG_ALLOW_EVENTS("conference"),
NUTAG_APPL_METHOD("OPTIONS"),
NUTAG_APPL_METHOD("REFER"),
NUTAG_APPL_METHOD("REGISTER"),
NUTAG_APPL_METHOD("NOTIFY"), NUTAG_APPL_METHOD("INFO"), NUTAG_APPL_METHOD("ACK"), NUTAG_APPL_METHOD("SUBSCRIBE"),
#ifdef MANUAL_BYE
NUTAG_APPL_METHOD("BYE"),
#endif
NUTAG_APPL_METHOD("MESSAGE"),
2012-07-11 20:15:43 +00:00
TAG_IF(profile->session_timeout && profile->minimum_session_expires, NUTAG_MIN_SE(profile->minimum_session_expires)),
NUTAG_SESSION_TIMER(profile->session_timeout),
NTATAG_MAX_PROCEEDING(profile->max_proceeding),
TAG_IF(profile->pres_type, NUTAG_ALLOW("PUBLISH")),
TAG_IF(profile->pres_type, NUTAG_ALLOW("SUBSCRIBE")),
TAG_IF(profile->pres_type, NUTAG_ENABLEMESSAGE(1)),
TAG_IF(profile->pres_type, NUTAG_ALLOW_EVENTS("presence")),
TAG_IF(profile->pres_type, NUTAG_ALLOW_EVENTS("as-feature-event")),
TAG_IF((profile->pres_type || sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE)), NUTAG_ALLOW_EVENTS("dialog")),
TAG_IF((profile->pres_type || sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE)), NUTAG_ALLOW_EVENTS("line-seize")),
TAG_IF(profile->pres_type, NUTAG_ALLOW_EVENTS("call-info")),
TAG_IF((profile->pres_type || sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE)), NUTAG_ALLOW_EVENTS("sla")),
TAG_IF(profile->pres_type, NUTAG_ALLOW_EVENTS("include-session-description")),
TAG_IF(profile->pres_type, NUTAG_ALLOW_EVENTS("presence.winfo")),
TAG_IF(profile->pres_type, NUTAG_ALLOW_EVENTS("message-summary")),
2012-06-04 19:16:30 +00:00
TAG_IF(profile->pres_type == PRES_TYPE_PNP, NUTAG_ALLOW_EVENTS("ua-profile")),
NUTAG_ALLOW_EVENTS("refer"), SIPTAG_SUPPORTED_STR(supported), 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);
2011-06-27 15:15:03 +00:00
if (sofia_test_pflag(profile, PFLAG_AUTO_ASSIGN_PORT) || sofia_test_pflag(profile, PFLAG_AUTO_ASSIGN_TLS_PORT)) {
sip_via_t *vias = nta_agent_via(profile->nua->nua_nta);
sip_via_t *via = NULL;
for (via = vias; via; via = via->v_next) {
if (sofia_test_pflag(profile, PFLAG_AUTO_ASSIGN_PORT) && !strcmp(via->v_protocol, "SIP/2.0/UDP")) {
profile->sip_port = (switch_port_t)atoi(via->v_port);
2012-12-10 19:52:25 +00:00
if (!profile->extsipport) profile->extsipport = profile->sip_port;
2011-06-27 15:15:03 +00:00
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Found auto sip port %d for %s\n", profile->sip_port, profile->name);
}
if (sofia_test_pflag(profile, PFLAG_AUTO_ASSIGN_TLS_PORT) && !strcmp(via->v_protocol, "SIP/2.0/TLS")) {
profile->tls_sip_port = (switch_port_t)atoi(via->v_port);
2011-06-27 15:15:03 +00:00
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Found auto sip port %d for %s (TLS)\n", profile->tls_sip_port, profile->name);
}
}
2011-06-27 15:15:03 +00:00
config_sofia_profile_urls(profile);
}
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 */
NTATAG_SERVER_RPORT(profile->server_rport_level), NUTAG_URL(node->url), TAG_END()); /* Last tag should always finish the sequence */
nua_set_params(node->nua,
NUTAG_APPL_METHOD("OPTIONS"),
NUTAG_APPL_METHOD("REFER"),
NUTAG_APPL_METHOD("SUBSCRIBE"),
NUTAG_AUTOANSWER(0),
NUTAG_AUTOACK(0),
NUTAG_AUTOALERT(0),
TAG_IF((profile->mflags & MFLAG_REGISTER), NUTAG_ALLOW("REGISTER")),
TAG_IF((profile->mflags & MFLAG_REFER), NUTAG_ALLOW("REFER")),
NUTAG_ALLOW("INFO"),
TAG_IF(profile->pres_type, NUTAG_ALLOW("PUBLISH")),
TAG_IF(profile->pres_type, NUTAG_ENABLEMESSAGE(1)),
SIPTAG_SUPPORTED_STR(supported), 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->dbh_mutex, SWITCH_MUTEX_NESTED, profile->pool);
switch_mutex_init(&profile->gateway_mutex, SWITCH_MUTEX_NESTED, profile->pool);
switch_queue_create(&profile->event_queue, SOFIA_QUEUE_SIZE, profile->pool);
switch_snprintf(qname, sizeof(qname), "sofia:%s", profile->name);
2012-10-25 20:09:09 +00:00
switch_sql_queue_manager_init_name(qname,
2012-10-27 17:27:00 +00:00
&profile->qm,
2012-11-17 02:09:38 +00:00
2,
2012-10-27 17:27:00 +00:00
profile->odbc_dsn ? profile->odbc_dsn : profile->dbname,
SWITCH_MAX_TRANS,
profile->pre_trans_execute,
profile->post_trans_execute,
profile->inner_pre_trans_execute,
profile->inner_post_trans_execute);
2012-10-25 20:09:09 +00:00
switch_sql_queue_manager_start(profile->qm);
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%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_string(s_event, SWITCH_STACK_BOTTOM, "module_name", "mod_sofia");
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile_name", profile->name);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile_uri", 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_string(s_event, SWITCH_STACK_BOTTOM, "profile_tls_uri", profile->tls_url);
}
switch_event_fire(&s_event);
}
sofia_glue_add_profile(profile->name, profile);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Starting thread for %s\n", profile->name);
profile->started = switch_epoch_time_now(NULL);
sofia_set_pflag_locked(profile, PFLAG_RUNNING);
worker_thread = launch_sofia_worker_thread(profile);
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);
profile->last_root_step = switch_time_now();
}
sofia_clear_pflag_locked(profile, PFLAG_RUNNING);
2013-04-24 21:35:58 +00:00
sofia_reg_close_handles(profile);
switch_core_session_hupall_matching_var("sofia_profile_name", profile->name, SWITCH_CAUSE_MANAGER_REQUEST);
sanity = 10;
while (profile->inuse) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Waiting for %d session(s)\n", profile->inuse);
su_root_step(profile->s_root, 1000);
if (!--sanity) {
break;
} else if (sanity == 5) {
switch_core_session_hupall_matching_var("sofia_profile_name", profile->name, SWITCH_CAUSE_MANAGER_REQUEST);
}
}
sofia_reg_unregister(profile);
nua_shutdown(profile->nua);
2013-04-24 21:35:58 +00:00
sanity = 100;
2011-10-03 23:53:17 +00:00
while (!sofia_test_pflag(profile, PFLAG_SHUTDOWN) || profile->queued_events > 0) {
2011-09-06 17:53:29 +00:00
su_root_step(profile->s_root, 1000);
if (!--sanity) {
break;
}
}
sofia_clear_pflag_locked(profile, PFLAG_RUNNING);
2011-09-06 17:53:29 +00:00
sofia_clear_pflag_locked(profile, PFLAG_SHUTDOWN);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Waiting for worker thread\n");
if ( worker_thread ) {
switch_thread_join(&st, worker_thread);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ERROR: Sofia worker thead failed to start\n");
}
sanity = 4;
while (profile->inuse) {
switch_core_session_hupall_matching_var("sofia_profile_name", profile->name, SWITCH_CAUSE_MANAGER_REQUEST);
switch_yield(5000000);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Waiting for %d session(s)\n", profile->inuse);
if (!--sanity) {
break;
}
}
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);
2012-10-31 13:59:31 +00:00
switch_sql_queue_manager_destroy(&profile->qm);
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%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_string(s_event, SWITCH_STACK_BOTTOM, "module_name", "mod_sofia");
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile_name", profile->name);
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile_uri", 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_string(s_event, SWITCH_STACK_BOTTOM, "profile_tls_uri", profile->tls_url);
}
switch_event_fire(&s_event);
}
if (sofia_test_pflag(profile, PFLAG_AUTO_NAT) && switch_nat_get_type()) {
if (switch_nat_del_mapping(profile->sip_port, SWITCH_NAT_UDP) == SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Deleted UDP nat mapping for %s port %d\n", profile->name, profile->sip_port);
}
if (switch_nat_del_mapping(profile->sip_port, SWITCH_NAT_TCP) == SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Deleted TCP nat mapping for %s port %d\n", profile->name, profile->sip_port);
}
if (sofia_test_pflag(profile, PFLAG_TLS) && switch_nat_del_mapping(profile->tls_sip_port, SWITCH_NAT_TCP) == SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Deleted TCP/TLS nat mapping for %s port %d\n", profile->name, profile->tls_sip_port);
}
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Write lock %s\n", profile->name);
switch_thread_rwlock_wrlock(profile->rwlock);
//su_home_unref(profile->home);
su_root_destroy(profile->s_root);
2011-04-22 21:43:29 +00:00
//pool = profile->pool;
sofia_glue_del_profile(profile);
switch_core_hash_destroy(&profile->chat_hash);
2013-04-24 21:35:58 +00:00
switch_core_hash_destroy(&profile->reg_nh_hash);
switch_core_hash_destroy(&profile->mwi_debounce_hash);
switch_thread_rwlock_unlock(profile->rwlock);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Write unlock %s\n", profile->name);
if (sofia_test_pflag(profile, PFLAG_RESPAWN)) {
config_sofia(SOFIA_CONFIG_RESPAWN, profile->name);
}
sofia_profile_destroy(profile);
end:
switch_mutex_lock(mod_sofia_globals.mutex);
mod_sofia_globals.threads--;
switch_mutex_unlock(mod_sofia_globals.mutex);
return NULL;
}
void sofia_profile_destroy(sofia_profile_t *profile)
{
if (!profile->inuse) {
switch_memory_pool_t *pool = profile->pool;
switch_core_destroy_memory_pool(&pool);
} else {
sofia_set_pflag(profile, PFLAG_DESTROY);
}
}
void launch_sofia_profile_thread(sofia_profile_t *profile)
{
2013-02-18 18:58:33 +00:00
//switch_thread_t *thread;
switch_threadattr_t *thd_attr = NULL;
switch_threadattr_create(&thd_attr, profile->pool);
switch_threadattr_detach_set(thd_attr, 1);
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
2012-10-01 15:20:48 +00:00
switch_threadattr_priority_set(thd_attr, SWITCH_PRI_REALTIME);
2013-02-18 18:58:33 +00:00
switch_thread_create(&profile->thread, thd_attr, sofia_profile_thread_run, profile, profile->pool);
}
static void logger(void *logarg, char const *fmt, va_list ap)
{
if (!fmt) return;
switch_log_vprintf(SWITCH_CHANNEL_LOG_CLEAN, mod_sofia_globals.tracelevel, fmt, ap);
}
static su_log_t *sofia_get_logger(const char *name)
{
if (!strcasecmp(name, "tport")) {
return tport_log;
} else if (!strcasecmp(name, "iptsec")) {
return iptsec_log;
} else if (!strcasecmp(name, "nea")) {
return nea_log;
} else if (!strcasecmp(name, "nta")) {
return nta_log;
} else if (!strcasecmp(name, "nth_client")) {
return nth_client_log;
} else if (!strcasecmp(name, "nth_server")) {
return nth_server_log;
} else if (!strcasecmp(name, "nua")) {
return nua_log;
} else if (!strcasecmp(name, "soa")) {
return soa_log;
} else if (!strcasecmp(name, "sresolv")) {
return sresolv_log;
#ifdef HAVE_SOFIA_STUN
} else if (!strcasecmp(name, "stun")) {
return stun_log;
#endif
} else if (!strcasecmp(name, "default")) {
return su_log_default;
} else {
return NULL;
}
}
switch_status_t sofia_set_loglevel(const char *name, int level)
{
su_log_t *log = NULL;
if (level < 0 || level > 9) {
return SWITCH_STATUS_FALSE;
}
if (!strcasecmp(name, "all")) {
su_log_set_level(su_log_default, level);
su_log_set_level(tport_log, level);
su_log_set_level(iptsec_log, level);
su_log_set_level(nea_log, level);
su_log_set_level(nta_log, level);
su_log_set_level(nth_client_log, level);
su_log_set_level(nth_server_log, level);
su_log_set_level(nua_log, level);
su_log_set_level(soa_log, level);
su_log_set_level(sresolv_log, level);
#ifdef HAVE_SOFIA_STUN
su_log_set_level(stun_log, level);
#endif
return SWITCH_STATUS_SUCCESS;
}
if (!(log = sofia_get_logger(name))) {
return SWITCH_STATUS_FALSE;
}
su_log_set_level(log, level);
return SWITCH_STATUS_SUCCESS;
}
int sofia_get_loglevel(const char *name)
{
su_log_t *log = NULL;
if ((log = sofia_get_logger(name))) {
return log->log_level;
} else {
return -1;
}
}
static void parse_gateway_subscriptions(sofia_profile_t *profile, sofia_gateway_t *gateway, switch_xml_t gw_subs_tag)
{
switch_xml_t subscription_tag, param;
for (subscription_tag = switch_xml_child(gw_subs_tag, "subscription"); subscription_tag; subscription_tag = subscription_tag->next) {
sofia_gateway_subscription_t *gw_sub;
if ((gw_sub = switch_core_alloc(profile->pool, sizeof(*gw_sub)))) {
char *expire_seconds = "3600", *retry_seconds = "30", *content_type = "NO_CONTENT_TYPE";
uint32_t username_in_request = 0;
char *event = (char *) switch_xml_attr_soft(subscription_tag, "event");
gw_sub->event = switch_core_strdup(gateway->pool, event);
gw_sub->gateway = gateway;
gw_sub->next = NULL;
for (param = switch_xml_child(subscription_tag, "param"); param; param = param->next) {
char *var = (char *) switch_xml_attr_soft(param, "name");
char *val = (char *) switch_xml_attr_soft(param, "value");
if (!strcmp(var, "expire-seconds")) {
expire_seconds = val;
} else if (!strcmp(var, "retry-seconds")) {
retry_seconds = val;
} else if (!strcmp(var, "content-type")) {
content_type = val;
} else if (!strcmp(var, "username-in-request")) {
username_in_request = switch_true(val);
}
}
gw_sub->retry_seconds = atoi(retry_seconds);
if (gw_sub->retry_seconds < 10) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "INVALID: retry_seconds correcting the value to 30\n");
gw_sub->retry_seconds = 30;
}
gw_sub->expires_str = switch_core_strdup(gateway->pool, expire_seconds);
if ((gw_sub->freq = atoi(gw_sub->expires_str)) < 5) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid Freq: %d. Setting Register-Frequency to 3600\n", gw_sub->freq);
gw_sub->freq = 3600;
}
if(username_in_request) {
gw_sub->request_uri = gateway->register_to;
} else {
gw_sub->request_uri = gateway->register_url;
}
gw_sub->freq -= 2;
gw_sub->content_type = switch_core_strdup(gateway->pool, content_type);
gw_sub->next = gateway->subscriptions;
}
gateway->subscriptions = gw_sub;
}
}
static void parse_gateways(sofia_profile_t *profile, switch_xml_t gateways_tag)
{
switch_xml_t gateway_tag, param = NULL, x_params, gw_subs_tag;
sofia_gateway_t *gp;
for (gateway_tag = switch_xml_child(gateways_tag, "gateway"); gateway_tag; gateway_tag = gateway_tag->next) {
char *name = (char *) switch_xml_attr_soft(gateway_tag, "name");
sofia_gateway_t *gateway;
char *pkey = switch_mprintf("%s::%s", profile->name, name);
if (zstr(name) || switch_regex_match(name, "^[\\w\\.\\-\\_]+$") != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Ignoring invalid name '%s'\n", name ? name : "NULL");
goto skip;
}
switch_mutex_lock(mod_sofia_globals.hash_mutex);
if ((gp = switch_core_hash_find(mod_sofia_globals.gateway_hash, name)) && (gp = switch_core_hash_find(mod_sofia_globals.gateway_hash, pkey)) && !gp->deleted) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Ignoring duplicate gateway '%s'\n", name);
switch_mutex_unlock(mod_sofia_globals.hash_mutex);
free(pkey);
goto skip;
}
free(pkey);
switch_mutex_unlock(mod_sofia_globals.hash_mutex);
if ((gateway = switch_core_alloc(profile->pool, sizeof(*gateway)))) {
const char *sipip, *format;
switch_uuid_t uuid;
uint32_t ping_freq = 0, extension_in_contact = 0, distinct_to = 0, rfc_5626 = 0;
2013-01-07 17:43:26 +00:00
int ping_max = 1, ping_min = 1;
char *register_str = "true", *scheme = "Digest",
*realm = NULL,
*username = NULL,
*auth_username = NULL,
*password = NULL,
*caller_id_in_from = "false",
*extension = NULL,
*proxy = NULL,
*options_user_agent = NULL,
*context = profile->context,
*expire_seconds = "3600",
*retry_seconds = "30",
*timeout_seconds = "60",
*from_user = "", *from_domain = NULL, *outbound_proxy = NULL, *register_proxy = NULL, *contact_host = NULL,
*contact_params = "", *params = NULL, *register_transport = NULL,
*reg_id = NULL, *str_rfc_5626 = "";
if (!context) {
context = "default";
}
switch_uuid_get(&uuid);
switch_uuid_format(gateway->uuid_str, &uuid);
gateway->register_transport = SOFIA_TRANSPORT_UDP;
gateway->pool = profile->pool;
gateway->profile = profile;
gateway->name = switch_core_strdup(gateway->pool, name);
gateway->freq = 0;
gateway->next = NULL;
gateway->ping = 0;
gateway->ping_freq = 0;
gateway->ping_max = 0;
gateway->ping_min = 0;
gateway->ping_count = 0;
gateway->ib_calls = 0;
gateway->ob_calls = 0;
gateway->ib_failed_calls = 0;
gateway->ob_failed_calls = 0;
gateway->destination_prefix = "";
if ((x_params = switch_xml_child(gateway_tag, "variables"))) {
param = switch_xml_child(x_params, "variable");
} else {
param = switch_xml_child(gateway_tag, "variable");
}
for (; param; param = param->next) {
const char *var = switch_xml_attr(param, "name");
const char *val = switch_xml_attr(param, "value");
const char *direction = switch_xml_attr(param, "direction");
int in = 0, out = 0;
if (var && val) {
if (direction) {
if (!strcasecmp(direction, "inbound")) {
in = 1;
} else if (!strcasecmp(direction, "outbound")) {
out = 1;
}
} else {
in = out = 1;
}
if (in) {
if (!gateway->ib_vars) {
switch_event_create_plain(&gateway->ib_vars, SWITCH_EVENT_GENERAL);
}
switch_event_add_header_string(gateway->ib_vars, SWITCH_STACK_BOTTOM, var, val);
}
if (out) {
if (!gateway->ob_vars) {
switch_event_create_plain(&gateway->ob_vars, SWITCH_EVENT_GENERAL);
}
switch_event_add_header_string(gateway->ob_vars, SWITCH_STACK_BOTTOM, var, val);
}
}
}
if ((x_params = switch_xml_child(gateway_tag, "params"))) {
param = switch_xml_child(x_params, "param");
} else {
param = switch_xml_child(gateway_tag, "param");
}
for (; param; param = param->next) {
char *var = (char *) switch_xml_attr_soft(param, "name");
char *val = (char *) switch_xml_attr_soft(param, "value");
if (!strcmp(var, "register")) {
register_str = val;
} else if (!strcmp(var, "scheme")) {
scheme = val;
} else if (!strcmp(var, "realm")) {
realm = val;
} else if (!strcmp(var, "username")) {
username = val;
} else if (!strcmp(var, "extension-in-contact")) {
extension_in_contact = switch_true(val);
} else if (!strcmp(var, "auth-username")) {
auth_username = val;
} else if (!strcmp(var, "password")) {
password = val;
} else if (!strcmp(var, "caller-id-in-from")) {
caller_id_in_from = val;
} else if (!strcmp(var, "extension")) {
extension = val;
} else if (!strcmp(var, "ping")) {
ping_freq = atoi(val);
} else if (!strcmp(var, "ping-max")) {
ping_max = atoi(val);
} else if (!strcmp(var, "ping-min")) {
ping_min = atoi(val);
} else if (!strcmp(var, "ping-user-agent")) {
options_user_agent = val;
} else if (!strcmp(var, "proxy")) {
proxy = val;
} else if (!strcmp(var, "context")) {
context = val;
} else if (!strcmp(var, "expire-seconds")) {
expire_seconds = val;
} else if (!strcmp(var, "retry-seconds")) {
retry_seconds = val;
} else if (!strcmp(var, "timeout-seconds")) {
timeout_seconds = val;
} else if (!strcmp(var, "retry_seconds")) { // support typo for back compat
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, "contact-host")) {
contact_host = val;
} else if (!strcmp(var, "register-proxy")) {
register_proxy = val;
} else if (!strcmp(var, "outbound-proxy")) {
outbound_proxy = val;
} else if (!strcmp(var, "distinct-to")) {
distinct_to = switch_true(val);
} else if (!strcmp(var, "destination-prefix")) {
if (!zstr(val)) {
gateway->destination_prefix = switch_core_strdup(gateway->pool, val);
}
} else if (!strcmp(var, "rfc-5626")) {
rfc_5626 = switch_true(val);
} else if (!strcmp(var, "reg-id")) {
reg_id = 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;
}
}
2011-12-19 17:49:14 +00:00
/* RFC 5626 enable in the GW profile and the UA profile */
if (rfc_5626 && sofia_test_pflag(profile, PFLAG_ENABLE_RFC5626)) {
char str_guid[su_guid_strlen + 1];
su_guid_t guid[1];
su_guid_generate(guid);
su_guid_sprintf(str_guid, su_guid_strlen + 1, guid);
str_rfc_5626 = switch_core_sprintf(gateway->pool, ";reg-id=%s;+sip.instance=\"<urn:uuid:%s>\"",reg_id,str_guid);
}
if (zstr(realm)) {
if (zstr(proxy)) {
realm = name;
} else {
realm = proxy;
}
}
if (switch_true(register_str)) {
if (zstr(username)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ERROR: username param is REQUIRED!\n");
goto skip;
}
if (zstr(password)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ERROR: password param is REQUIRED!\n");
goto skip;
}
} else {
if (zstr(username)) {
username = "FreeSWITCH";
}
if (zstr(password)) {
password = "";
}
}
if (zstr(from_user)) {
from_user = username;
}
if (zstr(proxy)) {
proxy = realm;
}
if (!switch_true(register_str)) {
gateway->state = REG_STATE_NOREG;
gateway->status = SOFIA_GATEWAY_UP;
}
if (zstr(auth_username)) {
auth_username = username;
}
if (!zstr(register_proxy)) {
if (strncasecmp(register_proxy, "sip:", 4) && strncasecmp(register_proxy, "sips:", 5)) {
gateway->register_sticky_proxy = switch_core_sprintf(gateway->pool, "sip:%s", register_proxy);
} else {
gateway->register_sticky_proxy = switch_core_strdup(gateway->pool, register_proxy);
}
}
if (!zstr(outbound_proxy)) {
if (strncasecmp(outbound_proxy, "sip:", 4) && strncasecmp(outbound_proxy, "sips:", 5)) {
gateway->outbound_sticky_proxy = switch_core_sprintf(gateway->pool, "sip:%s", outbound_proxy);
} else {
gateway->outbound_sticky_proxy = switch_core_strdup(gateway->pool, outbound_proxy);
}
}
gateway->retry_seconds = atoi(retry_seconds);
if (gateway->retry_seconds < 5) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid retry-seconds of %d on gateway %s, using the value of 30 instead.\n",
gateway->retry_seconds, name);
gateway->retry_seconds = 30;
}
gateway->reg_timeout_seconds = atoi(timeout_seconds);
2010-11-04 19:38:43 +00:00
if (gateway->reg_timeout_seconds < 5) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid timeout-seconds of %d on gateway %s, using the value of 60 instead.\n",
gateway->reg_timeout_seconds, name);
2010-11-04 19:38:43 +00:00
gateway->reg_timeout_seconds = 60;
}
gateway->register_scheme = switch_core_strdup(gateway->pool, scheme);
gateway->register_context = switch_core_strdup(gateway->pool, context);
gateway->register_realm = switch_core_strdup(gateway->pool, realm);
gateway->register_username = switch_core_strdup(gateway->pool, username);
gateway->auth_username = switch_core_strdup(gateway->pool, auth_username);
gateway->register_password = switch_core_strdup(gateway->pool, password);
gateway->distinct_to = distinct_to;
gateway->options_user_agent = options_user_agent;
if (switch_true(caller_id_in_from)) {
sofia_set_flag(gateway, REG_FLAG_CALLERID);
}
register_transport = (char *) sofia_glue_transport2str(gateway->register_transport);
2011-02-20 21:10:02 +00:00
if (! zstr(contact_params)) {
if (*contact_params == ';') {
params = switch_core_sprintf(gateway->pool, "%s;transport=%s;gw=%s", contact_params, register_transport, gateway->name);
} else {
params = switch_core_sprintf(gateway->pool, ";%s;transport=%s;gw=%s", contact_params, register_transport, gateway->name);
}
} else {
params = switch_core_sprintf(gateway->pool, ";transport=%s;gw=%s", register_transport, gateway->name);
}
if (!zstr(from_domain)) {
gateway->from_domain = switch_core_strdup(gateway->pool, from_domain);
}
if (!zstr(register_transport) && !switch_stristr("transport=", proxy)) {
gateway->register_url = switch_core_sprintf(gateway->pool, "sip:%s;transport=%s", proxy, register_transport);
} else {
gateway->register_url = switch_core_sprintf(gateway->pool, "sip:%s", proxy);
}
2012-04-09 18:30:51 +00:00
gateway->register_from = switch_core_sprintf(gateway->pool, "<sip:%s@%s>",
from_user, !zstr(from_domain) ? from_domain : proxy);
if (ping_freq) {
if (ping_freq >= 5) {
gateway->ping_freq = ping_freq;
gateway->ping_max = ping_max;
gateway->ping_min = ping_min;
gateway->ping = switch_epoch_time_now(NULL) + ping_freq;
2012-04-09 18:30:51 +00:00
gateway->options_to_uri = switch_core_sprintf(gateway->pool, "<sip:%s>",
!zstr(from_domain) ? from_domain : proxy);
gateway->options_from_uri = gateway->options_to_uri;
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ERROR: invalid ping!\n");
}
}
if (contact_host) {
if (!strcmp(contact_host, "sip-ip")) {
sipip = profile->sipip;
} else {
sipip = contact_host;
}
} else if (profile->extsipip) {
sipip = profile->extsipip;
} else {
sipip = profile->sipip;
}
if (zstr(extension)) {
extension = username;
} else {
gateway->real_extension = switch_core_strdup(gateway->pool, extension);
}
gateway->extension = switch_core_strdup(gateway->pool, extension);
if (!strncasecmp(proxy, "sip:", 4)) {
gateway->register_proxy = switch_core_strdup(gateway->pool, proxy);
gateway->register_to = switch_core_sprintf(gateway->pool, "sip:%s@%s", username, proxy + 4);
} else {
gateway->register_proxy = switch_core_sprintf(gateway->pool, "sip:%s", proxy);
gateway->register_to = switch_core_sprintf(gateway->pool, "sip:%s@%s", username, proxy);
}
/* This checks to make sure we provide the right contact on register for targets behind nat with us. */
if (sofia_test_pflag(profile, PFLAG_AUTO_NAT)) {
char *register_host = NULL;
register_host = sofia_glue_get_register_host(gateway->register_proxy);
if (register_host && switch_is_lan_addr(register_host)) {
sipip = profile->sipip;
}
switch_safe_free(register_host);
}
if (extension_in_contact) {
if (rfc_5626) {
format = strchr(sipip, ':') ? "<sip:%s@[%s]:%d>%s" : "<sip:%s@%s:%d%s>%s";
gateway->register_contact = switch_core_sprintf(gateway->pool, format, extension,
sipip,
sofia_glue_transport_has_tls(gateway->register_transport) ?
2012-12-07 16:29:44 +00:00
profile->tls_sip_port : profile->extsipport, params, str_rfc_5626);
} else {
2012-01-31 17:03:09 +00:00
format = strchr(sipip, ':') ? "<sip:%s@[%s]:%d%s>" : "<sip:%s@%s:%d%s>";
gateway->register_contact = switch_core_sprintf(gateway->pool, format, extension,
sipip,
sofia_glue_transport_has_tls(gateway->register_transport) ?
2012-12-07 16:29:44 +00:00
profile->tls_sip_port : profile->extsipport, params);
}
} else {
if (rfc_5626) {
format = strchr(sipip, ':') ? "<sip:gw+%s@[%s]:%d%s>%s" : "<sip:gw+%s@%s:%d%s>%s";
gateway->register_contact = switch_core_sprintf(gateway->pool, format, gateway->name,
sipip,
sofia_glue_transport_has_tls(gateway->register_transport) ?
2012-12-07 16:29:44 +00:00
profile->tls_sip_port : profile->extsipport, params, str_rfc_5626);
} else {
format = strchr(sipip, ':') ? "<sip:gw+%s@[%s]:%d%s>" : "<sip:gw+%s@%s:%d%s>";
gateway->register_contact = switch_core_sprintf(gateway->pool, format, gateway->name,
sipip,
sofia_glue_transport_has_tls(gateway->register_transport) ?
2012-12-07 16:29:44 +00:00
profile->tls_sip_port : profile->extsipport, params);
}
}
gateway->expires_str = switch_core_strdup(gateway->pool, expire_seconds);
if ((gateway->freq = atoi(gateway->expires_str)) < 5) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
"Invalid register-frequency of %d on gateway %s, using the value of 3600 instead\n", gateway->freq, name);
gateway->freq = 3600;
}
if ((gw_subs_tag = switch_xml_child(gateway_tag, "subscriptions"))) {
parse_gateway_subscriptions(profile, gateway, gw_subs_tag);
}
sofia_reg_add_gateway(profile, gateway->name, gateway);
}
skip:
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_DEBUG1, "Alias [%s] for profile [%s] (already exists)\n", dname, profile->name);
}
}
if (switch_true(parse)) {
switch_xml_t gts, gt, uts, ut, gateways_tag;
/* Backwards Compatibility */
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);
}
}
/* New Method with <groups> tags and users are now inside a <users> tag */
for (gts = switch_xml_child(x_domain_tag, "groups"); gts; gts = gts->next) {
for (gt = switch_xml_child(gts, "group"); gt; gt = gt->next) {
for (uts = switch_xml_child(gt, "users"); uts; uts = uts->next) {
for (ut = switch_xml_child(uts, "user"); ut; ut = ut->next) {
if (((gateways_tag = switch_xml_child(ut, "gateways")))) {
parse_gateways(profile, gateways_tag);
}
}
}
}
}
}
}
2011-06-27 15:15:03 +00:00
static void config_sofia_profile_urls(sofia_profile_t * profile)
{
if (profile->extsipip) {
char *ipv6 = strchr(profile->extsipip, ':');
profile->public_url = switch_core_sprintf(profile->pool,
"sip:%s@%s%s%s:%d",
profile->contact_user,
2012-12-07 16:29:44 +00:00
ipv6 ? "[" : "", profile->extsipip, ipv6 ? "]" : "", profile->extsipport);
2011-06-27 15:15:03 +00:00
}
if (profile->extsipip && !sofia_test_pflag(profile, PFLAG_AUTO_NAT)) {
char *ipv6 = strchr(profile->extsipip, ':');
profile->url = switch_core_sprintf(profile->pool,
"sip:%s@%s%s%s:%d",
2012-12-07 16:29:44 +00:00
profile->contact_user, ipv6 ? "[" : "", profile->extsipip, ipv6 ? "]" : "", profile->extsipport);
2011-06-27 15:15:03 +00:00
profile->bindurl = switch_core_sprintf(profile->pool, "%s;maddr=%s", profile->url, profile->sipip);
} else {
char *ipv6 = strchr(profile->sipip, ':');
profile->url = switch_core_sprintf(profile->pool,
"sip:%s@%s%s%s:%d",
profile->contact_user, ipv6 ? "[" : "", profile->sipip, ipv6 ? "]" : "", profile->sip_port);
profile->bindurl = profile->url;
}
2011-06-27 15:15:03 +00:00
profile->tcp_contact = switch_core_sprintf(profile->pool, "<%s;transport=tcp>", profile->url);
2011-06-27 15:15:03 +00:00
if (profile->public_url) {
profile->tcp_public_contact = switch_core_sprintf(profile->pool, "<%s;transport=tcp>", profile->public_url);
}
2011-06-27 15:15:03 +00:00
if (profile->bind_params) {
char *bindurl;
if (!switch_stristr("transport=", profile->bind_params)) {
profile->bind_params = switch_core_sprintf(profile->pool, "%s;transport=udp,tcp", profile->bind_params);
}
bindurl = switch_core_sprintf(profile->pool, "%s;%s", profile->bindurl, profile->bind_params);
profile->bindurl = bindurl;
} else {
char *bindurl = switch_core_sprintf(profile->pool, "%s;transport=udp,tcp", profile->bindurl);
profile->bindurl = bindurl;
2011-06-27 15:15:03 +00:00
}
if ( profile->ws_port ) {
char *ip = !zstr(profile->ws_ip) ? profile->ws_ip : profile->sipip;
switch_port_t port = profile->ws_port;
char *ipv6 = strchr(ip, ':');
profile->ws_bindurl =
switch_core_sprintf(profile->pool,
"sip:%s@%s%s%s:%d;transport=ws",
profile->contact_user, ipv6 ? "[" : "", ip, ipv6 ? "]" : "", port);
}
if ( profile->wss_port ) {
char *ip = !zstr(profile->wss_ip) ? profile->wss_ip : profile->sipip;
switch_port_t port = profile->wss_port;
char *ipv6 = strchr(ip, ':');
profile->wss_bindurl =
switch_core_sprintf(profile->pool,
"sips:%s@%s%s%s:%d;transport=wss",
profile->contact_user, ipv6 ? "[" : "", ip, ipv6 ? "]" : "", port);
}
2011-06-27 15:15:03 +00:00
/*
* handle TLS params #2
*/
if (sofia_test_pflag(profile, PFLAG_TLS)) {
if (!profile->tls_sip_port && !sofia_test_pflag(profile, PFLAG_AUTO_ASSIGN_TLS_PORT)) {
profile->tls_sip_port = (switch_port_t) atoi(SOFIA_DEFAULT_TLS_PORT);
}
2011-06-27 15:15:03 +00:00
if (profile->extsipip) {
char *ipv6 = strchr(profile->extsipip, ':');
profile->tls_public_url = switch_core_sprintf(profile->pool,
"sip:%s@%s%s%s:%d",
profile->contact_user,
ipv6 ? "[" : "", profile->extsipip, ipv6 ? "]" : "", profile->tls_sip_port);
}
2011-06-27 15:15:03 +00:00
if (profile->extsipip && !sofia_test_pflag(profile, PFLAG_AUTO_NAT)) {
char *ipv6 = strchr(profile->extsipip, ':');
profile->tls_url =
switch_core_sprintf(profile->pool,
"sip:%s@%s%s%s:%d",
profile->contact_user, ipv6 ? "[" : "", profile->extsipip, ipv6 ? "]" : "", profile->tls_sip_port);
profile->tls_bindurl =
switch_core_sprintf(profile->pool,
"sips:%s@%s%s%s:%d;maddr=%s",
profile->contact_user,
ipv6 ? "[" : "", profile->extsipip, ipv6 ? "]" : "", profile->tls_sip_port, profile->sipip);
} else {
char *ipv6 = strchr(profile->sipip, ':');
profile->tls_url =
switch_core_sprintf(profile->pool,
"sip:%s@%s%s%s:%d",
profile->contact_user, ipv6 ? "[" : "", profile->sipip, ipv6 ? "]" : "", profile->tls_sip_port);
profile->tls_bindurl =
switch_core_sprintf(profile->pool,
"sips:%s@%s%s%s:%d",
profile->contact_user, ipv6 ? "[" : "", profile->sipip, ipv6 ? "]" : "", profile->tls_sip_port);
}
2011-06-27 15:15:03 +00:00
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);
}
profile->tls_contact = switch_core_sprintf(profile->pool, "<%s;transport=tls>", profile->tls_url);
if (profile->tls_public_url) {
profile->tls_public_contact = switch_core_sprintf(profile->pool, "<%s;transport=tls>", profile->tls_public_url);
}
2011-06-27 15:15:03 +00:00
}
}
2013-06-28 15:42:01 +00:00
#ifdef SOFIA_CUSTOM_TIME
/* appears to not be granular enough */
static void sofia_time(su_time_t *tv)
{
switch_time_t now;
if (tv) {
now = switch_micro_time_now();
tv->tv_sec = ((uint32_t) (now / 1000000)) + 2208988800UL;
tv->tv_usec = (uint32_t) (now % 1000000);
}
2013-06-28 15:42:01 +00:00
}
#endif
switch_status_t sofia_init(void)
{
su_init();
if (sip_update_default_mclass(sip_extend_mclass(NULL)) < 0) {
su_deinit();
return SWITCH_STATUS_GENERR;
}
2013-06-28 15:42:01 +00:00
#ifdef SOFIA_TIME
su_set_time_func(sofia_time);
#endif
/* Redirect loggers in sofia */
su_log_redirect(su_log_default, logger, NULL);
su_log_redirect(tport_log, logger, NULL);
su_log_redirect(iptsec_log, logger, NULL);
su_log_redirect(nea_log, logger, NULL);
su_log_redirect(nta_log, logger, NULL);
su_log_redirect(nth_client_log, logger, NULL);
su_log_redirect(nth_server_log, logger, NULL);
su_log_redirect(nua_log, logger, NULL);
su_log_redirect(soa_log, logger, NULL);
su_log_redirect(sresolv_log, logger, NULL);
#ifdef HAVE_SOFIA_STUN
su_log_redirect(stun_log, logger, NULL);
#endif
return SWITCH_STATUS_SUCCESS;
}
switch_status_t config_sofia(sofia_config_t reload, char *profile_name)
{
char *cf = "sofia.conf";
2011-06-27 15:15:03 +00:00
switch_xml_t cfg, xml = NULL, xprofile, param, settings, profiles;
switch_status_t status = SWITCH_STATUS_SUCCESS;
sofia_profile_t *profile = NULL;
char url[512] = "";
int profile_found = 0;
switch_event_t *params = NULL;
sofia_profile_t *profile_already_started = NULL;
if (!zstr(profile_name) && (profile = sofia_glue_find_profile(profile_name))) {
if (reload == SOFIA_CONFIG_RESCAN) {
profile_already_started = profile;
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Profile [%s] Already exists.\n", switch_str_nil(profile_name));
status = SWITCH_STATUS_FALSE;
sofia_glue_release_profile(profile);
return status;
}
}
switch_event_create(&params, SWITCH_EVENT_REQUEST_PARAMS);
switch_assert(params);
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "profile", profile_name);
if (reload == SOFIA_CONFIG_RESCAN) {
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "reconfig", "true");
}
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;
}
mod_sofia_globals.auto_restart = SWITCH_TRUE;
2013-03-21 18:05:32 +00:00
mod_sofia_globals.reg_deny_binding_fetch_and_no_lookup = SWITCH_FALSE; /* handle backwards compatilibity - by default use new behavior */
mod_sofia_globals.rewrite_multicasted_fs_path = SWITCH_FALSE;
if ((settings = switch_xml_child(cfg, "global_settings"))) {
for (param = switch_xml_child(settings, "param"); param; param = param->next) {
char *var = (char *) switch_xml_attr_soft(param, "name");
char *val = (char *) switch_xml_attr_soft(param, "value");
if (!strcasecmp(var, "log-level")) {
su_log_set_level(NULL, atoi(val));
} else if (!strcasecmp(var, "tracelevel")) {
mod_sofia_globals.tracelevel = switch_log_str2level(val);
} else if (!strcasecmp(var, "debug-presence")) {
mod_sofia_globals.debug_presence = atoi(val);
} else if (!strcasecmp(var, "debug-sla")) {
mod_sofia_globals.debug_sla = atoi(val);
} else if (!strcasecmp(var, "max-reg-threads") && val) {
int x = atoi(val);
if (x > 0) {
mod_sofia_globals.max_reg_threads = x;
}
} else if (!strcasecmp(var, "auto-restart")) {
mod_sofia_globals.auto_restart = switch_true(val);
} else if (!strcasecmp(var, "reg-deny-binding-fetch-and-no-lookup")) { /* backwards compatibility */
mod_sofia_globals.reg_deny_binding_fetch_and_no_lookup = switch_true(val); /* remove when noone complains about the extra lookup */
if (switch_true(val)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Enabling reg-deny-binding-fetch-and-no-lookup - this functionality is "
"deprecated and will be removed - let FS devs know if you think it should stay\n");
}
} else if (!strcasecmp(var, "rewrite-multicasted-fs-path")) {
if( (!strcasecmp(val, "to_host")) || (!strcasecmp(val, "1")) ) {
/* old behaviour */
mod_sofia_globals.rewrite_multicasted_fs_path = 1;
} else if (!strcasecmp(val, "original_server_host")) {
mod_sofia_globals.rewrite_multicasted_fs_path = 2;
} else if (!strcasecmp(val, "original_hostname")) {
mod_sofia_globals.rewrite_multicasted_fs_path = 3;
} else {
mod_sofia_globals.rewrite_multicasted_fs_path = SWITCH_FALSE;
}
2013-03-29 22:55:50 +00:00
} else if (!strcasecmp(var, "capture-server")) {
mod_sofia_globals.capture_server = switch_core_strdup(mod_sofia_globals.pool, val);
}
}
}
if ((profiles = switch_xml_child(cfg, "profiles"))) {
for (xprofile = switch_xml_child(profiles, "profile"); xprofile; xprofile = xprofile->next) {
char *xprofilename = (char *) switch_xml_attr_soft(xprofile, "name");
char *xprofiledomain = (char *) switch_xml_attr(xprofile, "domain");
if (!(settings = switch_xml_child(xprofile, "settings"))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No Settings, check the new config!\n");
sofia_profile_start_failure(NULL, xprofilename);
} else {
switch_memory_pool_t *pool = NULL;
if (!xprofilename) {
xprofilename = "unnamed";
}
if (profile_name) {
if (strcasecmp(profile_name, xprofilename)) {
continue;
} else {
profile_found = 1;
}
}
if (!profile_already_started) {
/* 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");
sofia_profile_start_failure(NULL, xprofilename);
goto done;
}
if (!(profile = (sofia_profile_t *) switch_core_alloc(pool, sizeof(*profile)))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n");
sofia_profile_start_failure(NULL, xprofilename);
goto done;
}
profile->tls_verify_policy = TPTLS_VERIFY_NONE;
/* lib default */
profile->tls_verify_depth = 2;
switch_mutex_init(&profile->gw_mutex, SWITCH_MUTEX_NESTED, pool);
profile->trans_timeout = 100;
profile->auto_rtp_bugs = RTP_BUG_CISCO_SKIP_MARK_BIT_2833;// | RTP_BUG_SONUS_SEND_INVALID_TIMESTAMP_2833;
profile->pool = pool;
profile->user_agent = switch_core_sprintf(profile->pool, "FreeSWITCH-mod_sofia/%s", switch_version_full());
profile->name = switch_core_strdup(profile->pool, xprofilename);
switch_snprintf(url, sizeof(url), "sofia_reg_%s", xprofilename);
if (xprofiledomain) {
profile->domain_name = switch_core_strdup(profile->pool, xprofiledomain);
}
profile->dbname = switch_core_strdup(profile->pool, url);
switch_core_hash_init(&profile->chat_hash);
switch_core_hash_init(&profile->reg_nh_hash);
switch_core_hash_init(&profile->mwi_debounce_hash);
switch_thread_rwlock_create(&profile->rwlock, profile->pool);
switch_mutex_init(&profile->flag_mutex, SWITCH_MUTEX_NESTED, profile->pool);
profile->dtmf_duration = 100;
profile->rtp_digit_delay = 40;
profile->sip_force_expires = 0;
profile->sip_expires_max_deviation = 0;
profile->sip_expires_late_margin = 60;
2013-07-03 16:21:03 +00:00
profile->sip_subscription_max_deviation = 0;
profile->tls_ciphers = "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH";
profile->tls_version = SOFIA_TLS_VERSION_TLSv1;
profile->tls_version |= SOFIA_TLS_VERSION_TLSv1_1;
profile->tls_version |= SOFIA_TLS_VERSION_TLSv1_2;
profile->tls_timeout = 300;
profile->mflags = MFLAG_REFER | MFLAG_REGISTER;
profile->server_rport_level = 1;
profile->client_rport_level = 1;
2013-02-26 17:49:41 +00:00
profile->tls_cert_dir = SWITCH_GLOBAL_dirs.certs_dir;
sofia_set_pflag(profile, PFLAG_DISABLE_100REL);
sofia_set_pflag(profile, PFLAG_ENABLE_CHAT);
profile->auto_restart = 1;
2012-12-21 04:57:47 +00:00
sofia_set_media_flag(profile, SCMF_AUTOFIX_TIMING);
2013-11-07 22:48:00 +00:00
sofia_set_media_flag(profile, SCMF_RENEG_ON_REINVITE);
2012-12-22 17:51:03 +00:00
sofia_set_media_flag(profile, SCMF_RTP_AUTOFLUSH_DURING_BRIDGE);
profile->contact_user = SOFIA_DEFAULT_CONTACT_USER;
sofia_set_pflag(profile, PFLAG_PASS_CALLEE_ID);
sofia_set_pflag(profile, PFLAG_ALLOW_UPDATE);
sofia_set_pflag(profile, PFLAG_SEND_DISPLAY_UPDATE);
sofia_set_pflag(profile, PFLAG_MESSAGE_QUERY_ON_FIRST_REGISTER);
//sofia_set_pflag(profile, PFLAG_PRESENCE_ON_FIRST_REGISTER);
profile->shutdown_type = "false";
profile->local_network = "localnet.auto";
sofia_set_flag(profile, TFLAG_ENABLE_SOA);
sofia_set_pflag(profile, PFLAG_CID_IN_1XX);
2012-12-21 22:57:59 +00:00
profile->mndlb |= SM_NDLB_ALLOW_NONDUP_SDP;
profile->te = 101;
profile->ireg_seconds = IREG_SECONDS;
profile->paid_type = PAID_DEFAULT;
profile->bind_attempts = 2;
profile->bind_attempt_interval = 5;
profile->tls_verify_policy = TPTLS_VERIFY_NONE;
/* lib default */
profile->tls_verify_depth = 2;
profile->tls_verify_date = SWITCH_TRUE;
} else {
/* you could change profile->foo here if it was a minor change like context or dialplan ... */
profile->acl_count = 0;
profile->nat_acl_count = 0;
profile->reg_acl_count = 0;
profile->proxy_acl_count = 0;
sofia_set_pflag(profile, PFLAG_PASS_CALLEE_ID);
profile->ib_calls = 0;
profile->ob_calls = 0;
profile->ib_failed_calls = 0;
profile->ob_failed_calls = 0;
profile->shutdown_type = "false";
2012-10-30 19:22:31 +00:00
profile->rtpip_index = 0;
if (xprofiledomain) {
profile->domain_name = switch_core_strdup(profile->pool, xprofiledomain);
}
}
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");
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s [%s]\n", var, val);
if (!strcasecmp(var, "debug")) {
profile->debug = atoi(val);
2014-04-15 16:47:48 +00:00
} else if (!strcasecmp(var, "parse-invite-tel-params")) {
profile->parse_invite_tel_params = switch_true(val);
} else if (!strcasecmp(var, "keepalive-method")) {
if (!zstr(val)) {
if (!strcasecmp(val, "info")) {
profile->keepalive = KA_INFO;
} else {
profile->keepalive = KA_MESSAGE;
}
}
} else if (!strcasecmp(var, "bind-attempts") && val) {
int ba = atoi(val) - 1;
if (ba >= 0) {
profile->bind_attempts = ba;
}
} else if (!strcasecmp(var, "bind-attempt-interval") && val) {
int bai = atoi(val);
if (bai >= 0) {
profile->bind_attempt_interval = bai;
}
} else if (!strcasecmp(var, "shutdown-on-fail")) {
profile->shutdown_type = switch_core_strdup(profile->pool, val);
} else if (!strcasecmp(var, "sip-trace")) {
if (switch_true(val)) {
sofia_set_flag(profile, TFLAG_TPORT_LOG);
} else {
sofia_clear_flag(profile, TFLAG_TPORT_LOG);
}
} else if (!strcasecmp(var, "sip-capture")) {
if (switch_true(val)) {
sofia_set_flag(profile, TFLAG_CAPTURE);
nua_set_params(profile->nua, TPTAG_CAPT(mod_sofia_globals.capture_server), TAG_END());
} else {
sofia_clear_flag(profile, TFLAG_CAPTURE);
}
} else if (!strcasecmp(var, "socket-tcp-keepalive") && !zstr(val)) {
profile->socket_tcp_keepalive = atoi(val);
sofia_set_pflag(profile, PFLAG_SOCKET_TCP_KEEPALIVE);
} else if (!strcasecmp(var, "tcp-keepalive") && !zstr(val)) {
profile->tcp_keepalive = atoi(val);
sofia_set_pflag(profile, PFLAG_TCP_KEEPALIVE);
} else if (!strcasecmp(var, "tcp-pingpong") && !zstr(val)) {
profile->tcp_pingpong = atoi(val);
sofia_set_pflag(profile, PFLAG_TCP_PINGPONG);
} else if (!strcasecmp(var, "tcp-ping2pong") && !zstr(val)) {
profile->tcp_ping2pong = atoi(val);
sofia_set_pflag(profile, PFLAG_TCP_PING2PONG);
} else if ((!strcasecmp(var, "proxy-refer-replaces") || !strcasecmp(var, "proxy-refer")) && !zstr(val)) {
2014-06-05 18:49:50 +00:00
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_PROXY_REFER);
2014-06-05 18:49:50 +00:00
} else {
sofia_clear_pflag(profile, PFLAG_PROXY_REFER);
2014-06-05 18:49:50 +00:00
}
2014-01-22 21:13:10 +00:00
} else if (!strcasecmp(var, "sip-messages-respond-200-ok") && !zstr(val)) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_MESSAGES_RESPOND_200_OK);
} else {
sofia_clear_pflag(profile, PFLAG_MESSAGES_RESPOND_200_OK);
}
2014-03-04 21:41:34 +00:00
} else if (!strcasecmp(var, "sip-subscribe-respond-200-ok") && !zstr(val)) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_SUBSCRIBE_RESPOND_200_OK);
} else {
sofia_clear_pflag(profile, PFLAG_SUBSCRIBE_RESPOND_200_OK);
}
} else if (!strcasecmp(var, "odbc-dsn") && !zstr(val)) {
profile->odbc_dsn = switch_core_strdup(profile->pool, val);
} else if (!strcasecmp(var, "db-pre-trans-execute") && !zstr(val)) {
profile->pre_trans_execute = switch_core_strdup(profile->pool, val);
} else if (!strcasecmp(var, "db-post-trans-execute") && !zstr(val)) {
profile->post_trans_execute = switch_core_strdup(profile->pool, val);
} else if (!strcasecmp(var, "db-inner-pre-trans-execute") && !zstr(val)) {
profile->inner_pre_trans_execute = switch_core_strdup(profile->pool, val);
} else if (!strcasecmp(var, "db-inner-post-trans-execute") && !zstr(val)) {
profile->inner_post_trans_execute = switch_core_strdup(profile->pool, val);
} else if (!strcasecmp(var, "forward-unsolicited-mwi-notify")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_FORWARD_MWI_NOTIFY);
} else {
sofia_clear_pflag(profile, PFLAG_FORWARD_MWI_NOTIFY);
}
} else if (!strcasecmp(var, "NDLB-proxy-never-patch-reinvites")) {
if (switch_true(val)) {
profile->mndlb |= SM_NDLB_NEVER_PATCH_REINVITE;
} else {
profile->mndlb &= ~SM_NDLB_NEVER_PATCH_REINVITE;
}
} else if (!strcasecmp(var, "registration-thread-frequency")) {
profile->ireg_seconds = atoi(val);
if (profile->ireg_seconds < 0) {
profile->ireg_seconds = IREG_SECONDS;
}
} else if (!strcasecmp(var, "user-agent-string")) {
profile->user_agent = switch_core_strdup(profile->pool, val);
} else if (!strcasecmp(var, "auto-restart")) {
profile->auto_restart = switch_true(val);
} else if (!strcasecmp(var, "log-auth-failures")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_LOG_AUTH_FAIL);
} else {
sofia_clear_pflag(profile, PFLAG_LOG_AUTH_FAIL);
}
} else if (!strcasecmp(var, "confirm-blind-transfer")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_CONFIRM_BLIND_TRANSFER);
} else {
sofia_clear_pflag(profile, PFLAG_CONFIRM_BLIND_TRANSFER);
}
} else if (!strcasecmp(var, "allow-update")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_ALLOW_UPDATE);
} else {
sofia_clear_pflag(profile, PFLAG_ALLOW_UPDATE);
}
} else if (!strcasecmp(var, "send-display-update")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_SEND_DISPLAY_UPDATE);
} else {
sofia_clear_pflag(profile, PFLAG_SEND_DISPLAY_UPDATE);
}
2012-05-21 18:55:50 +00:00
} else if (!strcasecmp(var, "mwi-use-reg-callid")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_MWI_USE_REG_CALLID);
} else {
sofia_clear_pflag(profile, PFLAG_MWI_USE_REG_CALLID);
}
} else if (!strcasecmp(var, "tcp-unreg-on-socket-close")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_TCP_UNREG_ON_SOCKET_CLOSE);
} else {
sofia_clear_pflag(profile, PFLAG_TCP_UNREG_ON_SOCKET_CLOSE);
}
} else if (!strcasecmp(var, "tcp-always-nat")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_TCP_ALWAYS_NAT);
} else {
sofia_clear_pflag(profile, PFLAG_TCP_ALWAYS_NAT);
}
} else if (!strcasecmp(var, "tls-always-nat")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_TCP_ALWAYS_NAT);
} else {
sofia_clear_pflag(profile, PFLAG_TCP_ALWAYS_NAT);
}
2011-10-22 14:40:59 +00:00
} else if (!strcasecmp(var, "presence-proto-lookup")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_PRESENCE_MAP);
} else {
sofia_clear_pflag(profile, PFLAG_PRESENCE_MAP);
}
} else if (!strcasecmp(var, "profile-standby")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_STANDBY);
} else {
sofia_clear_pflag(profile, PFLAG_STANDBY);
}
} else if (!strcasecmp(var, "liberal-dtmf")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_LIBERAL_DTMF);
} else {
sofia_clear_pflag(profile, PFLAG_LIBERAL_DTMF);
}
2012-04-20 13:03:03 +00:00
} else if (!strcasecmp(var, "rtp-digit-delay")) {
int delay = atoi(val);
if (delay < 0) {
delay = 0;
}
profile->rtp_digit_delay = (uint32_t) delay;
2010-10-06 20:17:48 +00:00
} else if (!strcasecmp(var, "watchdog-enabled")) {
profile->watchdog_enabled = switch_true(val);
} else if (!strcasecmp(var, "watchdog-step-timeout")) {
profile->step_timeout = atoi(val);
2010-10-06 20:17:48 +00:00
} else if (!strcasecmp(var, "watchdog-event-timeout")) {
profile->event_timeout = atoi(val);
2010-08-18 19:58:14 +00:00
} else if (!strcasecmp(var, "in-dialog-chat")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_IN_DIALOG_CHAT);
} else {
sofia_clear_pflag(profile, PFLAG_IN_DIALOG_CHAT);
}
} else if (!strcasecmp(var, "enable-chat")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_ENABLE_CHAT);
} else {
sofia_clear_pflag(profile, PFLAG_ENABLE_CHAT);
}
2012-08-29 20:34:17 +00:00
} else if (!strcasecmp(var, "fire-message-events")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_FIRE_MESSAGE_EVENTS);
} else {
sofia_clear_pflag(profile, PFLAG_FIRE_MESSAGE_EVENTS);
}
2010-05-27 01:12:54 +00:00
} else if (!strcasecmp(var, "t38-passthru")) {
if (switch_true(val)) {
2013-06-26 15:47:40 +00:00
sofia_set_pflag(profile, PFLAG_T38_PASSTHRU);
2010-05-27 01:12:54 +00:00
} else {
2013-06-26 15:47:40 +00:00
sofia_clear_pflag(profile, PFLAG_T38_PASSTHRU);
2010-05-27 01:12:54 +00:00
}
} else if (!strcasecmp(var, "presence-disable-early")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_PRESENCE_DISABLE_EARLY);
} else {
sofia_clear_pflag(profile, PFLAG_PRESENCE_DISABLE_EARLY);
}
} else if (!strcasecmp(var, "ignore-183nosdp")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_IGNORE_183NOSDP);
} else {
sofia_clear_pflag(profile, PFLAG_IGNORE_183NOSDP);
}
} else if (!strcasecmp(var, "renegotiate-codec-on-hold")) {
if (switch_true(val)) {
2013-06-11 14:31:16 +00:00
sofia_set_media_flag(profile, SCMF_RENEG_ON_HOLD);
} else {
2013-06-11 14:31:16 +00:00
sofia_clear_media_flag(profile, SCMF_RENEG_ON_HOLD);
}
} else if (!strcasecmp(var, "renegotiate-codec-on-reinvite")) {
if (switch_true(val)) {
2013-06-11 14:31:16 +00:00
sofia_set_media_flag(profile, SCMF_RENEG_ON_REINVITE);
} else {
2013-06-11 14:31:16 +00:00
sofia_clear_media_flag(profile, SCMF_RENEG_ON_REINVITE);
}
} else if (!strcasecmp(var, "presence-probe-on-register")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_PRESENCE_PROBE_ON_REGISTER);
} else {
sofia_clear_pflag(profile, PFLAG_PRESENCE_PROBE_ON_REGISTER);
}
} else if (!strcasecmp(var, "send-presence-on-register")) {
if (switch_true(val) || !strcasecmp(val, "all")) {
sofia_set_pflag(profile, PFLAG_PRESENCE_ON_REGISTER);
} else if (!strcasecmp(val, "first-only")) {
sofia_clear_pflag(profile, PFLAG_PRESENCE_ON_REGISTER);
sofia_set_pflag(profile, PFLAG_PRESENCE_ON_FIRST_REGISTER);
} else {
sofia_clear_pflag(profile, PFLAG_PRESENCE_ON_REGISTER);
sofia_clear_pflag(profile, PFLAG_PRESENCE_ON_FIRST_REGISTER);
}
} else if (!strcasecmp(var, "cid-in-1xx")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_CID_IN_1XX);
} else {
sofia_clear_pflag(profile, PFLAG_CID_IN_1XX);
}
} else if (!strcasecmp(var, "disable-hold")) {
if (switch_true(val)) {
2012-12-21 04:57:47 +00:00
sofia_set_media_flag(profile, SCMF_DISABLE_HOLD);
} else {
2012-12-21 04:57:47 +00:00
sofia_clear_media_flag(profile, SCMF_DISABLE_HOLD);
}
} else if (!strcasecmp(var, "auto-jitterbuffer-msec")) {
int msec = atoi(val);
if (msec > 19) {
profile->jb_msec = 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, "NDLB-force-rport")) {
if (val && !strcasecmp(val, "safe")) {
profile->server_rport_level = 3;
profile->client_rport_level = 1;
} else if (val && !strcasecmp(val, "disabled")) {
profile->server_rport_level = 0;
profile->client_rport_level = 0;
} else if (val && !strcasecmp(val, "client-only")) {
profile->client_rport_level = 1;
} else if (val && !strcasecmp(val, "server-only")) {
profile->client_rport_level = 0;
2011-07-14 14:42:33 +00:00
profile->server_rport_level = 1;
} else if (switch_true(val)) {
profile->server_rport_level = 2;
profile->client_rport_level = 1;
}
} else if (!strcasecmp(var, "auto-rtp-bugs")) {
2012-12-21 04:57:47 +00:00
switch_core_media_parse_rtp_bugs(&profile->auto_rtp_bugs, val);
} else if (!strcasecmp(var, "manual-rtp-bugs")) {
2012-12-21 04:57:47 +00:00
switch_core_media_parse_rtp_bugs(&profile->manual_rtp_bugs, val);
2012-10-16 22:42:54 +00:00
} else if (!strcasecmp(var, "manual-video-rtp-bugs")) {
2012-12-21 04:57:47 +00:00
switch_core_media_parse_rtp_bugs(&profile->manual_video_rtp_bugs, val);
} else if (!strcasecmp(var, "dbname")) {
profile->dbname = switch_core_strdup(profile->pool, val);
} else if (!strcasecmp(var, "presence-hosts")) {
profile->presence_hosts = switch_core_strdup(profile->pool, val);
} else if (!strcasecmp(var, "caller-id-type")) {
profile->cid_type = sofia_cid_name2type(val);
} else if (!strcasecmp(var, "record-template")) {
profile->record_template = switch_core_strdup(profile->pool, val);
} else if (!strcasecmp(var, "record-path")) {
profile->record_path = switch_core_strdup(profile->pool, val);
} else if ((!strcasecmp(var, "inbound-no-media") || !strcasecmp(var, "inbound-bypass-media"))) {
if (switch_true(val)) {
sofia_set_flag(profile, TFLAG_INB_NOMEDIA);
} else {
sofia_clear_flag(profile, TFLAG_INB_NOMEDIA);
}
} else if (!strcasecmp(var, "inbound-late-negotiation")) {
if (switch_true(val)) {
sofia_set_flag(profile, TFLAG_LATE_NEGOTIATION);
} else {
sofia_clear_flag(profile, TFLAG_LATE_NEGOTIATION);
}
} else if (!strcasecmp(var, "rtp-notimer-during-bridge")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_RTP_NOTIMER_DURING_BRIDGE);
} else {
sofia_clear_pflag(profile, PFLAG_RTP_NOTIMER_DURING_BRIDGE);
}
} else if (!strcasecmp(var, "manual-redirect")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_MANUAL_REDIRECT);
} else {
sofia_clear_pflag(profile, PFLAG_MANUAL_REDIRECT);
}
} else if (!strcasecmp(var, "inbound-proxy-media")) {
if (switch_true(val)) {
sofia_set_flag(profile, TFLAG_PROXY_MEDIA);
} else {
sofia_clear_flag(profile, TFLAG_PROXY_MEDIA);
}
} else if (!strcasecmp(var, "inbound-zrtp-passthru")) {
if (switch_true(val)) {
sofia_set_flag(profile, TFLAG_ZRTP_PASSTHRU);
} else {
sofia_clear_flag(profile, TFLAG_ZRTP_PASSTHRU);
}
} else if (!strcasecmp(var, "force-subscription-expires")) {
int tmp = atoi(val);
if (tmp > 0) {
profile->force_subscription_expires = tmp;
}
} else if (!strcasecmp(var, "force-publish-expires")) {
int tmp = atoi(val);
if (tmp > 0) {
profile->force_publish_expires = tmp;
}
} else if (!strcasecmp(var, "send-message-query-on-register")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_MESSAGE_QUERY_ON_REGISTER);
} else if (!strcasecmp(val, "first-only")) {
sofia_clear_pflag(profile, PFLAG_MESSAGE_QUERY_ON_REGISTER);
sofia_set_pflag(profile, PFLAG_MESSAGE_QUERY_ON_FIRST_REGISTER);
} else {
sofia_clear_pflag(profile, PFLAG_MESSAGE_QUERY_ON_REGISTER);
sofia_clear_pflag(profile, PFLAG_MESSAGE_QUERY_ON_FIRST_REGISTER);
}
} else if (!strcasecmp(var, "inbound-reg-in-new-thread") && val) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_THREAD_PER_REG);
} else {
sofia_clear_pflag(profile, PFLAG_THREAD_PER_REG);
}
} else if (!strcasecmp(var, "inbound-use-callid-as-uuid")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_CALLID_AS_UUID);
} else {
sofia_clear_pflag(profile, PFLAG_CALLID_AS_UUID);
}
} else if (!strcasecmp(var, "outbound-use-uuid-as-callid")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_UUID_AS_CALLID);
} else {
sofia_clear_pflag(profile, PFLAG_UUID_AS_CALLID);
}
2010-06-30 15:35:03 +00:00
} else if (!strcasecmp(var, "track-calls")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_TRACK_CALLS);
}
} else if (!strcasecmp(var, "NDLB-received-in-nat-reg-contact")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_RECIEVED_IN_NAT_REG_CONTACT);
} else {
sofia_clear_pflag(profile, PFLAG_RECIEVED_IN_NAT_REG_CONTACT);
}
} else if (!strcasecmp(var, "aggressive-nat-detection")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_AGGRESSIVE_NAT_DETECTION);
} else {
sofia_clear_pflag(profile, PFLAG_AGGRESSIVE_NAT_DETECTION);
}
} else if (!strcasecmp(var, "disable-rtp-auto-adjust")) {
if (switch_true(val)) {
2012-12-21 20:22:25 +00:00
sofia_set_media_flag(profile, SCMF_DISABLE_RTP_AUTOADJ);
} else {
2012-12-21 20:22:25 +00:00
sofia_clear_media_flag(profile, SCMF_DISABLE_RTP_AUTOADJ);
}
} else if (!strcasecmp(var, "NDLB-support-asterisk-missing-srtp-auth")) {
if (switch_true(val)) {
profile->mndlb |= SM_NDLB_DISABLE_SRTP_AUTH;
} else {
profile->mndlb &= ~SM_NDLB_DISABLE_SRTP_AUTH;
}
} else if (!strcasecmp(var, "user-agent-filter")) {
profile->user_agent_filter = switch_core_strdup(profile->pool, val);
} else if (!strcasecmp(var, "max-registrations-per-extension")) {
profile->max_registrations_perext = atoi(val);
} else if (!strcasecmp(var, "rfc2833-pt")) {
profile->te = (switch_payload_t) atoi(val);
2012-12-22 03:30:14 +00:00
} else if (!strcasecmp(var, "cng-pt") && !sofia_test_media_flag(profile, SCMF_SUPPRESS_CNG)) {
profile->cng_pt = (switch_payload_t) atoi(val);
} else if (!strcasecmp(var, "sip-port")) {
2011-06-27 15:15:03 +00:00
if (!strcasecmp(val, "auto")) {
sofia_set_pflag(profile, PFLAG_AUTO_ASSIGN_PORT);
} else {
profile->sip_port = (switch_port_t) atoi(val);
2012-12-10 19:52:25 +00:00
if (!profile->extsipport) profile->extsipport = profile->sip_port;
2011-06-27 15:15:03 +00:00
}
} else if (!strcasecmp(var, "vad")) {
if (!strcasecmp(val, "in")) {
2012-12-21 20:22:25 +00:00
profile->vflags |= VAD_IN;
} else if (!strcasecmp(val, "out")) {
2012-12-21 20:22:25 +00:00
profile->vflags |= VAD_OUT;
} else if (!strcasecmp(val, "both")) {
2012-12-21 20:22:25 +00:00
profile->vflags |= VAD_OUT | VAD_IN;
} else if (strcasecmp(val, "none")) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid option %s for VAD\n", val);
}
} else if (!strcasecmp(var, "ext-rtp-ip")) {
if (!zstr(val)) {
char *ip = mod_sofia_globals.guess_ip;
if (!strcmp(val, "0.0.0.0")) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid IP 0.0.0.0 replaced with %s\n",
mod_sofia_globals.guess_ip);
} else if (!strcasecmp(val, "auto-nat")) {
ip = NULL;
} else {
ip = strcasecmp(val, "auto") ? val : mod_sofia_globals.guess_ip;
sofia_clear_pflag(profile, PFLAG_AUTO_NAT);
}
if (ip) {
if (!strncasecmp(ip, "autonat:", 8)) {
profile->extrtpip = switch_core_strdup(profile->pool, ip + 8);
2010-06-14 18:42:06 +00:00
if (zstr(profile->extsipip)) {
profile->extsipip = switch_core_strdup(profile->pool, profile->extrtpip);
}
sofia_set_pflag(profile, PFLAG_AUTO_NAT);
} else {
profile->extrtpip = switch_core_strdup(profile->pool, ip);
}
}
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid ext-rtp-ip\n");
}
} else if (!strcasecmp(var, "rtp-ip")) {
char *ip = mod_sofia_globals.guess_ip;
2013-08-16 21:16:28 +00:00
char buf[64];
if (!strcmp(val, "0.0.0.0")) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid IP 0.0.0.0 replaced with %s\n", mod_sofia_globals.guess_ip);
2013-08-16 21:16:28 +00:00
} else if (!strncasecmp(val, "interface:", 10)) {
char *ifname = val+10;
int family = AF_UNSPEC;
if (!strncasecmp(ifname, "auto/", 5)) { ifname += 5; family = AF_UNSPEC; }
if (!strncasecmp(ifname, "ipv4/", 5)) { ifname += 5; family = AF_INET; }
if (!strncasecmp(ifname, "ipv6/", 5)) { ifname += 5; family = AF_INET6; }
if (switch_find_interface_ip(buf, sizeof(buf), NULL, ifname, family) == SWITCH_STATUS_SUCCESS) {
ip = buf;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Using %s IP for interface %s for rtp-ip\n", ip, val+10);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown IP for interface %s for rtp-ip\n", val+10);
}
} else {
ip = strcasecmp(val, "auto") ? val : mod_sofia_globals.guess_ip;
}
if (profile->rtpip_index < MAX_RTPIP) {
profile->rtpip[profile->rtpip_index++] = switch_core_strdup(profile->pool, ip);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Max IPs configured for profile %s.\n", profile->name);
}
} else if (!strcasecmp(var, "sip-ip")) {
char *ip = mod_sofia_globals.guess_ip;
2013-08-16 21:16:28 +00:00
char buf[64];
if (!strcmp(val, "0.0.0.0")) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid IP 0.0.0.0 replaced with %s\n", mod_sofia_globals.guess_ip);
2013-08-16 21:16:28 +00:00
} else if (!strncasecmp(val, "interface:", 10)) {
char *ifname = val+10;
int family = AF_UNSPEC;
if (!strncasecmp(ifname, "auto/", 5)) { ifname += 5; family = AF_UNSPEC; }
if (!strncasecmp(ifname, "ipv4/", 5)) { ifname += 5; family = AF_INET; }
if (!strncasecmp(ifname, "ipv6/", 5)) { ifname += 5; family = AF_INET6; }
if (switch_find_interface_ip(buf, sizeof(buf), NULL, ifname, family) == SWITCH_STATUS_SUCCESS) {
ip = buf;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Using %s IP for interface %s for sip-ip\n", ip, val+10);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown IP for interface %s for sip-ip\n", val+10);
}
} else {
ip = strcasecmp(val, "auto") ? val : mod_sofia_globals.guess_ip;
}
profile->sipip = switch_core_strdup(profile->pool, ip);
2012-11-21 16:32:41 +00:00
} else if (!strcasecmp(var, "ext-sip-port") && val) {
int tmp = atoi(val);
if (tmp > 0) profile->extsipport = (switch_port_t)tmp;
} else if (!strcasecmp(var, "ext-sip-ip")) {
if (!zstr(val)) {
char *ip = mod_sofia_globals.guess_ip;
char stun_ip[50] = "";
char *myip = stun_ip;
switch_copy_string(stun_ip, ip, sizeof(stun_ip));
if (!strcasecmp(val, "0.0.0.0")) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid IP 0.0.0.0 replaced with %s\n",
mod_sofia_globals.guess_ip);
} else if (!strcasecmp(val, "auto-nat")) {
ip = NULL;
} else if (strcasecmp(val, "auto")) {
2012-12-22 03:30:14 +00:00
if (sofia_glue_ext_address_lookup(profile, &myip, &profile->extsipport, val, profile->pool) == SWITCH_STATUS_SUCCESS) {
ip = myip;
sofia_clear_pflag(profile, PFLAG_AUTO_NAT);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to get external ip.\n");
}
}
if (ip) {
if (!strncasecmp(ip, "autonat:", 8)) {
profile->extsipip = switch_core_strdup(profile->pool, ip + 8);
sofia_set_pflag(profile, PFLAG_AUTO_NAT);
} else {
profile->extsipip = switch_core_strdup(profile->pool, ip);
}
}
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid ext-sip-ip\n");
}
} else if (!strcasecmp(var, "local-network-acl")) {
if (!strcasecmp(var, "none")) {
profile->local_network = NULL;
} else {
profile->local_network = switch_core_strdup(profile->pool, val);
}
} else if (!strcasecmp(var, "force-register-domain")) {
profile->reg_domain = switch_core_strdup(profile->pool, val);
} else if (!strcasecmp(var, "force-register-db-domain")) {
profile->reg_db_domain = switch_core_strdup(profile->pool, val);
2010-08-27 23:36:28 +00:00
} else if (!strcasecmp(var, "force-subscription-domain")) {
profile->sub_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")) {
profile->sipdomain = switch_core_strdup(profile->pool, val);
} else if (!strcasecmp(var, "rtp-timer-name")) {
profile->timer_name = switch_core_strdup(profile->pool, val);
} else if (!strcasecmp(var, "hold-music")) {
profile->hold_music = switch_core_strdup(profile->pool, val);
} else if (!strcasecmp(var, "outbound-proxy")) {
profile->outbound_proxy = switch_core_strdup(profile->pool, val);
} else if (!strcasecmp(var, "rtcp-audio-interval-msec")) {
profile->rtcp_audio_interval_msec = switch_core_strdup(profile->pool, val);
} else if (!strcasecmp(var, "rtcp-video-interval-msec")) {
profile->rtcp_video_interval_msec = 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")) {
if (switch_true(val)) {
profile->mflags &= ~MFLAG_REFER;
} else {
profile->mflags |= MFLAG_REFER;
}
} else if (!strcasecmp(var, "disable-register")) {
if (switch_true(val)) {
profile->mflags &= ~MFLAG_REGISTER;
} else {
profile->mflags |= MFLAG_REGISTER;
}
} else if (!strcasecmp(var, "media-option")) {
if (!strcasecmp(val, "resume-media-on-hold")) {
profile->media_options |= MEDIA_OPT_MEDIA_ON_HOLD;
} else if (!strcasecmp(val, "bypass-media-after-att-xfer")) {
profile->media_options |= MEDIA_OPT_BYPASS_AFTER_ATT_XFER;
} else if (!strcasecmp(val, "bypass-media-after-hold")) {
if (profile->media_options & MEDIA_OPT_MEDIA_ON_HOLD) {
profile->media_options |= MEDIA_OPT_BYPASS_AFTER_HOLD;
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
"bypass-media-after-hold can be set only with resume-media-on-hold media-option\n");
}
} else if (!strcasecmp(val, "none")) {
profile->media_options = 0;
2014-02-05 02:15:08 +00:00
}
2012-06-04 19:16:30 +00:00
} else if (!strcasecmp(var, "pnp-provision-url")) {
profile->pnp_prov_url = switch_core_strdup(profile->pool, val);
} else if (!strcasecmp(var, "manage-presence")) {
if (!strcasecmp(val, "passive")) {
profile->pres_type = PRES_TYPE_PASSIVE;
2012-06-04 19:16:30 +00:00
} else if (!strcasecmp(val, "pnp")) {
profile->pres_type = PRES_TYPE_PNP;
} else if (switch_true(val)) {
profile->pres_type = PRES_TYPE_FULL;
} else {
profile->pres_type = 0;
}
2012-04-13 16:18:09 +00:00
} else if (!strcasecmp(var, "presence-hold-state")) {
if (!strcasecmp(val, "confirmed")) {
profile->pres_held_type = PRES_HELD_CONFIRMED;
} else if (!strcasecmp(val, "terminated")) {
profile->pres_held_type = PRES_HELD_TERMINATED;
} else {
profile->pres_held_type = 0;
2012-04-13 16:18:09 +00:00
}
2011-12-15 18:20:27 +00:00
} else if (!strcasecmp(var, "presence-privacy")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_PRESENCE_PRIVACY);
} else {
sofia_clear_pflag(profile, PFLAG_PRESENCE_PRIVACY);
2011-12-15 18:20:27 +00:00
}
} else if (!strcasecmp(var, "manage-shared-appearance")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE);
profile->pres_type = PRES_TYPE_FULL;
sofia_set_pflag(profile, PFLAG_MULTIREG);
} else if (!strcasecmp(val, "sylantro")) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
"Sylantro support has been removed.\n"
"It was incomplete anyway, and we fully support the broadsoft SCA shared line spec.");
sofia_clear_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE);
} else {
sofia_clear_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE);
}
} else if (!strcasecmp(var, "disable-srv")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_DISABLE_SRV);
} else {
sofia_clear_pflag(profile, PFLAG_DISABLE_SRV);
}
} else if (!strcasecmp(var, "disable-naptr")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_DISABLE_NAPTR);
} else {
sofia_clear_pflag(profile, PFLAG_DISABLE_NAPTR);
}
2011-08-19 21:34:39 +00:00
} else if (!strcasecmp(var, "disable-srv503")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_DISABLE_SRV503);
} else {
sofia_clear_pflag(profile, PFLAG_DISABLE_SRV503);
}
} else if (!strcasecmp(var, "unregister-on-options-fail")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_UNREG_OPTIONS_FAIL);
} else {
sofia_clear_pflag(profile, PFLAG_UNREG_OPTIONS_FAIL);
}
} else if (!strcasecmp(var, "require-secure-rtp")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_SECURE);
} else {
sofia_clear_pflag(profile, PFLAG_SECURE);
}
} else if (!strcasecmp(var, "multiple-registrations")) {
if (!strcasecmp(val, "call-id")) {
sofia_set_pflag(profile, PFLAG_MULTIREG);
} else if (!strcasecmp(val, "contact") || switch_true(val)) {
sofia_set_pflag(profile, PFLAG_MULTIREG);
sofia_set_pflag(profile, PFLAG_MULTIREG_CONTACT);
} else if (!switch_true(val)) {
sofia_clear_pflag(profile, PFLAG_MULTIREG);
sofia_clear_pflag(profile, PFLAG_MULTIREG_CONTACT);
}
} else if (!strcasecmp(var, "supress-cng") || !strcasecmp(var, "suppress-cng")) {
if (switch_true(val)) {
2012-12-22 03:30:14 +00:00
sofia_set_media_flag(profile, SCMF_SUPPRESS_CNG);
profile->cng_pt = 0;
} else {
sofia_clear_media_flag(profile, SCMF_SUPPRESS_CNG);
}
} else if (!strcasecmp(var, "NDLB-broken-auth-hash")) {
if (switch_true(val)) {
profile->ndlb |= PFLAG_NDLB_BROKEN_AUTH_HASH;
} else {
profile->ndlb &= ~PFLAG_NDLB_BROKEN_AUTH_HASH;
}
} else if (!strcasecmp(var, "NDLB-sendrecv-in-session")) {
if (switch_true(val)) {
2012-12-21 22:57:59 +00:00
profile->mndlb |= SM_NDLB_SENDRECV_IN_SESSION;
} else {
2012-12-21 22:57:59 +00:00
profile->mndlb &= ~SM_NDLB_SENDRECV_IN_SESSION;
}
} else if (!strcasecmp(var, "NDLB-allow-bad-iananame")) {
if (switch_true(val)) {
2012-12-21 22:57:59 +00:00
profile->mndlb |= SM_NDLB_ALLOW_BAD_IANANAME;
} else {
2012-12-21 22:57:59 +00:00
profile->mndlb &= ~SM_NDLB_ALLOW_BAD_IANANAME;
}
} else if (!strcasecmp(var, "NDLB-expires-in-register-response")) {
if (switch_true(val)) {
profile->ndlb |= PFLAG_NDLB_EXPIRES_IN_REGISTER_RESPONSE;
} else {
profile->ndlb &= ~PFLAG_NDLB_EXPIRES_IN_REGISTER_RESPONSE;
}
2012-09-14 15:29:25 +00:00
} else if (!strcasecmp(var, "NDLB-allow-crypto-in-avp")) {
if (switch_true(val)) {
2012-12-21 22:57:59 +00:00
profile->mndlb |= SM_NDLB_ALLOW_CRYPTO_IN_AVP;
2012-09-14 15:29:25 +00:00
} else {
2012-12-21 22:57:59 +00:00
profile->mndlb &= ~SM_NDLB_ALLOW_CRYPTO_IN_AVP;
2012-09-14 15:29:25 +00:00
}
} else if (!strcasecmp(var, "NDLB-allow-nondup-sdp")) {
if (switch_true(val)) {
2012-12-21 22:57:59 +00:00
profile->mndlb |= SM_NDLB_ALLOW_NONDUP_SDP;
} else {
2012-12-21 22:57:59 +00:00
profile->mndlb &= ~SM_NDLB_ALLOW_NONDUP_SDP;
}
} else if (!strcasecmp(var, "pass-rfc2833")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_PASS_RFC2833);
} else {
sofia_clear_pflag(profile, PFLAG_PASS_RFC2833);
}
} else if (!strcasecmp(var, "rtp-autofix-timing")) {
if (switch_true(val)) {
2012-12-21 04:57:47 +00:00
sofia_set_media_flag(profile, SCMF_AUTOFIX_TIMING);
} else {
2012-12-21 04:57:47 +00:00
sofia_clear_media_flag(profile, SCMF_AUTOFIX_TIMING);
}
} else if (!strcasecmp(var, "contact-user")) {
profile->contact_user = switch_core_strdup(profile->pool, val);
} else if (!strcasecmp(var, "nat-options-ping")) {
2013-07-03 16:21:47 +00:00
if (!strcasecmp(val, "udp-only")) {
sofia_set_pflag(profile, PFLAG_UDP_NAT_OPTIONS_PING);
} else if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_NAT_OPTIONS_PING);
} else {
sofia_clear_pflag(profile, PFLAG_NAT_OPTIONS_PING);
2013-07-03 16:21:47 +00:00
sofia_clear_pflag(profile, PFLAG_UDP_NAT_OPTIONS_PING);
}
} else if (!strcasecmp(var, "all-reg-options-ping")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_ALL_REG_OPTIONS_PING);
} else {
sofia_clear_pflag(profile, PFLAG_ALL_REG_OPTIONS_PING);
}
} else if (!strcasecmp(var, "inbound-codec-negotiation")) {
if (!strcasecmp(val, "greedy")) {
2012-12-21 04:57:47 +00:00
sofia_set_media_flag(profile, SCMF_CODEC_GREEDY);
} else if (!strcasecmp(val, "scrooge")) {
2012-12-21 04:57:47 +00:00
sofia_set_media_flag(profile, SCMF_CODEC_GREEDY);
sofia_set_media_flag(profile, SCMF_CODEC_SCROOGE);
} else {
2012-12-21 04:57:47 +00:00
sofia_clear_media_flag(profile, SCMF_CODEC_SCROOGE);
sofia_clear_media_flag(profile, SCMF_CODEC_GREEDY);
}
} else if (!strcasecmp(var, "disable-transcoding")) {
if (switch_true(val)) {
2012-12-21 04:57:47 +00:00
sofia_set_media_flag(profile, SCMF_DISABLE_TRANSCODING);
2012-12-20 04:42:03 +00:00
} else {
2012-12-21 04:57:47 +00:00
sofia_clear_media_flag(profile, SCMF_DISABLE_TRANSCODING);
}
} else if (!strcasecmp(var, "rtp-rewrite-timestamps")) {
if (switch_true(val)) {
2012-12-22 03:30:14 +00:00
sofia_set_media_flag(profile, SCMF_REWRITE_TIMESTAMPS);
} else {
sofia_clear_media_flag(profile, SCMF_REWRITE_TIMESTAMPS);
}
} else if (!strcasecmp(var, "auth-calls")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_AUTH_CALLS);
} else {
sofia_clear_pflag(profile, PFLAG_AUTH_CALLS);
}
} else if (!strcasecmp(var, "auth-messages")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_AUTH_MESSAGES);
} else {
sofia_clear_pflag(profile, PFLAG_AUTH_MESSAGES);
}
} else if (!strcasecmp(var, "auth-subscriptions")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_AUTH_SUBSCRIPTIONS);
} else {
sofia_clear_pflag(profile, PFLAG_AUTH_SUBSCRIPTIONS);
}
} else if (!strcasecmp(var, "extended-info-parsing")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_EXTENDED_INFO_PARSING);
} else {
sofia_clear_pflag(profile, PFLAG_EXTENDED_INFO_PARSING);
}
} else if (!strcasecmp(var, "nonce-ttl")) {
profile->nonce_ttl = atoi(val);
} else if (!strcasecmp(var, "accept-blind-reg")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_BLIND_REG);
} else {
sofia_clear_pflag(profile, PFLAG_BLIND_REG);
}
} else if (!strcasecmp(var, "3pcc-reinvite-bridged-on-ack")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_3PCC_REINVITE_BRIDGED_ON_ACK);
} else {
sofia_clear_pflag(profile, PFLAG_3PCC_REINVITE_BRIDGED_ON_ACK);
}
} else if (!strcasecmp(var, "enable-3pcc")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_3PCC);
} else if (!strcasecmp(val, "proxy")) {
sofia_set_pflag(profile, PFLAG_3PCC_PROXY);
}
} else if (!strcasecmp(var, "accept-blind-auth")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_BLIND_AUTH);
} else {
sofia_clear_pflag(profile, PFLAG_BLIND_AUTH);
}
} else if (!strcasecmp(var, "auth-all-packets")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_AUTH_ALL);
} else {
sofia_clear_pflag(profile, PFLAG_AUTH_ALL);
}
} else if (!strcasecmp(var, "full-id-in-dialplan")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_FULL_ID);
} else {
sofia_clear_pflag(profile, PFLAG_FULL_ID);
}
} else if (!strcasecmp(var, "inbound-reg-force-matching-username")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_CHECKUSER);
} else {
sofia_clear_pflag(profile, PFLAG_CHECKUSER);
}
} else if (!strcasecmp(var, "enable-timer")) {
if (!switch_true(val)) {
sofia_set_pflag(profile, PFLAG_DISABLE_TIMER);
} else {
sofia_clear_pflag(profile, PFLAG_DISABLE_TIMER);
}
} else if (!strcasecmp(var, "enable-rfc-5626")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_ENABLE_RFC5626);
} else {
sofia_clear_pflag(profile, PFLAG_ENABLE_RFC5626);
}
} else if (!strcasecmp(var, "minimum-session-expires")) {
profile->minimum_session_expires = atoi(val);
/* per RFC 4028: minimum_session_expires must be > 90 */
if (profile->minimum_session_expires < 90) {
profile->minimum_session_expires = 90;
}
} else if (!strcasecmp(var, "enable-100rel")) {
if (switch_true(val)) {
sofia_clear_pflag(profile, PFLAG_DISABLE_100REL);
} else {
sofia_set_pflag(profile, PFLAG_DISABLE_100REL);
}
} else if (!strcasecmp(var, "enable-compact-headers")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_SIPCOMPACT);
} else {
sofia_clear_pflag(profile, PFLAG_SIPCOMPACT);
}
} else if (!strcasecmp(var, "pass-callee-id")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_PASS_CALLEE_ID);
} else {
sofia_clear_pflag(profile, PFLAG_PASS_CALLEE_ID);
}
} else if (!strcasecmp(var, "enable-soa")) {
if (switch_true(val)) {
sofia_set_flag(profile, TFLAG_ENABLE_SOA);
} else {
sofia_clear_flag(profile, TFLAG_ENABLE_SOA);
}
} else if (!strcasecmp(var, "parse-all-invite-headers")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_PARSE_ALL_INVITE_HEADERS);
} else {
sofia_clear_pflag(profile, PFLAG_PARSE_ALL_INVITE_HEADERS);
}
} else if (!strcasecmp(var, "bitpacking")) {
if (!strcasecmp(val, "aal2")) {
profile->codec_flags = SWITCH_CODEC_FLAG_AAL2;
} else {
profile->codec_flags = 0;
}
} else if (!strcasecmp(var, "username")) {
2012-12-21 22:57:59 +00:00
profile->sdp_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-nat-acl")) {
if (!strcasecmp(val,"none")) {
profile->nat_acl_count = 0;
} else if (profile->nat_acl_count < SOFIA_MAX_ACL) {
if (!profile->extsipip && profile->sipip && switch_check_network_list_ip(profile->sipip, val)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Not adding acl %s because it's the local network\n", val);
} else {
profile->nat_acl[profile->nat_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-inbound-acl")) {
if (!strcasecmp(val,"none")) {
profile->acl_count = 0;
} else if (profile->acl_count < SOFIA_MAX_ACL) {
char *list, *pass = NULL, *fail = NULL;
list = switch_core_strdup(profile->pool, val);
if ((pass = strchr(list, ':'))) {
*pass++ = '\0';
if ((fail = strchr(pass, ':'))) {
*fail++ = '\0';
}
if (zstr(pass)) pass = NULL;
if (zstr(fail)) fail = NULL;
profile->acl_pass_context[profile->acl_count] = pass;
profile->acl_fail_context[profile->acl_count] = fail;
}
profile->acl[profile->acl_count++] = list;
} 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-proxy-acl")) {
if (!strcasecmp(val,"none")) {
profile->proxy_acl_count = 0;
} else if (profile->proxy_acl_count < SOFIA_MAX_ACL) {
profile->proxy_acl[profile->proxy_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 (!strcasecmp(val,"none")) {
profile->reg_acl_count = 0;
} else 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);
}
2013-01-10 04:31:25 +00:00
} else if (!strcasecmp(var, "apply-candidate-acl")) {
if (!strcasecmp(val,"none")) {
profile->cand_acl_count = 0;
} else if (profile->cand_acl_count < SWITCH_MAX_CAND_ACL) {
profile->cand_acl[profile->cand_acl_count++] = switch_core_strdup(profile->pool, val);
2013-01-10 04:31:25 +00:00
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Max acl records of %d reached\n", SWITCH_MAX_CAND_ACL);
}
} else if (!strcasecmp(var, "alias")) {
sip_alias_node_t *node;
2011-09-27 20:39:56 +00:00
if (zstr(val)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Alias Param has no data...\n");
} else {
if ((node = switch_core_alloc(profile->pool, sizeof(*node)))) {
if ((node->url = switch_core_strdup(profile->pool, val))) {
node->next = profile->aliases;
profile->aliases = node;
}
}
}
} else if (!strcasecmp(var, "dialplan")) {
profile->dialplan = switch_core_strdup(profile->pool, val);
} else if (!strcasecmp(var, "max-calls")) {
profile->max_calls = atoi(val);
} else if (!strcasecmp(var, "codec-prefs")) {
profile->inbound_codec_string = switch_core_strdup(profile->pool, val);
profile->outbound_codec_string = switch_core_strdup(profile->pool, val);
} else if (!strcasecmp(var, "inbound-codec-prefs")) {
profile->inbound_codec_string = switch_core_strdup(profile->pool, val);
} else if (!strcasecmp(var, "outbound-codec-prefs")) {
profile->outbound_codec_string = switch_core_strdup(profile->pool, val);
} else if (!strcasecmp(var, "challenge-realm")) {
profile->challenge_realm = switch_core_strdup(profile->pool, val);
} else if (!strcasecmp(var, "dtmf-duration")) {
uint32_t dur = atoi(val);
if (dur >= switch_core_min_dtmf_duration(0) && dur <= switch_core_max_dtmf_duration(0)) {
profile->dtmf_duration = dur;
} else {
profile->dtmf_duration = SWITCH_DEFAULT_DTMF_DURATION;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Duration out of bounds, using default of %d!\n",
SWITCH_DEFAULT_DTMF_DURATION);
}
} else if (!strcasecmp(var, "ws-binding") && !zstr(val)) {
int tmp;
char *p;
profile->ws_ip = switch_core_strdup(profile->pool, val);
if ((p = strrchr(profile->ws_ip, ':'))) {
*p++ = '\0';
if (p && (tmp = atol(p)) && tmp > 0) {
profile->ws_port = (switch_port_t) tmp;
}
}
} else if (!strcasecmp(var, "wss-binding") && !zstr(val)) {
int tmp;
char *p;
profile->wss_ip = switch_core_strdup(profile->pool, val);
if ((p = strrchr(profile->wss_ip, ':'))) {
*p++ = '\0';
if (p && (tmp = atol(p)) && tmp > 0) {
profile->wss_port = (switch_port_t) tmp;
}
}
/*
* handle TLS params #1
*/
} else if (!strcasecmp(var, "tls")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_TLS);
2013-04-17 20:58:10 +00:00
if (profile->tls_bind_params) {
2013-04-17 22:48:55 +00:00
if (!switch_stristr("transport=tls", profile->tls_bind_params)) {
profile->tls_bind_params = switch_core_sprintf(profile->pool, "%s;transport=tls", profile->tls_bind_params);
}
2013-04-17 20:58:10 +00:00
} else {
profile->tls_bind_params = switch_core_strdup(profile->pool, "transport=tls");
}
} else {
sofia_clear_pflag(profile, PFLAG_TLS);
}
} else if (!strcasecmp(var, "tls-bind-params")) {
2013-04-17 20:58:10 +00:00
if (switch_stristr("transport=tls", val)) {
profile->tls_bind_params = switch_core_strdup(profile->pool, val);
2013-04-17 22:48:55 +00:00
} else {
profile->tls_bind_params = switch_core_sprintf(profile->pool, "%s;transport=tls", val);
2013-04-17 20:58:10 +00:00
}
} else if (!strcasecmp(var, "tls-only")) {
profile->tls_only = switch_true(val);
} else if (!strcasecmp(var, "tls-verify-date")) {
profile->tls_verify_date = switch_true(val);
} else if (!strcasecmp(var, "tls-verify-depth")) {
profile->tls_verify_depth = atoi(val);
} else if (!strcasecmp(var, "tls-verify-policy")) {
profile->tls_verify_policy = sofia_glue_str2tls_verify_policy(val);
} else if (!strcasecmp(var, "tls-sip-port")) {
2011-06-27 15:15:03 +00:00
if (!strcasecmp(val, "auto")) {
sofia_set_pflag(profile, PFLAG_AUTO_ASSIGN_TLS_PORT);
} else {
sofia_clear_pflag(profile, PFLAG_AUTO_ASSIGN_TLS_PORT);
2011-06-27 15:15:03 +00:00
profile->tls_sip_port = (switch_port_t) atoi(val);
}
2013-02-26 17:49:41 +00:00
} else if (!strcasecmp(var, "tls-cert-dir") && !zstr(val)) {
profile->tls_cert_dir = switch_core_strdup(profile->pool, val);
2013-02-26 17:49:41 +00:00
} else if (!strcasecmp(var, "tls-passphrase") && !zstr(val)) {
profile->tls_passphrase = switch_core_strdup(profile->pool, val);
2013-02-26 17:49:41 +00:00
} else if (!strcasecmp(var, "tls-verify-in-subjects") && !zstr(val)) {
profile->tls_verify_in_subjects_str = switch_core_strdup(profile->pool, val);
} else if (!strcasecmp(var, "tls-ciphers") && !zstr(val)) {
profile->tls_ciphers = switch_core_strdup(profile->pool, val);
2013-02-26 17:49:41 +00:00
} else if (!strcasecmp(var, "tls-version") && !zstr(val)) {
char *ps = val, *pe;
profile->tls_version = 0;
while (1) {
int n;
pe = strchr(ps,',');
if (!pe && !(pe = memchr(ps,0,1024))) break;
n = pe-ps;
if (n==5 && !strncasecmp(ps, "sslv2", n))
profile->tls_version |= SOFIA_TLS_VERSION_SSLv2;
if (n==5 && !strncasecmp(ps, "sslv3", n))
profile->tls_version |= SOFIA_TLS_VERSION_SSLv3;
if (n==6 && !strncasecmp(ps, "sslv23", n))
profile->tls_version |= SOFIA_TLS_VERSION_SSLv2 | SOFIA_TLS_VERSION_SSLv3;
if (n==5 && !strncasecmp(ps, "tlsv1", n))
profile->tls_version |= SOFIA_TLS_VERSION_TLSv1;
if (n==7 && !strncasecmp(ps, "tlsv1.1", n))
profile->tls_version |= SOFIA_TLS_VERSION_TLSv1_1;
if (n==7 && !strncasecmp(ps, "tlsv1.2", n))
profile->tls_version |= SOFIA_TLS_VERSION_TLSv1_2;
ps=pe+1;
if (!*pe) break;
}
} else if (!strcasecmp(var, "tls-timeout")) {
int v = atoi(val);
profile->tls_timeout = v > 0 ? (unsigned int)v : 300;
} else if (!strcasecmp(var, "timer-T1")) {
int v = atoi(val);
if (v > 0) {
profile->timer_t1 = v;
} else {
profile->timer_t1 = 500;
}
} else if (!strcasecmp(var, "timer-T1X64")) {
int v = atoi(val);
if (v > 0) {
profile->timer_t1x64 = v;
} else {
profile->timer_t1x64 = 32000;
}
} else if (!strcasecmp(var, "timer-T2")) {
int v = atoi(val);
if (v > 0) {
profile->timer_t2 = v;
} else {
profile->timer_t2 = 4000;
}
} else if (!strcasecmp(var, "timer-T4")) {
int v = atoi(val);
if (v > 0) {
profile->timer_t4 = v;
} else {
profile->timer_t4 = 4000;
}
} else if (!strcasecmp(var, "sip-options-respond-503-on-busy")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_OPTIONS_RESPOND_503_ON_BUSY);
} else {
sofia_clear_pflag(profile, PFLAG_OPTIONS_RESPOND_503_ON_BUSY);
}
} else if (!strcasecmp(var, "sip-expires-late-margin")) {
int32_t sip_expires_late_margin = atoi(val);
if (sip_expires_late_margin >= 0) {
profile->sip_expires_late_margin = sip_expires_late_margin;
} else {
profile->sip_expires_late_margin = 60;
}
2011-12-22 20:03:32 +00:00
} else if (!strcasecmp(var, "sip-force-expires")) {
int32_t sip_force_expires = atoi(val);
2011-12-22 20:03:32 +00:00
if (sip_force_expires >= 0) {
profile->sip_force_expires = sip_force_expires;
} else {
profile->sip_force_expires = 0;
}
} else if (!strcasecmp(var, "sip-expires-max-deviation")) {
int32_t sip_expires_max_deviation = atoi(val);
2011-12-22 20:03:32 +00:00
if (sip_expires_max_deviation >= 0) {
profile->sip_expires_max_deviation = sip_expires_max_deviation;
} else {
profile->sip_expires_max_deviation = 0;
}
2013-07-03 16:21:03 +00:00
} else if (!strcasecmp(var, "sip-subscription-max-deviation")) {
int32_t sip_subscription_max_deviation = atoi(val);
if (sip_subscription_max_deviation >= 0) {
profile->sip_subscription_max_deviation = sip_subscription_max_deviation;
} else {
profile->sip_subscription_max_deviation = 0;
}
} else if (!strcasecmp(var, "reuse-connections")) {
switch_bool_t value = switch_true(val);
if (!value) {
sofia_set_pflag(profile, PFLAG_NO_CONNECTION_REUSE);
} else {
sofia_clear_pflag(profile, PFLAG_NO_CONNECTION_REUSE);
}
2012-04-10 20:46:27 +00:00
} else if (!strcasecmp(var, "p-asserted-id-parse")) {
if (!strncasecmp(val, "default", 7)) {
profile->paid_type = PAID_DEFAULT;
} else if (!strncasecmp(val, "user-only", 9)) {
profile->paid_type = PAID_USER;
} else if (!strncasecmp(val, "user-domain", 11)) {
profile->paid_type = PAID_USER_DOMAIN;
} else if (!strncasecmp(val, "verbatim", 8)) {
profile->paid_type = PAID_VERBATIM;
} else {
profile->paid_type = PAID_DEFAULT;
}
}
}
if (sofia_test_flag(profile, TFLAG_ZRTP_PASSTHRU) && !sofia_test_flag(profile, TFLAG_LATE_NEGOTIATION)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "ZRTP passthrough implictly enables inbound-late-negotiation\n");
add enhanced zrtp passthrough (zrtp passthru) mode ZRTP passthrough mode allows two ZRTP-capable clients to negotiate an end-to-end security association through FreeSWITCH. The clients are therefore able to be certain that the FreeSWITCH instance mediating the call cannot eavesdrop on their conversation. Importantly, this capability is maintained across multiple FreeSWITCH hops. If widely deployed, this enables a global network architecture where two people can speak securely with strong cryptographically protected authentication and confidentiality. With this commit we implement a zrtp-passthru mode that handles all the details of the negotiation intelligently. This mode can be selected by setting the boolean parameter inbound-zrtp-passthru in the sofia profile. This will also force late-negotiation as it is essential for correctly negotiating an end-to-end ZRTP security association. When an incoming call with a zrtp-hash is received and this mode is enabled, we find the first audio and the first video zrtp-hash in the SDP and store them as remote values on this channel. Once a b-leg is available, we set the local zrtp-hash values on that channel to the remote zrtp-hash values collected from the a-leg. Because zrtp-passthru absolutely requires that the channels negotiate the same codec, we offer to the b-leg only codecs that the a-leg can speak. Once the b-leg accepts a codec, we will force that choice onto the a-leg. If the b-leg sends us zrtp-hash values in the signaling, we store those as remote values on the b-leg and copy them to the local values on the a-leg. At this point, each leg has the zrtp-hash values from the other, and we know we can do ZRTP passthrough mode on the call. We send the b-leg's zrtp-hash back to the a-leg in the 200 OK. We then enable UDPTL mode on the rtp streams for both the audio and the video so that we don't interfere in the ZRTP negotiation. If the b-leg fails to return a zrtp-hash in the signaling, we set up a ZRTP security association with the a-leg ourselves, if we are so equipped. Likewise, if the a-leg fails to send a zrtp-hash in the signaling, we attempt to set up a ZRTP security association ourselves with the b-leg. The zrtp-passthru mode can also be enabled in the dialplan by setting the boolean channel variable zrtp_passthru. If enabled in this manner, we can't force late-negotiation, so the user would need to be sure this is configured. If ZRTP passthrough mode is not enabled in either manner, this change should have no effect. Channel variables for each of the various zrtp-hash values are set, though it is anticipated that there is no good reason to use them, so they may be removed without warning. For checking whether zrtp passthrough mode was successful, we provide the channel variable zrtp_passthru_active which is set on both legs. Though not implemented by this commit, the changes here should make it more straightforward to add correct zrtp-hash values to the signaling and verify that correct hello hash values are received when FreeSWITCH is acting as a terminating leg of the ZRTP security association. A historical note... This commit replaces the recently-added sdp_zrtp_hash_string method, commit 2ab1605a8887adc62be1b75f6ef67af87ff080de. This prior method sets a channel variable from the a-leg's zrtp-hash, then relies on the dialplan to export this channel variable to the b-leg, where it is put into the SDP. While it was a great start and wonderful for testing, this approach has some drawbacks that motivated the present work: * There's no good way to pass the zrtp-hash from the b-leg back to the a-leg. In fact, the implementation seems to send the a-leg's zrtp-hash back to the originating client in the 200 OK. This is not correct. * To support video, we'd need to have a separate dialplan variable, and the dialplan author would need to deal with that explicitly. * The API is problematic as it requires the dialplan author to understand intricate details of how ZRTP works to implement a correct dialplan. Further, by providing too fine-grained control (but at the same time, not enough control) it would limit our ability to make the behavior smarter once people started relying on this.
2012-05-24 20:39:03 +00:00
sofia_set_flag(profile, TFLAG_LATE_NEGOTIATION);
}
if (sofia_test_pflag(profile, PFLAG_SEND_DISPLAY_UPDATE) && !sofia_test_pflag(profile, PFLAG_ALLOW_UPDATE)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "send-display-update=true is set, but we can't comply because allow-update=false\n");
sofia_clear_pflag(profile, PFLAG_SEND_DISPLAY_UPDATE);
}
2012-12-22 03:30:14 +00:00
if ((!profile->cng_pt) && (!sofia_test_media_flag(profile, SCMF_SUPPRESS_CNG))) {
profile->cng_pt = SWITCH_RTP_CNG_PAYLOAD;
}
if (!profile->sipip) {
profile->sipip = switch_core_strdup(profile->pool, mod_sofia_globals.guess_ip);
}
if (!profile->rtpip[0]) {
profile->rtpip[profile->rtpip_index++] = switch_core_strdup(profile->pool, mod_sofia_globals.guess_ip);
}
if (switch_nat_get_type()) {
char *ip = switch_core_get_variable_dup("nat_public_addr");
if (ip && !strchr(profile->sipip, ':')) {
if (!profile->extrtpip) {
profile->extrtpip = switch_core_strdup(profile->pool, ip);
}
if (!profile->extsipip) {
profile->extsipip = switch_core_strdup(profile->pool, ip);
}
sofia_set_pflag(profile, PFLAG_AUTO_NAT);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "NAT detected setting external ip to %s\n", ip);
}
switch_safe_free(ip);
}
if (profile->nonce_ttl < 60) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Setting nonce TTL to 60 seconds\n");
profile->nonce_ttl = 60;
}
2012-12-22 03:30:14 +00:00
if (!profile->sdp_username) {
profile->sdp_username = switch_core_strdup(profile->pool, "FreeSWITCH");
}
if (!profile->rtpip[0]) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Setting ip to '127.0.0.1'\n");
profile->rtpip[profile->rtpip_index++] = switch_core_strdup(profile->pool, "127.0.0.1");
}
2011-06-27 15:15:03 +00:00
if (!profile->sip_port && !sofia_test_pflag(profile, PFLAG_AUTO_ASSIGN_PORT)) {
profile->sip_port = (switch_port_t) atoi(SOFIA_DEFAULT_PORT);
2012-12-10 19:52:25 +00:00
if (!profile->extsipport) profile->extsipport = profile->sip_port;
}
if (!profile->dialplan) {
profile->dialplan = switch_core_strdup(profile->pool, "XML");
}
if (!profile->context) {
profile->context = switch_core_strdup(profile->pool, "default");
}
if (!profile->sipdomain) {
profile->sipdomain = switch_core_strdup(profile->pool, profile->sipip);
}
2012-06-04 19:16:30 +00:00
if (profile->pres_type == PRES_TYPE_PNP) {
if (!profile->pnp_prov_url) {
profile->pnp_prov_url = switch_core_sprintf(profile->pool, "http://%s/provision/", mod_sofia_globals.guess_ip);
}
if (!profile->pnp_notify_profile) {
profile->pnp_notify_profile = switch_core_strdup(profile->pool, mod_sofia_globals.guess_ip);
}
if (!profile->extsipip) {
profile->extsipip = switch_core_strdup(profile->pool, mod_sofia_globals.guess_ip);
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "we're configured to provision to [%s] on profile [%s]\n",
2012-06-04 19:16:30 +00:00
profile->pnp_prov_url, profile->pnp_notify_profile);
}
2011-06-27 15:15:03 +00:00
config_sofia_profile_urls(profile);
2013-02-26 17:49:41 +00:00
if (profile->tls_cert_dir) {
if (profile->wss_ip) {
char *key, *cert;
key = switch_core_sprintf(profile->pool, "%s/%s", profile->tls_cert_dir, "wss.key");
if (switch_file_exists(key, profile->pool) != SWITCH_STATUS_SUCCESS) key = NULL;
cert = switch_core_sprintf(profile->pool, "%s/%s", profile->tls_cert_dir, "wss.crt");
if (switch_file_exists(cert, profile->pool) != SWITCH_STATUS_SUCCESS) cert = NULL;
if ( !key || !cert) {
key = switch_core_sprintf(profile->pool, "%s/%s", profile->tls_cert_dir, "wss.pem");
if ( switch_file_exists(key, profile->pool) != SWITCH_STATUS_SUCCESS ) {
switch_core_gen_certs(key);
}
}
}
if (sofia_test_pflag(profile, PFLAG_TLS)) {
char *key = switch_core_sprintf(profile->pool, "%s/%s", profile->tls_cert_dir, "agent.pem");
char *ca = switch_core_sprintf(profile->pool, "%s/%s", profile->tls_cert_dir, "cafile.pem");;
if (switch_file_exists(key, profile->pool) != SWITCH_STATUS_SUCCESS) key = NULL;
if (switch_file_exists(ca, profile->pool) != SWITCH_STATUS_SUCCESS) ca = NULL;
if ( !key || !ca ) {
key = switch_core_sprintf(profile->pool, "%s/%s", profile->tls_cert_dir, "tls.pem");
if ( switch_file_exists(key, profile->pool) != SWITCH_STATUS_SUCCESS ) {
switch_core_gen_certs(key);
}
}
}
}
}
if (profile) {
if (profile_already_started) {
switch_xml_t gateways_tag, domain_tag, domains_tag, aliases_tag, alias_tag;
if (sofia_test_flag(profile, TFLAG_ZRTP_PASSTHRU)) {
sofia_set_flag(profile, TFLAG_LATE_NEGOTIATION);
}
if ((gateways_tag = switch_xml_child(xprofile, "gateways"))) {
parse_gateways(profile, gateways_tag);
}
status = SWITCH_STATUS_SUCCESS;
if ((domains_tag = switch_xml_child(xprofile, "domains"))) {
switch_event_t *xml_params;
switch_event_create(&xml_params, SWITCH_EVENT_REQUEST_PARAMS);
switch_assert(xml_params);
switch_event_add_header_string(xml_params, SWITCH_STACK_BOTTOM, "purpose", "gateways");
switch_event_add_header_string(xml_params, SWITCH_STACK_BOTTOM, "profile", profile->name);
for (domain_tag = switch_xml_child(domains_tag, "domain"); domain_tag; domain_tag = domain_tag->next) {
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 (!zstr(dname)) {
if (!strcasecmp(dname, "all")) {
switch_xml_t xml_root, x_domains;
if (switch_xml_locate("directory", NULL, NULL, NULL, &xml_root, &x_domains, xml_params, SWITCH_FALSE) == 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(xml_root);
}
} else if (switch_xml_locate_domain(dname, xml_params, &droot, &x_domain_tag) == SWITCH_STATUS_SUCCESS) {
parse_domain_tag(profile, x_domain_tag, dname, parse, alias);
switch_xml_free(droot);
}
}
}
switch_event_destroy(&xml_params);
}
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");
if (!zstr(aname)) {
if (sofia_glue_add_profile(switch_core_strdup(profile->pool, aname), profile) == SWITCH_STATUS_SUCCESS) {
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_WARNING, "Alias [%s] for profile [%s] (already exists)\n",
aname, profile->name);
}
}
}
}
} else {
switch_xml_t aliases_tag, alias_tag;
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");
if (!zstr(aname)) {
if (sofia_glue_add_profile(switch_core_strdup(profile->pool, aname), profile) == SWITCH_STATUS_SUCCESS) {
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);
}
}
}
}
if (profile->sipip) {
2014-07-09 13:53:14 +00:00
switch_event_t *s_event;
2012-12-10 19:52:25 +00:00
if (!profile->extsipport) profile->extsipport = profile->sip_port;
2012-11-21 17:49:35 +00:00
launch_sofia_profile_thread(profile);
if (profile->odbc_dsn) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Connecting ODBC Profile %s [%s]\n", profile->name, url);
switch_yield(1000000);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Started Profile %s [%s]\n", profile->name, url);
}
2014-07-09 13:53:14 +00:00
if ((switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_PROFILE_START) == SWITCH_STATUS_SUCCESS)) {
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "module_name", "mod_sofia");
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile_name", profile->name);
if (profile) {
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile_uri", profile->url);
}
switch_event_fire(&s_event);
}
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Unable to start Profile %s due to no configured sip-ip\n", profile->name);
sofia_profile_start_failure(profile, profile->name);
}
profile = NULL;
}
if (profile_found) {
break;
}
}
}
}
done:
if (profile_already_started) {
sofia_glue_release_profile(profile_already_started);
}
switch_event_destroy(&params);
if (xml) {
switch_xml_free(xml);
}
if (profile_name && !profile_found) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "No Such Profile '%s'\n", profile_name);
status = SWITCH_STATUS_FALSE;
}
return status;
}
const char *sofia_gateway_status_name(sofia_gateway_status_t status)
{
static const char *status_names[] = { "DOWN", "UP", NULL };
if (status < SOFIA_GATEWAY_INVALID) {
return status_names[status];
} else {
return "INVALID";
}
}
static void sofia_handle_sip_r_options(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,
sofia_dispatch_event_t *de,
tagi_t tags[])
{
sofia_gateway_t *gateway = NULL;
if (sofia_private && !zstr(sofia_private->gateway_name)) {
gateway = sofia_reg_find_gateway(sofia_private->gateway_name);
sofia_private->destroy_me = 1;
}
if (gateway) {
if (status >= 200 && status < 600 && status != 408 && status != 503) {
if (gateway->state == REG_STATE_FAILED) {
gateway->state = REG_STATE_UNREGED;
}
2013-01-07 17:43:26 +00:00
if (gateway->ping_count < 0) {
gateway->ping_count = 0;
}
if (gateway->ping_count < gateway->ping_max) {
gateway->ping_count++;
2013-01-07 17:43:26 +00:00
if (gateway->ping_count >= gateway->ping_min && gateway->status != SOFIA_GATEWAY_UP) {
gateway->status = SOFIA_GATEWAY_UP;
sofia_reg_fire_custom_gateway_state_event(gateway, status, phrase);
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
"Ping succeeded %s with code %d - count %d/%d/%d, state %s\n",
gateway->name, status, gateway->ping_min, gateway->ping_count, gateway->ping_max, sofia_gateway_status_name(gateway->status));
}
} else {
if (gateway->state == REG_STATE_REGED) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Unregister %s\n", gateway->name);
gateway->state = REG_STATE_FAILED;
}
2013-01-07 17:43:26 +00:00
if (gateway->ping_count > 0) {
gateway->ping_count--;
2013-01-07 17:43:26 +00:00
}
2013-01-07 17:43:26 +00:00
if (gateway->ping_count < gateway->ping_min && gateway->status != SOFIA_GATEWAY_DOWN) {
gateway->status = SOFIA_GATEWAY_DOWN;
sofia_reg_fire_custom_gateway_state_event(gateway, status, phrase);
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
"Ping failed %s with code %d - count %d/%d/%d, state %s\n",
gateway->name, status, gateway->ping_min, gateway->ping_count, gateway->ping_max, sofia_gateway_status_name(gateway->status));
}
gateway->ping = switch_epoch_time_now(NULL) + gateway->ping_freq;
sofia_reg_release_gateway(gateway);
gateway->pinging = 0;
2012-11-29 21:49:05 +00:00
} else if (sofia_test_pflag(profile, PFLAG_UNREG_OPTIONS_FAIL) && (status != 200 && status != 486) &&
sip && sip->sip_to && sip->sip_call_id && sip->sip_call_id->i_id && strchr(sip->sip_call_id->i_id, '_')) {
char *sql;
time_t now = switch_epoch_time_now(NULL);
2012-11-29 18:59:33 +00:00
const char *call_id = strchr(sip->sip_call_id->i_id, '_') + 1;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Expire registration '%s@%s' due to options failure\n",
sip->sip_to->a_url->url_user, sip->sip_to->a_url->url_host);
sql = switch_mprintf("update sip_registrations set expires=%ld where sip_user='%s' and sip_host='%s' and call_id='%q'",
(long) now, sip->sip_to->a_url->url_user, sip->sip_to->a_url->url_host, call_id);
sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
}
}
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,
sofia_dispatch_event_t *de,
tagi_t tags[])
{
char *call_info = NULL;
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);
char network_ip[80];
int network_port = 0;
switch_caller_profile_t *caller_profile = NULL;
2010-08-17 20:00:25 +00:00
int has_t38 = 0;
switch_channel_clear_flag(channel, CF_REQ_MEDIA);
if (status >= 900) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "%s status %d received.\n",
switch_channel_get_name(channel), status);
return;
}
2012-07-16 18:53:19 +00:00
if (status > 299) {
switch_channel_set_variable(channel, "sip_hangup_disposition", "recv_refuse");
}
if (status >= 400) {
char status_str[5];
switch_snprintf(status_str, sizeof(status_str), "%d", status);
switch_channel_set_variable_partner(channel, "sip_invite_failure_status", status_str);
switch_channel_set_variable_partner(channel, "sip_invite_failure_phrase", phrase);
}
2012-11-11 15:09:22 +00:00
if (status >= 400 && sip->sip_reason && sip->sip_reason->re_protocol && (!strcasecmp(sip->sip_reason->re_protocol, "Q.850")
2012-03-27 15:18:08 +00:00
|| !strcasecmp(sip->sip_reason->re_protocol, "FreeSWITCH")
2012-12-22 03:30:14 +00:00
|| !strcasecmp(sip->sip_reason->re_protocol, profile->sdp_username)) && sip->sip_reason->re_cause) {
tech_pvt->q850_cause = atoi(sip->sip_reason->re_cause);
2012-03-27 15:18:08 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Remote Reason: %d\n", tech_pvt->q850_cause);
}
2012-03-27 15:18:08 +00:00
sofia_glue_get_addr(de->data->e_msg, network_ip, sizeof(network_ip), &network_port);
switch_channel_set_variable_printf(channel, "sip_local_network_addr", "%s", profile->extsipip ? profile->extsipip : profile->sipip);
switch_channel_set_variable(channel, "sip_reply_host", network_ip);
switch_channel_set_variable_printf(channel, "sip_reply_port", "%d", network_port);
switch_channel_set_variable_printf(channel, "sip_network_ip", "%s", network_ip);
switch_channel_set_variable_printf(channel, "sip_network_port", "%d", network_port);
if ((caller_profile = switch_channel_get_caller_profile(channel))) {
caller_profile->network_addr = switch_core_strdup(caller_profile->pool, network_ip);
}
2014-06-03 00:09:48 +00:00
tech_pvt->mparams.last_sdp_response = NULL;
if (sip->sip_payload && sip->sip_payload->pl_data) {
switch_core_media_set_sdp_codec_string(session, sip->sip_payload->pl_data, SDP_TYPE_RESPONSE);
2014-06-03 00:09:48 +00:00
tech_pvt->mparams.last_sdp_response = switch_core_session_strdup(session, sip->sip_payload->pl_data);
}
2011-06-08 23:50:21 +00:00
if (status > 299 && switch_channel_test_app_flag_key("T38", tech_pvt->channel, CF_APP_T38_REQ)) {
switch_channel_set_private(channel, "t38_options", NULL);
switch_channel_clear_app_flag_key("T38", tech_pvt->channel, CF_APP_T38);
switch_channel_clear_app_flag_key("T38", tech_pvt->channel, CF_APP_T38_REQ);
switch_channel_set_app_flag_key("T38", tech_pvt->channel, CF_APP_T38_FAIL);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s T38 invite failed\n", switch_channel_get_name(tech_pvt->channel));
}
if (sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE)) {
if (channel && sip->sip_call_info) {
char *p;
call_info = sip_header_as_string(nua_handle_home(nh), (void *) sip->sip_call_info);
if (switch_stristr("appearance", call_info)) {
switch_channel_set_variable(channel, "presence_call_info_full", call_info);
if ((p = strchr(call_info, ';'))) {
switch_channel_set_variable(channel, "presence_call_info", p + 1);
}
}
} else if ((status == 180 || status == 183 || status == 200)) {
char buf[128] = "";
char *sql;
char *state = "active";
if (status != 200) {
state = "progressing";
}
if (sip &&
sip->sip_from && sip->sip_from->a_url && sip->sip_from->a_url->url_user && sip->sip_from->a_url->url_host &&
sip->sip_to && sip->sip_to->a_url && sip->sip_to->a_url->url_user && sip->sip_to->a_url->url_host) {
sql =
switch_mprintf("select 'appearance-index=1' from sip_subscriptions where expires > -1 and hostname='%q' and event='call-info' and "
"sub_to_user='%q' and sub_to_host='%q'", mod_sofia_globals.hostname, sip->sip_to->a_url->url_user,
sip->sip_from->a_url->url_host);
sofia_glue_execute_sql2str(profile, profile->dbh_mutex, sql, buf, sizeof(buf));
if (mod_sofia_globals.debug_sla > 1) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "QUERY SQL %s [%s]\n", sql, buf);
}
free(sql);
if (!zstr(buf)) {
sql = switch_mprintf("update sip_dialogs set call_info='%q',call_info_state='%q' "
"where uuid='%q'", buf, state, switch_core_session_get_uuid(session));
if (mod_sofia_globals.debug_sla > 1) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "QUERY SQL %s\n", sql);
}
sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Auto-Fixing Broken SLA [<sip:%s>;%s]\n",
sip->sip_from->a_url->url_host, buf);
switch_channel_set_variable_printf(channel, "presence_call_info_full", "<sip:%s>;%s", sip->sip_from->a_url->url_host, buf);
switch_channel_set_variable(channel, "presence_call_info", buf);
}
}
}
}
#if 0
if (status == 200 && switch_channel_test_flag(channel, CF_PROXY_MEDIA) &&
sip->sip_payload && sip->sip_payload->pl_data && !strcasecmp(tech_pvt->iananame, "PROXY")) {
switch_core_session_t *other_session;
switch_core_media_proxy_codec(session, sip->sip_payload->pl_data);
if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
if (switch_core_session_compare(session, other_session)) {
switch_core_media_proxy_codec(other_session, sip->sip_payload->pl_data);
}
switch_core_session_rwunlock(other_session);
}
}
#endif
if ((status == 180 || status == 183 || status > 199)) {
const char *vval;
if (status > 199) {
sofia_glue_set_extra_headers(session, sip, SOFIA_SIP_RESPONSE_HEADER_PREFIX);
2011-02-18 16:32:44 +00:00
} else {
sofia_glue_set_extra_headers(session, sip, SOFIA_SIP_PROGRESS_HEADER_PREFIX);
2011-02-18 16:32:44 +00:00
}
if (!(vval = switch_channel_get_variable(channel, "sip_copy_custom_headers")) || switch_true(vval)) {
switch_core_session_t *other_session;
if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
if (status > 199) {
switch_ivr_transfer_variable(session, other_session, SOFIA_SIP_RESPONSE_HEADER_PREFIX_T);
2011-02-18 16:32:44 +00:00
} else {
switch_ivr_transfer_variable(session, other_session, SOFIA_SIP_PROGRESS_HEADER_PREFIX_T);
}
switch_core_session_rwunlock(other_session);
}
}
}
if ((status == 180 || status == 183 || status == 200)) {
const char *x_freeswitch_support;
switch_channel_set_flag(channel, CF_MEDIA_ACK);
if ((x_freeswitch_support = sofia_glue_get_unknown_header(sip, "X-FS-Support"))) {
tech_pvt->x_freeswitch_support_remote = switch_core_session_strdup(session, x_freeswitch_support);
}
if (sip->sip_user_agent && sip->sip_user_agent->g_string) {
switch_channel_set_variable(channel, "sip_user_agent", sip->sip_user_agent->g_string);
} else if (sip->sip_server && sip->sip_server->g_string) {
switch_channel_set_variable(channel, "sip_user_agent", sip->sip_server->g_string);
}
sofia_update_callee_id(session, profile, sip, SWITCH_FALSE);
2013-11-07 22:48:00 +00:00
if (sofia_test_media_flag(tech_pvt->profile, SCMF_AUTOFIX_TIMING)) {
2013-07-29 15:18:05 +00:00
switch_core_media_reset_autofix(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO);
}
}
if (channel && sip && (status == 300 || status == 301 || status == 302 || status == 305) && switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
sip_contact_t *p_contact = sip->sip_contact;
int i = 0;
char var_name[80];
const char *diversion_header;
char *full_contact = NULL;
char *invite_contact;
const char *br;
2010-04-20 21:50:40 +00:00
const char *v;
2010-04-20 21:50:40 +00:00
if ((v = switch_channel_get_variable(channel, "outbound_redirect_fatal")) && switch_true(v)) {
switch_channel_hangup(channel, SWITCH_CAUSE_REQUESTED_CHAN_UNAVAIL);
goto end;
}
if (!p_contact) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Missing contact header in redirect request\n");
goto end;
}
if ((br = switch_channel_get_partner_uuid(channel))) {
switch_xml_t root = NULL, domain = NULL;
switch_core_session_t *a_session;
switch_channel_t *a_channel;
const char *sip_redirect_profile, *sip_redirect_context, *sip_redirect_dialplan, *sip_redirect_fork;
if ((a_session = switch_core_session_locate(br)) && (a_channel = switch_core_session_get_channel(a_session))) {
switch_stream_handle_t stream = { 0 };
char separator[2] = "|";
char *redirect_dialstring;
su_home_t *home = su_home_new(sizeof(*home));
switch_assert(home != NULL);
SWITCH_STANDARD_STREAM(stream);
if (!(sip_redirect_profile = switch_channel_get_variable(channel, "sip_redirect_profile"))) {
sip_redirect_profile = profile->name;
}
if (!(sip_redirect_context = switch_channel_get_variable(channel, "sip_redirect_context"))) {
sip_redirect_context = "redirected";
}
if (!(sip_redirect_dialplan = switch_channel_get_variable(channel, "sip_redirect_dialplan"))) {
sip_redirect_dialplan = "XML";
}
sip_redirect_fork = switch_channel_get_variable(channel, "sip_redirect_fork");
if (switch_true(sip_redirect_fork)) {
*separator = ',';
}
for (p_contact = sip->sip_contact; p_contact; p_contact = p_contact->m_next) {
if (p_contact->m_url) {
full_contact = sip_header_as_string(home, (void *) p_contact);
invite_contact = sofia_glue_strip_uri(full_contact);
switch_snprintf(var_name, sizeof(var_name), "sip_redirect_contact_%d", i);
switch_channel_set_variable(a_channel, var_name, full_contact);
if (i == 0) {
switch_channel_set_variable(channel, "sip_redirected_to", full_contact);
switch_channel_set_variable(a_channel, "sip_redirected_to", full_contact);
}
if (p_contact->m_url->url_user) {
switch_snprintf(var_name, sizeof(var_name), "sip_redirect_contact_user_%d", i);
switch_channel_set_variable(channel, var_name, p_contact->m_url->url_user);
switch_channel_set_variable(a_channel, var_name, p_contact->m_url->url_user);
}
if (p_contact->m_url->url_host) {
switch_snprintf(var_name, sizeof(var_name), "sip_redirect_contact_host_%d", i);
switch_channel_set_variable(channel, var_name, p_contact->m_url->url_host);
switch_channel_set_variable(a_channel, var_name, p_contact->m_url->url_host);
}
if (p_contact->m_url->url_params) {
switch_snprintf(var_name, sizeof(var_name), "sip_redirect_contact_params_%d", i);
switch_channel_set_variable(channel, var_name, p_contact->m_url->url_params);
switch_channel_set_variable(a_channel, var_name, p_contact->m_url->url_params);
}
switch_snprintf(var_name, sizeof(var_name), "sip_redirect_dialstring_%d", i);
switch_channel_set_variable_printf(channel, var_name, "sofia/%s/%s", sip_redirect_profile, invite_contact);
switch_channel_set_variable_printf(a_channel, var_name, "sofia/%s/%s", sip_redirect_profile, invite_contact);
stream.write_function(&stream, "%ssofia/%s/%s", i ? separator : "", sip_redirect_profile, invite_contact);
free(invite_contact);
i++;
}
}
redirect_dialstring = stream.data;
switch_channel_set_variable_printf(channel, "sip_redirect_count", "%d", i);
switch_channel_set_variable(channel, "sip_redirect_dialstring", redirect_dialstring);
switch_channel_set_variable(a_channel, "sip_redirect_dialstring", redirect_dialstring);
p_contact = sip->sip_contact;
full_contact = sip_header_as_string(home, (void *) sip->sip_contact);
if ((diversion_header = sofia_glue_get_unknown_header(sip, "diversion"))) {
switch_channel_set_variable(channel, "sip_redirected_by", diversion_header);
switch_channel_set_variable(a_channel, "sip_redirected_by", diversion_header);
}
if (sofia_test_pflag(profile, PFLAG_MANUAL_REDIRECT)) {
2012-03-28 17:24:19 +00:00
if (!(v = switch_channel_get_variable(channel, "outbound_redirect_info"))) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Redirect: Transfering to %s %s %s\n",
p_contact->m_url->url_user, sip_redirect_dialplan, sip_redirect_context);
2011-05-31 18:10:37 +00:00
2012-03-28 17:24:19 +00:00
if (switch_true(switch_channel_get_variable(channel, "recording_follow_transfer"))) {
switch_core_media_bug_transfer_recordings(session, a_session);
}
2011-05-31 18:10:37 +00:00
2012-03-28 17:24:19 +00:00
switch_ivr_session_transfer(a_session, p_contact->m_url->url_user, sip_redirect_dialplan, sip_redirect_context);
}
switch_channel_hangup(channel, SWITCH_CAUSE_REDIRECTION_TO_NEW_DESTINATION);
} else if ((!strcmp(profile->sipip, p_contact->m_url->url_host))
|| (profile->extsipip && !strcmp(profile->extsipip, p_contact->m_url->url_host))
|| (switch_xml_locate_domain(p_contact->m_url->url_host, NULL, &root, &domain) == SWITCH_STATUS_SUCCESS)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Redirect: Transfering to %s\n",
p_contact->m_url->url_user);
2011-05-31 18:10:37 +00:00
if (switch_true(switch_channel_get_variable(channel, "recording_follow_transfer"))) {
switch_core_media_bug_transfer_recordings(session, a_session);
}
switch_ivr_session_transfer(a_session, p_contact->m_url->url_user, NULL, NULL);
switch_channel_hangup(channel, SWITCH_CAUSE_REDIRECTION_TO_NEW_DESTINATION);
switch_xml_free(root);
} else {
invite_contact = sofia_glue_strip_uri(full_contact);
tech_pvt->redirected = switch_core_session_strdup(session, invite_contact);
free(invite_contact);
}
if (home) {
su_home_unref(home);
home = NULL;
}
free(stream.data);
switch_core_session_rwunlock(a_session);
}
} else {
su_home_t *home = su_home_new(sizeof(*home));
switch_assert(home != NULL);
full_contact = sip_header_as_string(home, (void *) sip->sip_contact);
invite_contact = sofia_glue_strip_uri(full_contact);
switch_channel_set_variable(channel, "sip_redirected_to", invite_contact);
tech_pvt->redirected = switch_core_session_strdup(session, invite_contact);
free(invite_contact);
if (home) {
su_home_unref(home);
home = NULL;
}
}
}
2010-09-17 20:15:29 +00:00
2012-10-02 15:30:51 +00:00
if (sip->sip_payload && sip->sip_payload->pl_data && switch_stristr("m=image", sip->sip_payload->pl_data)) {
2010-08-17 20:00:25 +00:00
has_t38 = 1;
}
if (switch_channel_test_flag(channel, CF_PROXY_MODE)) {
switch_channel_clear_flag(channel, CF_T38_PASSTHRU);
2012-10-02 15:30:51 +00:00
has_t38 = 0;
}
if (switch_channel_test_flag(channel, CF_PROXY_MEDIA) && has_t38) {
if (switch_core_media_ready(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO)) {
switch_core_media_udptl_mode(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO);
2012-10-02 15:30:51 +00:00
if ((uuid = switch_channel_get_partner_uuid(channel)) && (other_session = switch_core_session_locate(uuid))) {
if (switch_core_session_compare(session, other_session)) {
private_object_t *other_tech_pvt = switch_core_session_get_private(other_session);
if (switch_core_media_ready(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO)) {
switch_core_media_udptl_mode(other_tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO);
2012-10-02 15:30:51 +00:00
}
}
switch_core_session_rwunlock(other_session);
}
}
2012-10-02 15:30:51 +00:00
has_t38 = 0;
}
2013-04-10 02:42:32 +00:00
if (status > 199 && (switch_channel_test_flag(channel, CF_PROXY_MODE) ||
switch_channel_test_flag(channel, CF_PROXY_MEDIA) ||
2013-06-26 15:47:40 +00:00
(switch_channel_test_flag(tech_pvt->channel, CF_T38_PASSTHRU) && (has_t38 || status > 299)))) {
if (sofia_test_flag(tech_pvt, TFLAG_SENT_UPDATE)) {
sofia_clear_flag_locked(tech_pvt, TFLAG_SENT_UPDATE);
if ((uuid = switch_channel_get_partner_uuid(channel)) && (other_session = switch_core_session_locate(uuid))) {
const char *r_sdp = NULL;
switch_core_session_message_t *msg;
2010-05-27 01:12:54 +00:00
private_object_t *other_tech_pvt = switch_core_session_get_private(other_session);
2011-03-31 23:17:52 +00:00
switch_channel_t *other_channel = switch_core_session_get_channel(other_session);
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)) {
tech_pvt->mparams.remote_sdp_str = switch_core_session_strdup(tech_pvt->session, sip->sip_payload->pl_data);
r_sdp = tech_pvt->mparams.remote_sdp_str;
2012-12-22 03:30:14 +00:00
switch_core_media_proxy_remote_addr(session, NULL);
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Passing %d %s to other leg\n", status, phrase);
2013-06-26 15:47:40 +00:00
if (status == 491 && (switch_channel_test_flag(tech_pvt->channel, CF_T38_PASSTHRU) ||
2013-04-10 02:38:11 +00:00
switch_channel_test_flag(channel, CF_PROXY_MODE))) {
nua_respond(other_tech_pvt->nh, SIP_491_REQUEST_PENDING, TAG_END());
switch_core_session_rwunlock(other_session);
goto end;
} else if (status > 299) {
2011-03-31 23:17:52 +00:00
switch_channel_set_private(channel, "t38_options", NULL);
switch_channel_set_private(other_channel, "t38_options", NULL);
2014-02-07 17:13:23 +00:00
switch_channel_clear_flag(channel, CF_T38_PASSTHRU);
switch_channel_clear_flag(other_channel, CF_T38_PASSTHRU);
switch_channel_clear_app_flag_key("T38", channel, CF_APP_T38);
switch_channel_clear_app_flag_key("T38", channel, CF_APP_T38_REQ);
switch_channel_set_app_flag_key("T38", channel, CF_APP_T38_FAIL);
} else if (status == 200 && switch_channel_test_flag(channel, CF_T38_PASSTHRU) &&
has_t38 && sip->sip_payload && sip->sip_payload->pl_data) {
2012-12-21 20:22:25 +00:00
switch_t38_options_t *t38_options = switch_core_media_extract_t38_options(session, sip->sip_payload->pl_data);
if (!t38_options) {
2012-08-29 16:50:55 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Could not parse T.38 options from sdp.\n");
switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "T.38 NEGOTIATION ERROR");
switch_channel_hangup(channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION);
switch_core_session_rwunlock(other_session);
goto end;
} else {
2012-12-21 22:57:59 +00:00
switch_core_media_process_t38_passthru(session, other_session, t38_options);
2010-05-27 01:12:54 +00:00
}
}
msg = switch_core_session_alloc(other_session, sizeof(*msg));
msg->message_id = SWITCH_MESSAGE_INDICATE_RESPOND;
msg->from = __FILE__;
msg->numeric_arg = status;
msg->string_arg = switch_core_session_strdup(other_session, phrase);
2010-05-27 01:12:54 +00:00
2013-06-26 15:47:40 +00:00
if (status == 200 && switch_channel_test_flag(tech_pvt->channel, CF_T38_PASSTHRU) && has_t38) {
2010-05-27 01:12:54 +00:00
msg->pointer_arg = switch_core_session_strdup(other_session, "t38");
} else if (r_sdp) {
msg->pointer_arg = switch_core_session_strdup(other_session, r_sdp);
msg->pointer_arg_size = strlen(r_sdp);
}
2014-02-07 17:13:23 +00:00
if (status == 200 && switch_channel_test_flag(channel, CF_T38_PASSTHRU) && has_t38) {
if (switch_core_media_ready(session, SWITCH_MEDIA_TYPE_AUDIO) &&
switch_core_media_ready(other_session, SWITCH_MEDIA_TYPE_AUDIO)) {
switch_channel_clear_flag(channel, CF_NOTIMER_DURING_BRIDGE);
switch_core_media_udptl_mode(session, SWITCH_MEDIA_TYPE_AUDIO);
2010-05-27 01:12:54 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Activating T38 Passthru\n");
}
}
2011-07-22 20:51:50 +00:00
switch_core_session_queue_message(other_session, msg);
switch_core_session_rwunlock(other_session);
}
goto end;
}
}
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)) || switch_channel_test_flag(channel, CF_RECOVERING)) {
const char *from_user = "", *from_host = "", *to_user = "", *to_host = "", *contact_user = "", *contact_host = "";
const char *user_agent = "", *call_id = "";
const char *to_tag = "";
const char *from_tag = "";
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);
from_tag = switch_str_nil(sip->sip_to->a_tag);
}
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);
to_tag = switch_str_nil(sip->sip_from->a_tag);
}
if (contact) {
contact_user = switch_str_nil(contact->url_user);
contact_host = switch_str_nil(contact->url_host);
}
if (profile->pres_type) {
const char *presence_data = switch_channel_get_variable(channel, "presence_data");
const char *presence_id = switch_channel_get_variable(channel, "presence_id");
char *full_contact = NULL;
char *p = NULL;
time_t now;
if (sip->sip_contact) {
full_contact = sip_header_as_string(nua_handle_home(tech_pvt->nh), (void *) sip->sip_contact);
}
if (call_info && (p = strchr(call_info, ';'))) {
p++;
}
now = switch_epoch_time_now(NULL);
sql = switch_mprintf("insert into sip_dialogs "
"(call_id,uuid,sip_to_user,sip_to_host,sip_to_tag,sip_from_user,sip_from_host,sip_from_tag,contact_user,"
2012-02-18 01:47:57 +00:00
"contact_host,state,direction,user_agent,profile_name,hostname,contact,presence_id,presence_data,"
"call_info,rcd,call_info_state) "
"values('%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q',%ld,'')",
call_id,
switch_core_session_get_uuid(session),
to_user, to_host, to_tag, from_user, from_host, from_tag, contact_user,
contact_host, astate, "outbound", user_agent,
profile->name, mod_sofia_globals.hostname, switch_str_nil(full_contact),
switch_str_nil(presence_id), switch_str_nil(presence_data), switch_str_nil(p), (long) now);
switch_assert(sql);
sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
if ( full_contact ) {
su_free(nua_handle_home(tech_pvt->nh), full_contact);
}
}
} else if (status == 200 && (profile->pres_type)) {
char *sql = NULL;
const char *presence_data = switch_channel_get_variable(channel, "presence_data");
const char *presence_id = switch_channel_get_variable(channel, "presence_id");
sql = switch_mprintf("update sip_dialogs set state='%q',presence_id='%q',presence_data='%q' "
"where uuid='%s';\n", astate, switch_str_nil(presence_id), switch_str_nil(presence_data),
switch_core_session_get_uuid(session));
switch_assert(sql);
sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
}
extract_header_vars(profile, sip, session, nh);
extract_vars(profile, sip, session);
switch_channel_clear_flag(tech_pvt->channel, CF_RECOVERING);
}
}
end:
if (call_info) {
su_free(nua_handle_home(nh), call_info);
}
if (!session && (status == 180 || status == 183 || status == 200)) {
/* nevermind */
nua_handle_bind(nh, NULL);
nua_handle_destroy(nh);
}
}
/* Pure black magic, if you can't understand this code you are lucky.........*/
void *SWITCH_THREAD_FUNC media_on_hold_thread_run(switch_thread_t *thread, void *obj)
{
switch_core_session_t *other_session = NULL, *session = (switch_core_session_t *) obj;
const char *uuid;
if (switch_core_session_read_lock(session) == SWITCH_STATUS_SUCCESS) {
switch_channel_t *channel = switch_core_session_get_channel(session);
private_object_t *tech_pvt = switch_core_session_get_private(session);
if ((uuid = switch_channel_get_partner_uuid(channel)) && (other_session = switch_core_session_locate(uuid))) {
if (switch_core_session_compare(session, other_session)) {
switch_channel_t *other_channel = switch_core_session_get_channel(other_session);
sofia_set_flag_locked(tech_pvt, TFLAG_HOLD_LOCK);
2012-07-05 16:42:07 +00:00
switch_yield(250000);
2012-07-05 16:42:07 +00:00
switch_channel_wait_for_flag(channel, CF_MEDIA_ACK, SWITCH_TRUE, 10000, NULL);
switch_channel_wait_for_flag(other_channel, CF_MEDIA_ACK, SWITCH_TRUE, 10000, NULL);
switch_ivr_media(switch_core_session_get_uuid(other_session), SMF_REBRIDGE);
if (switch_core_media_ready(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO)) {
switch_core_media_clear_rtp_flag(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, SWITCH_RTP_FLAG_AUTOADJ);
}
2012-12-21 20:22:25 +00:00
switch_core_media_toggle_hold(session, 1);
}
switch_core_session_rwunlock(other_session);
}
switch_core_session_rwunlock(session);
}
return NULL;
}
static void launch_media_on_hold(switch_core_session_t *session)
{
switch_thread_t *thread;
switch_threadattr_t *thd_attr = NULL;
switch_threadattr_create(&thd_attr, switch_core_session_get_pool(session));
switch_threadattr_detach_set(thd_attr, 1);
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
switch_thread_create(&thread, thd_attr, media_on_hold_thread_run, session, switch_core_session_get_pool(session));
}
2011-10-11 20:13:23 +00:00
static void mark_transfer_record(switch_core_session_t *session, const char *br_a, const char *br_b)
{
switch_core_session_t *br_b_session, *br_a_session;
switch_channel_t *channel;
const char *uvar1, *dvar1, *uvar2, *dvar2;
channel = switch_core_session_get_channel(session);
2011-10-11 20:13:23 +00:00
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) {
uvar1 = "sip_from_user";
dvar1 = "sip_from_host";
} else {
uvar1 = "sip_to_user";
dvar1 = "sip_to_host";
}
2011-10-11 20:13:23 +00:00
if ((br_b_session = switch_core_session_locate(br_b)) ) {
switch_channel_t *br_b_channel = switch_core_session_get_channel(br_b_session);
switch_caller_profile_t *cp = switch_channel_get_caller_profile(br_b_channel);
if (switch_channel_direction(br_b_channel) == SWITCH_CALL_DIRECTION_INBOUND) {
uvar2 = "sip_from_user";
dvar2 = "sip_from_host";
} else {
uvar2 = "sip_to_user";
dvar2 = "sip_to_host";
}
cp->transfer_source = switch_core_sprintf(cp->pool,
"%ld:%s:att_xfer:%s@%s/%s@%s",
(long) switch_epoch_time_now(NULL),
cp->uuid_str,
switch_channel_get_variable(channel, uvar1),
switch_channel_get_variable(channel, dvar1),
switch_channel_get_variable(br_b_channel, uvar2),
switch_channel_get_variable(br_b_channel, dvar2));
2011-10-11 20:13:23 +00:00
switch_channel_add_variable_var_check(br_b_channel, SWITCH_TRANSFER_HISTORY_VARIABLE, cp->transfer_source, SWITCH_FALSE, SWITCH_STACK_PUSH);
switch_channel_set_variable(br_b_channel, SWITCH_TRANSFER_SOURCE_VARIABLE, cp->transfer_source);
2011-10-11 20:13:23 +00:00
switch_core_session_rwunlock(br_b_session);
}
if ((br_a_session = switch_core_session_locate(br_a)) ) {
switch_channel_t *br_a_channel = switch_core_session_get_channel(br_a_session);
switch_caller_profile_t *cp = switch_channel_get_caller_profile(br_a_channel);
if (switch_channel_direction(br_a_channel) == SWITCH_CALL_DIRECTION_INBOUND) {
uvar2 = "sip_from_user";
dvar2 = "sip_from_host";
} else {
uvar2 = "sip_to_user";
dvar2 = "sip_to_host";
}
cp->transfer_source = switch_core_sprintf(cp->pool,
"%ld:%s:att_xfer:%s@%s/%s@%s",
(long) switch_epoch_time_now(NULL),
cp->uuid_str,
switch_channel_get_variable(channel, uvar1),
switch_channel_get_variable(channel, dvar1),
switch_channel_get_variable(br_a_channel, uvar2),
switch_channel_get_variable(br_a_channel, dvar2));
2011-10-11 20:13:23 +00:00
switch_channel_add_variable_var_check(br_a_channel, SWITCH_TRANSFER_HISTORY_VARIABLE, cp->transfer_source, SWITCH_FALSE, SWITCH_STACK_PUSH);
2011-12-08 23:33:31 +00:00
switch_channel_set_variable(br_a_channel, SWITCH_TRANSFER_SOURCE_VARIABLE, cp->transfer_source);
2011-10-11 20:13:23 +00:00
switch_core_session_rwunlock(br_a_session);
}
2011-10-11 20:13:23 +00:00
}
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,
sofia_dispatch_event_t *de,
tagi_t tags[])
{
const char *l_sdp = NULL, *r_sdp = NULL;
int offer_recv = 0, answer_recv = 0, offer_sent = 0, answer_sent = 0;
int ss_state = nua_callstate_init;
switch_channel_t *channel = NULL;
private_object_t *tech_pvt = NULL;
const char *replaces_str = NULL;
switch_core_session_t *other_session = NULL;
switch_channel_t *other_channel = NULL;
2011-06-15 15:29:44 +00:00
//private_object_t *other_tech_pvt = NULL;
char st[80] = "";
int is_dup_sdp = 0;
switch_event_t *s_event = NULL;
char *p;
tl_gets(tags,
NUTAG_CALLSTATE_REF(ss_state),
NUTAG_OFFER_RECV_REF(offer_recv),
NUTAG_ANSWER_RECV_REF(answer_recv),
NUTAG_OFFER_SENT_REF(offer_sent),
NUTAG_ANSWER_SENT_REF(answer_sent),
SIPTAG_REPLACES_STR_REF(replaces_str), SOATAG_LOCAL_SDP_STR_REF(l_sdp), SOATAG_REMOTE_SDP_STR_REF(r_sdp), TAG_END());
if (session) {
channel = switch_core_session_get_channel(session);
tech_pvt = switch_core_session_get_private(session);
if (!tech_pvt || !tech_pvt->nh) {
goto done;
}
}
2014-06-03 00:25:04 +00:00
if (tech_pvt) {
if ((status > 100 || switch_channel_test_flag(channel, CF_ANSWERED)) && status < 300 && !r_sdp && tech_pvt->mparams.last_sdp_str) {
r_sdp = tech_pvt->mparams.last_sdp_str;
}
tech_pvt->mparams.last_sdp_str = NULL;
}
2014-06-03 00:09:48 +00:00
if ((channel && (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA))) ||
(sofia_test_flag(profile, TFLAG_INB_NOMEDIA) || sofia_test_flag(profile, TFLAG_PROXY_MEDIA))) {
/* This marr in our code brought to you by people who can't read........ */
2012-12-18 22:06:29 +00:00
if (profile->ndlb & SM_NDLB_ALLOW_BAD_IANANAME && r_sdp && (p = (char *) switch_stristr("g729a/8000", r_sdp))) {
p += 4;
*p++ = '/';
*p++ = '8';
*p++ = '0';
*p++ = '0';
*p++ = '0';
*p++ = ' ';
}
}
if (ss_state == nua_callstate_terminated) {
2010-09-27 15:09:47 +00:00
if ((status == 300 || status == 301 || status == 302 || status == 305) && session) {
channel = switch_core_session_get_channel(session);
tech_pvt = switch_core_session_get_private(session);
if (!tech_pvt || !tech_pvt->nh) {
goto done;
}
if (tech_pvt->redirected) {
sofia_glue_do_invite(session);
goto done;
}
}
2012-08-21 05:04:58 +00:00
if (sofia_private) {
sofia_private->destroy_me = 1;
}
}
if (session) {
if (switch_channel_test_flag(channel, CF_ANSWERED) && (status == 180 || status == 183) && !r_sdp) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Channel %s skipping state [%s][%d]\n",
switch_channel_get_name(channel), nua_callstate_name(ss_state), status);
goto done;
} else if (switch_channel_test_flag(channel, CF_EARLY_MEDIA) && (status == 180 || status == 183) && r_sdp) {
2012-12-22 03:30:14 +00:00
switch_channel_set_flag(tech_pvt->channel, CF_REINVITE);
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Channel %s entering state [%s][%d]\n",
switch_channel_get_name(channel), nua_callstate_name(ss_state), status);
if (r_sdp) {
2013-07-17 22:08:03 +00:00
switch_channel_set_variable(channel, SWITCH_R_SDP_VARIABLE, r_sdp);
if (!(profile->mndlb & SM_NDLB_ALLOW_NONDUP_SDP) || (!zstr(tech_pvt->mparams.remote_sdp_str) && !strcmp(tech_pvt->mparams.remote_sdp_str, r_sdp))) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Duplicate SDP\n%s\n", r_sdp);
is_dup_sdp = 1;
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Remote SDP:\n%s\n", r_sdp);
tech_pvt->mparams.remote_sdp_str = switch_core_session_strdup(session, r_sdp);
//if ((sofia_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION) || switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND)) {
// switch_core_media_set_sdp_codec_string(session, r_sdp, status < 200 ? SDP_TYPE_REQUEST : SDP_TYPE_RESPONSE);
//}
sofia_glue_pass_sdp(tech_pvt, (char *) r_sdp);
2013-05-09 19:05:09 +00:00
sofia_set_flag(tech_pvt, TFLAG_NEW_SDP);
}
}
}
if (status == 988) {
goto done;
}
if (status == 183 && !r_sdp) {
2010-10-27 16:10:12 +00:00
if ((channel && switch_true(switch_channel_get_variable(channel, "sip_ignore_183nosdp"))) || sofia_test_pflag(profile, PFLAG_IGNORE_183NOSDP)) {
2011-04-26 17:06:11 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Ignoring 183 w/o sdp\n", channel ? switch_channel_get_name(channel) : "None");
goto done;
}
status = 180;
}
if (status == 180 && r_sdp) {
status = 183;
}
if (channel && profile->pres_type && ss_state == nua_callstate_ready && status == 200) {
const char* to_tag = "";
char *sql = NULL;
to_tag = switch_str_nil(switch_channel_get_variable(channel, "sip_to_tag"));
sql = switch_mprintf("update sip_dialogs set sip_to_tag='%q' "
"where uuid='%q' and sip_to_tag = ''", to_tag, switch_core_session_get_uuid(session));
if (mod_sofia_globals.debug_presence > 1) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "QUERY SQL %s\n", sql);
}
sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
}
2011-08-04 21:34:01 +00:00
if (channel && (status == 180 || status == 183) && switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
const char *val;
if ((val = switch_channel_get_variable(channel, "sip_auto_answer")) && switch_true(val)) {
nua_notify(nh, NUTAG_NEWSUB(1), NUTAG_WITH_THIS_MSG(de->data->e_msg),
NUTAG_SUBSTATE(nua_substate_terminated),SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"), SIPTAG_EVENT_STR("talk"), TAG_END());
2011-08-04 21:34:01 +00:00
}
}
state_process:
switch ((enum nua_callstate) ss_state) {
case nua_callstate_terminated:
case nua_callstate_terminating:
case nua_callstate_ready:
case nua_callstate_completed:
case nua_callstate_received:
case nua_callstate_proceeding:
case nua_callstate_completing:
if (!(session && channel && tech_pvt))
goto done;
default:
break;
}
switch ((enum nua_callstate) ss_state) {
case nua_callstate_init:
break;
case nua_callstate_authenticating:
break;
case nua_callstate_calling:
break;
case nua_callstate_proceeding:
2010-06-15 20:48:12 +00:00
switch (status) {
case 180:
switch_channel_mark_ring_ready(channel);
2010-06-15 20:48:12 +00:00
break;
case 182:
switch_channel_mark_ring_ready_value(channel, SWITCH_RING_READY_QUEUED);
break;
default:
break;
}
if (r_sdp) {
2013-10-31 15:35:53 +00:00
if (switch_channel_test_flag(channel, CF_PROXY_MODE) && r_sdp) {
char ibuf[35] = "", pbuf[35] = "";
const char *ptr;
if ((ptr = switch_stristr("c=IN IP4", r_sdp))) {
int i = 0;
ptr += 8;
while(*ptr == ' ') {
ptr++;
}
while(*ptr && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') {
ibuf[i++] = *ptr++;
}
switch_channel_set_variable(channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, ibuf);
}
if ((ptr = switch_stristr("m=audio", r_sdp))) {
int i = 0;
ptr += 7;
while(*ptr == ' ') {
ptr++;
}
while(*ptr && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') {
pbuf[i++] = *ptr++;
}
switch_channel_set_variable(channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, pbuf);
}
if (switch_channel_test_flag(channel, CF_PROXY_MEDIA) && switch_channel_direction(tech_pvt->channel) == SWITCH_CALL_DIRECTION_INBOUND) {
switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "PROXY MEDIA");
}
sofia_set_flag_locked(tech_pvt, TFLAG_EARLY_MEDIA);
switch_channel_mark_pre_answered(channel);
sofia_set_flag(tech_pvt, TFLAG_SDP);
2012-12-22 03:30:14 +00:00
if (switch_channel_test_flag(channel, CF_PROXY_MEDIA) || switch_channel_test_flag(channel, CF_REINVITE)) {
2012-12-18 22:06:29 +00:00
if (sofia_media_activate_rtp(tech_pvt) != SWITCH_STATUS_SUCCESS) {
goto done;
}
}
if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
other_channel = switch_core_session_get_channel(other_session);
if (!switch_channel_get_variable(other_channel, SWITCH_B_SDP_VARIABLE)) {
switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, r_sdp);
}
2010-11-15 17:22:25 +00:00
//switch_channel_pre_answer(other_channel);
switch_core_session_queue_indication(other_session, SWITCH_MESSAGE_INDICATE_PROGRESS);
switch_core_session_rwunlock(other_session);
}
goto done;
} else {
if (sofia_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION) && switch_channel_direction(tech_pvt->channel) == SWITCH_CALL_DIRECTION_INBOUND) {
switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "DELAYED NEGOTIATION");
2014-02-12 23:08:24 +00:00
} else if (switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "PROXY MEDIA");
switch_core_media_patch_sdp(tech_pvt->session);
if (sofia_media_activate_rtp(tech_pvt) != SWITCH_STATUS_SUCCESS) {
nua_respond(nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
switch_channel_hangup(channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION);
2014-02-13 15:45:57 +00:00
} else{
switch_channel_mark_pre_answered(channel);
}
2014-02-13 15:45:57 +00:00
} else {
2012-12-19 20:51:28 +00:00
if (sofia_media_tech_media(tech_pvt, (char *) r_sdp) != SWITCH_STATUS_SUCCESS) {
switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "CODEC NEGOTIATION ERROR");
nua_respond(nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
switch_channel_hangup(channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION);
}
}
goto done;
}
}
break;
case nua_callstate_completing:
2010-09-09 03:53:57 +00:00
{
2012-09-05 18:11:32 +00:00
int send_ack = 1;
2012-08-31 19:49:21 +00:00
if (!switch_channel_test_flag(channel, CF_ANSWERED)) {
const char *wait_for_ack = switch_channel_get_variable(channel, "sip_wait_for_aleg_ack");
if (switch_true(wait_for_ack)) {
switch_core_session_t *other_session;
if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
if (switch_core_session_compare(session, other_session)) {
private_object_t *other_tech_pvt = switch_core_session_get_private(other_session);
sofia_set_flag(other_tech_pvt, TFLAG_PASS_ACK);
2012-09-05 18:11:32 +00:00
send_ack = 0;
}
switch_core_session_rwunlock(other_session);
2012-09-05 18:11:32 +00:00
}
2012-08-31 19:49:21 +00:00
}
}
2011-09-12 19:26:42 +00:00
2013-01-07 16:27:28 +00:00
if (r_sdp && sofia_test_flag(tech_pvt, TFLAG_3PCC_INVITE) && !sofia_test_flag(tech_pvt, TFLAG_SDP)) {
sofia_set_flag(tech_pvt, TFLAG_SDP);
if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
other_channel = switch_core_session_get_channel(other_session);
//other_tech_pvt = switch_core_session_get_private(other_session);
if (!switch_channel_get_variable(other_channel, SWITCH_B_SDP_VARIABLE)) {
switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, r_sdp);
}
switch_core_session_queue_indication(other_session, SWITCH_MESSAGE_INDICATE_ANSWER);
switch_core_session_rwunlock(other_session);
}
goto done;
}
2012-09-05 18:11:32 +00:00
if (send_ack) {
tech_send_ack(nh, tech_pvt);
2012-09-05 18:48:52 +00:00
} else {
ss_state = nua_callstate_ready;
goto state_process;
2010-09-09 03:53:57 +00:00
}
2010-09-09 03:53:57 +00:00
}
goto done;
case nua_callstate_received:
if (!sofia_test_flag(tech_pvt, TFLAG_SDP)) {
if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
private_object_t *other_tech_pvt = switch_core_session_get_private(other_session);
2012-08-15 20:11:57 +00:00
int r = sofia_test_flag(other_tech_pvt, TFLAG_REINVITED);
switch_core_session_rwunlock(other_session);
2012-08-15 20:11:57 +00:00
if (r) {
/* Due to a race between simultaneous reinvites to both legs of a bridge,
an earlier call to nua_invite silently failed.
So we reject the incoming invite with a 491 and redo the failed outgoing invite. */
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
2012-08-15 20:11:57 +00:00
"Other leg already handling a reinvite, so responding with 491\n");
nua_respond(tech_pvt->nh, SIP_491_REQUEST_PENDING, TAG_END());
sofia_glue_do_invite(session);
goto done;
}
}
if (r_sdp && !sofia_test_flag(tech_pvt, TFLAG_SDP)) {
if (switch_channel_test_flag(channel, CF_PROXY_MODE)) {
switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "RECEIVED_NOMEDIA");
sofia_set_flag_locked(tech_pvt, TFLAG_READY);
if (switch_channel_get_state(channel) == CS_NEW) {
switch_channel_set_state(channel, CS_INIT);
}
sofia_set_flag(tech_pvt, TFLAG_SDP);
goto done;
} else if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA)) {
switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "PROXY MEDIA");
sofia_set_flag_locked(tech_pvt, TFLAG_READY);
if (switch_channel_get_state(channel) == CS_NEW) {
switch_channel_set_state(channel, CS_INIT);
}
} else if (sofia_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION)) {
switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "DELAYED NEGOTIATION");
sofia_set_flag_locked(tech_pvt, TFLAG_READY);
if (switch_channel_get_state(channel) == CS_NEW) {
switch_channel_set_state(channel, CS_INIT);
}
} else {
uint8_t match = 0;
if (tech_pvt->mparams.num_codecs) {
2013-05-17 20:39:21 +00:00
match = sofia_media_negotiate_sdp(session, r_sdp, SDP_TYPE_REQUEST);
}
2011-04-01 18:20:35 +00:00
if (!match) {
if (switch_channel_get_state(channel) != CS_NEW) {
nua_respond(tech_pvt->nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
}
} else {
nua_handle_t *bnh;
sip_replaces_t *replaces;
su_home_t *home = NULL;
switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "RECEIVED");
sofia_set_flag_locked(tech_pvt, TFLAG_READY);
if (switch_channel_get_state(channel) == CS_NEW) {
switch_channel_set_state(channel, CS_INIT);
2011-04-01 18:20:35 +00:00
} else {
nua_respond(tech_pvt->nh, SIP_200_OK, TAG_END());
}
sofia_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_SESSION_LOG(session), 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_partner_uuid(channel);
char *br_a = b_private->uuid;
if (br_b) {
switch_core_session_t *tmp;
2011-10-11 20:13:23 +00:00
if (switch_true(switch_channel_get_variable(channel, "recording_follow_transfer")) &&
(tmp = switch_core_session_locate(br_a))) {
switch_core_media_bug_transfer_recordings(session, tmp);
switch_core_session_rwunlock(tmp);
}
switch_channel_set_variable_printf(channel, "transfer_to", "att:%s", br_b);
2011-10-11 20:13:23 +00:00
mark_transfer_record(session, br_a, br_b);
switch_ivr_uuid_bridge(br_a, br_b);
switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER");
sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
switch_channel_clear_flag(channel, CF_LEG_HOLDING);
sofia_clear_flag_locked(tech_pvt, TFLAG_HOLD_LOCK);
switch_channel_hangup(channel, SWITCH_CAUSE_ATTENDED_TRANSFER);
} else {
switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER_ERROR");
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
}
} else {
switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER_ERROR");
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
}
nua_handle_unref(bnh);
}
su_home_unref(home);
home = NULL;
}
goto done;
}
switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "NO CODECS");
switch_channel_hangup(channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION);
}
} else {
2011-06-15 15:29:07 +00:00
if (sofia_test_pflag(profile, PFLAG_3PCC)) {
2012-02-24 21:18:44 +00:00
if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
2011-06-15 15:29:07 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "No SDP in INVITE and 3pcc=yes cannot work with bypass or proxy media, hanging up.\n");
switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "3PCC DISABLED");
switch_channel_hangup(channel, SWITCH_CAUSE_MANDATORY_IE_MISSING);
2012-02-24 21:18:44 +00:00
} else {
switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "RECEIVED_NOSDP");
switch_core_media_choose_port(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, 0);
2013-11-07 22:48:00 +00:00
switch_core_media_gen_local_sdp(session, SDP_TYPE_RESPONSE, NULL, 0, NULL, 0);
sofia_set_flag_locked(tech_pvt, TFLAG_3PCC);
switch_channel_set_state(channel, CS_HIBERNATE);
if (sofia_use_soa(tech_pvt)) {
nua_respond(tech_pvt->nh, SIP_200_OK,
SIPTAG_CONTACT_STR(tech_pvt->profile->url),
SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str),
SOATAG_REUSE_REJECTED(1),
SOATAG_ORDERED_USER(1), SOATAG_AUDIO_AUX("cn telephone-event"),
TAG_IF(sofia_test_pflag(profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)), TAG_END());
} else {
nua_respond(tech_pvt->nh, SIP_200_OK,
NUTAG_MEDIA_ENABLE(0),
SIPTAG_CONTACT_STR(tech_pvt->profile->url),
SIPTAG_CONTENT_TYPE_STR("application/sdp"), SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str), TAG_END());
}
2011-06-15 15:29:07 +00:00
}
2012-02-24 21:18:44 +00:00
} else if (sofia_test_pflag(profile, PFLAG_3PCC_PROXY)) {
//3PCC proxy mode delays the 200 OK until the call is answered
2011-06-15 15:29:07 +00:00
// so can be made to work with bypass media as we have time to find out what the other end thinks codec offer should be...
2012-02-24 21:18:44 +00:00
switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "RECEIVED_NOSDP");
sofia_set_flag_locked(tech_pvt, TFLAG_3PCC);
//switch_core_media_choose_port(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, 0);
//switch_core_media_gen_local_sdp(session, NULL, 0, NULL, 0);
2012-02-24 21:18:44 +00:00
sofia_set_flag(tech_pvt, TFLAG_LATE_NEGOTIATION);
//Moves into CS_INIT so call moves forward into the dialplan
switch_channel_set_state(channel, CS_INIT);
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "No SDP in INVITE and 3pcc not enabled, hanging up.\n");
switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "3PCC DISABLED");
switch_channel_hangup(channel, SWITCH_CAUSE_MANDATORY_IE_MISSING);
}
2012-02-24 21:18:44 +00:00
goto done;
}
} else if (tech_pvt && sofia_test_flag(tech_pvt, TFLAG_SDP) && !r_sdp) {
2011-06-15 15:10:37 +00:00
sofia_set_flag_locked(tech_pvt, TFLAG_NOSDP_REINVITE);
2011-06-15 16:16:04 +00:00
if ((switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) && sofia_test_pflag(profile, PFLAG_3PCC_PROXY)) {
2011-06-15 15:29:07 +00:00
sofia_set_flag_locked(tech_pvt, TFLAG_3PCC);
if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
2011-06-15 15:29:07 +00:00
switch_core_session_message_t *msg;
msg = switch_core_session_alloc(other_session, sizeof(*msg));
msg->message_id = SWITCH_MESSAGE_INDICATE_MEDIA_REDIRECT;
msg->from = __FILE__;
msg->string_arg = NULL;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Passing NOSDP to other leg.\n");
switch_core_session_queue_message(other_session, msg);
switch_core_session_rwunlock(other_session);
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
"NOSDP Re-INVITE to a proxy mode channel that is not in a bridge.\n");
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
}
goto done;
}
nua_respond(tech_pvt->nh, SIP_200_OK, TAG_END());
goto done;
} else {
ss_state = nua_callstate_completed;
goto state_process;
}
break;
case nua_callstate_early:
if (answer_recv) {
uint8_t match = 0;
sofia_set_flag_locked(tech_pvt, TFLAG_EARLY_MEDIA);
switch_channel_mark_pre_answered(channel);
sofia_set_flag(tech_pvt, TFLAG_SDP);
if (sofia_test_flag(tech_pvt, TFLAG_3PCC) && sofia_test_pflag(profile, PFLAG_3PCC_PROXY)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "3PCC-PROXY, Got my PRACK\n");
sofia_set_flag(tech_pvt, TFLAG_3PCC_HAS_ACK);
}
match = sofia_media_negotiate_sdp(session, r_sdp, SDP_TYPE_RESPONSE);
if (match) {
if (switch_core_media_choose_port(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, 0) != SWITCH_STATUS_SUCCESS) {
goto done;
}
switch_core_media_gen_local_sdp(session, SDP_TYPE_RESPONSE, NULL, 0, NULL, 0);
if (sofia_media_activate_rtp(tech_pvt) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Early Media RTP Error!\n");
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Processing updated SDP\n");
} else {
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Early Media Codec Error!\n");
}
}
break;
case nua_callstate_completed:
if (r_sdp) {
2011-06-15 15:29:07 +00:00
const char *var;
uint8_t match = 0, is_ok = 1, is_t38 = 0;
2012-12-22 17:51:03 +00:00
tech_pvt->mparams.hold_laps = 0;
if ((var = switch_channel_get_variable(channel, "sip_ignore_reinvites")) && switch_true(var)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Ignoring Re-invite\n");
nua_respond(tech_pvt->nh, SIP_200_OK, TAG_END());
goto done;
}
if (switch_stristr("m=image", r_sdp)) {
is_t38 = 1;
}
if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
switch_core_session_message_t *msg;
private_object_t *other_tech_pvt;
2012-07-05 16:42:07 +00:00
if (switch_channel_test_flag(channel, CF_PROXY_MODE) && !is_t38 && (profile->media_options & MEDIA_OPT_MEDIA_ON_HOLD)) {
2012-02-16 15:49:41 +00:00
if (switch_stristr("sendonly", r_sdp) || switch_stristr("0.0.0.0", r_sdp)) {
2012-12-22 17:51:03 +00:00
tech_pvt->mparams.hold_laps = 1;
2012-02-15 22:24:21 +00:00
switch_channel_set_variable(channel, SWITCH_R_SDP_VARIABLE, r_sdp);
switch_channel_clear_flag(channel, CF_PROXY_MODE);
switch_core_media_set_local_sdp(tech_pvt->session, NULL, SWITCH_FALSE);
2012-02-15 22:24:21 +00:00
if (!switch_channel_media_ready(channel)) {
if (switch_channel_direction(tech_pvt->channel) == SWITCH_CALL_DIRECTION_INBOUND) {
//const char *r_sdp = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE);
switch_core_media_prepare_codecs(tech_pvt->session, SWITCH_TRUE);
2012-12-19 20:51:28 +00:00
if (sofia_media_tech_media(tech_pvt, r_sdp) != SWITCH_STATUS_SUCCESS) {
2012-02-15 22:24:21 +00:00
switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "CODEC NEGOTIATION ERROR");
status = SWITCH_STATUS_FALSE;
switch_core_session_rwunlock(other_session);
goto done;
}
}
}
if (!switch_core_media_ready(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO)) {
switch_core_media_prepare_codecs(tech_pvt->session, SWITCH_FALSE);
if ((status = switch_core_media_choose_port(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, 0)) != SWITCH_STATUS_SUCCESS) {
2012-02-15 22:24:21 +00:00
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
switch_core_session_rwunlock(other_session);
goto done;
}
}
2013-11-07 22:48:00 +00:00
switch_core_media_gen_local_sdp(session, SDP_TYPE_RESPONSE, NULL, 0, NULL, 1);
2012-02-15 22:24:21 +00:00
if (sofia_use_soa(tech_pvt)) {
nua_respond(tech_pvt->nh, SIP_200_OK,
SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str),
2012-02-15 22:24:21 +00:00
SOATAG_REUSE_REJECTED(1),
SOATAG_ORDERED_USER(1), SOATAG_AUDIO_AUX("cn telephone-event"),
TAG_IF(sofia_test_pflag(profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)), TAG_END());
} else {
nua_respond(tech_pvt->nh, SIP_200_OK,
NUTAG_MEDIA_ENABLE(0),
SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
SIPTAG_CONTENT_TYPE_STR("application/sdp"), SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str), TAG_END());
}
switch_channel_set_flag(channel, CF_PROXY_MODE);
switch_yield(250000);
2012-02-15 22:24:21 +00:00
launch_media_on_hold(session);
2012-08-15 20:11:57 +00:00
switch_core_session_rwunlock(other_session);
2012-02-15 22:24:21 +00:00
goto done;
}
}
if (switch_channel_test_flag(channel, CF_PROXY_MEDIA) && !(tech_pvt->profile->mndlb & SM_NDLB_NEVER_PATCH_REINVITE)) {
2012-12-22 03:30:14 +00:00
if (switch_core_media_proxy_remote_addr(session, r_sdp) == SWITCH_STATUS_SUCCESS && !is_t38) {
nua_respond(tech_pvt->nh, SIP_200_OK, TAG_END());
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Audio params changed, NOT proxying re-invite.\n");
switch_core_session_rwunlock(other_session);
goto done;
}
}
other_tech_pvt = switch_core_session_get_private(other_session);
if(sofia_test_flag(other_tech_pvt, TFLAG_REINVITED)) {
/* The other leg won the reinvite race */
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Other leg already handling reinvite, so responding with 491\n");
nua_respond(tech_pvt->nh, SIP_491_REQUEST_PENDING, TAG_END());
2012-08-15 20:11:57 +00:00
switch_core_session_rwunlock(other_session);
goto done;
}
sofia_set_flag(tech_pvt, TFLAG_REINVITED);
msg = switch_core_session_alloc(other_session, sizeof(*msg));
msg->message_id = SWITCH_MESSAGE_INDICATE_MEDIA_REDIRECT;
msg->from = __FILE__;
msg->string_arg = switch_core_session_strdup(other_session, r_sdp);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Passing SDP to other leg.\n%s\n", r_sdp);
if (sofia_test_flag(tech_pvt, TFLAG_SIP_HOLD)) {
if (!switch_stristr("sendonly", r_sdp)) {
sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
switch_channel_clear_flag(channel, CF_LEG_HOLDING);
switch_channel_presence(tech_pvt->channel, "unknown", "unhold", NULL);
}
} else if (switch_stristr("sendonly", r_sdp)) {
const char *msg = "hold";
if (sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE)) {
const char *info = switch_channel_get_variable(channel, "presence_call_info");
if (info) {
if (switch_stristr("private", info)) {
msg = "hold-private";
}
}
}
sofia_set_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
switch_channel_set_flag(channel, CF_LEG_HOLDING);
switch_channel_presence(tech_pvt->channel, "unknown", msg, NULL);
}
switch_core_session_queue_message(other_session, msg);
switch_core_session_rwunlock(other_session);
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
"Re-INVITE to a no-media channel that is not in a bridge.\n");
is_ok = 0;
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
}
goto done;
} else {
if (switch_channel_test_app_flag_key("T38", tech_pvt->channel, CF_APP_T38_NEGOTIATED)) {
nua_respond(tech_pvt->nh, SIP_200_OK, TAG_END());
goto done;
}
2012-12-22 03:30:14 +00:00
switch_channel_set_flag(tech_pvt->channel, CF_REINVITE);
if (tech_pvt->mparams.num_codecs) {
2013-05-17 20:39:21 +00:00
match = sofia_media_negotiate_sdp(session, r_sdp, SDP_TYPE_REQUEST);
}
2011-06-09 15:22:40 +00:00
if (match && sofia_test_flag(tech_pvt, TFLAG_NOREPLY)) {
2011-06-09 15:57:04 +00:00
sofia_clear_flag(tech_pvt, TFLAG_NOREPLY);
2010-05-13 02:25:54 +00:00
goto done;
}
if (match) {
if (switch_core_media_choose_port(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, 0) != SWITCH_STATUS_SUCCESS) {
goto done;
}
2013-11-07 22:48:00 +00:00
switch_core_media_gen_local_sdp(session, SDP_TYPE_RESPONSE, NULL, 0, NULL, 0);
2012-12-18 22:06:29 +00:00
if (sofia_media_activate_rtp(tech_pvt) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Reinvite RTP Error!\n");
is_ok = 0;
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Processing updated SDP\n");
} else {
2012-12-22 03:30:14 +00:00
switch_channel_set_flag(tech_pvt->channel, CF_REINVITE);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Reinvite Codec Error!\n");
is_ok = 0;
}
}
if (is_ok) {
2012-12-19 02:40:00 +00:00
if (switch_core_session_local_crypto_key(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO)) {
2013-11-07 22:48:00 +00:00
switch_core_media_gen_local_sdp(session, SDP_TYPE_RESPONSE, NULL, 0, NULL, 0);
}
if (sofia_use_soa(tech_pvt)) {
nua_respond(tech_pvt->nh, SIP_200_OK,
SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str),
SOATAG_REUSE_REJECTED(1),
SOATAG_ORDERED_USER(1), SOATAG_AUDIO_AUX("cn telephone-event"),
TAG_IF(sofia_test_pflag(profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)), TAG_END());
} else {
nua_respond(tech_pvt->nh, SIP_200_OK,
NUTAG_MEDIA_ENABLE(0),
SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
SIPTAG_CONTENT_TYPE_STR("application/sdp"), SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str), TAG_END());
}
if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_REINVITE) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "Unique-ID", switch_core_session_get_uuid(session));
switch_event_fire(&s_event);
}
} else {
nua_respond(tech_pvt->nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
}
}
break;
case nua_callstate_ready:
2013-10-31 15:35:53 +00:00
if (!switch_channel_test_flag(channel, CF_PROXY_MODE) && !switch_channel_test_flag(channel, CF_PROXY_MEDIA) &&
2013-05-09 19:05:09 +00:00
r_sdp && (!is_dup_sdp || sofia_test_flag(tech_pvt, TFLAG_NEW_SDP)) && switch_core_media_ready(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO) && !sofia_test_flag(tech_pvt, TFLAG_NOSDP_REINVITE)) {
/* sdp changed since 18X w sdp, we're supposed to ignore it but we, of course, were pressured into supporting it */
uint8_t match = 0;
2013-05-09 19:05:09 +00:00
sofia_clear_flag(tech_pvt, TFLAG_NEW_SDP);
2012-12-22 03:30:14 +00:00
switch_channel_set_flag(tech_pvt->channel, CF_REINVITE);
if (tech_pvt->mparams.num_codecs) {
2013-11-25 18:08:17 +00:00
match = sofia_media_negotiate_sdp(session, r_sdp, SDP_TYPE_RESPONSE);
}
if (match) {
if (switch_core_media_choose_port(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, 0) != SWITCH_STATUS_SUCCESS) {
goto done;
}
2013-11-07 22:48:00 +00:00
switch_core_media_gen_local_sdp(session, SDP_TYPE_RESPONSE, NULL, 0, NULL, 0);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Processing updated SDP\n");
2012-12-22 03:30:14 +00:00
switch_channel_set_flag(tech_pvt->channel, CF_REINVITE);
2012-12-18 22:06:29 +00:00
if (sofia_media_activate_rtp(tech_pvt) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "RTP Error!\n");
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
goto done;
}
} else {
2012-12-22 03:30:14 +00:00
switch_channel_clear_flag(tech_pvt->channel, CF_REINVITE);
2010-06-14 19:12:14 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec Error! %s\n", r_sdp);
goto done;
}
}
if (r_sdp && sofia_test_flag(tech_pvt, TFLAG_NOSDP_REINVITE)) {
2011-06-15 15:29:07 +00:00
sofia_clear_flag_locked(tech_pvt, TFLAG_NOSDP_REINVITE);
if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
if (switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
2012-12-18 22:06:29 +00:00
if (sofia_media_activate_rtp(tech_pvt) != SWITCH_STATUS_SUCCESS) {
2011-06-15 15:29:07 +00:00
goto done;
}
}
if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
2011-06-15 15:29:07 +00:00
other_channel = switch_core_session_get_channel(other_session);
if (!switch_channel_get_variable(other_channel, SWITCH_B_SDP_VARIABLE)) {
switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, r_sdp);
}
2011-06-15 15:29:07 +00:00
if (sofia_test_flag(tech_pvt, TFLAG_3PCC) && sofia_test_pflag(profile, PFLAG_3PCC_PROXY)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "3PCC-PROXY, Got my ACK\n");
sofia_set_flag(tech_pvt, TFLAG_3PCC_HAS_ACK);
} else {
2013-01-07 16:27:28 +00:00
switch_core_session_message_t *msg;
if (sofia_test_pflag(profile, PFLAG_3PCC_REINVITE_BRIDGED_ON_ACK)) {
msg = switch_core_session_alloc(other_session, sizeof(*msg));
msg->message_id = SWITCH_MESSAGE_INDICATE_MEDIA_REDIRECT;
msg->from = __FILE__;
msg->string_arg = switch_core_session_strdup(other_session, r_sdp);
switch_core_session_queue_message(other_session, msg);
}
2011-06-15 15:29:07 +00:00
switch_core_session_queue_indication(other_session, SWITCH_MESSAGE_INDICATE_ANSWER);
}
switch_core_session_rwunlock(other_session);
}
} else {
2012-05-02 07:42:16 +00:00
uint8_t match = 0;
int is_ok = 1;
if (tech_pvt->mparams.num_codecs) {
2013-05-17 20:39:21 +00:00
match = sofia_media_negotiate_sdp(session, r_sdp, SDP_TYPE_REQUEST);
2012-05-02 07:42:16 +00:00
}
2012-05-02 07:42:16 +00:00
if (match) {
2012-12-22 03:30:14 +00:00
switch_channel_set_flag(tech_pvt->channel, CF_REINVITE);
2012-12-18 22:06:29 +00:00
if (sofia_media_activate_rtp(tech_pvt) != SWITCH_STATUS_SUCCESS) {
2012-05-02 07:42:16 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "RTP Error!\n");
switch_channel_set_variable(tech_pvt->channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "RTP ERROR");
is_ok = 0;
}
2012-12-22 03:30:14 +00:00
switch_channel_clear_flag(tech_pvt->channel, CF_REINVITE);
2012-05-02 07:42:16 +00:00
} else {
switch_channel_set_variable(tech_pvt->channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "CODEC NEGOTIATION ERROR");
is_ok = 0;
}
2012-05-02 07:42:16 +00:00
if (!is_ok) {
nua_respond(nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION);
}
2011-06-15 15:29:07 +00:00
}
goto done;
}
if (channel) {
switch_channel_clear_flag(channel, CF_REQ_MEDIA);
}
if (tech_pvt && nh == tech_pvt->nh2) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Cheater Reinvite!\n");
2012-12-22 03:30:14 +00:00
switch_channel_set_flag(tech_pvt->channel, CF_REINVITE);
tech_pvt->nh = tech_pvt->nh2;
tech_pvt->nh2 = NULL;
if (switch_core_media_choose_port(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, 0) == SWITCH_STATUS_SUCCESS) {
2012-12-18 22:06:29 +00:00
if (sofia_media_activate_rtp(tech_pvt) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cheater Reinvite RTP Error!\n");
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
}
}
goto done;
}
if (channel) {
2010-10-07 23:30:07 +00:00
if (sofia_test_flag(tech_pvt, TFLAG_EARLY_MEDIA) && !sofia_test_flag(tech_pvt, TFLAG_ANS)) {
sofia_set_flag_locked(tech_pvt, TFLAG_ANS);
sofia_set_flag(tech_pvt, TFLAG_SDP);
switch_channel_mark_answered(channel);
if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
2010-11-15 17:22:25 +00:00
//other_channel = switch_core_session_get_channel(other_session);
//switch_channel_answer(other_channel);
switch_core_session_queue_indication(other_session, SWITCH_MESSAGE_INDICATE_ANSWER);
switch_core_session_rwunlock(other_session);
}
}
goto done;
}
if (!r_sdp && !sofia_test_flag(tech_pvt, TFLAG_SDP)) {
r_sdp = (const char *) switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE);
}
if (r_sdp && !sofia_test_flag(tech_pvt, TFLAG_SDP)) {
if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
sofia_set_flag_locked(tech_pvt, TFLAG_ANS);
sofia_set_flag_locked(tech_pvt, TFLAG_SDP);
switch_channel_mark_answered(channel);
if (switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
2012-12-18 22:06:29 +00:00
if (sofia_media_activate_rtp(tech_pvt) != SWITCH_STATUS_SUCCESS) {
goto done;
}
}
if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
other_channel = switch_core_session_get_channel(other_session);
if (!switch_channel_get_variable(other_channel, SWITCH_B_SDP_VARIABLE)) {
switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, r_sdp);
}
2010-11-15 17:22:25 +00:00
//switch_channel_answer(other_channel);
switch_core_session_queue_indication(other_session, SWITCH_MESSAGE_INDICATE_ANSWER);
switch_core_session_rwunlock(other_session);
}
2011-06-15 15:29:07 +00:00
if (sofia_test_flag(tech_pvt, TFLAG_3PCC) && sofia_test_pflag(profile, PFLAG_3PCC_PROXY)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "3PCC-PROXY, Got my ACK\n");
sofia_set_flag(tech_pvt, TFLAG_3PCC_HAS_ACK);
}
goto done;
} else {
uint8_t match = 0;
if (tech_pvt->mparams.num_codecs) {
2013-05-17 20:39:21 +00:00
match = sofia_media_negotiate_sdp(session, r_sdp, SDP_TYPE_RESPONSE);
}
sofia_set_flag_locked(tech_pvt, TFLAG_ANS);
if (match) {
2012-03-29 23:37:10 +00:00
switch_channel_check_zrtp(channel);
if (switch_core_media_choose_port(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, 0) == SWITCH_STATUS_SUCCESS) {
2012-12-18 22:06:29 +00:00
if (sofia_media_activate_rtp(tech_pvt) == SWITCH_STATUS_SUCCESS) {
switch_channel_mark_answered(channel);
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "RTP Error!\n");
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
}
if (sofia_test_flag(tech_pvt, TFLAG_3PCC)) {
/* Check if we are in 3PCC proxy mode, if so then set the flag to indicate we received the ack */
if (sofia_test_pflag(profile, PFLAG_3PCC_PROXY)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "3PCC-PROXY, Got my ACK\n");
sofia_set_flag(tech_pvt, TFLAG_3PCC_HAS_ACK);
} else if (switch_channel_get_state(channel) == CS_HIBERNATE) {
sofia_set_flag_locked(tech_pvt, TFLAG_READY);
switch_channel_set_state(channel, CS_INIT);
sofia_set_flag(tech_pvt, TFLAG_SDP);
}
}
goto done;
}
}
switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "NO CODECS");
switch_channel_hangup(channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION);
}
}
}
break;
case nua_callstate_terminating:
if (status == 488 || switch_channel_get_state(channel) == CS_HIBERNATE) {
tech_pvt->q850_cause = SWITCH_CAUSE_MANDATORY_IE_MISSING;
}
case nua_callstate_terminated:
sofia_set_flag_locked(tech_pvt, TFLAG_BYE);
if (sofia_test_flag(tech_pvt, TFLAG_NOHUP)) {
sofia_clear_flag_locked(tech_pvt, TFLAG_NOHUP);
} else if (switch_channel_up(channel)) {
int cause;
if (tech_pvt->q850_cause) {
cause = tech_pvt->q850_cause;
} else {
cause = sofia_glue_sip_cause_to_freeswitch(status);
}
if (status) {
switch_snprintf(st, sizeof(st), "%d", status);
switch_channel_set_variable(channel, "sip_term_status", st);
switch_snprintf(st, sizeof(st), "sip:%d", status);
switch_channel_set_variable(channel, SWITCH_PROTO_SPECIFIC_HANGUP_CAUSE_VARIABLE, st);
if (phrase) {
switch_channel_set_variable_partner(channel, "sip_hangup_phrase", phrase);
}
sofia_glue_set_extra_headers(session, sip, SOFIA_SIP_BYE_HEADER_PREFIX);
}
switch_snprintf(st, sizeof(st), "%d", cause);
switch_channel_set_variable(channel, "sip_term_cause", st);
switch_channel_hangup(channel, cause);
ss_state = nua_callstate_terminated;
}
if (ss_state == nua_callstate_terminated) {
if (tech_pvt->sofia_private) {
tech_pvt->sofia_private = NULL;
}
tech_pvt->nh = NULL;
if (nh) {
nua_handle_bind(nh, NULL);
nua_handle_destroy(nh);
}
}
break;
}
done:
2010-06-18 22:09:26 +00:00
if ((enum nua_callstate) ss_state == nua_callstate_ready && channel && session && tech_pvt) {
2011-07-16 07:33:39 +00:00
sofia_set_flag(tech_pvt, TFLAG_SIMPLIFY);
2010-06-18 22:09:26 +00:00
}
return;
}
typedef struct {
char *exten;
char *exten_with_params;
char *event;
char *reply_uuid;
char *bridge_to_uuid;
switch_event_t *vars;
switch_memory_pool_t *pool;
} nightmare_xfer_helper_t;
void *SWITCH_THREAD_FUNC nightmare_xfer_thread_run(switch_thread_t *thread, void *obj)
{
nightmare_xfer_helper_t *nhelper = (nightmare_xfer_helper_t *) obj;
switch_memory_pool_t *pool;
switch_status_t status = SWITCH_STATUS_FALSE;
switch_core_session_t *session, *a_session;
if ((a_session = switch_core_session_locate(nhelper->bridge_to_uuid))) {
switch_core_session_t *tsession = NULL;
switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING;
uint32_t timeout = 60;
char *tuuid_str;
if ((session = switch_core_session_locate(nhelper->reply_uuid))) {
private_object_t *tech_pvt = switch_core_session_get_private(session);
switch_channel_t *channel_a = switch_core_session_get_channel(session);
if ((status = switch_ivr_originate(NULL, &tsession, &cause, nhelper->exten_with_params, timeout, NULL, NULL, NULL,
switch_channel_get_caller_profile(channel_a), nhelper->vars, SOF_NONE, NULL)) == SWITCH_STATUS_SUCCESS) {
if (switch_channel_up(channel_a)) {
if (switch_true(switch_channel_get_variable(channel_a, "recording_follow_transfer"))) {
switch_core_media_bug_transfer_recordings(session, a_session);
}
tuuid_str = switch_core_session_get_uuid(tsession);
switch_channel_set_variable_printf(channel_a, "transfer_to", "att:%s", tuuid_str);
2011-10-11 20:13:23 +00:00
mark_transfer_record(session, nhelper->bridge_to_uuid, tuuid_str);
switch_ivr_uuid_bridge(nhelper->bridge_to_uuid, tuuid_str);
switch_channel_set_variable(channel_a, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER");
} else {
switch_channel_hangup(switch_core_session_get_channel(tsession), SWITCH_CAUSE_ORIGINATOR_CANCEL);
status = SWITCH_STATUS_FALSE;
}
switch_core_session_rwunlock(tsession);
}
if (status == SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "The nightmare is over.....\n");
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "1 .. 2 .. Freddie's commin' for you...\n");
}
nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
NUTAG_SUBSTATE(nua_substate_terminated),SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"),
SIPTAG_PAYLOAD_STR(status == SWITCH_STATUS_SUCCESS ? "SIP/2.0 200 OK\r\n" :
"SIP/2.0 403 Forbidden\r\n"), SIPTAG_EVENT_STR(nhelper->event), TAG_END());
switch_core_session_rwunlock(session);
}
switch_core_session_rwunlock(a_session);
}
switch_event_destroy(&nhelper->vars);
pool = nhelper->pool;
switch_core_destroy_memory_pool(&pool);
return NULL;
}
static void launch_nightmare_xfer(nightmare_xfer_helper_t *nhelper)
{
switch_thread_t *thread;
switch_threadattr_t *thd_attr = NULL;
switch_threadattr_create(&thd_attr, nhelper->pool);
switch_threadattr_detach_set(thd_attr, 1);
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
switch_thread_create(&thread, thd_attr, nightmare_xfer_thread_run, nhelper, nhelper->pool);
}
/*---------------------------------------*/
static switch_status_t xfer_hanguphook(switch_core_session_t *session)
{
switch_channel_t *channel = switch_core_session_get_channel(session);
switch_channel_state_t state = switch_channel_get_state(channel);
if (state == CS_HANGUP) {
switch_core_session_t *ksession;
const char *uuid = switch_channel_get_variable(channel, "att_xfer_kill_uuid");
if (uuid && (ksession = switch_core_session_force_locate(uuid))) {
switch_channel_t *kchannel = switch_core_session_get_channel(ksession);
switch_channel_clear_flag(kchannel, CF_XFER_ZOMBIE);
switch_channel_clear_flag(kchannel, CF_TRANSFER);
if (switch_channel_up(kchannel)) {
switch_channel_hangup(kchannel, SWITCH_CAUSE_NORMAL_CLEARING);
}
switch_core_session_rwunlock(ksession);
}
switch_core_event_hook_remove_state_change(session, xfer_hanguphook);
}
return SWITCH_STATUS_SUCCESS;
}
nua_handle_t *sofia_global_nua_handle_by_replaces(sip_replaces_t *replaces)
{
nua_handle_t *nh = NULL;
switch_hash_index_t *hi;
const void *var;
void *val;
sofia_profile_t *profile;
switch_mutex_lock(mod_sofia_globals.hash_mutex);
if (mod_sofia_globals.profile_hash) {
2014-04-01 22:21:29 +00:00
for (hi = switch_core_hash_first(mod_sofia_globals.profile_hash); hi; hi = switch_core_hash_next(&hi)) {
switch_core_hash_this(hi, &var, NULL, &val);
if ((profile = (sofia_profile_t *) val)) {
if (!(nh = nua_handle_by_replaces(profile->nua, replaces))) {
nh = nua_handle_by_call_id(profile->nua, replaces->rp_call_id);
}
if (nh)
break;
}
}
2014-04-01 22:21:29 +00:00
switch_safe_free(hi);
}
switch_mutex_unlock(mod_sofia_globals.hash_mutex);
return nh;
}
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,
sofia_dispatch_event_t *de, tagi_t tags[])
{
/* Incoming refer */
sip_from_t const *from;
2011-04-22 21:43:29 +00:00
//sip_to_t const *to;
sip_refer_to_t const *refer_to;
private_object_t *tech_pvt = switch_core_session_get_private(session);
char *etmp = NULL, *exten = 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;
nightmare_xfer_helper_t *nightmare_xfer_helper;
switch_memory_pool_t *npool;
if (!(profile->mflags & MFLAG_REFER)) {
nua_respond(nh, SIP_403_FORBIDDEN, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
goto done;
}
if (!sip->sip_cseq || !(etmp = switch_mprintf("refer;id=%u", sip->sip_cseq->cs_seq))) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Memory Error!\n");
goto done;
}
2012-07-27 20:07:11 +00:00
2014-06-05 18:49:50 +00:00
if ((refer_to = sip->sip_refer_to)) {
full_ref_to = sip_header_as_string(home, (void *) sip->sip_refer_to);
}
if (sofia_test_pflag(profile, PFLAG_PROXY_REFER)) {
2014-06-05 18:49:50 +00:00
switch_core_session_t *other_session;
if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
2014-06-05 18:49:50 +00:00
switch_core_session_message_t *msg;
msg = switch_core_session_alloc(other_session, sizeof(*msg));
MESSAGE_STAMP_FFL(msg);
msg->message_id = SWITCH_MESSAGE_INDICATE_DEFLECT;
msg->string_arg = switch_core_session_strdup(other_session, full_ref_to);
msg->from = __FILE__;
switch_core_session_queue_message(other_session, msg);
switch_core_session_rwunlock(other_session);
nua_respond(nh, SIP_202_ACCEPTED, NUTAG_WITH_THIS_MSG(de->data->e_msg), SIPTAG_EXPIRES_STR("60"), TAG_END());
goto done;
}
}
from = sip->sip_from;
2011-04-22 21:43:29 +00:00
//to = sip->sip_to;
home = su_home_new(sizeof(*home));
switch_assert(home != NULL);
nua_respond(nh, SIP_202_ACCEPTED, NUTAG_WITH_THIS_MSG(de->data->e_msg), SIPTAG_EXPIRES_STR("60"), TAG_END());
switch_channel_set_variable(tech_pvt->channel, SOFIA_REPLACES_HEADER, NULL);
if (sip->sip_referred_by) {
full_ref_by = sip_header_as_string(home, (void *) sip->sip_referred_by);
}
2014-06-05 18:49:50 +00:00
if (refer_to) {
2012-07-11 20:15:43 +00:00
char *rep = NULL;
if (sofia_test_pflag(profile, PFLAG_FULL_ID)) {
exten = switch_core_session_sprintf(session, "%s@%s", (char *) refer_to->r_url->url_user, (char *) refer_to->r_url->url_host);
} else {
exten = (char *) refer_to->r_url->url_user;
}
2014-02-28 19:13:29 +00:00
if (refer_to->r_url->url_params) {
switch_channel_set_variable(tech_pvt->channel, "sip_refer_to_params", refer_to->r_url->url_params);
}
2013-10-24 19:29:29 +00:00
switch_core_session_queue_indication(session, SWITCH_MESSAGE_REFER_EVENT);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Process REFER to [%s@%s]\n", exten, (char *) refer_to->r_url->url_host);
2013-04-02 04:02:29 +00:00
switch_channel_set_variable(tech_pvt->channel, "transfer_disposition", "recv_replace");
2012-07-11 20:15:43 +00:00
if (refer_to->r_url && refer_to->r_url->url_headers) {
rep = (char *) switch_stristr("Replaces=", refer_to->r_url->url_headers);
}
2012-07-27 20:07:11 +00:00
if (rep) {
sip_replaces_t *replaces;
nua_handle_t *bnh = NULL;
if (rep) {
const char *br_a = NULL, *br_b = NULL;
char *buf;
char *p;
rep = switch_core_session_strdup(session, rep + 9);
if ((buf = switch_core_session_alloc(session, strlen(rep) + 1))) {
rep = url_unescape(buf, (const char *) rep);
if ((p = strchr(rep, ';'))) {
*p = '\0';
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Replaces: [%s]\n", rep);
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Memory Error!\n");
goto done;
}
if ((replaces = sip_replaces_make(home, rep))) {
if (!(bnh = nua_handle_by_replaces(nua, replaces))) {
if (!(bnh = nua_handle_by_call_id(nua, replaces->rp_call_id))) {
bnh = sofia_global_nua_handle_by_replaces(replaces);
}
}
}
if (bnh) {
sofia_private_t *b_private = NULL;
private_object_t *b_tech_pvt = NULL;
switch_core_session_t *b_session = NULL;
switch_channel_set_variable(channel_a, SOFIA_REPLACES_HEADER, rep);
if ((b_private = nua_handle_magic(bnh))) {
2011-05-28 01:41:31 +00:00
int deny_refer_requests = 0;
if (!(b_session = switch_core_session_locate(b_private->uuid))) {
goto done;
}
b_tech_pvt = (private_object_t *) switch_core_session_get_private(b_session);
channel_b = switch_core_session_get_channel(b_session);
2013-04-29 15:09:14 +00:00
switch_channel_set_variable(channel_a, "refer_uuid", b_private->uuid);
2013-04-02 04:02:29 +00:00
switch_channel_set_variable(channel_b, "transfer_disposition", "replaced");
br_a = switch_channel_get_partner_uuid(channel_a);
br_b = switch_channel_get_partner_uuid(channel_b);
if (!switch_ivr_uuid_exists(br_a)) {
br_a = NULL;
}
if (!switch_ivr_uuid_exists(br_b)) {
br_b = NULL;
}
2011-05-28 01:41:31 +00:00
if (channel_a && switch_true(switch_channel_get_variable(channel_a, "deny_refer_requests"))) {
deny_refer_requests = 1;
}
if (!deny_refer_requests && channel_b && switch_true(switch_channel_get_variable(channel_b, "deny_refer_requests"))) {
deny_refer_requests = 1;
}
if (!deny_refer_requests && br_a) {
switch_core_session_t *a_session;
if ((a_session = switch_core_session_locate(br_a))) {
switch_channel_t *a_channel = switch_core_session_get_channel(a_session);
if (a_channel && switch_true(switch_channel_get_variable(a_channel, "deny_refer_requests"))) {
deny_refer_requests = 1;
}
switch_core_session_rwunlock(a_session);
}
}
if (!deny_refer_requests && br_b) {
switch_core_session_t *b_session;
if ((b_session = switch_core_session_locate(br_b))) {
switch_channel_t *b_channel = switch_core_session_get_channel(b_session);
if (b_channel && switch_true(switch_channel_get_variable(b_channel, "deny_refer_requests"))) {
deny_refer_requests = 1;
}
switch_core_session_rwunlock(b_session);
}
}
if (deny_refer_requests) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Denying Attended Transfer, variable [deny_refer_requests] was set to true\n");
nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("message/sipfrag;version=2.0"),
NUTAG_SUBSTATE(nua_substate_terminated),SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"),
2011-05-28 01:41:31 +00:00
SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden\r\n"), SIPTAG_EVENT_STR(etmp), TAG_END());
} else if (switch_channel_test_flag(channel_b, CF_ORIGINATOR)) {
switch_core_session_t *a_session;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE,
"Attended Transfer on originating session %s\n", switch_core_session_get_uuid(b_session));
switch_channel_set_variable_printf(channel_b, "transfer_to", "satt:%s", br_a);
switch_channel_set_variable(channel_b, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER");
sofia_clear_flag_locked(b_tech_pvt, TFLAG_SIP_HOLD);
switch_channel_clear_flag(channel_b, CF_LEG_HOLDING);
sofia_clear_flag_locked(tech_pvt, TFLAG_HOLD_LOCK);
switch_channel_set_variable(channel_b, SWITCH_HOLDING_UUID_VARIABLE, br_a);
switch_channel_set_flag(channel_b, CF_XFER_ZOMBIE);
switch_channel_set_flag(channel_b, CF_TRANSFER);
if ((a_session = switch_core_session_locate(br_a))) {
const char *moh = profile->hold_music;
switch_channel_t *a_channel = switch_core_session_get_channel(a_session);
switch_caller_profile_t *prof = switch_channel_get_caller_profile(channel_b);
const char *tmp;
switch_core_event_hook_add_state_change(a_session, xfer_hanguphook);
switch_channel_set_variable(a_channel, "att_xfer_kill_uuid", switch_core_session_get_uuid(b_session));
switch_channel_set_variable(a_channel, "att_xfer_destination_number", prof->destination_number);
switch_channel_set_variable(a_channel, "att_xfer_callee_id_name", prof->callee_id_name);
switch_channel_set_variable(a_channel, "att_xfer_callee_id_number", prof->callee_id_number);
if (profile->media_options & MEDIA_OPT_BYPASS_AFTER_ATT_XFER) {
switch_channel_set_flag(a_channel, CF_BYPASS_MEDIA_AFTER_BRIDGE);
}
if ((tmp = switch_channel_get_hold_music(a_channel))) {
moh = tmp;
}
if (!zstr(moh) && !strcasecmp(moh, "silence")) {
moh = NULL;
}
if (moh) {
char *xdest;
xdest = switch_core_session_sprintf(a_session, "endless_playback:%s,park", moh);
switch_ivr_session_transfer(a_session, xdest, "inline", NULL);
} else {
switch_ivr_session_transfer(a_session, "park", "inline", NULL);
}
switch_core_session_rwunlock(a_session);
nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("message/sipfrag;version=2.0"),
NUTAG_SUBSTATE(nua_substate_terminated),SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"), SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK\r\n"), SIPTAG_EVENT_STR(etmp),
TAG_END());
if (b_tech_pvt && !sofia_test_flag(b_tech_pvt, TFLAG_BYE)) {
char *q850 = NULL;
const char *val = NULL;
sofia_set_flag_locked(b_tech_pvt, TFLAG_BYE);
val = switch_channel_get_variable(tech_pvt->channel, "disable_q850_reason");
if (!val || switch_true(val)) {
q850 = switch_core_session_sprintf(a_session, "Q.850;cause=16;text=\"normal_clearing\"");
}
nua_bye(b_tech_pvt->nh,
TAG_IF(!zstr(q850), SIPTAG_REASON_STR(q850)),
TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), TAG_END());
}
} else {
nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("message/sipfrag;version=2.0"),
NUTAG_SUBSTATE(nua_substate_terminated),SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"),
SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden\r\n"), SIPTAG_EVENT_STR(etmp), TAG_END());
}
} else if (br_a && br_b) {
switch_core_session_t *tmp = NULL;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Attended Transfer [%s][%s]\n",
switch_str_nil(br_a), switch_str_nil(br_b));
if ((tmp = switch_core_session_locate(br_b))) {
switch_channel_t *tchannel = switch_core_session_get_channel(tmp);
if ((profile->media_options & MEDIA_OPT_BYPASS_AFTER_ATT_XFER)) {
switch_channel_set_flag(tchannel, CF_BYPASS_MEDIA_AFTER_BRIDGE);
}
2013-04-02 04:02:29 +00:00
switch_channel_set_variable(tchannel, "transfer_disposition", "bridge");
switch_channel_set_flag(tchannel, CF_ATTENDED_TRANSFER);
switch_core_session_rwunlock(tmp);
}
if ((profile->media_options & MEDIA_OPT_BYPASS_AFTER_ATT_XFER) && (tmp = switch_core_session_locate(br_a))) {
switch_channel_t *tchannel = switch_core_session_get_channel(tmp);
switch_channel_set_flag(tchannel, CF_BYPASS_MEDIA_AFTER_BRIDGE);
switch_core_session_rwunlock(tmp);
}
if (switch_true(switch_channel_get_variable(channel_a, "recording_follow_transfer")) &&
(tmp = switch_core_session_locate(br_a))) {
2013-04-02 04:02:29 +00:00
switch_channel_set_variable(switch_core_session_get_channel(tmp), "transfer_disposition", "bridge");
switch_core_media_bug_transfer_recordings(session, tmp);
switch_core_session_rwunlock(tmp);
}
2011-05-31 18:10:37 +00:00
if (switch_true(switch_channel_get_variable(channel_b, "recording_follow_transfer")) &&
2011-05-31 18:10:37 +00:00
(tmp = switch_core_session_locate(br_b))) {
switch_core_media_bug_transfer_recordings(b_session, tmp);
switch_core_session_rwunlock(tmp);
}
switch_channel_set_variable_printf(channel_a, "transfer_to", "att:%s", br_b);
2013-04-02 04:02:29 +00:00
mark_transfer_record(session, br_a, br_b);
2013-04-02 04:02:29 +00:00
switch_ivr_uuid_bridge(br_a, br_b);
switch_channel_set_variable(channel_b, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER");
nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("message/sipfrag;version=2.0"),
NUTAG_SUBSTATE(nua_substate_terminated),SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"), SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK\r\n"), SIPTAG_EVENT_STR(etmp),
TAG_END());
sofia_clear_flag_locked(b_tech_pvt, TFLAG_SIP_HOLD);
switch_channel_clear_flag(channel_b, CF_LEG_HOLDING);
sofia_clear_flag_locked(tech_pvt, TFLAG_HOLD_LOCK);
switch_channel_set_variable(channel_b, "park_timeout", "2:attended_transfer");
switch_channel_set_state(channel_b, CS_PARK);
} else {
if (!br_a && !br_b) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
"Cannot transfer channels that are not in a bridge.\n");
nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("message/sipfrag;version=2.0"),
NUTAG_SUBSTATE(nua_substate_terminated),SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"), SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden\r\n"),
SIPTAG_EVENT_STR(etmp), TAG_END());
} else {
switch_core_session_t *t_session, *hup_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;
hup_session = b_session;
} 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;
hup_session = session;
sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
switch_channel_clear_flag(tech_pvt->channel, CF_LEG_HOLDING);
sofia_clear_flag_locked(h_tech_pvt, TFLAG_SIP_HOLD);
switch_channel_clear_flag(h_tech_pvt->channel, CF_LEG_HOLDING);
switch_channel_hangup(channel_b, SWITCH_CAUSE_ATTENDED_TRANSFER);
}
if (t_session) {
switch_channel_t *t_channel = switch_core_session_get_channel(t_session);
const char *idest = switch_channel_get_variable(hup_channel, "inline_destination");
ext = switch_channel_get_variable(hup_channel, "destination_number");
if (!zstr(full_ref_by)) {
switch_channel_set_variable(t_channel, SOFIA_SIP_HEADER_PREFIX "Referred-By", full_ref_by);
}
if (!zstr(full_ref_to)) {
switch_channel_set_variable(t_channel, SOFIA_REFER_TO_VARIABLE, full_ref_to);
}
if (switch_true(switch_channel_get_variable(hup_channel, "recording_follow_transfer"))) {
switch_core_media_bug_transfer_recordings(hup_session, t_session);
}
if (idest) {
switch_ivr_session_transfer(t_session, idest, "inline", NULL);
} else {
switch_ivr_session_transfer(t_session, ext, NULL, NULL);
}
nua_notify(tech_pvt->nh,
NUTAG_NEWSUB(1),
SIPTAG_CONTENT_TYPE_STR("message/sipfrag;version=2.0"),
NUTAG_SUBSTATE(nua_substate_terminated),SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"),
SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK\r\n"), 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_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Session to transfer to not found.\n");
nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("message/sipfrag;version=2.0"),
NUTAG_SUBSTATE(nua_substate_terminated),SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"),
SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden\r\n"), SIPTAG_EVENT_STR(etmp), TAG_END());
}
}
}
if (b_session) {
switch_core_session_rwunlock(b_session);
}
}
nua_handle_unref(bnh);
} else { /* the other channel is on a different box, we have to go find them */
if (exten && (br_a = switch_channel_get_partner_uuid(channel_a))) {
switch_core_session_t *a_session;
switch_channel_t *channel = switch_core_session_get_channel(session);
if ((a_session = switch_core_session_locate(br_a))) {
const char *port = NULL;
const char *rep_h = NULL;
if (refer_to && refer_to->r_url && refer_to->r_url->url_port) {
port = refer_to->r_url->url_port;
}
channel = switch_core_session_get_channel(a_session);
exten = switch_core_session_sprintf(session, "sofia/%s/sip:%s@%s%s%s",
profile->name, refer_to->r_url->url_user,
refer_to->r_url->url_host, port ? ":" : "", port ? port : "");
switch_core_new_memory_pool(&npool);
nightmare_xfer_helper = switch_core_alloc(npool, sizeof(*nightmare_xfer_helper));
nightmare_xfer_helper->exten = switch_core_strdup(npool, exten);
if (refer_to->r_url && (refer_to->r_url->url_params || refer_to->r_url->url_headers)) {
if (refer_to->r_url->url_headers) {
nightmare_xfer_helper->exten_with_params = switch_core_sprintf(npool,
"{sip_invite_params=%s?%s}%s",
refer_to->r_url->url_params ? refer_to->r_url->
url_params : "", refer_to->r_url->url_headers, exten);
} else {
nightmare_xfer_helper->exten_with_params = switch_core_sprintf(npool,
"{sip_invite_params=%s}%s", refer_to->r_url->url_params,
exten);
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "INVITE RURI '%s'\n", nightmare_xfer_helper->exten_with_params);
} else {
nightmare_xfer_helper->exten_with_params = nightmare_xfer_helper->exten;
}
nightmare_xfer_helper->event = switch_core_strdup(npool, etmp);
nightmare_xfer_helper->reply_uuid = switch_core_strdup(npool, switch_core_session_get_uuid(session));
nightmare_xfer_helper->bridge_to_uuid = switch_core_strdup(npool, br_a);
nightmare_xfer_helper->pool = npool;
if (refer_to->r_url && refer_to->r_url->url_headers) {
char *h, *v, *hp;
p = switch_core_session_strdup(session, refer_to->r_url->url_headers);
while (p && *p) {
h = p;
if ((p = strchr(p, '='))) {
*p++ = '\0';
v = p;
if ((p = strchr(p, '&'))) {
*p++ = '\0';
}
url_unescape(h, (const char *) h);
url_unescape(v, (const char *) v);
if (strcasecmp("Replaces", h)) {
hp = switch_core_session_sprintf(session, "%s%s", SOFIA_SIP_HEADER_PREFIX, h);
switch_channel_set_variable(channel, hp, v);
} else {
// use this one instead of rep value from above to keep all parameters
switch_channel_set_variable(channel, SOFIA_REPLACES_HEADER, v);
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Exporting replaces URL header [%s:%s]\n",
h, v);
}
}
}
switch_event_create(&nightmare_xfer_helper->vars, SWITCH_EVENT_CHANNEL_DATA);
rep_h = switch_channel_get_variable(channel, SOFIA_REPLACES_HEADER);
if (rep_h) {
switch_event_add_header_string(nightmare_xfer_helper->vars, SWITCH_STACK_BOTTOM, SOFIA_REPLACES_HEADER, rep_h);
} else {
switch_event_add_header_string(nightmare_xfer_helper->vars, SWITCH_STACK_BOTTOM, SOFIA_REPLACES_HEADER, rep);
}
if (!zstr(full_ref_by)) {
switch_event_add_header_string(nightmare_xfer_helper->vars, SWITCH_STACK_BOTTOM, "Referred-By", full_ref_by);
}
if (!zstr(full_ref_to)) {
switch_event_add_header_string(nightmare_xfer_helper->vars, SWITCH_STACK_BOTTOM, SOFIA_REFER_TO_VARIABLE, full_ref_to);
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Good Luck, you'll need it......\n");
launch_nightmare_xfer(nightmare_xfer_helper);
switch_core_session_rwunlock(a_session);
} else {
goto error;
}
} else {
error:
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), 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, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("message/sipfrag;version=2.0"),
NUTAG_SUBSTATE(nua_substate_terminated),SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"), SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden\r\n"), SIPTAG_EVENT_STR(etmp),
TAG_END());
}
}
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot parse Replaces!\n");
}
goto done;
}
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Missing Refer-To\n");
goto done;
}
if (exten) {
switch_channel_t *channel = switch_core_session_get_channel(session);
const char *br = switch_channel_get_partner_uuid(channel);
switch_core_session_t *b_session;
switch_channel_set_variable_printf(channel, "transfer_to", "blind:%s", br ? br : exten);
if (!zstr(br) && (b_session = switch_core_session_locate(br))) {
const char *var;
switch_channel_t *b_channel = switch_core_session_get_channel(b_session);
switch_channel_set_variable(channel, "transfer_fallback_extension", from->a_user);
if (!zstr(full_ref_by)) {
switch_channel_set_variable(b_channel, SOFIA_SIP_HEADER_PREFIX "Referred-By", full_ref_by);
}
if (!zstr(full_ref_to)) {
switch_channel_set_variable(b_channel, SOFIA_REFER_TO_VARIABLE, full_ref_to);
}
if (switch_true(switch_channel_get_variable(channel, "recording_follow_transfer"))) {
switch_core_media_bug_transfer_recordings(session, b_session);
}
switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "BLIND_TRANSFER");
if (((var = switch_channel_get_variable(channel, "confirm_blind_transfer")) && switch_true(var)) ||
sofia_test_pflag(profile, PFLAG_CONFIRM_BLIND_TRANSFER)) {
switch_channel_set_state_flag(b_channel, CF_CONFIRM_BLIND_TRANSFER);
switch_channel_set_variable(channel, "sip_blind_transfer_event", etmp);
switch_channel_set_variable(b_channel, "blind_transfer_uuid", switch_core_session_get_uuid(session));
switch_channel_set_variable(channel, "blind_transfer_uuid", switch_core_session_get_uuid(b_session));
switch_channel_set_variable(channel, "park_timeout", "600:blind_transfer");
switch_channel_set_state(channel, CS_PARK);
} else {
nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("message/sipfrag;version=2.0"),
NUTAG_SUBSTATE(nua_substate_terminated),
SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"),
SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK\r\n"), SIPTAG_EVENT_STR(etmp), TAG_END());
}
if (refer_to->r_url->url_params) {
switch_channel_set_variable(b_channel, "sip_h_X-FS-Refer-Params", refer_to->r_url->url_params);
}
switch_ivr_session_transfer(b_session, exten, NULL, NULL);
switch_core_session_rwunlock(b_session);
} else {
2012-07-09 15:56:04 +00:00
switch_event_t *event;
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, MY_EVENT_ERROR) == SWITCH_STATUS_SUCCESS) {
2012-07-19 04:02:32 +00:00
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Error-Type", "blind_transfer");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Transfer-Exten", exten);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Full-Refer-To", full_ref_to);
2012-07-09 15:56:04 +00:00
switch_channel_event_set_data(channel, event);
2012-07-18 17:37:08 +00:00
switch_event_fire(&event);
2012-07-09 15:56:04 +00:00
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), 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;version=2.0"),
NUTAG_SUBSTATE(nua_substate_terminated),
SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"),
SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden\r\n"), SIPTAG_EVENT_STR(etmp), TAG_END());
}
}
done:
if (home) {
su_home_unref(home);
home = NULL;
}
if (etmp) {
switch_safe_free(etmp);
}
}
static switch_status_t create_info_event(sip_t const *sip,
nua_handle_t *nh, switch_event_t **revent)
{
sip_alert_info_t *alert_info = sip_alert_info(sip);
switch_event_t *event;
if (!(sip && switch_event_create(&event, SWITCH_EVENT_RECV_INFO) == SWITCH_STATUS_SUCCESS)) {
return SWITCH_STATUS_FALSE;
}
if (sip && sip->sip_content_type) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "SIP-Content-Type", sip->sip_content_type->c_type);
}
if (sip->sip_from && sip->sip_from->a_url) {
if (sip->sip_from->a_url->url_user) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "SIP-From-User", sip->sip_from->a_url->url_user);
}
if (sip->sip_from->a_url->url_host) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "SIP-From-Host", sip->sip_from->a_url->url_host);
}
}
if (sip->sip_to && sip->sip_to->a_url) {
if (sip->sip_to->a_url->url_user) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "SIP-To-User", sip->sip_to->a_url->url_user);
}
if (sip->sip_to->a_url->url_host) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "SIP-To-Host", sip->sip_to->a_url->url_host);
}
}
if (sip->sip_contact && sip->sip_contact->m_url) {
if (sip->sip_contact->m_url->url_user) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "SIP-Contact-User", sip->sip_contact->m_url->url_user);
}
if (sip->sip_contact->m_url->url_host) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "SIP-Contact-Host", sip->sip_contact->m_url->url_host);
}
}
if (sip->sip_call_info) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Call-Info",
sip_header_as_string(nua_handle_home(nh), (void *) sip->sip_call_info));
}
if (alert_info) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Alert-Info", sip_header_as_string(nua_handle_home(nh), (void *) alert_info));
}
if (sip->sip_payload && sip->sip_payload->pl_data) {
switch_event_add_body(event, "%s", sip->sip_payload->pl_data);
}
*revent = event;
return SWITCH_STATUS_SUCCESS;
}
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,
sofia_dispatch_event_t *de, 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_core_default_dtmf_duration(0), 0, SWITCH_DTMF_ENDPOINT };
switch_event_t *event;
private_object_t *tech_pvt = NULL;
2012-08-23 18:07:08 +00:00
switch_channel_t *channel = NULL;
if (session) {
tech_pvt = (private_object_t *) switch_core_session_get_private(session);
2012-08-23 18:07:08 +00:00
channel = switch_core_session_get_channel(session);
}
if (sofia_test_pflag(profile, PFLAG_EXTENDED_INFO_PARSING)) {
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, "freeswitch", 10)) {
if (!strcasecmp(sip->sip_content_type->c_subtype, "session-event")) {
if (session) {
if (create_info_event(sip, nh, &event) == SWITCH_STATUS_SUCCESS) {
if (switch_core_session_queue_event(session, &event) == SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "queued freeswitch event for INFO\n");
nua_respond(nh, SIP_200_OK, SIPTAG_CONTENT_TYPE_STR("freeswitch/session-event-response"),
SIPTAG_PAYLOAD_STR("+OK MESSAGE QUEUED"), NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
} else {
switch_event_destroy(&event);
nua_respond(nh, SIP_200_OK, SIPTAG_CONTENT_TYPE_STR("freeswitch/session-event-response"),
SIPTAG_PAYLOAD_STR("-ERR MESSAGE NOT QUEUED"), NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
}
}
} else {
nua_respond(nh, SIP_200_OK, SIPTAG_CONTENT_TYPE_STR("freeswitch/session-event-response"),
SIPTAG_PAYLOAD_STR("-ERR INVALID SESSION"), NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
}
return;
} else if (!strcasecmp(sip->sip_content_type->c_subtype, "api-request")) {
char *cmd = strdup(sip->sip_payload->pl_data);
char *arg;
switch_stream_handle_t stream = { 0 };
switch_status_t status;
SWITCH_STANDARD_STREAM(stream);
switch_assert(stream.data);
if ((arg = strchr(cmd, ':'))) {
*arg++ = '\0';
}
if ((status = switch_api_execute(cmd, arg, NULL, &stream)) == SWITCH_STATUS_SUCCESS) {
nua_respond(nh, SIP_200_OK, SIPTAG_CONTENT_TYPE_STR("freeswitch/api-response"),
SIPTAG_PAYLOAD_STR(stream.data), NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
} else {
nua_respond(nh, SIP_200_OK, SIPTAG_CONTENT_TYPE_STR("freeswitch/api-response"),
SIPTAG_PAYLOAD_STR("-ERR INVALID COMMAND"), NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
}
switch_safe_free(stream.data);
switch_safe_free(cmd);
return;
}
nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
return;
}
}
}
if (session) {
const char *vval;
/* Barf if we didn't get our private */
assert(switch_core_session_get_private(session));
sofia_glue_set_extra_headers(session, sip, SOFIA_SIP_INFO_HEADER_PREFIX);
if (sip && sip->sip_content_type && sip->sip_content_type->c_type && !strcasecmp(sip->sip_content_type->c_type, "freeswitch/data")) {
char *data = NULL;
if (sip->sip_payload && sip->sip_payload->pl_data) {
data = sip->sip_payload->pl_data;
}
if ((vval = switch_channel_get_variable(channel, "sip_copy_custom_headers")) && switch_true(vval)) {
switch_core_session_t *nsession = NULL;
switch_core_session_get_partner(session, &nsession);
if (nsession) {
switch_core_session_message_t *msg;
switch_ivr_transfer_variable(session, nsession, SOFIA_SIP_INFO_HEADER_PREFIX_T);
msg = switch_core_session_alloc(nsession, sizeof(*msg));
MESSAGE_STAMP_FFL(msg);
msg->message_id = SWITCH_MESSAGE_INDICATE_INFO;
msg->string_array_arg[2] = switch_core_session_strdup(nsession, data);
msg->from = __FILE__;
switch_core_session_queue_message(nsession, msg);
switch_core_session_rwunlock(nsession);
}
}
}
2011-04-01 22:38:58 +00:00
if (sip && sip->sip_content_type && sip->sip_content_type->c_subtype && sip->sip_content_type->c_type &&
2010-11-22 16:10:26 +00:00
!strncasecmp(sip->sip_content_type->c_type, "message", 7) &&
!strcasecmp(sip->sip_content_type->c_subtype, "update_display")) {
2010-11-19 20:47:45 +00:00
sofia_update_callee_id(session, profile, sip, SWITCH_TRUE);
goto end;
}
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, "media_control+xml")) {
switch_core_session_t *other_session;
if (switch_channel_test_flag(channel, CF_VIDEO)) {
if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
sofia_glue_build_vid_refresh_message(other_session, sip->sip_payload->pl_data);
switch_core_session_rwunlock(other_session);
} else {
switch_channel_set_flag(channel, CF_VIDEO_REFRESH_REQ);
}
}
2014-08-27 18:28:11 +00:00
} else if (!strncasecmp(sip->sip_content_type->c_type, "application", 11) &&
!strcasecmp(sip->sip_content_type->c_subtype, "vnd.nortelnetworks.digits")) {
int tmp;
if ((signal_ptr = switch_stristr("d=", sip->sip_payload->pl_data))) {
signal_ptr = signal_ptr + 2;
while (*signal_ptr && *signal_ptr == ' ') {
signal_ptr++;
}
if (*signal_ptr && (*signal_ptr == '*' || *signal_ptr == '#' || *signal_ptr == 'A' || *signal_ptr == 'B'
|| *signal_ptr == 'C' || *signal_ptr == 'D')) {
dtmf.digit = *signal_ptr;
} else {
tmp = atoi(signal_ptr);
dtmf.digit = switch_rfc2833_to_char(tmp);
}
dtmf.duration = 100;
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Bad signal\n");
goto end;
}
} else 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))) {
int tmp;
/* move signal_ptr where we need it (right past Signal=) */
signal_ptr = signal_ptr + 7;
/* handle broken devices with spaces after the = (cough) VegaStream (cough) */
while (*signal_ptr && *signal_ptr == ' ')
signal_ptr++;
if (*signal_ptr
&& (*signal_ptr == '*' || *signal_ptr == '#' || *signal_ptr == 'A' || *signal_ptr == 'B' || *signal_ptr == 'C'
|| *signal_ptr == 'D')) {
dtmf.digit = *signal_ptr;
} else {
tmp = atoi(signal_ptr);
dtmf.digit = switch_rfc2833_to_char(tmp);
}
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Bad signal\n");
goto end;
}
if ((signal_ptr = switch_stristr("Duration=", sip->sip_payload->pl_data))) {
int tmp;
signal_ptr += 9;
/* handle broken devices with spaces after the = (cough) VegaStream (cough) */
while (*signal_ptr && *signal_ptr == ' ')
signal_ptr++;
if ((tmp = atoi(signal_ptr)) <= 0) {
tmp = switch_core_default_dtmf_duration(0);
}
dtmf.duration = tmp * 8;
}
} else if (!strncasecmp(sip->sip_content_type->c_type, "application", 11) && !strcasecmp(sip->sip_content_type->c_subtype, "dtmf")) {
int tmp = atoi(sip->sip_payload->pl_data);
dtmf.digit = switch_rfc2833_to_char(tmp);
} else {
goto end;
}
if (dtmf.digit) {
if (tech_pvt->mparams.dtmf_type == DTMF_INFO ||
2012-12-21 04:57:47 +00:00
sofia_test_pflag(tech_pvt->profile, PFLAG_LIBERAL_DTMF) || switch_channel_test_flag(tech_pvt->channel, CF_LIBERAL_DTMF)) {
/* queue it up */
switch_channel_queue_dtmf(channel, &dtmf);
/* print debug info */
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "INFO DTMF(%c)\n", dtmf.digit);
if (switch_channel_test_flag(channel, CF_PROXY_MODE)) {
const char *uuid;
switch_core_session_t *session_b;
if ((uuid = switch_channel_get_partner_uuid(channel)) && (session_b = switch_core_session_locate(uuid))) {
while (switch_channel_has_dtmf(channel)) {
switch_dtmf_t idtmf = { 0, 0 };
if (switch_channel_dequeue_dtmf(channel, &idtmf) == SWITCH_STATUS_SUCCESS) {
switch_core_session_send_dtmf(session_b, &idtmf);
}
}
switch_core_session_rwunlock(session_b);
}
}
/* Send 200 OK response */
nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
"IGNORE INFO DTMF(%c) (This channel was not configured to use INFO DTMF!)\n", dtmf.digit);
}
}
goto end;
}
if ((clientcode_header = sofia_glue_get_unknown_header(sip, "x-clientcode"))) {
if (!zstr(clientcode_header)) {
switch_channel_set_variable(channel, "call_clientcode", clientcode_header);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Setting CMC to %s\n", clientcode_header);
nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
}
goto end;
}
if ((rec_header = sofia_glue_get_unknown_header(sip, "record"))) {
if (zstr(profile->record_template)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Record attempted but no template defined.\n");
nua_respond(nh, 488, "Recording not enabled", NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
} else {
if (!strcasecmp(rec_header, "on")) {
char *file = NULL, *tmp = NULL;
2014-02-25 01:25:31 +00:00
if (switch_true(switch_channel_get_variable(channel, "sip_disable_recording"))) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Record attempted but is disabled by sip_disable_recording variable.\n");
nua_respond(nh, 488, "Recording disabled for this channel", NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
} else {
tmp = switch_mprintf("%s%s%s", profile->record_path ? profile->record_path : "${recordings_dir}",
SWITCH_PATH_SEPARATOR, profile->record_template);
file = switch_channel_expand_variables(channel, tmp);
switch_ivr_record_session(session, file, 0, NULL);
switch_channel_set_variable(channel, "sofia_record_file", file);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Recording %s to %s\n", switch_channel_get_name(channel),
file);
switch_safe_free(tmp);
nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
if (file != profile->record_template) {
free(file);
file = NULL;
}
}
} else {
const char *file;
if ((file = switch_channel_get_variable(channel, "sofia_record_file"))) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), 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_MSG(de->data->e_msg), TAG_END());
} else {
nua_respond(nh, 488, "Nothing to stop", NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
}
}
}
}
}
end:
if (create_info_event(sip, nh, &event) == SWITCH_STATUS_SUCCESS) {
2012-08-23 18:07:08 +00:00
if (channel) {
switch_channel_event_set_data(channel, event);
}
switch_event_fire(&event);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "dispatched freeswitch event for INFO\n");
}
nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
return;
}
void sofia_handle_sip_i_reinvite(switch_core_session_t *session,
nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip,
sofia_dispatch_event_t *de,
tagi_t tags[])
{
char *call_info = NULL;
switch_channel_t *channel = NULL;
2014-05-27 15:39:53 +00:00
private_object_t *tech_pvt = NULL;
if (session) {
channel = switch_core_session_get_channel(session);
2014-05-27 15:39:53 +00:00
tech_pvt = switch_core_session_get_private(session);
}
2010-09-09 03:53:57 +00:00
if (session && profile && sip && sofia_test_pflag(profile, PFLAG_TRACK_CALLS)) {
switch_channel_t *channel = switch_core_session_get_channel(session);
private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session);
char network_ip[80];
int network_port = 0;
char via_space[2048];
char branch[16] = "";
2011-07-16 07:33:39 +00:00
sofia_clear_flag(tech_pvt, TFLAG_GOT_ACK);
sofia_glue_get_addr(de->data->e_msg, network_ip, sizeof(network_ip), &network_port);
2010-09-09 03:53:57 +00:00
switch_stun_random_string(branch, sizeof(branch) - 1, "0123456789abcdef");
switch_snprintf(via_space, sizeof(via_space), "SIP/2.0/UDP %s;rport=%d;branch=%s", network_ip, network_port, branch);
switch_channel_set_variable(channel, "sip_full_via", via_space);
switch_channel_set_variable_printf(channel, "sip_network_port", "%d", network_port);
switch_channel_set_variable_printf(channel, "sip_recieved_port", "%d", network_port);
switch_channel_set_variable_printf(channel, "sip_via_rport", "%d", network_port);
switch_core_recovery_track(session);
2010-09-09 03:53:57 +00:00
}
if (sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE)) {
if (channel && sip->sip_call_info) {
char *p;
if ((call_info = sip_header_as_string(nua_handle_home(nh), (void *) sip->sip_call_info))) {
if (switch_stristr("appearance", call_info)) {
switch_channel_set_variable(channel, "presence_call_info_full", call_info);
if ((p = strchr(call_info, ';'))) {
switch_channel_set_variable(channel, "presence_call_info", p + 1);
}
}
su_free(nua_handle_home(nh), call_info);
}
}
}
if (channel) {
2014-05-27 15:39:53 +00:00
tech_pvt->mparams.last_sdp_str = NULL;
if (sip->sip_payload && sip->sip_payload->pl_data) {
switch_channel_set_variable(channel, "sip_reinvite_sdp", sip->sip_payload->pl_data);
2014-05-27 15:39:53 +00:00
tech_pvt->mparams.last_sdp_str = switch_core_session_strdup(session, sip->sip_payload->pl_data);
}
switch_channel_execute_on(channel, "execute_on_sip_reinvite");
}
}
2012-08-21 05:04:58 +00:00
void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, sofia_dispatch_event_t *de, tagi_t tags[])
{
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_privacy_t *privacy = NULL;
sip_alert_info_t *alert_info = NULL;
sip_call_info_t *call_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;
2011-04-22 21:43:29 +00:00
const char *referred_by_user = NULL;//, *referred_by_host = NULL;
const char *context = NULL;
const char *dialplan = NULL;
char network_ip[80];
char proxied_client_ip[80];
switch_event_t *v_event = NULL;
2013-07-19 17:03:46 +00:00
switch_xml_t x_user = NULL;
uint32_t sess_count = switch_core_session_count();
uint32_t sess_max = switch_core_session_limit(0);
int is_auth = 0, calling_myself = 0;
int network_port = 0;
char *is_nat = NULL;
char *aniii = NULL;
char acl_token[512] = "";
sofia_transport_t transport;
const char *gw_name = NULL;
const char *gw_param_name = NULL;
char *call_info_str = NULL;
nua_handle_t *bnh = NULL;
2010-05-06 22:17:33 +00:00
char sip_acl_authed_by[512] = "";
char sip_acl_token[512] = "";
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;
const char *to_tag = "";
const char *from_tag = "";
char *sql = NULL;
char *acl_context = NULL;
const char *r_sdp = NULL;
2014-03-11 21:12:43 +00:00
int is_tcp = 0, is_tls = 0;
const char *uparams = NULL;
char *name_params = NULL;
2014-03-11 21:12:43 +00:00
if (sip && sip->sip_contact && sip->sip_contact->m_url && sip->sip_contact->m_url->url_params) {
uparams = sip->sip_contact->m_url->url_params;
} else {
uparams = NULL;
}
if (uparams) {
if (switch_stristr("transport=tcp", uparams)) {
is_tcp = 1;
} else if (switch_stristr("transport=tls", uparams)) {
is_tls = 1;
}
}
2011-11-18 23:00:30 +00:00
profile->ib_calls++;
if (sip->sip_payload && sip->sip_payload->pl_data) {
r_sdp = sip->sip_payload->pl_data;
}
2012-08-16 17:09:19 +00:00
2012-08-21 05:04:58 +00:00
if (!session || (sess_count >= sess_max || !sofia_test_pflag(profile, PFLAG_RUNNING))) {
nua_respond(nh, 503, "Maximum Calls In Progress", SIPTAG_RETRY_AFTER_STR("300"), TAG_END());
goto fail;
}
2012-08-21 05:04:58 +00:00
tech_pvt = switch_core_session_get_private(session);
if (!sip || !sip->sip_request || !sip->sip_request->rq_method_name) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Received an invalid packet!\n");
nua_respond(nh, SIP_503_SERVICE_UNAVAILABLE, TAG_END());
goto fail;
}
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());
goto fail;
}
2014-01-20 18:34:32 +00:00
sofia_glue_get_addr(de->data->e_msg, network_ip, sizeof(network_ip), &network_port);
2014-01-20 18:34:32 +00:00
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "%s receiving invite from %s:%d version: %s\n",
switch_channel_get_name(tech_pvt->channel), network_ip, network_port, switch_version_full_human());
2013-02-06 15:48:04 +00:00
if (sip && sip->sip_via && sip->sip_via->v_protocol && switch_stristr("sip/2.0/ws", sip->sip_via->v_protocol)) {
is_nat = "websockets";
}
if (r_sdp) {
switch_core_media_set_sdp_codec_string(session, r_sdp, SDP_TYPE_REQUEST);
}
2014-03-11 21:12:43 +00:00
if (sofia_test_pflag(profile, PFLAG_AGGRESSIVE_NAT_DETECTION) ||
(sofia_test_pflag(profile, PFLAG_TLS_ALWAYS_NAT) && (is_tcp || is_tls)) ||
(!is_tcp && !is_tls && (zstr(network_ip) || !switch_check_network_list_ip(network_ip, profile->local_network)) &&
profile->server_rport_level >= 2 && sip->sip_user_agent &&
sip->sip_user_agent->g_string &&
(!strncasecmp(sip->sip_user_agent->g_string, "Polycom", 7) || !strncasecmp(sip->sip_user_agent->g_string, "KIRK Wireless Server", 20)))
) {
if (sip && sip->sip_via) {
const char *port = sip->sip_via->v_port;
const char *host = sip->sip_via->v_host;
if (host && sip->sip_via->v_received) {
is_nat = "via received";
} else if (host && strcmp(network_ip, host)) {
is_nat = "via host";
} else if (port && atoi(port) != network_port) {
is_nat = "via port";
}
}
}
if (!is_nat && profile->nat_acl_count) {
uint32_t x = 0;
2010-12-15 04:29:25 +00:00
int contact_private_ip = 1;
int network_private_ip = 0;
char *last_acl = NULL;
const char *contact_host = NULL;
if (sip && sip->sip_contact && sip->sip_contact->m_url) {
contact_host = sip->sip_contact->m_url->url_host;
}
if (!zstr(contact_host)) {
2010-12-15 04:29:25 +00:00
/* NAT mode double check logic and examples.
2010-12-14 18:43:51 +00:00
Example 1: the contact_host is 192.168.1.100 and the network_ip is also 192.168.1.100 the end point
2010-12-15 04:29:25 +00:00
is most likely behind nat with us so we need to veto that decision to turn on nat processing.
2010-12-14 18:43:51 +00:00
2010-12-15 04:29:25 +00:00
Example 2: the contact_host is 192.168.1.100 and the network_ip is 192.0.2.100 which is a public internet ip
the remote endpoint is likely behind a remote nat traversing the public internet.
2010-12-14 18:43:51 +00:00
2010-12-15 04:29:25 +00:00
This secondary check is here to double check the conclusion of nat settigs to ensure we don't set net
in cases where we don't really need to be doing this.
2010-12-14 18:43:51 +00:00
2010-12-15 04:29:25 +00:00
Why would you want to do this? Well if your FreeSWITCH is behind nat and you want to talk to endpoints behind
remote NAT over the public internet in addition to endpoints behind nat with you. This simplifies that process.
*/
for (x = 0; x < profile->nat_acl_count; x++) {
last_acl = profile->nat_acl[x];
if ((contact_private_ip = switch_check_network_list_ip(contact_host, last_acl))) {
break;
}
}
2010-12-15 04:29:25 +00:00
if (contact_private_ip) {
for (x = 0; x < profile->nat_acl_count; x++) {
if ((network_private_ip = switch_check_network_list_ip(network_ip, profile->nat_acl[x]))) {
break;
}
}
}
2010-12-15 04:29:25 +00:00
if (contact_private_ip && !network_private_ip) {
is_nat = last_acl;
}
}
}
if (profile->acl_count) {
uint32_t x = 0;
int ok = 1;
char *last_acl = NULL;
const char *token = NULL;
for (x = 0; x < profile->acl_count; x++) {
last_acl = profile->acl[x];
if ((ok = switch_check_network_list_ip_token(network_ip, last_acl, &token))) {
if (profile->acl_pass_context[x]) {
acl_context = profile->acl_pass_context[x];
}
break;
}
if (profile->acl_fail_context[x]) {
acl_context = profile->acl_fail_context[x];
} else {
acl_context = NULL;
}
}
if (ok) {
if (token) {
switch_set_string(acl_token, token);
}
if (sofia_test_pflag(profile, PFLAG_AUTH_CALLS)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IP %s Approved by acl \"%s[%s]\". Access Granted.\n",
network_ip, switch_str_nil(last_acl), acl_token);
2010-05-06 22:17:33 +00:00
switch_set_string(sip_acl_authed_by, last_acl);
switch_set_string(sip_acl_token, acl_token);
is_auth = 1;
}
} else {
int network_ip_is_proxy = 0;
/* Check if network_ip is a proxy allowed to send us calls */
if (profile->proxy_acl_count) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%d acls to check for proxy\n", profile->proxy_acl_count);
}
for (x = 0; x < profile->proxy_acl_count; x++) {
last_acl = profile->proxy_acl[x];
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "checking %s against acl %s\n", network_ip, last_acl);
if (switch_check_network_list_ip_token(network_ip, last_acl, &token)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s is a proxy according to the %s acl\n", network_ip, last_acl);
network_ip_is_proxy = 1;
break;
}
}
/*
* if network_ip is a proxy allowed to send calls, check for auth
* ip header and see if it matches against the inbound acl
*/
if (network_ip_is_proxy) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "network ip is a proxy\n");
for (un = sip->sip_unknown; un; un = un->un_next) {
if (!strcasecmp(un->un_name, "X-AUTH-IP")) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "found auth ip [%s] header of [%s]\n", un->un_name, un->un_value);
if (!zstr(un->un_value)) {
for (x = 0; x < profile->acl_count; x++) {
last_acl = profile->acl[x];
if ((ok = switch_check_network_list_ip_token(un->un_value, last_acl, &token))) {
switch_copy_string(proxied_client_ip, un->un_value, sizeof(proxied_client_ip));
break;
}
}
}
}
}
}
if (!ok) {
if (!sofia_test_pflag(profile, PFLAG_AUTH_CALLS)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "IP %s Rejected by acl \"%s\"\n", network_ip, switch_str_nil(last_acl));
if (!acl_context) {
nua_respond(nh, SIP_403_FORBIDDEN, TAG_END());
goto fail;
}
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IP %s Rejected by acl \"%s\". Falling back to Digest auth.\n",
network_ip, switch_str_nil(last_acl));
}
} else {
if (token) {
switch_set_string(acl_token, token);
}
if (sofia_test_pflag(profile, PFLAG_AUTH_CALLS)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IP %s Approved by acl \"%s[%s]\". Access Granted.\n",
proxied_client_ip, switch_str_nil(last_acl), acl_token);
2010-05-06 22:17:33 +00:00
switch_set_string(sip_acl_authed_by, last_acl);
switch_set_string(sip_acl_token, acl_token);
is_auth = 1;
}
}
}
}
2013-01-10 16:32:48 +00:00
if (!is_auth && sofia_test_pflag(profile, PFLAG_AUTH_CALLS) && sofia_test_pflag(profile, PFLAG_BLIND_AUTH)) {
char *user;
if (!strcmp(network_ip, profile->sipip) && network_port == profile->sip_port) {
calling_myself++;
}
if (sip && sip->sip_from) {
2013-01-10 18:44:35 +00:00
user = switch_core_session_sprintf(session, "%s@%s", sip->sip_from->a_url->url_user, sip->sip_from->a_url->url_host);
2013-01-10 16:32:48 +00:00
switch_ivr_set_user(session, user);
}
is_auth++;
}
if (!is_auth &&
(sofia_test_pflag(profile, PFLAG_AUTH_CALLS)
|| (!sofia_test_pflag(profile, PFLAG_BLIND_AUTH) && (sip->sip_proxy_authorization || sip->sip_authorization)))) {
if (!strcmp(network_ip, profile->sipip) && network_port == profile->sip_port) {
calling_myself++;
} else {
2013-07-29 21:55:16 +00:00
switch_event_create(&v_event, SWITCH_EVENT_REQUEST_PARAMS);
2013-07-19 17:03:46 +00:00
if (sofia_reg_handle_register(nua, profile, nh, sip, de, REG_INVITE, key, sizeof(key), &v_event, NULL, NULL, &x_user)) {
if (v_event) {
switch_event_destroy(&v_event);
}
2013-07-19 17:03:46 +00:00
if (x_user) {
switch_xml_free(x_user);
}
if (sip->sip_authorization || sip->sip_proxy_authorization) {
goto fail;
}
return;
}
}
is_auth++;
}
tech_pvt->mparams.remote_ip = switch_core_session_strdup(session, network_ip);
tech_pvt->mparams.remote_port = network_port;
channel = tech_pvt->channel = switch_core_session_get_channel(session);
switch_channel_set_variable_printf(channel, "sip_local_network_addr", "%s", profile->extsipip ? profile->extsipip : profile->sipip);
switch_channel_set_variable_printf(channel, "sip_network_ip", "%s", network_ip);
switch_channel_set_variable_printf(channel, "sip_network_port", "%d", network_port);
if (*acl_token) {
switch_channel_set_variable(channel, "acl_token", acl_token);
if (strchr(acl_token, '@')) {
if (switch_ivr_set_user(session, acl_token) == SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Authenticating user %s\n", acl_token);
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Error Authenticating user %s\n", acl_token);
}
}
}
2013-02-06 15:48:04 +00:00
if (sip->sip_via || (sip->sip_contact && sip->sip_contact->m_url)) {
char tmp[35] = "";
const char *ipv6 = strchr(tech_pvt->mparams.remote_ip, ':');
2013-02-06 15:48:04 +00:00
if (sip->sip_via) {
transport = sofia_glue_via2transport(sip->sip_via);
} else {
transport = sofia_glue_url2transport(sip->sip_contact->m_url);
}
2013-02-06 15:48:04 +00:00
tech_pvt->record_route =
switch_core_session_sprintf(session,
2013-02-06 15:48:04 +00:00
"sip:%s%s%s:%d;transport=%s",
ipv6 ? "[" : "", tech_pvt->mparams.remote_ip, ipv6 ? "]" : "",
2013-02-06 15:48:04 +00:00
tech_pvt->mparams.remote_port, sofia_glue_transport2str(transport));
switch_channel_set_variable(channel, "sip_received_ip", tech_pvt->mparams.remote_ip);
snprintf(tmp, sizeof(tmp), "%d", tech_pvt->mparams.remote_port);
switch_channel_set_variable(channel, "sip_received_port", tmp);
}
if (sip->sip_via) {
switch_channel_set_variable(channel, "sip_via_protocol", sofia_glue_transport2str(sofia_glue_via2transport(sip->sip_via)));
}
if (*key != '\0') {
tech_pvt->key = switch_core_session_strdup(session, key);
}
if (is_auth) {
switch_channel_set_variable(channel, "sip_authorized", "true");
2010-05-06 22:17:33 +00:00
if (!zstr(sip_acl_authed_by)) {
switch_channel_set_variable(channel, "sip_acl_authed_by", sip_acl_authed_by);
}
if (!zstr(sip_acl_token)) {
switch_channel_set_variable(channel, "sip_acl_token", sip_acl_token);
}
}
if (calling_myself) {
switch_channel_set_variable(channel, "sip_looped_call", "true");
}
2013-07-20 02:50:55 +00:00
tech_pvt->caller_profile = switch_caller_profile_new(switch_core_session_get_pool(session),
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, MODNAME, NULL, NULL);
switch_channel_set_caller_profile(channel, tech_pvt->caller_profile);
if (x_user) {
2013-07-20 19:06:34 +00:00
const char *ruser = NULL, *rdomain = NULL, *user = switch_xml_attr(x_user, "id"), *domain = switch_xml_attr(x_user, "domain-name");
2013-07-20 02:50:55 +00:00
if (v_event) {
2013-07-29 21:55:16 +00:00
switch_event_header_t *hp;
for (hp = v_event->headers; hp; hp = hp->next) {
switch_channel_set_variable(channel, hp->name, hp->value);
}
2013-07-20 19:06:34 +00:00
ruser = switch_event_get_header(v_event, "username");
rdomain = switch_event_get_header(v_event, "domain_name");
2013-07-20 19:06:34 +00:00
switch_channel_set_variable(channel, "requested_user_name", ruser);
switch_channel_set_variable(channel, "requested_domain_name", rdomain);
2013-07-20 02:50:55 +00:00
}
2013-07-20 19:06:34 +00:00
if (!user) user = ruser;
if (!domain) domain = rdomain;
2013-07-20 02:50:55 +00:00
switch_ivr_set_user_xml(session, NULL, user, domain, x_user);
switch_xml_free(x_user);
x_user = NULL;
}
if (v_event) {
switch_event_destroy(&v_event);
}
if (sip->sip_from && sip->sip_from->a_url) {
from_user = sip->sip_from->a_url->url_user;
from_host = sip->sip_from->a_url->url_host;
//channel_name = url_set_chanvars(session, sip->sip_from->a_url, sip_from);
2011-11-04 18:16:47 +00:00
if (sip->sip_from->a_url->url_params) {
aniii = switch_find_parameter(sip->sip_from->a_url->url_params, "isup-oli", switch_core_session_get_pool(session));
}
if (!zstr(from_user)) {
if (*from_user == '+') {
switch_channel_set_variable(channel, "sip_from_user_stripped", (const char *) (from_user + 1));
} else {
switch_channel_set_variable(channel, "sip_from_user_stripped", from_user);
}
}
switch_channel_set_variable(channel, "sip_from_comment", sip->sip_from->a_comment);
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, "recovery_profile_name", profile->name);
switch_channel_set_variable(channel, "sofia_profile_domain_name", profile->domain_name);
if (!zstr(sip->sip_from->a_display)) {
displayname = sip->sip_from->a_display;
} else {
displayname = zstr(from_user) ? "unknown" : from_user;
}
}
if ((rpid = sip_remote_party_id(sip))) {
if (rpid->rpid_url && rpid->rpid_url->url_user) {
char *full_rpid_header = sip_header_as_string(nh->nh_home, (void *) rpid);
from_user = rpid->rpid_url->url_user;
if (!zstr(full_rpid_header)) {
switch_channel_set_variable(channel, "sip_Remote-Party-ID", full_rpid_header);
}
}
if (!zstr(rpid->rpid_display)) {
displayname = rpid->rpid_display;
}
switch_channel_set_variable(channel, "sip_cid_type", "rpid");
tech_pvt->cid_type = CID_TYPE_RPID;
}
if ((passerted = sip_p_asserted_identity(sip))) {
if (passerted->paid_url && passerted->paid_url->url_user) {
char *full_paid_header = sip_header_as_string(nh->nh_home, (void *) passerted);
2012-04-10 20:46:27 +00:00
//char *full_paid_header = (char *)(passerted->paid_common->h_data);
from_user = passerted->paid_url->url_user;
if (!zstr(full_paid_header)) {
2012-04-10 20:46:27 +00:00
if (profile->paid_type == PAID_DEFAULT || profile->paid_type == PAID_USER) {
switch_channel_set_variable(channel, "sip_P-Asserted-Identity", from_user);
} else if (profile->paid_type == PAID_USER_DOMAIN) {
switch_channel_set_variable(channel, "sip_P-Asserted-Identity",
switch_core_session_sprintf(session, "%s@%s", passerted->paid_url->url_user, passerted->paid_url->url_host));
} else if (profile->paid_type == PAID_VERBATIM) {
switch_channel_set_variable(channel, "sip_P-Asserted-Identity", full_paid_header);
}
}
}
if (!zstr(passerted->paid_display)) {
displayname = passerted->paid_display;
}
switch_channel_set_variable(channel, "sip_cid_type", "pid");
tech_pvt->cid_type = CID_TYPE_PID;
}
if ((ppreferred = sip_p_preferred_identity(sip))) {
if (ppreferred->ppid_url && ppreferred->ppid_url->url_user) {
char *full_ppid_header = sip_header_as_string(nh->nh_home, (void *) ppreferred);
from_user = ppreferred->ppid_url->url_user;
if (!zstr(full_ppid_header)) {
switch_channel_set_variable(channel, "sip_P-Preferred-Identity", full_ppid_header);
}
}
if (!zstr(ppreferred->ppid_display)) {
displayname = ppreferred->ppid_display;
}
switch_channel_set_variable(channel, "sip_cid_type", "pid");
tech_pvt->cid_type = CID_TYPE_PID;
}
if (from_user) {
check_decode(from_user, session);
if ((name_params = strchr(from_user, ';'))) {
*name_params++ = '\0';
switch_channel_set_variable(channel, "sip_name_params", name_params);
}
}
extract_header_vars(profile, sip, session, nh);
if (sip->sip_request->rq_url) {
const char *req_uri = url_set_chanvars(session, sip->sip_request->rq_url, sip_req);
2014-04-15 16:47:48 +00:00
char *user = NULL;
if (sip->sip_request->rq_url->url_user) {
user = switch_core_session_strdup(session, sip->sip_request->rq_url->url_user);
if (profile->parse_invite_tel_params) {
if (strchr(user, ';')) {
int argc1, x1 = 0;
char *argv1[32] = { 0 };
if ((argc1 = switch_separate_string(user, ';', argv1, (sizeof(argv1) / sizeof(argv1[0]))))) {
for (x1 = 0; x1 < argc1; x1++) {
if (x1 == 0) {
switch_channel_set_variable(channel, "sip_req_user", argv1[0]);
} else {
int argc2 = 0;
char *argv2[2] = { 0 };
if ((argc2 = switch_separate_string(argv1[x1], '=', argv2, (sizeof(argv2) / sizeof(argv2[0])))) == 2) {
2014-04-15 16:47:48 +00:00
char *var_name = NULL;
var_name = switch_mprintf("sip_invite_%s", argv2[0]);
switch_channel_set_variable(channel, var_name, argv2[1]);
switch_safe_free( var_name );
} else {
char *var_name = NULL;
var_name = switch_mprintf("sip_invite_%s", argv1[x1]);
switch_channel_set_variable(channel, var_name, "true");
switch_safe_free( var_name );
2014-04-15 16:47:48 +00:00
}
}
}
}
}
}
}
if (sofia_test_pflag(profile, PFLAG_FULL_ID)) {
destination_number = req_uri;
} else {
2014-04-15 16:47:48 +00:00
destination_number = user;
}
if (sip->sip_request->rq_url->url_params && (sofia_glue_find_parameter(sip->sip_request->rq_url->url_params, "intercom=true"))) {
switch_channel_set_variable(channel, "sip_auto_answer_detected", "true");
}
}
if (!destination_number && sip->sip_to && sip->sip_to->a_url) {
destination_number = sip->sip_to->a_url->url_user;
}
/* The human network, OH THE HUMANITY!!! lets send invites with no number! */
if (!destination_number && sip->sip_from && sip->sip_from->a_url) {
destination_number = sip->sip_from->a_url->url_user;
}
if (destination_number) {
check_decode(destination_number, session);
} else {
destination_number = "service";
}
if (sip->sip_to && sip->sip_to->a_url) {
const char *host, *user;
int port, check_nat = 0;
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 (switch_channel_get_variable(channel, "sip_to_uri")) {
const char *ipv6;
const char *tmp, *at, *url = NULL;
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 {
2012-12-07 16:29:44 +00:00
port = sofia_glue_transport_has_tls(transport) ? profile->tls_sip_port : profile->extsipport;
}
ipv6 = strchr(host, ':');
tech_pvt->to_uri =
switch_core_session_sprintf(session,
"sip:%s@%s%s%s:%d;transport=%s",
user, ipv6 ? "[" : "", host, ipv6 ? "]" : "", port, sofia_glue_transport2str(transport));
if (sofia_glue_check_nat(profile, tech_pvt->mparams.remote_ip)) {
url = (sofia_glue_transport_has_tls(transport)) ? profile->tls_public_url : profile->public_url;
check_nat = 1;
} else {
url = (sofia_glue_transport_has_tls(transport)) ? profile->tls_url : profile->url;
}
if (!url) {
if (check_nat) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Nat detected but no external address configured.\n");
}
url = profile->url;
}
if (!url) {
switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
}
2013-02-27 15:04:51 +00:00
tmp = sofia_overcome_sip_uri_weakness(session, url, transport, SWITCH_TRUE, NULL, NULL);
if ((at = strchr(tmp, '@'))) {
url = switch_core_session_sprintf(session, "sip:%s%s", user, at);
}
if (url) {
const char *brackets = NULL;
const char *proto = NULL;
brackets = strchr(url, '>');
proto = switch_stristr("transport=", url);
tech_pvt->reply_contact = switch_core_session_sprintf(session, "%s%s%s%s%s",
brackets ? "" : "<", url,
proto ? "" : ";transport=",
proto ? "" : sofia_glue_transport2str(transport), brackets ? "" : ">");
} else {
switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
}
} else {
const char *url = NULL;
if (sofia_glue_check_nat(profile, tech_pvt->mparams.remote_ip)) {
url = (sofia_glue_transport_has_tls(transport)) ? profile->tls_public_url : profile->public_url;
} else {
url = (sofia_glue_transport_has_tls(transport)) ? profile->tls_url : profile->url;
}
if (url) {
const char *brackets = NULL;
const char *proto = NULL;
brackets = strchr(url, '>');
proto = switch_stristr("transport=", url);
tech_pvt->reply_contact = switch_core_session_sprintf(session, "%s%s%s%s%s",
brackets ? "" : "<", url,
proto ? "" : ";transport=",
proto ? "" : sofia_glue_transport2str(transport), brackets ? "" : ">");
} else {
switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
}
}
}
if (sofia_glue_check_nat(profile, tech_pvt->mparams.remote_ip)) {
tech_pvt->user_via = sofia_glue_create_external_via(session, profile, tech_pvt->transport);
nua_set_hparams(tech_pvt->nh, SIPTAG_VIA_STR(tech_pvt->user_via), TAG_END());
}
if (sip->sip_contact && sip->sip_contact->m_url) {
url_set_chanvars(session, sip->sip_contact->m_url, sip_contact);
}
if (sip->sip_referred_by) {
referred_by_user = sip->sip_referred_by->b_url->url_user;
2011-04-22 21:43:29 +00:00
//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 (!zstr(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_set_name(tech_pvt, channel_name);
switch_core_media_prepare_codecs(tech_pvt->session, SWITCH_FALSE);
switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "INBOUND CALL");
if (sofia_test_flag(tech_pvt, TFLAG_INB_NOMEDIA)) {
switch_channel_set_flag(channel, CF_PROXY_MODE);
}
if (profile->media_options & MEDIA_OPT_BYPASS_AFTER_HOLD) {
2014-02-05 02:15:08 +00:00
switch_channel_set_flag(channel, CF_BYPASS_MEDIA_AFTER_HOLD);
}
if (sofia_test_flag(tech_pvt, TFLAG_PROXY_MEDIA)) {
switch_channel_set_flag(channel, CF_PROXY_MEDIA);
}
add enhanced zrtp passthrough (zrtp passthru) mode ZRTP passthrough mode allows two ZRTP-capable clients to negotiate an end-to-end security association through FreeSWITCH. The clients are therefore able to be certain that the FreeSWITCH instance mediating the call cannot eavesdrop on their conversation. Importantly, this capability is maintained across multiple FreeSWITCH hops. If widely deployed, this enables a global network architecture where two people can speak securely with strong cryptographically protected authentication and confidentiality. With this commit we implement a zrtp-passthru mode that handles all the details of the negotiation intelligently. This mode can be selected by setting the boolean parameter inbound-zrtp-passthru in the sofia profile. This will also force late-negotiation as it is essential for correctly negotiating an end-to-end ZRTP security association. When an incoming call with a zrtp-hash is received and this mode is enabled, we find the first audio and the first video zrtp-hash in the SDP and store them as remote values on this channel. Once a b-leg is available, we set the local zrtp-hash values on that channel to the remote zrtp-hash values collected from the a-leg. Because zrtp-passthru absolutely requires that the channels negotiate the same codec, we offer to the b-leg only codecs that the a-leg can speak. Once the b-leg accepts a codec, we will force that choice onto the a-leg. If the b-leg sends us zrtp-hash values in the signaling, we store those as remote values on the b-leg and copy them to the local values on the a-leg. At this point, each leg has the zrtp-hash values from the other, and we know we can do ZRTP passthrough mode on the call. We send the b-leg's zrtp-hash back to the a-leg in the 200 OK. We then enable UDPTL mode on the rtp streams for both the audio and the video so that we don't interfere in the ZRTP negotiation. If the b-leg fails to return a zrtp-hash in the signaling, we set up a ZRTP security association with the a-leg ourselves, if we are so equipped. Likewise, if the a-leg fails to send a zrtp-hash in the signaling, we attempt to set up a ZRTP security association ourselves with the b-leg. The zrtp-passthru mode can also be enabled in the dialplan by setting the boolean channel variable zrtp_passthru. If enabled in this manner, we can't force late-negotiation, so the user would need to be sure this is configured. If ZRTP passthrough mode is not enabled in either manner, this change should have no effect. Channel variables for each of the various zrtp-hash values are set, though it is anticipated that there is no good reason to use them, so they may be removed without warning. For checking whether zrtp passthrough mode was successful, we provide the channel variable zrtp_passthru_active which is set on both legs. Though not implemented by this commit, the changes here should make it more straightforward to add correct zrtp-hash values to the signaling and verify that correct hello hash values are received when FreeSWITCH is acting as a terminating leg of the ZRTP security association. A historical note... This commit replaces the recently-added sdp_zrtp_hash_string method, commit 2ab1605a8887adc62be1b75f6ef67af87ff080de. This prior method sets a channel variable from the a-leg's zrtp-hash, then relies on the dialplan to export this channel variable to the b-leg, where it is put into the SDP. While it was a great start and wonderful for testing, this approach has some drawbacks that motivated the present work: * There's no good way to pass the zrtp-hash from the b-leg back to the a-leg. In fact, the implementation seems to send the a-leg's zrtp-hash back to the originating client in the 200 OK. This is not correct. * To support video, we'd need to have a separate dialplan variable, and the dialplan author would need to deal with that explicitly. * The API is problematic as it requires the dialplan author to understand intricate details of how ZRTP works to implement a correct dialplan. Further, by providing too fine-grained control (but at the same time, not enough control) it would limit our ability to make the behavior smarter once people started relying on this.
2012-05-24 20:39:03 +00:00
if (sofia_test_flag(tech_pvt, TFLAG_ZRTP_PASSTHRU)) {
switch_channel_set_flag(channel, CF_ZRTP_PASSTHRU_REQ);
}
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 && !zstr(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) {
switch_channel_set_variable(channel, "sip_via_host", sip->sip_via->v_host);
}
if (sip->sip_via->v_port) {
switch_channel_set_variable(channel, "sip_via_port", sip->sip_via->v_port);
}
if (sip->sip_via->v_rport) {
switch_channel_set_variable(channel, "sip_via_rport", sip->sip_via->v_rport);
}
}
if (sip->sip_multipart) {
msg_multipart_t *mp;
for (mp = sip->sip_multipart; mp; mp = mp->mp_next) {
if (mp->mp_payload && mp->mp_payload->pl_data && mp->mp_content_type && mp->mp_content_type->c_type) {
char *val = switch_core_session_sprintf(session, "%s:%s", mp->mp_content_type->c_type, mp->mp_payload->pl_data);
switch_channel_add_variable_var_check(channel, "sip_multipart", val, SWITCH_FALSE, SWITCH_STACK_PUSH);
}
}
}
if (sip->sip_max_forwards) {
char max_forwards[32];
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 (acl_context) context = acl_context;
if (!context) {
context = switch_channel_get_variable(channel, "user_context");
}
if (!context) {
if (profile->context && !strcasecmp(profile->context, "_domain_")) {
context = from_host;
} else {
context = profile->context;
}
}
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(nh->nh_home, (void *) alert_info);
switch_channel_set_variable(channel, "alert_info", tmp);
su_free(nh->nh_home, tmp);
}
if ((call_info = sip_call_info(sip))) {
call_info_str = sip_header_as_string(nh->nh_home, (void *) call_info);
if (sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE) && switch_stristr("appearance", call_info_str)) {
char *p;
switch_channel_set_variable(channel, "presence_call_info_full", call_info_str);
if ((p = strchr(call_info_str, ';'))) {
p++;
switch_channel_set_variable(channel, "presence_call_info", p);
}
}
if (call_info->ci_params && (msg_params_find(call_info->ci_params, "answer-after=0"))) {
switch_channel_set_variable(channel, "sip_auto_answer_detected", "true");
}
switch_channel_set_variable(channel, "sip_call_info", call_info_str);
call_info = call_info->ci_next;
while (call_info) {
call_info_str = sip_header_as_string(nh->nh_home, (void *) call_info);
switch_channel_add_variable_var_check(channel, "sip_call_info", call_info_str, SWITCH_FALSE, SWITCH_STACK_PUSH);
call_info = call_info->ci_next;
}
call_info = sip_call_info(sip);
} else if (sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE)) {
char buf[128] = "";
char *sql;
char *state = "progressing";
if (sip &&
sip->sip_from && sip->sip_from->a_url && sip->sip_from->a_url->url_user && sip->sip_from->a_url->url_host &&
sip->sip_to && sip->sip_to->a_url && sip->sip_to->a_url->url_user && sip->sip_to->a_url->url_host) {
sql =
switch_mprintf("select 'appearance-index=1' from sip_subscriptions where expires > -1 and hostname='%q' and event='call-info' and "
"sub_to_user='%q' and sub_to_host='%q'", mod_sofia_globals.hostname, sip->sip_to->a_url->url_user,
sip->sip_from->a_url->url_host);
sofia_glue_execute_sql2str(profile, profile->dbh_mutex, sql, buf, sizeof(buf));
if (mod_sofia_globals.debug_sla > 1) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "QUERY SQL %s [%s]\n", sql, buf);
}
free(sql);
if (!zstr(buf)) {
sql = switch_mprintf("update sip_dialogs set call_info='%q',call_info_state='%q' "
"where uuid='%q'", buf, state, switch_core_session_get_uuid(session));
if (mod_sofia_globals.debug_sla > 1) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "QUERY SQL %s\n", sql);
}
sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Auto-Fixing Broken SLA [<sip:%s>;%s]\n",
sip->sip_from->a_url->url_host, buf);
switch_channel_set_variable_printf(channel, "presence_call_info_full", "<sip:%s>;%s", sip->sip_from->a_url->url_host, buf);
switch_channel_set_variable(channel, "presence_call_info", buf);
call_info_str = switch_core_session_sprintf(session, "<sip:%s>;%s", sip->sip_from->a_url->url_host, buf);
}
}
}
if (profile->pres_type) {
const char *presence_id = switch_channel_get_variable(channel, "presence_id");
if (zstr(presence_id)) {
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);
}
}
if (sip->sip_request->rq_url->url_params) {
2011-11-04 18:16:47 +00:00
gw_param_name = switch_find_parameter(sip->sip_request->rq_url->url_params, "gw", switch_core_session_get_pool(session));
}
if (strstr(destination_number, "gw+")) {
if (sofia_test_pflag(profile, PFLAG_FULL_ID)) {
char *tmp;
gw_name = switch_core_session_strdup(session, destination_number + 3);
if ((tmp = strchr(gw_name, '@'))) {
*tmp = '\0';
}
} else {
gw_name = destination_number + 3;
}
}
if (gw_name || gw_param_name) {
sofia_gateway_t *gateway = NULL;
char *extension = NULL;
if (gw_name && ((gateway = sofia_reg_find_gateway(gw_name)))) {
gw_param_name = NULL;
extension = gateway->extension;
}
if (!gateway && gw_param_name) {
if ((gateway = sofia_reg_find_gateway(gw_param_name))) {
extension = gateway->real_extension;
}
}
if (gateway) {
context = switch_core_session_strdup(session, gateway->register_context);
switch_channel_set_variable(channel, "sip_gateway", gateway->name);
if (!zstr(extension)) {
if (!strcasecmp(extension, "auto_to_user")) {
destination_number = sip->sip_to->a_url->url_user;
} else if (!strcasecmp(extension, "auto")) {
if (gw_name) {
destination_number = sip->sip_to->a_url->url_user;
}
} else {
destination_number = switch_core_session_strdup(session, extension);
}
} else if (!gw_param_name) {
destination_number = sip->sip_to->a_url->url_user;
}
gateway->ib_calls++;
if (gateway->ib_vars) {
switch_event_header_t *hp;
for (hp = gateway->ib_vars->headers; hp; hp = hp->next) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s setting variable [%s]=[%s]\n",
switch_channel_get_name(channel), hp->name, hp->value);
switch_channel_set_variable(channel, hp->name, hp->value);
}
}
sofia_reg_release_gateway(gateway);
}
}
if (call_info_str) {
char *sql;
char cid[512] = "";
char *str;
char *p = NULL;
const char *user = NULL, *host = NULL, *from_user = NULL, *from_host = NULL;
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;
}
if (sip->sip_from && sip->sip_from->a_url) {
from_user = sip->sip_from->a_url->url_user;
from_host = sip->sip_from->a_url->url_host;
}
if (!user) user = from_user;
if (!host) user = from_host;
if (user && host && from_user && !strcmp(user, from_user)) {
if ((p = strchr(call_info_str, ';'))) {
p++;
}
sql =
switch_mprintf
("select call_id from sip_dialogs where call_info='%q' and ((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q') "
"and call_id is not null",
switch_str_nil(p), user, host, user, host);
if ((str = sofia_glue_execute_sql2str(profile, profile->dbh_mutex, sql, cid, sizeof(cid)))) {
bnh = nua_handle_by_call_id(nua, str);
}
if (mod_sofia_globals.debug_sla > 1) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "PICK SQL %s [%s] [%s] %d\n", sql, str, cid, !!bnh);
}
free(sql);
}
}
2011-09-01 20:10:23 +00:00
check_decode(displayname, session);
2013-07-20 02:50:55 +00:00
profile_dup_clean(from_user, tech_pvt->caller_profile->username, tech_pvt->caller_profile->pool);
profile_dup_clean(dialplan, tech_pvt->caller_profile->dialplan, tech_pvt->caller_profile->pool);
profile_dup_clean(displayname, tech_pvt->caller_profile->caller_id_name, tech_pvt->caller_profile->pool);
profile_dup_clean(from_user, tech_pvt->caller_profile->caller_id_number, tech_pvt->caller_profile->pool);
profile_dup_clean(displayname, tech_pvt->caller_profile->orig_caller_id_name, tech_pvt->caller_profile->pool);
profile_dup_clean(from_user, tech_pvt->caller_profile->orig_caller_id_number, tech_pvt->caller_profile->pool);
2013-07-20 02:50:55 +00:00
profile_dup_clean(network_ip, tech_pvt->caller_profile->network_addr, tech_pvt->caller_profile->pool);
2013-08-14 14:48:05 +00:00
profile_dup_clean(from_user, tech_pvt->caller_profile->ani, tech_pvt->caller_profile->pool);
2013-07-20 02:50:55 +00:00
profile_dup_clean(aniii, tech_pvt->caller_profile->aniii, tech_pvt->caller_profile->pool);
profile_dup_clean(context, tech_pvt->caller_profile->context, tech_pvt->caller_profile->pool);
profile_dup_clean(destination_number, tech_pvt->caller_profile->destination_number, tech_pvt->caller_profile->pool);
2011-09-01 20:10:23 +00:00
if (!bnh && sip->sip_replaces) {
if (!(bnh = nua_handle_by_replaces(nua, sip->sip_replaces))) {
if (!(bnh = nua_handle_by_call_id(nua, sip->sip_replaces->rp_call_id))) {
bnh = sofia_global_nua_handle_by_replaces(sip->sip_replaces);
}
}
}
if (bnh) {
sofia_private_t *b_private = NULL;
if ((b_private = nua_handle_magic(bnh))) {
switch_core_session_t *b_session = NULL;
if ((b_session = switch_core_session_locate(b_private->uuid))) {
switch_channel_t *b_channel = switch_core_session_get_channel(b_session);
2012-05-11 03:34:37 +00:00
const char *bridge_uuid;
2013-09-05 20:52:11 +00:00
switch_caller_profile_t *orig_cp, *cp;
2013-04-05 05:38:57 +00:00
//const char *sent_name, *sent_number;
2011-09-01 20:10:23 +00:00
orig_cp = switch_channel_get_caller_profile(b_channel);
2013-04-05 05:38:57 +00:00
tech_pvt->caller_profile->callee_id_name = switch_core_strdup(tech_pvt->caller_profile->pool, orig_cp->callee_id_name);
tech_pvt->caller_profile->callee_id_number = switch_core_strdup(tech_pvt->caller_profile->pool, orig_cp->callee_id_number);
if (!call_info) {
tech_pvt->caller_profile->caller_id_name = switch_core_strdup(tech_pvt->caller_profile->pool, orig_cp->caller_id_name);
tech_pvt->caller_profile->caller_id_number = switch_core_strdup(tech_pvt->caller_profile->pool, orig_cp->caller_id_number);
}
2013-04-05 05:38:57 +00:00
2013-09-05 20:52:11 +00:00
if (orig_cp) {
cp = switch_caller_profile_dup(tech_pvt->caller_profile->pool, orig_cp);
switch_channel_set_originator_caller_profile(channel, cp);
}
2013-04-05 05:38:57 +00:00
#if 0
2011-09-01 20:10:23 +00:00
sent_name = switch_channel_get_variable(b_channel, "last_sent_callee_id_name");
sent_number = switch_channel_get_variable(b_channel, "last_sent_callee_id_number");
if (!zstr(sent_name) && !zstr(sent_number)) {
tech_pvt->caller_profile->callee_id_name = switch_core_strdup(tech_pvt->caller_profile->pool, sent_name);
tech_pvt->caller_profile->callee_id_number = switch_core_strdup(tech_pvt->caller_profile->pool, sent_number);
} else {
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) {
tech_pvt->caller_profile->callee_id_name = switch_core_strdup(tech_pvt->caller_profile->pool, orig_cp->callee_id_name);
tech_pvt->caller_profile->callee_id_number = switch_core_strdup(tech_pvt->caller_profile->pool, orig_cp->callee_id_number);
} else {
tech_pvt->caller_profile->callee_id_name = switch_core_strdup(tech_pvt->caller_profile->pool, orig_cp->caller_id_name);
tech_pvt->caller_profile->callee_id_number = switch_core_strdup(tech_pvt->caller_profile->pool, orig_cp->caller_id_number);
}
}
2013-04-05 05:38:57 +00:00
#endif
2012-04-04 20:52:01 +00:00
if (is_nat) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Setting NAT mode based on %s\n", is_nat);
}
2011-09-01 20:10:23 +00:00
2012-05-11 03:34:37 +00:00
tech_pvt->caller_profile->dialplan = "inline";
bridge_uuid = switch_channel_get_partner_uuid(b_channel);
2012-05-11 03:34:37 +00:00
if (call_info) {
const char *olu;
switch_core_session_t *os;
switch_codec_implementation_t read_impl = { 0 };
char *codec_str = "";
if (!zstr(bridge_uuid) && switch_channel_test_flag(b_channel, CF_LEG_HOLDING)) {
olu = bridge_uuid;
} else {
olu = b_private->uuid;
}
if ((os = switch_core_session_locate(olu))) {
switch_core_session_get_real_read_impl(os, &read_impl);
switch_core_session_rwunlock(os);
codec_str = switch_core_session_sprintf(session, "set:absolute_codec_string=%s@%di,", read_impl.iananame,
read_impl.microseconds_per_packet / 1000);
}
2012-05-11 03:34:37 +00:00
if (!zstr(bridge_uuid) && switch_channel_test_flag(b_channel, CF_LEG_HOLDING)) {
const char *b_call_id = switch_channel_get_variable(b_channel, "sip_call_id");
if (b_call_id) {
char *sql = switch_mprintf("update sip_dialogs set call_info_state='idle' where call_id='%q'", b_call_id);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "SQL: %s\n", sql);
sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
switch_channel_presence(b_channel, "unknown", "idle", NULL);
}
switch_channel_set_flag(tech_pvt->channel, CF_SLA_INTERCEPT);
tech_pvt->caller_profile->destination_number = switch_core_sprintf(tech_pvt->caller_profile->pool,
"%sanswer,intercept:%s", codec_str, bridge_uuid);
2012-05-11 03:34:37 +00:00
} else {
2013-04-05 05:38:57 +00:00
switch_caller_profile_t *bcp = switch_channel_get_caller_profile(b_channel);
2013-09-05 23:48:56 +00:00
if (switch_channel_test_flag(b_channel, CF_BRIDGE_ORIGINATOR)) {
switch_channel_set_flag(tech_pvt->channel, CF_BRIDGE_ORIGINATOR);
}
if (!zstr(bcp->callee_id_name)) {
tech_pvt->caller_profile->callee_id_name = switch_core_strdup(tech_pvt->caller_profile->pool, bcp->callee_id_name);
}
if (!zstr(bcp->callee_id_number)) {
tech_pvt->caller_profile->callee_id_number = switch_core_strdup(tech_pvt->caller_profile->pool, bcp->callee_id_number);
}
2013-09-05 23:48:56 +00:00
if (!zstr(bcp->caller_id_name)) {
tech_pvt->caller_profile->caller_id_name = switch_core_strdup(tech_pvt->caller_profile->pool, bcp->caller_id_name);
}
if (!zstr(bcp->caller_id_number)) {
tech_pvt->caller_profile->caller_id_number = switch_core_strdup(tech_pvt->caller_profile->pool, bcp->caller_id_number);
}
2013-04-05 05:38:57 +00:00
2013-09-05 20:52:11 +00:00
if (bcp->originatee_caller_profile) {
switch_caller_profile_t *cp;
cp = switch_caller_profile_dup(tech_pvt->caller_profile->pool,
bcp->originatee_caller_profile);
switch_channel_set_originatee_caller_profile(tech_pvt->channel, cp);
}
2013-09-05 15:35:31 +00:00
tech_pvt->caller_profile->destination_number = switch_core_sprintf(tech_pvt->caller_profile->pool,
"%sanswer,sofia_sla:%s", codec_str, b_private->uuid);
2012-05-11 03:34:37 +00:00
}
} else {
if (!zstr(bridge_uuid)) {
switch_channel_mark_hold(b_channel, SWITCH_FALSE);
tech_pvt->caller_profile->destination_number = switch_core_sprintf(tech_pvt->caller_profile->pool, "answer,intercept:%s", bridge_uuid);
} else {
const char *b_app = switch_channel_get_variable(b_channel, SWITCH_CURRENT_APPLICATION_VARIABLE);
const char *b_data = switch_channel_get_variable(b_channel, SWITCH_CURRENT_APPLICATION_DATA_VARIABLE);
2012-05-11 03:34:37 +00:00
if (b_data && b_app) {
tech_pvt->caller_profile->destination_number = switch_core_sprintf(tech_pvt->caller_profile->pool, "answer,%s:%s", b_app, b_data);
} else if (b_app) {
tech_pvt->caller_profile->destination_number = switch_core_sprintf(tech_pvt->caller_profile->pool, "answer,%s", b_app);
}
2012-05-11 03:34:37 +00:00
switch_channel_hangup(b_channel, SWITCH_CAUSE_ATTENDED_TRANSFER);
}
}
switch_core_session_rwunlock(b_session);
}
}
nua_handle_unref(bnh);
}
2011-09-01 20:10:23 +00:00
if (tech_pvt->caller_profile) {
int first_history_info = 1;
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);
}
}
if ((privacy = sip_privacy(sip))) {
char *full_priv_header = sip_header_as_string(nh->nh_home, (void *) privacy);
if (!zstr(full_priv_header)) {
switch_channel_set_variable(channel, "sip_Privacy", full_priv_header);
}
if (msg_params_find(privacy->priv_values, "id")) {
switch_set_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NAME | SWITCH_CPF_HIDE_NUMBER);
}
}
/* 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, "Diversion", 9)) {
/* Basic Diversion Support for Diversion Indication in SIP */
/* draft-levy-sip-diversion-08 */
if (!zstr(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, "History-Info", 12)) {
if (first_history_info) {
/* If the header exists first time, make sure to remove old info and re-set the variable */
switch_channel_set_variable(channel, "sip_history_info", un->un_value);
first_history_info = 0;
} else {
/* Append the History-Info into one long string */
const char *history_var = switch_channel_get_variable(channel, "sip_history_info");
if (!zstr(history_var)) {
char *tmp_str;
if ((tmp_str = switch_mprintf("%s, %s", history_var, un->un_value))) {
switch_channel_set_variable(channel, "sip_history_info", tmp_str);
free(tmp_str);
} else {
switch_channel_set_variable(channel, "sip_history_info", un->un_value);
}
} else {
switch_channel_set_variable(channel, "sip_history_info", un->un_value);
}
}
2011-01-13 01:34:19 +00:00
} else if (!strcasecmp(un->un_name, "X-FS-Channel-Name") && !zstr(un->un_value)) {
switch_channel_set_name(channel, un->un_value);
switch_channel_set_variable(channel, "push_channel_name", "true");
} else if (!strcasecmp(un->un_name, "X-FS-Support")) {
tech_pvt->x_freeswitch_support_remote = switch_core_session_strdup(session, un->un_value);
2013-04-18 21:44:40 +00:00
} else if (!strcasecmp(un->un_name, "Geolocation")) {
switch_channel_set_variable(channel, "sip_geolocation", un->un_value);
2014-07-15 19:55:46 +00:00
} else if (!strcasecmp(un->un_name, "Geolocation-Error")) {
switch_channel_set_variable(channel, "sip_geolocation_error", un->un_value);
2013-01-07 19:41:08 +00:00
} else if (!strncasecmp(un->un_name, "X-", 2) || !strncasecmp(un->un_name, "P-", 2) || !strcasecmp(un->un_name, "User-to-User")) {
if (!zstr(un->un_value)) {
char new_name[512] = "";
int reps = 0;
for (;;) {
char postfix[25] = "";
if (reps > 0) {
switch_snprintf(postfix, sizeof(postfix), "-%d", reps);
}
reps++;
switch_snprintf(new_name, sizeof(new_name), "%s%s%s", SOFIA_SIP_HEADER_PREFIX, un->un_name, postfix);
if (switch_channel_get_variable(channel, new_name)) {
continue;
}
switch_channel_set_variable(channel, new_name, un->un_value);
break;
}
}
}
}
}
tech_pvt->sofia_private = sofia_private;
tech_pvt->nh = nh;
2010-08-18 19:58:14 +00:00
if (profile->pres_type && sofia_test_pflag(profile, PFLAG_IN_DIALOG_CHAT)) {
sofia_presence_set_chat_hash(tech_pvt, sip);
}
if (sofia_test_pflag(profile, PFLAG_PARSE_ALL_INVITE_HEADERS)) {
sofia_parse_all_invite_headers(sip, session, nh);
}
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;
}
2012-08-16 17:09:19 +00:00
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);
to_tag = switch_str_nil(sip->sip_to->a_tag);
}
if (from) {
dialog_from_user = switch_str_nil(from->url_user);
dialog_from_host = switch_str_nil(from->url_host);
from_tag = switch_str_nil(sip->sip_from->a_tag);
}
if (contact) {
contact_user = switch_str_nil(contact->url_user);
contact_host = switch_str_nil(contact->url_host);
}
if (profile->pres_type) {
const char *presence_data = switch_channel_get_variable(channel, "presence_data");
const char *presence_id = switch_channel_get_variable(channel, "presence_id");
char *full_contact = "";
char *p = NULL;
time_t now;
if (sip->sip_contact) {
full_contact = sip_header_as_string(nua_handle_home(tech_pvt->nh), (void *) sip->sip_contact);
}
if (call_info_str && switch_stristr("appearance", call_info_str)) {
switch_channel_set_variable(channel, "presence_call_info_full", call_info_str);
if ((p = strchr(call_info_str, ';'))) {
p++;
switch_channel_set_variable(channel, "presence_call_info", p);
}
}
now = switch_epoch_time_now(NULL);
sql = switch_mprintf("insert into sip_dialogs "
"(call_id,uuid,sip_to_user,sip_to_host,sip_to_tag,sip_from_user,sip_from_host,sip_from_tag,contact_user,"
"contact_host,state,direction,user_agent,profile_name,hostname,contact,presence_id,presence_data,"
"call_info,rcd,call_info_state) "
"values('%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q',%ld,'')",
call_id,
tech_pvt->sofia_private->uuid,
to_user, to_host, to_tag, dialog_from_user, dialog_from_host, from_tag,
contact_user, contact_host, "confirmed", "inbound", user_agent,
profile->name, mod_sofia_globals.hostname, switch_str_nil(full_contact),
switch_str_nil(presence_id), switch_str_nil(presence_data), switch_str_nil(p), now);
switch_assert(sql);
2012-08-16 17:09:19 +00:00
sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
if ( full_contact ) {
su_free(nua_handle_home(tech_pvt->nh), full_contact);
}
}
if (is_nat) {
sofia_set_flag(tech_pvt, TFLAG_NAT);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Setting NAT mode based on %s\n", is_nat);
switch_channel_set_variable(channel, "sip_nat_detected", "true");
}
return;
fail:
profile->ib_failed_calls++;
return;
}
void sofia_handle_sip_i_options(int status,
char const *phrase,
nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip,
sofia_dispatch_event_t *de,
tagi_t tags[])
{
2011-11-15 20:26:42 +00:00
uint32_t sess_count = switch_core_session_count();
uint32_t sess_max = switch_core_session_limit(0);
if (sofia_test_pflag(profile, PFLAG_OPTIONS_RESPOND_503_ON_BUSY) &&
2011-12-14 19:23:54 +00:00
(sess_count >= sess_max || !sofia_test_pflag(profile, PFLAG_RUNNING) || !switch_core_ready_inbound())) {
2011-11-15 20:26:42 +00:00
nua_respond(nh, 503, "Maximum Calls In Progress", NUTAG_WITH_THIS_MSG(de->data->e_msg), SIPTAG_RETRY_AFTER_STR("300"), TAG_END());
} else {
nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg),
TAG_IF(sip->sip_record_route, SIPTAG_RECORD_ROUTE(sip->sip_record_route)), TAG_END());
2011-11-15 20:26:42 +00:00
}
}
/*
* 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@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 params 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 params data or the */
/* equal (=) sign separating 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 noet:
*/