Merge "res_pjsip_pubsub: Prune subs with reliable transports at startup"
[asterisk/asterisk.git] / res / res_pjsip_registrar.c
index 76d8b04..bdee91f 100644 (file)
@@ -328,6 +328,15 @@ struct contact_transport_monitor {
        char aor_name[0];
 };
 
+static int contact_transport_monitor_matcher(void *a, void *b)
+{
+       struct contact_transport_monitor *ma = a;
+       struct contact_transport_monitor *mb = b;
+
+       return strcmp(ma->aor_name, mb->aor_name) == 0
+               && strcmp(ma->contact_name, mb->contact_name) == 0;
+}
+
 static void register_contact_transport_shutdown_cb(void *data)
 {
        struct contact_transport_monitor *monitor = data;
@@ -579,8 +588,7 @@ static void register_aor_core(pjsip_rx_data *rdata,
 
                contact = ao2_callback(contacts, OBJ_UNLINK, registrar_find_contact, &details);
                if (!contact) {
-                       int prune_on_boot = 0;
-                       pj_str_t host_name;
+                       int prune_on_boot;
 
                        /* If they are actually trying to delete a contact that does not exist... be forgiving */
                        if (!expiration) {
@@ -589,35 +597,7 @@ static void register_aor_core(pjsip_rx_data *rdata,
                                continue;
                        }
 
-                       /* Determine if the contact cannot survive a restart/boot. */
-                       if (details.uri->port == rdata->pkt_info.src_port
-                               && !pj_strcmp(&details.uri->host,
-                                       pj_cstr(&host_name, rdata->pkt_info.src_name))
-                               /* We have already checked if the URI scheme is sip: or sips: */
-                               && PJSIP_TRANSPORT_IS_RELIABLE(rdata->tp_info.transport)) {
-                               pj_str_t type_name;
-
-                               /* Determine the transport parameter value */
-                               if (!strcasecmp("WSS", rdata->tp_info.transport->type_name)) {
-                                       /* WSS is special, as it needs to be ws. */
-                                       pj_cstr(&type_name, "ws");
-                               } else {
-                                       pj_cstr(&type_name, rdata->tp_info.transport->type_name);
-                               }
-
-                               if (!pj_stricmp(&details.uri->transport_param, &type_name)
-                                       && (endpoint->nat.rewrite_contact
-                                               /* Websockets are always rewritten */
-                                               || !pj_stricmp(&details.uri->transport_param,
-                                                       pj_cstr(&type_name, "ws")))) {
-                                       /*
-                                        * The contact was rewritten to the reliable transport's
-                                        * source address.  Disconnecting the transport for any
-                                        * reason invalidates the contact.
-                                        */
-                                       prune_on_boot = 1;
-                               }
-                       }
+                       prune_on_boot = !ast_sip_will_uri_survive_restart(details.uri, endpoint, rdata);
 
                        contact = ast_sip_location_create_contact(aor, contact_uri,
                                ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1)),
@@ -704,6 +684,21 @@ static void register_aor_core(pjsip_rx_data *rdata,
                                        contact_update->user_agent);
                        ao2_cleanup(contact_update);
                } else {
+                       if (contact->prune_on_boot) {
+                               struct contact_transport_monitor *monitor;
+                               const char *contact_name =
+                                       ast_sorcery_object_get_id(contact);
+
+                               monitor = ast_alloca(sizeof(*monitor) + 2 + strlen(aor_name)
+                                       + strlen(contact_name));
+                               strcpy(monitor->aor_name, aor_name);/* Safe */
+                               monitor->contact_name = monitor->aor_name + strlen(aor_name) + 1;
+                               strcpy(monitor->contact_name, contact_name);/* Safe */
+
+                               ast_sip_transport_monitor_unregister(rdata->tp_info.transport,
+                                       register_contact_transport_shutdown_cb, monitor, contact_transport_monitor_matcher);
+                       }
+
                        /* We want to report the user agent that was actually in the removed contact */
                        ast_sip_location_delete_contact(contact);
                        ast_verb(3, "Removed contact '%s' from AOR '%s' due to request\n", contact_uri, aor_name);
@@ -1115,6 +1110,19 @@ static int expire_contact(void *obj, void *arg, int flags)
         */
        ao2_lock(lock);
        if (ast_tvdiff_ms(ast_tvnow(), contact->expiration_time) > 0) {
+               if (contact->prune_on_boot) {
+                       struct contact_transport_monitor *monitor;
+                       const char *contact_name = ast_sorcery_object_get_id(contact);
+
+                       monitor = ast_alloca(sizeof(*monitor) + 2 + strlen(contact->aor)
+                               + strlen(contact_name));
+                       strcpy(monitor->aor_name, contact->aor);/* Safe */
+                       monitor->contact_name = monitor->aor_name + strlen(contact->aor) + 1;
+                       strcpy(monitor->contact_name, contact_name);/* Safe */
+
+                       ast_sip_transport_monitor_unregister_all(register_contact_transport_shutdown_cb,
+                               monitor, contact_transport_monitor_matcher);
+               }
                ast_sip_location_delete_contact(contact);
        }
        ao2_unlock(lock);
@@ -1222,7 +1230,7 @@ static int unload_module(void)
        ast_manager_unregister(AMI_SHOW_REGISTRATIONS);
        ast_manager_unregister(AMI_SHOW_REGISTRATION_CONTACT_STATUSES);
        ast_sip_unregister_service(&registrar_module);
-       ast_sip_transport_monitor_unregister_all(register_contact_transport_shutdown_cb);
+       ast_sip_transport_monitor_unregister_all(register_contact_transport_shutdown_cb, NULL, NULL);
        return 0;
 }