diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 267286daf8..4917cd8824 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -72,6 +72,7 @@ static switch_status_t sofia_kill_channel(switch_core_session_t *session, int si */ static switch_status_t sofia_on_init(switch_core_session_t *session) { + const char *hval = NULL; switch_channel_t *channel = switch_core_session_get_channel(session); private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session); switch_status_t status = SWITCH_STATUS_SUCCESS; @@ -89,6 +90,23 @@ static switch_status_t sofia_on_init(switch_core_session_t *session) switch_core_media_absorb_sdp(session); } + if ((hval = switch_channel_get_variable(channel, "sip_watch_headers"))) { + char *dupvar = NULL; + char *watch_headers[10]; + unsigned int numhdrs = 0; + int i = 0; + dupvar = switch_core_session_strdup(session, hval); + numhdrs = switch_separate_string(dupvar, ',', watch_headers, switch_arraylen(watch_headers)); + if (numhdrs) { + char **wheaders = switch_core_session_alloc(session, ((numhdrs+1) * sizeof(wheaders[0]))); + for (i = 0; i < numhdrs; i++) { + wheaders[i] = watch_headers[i]; + } + wheaders[i] = NULL; + tech_pvt->watch_headers = wheaders; + } + } + if (switch_channel_test_flag(tech_pvt->channel, CF_RECOVERING) || switch_channel_test_flag(tech_pvt->channel, CF_RECOVERING_BRIDGE)) { sofia_set_flag(tech_pvt, TFLAG_RECOVERED); } diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index eecde673fd..864eff79ac 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -96,6 +96,7 @@ typedef struct private_object private_object_t; #define MY_EVENT_RECOVERY_RECOVERED "sofia::recovery_recovered" #define MY_EVENT_ERROR "sofia::error" #define MY_EVENT_PROFILE_START "sofia::profile_start" +#define MY_EVENT_NOTIFY_WATCHED_HEADER "sofia::notify_watched_header" #define MULTICAST_EVENT "multicast::event" #define SOFIA_REPLACES_HEADER "_sofia_replaces_" @@ -805,6 +806,7 @@ struct private_object { sofia_cid_type_t cid_type; uint32_t session_timeout; enum nua_session_refresher session_refresher; + char **watch_headers; char *respond_phrase; int respond_code; char *respond_dest; diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 6b969ca388..cf461262d3 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -1272,6 +1272,21 @@ static void tech_send_ack(nua_handle_t *nh, private_object_t *tech_pvt) } +static void notify_watched_header(switch_core_session_t *session, const char *msgline, const char *hdrname, const char *hdrval) +{ + switch_event_t *event = NULL; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Found known watched header in message '%s', %s: %s\n", msgline, hdrname, hdrval); + if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, MY_EVENT_NOTIFY_WATCHED_HEADER) == SWITCH_STATUS_SUCCESS) { + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "SIP-Message", msgline); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Header-Name", hdrname); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Header-Value", hdrval); + switch_channel_event_set_data(channel, event); + switch_event_fire(&event); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Failed creating event of type %s!\n", MY_EVENT_NOTIFY_WATCHED_HEADER); + } +} //sofia_dispatch_event_t *de static void our_sofia_event_callback(nua_event_t event, @@ -1347,6 +1362,56 @@ static void our_sofia_event_callback(nua_event_t event, } } + if (session && tech_pvt && tech_pvt->watch_headers && sip) { + char msgline[512]; + int hi; + msg_header_t *h = NULL; + if (sip->sip_request) { + h = (msg_header_t *)sip->sip_request; + msg_header_field_e(msgline, sizeof(msgline), h, 0); + } else if (sip->sip_status) { + h = (msg_header_t *)sip->sip_status; + msg_header_field_e(msgline, sizeof(msgline), h, 0); + } + if (h) { + sip_unknown_t *un = NULL; + char buf[512]; + char *c = NULL; + + msgline[sizeof(msgline)-1] = '\0'; + c = strchr(msgline, '\r'); + if (c) { + *c = '\0'; + } + + /* Faster (ie hash-based) search here would be nice? ie, make watch_headers a hash? */ + + /* Search first in the valid headers */ + for (h = h->sh_succ; h; h = h->sh_succ) { + sip_header_t *sh = (sip_header_t *)h; + if (!sh->sh_class->hc_name) { + continue; + } + for (hi = 0; tech_pvt->watch_headers[hi]; hi++) { + if (!strcasecmp(tech_pvt->watch_headers[hi], sh->sh_class->hc_name)) { + msg_header_field_e(buf, sizeof(buf), h, 0); + buf[sizeof(buf)-1] = '\0'; + notify_watched_header(session, msgline, sh->sh_class->hc_name, buf); + } + } + } + + /* Search now in the unknown headers */ + for (un = sip->sip_unknown; un; un = un->un_next) { + for (hi = 0; tech_pvt->watch_headers[hi]; hi++) { + if (!strcasecmp(tech_pvt->watch_headers[hi], un->un_name)) { + notify_watched_header(session, msgline, un->un_name, un->un_value); + } + } + } + } + } + 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;