From 41944b7e6f0f651b28882fb2465b4a299805707a Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Sun, 22 Mar 2009 05:15:17 +0000 Subject: [PATCH] clean up dialog stuff on presence for sla and other stuff git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@12708 d0543943-73ff-0310-b7d9-9358b9ac24b2 --- src/mod/endpoints/mod_sofia/mod_sofia.c | 4 + src/mod/endpoints/mod_sofia/mod_sofia.h | 9 +- src/mod/endpoints/mod_sofia/sofia.c | 6 +- src/mod/endpoints/mod_sofia/sofia_glue.c | 41 ++++ src/mod/endpoints/mod_sofia/sofia_presence.c | 14 +- src/mod/endpoints/mod_sofia/sofia_reg.c | 202 ++++++++++++------- src/mod/endpoints/mod_sofia/sofia_sla.c | 113 ++++++++--- 7 files changed, 287 insertions(+), 102 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 6b9dd742b5..661556d51b 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -2703,6 +2703,8 @@ static int notify_callback(void *pArg, int argc, char **argv, char **columnNames SIPTAG_CONTACT_STR(profile->url), TAG_END()); + nua_handle_bind(nh, &mod_sofia_globals.destroy_private); + nua_notify(nh, NUTAG_NEWSUB(1), SIPTAG_EVENT_STR(es), @@ -2902,6 +2904,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load) memset(&mod_sofia_globals, 0, sizeof(mod_sofia_globals)); mod_sofia_globals.destroy_private.destroy_nh = 1; + mod_sofia_globals.destroy_private.is_static = 1; + mod_sofia_globals.keep_private.is_static = 1; mod_sofia_globals.pool = pool; switch_mutex_init(&mod_sofia_globals.mutex, SWITCH_MUTEX_NESTED, mod_sofia_globals.pool); diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index 8065cbbee4..c2de0e46a8 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -122,10 +122,12 @@ struct sofia_private { int destroy_nh; int destroy_me; int is_call; + int is_static; }; #define set_param(ptr,val) if (ptr) {free(ptr) ; ptr = NULL;} if (val) {ptr = strdup(val);} #define set_anchor(t,m) if (t->Anchor) {delete t->Anchor;} t->Anchor = new SipMessage(m); +#define sofia_private_free(_pvt) if (_pvt && ! _pvt->is_static) {free(_pvt); _pvt = NULL;} /* Local Structures */ /*************************************************************************************************************************************************************/ @@ -321,6 +323,7 @@ struct sofia_gateway_subscription { struct sofia_gateway { sofia_private_t *sofia_private; nua_handle_t *nh; + nua_handle_t *sub_nh; sofia_profile_t *profile; char *name; char *register_scheme; @@ -810,10 +813,12 @@ void sofia_glue_set_image_sdp(private_object_t *tech_pvt, switch_t38_options_t * * SLA (shared line appearance) entrypoints */ -void sofia_sla_handle_register(nua_t *nua, sofia_profile_t *profile, sip_t const *sip); +void sofia_sla_handle_register(nua_t *nua, sofia_profile_t *profile, sip_t const *sip, 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, 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, tagi_t tags[]); -void sofia_sla_handle_sip_r_subscribe(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip, 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, 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, tagi_t tags[]); /* diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 3cdda830a1..46e031aec5 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -111,6 +111,7 @@ void sofia_handle_sip_i_notify(switch_core_session_t *session, int status, sofia_sla_handle_sip_i_notify(nua, profile, nh, sip, tags); if (sub_state == nua_substate_terminated) { + sofia_private_free(sofia_private); nua_handle_bind(nh, NULL); nua_handle_destroy(nh); } @@ -544,8 +545,7 @@ void sofia_event_callback(nua_event_t event, nua_handle_bind(nh, NULL); } sofia_private->destroy_me = 12; - free(sofia_private); - sofia_private = NULL; + sofia_private_free(sofia_private); } if (gateway) { @@ -4721,7 +4721,7 @@ void sofia_handle_sip_i_invite(nua_t *nua, sofia_profile_t *profile, nua_handle_ } nua_handle_bind(nh, NULL); - free(sofia_private); + 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()); } diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index 3ddb9488b7..ae5ec822c3 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -3265,6 +3265,15 @@ int sofia_glue_init_sql(sofia_profile_t *profile) " contact_str VARCHAR(255)\n" ");\n"; + char shared_appearance_dialogs_sql[] = + "CREATE TABLE sip_shared_appearance_dialogs (\n" + " profile_name VARCHAR(255),\n" + " hostname VARCHAR(255),\n" + " contact_str VARCHAR(255),\n" + " call_id VARCHAR(255),\n" + " expires INTEGER\n" + ");\n"; + if (profile->odbc_dsn) { #ifdef SWITCH_HAVE_ODBC int x; @@ -3298,6 +3307,13 @@ int sofia_glue_init_sql(sofia_profile_t *profile) "create index ssa_subscriber on sip_shared_appearance_subscriptions (subscriber)", "create index ssa_profile_name on sip_shared_appearance_subscriptions (profile_name)", "create index ssa_aor on sip_shared_appearance_subscriptions (aor)", + + "create index ssd_profile_name on sip_shared_appearance_dialogs (profile_name)", + "create index ssd_hostname on sip_shared_appearance_dialogs (hostname)", + "create index ssd_contact_str on sip_shared_appearance_dialogs (contact_str)", + "create index ssd_call_id on sip_shared_appearance_dialogs (call_id)", + "create index ssd_expires on sip_shared_appearance_dialogs (expires)", + NULL }; @@ -3361,6 +3377,15 @@ int sofia_glue_init_sql(sofia_profile_t *profile) } free(test_sql); + + test_sql = switch_mprintf("delete from sip_shared_appearance_dialogs where contact_str='' or hostname='%q'", mod_sofia_globals.hostname); + if (switch_odbc_handle_exec(profile->master_odbc, test_sql, NULL) != SWITCH_ODBC_SUCCESS) { + switch_odbc_handle_exec(profile->master_odbc, "DROP TABLE sip_shared_appearance_dialogs", NULL); + switch_odbc_handle_exec(profile->master_odbc, shared_appearance_dialogs_sql, NULL); + } + free(test_sql); + + for (x = 0; indexes[x]; x++) { switch_odbc_handle_exec(profile->master_odbc, indexes[x], NULL); } @@ -3402,6 +3427,10 @@ int sofia_glue_init_sql(sofia_profile_t *profile) test_sql = switch_mprintf("delete from sip_shared_appearance_subscriptions where contact_str = '' or hostname='%q'", mod_sofia_globals.hostname); switch_core_db_test_reactive(profile->master_db, test_sql, "DROP TABLE sip_shared_appearance_subscriptions", shared_appearance_sql); free(test_sql); + + test_sql = switch_mprintf("delete from sip_shared_appearance_dialogs where contact_str = '' or hostname='%q'", mod_sofia_globals.hostname); + switch_core_db_test_reactive(profile->master_db, test_sql, "DROP TABLE sip_shared_appearance_dialogs", shared_appearance_dialogs_sql); + free(test_sql); switch_core_db_exec(profile->master_db, "create index if not exists ssa_hostname on sip_shared_appearance_subscriptions (hostname)", NULL, NULL, NULL); @@ -3412,6 +3441,18 @@ int sofia_glue_init_sql(sofia_profile_t *profile) switch_core_db_exec(profile->master_db, "create index if not exists ssa_aor on sip_shared_appearance_subscriptions (aor)", NULL, NULL, NULL); + switch_core_db_exec(profile->master_db, "create index if not exists ssd_profile_name on sip_shared_appearance_dialogs (profile_name)", + NULL, NULL, NULL); + switch_core_db_exec(profile->master_db, "create index if not exists ssd_hostname on sip_shared_appearance_dialogs (hostname)", + NULL, NULL, NULL); + switch_core_db_exec(profile->master_db, "create index if not exists ssd_contact_str on sip_shared_appearance_dialogs (contact_str)", + NULL, NULL, NULL); + switch_core_db_exec(profile->master_db, "create index if not exists ssd_call_id on sip_shared_appearance_dialogs (call_id)", + NULL, NULL, NULL); + switch_core_db_exec(profile->master_db, "create index if not exists ssd_expires on sip_shared_appearance_dialogs (expires)", + NULL, NULL, NULL); + + switch_core_db_exec(profile->master_db, "create index if not exists sr_call_id on sip_registrations (call_id)", NULL, NULL, NULL); switch_core_db_exec(profile->master_db, "create index if not exists sr_sip_user on sip_registrations (sip_user)", NULL, NULL, NULL); diff --git a/src/mod/endpoints/mod_sofia/sofia_presence.c b/src/mod/endpoints/mod_sofia/sofia_presence.c index d3820dc8ec..2d8579a087 100644 --- a/src/mod/endpoints/mod_sofia/sofia_presence.c +++ b/src/mod/endpoints/mod_sofia/sofia_presence.c @@ -177,7 +177,7 @@ switch_status_t sofia_presence_chat_send(const char *proto, const char *from, co SIPTAG_FROM_STR(from), NUTAG_URL(contact), SIPTAG_TO_STR(clean_to), SIPTAG_CONTACT_STR(profile->url), TAG_END()); - + nua_handle_bind(msg_nh, &mod_sofia_globals.destroy_private); nua_message(msg_nh, SIPTAG_CONTENT_TYPE_STR(ct), SIPTAG_PAYLOAD_STR(body), TAG_END()); end: @@ -1827,7 +1827,7 @@ void sofia_presence_handle_sip_r_subscribe(int status, /* 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(nua, profile, nh, sip, tags); + sofia_sla_handle_sip_r_subscribe(status, phrase, nua, profile, nh, sofia_private, sip, tags); return; } } @@ -1860,6 +1860,16 @@ void sofia_presence_handle_sip_r_subscribe(int status, default: switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "status (%d) != 200, updated state to SUB_STATE_FAILED.\n", status); gw_sub_ptr->state = SUB_STATE_FAILED; + + if (sofia_private) { + nua_handle_destroy(sofia_private->gateway->sub_nh); + sofia_private->gateway->sub_nh = NULL; + nua_handle_bind(sofia_private->gateway->sub_nh, NULL); + sofia_private_free(sofia_private); + } else { + nua_handle_destroy(nh); + } + break; } } diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c index 9eecb33bc4..4b377308de 100644 --- a/src/mod/endpoints/mod_sofia/sofia_reg.c +++ b/src/mod/endpoints/mod_sofia/sofia_reg.c @@ -37,24 +37,54 @@ */ #include "mod_sofia.h" -static void sofia_reg_kill_reg(sofia_gateway_t *gateway_ptr, int unreg) +static void sofia_reg_new_handle(sofia_gateway_t *gateway_ptr) { + int ss_state = nua_callstate_authenticating; + if (gateway_ptr->nh) { - if (unreg) { - nua_unregister(gateway_ptr->nh, - NUTAG_URL(gateway_ptr->register_url), - SIPTAG_FROM_STR(gateway_ptr->register_from), - SIPTAG_TO_STR(gateway_ptr->register_from), - SIPTAG_CONTACT_STR(gateway_ptr->register_contact), - SIPTAG_EXPIRES_STR(gateway_ptr->expires_str), - NUTAG_REGISTRAR(gateway_ptr->register_proxy), - NUTAG_OUTBOUND("no-options-keepalive"), NUTAG_OUTBOUND("no-validate"), NUTAG_KEEPALIVE(0), TAG_NULL()); - } nua_handle_bind(gateway_ptr->nh, NULL); nua_handle_destroy(gateway_ptr->nh); gateway_ptr->nh = NULL; + sofia_private_free(gateway_ptr->sofia_private); } + gateway_ptr->nh = nua_handle(gateway_ptr->profile->nua, NULL, + SIPTAG_CALL_ID_STR(gateway_ptr->uuid_str), + NUTAG_URL(gateway_ptr->register_proxy), + SIPTAG_TO_STR(gateway_ptr->register_to), + NUTAG_CALLSTATE_REF(ss_state), SIPTAG_FROM_STR(gateway_ptr->register_from), TAG_END()); + + + if (!gateway_ptr->sofia_private) { + gateway_ptr->sofia_private = malloc(sizeof(*gateway_ptr->sofia_private)); + switch_assert(gateway_ptr->sofia_private); + } + memset(gateway_ptr->sofia_private, 0, sizeof(*gateway_ptr->sofia_private)); + + gateway_ptr->sofia_private->gateway = gateway_ptr; + nua_handle_bind(gateway_ptr->nh, gateway_ptr->sofia_private); +} + +static void sofia_reg_kill_reg(sofia_gateway_t *gateway_ptr) +{ + + if (!gateway_ptr->nh) { + sofia_reg_new_handle(gateway_ptr); + + } + + if (gateway_ptr->nh) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "UN-Registering %s\n", gateway_ptr->name); + nua_unregister(gateway_ptr->nh, + NUTAG_URL(gateway_ptr->register_url), + SIPTAG_FROM_STR(gateway_ptr->register_from), + SIPTAG_TO_STR(gateway_ptr->register_from), + SIPTAG_CONTACT_STR(gateway_ptr->register_contact), + SIPTAG_EXPIRES_STR(gateway_ptr->expires_str), + NUTAG_REGISTRAR(gateway_ptr->register_proxy), + NUTAG_OUTBOUND("no-options-keepalive"), NUTAG_OUTBOUND("no-validate"), NUTAG_KEEPALIVE(0), TAG_NULL()); + } + } static void sofia_reg_fire_custom_gateway_state_event(sofia_gateway_t *gateway) { @@ -71,10 +101,9 @@ void sofia_reg_unregister(sofia_profile_t *profile) sofia_gateway_t *gateway_ptr; for (gateway_ptr = profile->gateways; gateway_ptr; gateway_ptr = gateway_ptr->next) { if (gateway_ptr->sofia_private) { - free(gateway_ptr->sofia_private); - gateway_ptr->sofia_private = NULL; + sofia_private_free(gateway_ptr->sofia_private); } - sofia_reg_kill_reg(gateway_ptr, 1); + sofia_reg_kill_reg(gateway_ptr); } } @@ -108,7 +137,7 @@ void sofia_sub_check_gateway(sofia_profile_t *profile, time_t now) break; case SUB_STATE_UNSUBSCRIBE: gw_sub_ptr->state = SUB_STATE_NOSUB; - + /* not tested .. */ nua_unsubscribe(gateway_ptr->nh, NUTAG_URL(gateway_ptr->register_url), @@ -121,24 +150,23 @@ void sofia_sub_check_gateway(sofia_profile_t *profile, time_t now) break; case SUB_STATE_UNSUBED: - if ((gateway_ptr->nh = nua_handle(gateway_ptr->profile->nua, NULL, - NUTAG_URL(gateway_ptr->register_proxy), - SIPTAG_TO_STR(gateway_ptr->register_to), - NUTAG_CALLSTATE_REF(ss_state), - SIPTAG_FROM_STR(gateway_ptr->register_from), TAG_END()))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "subscribing to [%s] on gateway [%s]\n", gw_sub_ptr->event, gateway_ptr->name); - } + gateway_ptr->sub_nh = nua_handle(gateway_ptr->profile->nua, NULL, + NUTAG_URL(gateway_ptr->register_proxy), + SIPTAG_TO_STR(gateway_ptr->register_to), + NUTAG_CALLSTATE_REF(ss_state), + SIPTAG_FROM_STR(gateway_ptr->register_from), TAG_END()); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "subscribing to [%s] on gateway [%s]\n", gw_sub_ptr->event, gateway_ptr->name); gateway_ptr->sofia_private = malloc(sizeof(*gateway_ptr->sofia_private)); switch_assert(gateway_ptr->sofia_private); - + memset(gateway_ptr->sofia_private, 0, sizeof(*gateway_ptr->sofia_private)); gateway_ptr->sofia_private->gateway = gateway_ptr; nua_handle_bind(gateway_ptr->nh, gateway_ptr->sofia_private); if (now) { - nua_subscribe(gateway_ptr->nh, + nua_subscribe(gateway_ptr->sub_nh, NUTAG_URL(gateway_ptr->register_url), SIPTAG_EVENT_STR(gw_sub_ptr->event), SIPTAG_ACCEPT_STR(gw_sub_ptr->content_type), @@ -149,7 +177,7 @@ void sofia_sub_check_gateway(sofia_profile_t *profile, time_t now) TAG_NULL()); gw_sub_ptr->retry = now + gw_sub_ptr->retry_seconds; } else { - nua_unsubscribe(gateway_ptr->nh, + nua_unsubscribe(gateway_ptr->sub_nh, NUTAG_URL(gateway_ptr->register_url), SIPTAG_EVENT_STR(gw_sub_ptr->event), SIPTAG_ACCEPT_STR(gw_sub_ptr->content_type), @@ -207,7 +235,6 @@ void sofia_reg_check_gateway(sofia_profile_t *profile, time_t now) } for (gateway_ptr = profile->gateways; gateway_ptr; gateway_ptr = gateway_ptr->next) { - int ss_state = nua_callstate_authenticating; reg_state_t ostate = gateway_ptr->state; if (!now) { @@ -223,6 +250,7 @@ void sofia_reg_check_gateway(sofia_profile_t *profile, time_t now) switch_assert(pvt); memset(pvt, 0, sizeof(*pvt)); pvt->destroy_nh = 1; + pvt->destroy_me = 1; switch_copy_string(pvt->gateway_name, gateway_ptr->name, sizeof(pvt->gateway_name)); nua_handle_bind(nh, pvt); @@ -254,64 +282,46 @@ void sofia_reg_check_gateway(sofia_profile_t *profile, time_t now) break; case REG_STATE_UNREGISTER: - sofia_reg_kill_reg(gateway_ptr, 1); + sofia_reg_kill_reg(gateway_ptr); gateway_ptr->state = REG_STATE_NOREG; break; case REG_STATE_UNREGED: gateway_ptr->status = SOFIA_GATEWAY_DOWN; - sofia_reg_kill_reg(gateway_ptr, 0); + + sofia_reg_new_handle(gateway_ptr); - if ((gateway_ptr->nh = nua_handle(gateway_ptr->profile->nua, NULL, - SIPTAG_CALL_ID_STR(gateway_ptr->uuid_str), - NUTAG_URL(gateway_ptr->register_proxy), - SIPTAG_TO_STR(gateway_ptr->register_to), - NUTAG_CALLSTATE_REF(ss_state), SIPTAG_FROM_STR(gateway_ptr->register_from), TAG_END()))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Registering %s\n", gateway_ptr->name); - - if (!gateway_ptr->sofia_private) { - gateway_ptr->sofia_private = malloc(sizeof(*gateway_ptr->sofia_private)); - switch_assert(gateway_ptr->sofia_private); - } - memset(gateway_ptr->sofia_private, 0, sizeof(*gateway_ptr->sofia_private)); - - gateway_ptr->sofia_private->gateway = gateway_ptr; - nua_handle_bind(gateway_ptr->nh, gateway_ptr->sofia_private); - - if (now) { - nua_register(gateway_ptr->nh, - NUTAG_URL(gateway_ptr->register_url), - TAG_IF(gateway_ptr->register_sticky_proxy, NUTAG_PROXY(gateway_ptr->register_sticky_proxy)), - SIPTAG_TO_STR(gateway_ptr->register_from), - SIPTAG_FROM_STR(gateway_ptr->register_from), - SIPTAG_CONTACT_STR(gateway_ptr->register_contact), - SIPTAG_EXPIRES_STR(gateway_ptr->expires_str), - NUTAG_REGISTRAR(gateway_ptr->register_proxy), - NUTAG_OUTBOUND("no-options-keepalive"), NUTAG_OUTBOUND("no-validate"), NUTAG_KEEPALIVE(0), TAG_NULL()); - gateway_ptr->retry = now + gateway_ptr->retry_seconds; - } else { - nua_unregister(gateway_ptr->nh, - NUTAG_URL(gateway_ptr->register_url), - SIPTAG_FROM_STR(gateway_ptr->register_from), - SIPTAG_TO_STR(gateway_ptr->register_from), - SIPTAG_CONTACT_STR(gateway_ptr->register_contact), - SIPTAG_EXPIRES_STR(gateway_ptr->expires_str), - NUTAG_REGISTRAR(gateway_ptr->register_proxy), - NUTAG_OUTBOUND("no-options-keepalive"), NUTAG_OUTBOUND("no-validate"), NUTAG_KEEPALIVE(0), TAG_NULL()); - } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Registering %s\n", gateway_ptr->name); + + if (now) { + nua_register(gateway_ptr->nh, + NUTAG_URL(gateway_ptr->register_url), + TAG_IF(gateway_ptr->register_sticky_proxy, NUTAG_PROXY(gateway_ptr->register_sticky_proxy)), + SIPTAG_TO_STR(gateway_ptr->register_from), + SIPTAG_FROM_STR(gateway_ptr->register_from), + SIPTAG_CONTACT_STR(gateway_ptr->register_contact), + SIPTAG_EXPIRES_STR(gateway_ptr->expires_str), + NUTAG_REGISTRAR(gateway_ptr->register_proxy), + NUTAG_OUTBOUND("no-options-keepalive"), NUTAG_OUTBOUND("no-validate"), NUTAG_KEEPALIVE(0), TAG_NULL()); gateway_ptr->retry = now + gateway_ptr->retry_seconds; - gateway_ptr->state = REG_STATE_TRYING; - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error registering %s failure #%d\n", gateway_ptr->name, ++gateway_ptr->failures); - gateway_ptr->state = REG_STATE_FAILED; + nua_unregister(gateway_ptr->nh, + NUTAG_URL(gateway_ptr->register_url), + SIPTAG_FROM_STR(gateway_ptr->register_from), + SIPTAG_TO_STR(gateway_ptr->register_from), + SIPTAG_CONTACT_STR(gateway_ptr->register_contact), + SIPTAG_EXPIRES_STR(gateway_ptr->expires_str), + NUTAG_REGISTRAR(gateway_ptr->register_proxy), + NUTAG_OUTBOUND("no-options-keepalive"), NUTAG_OUTBOUND("no-validate"), NUTAG_KEEPALIVE(0), TAG_NULL()); } + gateway_ptr->retry = now + gateway_ptr->retry_seconds; + gateway_ptr->state = REG_STATE_TRYING; + break; case REG_STATE_FAILED: switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "%s Failed Registration, setting retry to %d seconds.\n", gateway_ptr->name, gateway_ptr->retry_seconds * (gateway_ptr->failures + 1)); gateway_ptr->retry = now + (gateway_ptr->retry_seconds * (gateway_ptr->failures + 1)); - sofia_reg_kill_reg(gateway_ptr, 0); gateway_ptr->status = SOFIA_GATEWAY_DOWN; gateway_ptr->state = REG_STATE_FAIL_WAIT; break; @@ -408,6 +418,7 @@ void sofia_reg_send_reboot(sofia_profile_t *profile, const char *user, const cha SIPTAG_CONTACT_STR(profile->url), TAG_END()); + nua_handle_bind(nh, &mod_sofia_globals.destroy_private); nua_notify(nh, NUTAG_NEWSUB(1), SIPTAG_EVENT_STR(event), @@ -422,6 +433,17 @@ void sofia_reg_send_reboot(sofia_profile_t *profile, const char *user, const cha switch_safe_free(id); } +int sofia_sla_dialog_del_callback(void *pArg, int argc, char **argv, char **columnNames) +{ + sofia_profile_t *profile = (sofia_profile_t *) pArg; + nua_handle_t *nh = NULL; + + if ((nh = nua_handle_by_call_id(profile->nua, argv[0]))) { + nua_handle_destroy(nh); + } + + return 0; +} int sofia_reg_del_callback(void *pArg, int argc, char **argv, char **columnNames) { @@ -522,6 +544,21 @@ void sofia_reg_check_expire(sofia_profile_t *profile, time_t now, int reboot) sofia_glue_actually_execute_sql(profile, SWITCH_FALSE, sql, NULL); + + if (now) { + switch_snprintf(sql, sizeof(sql), "select call_id from sip_shared_appearance_dialogs where hostname='%s' " + "and profile_name='%s' and expires <= %ld", + mod_sofia_globals.hostname, profile->name, (long) now); + + sofia_glue_execute_sql_callback(profile, SWITCH_TRUE, NULL, sql, sofia_sla_dialog_del_callback, profile); + switch_snprintf(sql, sizeof(sql), "delete from sip_registrations where expires > 0 and hostname='%s' and expires <= %ld", + mod_sofia_globals.hostname, (long) now); + + + sofia_glue_actually_execute_sql(profile, SWITCH_FALSE, sql, NULL); + } + + if (now) { switch_snprintf(sql, sizeof(sql), "delete from sip_presence where expires > 0 and expires <= %ld and hostname='%s'", (long) now, mod_sofia_globals.hostname); @@ -1018,7 +1055,7 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand 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", to_user, reg_host); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "status", "UNRegistered"); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "status", "Unregistered"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", "presence"); switch_event_fire(&event); } @@ -1112,7 +1149,11 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand } if (sofia_test_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE)) { - sofia_sla_handle_register(nua, profile, sip); + char *full_contact = sip_header_as_string(nh->nh_home, (void *) sip->sip_contact); + if (full_contact && switch_stristr("SUBSCRIBE", full_contact)) { + sofia_sla_handle_register(nua, profile, sip, exptime, full_contact); + su_free(nh->nh_home, full_contact); + } } return 1; @@ -1275,6 +1316,23 @@ void sofia_reg_handle_sip_r_register(int status, if (ostate != sofia_private->gateway->state) { sofia_reg_fire_custom_gateway_state_event(sofia_private->gateway); } + + + if (status >= 200) { + if (sofia_private) { + if (sofia_private->gateway) { + nua_handle_destroy(sofia_private->gateway->nh); + sofia_private->gateway->nh = NULL; + nua_handle_bind(sofia_private->gateway->nh, NULL); + sofia_private->gateway->sofia_private = NULL; + } else { + nua_handle_destroy(nh); + } + sofia_private_free(sofia_private); + } else { + nua_handle_destroy(nh); + } + } } } diff --git a/src/mod/endpoints/mod_sofia/sofia_sla.c b/src/mod/endpoints/mod_sofia/sofia_sla.c index 07d9cc4ca4..258fd7ede2 100644 --- a/src/mod/endpoints/mod_sofia/sofia_sla.c +++ b/src/mod/endpoints/mod_sofia/sofia_sla.c @@ -39,37 +39,81 @@ static int sofia_sla_sub_callback(void *pArg, int argc, char **argv, char **columnNames); -void sofia_sla_handle_register(nua_t *nua, sofia_profile_t *profile, sip_t const *sip) +struct sla_helper { + char call_id[1024]; +}; + + +static int get_call_id_callback(void *pArg, int argc, char **argv, char **columnNames) { - nua_handle_t *nh; + struct sla_helper *sh = (struct sla_helper *) pArg; - /* TODO: - * check to see if it says in the group or extension xml that we are handling SLA for this AOR - * check to see if we're already subscribed and the call-id in the subscribe matches. if so, - * we can skip this, which would keep us from re-subscribing which would also keep us from - * leaking so horribly much memory like we do now - */ + switch_set_string(sh->call_id, argv[0]); - nh = nua_handle(nua, NULL, NUTAG_URL(sip->sip_contact->m_url), TAG_NULL()); + return 0; +} - /* we make up and bind a sofia_private so that the existing event handler destruction code won't be confused by us */ - /* (though it isn't clear that this is sufficient... we still have break cases for nua_i_notify and nua_r_notify - * in sofia_event_callback's destruction end because if we don't, the handle gets destroyed. or maybe it is - * something else i'm doing wrong? MTK +char *strip_uri(const char *str) +{ + char *p; + char *r; - mod_sofia_globals.keep_private is a magic static private things can share for this purpose: ACM - */ + if ((p = strchr(str, '<'))) { + p++; + r = strdup(p); + if ((p = strchr(r, '>'))) { + *p = '\0'; + } + } else { + r = strdup(str); + } + + return r; +} + +void sofia_sla_handle_register(nua_t *nua, sofia_profile_t *profile, sip_t const *sip, 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 = strip_uri(full_contact); + + + 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, SWITCH_FALSE, 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))) { + 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(my_contact, sizeof(my_contact), "%s;expires=%s", profile->sla_contact, exp_str); nua_subscribe(nh, - SIPTAG_TO(sip->sip_to), - SIPTAG_FROM(sip->sip_to), // ? - SIPTAG_CONTACT_STR(profile->sla_contact), - SIPTAG_EXPIRES_STR("3500"), /* ok, this is totally fake here XXX MTK */ - SIPTAG_EVENT_STR("dialog;sla"), /* some phones want ;include-session-description too? */ - TAG_NULL()); + 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"), /* some phones want ;include-session-description too? */ + TAG_NULL()); + + 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, tagi_t tags[]) @@ -165,9 +209,32 @@ struct sla_notify_helper { char *payload; }; -void sofia_sla_handle_sip_r_subscribe(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip, 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, tagi_t tags[]) { - /* apparently, we do nothing */ + if (status >= 300) { + nua_handle_destroy(nh); + sofia_private_free(sofia_private); + } else { + char *full_contact = sip_header_as_string(nh->nh_home, (void *) sip->sip_contact); + time_t expires = switch_epoch_time_now(NULL); + char *sql; + char *contact_str = 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, tagi_t tags[])