<p>George Joseph has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/7139">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">AST-2017-011 - res_pjsip_session: session leak when a call is rejected<br><br>A previous commit made it so when an invite session transitioned into a<br>disconnected state destruction of the Asterisk pjsip session object was<br>postponed until either a transport error occurred or the event timer<br>expired. However, if a call was rejected (for instance a 488) before the<br>session was fully established the event timer may not have been initiated,<br>or it was canceled without triggering either of the session finalizing states<br>mentioned above.<br><br>Really the only time destruction of the session should be delayed is when a<br>BYE is being transacted. This is because it's possible in some cases for the<br>session to be disconnected, but the BYE is still transacting.<br><br>This patch makes it so the session object always gets released (no more<br>memory leak) when the pjsip session is in a disconnected state. Except when<br>the method is a BYE. Then it waits until a transport error occurs or an event<br>timeout.<br><br>ASTERISK-27345 #close<br><br>Reported by: Corey Farrell<br><br>Change-Id: I1e724737b758c20ac76d19d3611e3d2876ae10ed<br>---<br>M res/res_pjsip_session.c<br>1 file changed, 42 insertions(+), 38 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/39/7139/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c<br>index 808477c..8ad6d3c 100644<br>--- a/res/res_pjsip_session.c<br>+++ b/res/res_pjsip_session.c<br>@@ -2686,6 +2686,36 @@<br>      /* XXX STUB */<br> }<br> <br>+static int session_end_if_disconnected(int id, pjsip_inv_session *inv)<br>+{<br>+   struct ast_sip_session *session;<br>+<br>+  if (inv->state != PJSIP_INV_STATE_DISCONNECTED) {<br>+         return 0;<br>+    }<br>+<br>+ /*<br>+    * We are locking because ast_sip_dialog_get_session() needs<br>+  * the dialog locked to get the session by other threads.<br>+     */<br>+  pjsip_dlg_inc_lock(inv->dlg);<br>+     session = inv->mod_data[id];<br>+      inv->mod_data[id] = NULL;<br>+ pjsip_dlg_dec_lock(inv->dlg);<br>+<br>+  /*<br>+    * Pass the session ref held by session->inv_session to<br>+    * session_end_completion().<br>+  */<br>+  if (session<br>+          && ast_sip_push_task(session->serializer, session_end_completion, session)) {<br>+             /* Do it anyway even though this is not the right thread. */<br>+         session_end_completion(session);<br>+     }<br>+<br>+ return 1;<br>+}<br>+<br> static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e)<br> {<br>   ast_sip_session_response_cb cb;<br>@@ -2710,6 +2740,17 @@<br>               /* The session has ended.  Ignore the transaction change. */<br>          return;<br>       }<br>+<br>+ /*<br>+    * If the session is disconnected really nothing else to do unless currently transacting<br>+      * a BYE. If a BYE then hold off destruction until the transaction timeout occurs. This<br>+       * has to be done for BYEs because sometimes the dialog can be in a disconnected<br>+      * state but the BYE request transaction has not yet completed.<br>+       */<br>+  if (tsx->method.id != PJSIP_BYE_METHOD && session_end_if_disconnected(id, inv)) {<br>+         return;<br>+      }<br>+<br>  switch (e->body.tsx_state.type) {<br>  case PJSIP_EVENT_TX_MSG:<br>              /* When we create an outgoing request, we do not have access to the transaction that<br>@@ -2832,49 +2873,12 @@<br>                 }<br>             break;<br>        case PJSIP_EVENT_TRANSPORT_ERROR:<br>-            if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {<br>-                 /*<br>-                    * Clear the module data now to block session_inv_on_state_changed()<br>-                  * from calling session_end() if it hasn't already done so.<br>-                       */<br>-                  inv->mod_data[id] = NULL;<br>-<br>-                      /*<br>-                    * Pass the session ref held by session->inv_session to<br>-                    * session_end_completion().<br>-                  */<br>-                  if (session<br>-                          && ast_sip_push_task(session->serializer, session_end_completion, session)) {<br>-                             /* Do it anyway even though this is not the right thread. */<br>-                         session_end_completion(session);<br>-                     }<br>-                    return;<br>-              }<br>-            break;<br>        case PJSIP_EVENT_TIMER:<br>               /*<br>             * The timer event is run by the pjsip monitor thread and not<br>                  * by the session serializer.<br>                  */<br>-          if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {<br>-                 /*<br>-                    * We are locking because ast_sip_dialog_get_session() needs<br>-                  * the dialog locked to get the session by other threads.<br>-                     */<br>-                  pjsip_dlg_inc_lock(inv->dlg);<br>-                     session = inv->mod_data[id];<br>-                      inv->mod_data[id] = NULL;<br>-                 pjsip_dlg_dec_lock(inv->dlg);<br>-<br>-                  /*<br>-                    * Pass the session ref held by session->inv_session to<br>-                    * session_end_completion().<br>-                  */<br>-                  if (session<br>-                          && ast_sip_push_task(session->serializer, session_end_completion, session)) {<br>-                             /* Do it anyway even though this is not the right thread. */<br>-                         session_end_completion(session);<br>-                     }<br>+            if (session_end_if_disconnected(id, inv)) {<br>                   return;<br>               }<br>             break;<br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/7139">change 7139</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/7139"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 14.7 </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: I1e724737b758c20ac76d19d3611e3d2876ae10ed </div>
<div style="display:none"> Gerrit-Change-Number: 7139 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Kevin Harwell <kharwell@digium.com> </div>