<p>Richard Mudgett has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/6202">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">res_pjsip_outbound_registration.c: Re-REGISTER on transport shutdown.<br><br>The fix for the issue is broken up into three parts.<br><br>This is part three which handles the client side of REGISTER requests.<br>The registered contact may no longer be valid on the server when the<br>transport used is reliable and the connection is broken.<br><br>* Re-REGISTER our contact if the reliable transport is broken after<br>registration completes.  We attempt to re-REGISTER immediately to minimize<br>the time we are unreachable.  Time may have already passed between the<br>connection being broken and the loss being detected.<br><br>* Reorder sip_outbound_registration_state_alloc() so the STATSD_GUAGE's<br>are still correct if an allocation failure happens.<br><br>ASTERISK-27147<br><br>Change-Id: I3668405b1ee75dfefb07c0d637826176f741ce83<br>---<br>M res/res_pjsip_outbound_registration.c<br>1 file changed, 105 insertions(+), 9 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/02/6202/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c<br>index 7b605b9..bbb286a 100644<br>--- a/res/res_pjsip_outbound_registration.c<br>+++ b/res/res_pjsip_outbound_registration.c<br>@@ -358,6 +358,8 @@<br>  unsigned int auth_attempted:1;<br>        /*! \brief The name of the transport to be used for the registration */<br>       char *transport_name;<br>+        /*! \brief The name of the registration sorcery object */<br>+    char *registration_name;<br> };<br> <br> /*! \brief Outbound registration state information (persists for lifetime that registration should exist) */<br>@@ -795,6 +797,82 @@<br>         }<br> }<br> <br>+static int reregister_immediately_cb(void *obj)<br>+{<br>+       struct sip_outbound_registration_state *state = obj;<br>+<br>+      if (state->client_state->status != SIP_REGISTRATION_REGISTERED) {<br>+              ao2_ref(state, -1);<br>+          return 0;<br>+    }<br>+<br>+ if (DEBUG_ATLEAST(1)) {<br>+              pjsip_regc_info info;<br>+<br>+             pjsip_regc_get_info(state->client_state->client, &info);<br>+           ast_log(LOG_DEBUG,<br>+                   "Outbound registration transport to server '%.*s' from client '%.*s' shutdown\n",<br>+                  (int) info.server_uri.slen, info.server_uri.ptr,<br>+                     (int) info.client_uri.slen, info.client_uri.ptr);<br>+    }<br>+<br>+ cancel_registration(state->client_state);<br>+<br>+      ao2_ref(state->client_state, +1);<br>+ handle_client_registration(state->client_state);<br>+<br>+       ao2_ref(state, -1);<br>+  return 0;<br>+}<br>+<br>+/*!<br>+ * \internal<br>+ * \brief The reliable transport we registered using has shutdown.<br>+ * \since 13.18.0<br>+ *<br>+ * \param obj What is needed to initiate a reregister attempt.<br>+ *<br>+ * \return Nothing<br>+ */<br>+static void registration_transport_shutdown_cb(void *obj)<br>+{<br>+ const char *registration_name = obj;<br>+ struct sip_outbound_registration_state *state;<br>+<br>+    state = get_state(registration_name);<br>+        if (!state) {<br>+                /* Registration no longer exists or shutting down. */<br>+                return;<br>+      }<br>+    if (ast_sip_push_task(state->client_state->serializer, reregister_immediately_cb, state)) {<br>+            ao2_ref(state, -1);<br>+  }<br>+}<br>+<br>+static void registration_transport_monitor_setup(pjsip_transport *transport, const char *registration_name)<br>+{<br>+   char *monitor;<br>+<br>+    if (!PJSIP_TRANSPORT_IS_RELIABLE(transport)) {<br>+               return;<br>+      }<br>+    monitor = ao2_alloc_options(strlen(registration_name) + 1, NULL,<br>+             AO2_ALLOC_OPT_LOCK_NOLOCK);<br>+  if (!monitor) {<br>+              return;<br>+      }<br>+    strcpy(monitor, registration_name);/* Safe */<br>+<br>+     /*<br>+    * We'll ignore if the transport has already been shutdown before we<br>+      * register the monitor.  We might get into a message spamming infinite<br>+       * loop of registration, shutdown, reregistration...<br>+  */<br>+  ast_sip_transport_monitor_register(transport, registration_transport_shutdown_cb,<br>+            monitor);<br>+    ao2_ref(monitor, -1);<br>+}<br>+<br> /*! \brief Callback function for handling a response to a registration attempt */<br> static int handle_registration_response(void *data)<br> {<br>@@ -863,9 +941,15 @@<br>                              next_registration_round = 0;<br>                  }<br>                     schedule_registration(response->client_state, next_registration_round);<br>+<br>+                        /* See if we should monitor for transport shutdown */<br>+                        registration_transport_monitor_setup(response->rdata->tp_info.transport,<br>+                               response->client_state->registration_name);<br>             } else {<br>                      ast_debug(1, "Outbound unregistration to '%s' with client '%s' successful\n", server_uri, client_uri);<br>                      update_client_state_status(response->client_state, SIP_REGISTRATION_UNREGISTERED);<br>+                        ast_sip_transport_monitor_unregister(response->rdata->tp_info.transport,<br>+                               registration_transport_shutdown_cb);<br>          }<br>     } else if (response->client_state->destroy) {<br>           /* We need to deal with the pending destruction instead. */<br>@@ -1008,12 +1092,13 @@<br> {<br>      struct sip_outbound_registration_client_state *client_state = obj;<br> <br>-        ast_free(client_state->transport_name);<br>    ast_statsd_log_string("PJSIP.registrations.count", AST_STATSD_GAUGE, "-1", 1.0);<br>  ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "-1", 1.0,<br>             sip_outbound_registration_status_str(client_state->status));<br> <br>    ast_taskprocessor_unreference(client_state->serializer);<br>+  ast_free(client_state->transport_name);<br>+   ast_free(client_state->registration_name);<br> }<br> <br> /*! \brief Allocator function for registration state */<br>@@ -1033,6 +1118,23 @@<br>                return NULL;<br>  }<br> <br>+ state->client_state->status = SIP_REGISTRATION_UNREGISTERED;<br>+   state->client_state->timer.user_data = state->client_state;<br>+ state->client_state->timer.cb = sip_outbound_registration_timer_cb;<br>+    state->client_state->transport_name = ast_strdup(registration->transport);<br>+  state->client_state->registration_name =<br>+               ast_strdup(ast_sorcery_object_get_id(registration));<br>+<br>+      ast_statsd_log_string("PJSIP.registrations.count", AST_STATSD_GAUGE, "+1", 1.0);<br>+ ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "+1", 1.0,<br>+            sip_outbound_registration_status_str(state->client_state->status));<br>+<br>+ if (!state->client_state->transport_name<br>+               || !state->client_state->registration_name) {<br>+          ao2_cleanup(state);<br>+          return NULL;<br>+ }<br>+<br>  /* Create name with seq number appended. */<br>   ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/outreg/%s",<br>                 ast_sorcery_object_get_id(registration));<br>@@ -1043,14 +1145,6 @@<br>             ao2_cleanup(state);<br>           return NULL;<br>  }<br>-    state->client_state->status = SIP_REGISTRATION_UNREGISTERED;<br>-   state->client_state->timer.user_data = state->client_state;<br>- state->client_state->timer.cb = sip_outbound_registration_timer_cb;<br>-    state->client_state->transport_name = ast_strdup(registration->transport);<br>-<br>-       ast_statsd_log_string("PJSIP.registrations.count", AST_STATSD_GAUGE, "+1", 1.0);<br>- ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "+1", 1.0,<br>-            sip_outbound_registration_status_str(state->client_state->status));<br> <br>  state->registration = ao2_bump(registration);<br>      return state;<br>@@ -2054,6 +2148,8 @@<br> <br>       ao2_global_obj_release(current_states);<br> <br>+   ast_sip_transport_monitor_unregister_all(registration_transport_shutdown_cb);<br>+<br>      /* Wait for registration serializers to get destroyed. */<br>     ast_debug(2, "Waiting for registration transactions to complete for unload.\n");<br>    remaining = ast_serializer_shutdown_group_join(shutdown_group, MAX_UNLOAD_TIMEOUT_TIME);<br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/6202">change 6202</a>. To unsubscribe, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/6202"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 15 </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: I3668405b1ee75dfefb07c0d637826176f741ce83 </div>
<div style="display:none"> Gerrit-Change-Number: 6202 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Richard Mudgett <rmudgett@digium.com> </div>