]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
unreg on sock disconnect
authorAnthony Minessale <anthm@freeswitch.org>
Sun, 27 Jan 2013 05:16:26 +0000 (23:16 -0600)
committerAnthony Minessale <anthm@freeswitch.org>
Mon, 1 Apr 2013 02:27:22 +0000 (21:27 -0500)
libs/sofia-sip/libsofia-sip-ua/nta/nta.c
libs/sofia-sip/libsofia-sip-ua/nua/check_register.c
libs/sofia-sip/libsofia-sip-ua/nua/nua_registrar.c
src/mod/endpoints/mod_sofia/mod_sofia.h
src/mod/endpoints/mod_sofia/sofia.c
src/mod/endpoints/mod_sofia/sofia_reg.c

index 56a3c59b36c7fd6e47f35003c8d74656960730cd..0ef2dcce7654d43d11dda3ee6577253b0b3f3622 100644 (file)
@@ -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 ",
index 6a3b3356a9813c3548ebceb2a5914bf8bafe0746..2372c9c2fc6b6f30d6c4effccad24ff57417e0f1 100644 (file)
@@ -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("<sip:tst@example.com>"),
+                           SIPTAG_TO_STR("<sip:tst@example.com>"),
+                           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("<sip:tst@example.com>"),
+                           SIPTAG_TO_STR("<sip:tst@example.com>"),
+                           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("<sip:tst@example.com>"),
+                           SIPTAG_TO_STR("<sip:tst@example.com>"),
+                           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));
 }
 
index be58993868bbb434cf162c89a01849b49519e5f4..cb661b1717cc43273218ac227bce329a2da11c05 100644 (file)
@@ -39,6 +39,9 @@
 
 #include <assert.h>
 
+#define TP_CLIENT_T struct nua_handle_s
+#define TP_STACK_T struct nta_agent_s
+
 #include <sofia-sip/su_string.h>
 #include <sofia-sip/sip_protos.h>
 #include <sofia-sip/sip_status.h>
 
 #include "nua_stack.h"
 
+#include <sofia-sip/tport.h>
+#include <sofia-sip/nta_tport.h>
+
+/* ---------------------------------------------------------------------- */
+/* 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 */
 
  * @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);
+}
index bc5765aa0dd1fd7d5cc1e72f04f2a45820d2dd7e..269371b30c6614b9f805375fef6f231e5817eee2 100644 (file)
@@ -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:
index 3c7f45e20a870a0f4ae128a19423d31afe79f8b6..10f0fc61f2bd64d0e4762bce697f1d3f2fb3617b 100644 (file)
@@ -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);
                                }
index b74b979ff1b823402069992872f5aa2ded815b15..5df024328307ae0e01928fbe08f7ec24a9bd4d38 100644 (file)
@@ -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);
 
 }