<p>Richard Mudgett has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/6200">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">res_pjsip: PJSIP Transport state monitor refactor.<br><br>The fix for the issue is broken up into three parts.<br><br>This is part one which refactors the transport state monitor code to allow<br>more modules to be able to monitor transports.<br><br>* Pull the management of PJPROJECT's transport state callback code from<br>res_pjsip_transport_management.c into res_pjsip.  Now other modules can<br>dynamically add and remove themselves from transport monitoring without<br>worrying about breaking PJPROJECT's callback chain.<br><br>* Add the ability for other modules to get a callback whenever a specific<br>transport is shutdown.<br><br>ASTERISK-27147<br><br>Change-Id: I7d9a31371eb1487c9b7050cf82a9af5180a57912<br>---<br>M include/asterisk/res_pjsip.h<br>M res/res_pjsip.c<br>M res/res_pjsip/include/res_pjsip_private.h<br>A res/res_pjsip/pjsip_transport_events.c<br>M res/res_pjsip_transport_management.c<br>5 files changed, 493 insertions(+), 30 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/00/6200/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h<br>index 890ce59..31db367 100644<br>--- a/include/asterisk/res_pjsip.h<br>+++ b/include/asterisk/res_pjsip.h<br>@@ -2926,4 +2926,91 @@<br>  */<br> int ast_sip_str_to_dtmf(const char *dtmf_mode);<br> <br>+/*!<br>+ * \brief Transport shutdown monitor callback.<br>+ * \since 13.18.0<br>+ *<br>+ * \param data User data to know what to do when transport shuts down.<br>+ *<br>+ * \note The callback does not need to care that data is an ao2 object.<br>+ *<br>+ * \return Nothing<br>+ */<br>+typedef void (*ast_transport_monitor_shutdown_cb)(void *data);<br>+<br>+enum ast_transport_monitor_reg {<br>+  /*! \brief Successfully registered the transport monitor */<br>+  AST_TRANSPORT_MONITOR_REG_SUCCESS,<br>+   /*! \brief Replaced the already existing transport monitor with new one. */<br>+  AST_TRANSPORT_MONITOR_REG_REPLACED,<br>+  /*!<br>+   * \brief Transport not found to monitor.<br>+     * \note Transport is either already shutdown or is not reliable.<br>+     */<br>+  AST_TRANSPORT_MONITOR_REG_NOT_FOUND,<br>+ /*! \brief Error while registering transport monitor. */<br>+     AST_TRANSPORT_MONITOR_REG_FAILED,<br>+};<br>+<br>+/*!<br>+ * \brief Register a reliable transport shutdown monitor callback.<br>+ * \since 13.18.0<br>+ *<br>+ * \param transport Transport to monitor for shutdown.<br>+ * \param cb Who to call when transport is shutdown.<br>+ * \param ao2_data Data to pass with the callback.<br>+ *<br>+ * \return enum ast_transport_monitor_reg<br>+ */<br>+enum ast_transport_monitor_reg ast_sip_transport_monitor_register(pjsip_transport *transport,<br>+    ast_transport_monitor_shutdown_cb cb, void *ao2_data);<br>+<br>+/*!<br>+ * \brief Unregister a reliable transport shutdown monitor callback.<br>+ * \since 13.18.0<br>+ *<br>+ * \param transport Transport to monitor for shutdown.<br>+ * \param cb Who to call when transport is shutdown.<br>+ *<br>+ * \return Nothing<br>+ */<br>+void ast_sip_transport_monitor_unregister(pjsip_transport *transport, ast_transport_monitor_shutdown_cb cb);<br>+<br>+/*!<br>+ * \brief Unregister monitor callback from all reliable transports.<br>+ * \since 13.18.0<br>+ *<br>+ * \param cb Who to call when a transport is shutdown.<br>+ *<br>+ * \return Nothing<br>+ */<br>+void ast_sip_transport_monitor_unregister_all(ast_transport_monitor_shutdown_cb cb);<br>+<br>+/*! Transport state notification registration element.  */<br>+struct ast_sip_tpmgr_state_callback {<br>+       /*! PJPROJECT transport state notification callback */<br>+       pjsip_tp_state_callback cb;<br>+  AST_LIST_ENTRY(ast_sip_tpmgr_state_callback) node;<br>+};<br>+<br>+/*!<br>+ * \brief Register a transport state notification callback element.<br>+ * \since 13.18.0<br>+ *<br>+ * \param element What we are registering.<br>+ *<br>+ * \return Nothing<br>+ */<br>+void ast_sip_transport_state_register(struct ast_sip_tpmgr_state_callback *element);<br>+<br>+/*!<br>+ * \brief Unregister a transport state notification callback element.<br>+ * \since 13.18.0<br>+ *<br>+ * \param element What we are unregistering.<br>+ *<br>+ * \return Nothing<br>+ */<br>+void ast_sip_transport_state_unregister(struct ast_sip_tpmgr_state_callback *element);<br>+<br> #endif /* _RES_PJSIP_H */<br>diff --git a/res/res_pjsip.c b/res/res_pjsip.c<br>index f3648ac..2917df3 100644<br>--- a/res/res_pjsip.c<br>+++ b/res/res_pjsip.c<br>@@ -4662,6 +4662,7 @@<br>              ast_sip_destroy_system();<br>             ast_sip_destroy_global_headers();<br>             internal_sip_unregister_service(&supplement_module);<br>+             ast_sip_destroy_transport_events();<br>   }<br> <br>  if (monitor_thread) {<br>@@ -4740,7 +4741,6 @@<br>  return AST_MODULE_LOAD_SUCCESS;<br> <br> error:<br>-  unload_pjsip(NULL);<br>   return AST_MODULE_LOAD_DECLINE;<br> }<br> <br>@@ -4806,6 +4806,11 @@<br>                goto error;<br>   }<br> <br>+ if (ast_sip_initialize_transport_events()) {<br>+         ast_log(LOG_ERROR, "Failed to initialize SIP transport monitor. Aborting load\n");<br>+         goto error;<br>+  }<br>+<br>  ast_sip_initialize_dns();<br> <br>  ast_sip_initialize_global_headers();<br>diff --git a/res/res_pjsip/include/res_pjsip_private.h b/res/res_pjsip/include/res_pjsip_private.h<br>index 0bdb633..2969f0e 100644<br>--- a/res/res_pjsip/include/res_pjsip_private.h<br>+++ b/res/res_pjsip/include/res_pjsip_private.h<br>@@ -135,6 +135,29 @@<br> <br> /*!<br>  * \internal<br>+ * \brief Initialize the transport events notify module<br>+ * \since 13.18.0<br>+ *<br>+ * The transport events notify module is responsible for monitoring<br>+ * when transports die and calling any registered callbacks when that<br>+ * happens.  It also manages any PJPROJECT transport state callbacks<br>+ * registered to it so the callbacks be more dynamic allowing module<br>+ * loading/unloading.<br>+ *<br>+ * \retval -1 Failure<br>+ * \retval 0 Success<br>+ */<br>+int ast_sip_initialize_transport_events(void);<br>+<br>+/*!<br>+ * \internal<br>+ * \brief Destruct the transport events notify module.<br>+ * \since 13.18.0<br>+ */<br>+void ast_sip_destroy_transport_events(void);<br>+<br>+/*!<br>+ * \internal<br>  * \brief Initialize global type on a sorcery instance<br>  *<br>  * \retval -1 failure<br>diff --git a/res/res_pjsip/pjsip_transport_events.c b/res/res_pjsip/pjsip_transport_events.c<br>new file mode 100644<br>index 0000000..0f57303<br>--- /dev/null<br>+++ b/res/res_pjsip/pjsip_transport_events.c<br>@@ -0,0 +1,366 @@<br>+/*<br>+ * Asterisk -- An open source telephony toolkit.<br>+ *<br>+ * Copyright (C) 2017, Digium Inc.<br>+ *<br>+ * Richard Mudgett <rmudgett@digium.com><br>+ *<br>+ * See http://www.asterisk.org for more information about<br>+ * the Asterisk project. Please do not directly contact<br>+ * any of the maintainers of this project for assistance;<br>+ * the project provides a web site, mailing lists and IRC<br>+ * channels for your use.<br>+ *<br>+ * This program is free software, distributed under the terms of<br>+ * the GNU General Public License Version 2. See the LICENSE file<br>+ * at the top of the source tree.<br>+ */<br>+<br>+/*!<br>+ * \file<br>+ * \brief Manages the global transport event notification callbacks.<br>+ *<br>+ * \author Richard Mudgett <rmudgett@digium.com><br>+ *        See Also:<br>+ *<br>+ * \arg \ref AstCREDITS<br>+ */<br>+<br>+<br>+#include "asterisk.h"<br>+<br>+#include "asterisk/res_pjsip.h"<br>+#include "include/res_pjsip_private.h"<br>+#include "asterisk/linkedlists.h"<br>+#include "asterisk/vector.h"<br>+<br>+/* ------------------------------------------------------------------- */<br>+<br>+/*! \brief Number of buckets for monitored active transports */<br>+#define ACTIVE_TRANSPORTS_BUCKETS 127<br>+<br>+/*! Who to notify when transport shuts down. */<br>+struct transport_monitor_notifier {<br>+       /*! Who to call when transport shuts down. */<br>+        ast_transport_monitor_shutdown_cb cb;<br>+        /*! ao2 data object to pass to callback. */<br>+  void *data;<br>+};<br>+<br>+/*! \brief Structure for transport to be monitored */<br>+struct transport_monitor {<br>+     /*! \brief The underlying PJSIP transport */<br>+ pjsip_transport *transport;<br>+  /*! Who is interested in when this transport shuts down. */<br>+  AST_VECTOR(, struct transport_monitor_notifier) monitors;<br>+};<br>+<br>+/*! \brief Global container of active reliable transports */<br>+static AO2_GLOBAL_OBJ_STATIC(active_transports);<br>+<br>+/*! \brief Existing transport events callback that we need to invoke */<br>+static pjsip_tp_state_callback tpmgr_state_callback;<br>+<br>+/*! List of registered transport state callbacks. */<br>+static AST_RWLIST_HEAD(, ast_sip_tpmgr_state_callback) transport_state_list;<br>+<br>+<br>+/*! \brief Hashing function for struct transport_monitor */<br>+AO2_STRING_FIELD_HASH_FN(transport_monitor, transport->obj_name);<br>+<br>+/*! \brief Comparison function for struct transport_monitor */<br>+AO2_STRING_FIELD_CMP_FN(transport_monitor, transport->obj_name);<br>+<br>+static const char *transport_state2str(pjsip_transport_state state)<br>+{<br>+   const char *name;<br>+<br>+ switch (state) {<br>+     case PJSIP_TP_STATE_CONNECTED:<br>+               name = "CONNECTED";<br>+                break;<br>+       case PJSIP_TP_STATE_DISCONNECTED:<br>+            name = "DISCONNECTED";<br>+             break;<br>+       case PJSIP_TP_STATE_SHUTDOWN:<br>+                name = "SHUTDOWN";<br>+         break;<br>+       case PJSIP_TP_STATE_DESTROY:<br>+         name = "DESTROY";<br>+          break;<br>+       default:<br>+             /*<br>+            * We have to have a default case because the enum is<br>+                 * defined by a third-party library.<br>+          */<br>+          ast_assert(0);<br>+               name = "<unknown>";<br>+          break;<br>+       }<br>+    return name;<br>+}<br>+<br>+static void transport_monitor_dtor(void *vdoomed)<br>+{<br>+  struct transport_monitor *monitored = vdoomed;<br>+       int idx;<br>+<br>+  for (idx = AST_VECTOR_SIZE(&monitored->monitors); idx--;) {<br>+           struct transport_monitor_notifier *notifier;<br>+<br>+              notifier = AST_VECTOR_GET_ADDR(&monitored->monitors, idx);<br>+            ao2_cleanup(notifier->data);<br>+      }<br>+    AST_VECTOR_FREE(&monitored->monitors);<br>+}<br>+<br>+/*! \brief Callback invoked when transport state changes occur */<br>+static void transport_state_callback(pjsip_transport *transport,<br>+  pjsip_transport_state state, const pjsip_transport_state_info *info)<br>+{<br>+     struct ao2_container *transports;<br>+<br>+ /* We only care about monitoring reliable transports */<br>+      if (PJSIP_TRANSPORT_IS_RELIABLE(transport)<br>+           && (transports = ao2_global_obj_ref(active_transports))) {<br>+           struct transport_monitor *monitored;<br>+<br>+              ast_debug(3, "Reliable transport '%s' state:%s\n",<br>+                 transport->obj_name, transport_state2str(state));<br>+         switch (state) {<br>+             case PJSIP_TP_STATE_CONNECTED:<br>+                       monitored = ao2_alloc_options(sizeof(*monitored),<br>+                            transport_monitor_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK);<br>+                  if (!monitored) {<br>+                            break;<br>+                       }<br>+                    monitored->transport = transport;<br>+                 if (AST_VECTOR_INIT(&monitored->monitors, 2)) {<br>+                               ao2_ref(monitored, -1);<br>+                              break;<br>+                       }<br>+<br>+                 ao2_link(transports, monitored);<br>+                     ao2_ref(monitored, -1);<br>+                      break;<br>+               case PJSIP_TP_STATE_DISCONNECTED:<br>+                    if (!transport->is_shutdown) {<br>+                            pjsip_transport_shutdown(transport);<br>+                 }<br>+                    break;<br>+               case PJSIP_TP_STATE_SHUTDOWN:<br>+                        /*<br>+                    * Set shutdown flag early so we can force a new transport to be<br>+                      * created if a monitor callback needs to reestablish a link.<br>+                         * PJPROJECT sets the flag after this routine returns even though<br>+                     * it has already called the transport's shutdown routine.<br>+                        */<br>+                  transport->is_shutdown = PJ_TRUE;<br>+<br>+                      monitored = ao2_find(transports, transport->obj_name,<br>+                             OBJ_SEARCH_KEY | OBJ_UNLINK);<br>+                        if (monitored) {<br>+                             int idx;<br>+<br>+                          for (idx = AST_VECTOR_SIZE(&monitored->monitors); idx--;) {<br>+                                   struct transport_monitor_notifier *notifier;<br>+<br>+                                      notifier = AST_VECTOR_GET_ADDR(&monitored->monitors, idx);<br>+                                    notifier->cb(notifier->data);<br>+                          }<br>+                            ao2_ref(monitored, -1);<br>+                      }<br>+                    break;<br>+               default:<br>+                     break;<br>+               }<br>+<br>+         ao2_ref(transports, -1);<br>+     }<br>+<br>+ /* Loop over other transport state callbacks registered with us. */<br>+  if (!AST_LIST_EMPTY(&transport_state_list)) {<br>+            struct ast_sip_tpmgr_state_callback *tpmgr_notifier;<br>+<br>+              AST_RWLIST_RDLOCK(&transport_state_list);<br>+                AST_LIST_TRAVERSE(&transport_state_list, tpmgr_notifier, node) {<br>+                 tpmgr_notifier->cb(transport, state, info);<br>+               }<br>+            AST_RWLIST_UNLOCK(&transport_state_list);<br>+        }<br>+<br>+ /* Forward to the old state callback if present */<br>+   if (tpmgr_state_callback) {<br>+          tpmgr_state_callback(transport, state, info);<br>+        }<br>+}<br>+<br>+static int transport_monitor_unregister_all(void *obj, void *arg, int flags)<br>+{<br>+  struct transport_monitor *monitored = obj;<br>+   ast_transport_monitor_shutdown_cb cb = arg;<br>+  int idx;<br>+<br>+  for (idx = AST_VECTOR_SIZE(&monitored->monitors); idx--;) {<br>+           struct transport_monitor_notifier *notifier;<br>+<br>+              notifier = AST_VECTOR_GET_ADDR(&monitored->monitors, idx);<br>+            if (notifier->cb == cb) {<br>+                 ao2_cleanup(notifier->data);<br>+                      AST_VECTOR_REMOVE_UNORDERED(&monitored->monitors, idx);<br>+                       break;<br>+               }<br>+    }<br>+    return 0;<br>+}<br>+<br>+void ast_sip_transport_monitor_unregister_all(ast_transport_monitor_shutdown_cb cb)<br>+{<br>+   struct ao2_container *transports;<br>+<br>+ transports = ao2_global_obj_ref(active_transports);<br>+  if (!transports) {<br>+           return;<br>+      }<br>+    ao2_callback(transports, OBJ_MULTIPLE | OBJ_NODATA, transport_monitor_unregister_all,<br>+                cb);<br>+ ao2_ref(transports, -1);<br>+}<br>+<br>+void ast_sip_transport_monitor_unregister(pjsip_transport *transport, ast_transport_monitor_shutdown_cb cb)<br>+{<br>+    struct ao2_container *transports;<br>+    struct transport_monitor *monitored;<br>+<br>+      transports = ao2_global_obj_ref(active_transports);<br>+  if (!transports) {<br>+           return;<br>+      }<br>+<br>+ ao2_lock(transports);<br>+        monitored = ao2_find(transports, transport->obj_name, OBJ_SEARCH_KEY | OBJ_NOLOCK);<br>+       if (monitored) {<br>+             int idx;<br>+<br>+          for (idx = AST_VECTOR_SIZE(&monitored->monitors); idx--;) {<br>+                   struct transport_monitor_notifier *notifier;<br>+<br>+                      notifier = AST_VECTOR_GET_ADDR(&monitored->monitors, idx);<br>+                    if (notifier->cb == cb) {<br>+                         ao2_cleanup(notifier->data);<br>+                              AST_VECTOR_REMOVE_UNORDERED(&monitored->monitors, idx);<br>+                               break;<br>+                       }<br>+            }<br>+            ao2_ref(monitored, -1);<br>+      }<br>+    ao2_unlock(transports);<br>+      ao2_ref(transports, -1);<br>+}<br>+<br>+enum ast_transport_monitor_reg ast_sip_transport_monitor_register(pjsip_transport *transport,<br>+      ast_transport_monitor_shutdown_cb cb, void *ao2_data)<br>+{<br>+    struct ao2_container *transports;<br>+    struct transport_monitor *monitored;<br>+ enum ast_transport_monitor_reg res = AST_TRANSPORT_MONITOR_REG_NOT_FOUND;<br>+<br>+ transports = ao2_global_obj_ref(active_transports);<br>+  if (!transports) {<br>+           return res;<br>+  }<br>+<br>+ ao2_lock(transports);<br>+        monitored = ao2_find(transports, transport->obj_name, OBJ_SEARCH_KEY | OBJ_NOLOCK);<br>+       if (monitored) {<br>+             int idx;<br>+             struct transport_monitor_notifier new_monitor;<br>+<br>+            /* Check if the callback monitor already exists */<br>+           for (idx = AST_VECTOR_SIZE(&monitored->monitors); idx--;) {<br>+                   struct transport_monitor_notifier *notifier;<br>+<br>+                      notifier = AST_VECTOR_GET_ADDR(&monitored->monitors, idx);<br>+                    if (notifier->cb == cb) {<br>+                         /* The monitor is already in the vector replace with new ao2_data. */<br>+                                ao2_replace(notifier->data, ao2_data);<br>+                            res = AST_TRANSPORT_MONITOR_REG_REPLACED;<br>+                            goto register_done;<br>+                  }<br>+            }<br>+<br>+         /* Add new monitor to vector */<br>+              new_monitor.cb = cb;<br>+         new_monitor.data = ao2_bump(ao2_data);<br>+               if (AST_VECTOR_APPEND(&monitored->monitors, new_monitor)) {<br>+                   ao2_cleanup(ao2_data);<br>+                       res = AST_TRANSPORT_MONITOR_REG_FAILED;<br>+              }<br>+<br>+register_done:<br>+                ao2_ref(monitored, -1);<br>+      }<br>+    ao2_unlock(transports);<br>+      ao2_ref(transports, -1);<br>+     return res;<br>+}<br>+<br>+void ast_sip_transport_state_unregister(struct ast_sip_tpmgr_state_callback *element)<br>+{<br>+       AST_RWLIST_WRLOCK(&transport_state_list);<br>+        AST_LIST_REMOVE(&transport_state_list, element, node);<br>+   AST_RWLIST_UNLOCK(&transport_state_list);<br>+}<br>+<br>+void ast_sip_transport_state_register(struct ast_sip_tpmgr_state_callback *element)<br>+{<br>+       struct ast_sip_tpmgr_state_callback *tpmgr_notifier;<br>+<br>+      AST_RWLIST_WRLOCK(&transport_state_list);<br>+        AST_LIST_TRAVERSE(&transport_state_list, tpmgr_notifier, node) {<br>+         if (element == tpmgr_notifier) {<br>+                     /* Already registered. */<br>+                    AST_RWLIST_UNLOCK(&transport_state_list);<br>+                        return;<br>+              }<br>+    }<br>+    AST_LIST_INSERT_HEAD(&transport_state_list, element, node);<br>+      AST_RWLIST_UNLOCK(&transport_state_list);<br>+}<br>+<br>+void ast_sip_destroy_transport_events(void)<br>+{<br>+       pjsip_tpmgr *tpmgr;<br>+<br>+       tpmgr = pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint());<br>+ if (tpmgr) {<br>+         pjsip_tpmgr_set_state_cb(tpmgr, tpmgr_state_callback);<br>+       }<br>+<br>+ ao2_global_obj_release(active_transports);<br>+}<br>+<br>+int ast_sip_initialize_transport_events(void)<br>+{<br>+        pjsip_tpmgr *tpmgr;<br>+  struct ao2_container *transports;<br>+<br>+ tpmgr = pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint());<br>+ if (!tpmgr) {<br>+                return -1;<br>+   }<br>+<br>+ transports = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,<br>+           ACTIVE_TRANSPORTS_BUCKETS, transport_monitor_hash_fn, NULL,<br>+          transport_monitor_cmp_fn);<br>+   if (!transports) {<br>+           return -1;<br>+   }<br>+    ao2_global_obj_replace_unref(active_transports, transports);<br>+ ao2_ref(transports, -1);<br>+<br>+  tpmgr_state_callback = pjsip_tpmgr_get_state_cb(tpmgr);<br>+      pjsip_tpmgr_set_state_cb(tpmgr, &transport_state_callback);<br>+<br>+   return 0;<br>+}<br>diff --git a/res/res_pjsip_transport_management.c b/res/res_pjsip_transport_management.c<br>index 86c53ca..eb92eb7 100644<br>--- a/res/res_pjsip_transport_management.c<br>+++ b/res/res_pjsip_transport_management.c<br>@@ -34,7 +34,7 @@<br> #include "asterisk/astobj2.h"<br> <br> /*! \brief Number of buckets for monitored transports */<br>-#define TRANSPORTS_BUCKETS 53<br>+#define TRANSPORTS_BUCKETS 127<br> <br> #define IDLE_TIMEOUT (pjsip_cfg()->tsx.td)<br> <br>@@ -52,9 +52,6 @@<br> <br> /*! \brief The global interval at which to send keepalives */<br> static unsigned int keepalive_interval;<br>-<br>-/*! \brief Existing transport manager callback that we need to invoke */<br>-static pjsip_tp_state_callback tpmgr_state_callback;<br> <br> /*! \brief Structure for transport to be monitored */<br> struct monitored_transport {<br>@@ -178,14 +175,13 @@<br>                                /* Let the scheduler inherit the reference from allocation */<br>                                 if (ast_sched_add_variable(sched, IDLE_TIMEOUT, idle_sched_cb, monitored, 1) < 0) {<br>                                        /* Uh Oh.  Could not schedule the idle check.  Kill the transport. */<br>-                                        ao2_unlink(transports, monitored);<br>-                                   ao2_ref(monitored, -1);<br>                                       pjsip_transport_shutdown(transport);<br>+                         } else {<br>+                                     /* monitored ref successfully passed to idle_sched_cb() */<br>+                                   break;<br>                                }<br>-                    } else {<br>-                             /* No scheduled task, so get rid of the allocation reference */<br>-                              ao2_ref(monitored, -1);<br>                       }<br>+                    ao2_ref(monitored, -1);<br>                       break;<br>                case PJSIP_TP_STATE_SHUTDOWN:<br>                 case PJSIP_TP_STATE_DISCONNECTED:<br>@@ -197,12 +193,11 @@<br> <br>           ao2_ref(transports, -1);<br>      }<br>-<br>- /* Forward to the old state callback if present */<br>-   if (tpmgr_state_callback) {<br>-          tpmgr_state_callback(transport, state, info);<br>-        }<br> }<br>+<br>+struct ast_sip_tpmgr_state_callback monitored_transport_reg = {<br>+   monitored_transport_state_callback,<br>+};<br> <br> /*! \brief Hashing function for monitored transport */<br> static int monitored_transport_hash_fn(const void *obj, int flags)<br>@@ -327,15 +322,8 @@<br> static int load_module(void)<br> {<br>    struct ao2_container *transports;<br>-    pjsip_tpmgr *tpmgr;<br> <br>        CHECK_PJSIP_MODULE_LOADED();<br>-<br>-      tpmgr = pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint());<br>- if (!tpmgr) {<br>-                ast_log(LOG_ERROR, "No transport manager to attach keepalive functionality to.\n");<br>-                return AST_MODULE_LOAD_DECLINE;<br>-      }<br> <br>  transports = ao2_container_alloc(TRANSPORTS_BUCKETS, monitored_transport_hash_fn,<br>             monitored_transport_cmp_fn);<br>@@ -363,8 +351,7 @@<br> <br>  ast_sip_register_service(&idle_monitor_module);<br> <br>-       tpmgr_state_callback = pjsip_tpmgr_get_state_cb(tpmgr);<br>-      pjsip_tpmgr_set_state_cb(tpmgr, &monitored_transport_state_callback);<br>+    ast_sip_transport_state_register(&monitored_transport_reg);<br> <br>    ast_sorcery_observer_add(ast_sip_get_sorcery(), "global", &keepalive_global_observer);<br>  ast_sorcery_reload_object(ast_sip_get_sorcery(), "global");<br>@@ -375,8 +362,6 @@<br> <br> static int unload_module(void)<br> {<br>-   pjsip_tpmgr *tpmgr;<br>-<br>        if (keepalive_interval) {<br>             keepalive_interval = 0;<br>               if (keepalive_thread != AST_PTHREADT_NULL) {<br>@@ -388,10 +373,7 @@<br> <br>         ast_sorcery_observer_remove(ast_sip_get_sorcery(), "global", &keepalive_global_observer);<br> <br>-   tpmgr = pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint());<br>- if (tpmgr) {<br>-         pjsip_tpmgr_set_state_cb(tpmgr, tpmgr_state_callback);<br>-       }<br>+    ast_sip_transport_state_unregister(&monitored_transport_reg);<br> <br>  ast_sip_unregister_service(&idle_monitor_module);<br> <br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/6200">change 6200</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/6200"/><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: I7d9a31371eb1487c9b7050cf82a9af5180a57912 </div>
<div style="display:none"> Gerrit-Change-Number: 6200 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Richard Mudgett <rmudgett@digium.com> </div>