From e9bde2eb0e1e70acbb67f4249a8789fbd1f568b5 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Thu, 15 Dec 2011 16:30:33 -0600 Subject: [PATCH] FS-3758 --resolve ok so I wrote my own patch but i did borrow the 2 lines of code to create a seq from the original patch! sofia changes probably need to be converted to a tag if they are to go upstream. This completely manages sub/pub from inside mod_sofia inside the db and subs can now persist and/or fail over mid dialog tested on several things like polycom/snom/yealink on SLA and presence --- .../libsofia-sip-ua/nua/nua_notifier.c | 6 +- .../libsofia-sip-ua/nua/nua_server.c | 5 +- src/mod/endpoints/mod_sofia/Makefile.am | 2 +- src/mod/endpoints/mod_sofia/mod_sofia.h | 22 +- src/mod/endpoints/mod_sofia/sofia.c | 47 +- src/mod/endpoints/mod_sofia/sofia_glue.c | 9 +- src/mod/endpoints/mod_sofia/sofia_presence.c | 497 ++++++++++-------- src/mod/endpoints/mod_sofia/sofia_reg.c | 36 +- src/mod/endpoints/mod_sofia/sofia_sla.c | 413 --------------- 9 files changed, 314 insertions(+), 723 deletions(-) delete mode 100644 src/mod/endpoints/mod_sofia/sofia_sla.c diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_notifier.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_notifier.c index 6064333ba3..923e8de416 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_notifier.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/nua_notifier.c @@ -827,10 +827,10 @@ static int nua_notify_usage_shutdown(nua_handle_t *nh, nua_dialog_usage_t *du) { struct notifier_usage *nu = nua_dialog_usage_private(du); - nua_client_request_t *cr = du->du_cr; + //nua_client_request_t *cr = du->du_cr; nu->nu_substate = nua_substate_terminated; - +#if 0 if (cr) { SU_DEBUG_5(("%s(%p, %p, %p): using existing cr=%p\n", "nua_notify_usage_shutdown", @@ -852,7 +852,7 @@ static int nua_notify_usage_shutdown(nua_handle_t *nh, TAG_END()) >= 0) return 0; } - +#endif nua_dialog_usage_remove(nh, ds, du, NULL, NULL); return 200; } diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_server.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_server.c index c8c42f44f9..50150a3a42 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_server.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/nua_server.c @@ -158,14 +158,15 @@ int nua_stack_process_request(nua_handle_t *nh, /* These must be in-dialog */ sm = NULL; } - else if (initial && sip->sip_to->a_tag) { + else if (initial && sip->sip_to->a_tag && method != sip_method_subscribe) { /* RFC 3261 section 12.2.2: If the UAS wishes to reject the request because it does not wish to recreate the dialog, it MUST respond to the request with a 481 (Call/Transaction Does Not Exist) status code and pass that to the server transaction. - */ + */ /* we allow this on subscribes because we have disabled the built-in notify server and we need those messages in the application layer */ + if (method == sip_method_info) /* accept out-of-dialog info */; else if (method != sip_method_message || !NH_PGET(nh, win_messenger_enable)) diff --git a/src/mod/endpoints/mod_sofia/Makefile.am b/src/mod/endpoints/mod_sofia/Makefile.am index 5825fc7f5c..fb0ab25e0b 100644 --- a/src/mod/endpoints/mod_sofia/Makefile.am +++ b/src/mod/endpoints/mod_sofia/Makefile.am @@ -9,7 +9,7 @@ SOFIAUA_BUILDDIR=$(SOFIA_BUILDDIR)/libsofia-sip-ua SOFIALA=$(SOFIAUA_BUILDDIR)/libsofia-sip-ua.la mod_LTLIBRARIES = mod_sofia.la -mod_sofia_la_SOURCES = mod_sofia.c sofia.c sofia_glue.c sofia_presence.c sofia_reg.c sofia_sla.c sip-dig.c mod_sofia.h +mod_sofia_la_SOURCES = mod_sofia.c sofia.c sofia_glue.c sofia_presence.c sofia_reg.c sip-dig.c mod_sofia.h mod_sofia_la_CFLAGS = $(AM_CFLAGS) -I. $(SOFIA_CMD_LINE_CFLAGS) mod_sofia_la_CFLAGS += -I$(SOFIAUA_DIR)/bnf -I$(SOFIAUA_BUILDDIR)/bnf mod_sofia_la_CFLAGS += -I$(SOFIAUA_DIR)/http -I$(SOFIAUA_BUILDDIR)/http diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index 2648598b72..7a1dc87868 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -217,7 +217,7 @@ typedef enum { PFLAG_UUID_AS_CALLID, PFLAG_SCROOGE, PFLAG_MANAGE_SHARED_APPEARANCE, - PFLAG_MANAGE_SHARED_APPEARANCE_SYLANTRO, + PFLAG_MANAGE_SHARED_APPEARANCE_SYLANTRO_DELETED_USE_ME, PFLAG_DISABLE_SRV, PFLAG_DISABLE_SRV503, PFLAG_DISABLE_NAPTR, @@ -634,6 +634,7 @@ struct sofia_profile { int watchdog_enabled; switch_mutex_t *gw_mutex; uint32_t queued_events; + uint32_t cseq_base; }; struct private_object { @@ -1064,24 +1065,6 @@ switch_status_t sofia_glue_tech_set_codec(private_object_t *tech_pvt, int force) void sofia_wait_for_reply(struct private_object *tech_pvt, nua_event_t event, uint32_t timeout); void sofia_glue_set_image_sdp(private_object_t *tech_pvt, switch_t38_options_t *t38_options, int insist); -/* - * SLA (shared line appearance) entrypoints - */ - -void sofia_sla_handle_register(nua_t *nua, sofia_profile_t *profile, sip_t const *sip, - sofia_dispatch_event_t *de, long exptime, const char *full_contact); -void sofia_sla_handle_sip_i_publish(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip, - sofia_dispatch_event_t *de, tagi_t tags[]); -void sofia_sla_handle_sip_i_subscribe(nua_t *nua, const char *contact_str, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip, - sofia_dispatch_event_t *de, tagi_t tags[]); -void sofia_sla_handle_sip_r_subscribe(int status, - char const *phrase, - nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, - sofia_dispatch_event_t *de, - tagi_t tags[]); -void sofia_sla_handle_sip_i_notify(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip, - sofia_dispatch_event_t *de, tagi_t tags[]); - /* * Logging control functions */ @@ -1145,3 +1128,4 @@ char *sofia_glue_gen_contact_str(sofia_profile_t *profile, sip_t const *sip, sof void sofia_glue_pause_jitterbuffer(switch_core_session_t *session, switch_bool_t on); void sofia_process_dispatch_event(sofia_dispatch_event_t **dep); char *sofia_glue_get_host(const char *str, switch_memory_pool_t *pool); +void sofia_presence_check_subscriptions(sofia_profile_t *profile, time_t now); diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 70cb12684e..759d8f1219 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -90,7 +90,8 @@ void sofia_handle_sip_r_notify(switch_core_session_t *session, int status, if (status >= 300 && sip && sip->sip_call_id && (!sofia_private || !sofia_private->is_call)) { char *sql; - sql = switch_mprintf("delete from sip_subscriptions where call_id='%q'", sip->sip_call_id->i_id); + + sql = switch_mprintf("update sip_subscriptions set expires=%ld where call_id='%q'", (long) switch_epoch_time_now(NULL), sip->sip_call_id->i_id); switch_assert(sql != NULL); sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE); nua_handle_destroy(nh); @@ -238,19 +239,21 @@ static void extract_header_vars(sofia_profile_t *profile, sip_t const *sip, switch_stream_handle_t stream = { 0 }; int x = 0; - SWITCH_STANDARD_STREAM(stream); - - for(vp = sip->sip_via; vp; vp = vp->v_next) { - char *v = sip_header_as_string(nh->nh_home, (void *) vp); - - stream.write_function(&stream, x == 0 ? "%s" : ",%s", v); - su_free(nh->nh_home, v); + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { + SWITCH_STANDARD_STREAM(stream); - x++; + for(vp = sip->sip_via; vp; vp = vp->v_next) { + char *v = sip_header_as_string(nh->nh_home, (void *) vp); + + stream.write_function(&stream, x == 0 ? "%s" : ",%s", v); + su_free(nh->nh_home, v); + + x++; + } + + switch_channel_set_variable(channel, "sip_recover_via", (char *)stream.data); + free(stream.data); } - - switch_channel_set_variable(channel, "sip_recover_via", (char *)stream.data); - free(stream.data); } if (sip->sip_from) { @@ -337,21 +340,6 @@ void sofia_handle_sip_i_notify(switch_core_session_t *session, int status, goto error; } - /* the following could be refactored back to the calling event handler here in sofia.c XXX MTK */ - /* potentially interesting note: for Linksys shared appearance, we'll probably have to set up to get bare notifies - * and pass them inward to the sla handler. we'll have to set NUTAG_APPL_METHOD("NOTIFY") when creating - * nua, and also pick them off special elsewhere here in sofia.c - MTK - * *and* for Linksys, I believe they use "sa" as their magic appearance agent name for those blind notifies, so - * we'll probably have to change to match - */ - if (sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE)) { - - if (sip->sip_request->rq_url->url_user && !strncmp(sip->sip_request->rq_url->url_user, "sla-agent", sizeof("sla-agent"))) { - sofia_sla_handle_sip_i_notify(nua, profile, nh, sip, de, tags); - goto end; - } - } - /* 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? */ @@ -4077,8 +4065,9 @@ switch_status_t config_sofia(int reload, char *profile_name) sofia_set_pflag(profile, PFLAG_MULTIREG); } else if (!strcasecmp(val, "sylantro")) { - profile->sla_contact = switch_core_sprintf(profile->pool, "sla-agent"); - sofia_set_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE_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."); } } else if (!strcasecmp(var, "disable-srv")) { if (switch_true(val)) { diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index ed16ce0a8a..191dd5083a 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -5904,7 +5904,8 @@ int sofia_glue_init_sql(sofia_profile_t *profile) " network_port VARCHAR(6),\n" " network_ip VARCHAR(255),\n" " version INTEGER DEFAULT 0 NOT NULL,\n" - " orig_proto VARCHAR(255)\n" + " orig_proto VARCHAR(255),\n" + " full_to VARCHAR(255)\n" ");\n"; char auth_sql[] = @@ -6047,10 +6048,8 @@ int sofia_glue_init_sql(sofia_profile_t *profile) free(test_sql); - - test_sql = switch_mprintf("delete from sip_subscriptions where hostname='%q' " - "and (version < 0 or orig_proto like '%%' or network_ip like '%%' or network_port like '%%')", - mod_sofia_globals.hostname); + test_sql = switch_mprintf("delete from sip_subscriptions where hostname='%q' and full_to='XXX'", mod_sofia_globals.hostname); + switch_cache_db_test_reactive(dbh, test_sql, "DROP TABLE sip_subscriptions", sub_sql); free(test_sql); diff --git a/src/mod/endpoints/mod_sofia/sofia_presence.c b/src/mod/endpoints/mod_sofia/sofia_presence.c index b165d62e17..c9b8539fed 100644 --- a/src/mod/endpoints/mod_sofia/sofia_presence.c +++ b/src/mod/endpoints/mod_sofia/sofia_presence.c @@ -537,14 +537,14 @@ static void actual_sofia_presence_mwi_event_handler(switch_event_t *event) if (for_everyone) { sql = switch_mprintf("select proto,sip_user,sip_host,sub_to_user,sub_to_host,event,contact,call_id,full_from," "full_via,expires,user_agent,accept,profile_name,network_ip" - ",'%q','%q' from sip_subscriptions where version > -1 and expires > -1 and event='message-summary' " - "and sub_to_user='%q' and (sub_to_host='%q' or presence_hosts like '%%%q%%')", stream.data, host, user, host, host); + ",'%q',full_to,network_ip,network_port from sip_subscriptions where version > -1 and expires > -1 and event='message-summary' " + "and sub_to_user='%q' and (sub_to_host='%q' or presence_hosts like '%%%q%%')", stream.data, user, host, host); } else if (sub_call_id) { sql = switch_mprintf("select proto,sip_user,sip_host,sub_to_user,sub_to_host,event,contact,call_id,full_from," "full_via,expires,user_agent,accept,profile_name,network_ip" - ",'%q','%q' from sip_subscriptions where version > -1 and expires > -1 and event='message-summary' " + ",'%q',full_to,network_ip,network_port from sip_subscriptions where version > -1 and expires > -1 and event='message-summary' " "and sub_to_user='%q' and (sub_to_host='%q' or presence_hosts like '%%%q%%' and call_id='%q')", - stream.data, host, user, host, host, sub_call_id); + stream.data, user, host, host, sub_call_id); } @@ -798,7 +798,7 @@ static void do_dialog_probe(sofia_profile_t *profile, switch_event_t *event) // The dialog_probe_callback has built up the dialogs to be included in the NOTIFY. // Now send the "full" dialog event to the triggering subscription. sql = switch_mprintf("select call_id,expires,sub_to_user,sub_to_host,event,version, " - "'full' " + "'full',full_to,full_from,contact,expires,event,network_ip,network_port " "from sip_subscriptions " "where expires > -1 and hostname='%q' " "and sub_to_user='%q' and sub_to_host='%q' " "and (event='dialog') and " @@ -887,7 +887,8 @@ static void actual_sofia_presence_event_handler(switch_event_t *event) "sip_subscriptions.contact,sip_subscriptions.call_id,sip_subscriptions.full_from," "sip_subscriptions.full_via,sip_subscriptions.expires,sip_subscriptions.user_agent," "sip_subscriptions.accept,sip_subscriptions.profile_name,sip_subscriptions.network_ip" - ",1,'%q','%q',sip_presence.status,sip_presence.rpid,sip_presence.open_closed " + ",1,'%q','%q',sip_presence.status,sip_presence.rpid,sip_presence.open_closed,'','','','','sip'," + " sip_subscriptions.full_to,sip_subscriptions.network_ip,sip_subscriptions.network_port " "from sip_subscriptions left join sip_presence on " "(sip_subscriptions.sub_to_user=sip_presence.sip_user and sip_subscriptions.sub_to_host=sip_presence.sip_host and " "sip_subscriptions.profile_name=sip_presence.profile_name) " @@ -900,7 +901,8 @@ static void actual_sofia_presence_event_handler(switch_event_t *event) "sip_subscriptions.contact,sip_subscriptions.call_id,sip_subscriptions.full_from," "sip_subscriptions.full_via,sip_subscriptions.expires,sip_subscriptions.user_agent," "sip_subscriptions.accept,sip_subscriptions.profile_name,sip_subscriptions.network_ip" - ",1,'%q','%q',sip_presence.status,sip_presence.rpid,sip_presence.open_closed " + ",1,'%q','%q',sip_presence.status,sip_presence.rpid,sip_presence.open_closed,'','','','','sip'," + "sip_subscriptions.full_to,sip_subscriptions.network_ip,sip_subscriptions.network_port " "from sip_subscriptions left join sip_presence on " "(sip_subscriptions.sub_to_user=sip_presence.sip_user and sip_subscriptions.sub_to_host=sip_presence.sip_host and " "sip_subscriptions.profile_name=sip_presence.profile_name) " @@ -1028,7 +1030,6 @@ static void actual_sofia_presence_event_handler(switch_event_t *event) call_info, call_info_state, mod_sofia_globals.hostname, euser, host, euser, host, call_info); } - //printf("WTF %s\n", sql); if (mod_sofia_globals.debug_sla > 1) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "STATE SQL %s\n", sql); @@ -1068,7 +1069,8 @@ static void actual_sofia_presence_event_handler(switch_event_t *event) "sip_subscriptions.full_via,sip_subscriptions.expires,sip_subscriptions.user_agent," "sip_subscriptions.accept,sip_subscriptions.profile_name" ",'%q','%q','%q',sip_presence.status,sip_presence.rpid,sip_presence.open_closed,'%q','%q'," - "sip_subscriptions.version, '%q',sip_subscriptions.orig_proto " + "sip_subscriptions.version, '%q',sip_subscriptions.orig_proto,sip_subscriptions.full_to," + "sip_subscriptions.network_ip, sip_subscriptions.network_port " "from sip_subscriptions " "left join sip_presence on " "(sip_subscriptions.sub_to_user=sip_presence.sip_user and sip_subscriptions.sub_to_host=sip_presence.sip_host and " @@ -1638,6 +1640,111 @@ static int sofia_dialog_probe_callback(void *pArg, int argc, char **argv, char * return 0; } +static void send_presence_notify(sofia_profile_t *profile, + const char *full_to, + const char *full_from, + const char *contact, + const char *expires, + const char *call_id, + const char *event, + const char *remote_ip, + const char *remote_port, + const char *ct, + const char *pl, + const char *call_info + ) +{ + char sstr[128] = ""; + nua_handle_t *nh; + int exptime = 0; + char expires_str[10] = ""; + char *tmp, *route = NULL; + sip_cseq_t *cseq = NULL; + uint32_t callsequence; + uint32_t now = (uint32_t) switch_epoch_time_now(NULL); + + if (expires) { + long ltmp = atol(expires); + + if (ltmp > 0) { + exptime = (ltmp - now); + } else { + exptime = 0; + } + } + + + switch_mutex_lock(profile->ireg_mutex); + if (!profile->cseq_base) { + profile->cseq_base = (now - 1312693200) * 10; + } + callsequence = ++profile->cseq_base; + switch_mutex_unlock(profile->ireg_mutex); + + + nh = nua_handle(profile->nua, NULL, TAG_END()); + cseq = sip_cseq_create(nh->nh_home, callsequence, SIP_METHOD_NOTIFY); + nua_handle_bind(nh, &mod_sofia_globals.destroy_private); + + if (exptime > 0) { + switch_snprintf(sstr, sizeof(sstr), "active;expires=%u", (unsigned) exptime); + } else { + switch_snprintf(sstr, sizeof(sstr), "terminated;reason=noresource"); + } + + + tmp = (char *)contact; + contact = sofia_glue_get_url_from_contact(tmp, 0); + + if (remote_ip && remote_port) { + route = switch_mprintf("sip:%s:%s", remote_ip, remote_port); + } + + if (mod_sofia_globals.debug_presence > 1) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SEND PRES NOTIFY:\n" + "route[%s]\ncontact[%s]\nto[%s]\nfrom[%s]\nurl[%s]\ncall_id[%s]\nexpires_str[%s]\n" + "event[%s]\nct[%s]\npl[%s]\ncall_info[%s]\nexptime[%ld]\n", + route, + contact, + full_to, + full_from, + profile->url, + call_id, + expires_str, + event, + switch_str_nil(ct), + switch_str_nil(pl), + switch_str_nil(call_info), + (long)exptime + ); + + + } + + nua_notify(nh, + NUTAG_NEWSUB(1), + TAG_IF(route, NUTAG_PROXY(route)), + NUTAG_URL(contact), + SIPTAG_FROM_STR(full_to), + SIPTAG_TO_STR(full_from), + SIPTAG_CONTACT_STR(profile->url), + SIPTAG_CALL_ID_STR(call_id), + TAG_IF(*expires_str, SIPTAG_EXPIRES_STR(expires_str)), + SIPTAG_SUBSCRIPTION_STATE_STR(sstr), + SIPTAG_EVENT_STR(event), + TAG_IF(!zstr(ct), SIPTAG_CONTENT_TYPE_STR(ct)), + TAG_IF(!zstr(pl), SIPTAG_PAYLOAD_STR(pl)), + TAG_IF(!zstr(call_info), SIPTAG_CALL_INFO_STR(call_info)), + TAG_IF(!exptime, SIPTAG_EXPIRES_STR("0")), + SIPTAG_CSEQ(cseq), + TAG_END()); + + switch_safe_free(route); + + +} + + static int sofia_dialog_probe_notify_callback(void *pArg, int argc, char **argv, char **columnNames) { struct rfc4235_helper *sh = (struct rfc4235_helper *) pArg; @@ -1650,21 +1757,18 @@ static int sofia_dialog_probe_notify_callback(void *pArg, int argc, char **argv, char *event = argv[4]; char *version = argv[5]; char *notify_state = argv[6]; - + char *full_to = argv[7]; + char *full_from = argv[8]; + char *contact = argv[9]; + char *remote_ip = argv[10]; + char *remote_port = argv[11]; + switch_stream_handle_t stream = { 0 }; - nua_handle_t *nh; - time_t exptime = switch_epoch_time_now(NULL) + 3600; - char sstr[128] = ""; - char expires_str[10] = ""; char *to; const char *pl = NULL; const char *ct = "application/dialog-info+xml"; - if (!(nh = nua_handle_by_call_id(sh->profile->nua, call_id))) { - switch_log_printf(SWITCH_CHANNEL_LOG,SWITCH_LOG_DEBUG, "sofia_dialog_probe_notify_callback: could not find nua handle (old subscription)\n"); - return 0; - } - + if (mod_sofia_globals.debug_presence > 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "SEND DIALOG\nTo: \t%s@%s\nFrom: \t%s@%s\nCall-ID: \t%s\n", @@ -1698,25 +1802,25 @@ static int sofia_dialog_probe_notify_callback(void *pArg, int argc, char **argv, pl = stream.data; ct = "application/dialog-info+xml"; - nua_handle_bind(nh, &mod_sofia_globals.keep_private); - - if (expires) { - long tmp = atol(expires); - exptime = tmp - switch_epoch_time_now(NULL); - } - if (exptime > 0) { - switch_snprintf(sstr, sizeof(sstr), "active;expires=%u", (unsigned) exptime); - } else { - switch_snprintf(sstr, sizeof(sstr), "terminated;reason=timeout"); - } - if (mod_sofia_globals.debug_presence > 0 && pl) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "send payload:\n%s\n", pl); } - nua_notify(nh, - TAG_IF(*expires_str, SIPTAG_EXPIRES_STR(expires_str)), - SIPTAG_SUBSCRIPTION_STATE_STR(sstr), SIPTAG_EVENT_STR(event), SIPTAG_CONTENT_TYPE_STR(ct), SIPTAG_PAYLOAD_STR(pl), TAG_END()); + + send_presence_notify(sh->profile, + full_to, + full_from, + contact, + expires, + call_id, + event, + remote_ip, + remote_port, + ct, + pl, + NULL + ); + switch_safe_free(to); switch_safe_free(stream.data); @@ -1862,12 +1966,17 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char * struct presence_helper *helper = (struct presence_helper *) pArg; char *pl = NULL; char *clean_id = NULL, *id = NULL; + char *proto = argv[0]; char *user = argv[1]; char *host = argv[2]; char *sub_to_user = argv[3]; char *event = argv[5]; + char *contact = argv[6]; char *call_id = argv[7]; + char *full_from = argv[8]; + //char *full_via = argv[9]; + char *expires = argv[10]; char *user_agent = argv[11]; char *profile_name = argv[13]; @@ -1880,16 +1989,14 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char * char *dialog_rpid = NULL; const char *ct = "no/idea"; - nua_handle_t *nh; + char *to = NULL; char *open; char *prpid; - time_t exptime = switch_epoch_time_now(NULL) + 3600; + int is_dialog = 0; sofia_profile_t *ext_profile = NULL, *profile = helper->profile; - char sstr[128] = ""; - int kill_handle = 0; - char expires_str[10] = ""; + char status_line[256] = ""; char *version = "0"; char *presence_id = NULL; @@ -1897,14 +2004,17 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char * int holding = 0; char *orig_proto = NULL; int skip_proto = 0; + char *full_to = NULL; + char *ip = NULL; + char *port = 0; - - //int i; - - //for(i = 0; i < argc; i++) { - //printf("arg %d[%s] = [%s]\n", i, columnNames[i], argv[i]); - //} - //DUMP_EVENT(helper->event); + if (mod_sofia_globals.debug_presence > 0) { + int i; + for(i = 0; i < argc; i++) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "arg %d[%s] = [%s]\n", i, columnNames[i], argv[i]); + } + DUMP_EVENT(helper->event); + } if (argc > 18) { if (!zstr(argv[17])) { @@ -1922,6 +2032,9 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char * version = argv[22]; presence_id = argv[23]; orig_proto = argv[24]; + full_to = argv[25]; + ip = argv[26]; + port = argv[27]; } if (!zstr(presence_id) && strchr(presence_id, '@')) { @@ -1969,34 +2082,25 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char * } } - if (!(nh = nua_handle_by_call_id(profile->nua, call_id))) { - if (mod_sofia_globals.debug_presence > 0) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to find handle for call id %s\n", call_id); - } - - goto end; - } - - if (expires) { - long tmp = atol(expires); - if (tmp > 0) { - exptime = tmp - switch_epoch_time_now(NULL); // - SUB_OVERLAP; - } else { - exptime = tmp; - } - } - - if (!rpid) { - rpid = "unknown"; - } - if (!strcasecmp(proto, SOFIA_CHAT_PROTO) || skip_proto) { clean_id = switch_mprintf("sip:%s@%s", sub_to_user, sub_to_host); } else { clean_id = switch_mprintf("sip:%s+%s@%s", proto, sub_to_user, sub_to_host); } + + + if (!rpid) { + rpid = "unknown"; + } + + // if (!strcasecmp(proto, SOFIA_CHAT_PROTO) || skip_proto) { + // clean_id = switch_mprintf("sip:%s@%s", sub_to_user, sub_to_host); + //} else { + // clean_id = switch_mprintf("sip:%s+%s@%s", proto, sub_to_user, sub_to_host); + //} + if (mod_sofia_globals.debug_presence > 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "SEND PRESENCE\nTo: \t%s@%s\nFrom: \t%s@%s\nCall-ID: \t%s\nProfile:\t%s [%s]\n\n", @@ -2220,7 +2324,6 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char * if (!zstr(astate) && !zstr(uuid) && helper && helper->stream.data && strcmp(helper->last_uuid, uuid) && strcasecmp(astate, "terminated") && strchr(uuid, '-')) { helper->stream.write_function(&helper->stream, "update sip_dialogs set state='%s' where uuid='%s';", astate, uuid); - //printf("WTF update sip_dialogs set state='%s' where uuid='%s';\n", astate, uuid); switch_copy_string(helper->last_uuid, uuid, sizeof(helper->last_uuid)); } @@ -2347,40 +2450,11 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char * if (!zstr(uuid) && strchr(uuid, '-') && !zstr(status_line) && !zstr(rpid) && (zstr(register_source) || strcasecmp(register_source, "register"))) { char *sql = switch_mprintf("update sip_dialogs set rpid='%q',status='%q' where uuid='%q'", rpid, status_line, uuid); - //printf("WTF %s\n", sql); sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE); } } - - nua_handle_bind(nh, &mod_sofia_globals.keep_private); - - if (helper->event && helper->event->event_id == SWITCH_EVENT_PRESENCE_OUT) { - switch_set_string(sstr, "terminated;reason=noresource"); - switch_set_string(expires_str, "0"); - kill_handle = 1; - } else if (exptime > 0) { - switch_snprintf(sstr, sizeof(sstr), "active;expires=%u", (unsigned) exptime); - } else { - unsigned delta = (unsigned) (exptime * -1); - switch_snprintf(sstr, sizeof(sstr), "active;expires=%u", delta); - switch_snprintf(expires_str, sizeof(expires_str), "%u", delta); - if (nh && nh->nh_ds && nh->nh_ds->ds_usage) { - nua_dialog_usage_set_refresh_range(nh->nh_ds->ds_usage, delta, delta); - } - } - - if (mod_sofia_globals.debug_presence > 0 && pl) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "send payload:\n%s\n", pl); - } - - nua_notify(nh, - TAG_IF(*expires_str, SIPTAG_EXPIRES_STR(expires_str)), - SIPTAG_SUBSCRIPTION_STATE_STR(sstr), SIPTAG_EVENT_STR(event), SIPTAG_CONTENT_TYPE_STR(ct), SIPTAG_PAYLOAD_STR(pl), TAG_END()); - - nua_handle_unref(nh); - - end: + send_presence_notify(profile, full_to, full_from, contact, expires, call_id, event, ip, port, ct, pl, NULL); switch_safe_free(free_me); @@ -2393,25 +2467,24 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char * switch_safe_free(pl); switch_safe_free(to); - if (nh && kill_handle) { - nua_handle_destroy(nh); - } - return 0; } static int sofia_presence_mwi_callback(void *pArg, int argc, char **argv, char **columnNames) { - char *sub_to_user = argv[3]; - char *sub_to_host = argv[15]; + //char *sub_to_user = argv[3]; + //char *sub_to_host = argv[4]; char *event = argv[5]; + char *contact = argv[6]; char *call_id = argv[7]; + char *full_from = argv[8]; char *expires = argv[10]; char *profile_name = argv[13]; char *body = argv[15]; - char *id = NULL; - nua_handle_t *nh; - int expire_sec = atoi(expires); + char *full_to = argv[16]; + char *remote_ip = argv[17]; + char *remote_port = argv[18]; + struct mwi_helper *h = (struct mwi_helper *) pArg; sofia_profile_t *ext_profile = NULL, *profile = h->profile; @@ -2421,31 +2494,23 @@ static int sofia_presence_mwi_callback(void *pArg, int argc, char **argv, char * } } - if (!(nh = nua_handle_by_call_id(h->profile->nua, call_id))) { - if (profile->debug) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Cannot find handle for %s\n", call_id); - } - goto end; - } + send_presence_notify(profile, + full_to, + full_from, + contact, + expires, + call_id, + event, + remote_ip, + remote_port, + "application/simple-message-summary", + body, + NULL + ); - id = switch_mprintf("sip:%s@%s", sub_to_user, sub_to_host); - expire_sec = (int) (expire_sec - switch_epoch_time_now(NULL)); - if (expire_sec < 0) { - expire_sec = 3600; - } - - nua_handle_bind(nh, &mod_sofia_globals.keep_private); - nua_notify(nh, SIPTAG_SUBSCRIPTION_STATE_STR("active"), - SIPTAG_EVENT_STR(event), SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"), SIPTAG_PAYLOAD_STR(body), TAG_END()); - - nua_handle_unref(nh); - - switch_safe_free(id); h->total++; - end: - if (ext_profile) { sofia_glue_release_profile(ext_profile); } @@ -2488,14 +2553,11 @@ static int broadsoft_sla_notify_callback(void *pArg, int argc, char **argv, char char key[256] = ""; char *data = NULL, *tmp; char *call_id = argv[0]; - char *expires = argv[1]; + //char *expires = argv[1]; char *user = argv[2]; char *host = argv[3]; char *event = argv[4]; int i; - char sstr[128] = "", expires_str[128] = ""; - time_t exptime = 3600; - nua_handle_t *nh; if (mod_sofia_globals.debug_sla > 1) { for (i = 0; i < argc; i++) { @@ -2505,19 +2567,7 @@ static int broadsoft_sla_notify_callback(void *pArg, int argc, char **argv, char switch_snprintf(key, sizeof(key), "%s%s", user, host); data = switch_core_hash_find(sh->hash, key); - - if (expires) { - long tmp = atol(expires); - exptime = tmp - switch_epoch_time_now(NULL); - } - - if (exptime > 0) { - switch_snprintf(sstr, sizeof(sstr), "active;expires=%u", (unsigned) exptime); - } else { - switch_snprintf(sstr, sizeof(sstr), "terminated;reason=noresource"); - } - - switch_snprintf(expires_str, sizeof(expires_str), "%u", (unsigned) exptime); + data = switch_core_hash_find(sh->hash, key); @@ -2527,26 +2577,23 @@ static int broadsoft_sla_notify_callback(void *pArg, int argc, char **argv, char tmp = switch_core_sprintf(sh->pool, ";appearance-index=*;appearance-state=idle", host); } - if (!strcasecmp(event, "line-seize") && (nh = nua_handle_by_call_id(sh->profile->nua, call_id))) { + + if (!strcasecmp(event, "line-seize")) { char *hack; if ((hack = (char *) switch_stristr("=seized", tmp))) { switch_snprintf(hack, 7, "=idle "); } - nua_notify(nh, - SIPTAG_EXPIRES_STR("0"), - SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"), SIPTAG_EVENT_STR("line-seize"), SIPTAG_CALL_INFO_STR(tmp), TAG_END()); - nua_handle_unref(nh); - return 0; } - if (!strcasecmp(event, "call-info") && (nh = nua_handle_by_call_id(sh->profile->nua, call_id))) { - nua_notify(nh, - TAG_IF(*expires_str, SIPTAG_EXPIRES_STR(expires_str)), - SIPTAG_SUBSCRIPTION_STATE_STR(sstr), SIPTAG_EVENT_STR("call-info"), SIPTAG_CALL_INFO_STR(tmp), TAG_END()); - nua_handle_unref(nh); + if (mod_sofia_globals.debug_sla > 1) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "DB PRES NOTIFY: [%s]\n[%s]\n[%s]\n[%s]\n[%s]\n[%s]\n[%s]\n[%s]\n[%s]\n", + argv[5], argv[6], argv[7], argv[8], call_id, event, argv[9], argv[10], tmp); + } - + + send_presence_notify(sh->profile, argv[5], argv[6], argv[7], argv[8], call_id, event, argv[9], argv[10], NULL, NULL, tmp); + return 0; } @@ -2667,13 +2714,13 @@ static void sync_sla(sofia_profile_t *profile, const char *to_user, const char * if (unseize) { - sql = switch_mprintf("select call_id,expires,sub_to_user,sub_to_host,event " + sql = switch_mprintf("select call_id,expires,sub_to_user,sub_to_host,event,full_to,full_from,contact,expires,network_ip,network_port " "from sip_subscriptions " "where version > -1 and expires > -1 and hostname='%q' " "and sub_to_user='%q' and sub_to_host='%q' " "and (event='call-info' or event='line-seize')", mod_sofia_globals.hostname, to_user, to_host); } else { - sql = switch_mprintf("select call_id,expires,sub_to_user,sub_to_host,event " + sql = switch_mprintf("select call_id,expires,sub_to_user,sub_to_host,event,full_to,full_from,contact,expires,network_ip,network_port " "from sip_subscriptions " "where version > -1 and expires > -1 and hostname='%q' " "and sub_to_user='%q' and sub_to_host='%q' " "and (event='call-info')", mod_sofia_globals.hostname, to_user, to_host); @@ -2711,7 +2758,7 @@ void sofia_presence_handle_sip_i_subscribe(int status, tagi_t tags[]) { - long exp_delta; + long exp_delta = 0; char exp_delta_str[30] = ""; sip_to_t const *to; const char *from_user = NULL, *from_host = NULL; @@ -2726,6 +2773,7 @@ void sofia_presence_handle_sip_i_subscribe(int status, const char *call_id = NULL; char *to_str = NULL; char *full_from = NULL; + char *full_to = NULL; char *full_via = NULL; char *full_agent = NULL; char *sstr; @@ -2737,6 +2785,7 @@ void sofia_presence_handle_sip_i_subscribe(int status, const char *contact_user; sofia_nat_parse_t np = { { 0 } }; int found_proto = 0; + char to_tag[13] = ""; if (!sip) { return; @@ -2750,6 +2799,8 @@ void sofia_presence_handle_sip_i_subscribe(int status, return; } + switch_stun_random_string(to_tag, 12, NULL); + //contact_host = sip->sip_contact->m_url->url_host; contact_user = sip->sip_contact->m_url->url_user; @@ -2757,19 +2808,6 @@ void sofia_presence_handle_sip_i_subscribe(int status, event = sip_header_as_string(nh->nh_home, (void *) sip->sip_event); - - /* the following could be refactored back to the calling event handler in sofia.c XXX MTK */ - if (sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE)) { - if (sip->sip_request->rq_url->url_user && !strncmp(sip->sip_request->rq_url->url_user, "sla-agent", sizeof("sla-agent"))) { - /* only fire this on <200 to try to avoid resubscribes. probably better ways to do this? */ - if (status < 200) { - sofia_sla_handle_sip_i_subscribe(nua, contact_str, profile, nh, sip, de, tags); - } - switch_safe_free(contact_str); - return; - } - } - if (to) { to_str = switch_mprintf("sip:%s@%s", to->a_url->url_user, to->a_url->url_host); } @@ -2826,8 +2864,10 @@ void sofia_presence_handle_sip_i_subscribe(int status, 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); + if (sip->sip_expires && sip->sip_expires->ex_delta > 31536000) { sip->sip_expires->ex_delta = 31536000; } @@ -2879,6 +2919,7 @@ void sofia_presence_handle_sip_i_subscribe(int status, } else { sip_accept_t *ap = sip->sip_accept; char accept[256] = ""; + full_agent = sip_header_as_string(nh->nh_home, (void *) sip->sip_user_agent); while (ap) { switch_snprintf(accept + strlen(accept), sizeof(accept) - strlen(accept), "%s%s ", ap->ac_type, ap->ac_next ? "," : ""); @@ -2887,13 +2928,13 @@ void sofia_presence_handle_sip_i_subscribe(int status, 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, orig_proto) " - "values ('%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q',%ld,'%q','%q','%q','%q','%d','%q','%q')", + "full_via,expires,user_agent,accept,profile_name,hostname,network_port,network_ip, orig_proto, full_to) " + "values ('%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q',%ld,'%q','%q','%q','%q','%d','%q','%q','%q;tag=%q')", proto, from_user, from_host, to_user, to_host, profile->presence_hosts ? profile->presence_hosts : to_host, event, contact_str, call_id, full_from, full_via, - //sofia_test_pflag(profile, PFLAG_MULTIREG) ? switch_epoch_time_now(NULL) + exp_delta : exp_delta * -1, (long) switch_epoch_time_now(NULL) + exp_delta, - full_agent, accept, profile->name, mod_sofia_globals.hostname, np.network_port, np.network_ip, orig_proto); + full_agent, accept, profile->name, mod_sofia_globals.hostname, + np.network_port, np.network_ip, orig_proto, full_to, to_tag); switch_assert(sql != NULL); @@ -2905,15 +2946,16 @@ void sofia_presence_handle_sip_i_subscribe(int status, sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); sstr = switch_mprintf("active;expires=%ld", exp_delta); - } - - switch_mutex_unlock(profile->ireg_mutex); + } + + switch_mutex_unlock(profile->ireg_mutex); } if (status < 200) { char *sticky = NULL; char *contactstr = profile->url, *cs = NULL; char *p = NULL, *new_contactstr = NULL; + if (np.is_nat) { char params[128] = ""; @@ -2962,8 +3004,11 @@ void sofia_presence_handle_sip_i_subscribe(int status, new_contactstr = switch_mprintf("", to_user, p); } } - + + sip_to_tag(nh->nh_home, sip->sip_to, to_tag); + nua_respond(nh, SIP_202_ACCEPTED, + SIPTAG_TO(sip->sip_to), TAG_IF(new_contactstr, SIPTAG_CONTACT_STR(new_contactstr)), NUTAG_WITH_THIS_MSG(de->data->e_msg), SIPTAG_SUBSCRIPTION_STATE_STR(sstr), SIPTAG_EXPIRES_STR(exp_delta_str), TAG_IF(sticky, NUTAG_PROXY(sticky)), TAG_END()); @@ -3141,6 +3186,10 @@ void sofia_presence_handle_sip_i_subscribe(int status, if (full_from) { su_free(nh->nh_home, full_from); } + if (full_to) { + su_free(nh->nh_home, full_to); + } + if (full_via) { su_free(nh->nh_home, full_via); } @@ -3156,7 +3205,9 @@ void sofia_presence_handle_sip_i_subscribe(int status, if (!sent_reply) { nua_respond(nh, 481, "INVALID SUBSCRIPTION", TAG_END()); } - + + nua_handle_destroy(nh); + } @@ -3192,14 +3243,6 @@ void sofia_presence_handle_sip_r_subscribe(int status, return; } - /* the following could possibly be refactored back towards the calling event handler in sofia.c XXX MTK */ - if (sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE)) { - if (!strcasecmp(o->o_type, "dialog") && msg_params_find(o->o_params, "sla")) { - sofia_sla_handle_sip_r_subscribe(status, phrase, nua, profile, nh, sofia_private, sip, de, tags); - return; - } - } - if (!sofia_private || !sofia_private->gateway) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Gateway information missing\n"); return; @@ -3244,32 +3287,13 @@ void sofia_presence_handle_sip_r_subscribe(int status, } } -struct cpc { - sofia_profile_t *profile; - sofia_dispatch_event_t *de; -}; -static int sofia_counterpath_crutch(void *pArg, int argc, char **argv, char **columnNames) +static int sofia_presence_send_sql(void *pArg, int argc, char **argv, char **columnNames) { - nua_handle_t *nh; - struct cpc *crutch = (struct cpc *) pArg; - char *call_id = argv[0]; - char *pl = argv[1]; - char *event_type = argv[2]; - long exp_delta = atol(argv[3]); - - if ((nh = nua_handle_by_call_id(crutch->profile->nua, call_id))) { - char sstr[128] = "", expstr[128] = ""; - switch_snprintf(expstr, sizeof(expstr), "%d", exp_delta); - switch_snprintf(sstr, sizeof(sstr), "active;expires=%u", exp_delta); - nua_notify(nh, - NUTAG_WITH_THIS_MSG(crutch->de->data->e_msg), - SIPTAG_EXPIRES_STR(expstr), - SIPTAG_SUBSCRIPTION_STATE_STR(sstr), SIPTAG_EVENT_STR(event_type), - SIPTAG_CONTENT_TYPE_STR("application/pidf+xml"), SIPTAG_PAYLOAD_STR(pl), TAG_END()); - nua_handle_unref(nh); - } + sofia_profile_t *profile = (sofia_profile_t *) pArg; + send_presence_notify(profile, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], NULL); + return 0; } @@ -3312,15 +3336,6 @@ void sofia_presence_handle_sip_i_publish(nua_t *nua, sofia_profile_t *profile, n from = sip->sip_from; payload = sip->sip_payload; - /* the following could instead be refactored back to the calling event handler in sofia.c XXX MTK */ - if (sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE)) { - /* also it probably is unsafe to dereference so many things in a row without testing XXX MTK */ - if (sip->sip_request->rq_url->url_user && !strncmp(sip->sip_request->rq_url->url_user, "sla-agent", sizeof("sla-agent"))) { - sofia_sla_handle_sip_i_publish(nua, profile, nh, sip, de, tags); - return; - } - } - contact_str = sofia_glue_gen_contact_str(profile, sip, de, NULL); if (from) { @@ -3407,14 +3422,12 @@ void sofia_presence_handle_sip_i_publish(nua_t *nua, sofia_profile_t *profile, n } } else if (contact_str) { - struct cpc crutch; - - crutch.profile = profile; - crutch.de = de; - sql = switch_mprintf("select call_id,'%q','%q','%ld' from sip_subscriptions where sub_to_user='%q' and sub_to_host='%q' " - "and contact = '%q' ", payload->pl_data ? payload->pl_data : "", event_type, exp_delta, - from_user, from_host, contact_str); - sofia_glue_execute_sql_callback(profile, profile->ireg_mutex, sql, sofia_counterpath_crutch, &crutch); + sql = switch_mprintf("select full_to, full_from, contact, expires, call_id, event, network_ip, network_port, " + "'application/pidf+xml' as ct,'%q' as pt " + " from sip_subscriptions where sub_to_user='%q' and sub_to_host='%q' and event='%q'" + "and contact = '%q' ", switch_str_nil(payload->pl_data), from_user, from_host, event_type); + + sofia_glue_execute_sql_callback(profile, profile->ireg_mutex, sql, sofia_presence_send_sql, profile); switch_safe_free(sql); } @@ -3636,6 +3649,30 @@ void sofia_presence_set_chat_hash(private_object_t *tech_pvt, sip_t const *sip) switch_mutex_unlock(tech_pvt->profile->flag_mutex); } + +void sofia_presence_check_subscriptions(sofia_profile_t *profile, time_t now) +{ + char *sql; + + if (now) { + sql = switch_mprintf("select full_to, full_from, contact, expires, call_id, event, network_ip, network_port, " + "NULL as ct, NULL as pt " + " from sip_subscriptions where (expires = -1 or (expires > 0 and expires <= %ld)) and hostname='%q'", + (long) now, mod_sofia_globals.hostname); + + sofia_glue_execute_sql_callback(profile, profile->ireg_mutex, sql, sofia_presence_send_sql, profile); + switch_safe_free(sql); + + sql = switch_mprintf("delete from sip_subscriptions where (expires = -1 or (expires > 0 and expires <= %ld)) and hostname='%q'", + (long) now, mod_sofia_globals.hostname); + sofia_glue_actually_execute_sql(profile, sql, NULL); + } + + + +} + + /* For Emacs: * Local Variables: * mode:c diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c index 1fcafc07a4..ff5da47af4 100644 --- a/src/mod/endpoints/mod_sofia/sofia_reg.c +++ b/src/mod/endpoints/mod_sofia/sofia_reg.c @@ -763,15 +763,8 @@ void sofia_reg_check_expire(sofia_profile_t *profile, time_t now, int reboot) sofia_glue_execute_sql_callback(profile, NULL, sql, sofia_sub_del_callback, profile); - if (now) { - switch_snprintfv(sql, sizeof(sql), "delete from sip_subscriptions where (expires = -1 or (expires > 0 and expires <= %ld)) and hostname='%q'", - (long) now, mod_sofia_globals.hostname); - } else { - switch_snprintfv(sql, sizeof(sql), "delete from sip_subscriptions where expires >= -1 and hostname='%q'", mod_sofia_globals.hostname); - } - - sofia_glue_actually_execute_sql(profile, sql, NULL); + sofia_presence_check_subscriptions(profile, now); if (now) { switch_snprintfv(sql, sizeof(sql), "delete from sip_dialogs where (expires = -1 or (expires > 0 and expires <= %ld)) and hostname='%q'", @@ -1500,8 +1493,8 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand if (delete_subs) { if (reg_count == 1) { - sql = switch_mprintf("delete from sip_subscriptions where sip_user='%q' and sip_host='%q' and contact='%q'", - to_user, sub_host, contact_str); + sql = switch_mprintf("update sip_subscriptions set expires=%ld where sip_user='%q' and sip_host='%q' and contact='%q'", + (long) switch_epoch_time_now(NULL), to_user, sub_host, contact_str); sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); } } @@ -1509,16 +1502,19 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand if (multi_reg_contact) { sql = - switch_mprintf("delete from sip_registrations where sip_user='%q' and sip_host='%q' and contact='%q'", to_user, reg_host, contact_str); + switch_mprintf("update sip_registrations set expires=%ld where sip_user='%q' and sip_host='%q' and contact='%q'", + (long) switch_epoch_time_now(NULL), to_user, reg_host, contact_str); } else { - sql = switch_mprintf("delete from sip_registrations where call_id='%q'", call_id); + sql = switch_mprintf("update sip_registrations set expires=%ld where call_id='%q'", (long) switch_epoch_time_now(NULL), call_id); } } else { if (delete_subs) { - sql = switch_mprintf("delete from sip_subscriptions where sip_user='%q' and sip_host='%q'", to_user, sub_host); + sql = switch_mprintf("update sip_subscriptions set expires=%ld where sip_user='%q' and sip_host='%q'", + (long) switch_epoch_time_now(NULL), to_user, sub_host); sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); } - sql = switch_mprintf("delete from sip_registrations where sip_user='%q' and sip_host='%q'", to_user, reg_host); + sql = switch_mprintf("update sip_registrations set expires=%ld where sip_user='%q' and sip_host='%q'", + (long) switch_epoch_time_now(NULL), to_user, reg_host); } switch_mutex_lock(profile->ireg_mutex); sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); @@ -1664,9 +1660,10 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand if (delete_subs) { if (multi_reg_contact) { sql = - switch_mprintf("delete from sip_subscriptions where sip_user='%q' and sip_host='%q' and contact='%q'", to_user, sub_host, contact_str); + switch_mprintf("update sip_subscriptions set expires=%ld where sip_user='%q' and sip_host='%q' and contact='%q'", + (long) switch_epoch_time_now(NULL), to_user, sub_host, contact_str); } else { - sql = switch_mprintf("delete from sip_subscriptions where call_id='%q'", call_id); + sql = switch_mprintf("update sip_subscriptions set expires=%ld where call_id='%q'", (long) switch_epoch_time_now(NULL), call_id); } sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); @@ -1684,7 +1681,8 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand switch_safe_free(icontact); } else { if (delete_subs) { - if ((sql = switch_mprintf("delete from sip_subscriptions where sip_user='%q' and sip_host='%q'", to_user, sub_host))) { + if ((sql = switch_mprintf("update sip_subscriptions set expires=%ld where sip_user='%q' and sip_host='%q'", + (long) switch_epoch_time_now(NULL), to_user, sub_host))) { sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); } } @@ -1812,10 +1810,6 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand switch_event_fire(&s_mwi_event); } - if (contact && *contact_str && sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE_SYLANTRO)) { - sofia_sla_handle_register(nua, profile, sip, de, exptime, contact_str); - } - switch_goto_int(r, 1, end); } diff --git a/src/mod/endpoints/mod_sofia/sofia_sla.c b/src/mod/endpoints/mod_sofia/sofia_sla.c deleted file mode 100644 index 3dcc455d29..0000000000 --- a/src/mod/endpoints/mod_sofia/sofia_sla.c +++ /dev/null @@ -1,413 +0,0 @@ -/* - * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application - * Copyright (C) 2005-2011, Anthony Minessale II - * - * 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 - * Portions created by the Initial Developer are Copyright (C) - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Anthony Minessale II - * Ken Rice, Asteria Solutions Group, Inc - * Paul D. Tinsley - * Bret McDanel - * Brian West - * - * sofia_sla.c -- SOFIA SIP Endpoint (support for shared line appearance) - * This file (and calls into it) developed by Matthew T Kaufman - * - */ -#include "mod_sofia.h" - -static int sofia_sla_sub_callback(void *pArg, int argc, char **argv, char **columnNames); - -struct sla_helper { - char call_id[1024]; -}; - -static int get_call_id_callback(void *pArg, int argc, char **argv, char **columnNames) -{ - struct sla_helper *sh = (struct sla_helper *) pArg; - - switch_set_string(sh->call_id, argv[0]); - return 0; -} - -int sofia_sla_supported(sip_t const *sip) -{ - if (sip && sip->sip_user_agent && sip->sip_user_agent->g_string) { - const char *ua = sip->sip_user_agent->g_string; - - if (switch_stristr("polycom", ua)) { - return 1; - } - - if (switch_stristr("snom", ua)) { - return 1; - } - - } - - return 0; -} - - -void sofia_sla_handle_register(nua_t *nua, sofia_profile_t *profile, sip_t const *sip, - sofia_dispatch_event_t *de, long exptime, const char *full_contact) -{ - nua_handle_t *nh = NULL; - char exp_str[256] = ""; - char my_contact[256] = ""; - char *sql; - struct sla_helper sh = { {0} }; - char *contact_str = sofia_glue_strip_uri(full_contact); - sofia_transport_t transport = sofia_glue_url2transport(sip->sip_contact->m_url); - char network_ip[80]; - int network_port = 0; - sofia_destination_t *dst; - char *route_uri = NULL; - char port_str[25] = ""; - nua_handle_t *fnh = NULL; - - sofia_glue_get_addr(de->data->e_msg, network_ip, sizeof(network_ip), &network_port); - - sql = switch_mprintf("select call_id from sip_shared_appearance_dialogs where hostname='%q' and profile_name='%q' and contact_str='%q'", - mod_sofia_globals.hostname, profile->name, contact_str); - sofia_glue_execute_sql_callback(profile, profile->ireg_mutex, sql, get_call_id_callback, &sh); - - free(sql); - - if (*sh.call_id) { - if ((nh = nua_handle_by_call_id(profile->nua, sh.call_id))) { - fnh = nh; - } else { - if ((sql = switch_mprintf("delete from sip_shared_appearance_dialogs where hostname='%q' and profile_name='%q' and contact_str='%q'", - mod_sofia_globals.hostname, profile->name, contact_str))) { - sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE); - } - } - } - - if (!nh) { - nh = nua_handle(nua, NULL, NUTAG_URL(sip->sip_contact->m_url), TAG_NULL()); - } - - nua_handle_bind(nh, &mod_sofia_globals.keep_private); - - switch_snprintf(exp_str, sizeof(exp_str), "%ld", exptime + 30); - - switch_snprintf(port_str, sizeof(port_str), ":%ld", sofia_glue_transport_has_tls(transport) ? profile->tls_sip_port : profile->sip_port); - - if (sofia_glue_check_nat(profile, network_ip)) { - switch_snprintf(my_contact, sizeof(my_contact), ";expires=%s", profile->sla_contact, - profile->extsipip, port_str, sofia_glue_transport2str(transport), exp_str); - } else { - switch_snprintf(my_contact, sizeof(my_contact), ";expires=%s", profile->sla_contact, - profile->sipip, port_str, sofia_glue_transport2str(transport), exp_str); - } - - dst = sofia_glue_get_destination((char *) full_contact); - - if (dst->route_uri) { - route_uri = sofia_glue_strip_uri(dst->route_uri); - } - - nua_subscribe(nh, - TAG_IF(dst->route_uri, NUTAG_PROXY(route_uri)), TAG_IF(dst->route, SIPTAG_ROUTE_STR(dst->route)), - SIPTAG_TO(sip->sip_to), - SIPTAG_FROM(sip->sip_to), - SIPTAG_CONTACT_STR(my_contact), - SIPTAG_EXPIRES_STR(exp_str), - SIPTAG_EVENT_STR("dialog;sla;include-session-description"), SIPTAG_ACCEPT_STR("application/dialog-info+xml"), TAG_NULL()); - - - if (fnh) { - nua_handle_unref(fnh); - } - - sofia_glue_free_destination(dst); - - free(contact_str); -} - -void sofia_sla_handle_sip_i_publish(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip, - sofia_dispatch_event_t *de, tagi_t tags[]) -{ - /* at present there's no SLA versions that we deal with that do publish. to be safe, we say "OK" */ - nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END()); -} - -void sofia_sla_handle_sip_i_subscribe(nua_t *nua, const char *contact_str, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip, - sofia_dispatch_event_t *de, tagi_t tags[]) -{ - char *aor = NULL; - char *subscriber = NULL; - char *sql = NULL; - char *route_uri = NULL; - char *sla_contact = NULL; - char network_ip[80]; - int network_port = 0; - char port_str[25] = ""; - - sofia_transport_t transport = sofia_glue_url2transport(sip->sip_contact->m_url); - - sofia_glue_get_addr(de->data->e_msg, network_ip, sizeof(network_ip), &network_port); - /* - * XXX MTK FIXME - we don't look at the tag to see if NUTAG_SUBSTATE(nua_substate_terminated) or - * a Subscription-State header with state "terminated" and/or expiration of 0. So we never forget - * about them here. - * likewise, we also don't have a hook against nua_r_notify events, so we can't see nua_substate_terminated there. - */ - - /* - * extracting AOR is weird... - * the From is the main extension, not the third-party one... - * and the contact has the phone's own network address, not the AOR address - * so we do what openser's pua_bla does and... - */ - - /* We always store the AOR as the sipip and not the request so SLA works with NAT inside out */ - aor = switch_mprintf("sip:%s@%s", sip->sip_contact->m_url->url_user, profile->sipip); - - /* - * ok, and now that we HAVE the AOR, we REALLY should go check in the XML config and see if this particular - * extension is set up to have shared appearances managed. right now it is all-or-nothing on the profile, - * which won't be sufficient for real life. FIXME XXX MTK - */ - - /* then the subscriber is the user at their network location... this is arguably the wrong way, but works so far... */ - - subscriber = switch_mprintf("sip:%s@%s;transport=%s", sip->sip_from->a_url->url_user, - sip->sip_contact->m_url->url_host, sofia_glue_transport2str(transport)); - - if ((sql = - switch_mprintf("delete from sip_shared_appearance_subscriptions where subscriber='%q' and profile_name='%q' and hostname='%q'", - subscriber, profile->name, mod_sofia_globals.hostname))) { - sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE); - } - - if ((sql = - switch_mprintf("insert into sip_shared_appearance_subscriptions (subscriber, call_id, aor, profile_name, hostname, contact_str, network_ip) " - "values ('%q','%q','%q','%q','%q','%q','%q')", - subscriber, sip->sip_call_id->i_id, aor, profile->name, mod_sofia_globals.hostname, contact_str, network_ip))) { - sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE); - } - - if (strstr(contact_str, ";fs_nat")) { - char *p; - route_uri = sofia_glue_get_url_from_contact((char *) contact_str, 1); - if ((p = strstr(contact_str, ";fs_"))) { - *p = '\0'; - } - } - - if (route_uri) { - char *p; - - while (route_uri && *route_uri && (*route_uri == '<' || *route_uri == ' ')) { - route_uri++; - } - if ((p = strchr(route_uri, '>'))) { - *p++ = '\0'; - } - } - - switch_snprintf(port_str, sizeof(port_str), ":%ld", sofia_glue_transport_has_tls(transport) ? profile->tls_sip_port : profile->sip_port); - - if (sofia_glue_check_nat(profile, network_ip)) { - sla_contact = switch_mprintf("", profile->sla_contact, profile->extsipip, port_str, sofia_glue_transport2str(transport)); - } else { - sla_contact = switch_mprintf("", profile->sla_contact, profile->sipip, port_str, sofia_glue_transport2str(transport)); - } - - nua_respond(nh, SIP_202_ACCEPTED, SIPTAG_CONTACT_STR(sla_contact), NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_IF(route_uri, NUTAG_PROXY(route_uri)), SIPTAG_SUBSCRIPTION_STATE_STR("active;expires=300"), /* you thought the OTHER time was fake... need delta here FIXME XXX MTK */ - SIPTAG_EXPIRES_STR("300"), /* likewise, totally fake - FIXME XXX MTK */ - /* sofia_presence says something about needing TAG_IF(sticky, NUTAG_PROXY(sticky)) for NAT stuff? */ - TAG_END()); - - switch_safe_free(aor); - switch_safe_free(subscriber); - switch_safe_free(route_uri); - switch_safe_free(sla_contact); - switch_safe_free(sql); -} - -struct sla_notify_helper { - sofia_profile_t *profile; - char *payload; -}; - -void sofia_sla_handle_sip_r_subscribe(int status, - char const *phrase, - nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, - sofia_dispatch_event_t *de, - tagi_t tags[]) -{ - if (status >= 300) { - nua_handle_destroy(nh); - sofia_private_free(sofia_private); - } else { - char *full_contact = sip_header_as_string(nua_handle_home(nh), (void *) sip->sip_contact); - time_t expires = switch_epoch_time_now(NULL); - char *sql; - char *contact_str = sofia_glue_strip_uri(full_contact); - - if (sip && sip->sip_expires) { - expires += sip->sip_expires->ex_delta + 30; - } - - if ((sql = switch_mprintf("insert into sip_shared_appearance_dialogs (profile_name, hostname, contact_str, call_id, expires) " - "values ('%q','%q','%q','%q','%ld')", - profile->name, mod_sofia_globals.hostname, contact_str, sip->sip_call_id->i_id, (long) expires))) { - sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE); - } - - free(contact_str); - } -} - -void sofia_sla_handle_sip_i_notify(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip, - sofia_dispatch_event_t *de, tagi_t tags[]) -{ - char *sql = NULL; - struct sla_notify_helper helper; - char *aor = NULL; - char *contact = NULL; - sofia_transport_t transport = sofia_glue_url2transport(sip->sip_contact->m_url); - - /* - * things we know we don't do: - * draft-anil-sipping-bla says we should look and see if the specific appearance is in use and if it is - * return an error for the i_notify, to handle the initial line-seize for dialing out case. - * to do that we would need to really track all the appearances *and* override sofia's autoresponder for i_notify - * because at this point, it already sent the 200 for us. - * and we simply don't track all the appearance status by decoding the XML payload out and recording that in - * an SQL line appearance database yet. we'll need to do that in order to do the above, and in order to make - * interoperation possible between devices that disagree on the dialog xml payload OR don't even do it that - * way and instead use things like call-info/line-seize events like the old Broadsoft spec. - * instead we cheat and just reflect the entire payload back to the subscribers (who, because we don't - * yet check each AOR as it comes in to see if it is to be managed, is more subscribers than we probably - * should have). for the current prototype stage, this works ok anyway. - * and because we don't parse the XML, we even reflect it right back to the notifier/sender (which is called - * "target" in the payload XML, of course). - * also because we don't track on a per-appearance basis, there IS NOT a hook back from sofia_glue to add - * an appearance index to the outbound invite for the "next free appearance". this can lead to race - * conditions where a call shows up on slightly different line key numbers at different phones, making - * "pick up on line X" meaningless if such a race occurs. again, it is a prototype. we can fix it later. - */ - - - /* the dispatcher calls us just because it is aimed at us, so check to see if it is dialog;sla at the very least... */ - - if ((!sip->sip_event) - || (strcasecmp(sip->sip_event->o_type, "dialog")) - || !msg_params_find(sip->sip_event->o_params, "sla")) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "sent to sla-agent but not dialog;sla\n"); - return; - } - - /* calculate the AOR we're trying to tell people about. should probably double-check before derferencing XXX MTK */ - /* We always store the AOR as the sipip and not the request so SLA works with NAT inside out */ - aor = switch_mprintf("sip:%s@%s", sip->sip_to->a_url->url_user, profile->sipip); - - /* this isn't sufficient because on things like the polycom, the subscriber is the 'main' ext number, but the - * 'main' ext number isn't in ANY of the headers they send us in the notify. of course. - * as a side effect, the subscriber<>'%q' below isn't sufficient to prevent reflecting the event back - * at a phone that has the ext # != third-party#. see above, can only fix by parsing the XML for the 'target' - * so we don't reflect it back at anyone who is the "boss" config, but we do reflect it back at the "secretary" - * config. if that breaks the phone, just set them all up as the "boss" config where ext#==third-party# - */ - contact = switch_mprintf("sip:%s@%s;transport=%s", sip->sip_contact->m_url->url_user, - sip->sip_contact->m_url->url_host, sofia_glue_transport2str(transport)); - - if (sip->sip_payload && sip->sip_payload->pl_data) { - sql = switch_mprintf("select subscriber,call_id,aor,profile_name,hostname,contact_str,network_ip from sip_shared_appearance_subscriptions where " - "aor='%q' and profile_name='%q' and hostname='%q'", aor, profile->name, mod_sofia_globals.hostname); - - helper.profile = profile; - helper.payload = sip->sip_payload->pl_data; /* could just send the WHOLE payload. you'd get the type that way. */ - - /* which mutex if any is correct to hold in this callback? XXX MTK FIXME */ - sofia_glue_execute_sql_callback(profile, profile->ireg_mutex, sql, sofia_sla_sub_callback, &helper); - - switch_safe_free(sql); - switch_safe_free(aor); - switch_safe_free(contact); - } -} - -static int sofia_sla_sub_callback(void *pArg, int argc, char **argv, char **columnNames) -{ - struct sla_notify_helper *helper = pArg; - /* char *subscriber = argv[0]; */ - char *call_id = argv[1]; - /* char *aor = argv[2]; */ - /* char *profile_name = argv[3]; */ - /* char *hostname = argv[4]; */ - char *contact_str = argv[5]; - char *network_ip = argv[6]; - nua_handle_t *nh; - char *route_uri = NULL; - char *xml_fixup = NULL; - char *fixup = NULL; - nh = nua_handle_by_call_id(helper->profile->nua, call_id); /* that's all you need to find the subscription's nh */ - - if (nh) { - - if (strstr(contact_str, ";fs_nat")) { - char *p; - route_uri = sofia_glue_get_url_from_contact(contact_str, 1); - if ((p = strstr(contact_str, ";fs_"))) { - *p = '\0'; - } - } - - if (route_uri) { - char *p; - - while (route_uri && *route_uri && (*route_uri == '<' || *route_uri == ' ')) { - route_uri++; - } - if ((p = strchr(route_uri, '>'))) { - *p++ = '\0'; - } - } - - if (helper->profile->extsipip) { - if (sofia_glue_check_nat(helper->profile, network_ip)) { - fixup = switch_string_replace(helper->payload, helper->profile->sipip, helper->profile->extsipip); - } else { - fixup = switch_string_replace(helper->payload, helper->profile->extsipip, helper->profile->sipip); - } - xml_fixup = fixup; - } else { - xml_fixup = helper->payload; - } - - nua_notify(nh, SIPTAG_SUBSCRIPTION_STATE_STR("active;expires=300"), /* XXX MTK FIXME - this is totally fake calculation */ - TAG_IF(route_uri, NUTAG_PROXY(route_uri)), SIPTAG_CONTENT_TYPE_STR("application/dialog-info+xml"), /* could've just kept the type from the payload */ - SIPTAG_PAYLOAD_STR(xml_fixup), TAG_END()); - switch_safe_free(route_uri); - if (fixup && fixup != helper->payload) { - free(fixup); - } - nua_handle_unref(nh); - } - return 0; -}