From e00ede7e7de2f4da2227b523e434a693f0c66951 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Sat, 26 Jan 2013 23:16:26 -0600 Subject: [PATCH] unreg on sock disconnect --- libs/sofia-sip/libsofia-sip-ua/nta/nta.c | 9 +- .../libsofia-sip-ua/nua/check_register.c | 162 ++++++++++++++++++ .../libsofia-sip-ua/nua/nua_registrar.c | 153 ++++++++++++++++- src/mod/endpoints/mod_sofia/mod_sofia.h | 12 +- src/mod/endpoints/mod_sofia/sofia.c | 26 ++- src/mod/endpoints/mod_sofia/sofia_reg.c | 99 +++++++++-- 6 files changed, 440 insertions(+), 21 deletions(-) diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/nta.c b/libs/sofia-sip/libsofia-sip-ua/nta/nta.c index 56a3c59b36..0ef2dcce76 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nta/nta.c +++ b/libs/sofia-sip/libsofia-sip-ua/nta/nta.c @@ -2286,7 +2286,6 @@ int agent_create_master_transport(nta_agent_t *self, tagi_t *tags) { self->sa_tports = tport_tcreate(self, nta_agent_class, self->sa_root, - TPTAG_SDWN_ERROR(0), TPTAG_IDLE(1800000), TAG_NEXT(tags)); @@ -8339,6 +8338,14 @@ outgoing_tport_error(nta_agent_t *agent, nta_outgoing_t *orq, return; } } + else if (error == 0) { + /* + * Server closed connection. RFC3261: + * "there is no coupling between TCP connection state and SIP + * processing." + */ + return; + } if (outgoing_other_destinations(orq)) { outgoing_print_tport_error(orq, 5, "trying alternative server after ", diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/check_register.c b/libs/sofia-sip/libsofia-sip-ua/nua/check_register.c index 6a3b3356a9..2372c9c2fc 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/check_register.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/check_register.c @@ -877,9 +877,171 @@ TCase *pingpong_tcase(int threading) return tc; } +/* ---------------------------------------------------------------------- */ + +static struct dialog *dialog = NULL; + +static void registrar_setup(void) +{ + struct event *event; + tagi_t const *t; + sip_contact_t *m; + + dialog = su_home_new(sizeof *dialog); fail_if(!dialog); + + nua = s2_nua_setup("register", + NUTAG_APPL_METHOD("REGISTER"), + NUTAG_ALLOW("REGISTER"), + NUTAG_PROXY(SIP_NONE), + TAG_END()); + + nua_get_params(nua, TAG_ANY(), TAG_END()); + event = s2_wait_for_event(nua_r_get_params, 200); + fail_unless(event != NULL); + + t = tl_find(event->data->e_tags, ntatag_contact); + fail_unless(t != NULL); + m = sip_contact_dup(dialog->home, (sip_contact_t *)t->t_value); + fail_unless(m != NULL); + + s2sip->sut.contact = m; +} + +static void registrar_thread_setup(void) +{ + s2_nua_thread = 1; + registrar_setup(); +} + +static void registrar_threadless_setup(void) +{ + s2_nua_thread = 1; + registrar_setup(); +} + +static void registrar_teardown(void) +{ + s2_teardown_started("registrar"); + nua_shutdown(nua); + fail_unless_event(nua_r_shutdown, 200); + s2_nua_teardown(); +} + +static void add_registrar_fixtures(TCase *tc, int threading) +{ + void (*setup)(void); + + if (threading) + setup = registrar_thread_setup; + else + setup = registrar_threadless_setup; + + tcase_add_checked_fixture(tc, setup, registrar_teardown); +} + +START_TEST(registrar_1_4_0) +{ + struct event *event; + nua_handle_t *nh; + struct message *response; + + S2_CASE("1.4.0", "Registrar", "Test receiving a REGISTER"); + + fail_if(s2_sip_request_to(dialog, SIP_METHOD_REGISTER, NULL, + SIPTAG_FROM_STR(""), + SIPTAG_TO_STR(""), + TAG_END())); + + event = s2_wait_for_event(nua_i_register, 100); + fail_unless(event != NULL); + nh = event->nh; fail_if(!nh); + + nua_respond(nh, 200, "Ok", + NUTAG_WITH_SAVED(event->event), + TAG_END()); + + response = s2_sip_wait_for_response(200, SIP_METHOD_REGISTER); + fail_if(!response); + s2_sip_free_message(response); + + nua_handle_destroy(nh); +} +END_TEST + +START_TEST(registrar_1_4_1) +{ + struct event *event; + nua_handle_t *nh; + struct message *response; + + S2_CASE("1.4.1", "Registrar", "Test receiving a REGISTER via TCP"); + + fail_if(s2_sip_request_to(dialog, SIP_METHOD_REGISTER, s2sip->tcp.tport, + SIPTAG_FROM_STR(""), + SIPTAG_TO_STR(""), + TAG_END())); + + event = s2_wait_for_event(nua_i_register, 100); + fail_if(!event); + nh = event->nh; fail_if(!nh); + + nua_respond(nh, 200, "Ok", + NUTAG_WITH_SAVED(event->event), + TAG_END()); + + response = s2_sip_wait_for_response(200, SIP_METHOD_REGISTER); + fail_if(!response); + tport_shutdown(response->tport, 2); + s2_sip_free_message(response); + + event = s2_wait_for_event(nua_i_media_error, 0); + fail_if(!event); + nua_handle_destroy(nh); + + fail_if(s2_sip_request_to(dialog, SIP_METHOD_REGISTER, s2sip->tcp.tport, + SIPTAG_FROM_STR(""), + SIPTAG_TO_STR(""), + TAG_END())); + + event = s2_wait_for_event(nua_i_register, 100); + fail_if(!event); + nh = event->nh; fail_if(!nh); + + nua_respond(nh, 200, "Ok", + NUTAG_WITH_SAVED(event->event), + TAG_END()); + + response = s2_sip_wait_for_response(200, SIP_METHOD_REGISTER); + fail_if(!response); + nua_handle_destroy(nh); + + s2_step(); + s2_step(); + s2_step(); + + tport_shutdown(response->tport, 2); + s2_sip_free_message(response); +} +END_TEST + +TCase *registrar_tcase(int threading) +{ + TCase *tc = tcase_create("1.4 - REGISTER server"); + + add_registrar_fixtures(tc, threading); + + tcase_add_test(tc, registrar_1_4_0); + tcase_add_test(tc, registrar_1_4_1); + + tcase_set_timeout(tc, 10); + + return tc; +} + void check_register_cases(Suite *suite, int threading) { suite_add_tcase(suite, register_tcase(threading)); suite_add_tcase(suite, pingpong_tcase(threading)); + suite_add_tcase(suite, registrar_tcase(threading)); } diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_registrar.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_registrar.c index be58993868..cb661b1717 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_registrar.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/nua_registrar.c @@ -39,6 +39,9 @@ #include +#define TP_CLIENT_T struct nua_handle_s +#define TP_STACK_T struct nta_agent_s + #include #include #include @@ -49,6 +52,79 @@ #include "nua_stack.h" +#include +#include + +/* ---------------------------------------------------------------------- */ +/* Registrar usage */ + +struct registrar_usage +{ + tport_t *tport; /**< */ + int pending; /**< Waiting for tport to close */ +}; + +static char const *nua_registrar_usage_name(nua_dialog_usage_t const *du) +{ + return "registrar"; +} + +static int nua_registrar_usage_add(nua_handle_t *nh, + nua_dialog_state_t *ds, + nua_dialog_usage_t *du) +{ + return 0; +} + +static void nua_registrar_usage_remove(nua_handle_t *nh, + nua_dialog_state_t *ds, + nua_dialog_usage_t *du, + nua_client_request_t *cr, + nua_server_request_t *sr) +{ + struct registrar_usage *ru; + + ru = nua_dialog_usage_private(du); + + if (ru->pending) + tport_release(ru->tport, ru->pending, NULL, NULL, nh, 0), ru->pending = 0; + + tport_unref(ru->tport), ru->tport = NULL; +} + +static void nua_registrar_usage_refresh(nua_handle_t *nh, + nua_dialog_state_t *ds, + nua_dialog_usage_t *du, + sip_time_t now) +{ +} + +/** Terminate registration usage. + * + * @retval >0 shutdown done + * @retval 0 shutdown in progress + * @retval <0 try again later + */ +static int nua_registrar_usage_shutdown(nua_handle_t *nh, + nua_dialog_state_t *ds, + nua_dialog_usage_t *du) +{ + return 1; +} + +static nua_usage_class const nua_registrar_usage[1] = { + { + sizeof (struct registrar_usage), sizeof nua_registrar_usage, + nua_registrar_usage_add, + nua_registrar_usage_remove, + nua_registrar_usage_name, + nua_base_usage_update_params, + NULL, + nua_registrar_usage_refresh, + nua_registrar_usage_shutdown + }}; + + /* ======================================================================== */ /* REGISTER */ @@ -93,6 +169,9 @@ * @END_NUA_EVENT */ +static int nua_registrar_server_preprocess(nua_server_request_t *sr); +static int nua_registrar_server_report(nua_server_request_t *, tagi_t const *); + nua_server_methods_t const nua_register_server_methods = { SIP_METHOD_REGISTER, @@ -104,8 +183,78 @@ nua_server_methods_t const nua_register_server_methods = 0, /* Do not add Contact */ }, nua_base_server_init, - nua_base_server_preprocess, + nua_registrar_server_preprocess, nua_base_server_params, nua_base_server_respond, - nua_base_server_report, + nua_registrar_server_report, }; + +static void +registrar_tport_error(nta_agent_t *nta, nua_handle_t *nh, + tport_t *tp, msg_t *msg, int error) +{ + nua_dialog_state_t *ds = nh->nh_ds; + nua_dialog_usage_t *du; + struct registrar_usage *ru; + + SU_DEBUG_3(("tport error %d: %s\n", error, su_strerror(error))); + + du = nua_dialog_usage_get(ds, nua_registrar_usage, NULL); + + if (du == NULL) + return; + + ru = nua_dialog_usage_private(du); + if (ru->tport) { + tport_release(ru->tport, ru->pending, NULL, NULL, nh, 0), ru->pending = 0; + tport_unref(ru->tport), ru->tport = NULL; + } + + nua_stack_event(nh->nh_nua, nh, NULL, + nua_i_media_error, 500, "Transport error detected", + NULL); +} + +static int +nua_registrar_server_preprocess(nua_server_request_t *sr) +{ + nua_handle_t *nh = sr->sr_owner; + nua_dialog_state_t *ds = sr->sr_owner->nh_ds; + nua_dialog_usage_t *du; + struct registrar_usage *ru; + tport_t *tport; + + tport = nta_incoming_transport(nh->nh_nua->nua_nta, sr->sr_irq, sr->sr_request.msg); + + if (!tport_is_tcp(tport)) + return 0; + + du = nua_dialog_usage_get(ds, nua_registrar_usage, NULL); + if (du == NULL) + du = nua_dialog_usage_add(nh, ds, nua_registrar_usage, NULL); + + if (du == NULL) + return SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR); + + ru = nua_dialog_usage_private(du); + + if (ru->tport && ru->tport != tport) { + tport_release(ru->tport, ru->pending, NULL, NULL, nh, 0), ru->pending = 0; + tport_unref(ru->tport), ru->tport = NULL; + } + + ru->tport = tport_ref(tport); + ru->pending = tport_pend(tport, NULL, registrar_tport_error, nh); + + tport_set_params(tport, + TPTAG_SDWN_ERROR(1), + TAG_END()); + + return 0; +} + +static int +nua_registrar_server_report(nua_server_request_t *sr, tagi_t const *tags) +{ + return nua_base_server_report(sr, tags); +} diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index bc5765aa0d..269371b30c 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -166,6 +166,10 @@ struct sofia_private { sofia_gateway_t *gateway; char gateway_name[256]; char auth_gateway_name[256]; + char *call_id; + char *network_ip; + char *network_port; + char *key; int destroy_nh; int destroy_me; int is_call; @@ -838,7 +842,7 @@ void sofia_handle_sip_i_info(nua_t *nua, sofia_profile_t *profile, nua_handle_t void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, sofia_dispatch_event_t *de, tagi_t tags[]); -void sofia_reg_handle_sip_i_register(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, +void sofia_reg_handle_sip_i_register(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[]); @@ -919,8 +923,9 @@ void sofia_glue_pass_sdp(private_object_t *tech_pvt, char *sdp); switch_call_cause_t sofia_glue_sip_cause_to_freeswitch(int status); void sofia_glue_do_xfer_invite(switch_core_session_t *session); uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip, - sofia_dispatch_event_t *de, - sofia_regtype_t regtype, char *key, uint32_t keylen, switch_event_t **v_event, const char *is_nat); + sofia_dispatch_event_t *de, + sofia_regtype_t regtype, char *key, + uint32_t keylen, switch_event_t **v_event, const char *is_nat, sofia_private_t **sofia_private_p); extern switch_endpoint_interface_t *sofia_endpoint_interface; void sofia_presence_set_chat_hash(private_object_t *tech_pvt, sip_t const *sip); switch_status_t sofia_on_hangup(switch_core_session_t *session); @@ -1098,6 +1103,7 @@ int sofia_glue_check_nat(sofia_profile_t *profile, const char *network_ip); switch_status_t sofia_glue_ext_address_lookup(sofia_profile_t *profile, char **ip, switch_port_t *port, const char *sourceip, switch_memory_pool_t *pool); +void sofia_reg_check_socket(sofia_profile_t *profile, const char *call_id, const char *network_addr, const char *network_ip); /* For Emacs: * Local Variables: diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 3c7f45e20a..10f0fc61f2 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -1268,7 +1268,7 @@ static void our_sofia_event_callback(nua_event_t event, case nua_i_register: //nua_respond(nh, SIP_200_OK, SIPTAG_CONTACT(sip->sip_contact), NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END()); //nua_handle_destroy(nh); - sofia_reg_handle_sip_i_register(nua, profile, nh, sofia_private, sip, de, tags); + sofia_reg_handle_sip_i_register(nua, profile, nh, &sofia_private, sip, de, tags); break; case nua_i_state: sofia_handle_sip_i_state(session, status, phrase, nua, profile, nh, sofia_private, sip, de, tags); @@ -1458,6 +1458,24 @@ static void our_sofia_event_callback(nua_event_t event, case nua_i_subscribe: sofia_presence_handle_sip_i_subscribe(status, phrase, nua, profile, nh, sofia_private, sip, de, tags); break; + case nua_i_media_error: + { + + if (sofia_private && sofia_private->call_id && sofia_private->network_ip && sofia_private->network_port) { + char *sql; + + sql = switch_mprintf("delete from sip_registrations where call_id='%q' and network_ip='%q' and network_port='%q'", + sofia_private->call_id, sofia_private->network_ip, sofia_private->network_port); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "SOCKET DISCONNECT: %s %s:%s\n", + sofia_private->call_id, sofia_private->network_ip, sofia_private->network_port); + sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE); + + + sofia_reg_check_socket(profile, sofia_private->call_id, sofia_private->network_ip, sofia_private->network_port); + } + nua_handle_destroy(nh); + } + break; case nua_r_authenticate: if (status >= 500) { @@ -1486,6 +1504,10 @@ static void our_sofia_event_callback(nua_event_t event, tech_pvt->want_event = 0; } + if (sofia_private && sofia_private->call_id) { + check_destroy = 0; + } + switch (event) { case nua_i_subscribe: case nua_r_notify: @@ -7837,7 +7859,7 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia if (!strcmp(network_ip, profile->sipip) && network_port == profile->sip_port) { calling_myself++; } else { - if (sofia_reg_handle_register(nua, profile, nh, sip, de, REG_INVITE, key, sizeof(key), &v_event, NULL)) { + if (sofia_reg_handle_register(nua, profile, nh, sip, de, REG_INVITE, key, sizeof(key), &v_event, NULL, NULL)) { if (v_event) { switch_event_destroy(&v_event); } diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c index b74b979ff1..5df0243283 100644 --- a/src/mod/endpoints/mod_sofia/sofia_reg.c +++ b/src/mod/endpoints/mod_sofia/sofia_reg.c @@ -636,15 +636,34 @@ int sofia_sla_dialog_del_callback(void *pArg, int argc, char **argv, char **colu return 0; } +void sofia_reg_check_socket(sofia_profile_t *profile, const char *call_id, const char *network_addr, const char *network_ip) +{ + char key[256] = ""; + nua_handle_t *hnh; + + switch_snprintf(key, sizeof(key), "%s%s%s", call_id, network_addr, network_ip); + switch_mutex_lock(profile->flag_mutex); + if ((hnh = switch_core_hash_find(profile->chat_hash, key))) { + switch_core_hash_delete(profile->chat_hash, key); + nua_handle_unref(hnh); + } + switch_mutex_unlock(profile->flag_mutex); +} + + + int sofia_reg_del_callback(void *pArg, int argc, char **argv, char **columnNames) { switch_event_t *s_event; sofia_profile_t *profile = (sofia_profile_t *) pArg; - if (argc > 12 && atoi(argv[12]) == 1) { + if (argc > 13 && atoi(argv[13]) == 1) { sofia_reg_send_reboot(profile, argv[0], argv[1], argv[2], argv[3], argv[7], argv[11]); } + sofia_reg_check_socket(profile, argv[0], argv[11], argv[12]); + + if (argc >= 3) { if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_EXPIRE) == SWITCH_STATUS_SUCCESS) { switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile-name", argv[10]); @@ -706,7 +725,7 @@ void sofia_reg_expire_call_id(sofia_profile_t *profile, const char *call_id, int } sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,rpid,expires" - ",user_agent,server_user,server_host,profile_name,network_ip" + ",user_agent,server_user,server_host,profile_name,network_ip,network_port" ",%d from sip_registrations where call_id='%q' %s", reboot, call_id, sqlextra); @@ -728,11 +747,11 @@ void sofia_reg_check_expire(sofia_profile_t *profile, time_t now, int reboot) if (now) { sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,rpid,expires" - ",user_agent,server_user,server_host,profile_name,network_ip" + ",user_agent,server_user,server_host,profile_name,network_ip, network_port" ",%d from sip_registrations where expires > 0 and expires <= %ld", reboot, (long) now); } else { sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,rpid,expires" - ",user_agent,server_user,server_host,profile_name,network_ip" ",%d from sip_registrations where expires > 0", reboot); + ",user_agent,server_user,server_host,profile_name,network_ip, network_port" ",%d from sip_registrations where expires > 0", reboot); } sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sofia_reg_del_callback, profile); @@ -872,7 +891,7 @@ void sofia_reg_check_sync(sofia_profile_t *profile) char *sql; sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,rpid,expires" - ",user_agent,server_user,server_host,profile_name,network_ip" + ",user_agent,server_user,server_host,profile_name,network_ip,network_port" " from sip_registrations where expires > 0"); @@ -1065,7 +1084,7 @@ static int debounce_check(sofia_profile_t *profile, const char *user, const char uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sip_t const *sip, sofia_dispatch_event_t *de, sofia_regtype_t regtype, char *key, - uint32_t keylen, switch_event_t **v_event, const char *is_nat) + uint32_t keylen, switch_event_t **v_event, const char *is_nat, sofia_private_t **sofia_private_p) { sip_to_t const *to = NULL; sip_from_t const *from = NULL; @@ -1117,6 +1136,11 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand const char *uparams = NULL; const char *p; char *utmp = NULL; + sofia_private_t *sofia_private = NULL; + + if (sofia_private_p) { + sofia_private = *sofia_private_p; + } if (sip && sip->sip_contact->m_url->url_params) { uparams = sip->sip_contact->m_url->url_params; @@ -1606,6 +1630,7 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand multi_reg = (sofia_test_pflag(profile, PFLAG_MULTIREG)) ? 1 : 0; multi_reg_contact = (sofia_test_pflag(profile, PFLAG_MULTIREG_CONTACT)) ? 1 : 0; + if (multi_reg && avoid_multi_reg) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Disabling multiple registrations on a per-user basis for %s@%s\n", switch_str_nil(to_user), switch_str_nil(to_host)); @@ -1624,6 +1649,7 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand username = switch_event_get_header(auth_params, "sip_auth_username"); realm = switch_event_get_header(auth_params, "sip_auth_realm"); } + if (auth_res != AUTH_RENEWED || !multi_reg) { if (multi_reg) { if (multi_reg_contact) { @@ -1635,7 +1661,7 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand } else { sql = switch_mprintf("delete from sip_registrations where sip_user='%q' and sip_host='%q'", to_user, reg_host); } - + sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); } else { char buf[32] = ""; @@ -1663,6 +1689,38 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand switch_safe_free(url); switch_safe_free(contact); + + + + if ((is_wss || is_ws || is_tcp || is_tls) && !sofia_private && call_id) { + char key[256] = ""; + nua_handle_t *hnh; + switch_snprintf(key, sizeof(key), "%s%s%s", call_id, network_ip, network_port_c); + + switch_mutex_lock(profile->flag_mutex); + hnh = switch_core_hash_find(profile->chat_hash, key); + switch_mutex_unlock(profile->flag_mutex); + + if (!hnh) { + if (!(sofia_private = su_alloc(nh->nh_home, sizeof(*sofia_private)))) { + abort(); + } + + printf("SOFIA nh[%p] pvt[%p] call_id %s key %s\n", (void*) nh, (void *) sofia_private, call_id, key); + + memset(sofia_private, 0, sizeof(*sofia_private)); + sofia_private->call_id = su_strdup(nh->nh_home, call_id); + sofia_private->network_ip = su_strdup(nh->nh_home, network_ip); + sofia_private->network_port = su_strdup(nh->nh_home, network_port_c); + sofia_private->key = su_strdup(nh->nh_home, key); + sofia_private->is_static++; + *sofia_private_p = sofia_private; + nua_handle_bind(nh, sofia_private); + nua_handle_ref(nh); + switch_core_hash_insert(profile->chat_hash, key, nh); + } + } + if (!update_registration) { sql = switch_mprintf("insert into sip_registrations " @@ -1700,6 +1758,18 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); } + if (multi_reg) { + if (multi_reg_contact) { + sql = switch_mprintf("delete from sip_registrations where contact='%q' and expires!=%ld", contact_str, (long) reg_time + (long) exptime + 60); + } else { + sql = switch_mprintf("delete from sip_registrations where call_id='%q' and expires!=%ld", call_id, (long) reg_time + (long) exptime + 60); + } + + sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE); + } + + + if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_REGISTER) == SWITCH_STATUS_SUCCESS) { switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile-name", profile->name); switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "from-user", to_user); @@ -1739,6 +1809,8 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand } } + sofia_reg_check_socket(profile, call_id, network_ip, network_port_c); + if (send && switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) { switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "rpid", rpid); @@ -1769,7 +1841,7 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand } else { sql = switch_mprintf("delete from sip_registrations where call_id='%q'", call_id); } - + sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); switch_safe_free(icontact); @@ -1927,8 +1999,8 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand -void sofia_reg_handle_sip_i_register(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, +void sofia_reg_handle_sip_i_register(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t **sofia_private_p, sip_t const *sip, + sofia_dispatch_event_t *de, tagi_t tags[]) { char key[128] = ""; @@ -1938,6 +2010,7 @@ void sofia_reg_handle_sip_i_register(nua_t *nua, sofia_profile_t *profile, nua_h int network_port = 0; char *is_nat = NULL; + #if 0 /* This seems to cause undesirable effects so nevermind */ if (sip->sip_to && sip->sip_to->a_url && sip->sip_to->a_url->url_host) { const char *to_host = sip->sip_to->a_url->url_host; @@ -2043,15 +2116,15 @@ void sofia_reg_handle_sip_i_register(nua_t *nua, sofia_profile_t *profile, nua_h is_nat = NULL; } - sofia_reg_handle_register(nua, profile, nh, sip, de, type, key, sizeof(key), &v_event, is_nat); + sofia_reg_handle_register(nua, profile, nh, sip, de, type, key, sizeof(key), &v_event, is_nat, sofia_private_p); if (v_event) { switch_event_destroy(&v_event); } end: - - nua_handle_destroy(nh); + + if (!sofia_private_p || !*sofia_private_p) nua_handle_destroy(nh); }