diff --git a/configure b/configure
index 3e5140ddb63766a0375dc52f7adc6ab176f5eef1..886ef6f9fa3fa4a8e876d629a272e9002329e018 100755
--- a/configure
+++ b/configure
@@ -935,6 +935,10 @@ PBX_POPT
 POPT_DIR
 POPT_INCLUDE
 POPT_LIB
+PBX_PJSIP_INV_SESSION_REF
+PJSIP_INV_SESSION_REF_DIR
+PJSIP_INV_SESSION_REF_INCLUDE
+PJSIP_INV_SESSION_REF_LIB
 PBX_PJSIP_EVSUB_GRP_LOCK
 PJSIP_EVSUB_GRP_LOCK_DIR
 PJSIP_EVSUB_GRP_LOCK_INCLUDE
@@ -11001,6 +11005,18 @@ PBX_PJSIP_EVSUB_GRP_LOCK=0
 
 
 
+PJSIP_INV_SESSION_REF_DESCRIP="PJSIP INVITE Session Reference Count support"
+PJSIP_INV_SESSION_REF_OPTION=pjsip
+PJSIP_INV_SESSION_REF_DIR=${PJPROJECT_DIR}
+
+PBX_PJSIP_INV_SESSION_REF=0
+
+
+
+
+
+
+
 
     POPT_DESCRIP="popt"
     POPT_OPTION="popt"
@@ -25269,6 +25285,9 @@ $as_echo "#define HAVE_PJSIP_TLS_TRANSPORT_PROTO 1" >>confdefs.h
 $as_echo "#define HAVE_PJSIP_EVSUB_GRP_LOCK 1" >>confdefs.h
 
 
+$as_echo "#define HAVE_PJSIP_INV_SESSION_REF 1" >>confdefs.h
+
+
    else
 
    if test "x${PBX_PJPROJECT}" != "x1" -a "${USE_PJPROJECT}" != "no"; then
@@ -26089,6 +26108,110 @@ _ACEOF
 fi
 
 
+
+if test "x${PBX_PJSIP_INV_SESSION_REF}" != "x1" -a "${USE_PJSIP_INV_SESSION_REF}" != "no"; then
+   pbxlibdir=""
+   # if --with-PJSIP_INV_SESSION_REF=DIR has been specified, use it.
+   if test "x${PJSIP_INV_SESSION_REF_DIR}" != "x"; then
+      if test -d ${PJSIP_INV_SESSION_REF_DIR}/lib; then
+         pbxlibdir="-L${PJSIP_INV_SESSION_REF_DIR}/lib"
+      else
+         pbxlibdir="-L${PJSIP_INV_SESSION_REF_DIR}"
+      fi
+   fi
+   pbxfuncname="pjsip_inv_add_ref"
+   if test "x${pbxfuncname}" = "x" ; then   # empty lib, assume only headers
+      AST_PJSIP_INV_SESSION_REF_FOUND=yes
+   else
+      ast_ext_lib_check_save_CFLAGS="${CFLAGS}"
+      CFLAGS="${CFLAGS} $PJPROJECT_CFLAGS"
+      as_ac_Lib=`$as_echo "ac_cv_lib_pjsip_${pbxfuncname}" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpjsip" >&5
+$as_echo_n "checking for ${pbxfuncname} in -lpjsip... " >&6; }
+if eval \${$as_ac_Lib+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpjsip ${pbxlibdir} $PJPROJECT_LIB $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char ${pbxfuncname} ();
+int
+main ()
+{
+return ${pbxfuncname} ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  eval "$as_ac_Lib=yes"
+else
+  eval "$as_ac_Lib=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+eval ac_res=\$$as_ac_Lib
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+  AST_PJSIP_INV_SESSION_REF_FOUND=yes
+else
+  AST_PJSIP_INV_SESSION_REF_FOUND=no
+fi
+
+      CFLAGS="${ast_ext_lib_check_save_CFLAGS}"
+   fi
+
+   # now check for the header.
+   if test "${AST_PJSIP_INV_SESSION_REF_FOUND}" = "yes"; then
+      PJSIP_INV_SESSION_REF_LIB="${pbxlibdir} -lpjsip $PJPROJECT_LIB"
+      # if --with-PJSIP_INV_SESSION_REF=DIR has been specified, use it.
+      if test "x${PJSIP_INV_SESSION_REF_DIR}" != "x"; then
+         PJSIP_INV_SESSION_REF_INCLUDE="-I${PJSIP_INV_SESSION_REF_DIR}/include"
+      fi
+      PJSIP_INV_SESSION_REF_INCLUDE="${PJSIP_INV_SESSION_REF_INCLUDE} $PJPROJECT_CFLAGS"
+      if test "xpjsip.h" = "x" ; then	# no header, assume found
+         PJSIP_INV_SESSION_REF_HEADER_FOUND="1"
+      else				# check for the header
+         ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
+         CPPFLAGS="${CPPFLAGS} ${PJSIP_INV_SESSION_REF_INCLUDE}"
+         ac_fn_c_check_header_mongrel "$LINENO" "pjsip.h" "ac_cv_header_pjsip_h" "$ac_includes_default"
+if test "x$ac_cv_header_pjsip_h" = xyes; then :
+  PJSIP_INV_SESSION_REF_HEADER_FOUND=1
+else
+  PJSIP_INV_SESSION_REF_HEADER_FOUND=0
+fi
+
+
+         CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}"
+      fi
+      if test "x${PJSIP_INV_SESSION_REF_HEADER_FOUND}" = "x0" ; then
+         PJSIP_INV_SESSION_REF_LIB=""
+         PJSIP_INV_SESSION_REF_INCLUDE=""
+      else
+         if test "x${pbxfuncname}" = "x" ; then		# only checking headers -> no library
+            PJSIP_INV_SESSION_REF_LIB=""
+         fi
+         PBX_PJSIP_INV_SESSION_REF=1
+         cat >>confdefs.h <<_ACEOF
+#define HAVE_PJSIP_INV_SESSION_REF 1
+_ACEOF
+
+      fi
+   fi
+fi
+
+
    fi
 fi
 
diff --git a/configure.ac b/configure.ac
index 950cfc5a13776692d7f55cc891b1c4cf94f99259..7fd702fee5786ca480542de0018f379bb8c35c88 100644
--- a/configure.ac
+++ b/configure.ac
@@ -487,6 +487,7 @@ AST_EXT_LIB_SETUP_OPTIONAL([PJ_SSL_CERT_LOAD_FROM_FILES2], [pj_ssl_cert_load_fro
 AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_EXTERNAL_RESOLVER], [PJSIP External Resolver Support], [PJPROJECT], [pjsip])
 AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_TLS_TRANSPORT_PROTO], [PJSIP TLS Transport proto field support], [PJPROJECT], [pjsip])
 AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_EVSUB_GRP_LOCK], [PJSIP EVSUB Group Lock support], [PJPROJECT], [pjsip])
+AST_EXT_LIB_SETUP_OPTIONAL([PJSIP_INV_SESSION_REF], [PJSIP INVITE Session Reference Count support], [PJPROJECT], [pjsip])
 
 AST_EXT_LIB_SETUP([POPT], [popt], [popt])
 AST_EXT_LIB_SETUP([PORTAUDIO], [PortAudio], [portaudio])
@@ -2210,6 +2211,7 @@ if test "$USE_PJPROJECT" != "no" ; then
       CPPFLAGS="${saved_cppflags}"
 
       AST_EXT_LIB_CHECK([PJSIP_EVSUB_GRP_LOCK], [pjsip], [pjsip_evsub_add_ref], [pjsip.h], [$PJPROJECT_LIB], [$PJPROJECT_CFLAGS])
+      AST_EXT_LIB_CHECK([PJSIP_INV_SESSION_REF], [pjsip], [pjsip_inv_add_ref], [pjsip.h], [$PJPROJECT_LIB], [$PJPROJECT_CFLAGS])
    fi
 fi
 
diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in
index f9a6b46e47ca1f856df605a9f76521450aacca5c..5e7ea7e2ae3b20b10799b6e120295324c9981d8d 100644
--- a/include/asterisk/autoconfig.h.in
+++ b/include/asterisk/autoconfig.h.in
@@ -598,6 +598,9 @@
 /* Define if your system has pjsip_get_dest_info declared. */
 #undef HAVE_PJSIP_GET_DEST_INFO
 
+/* Define if your system has PJSIP_INV_SESSION_REF */
+#undef HAVE_PJSIP_INV_SESSION_REF
+
 /* Define if your system has the PJSIP_REPLACE_MEDIA_STREAM headers. */
 #undef HAVE_PJSIP_REPLACE_MEDIA_STREAM
 
diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c
index 315393fdb895e6005eddedfd1c99cce72c2da0e2..f54ee941199718d7fd56926a2e6f7e72cc40f0c1 100644
--- a/res/res_pjsip_session.c
+++ b/res/res_pjsip_session.c
@@ -213,6 +213,11 @@ static int handle_incoming_sdp(struct ast_sip_session *session, const pjmedia_sd
 	int i;
 	int handled = 0;
 
+	if (session->inv_session && session->inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {
+		ast_log(LOG_ERROR, "Failed to handle incoming SDP. Session has been already disconnected\n");
+		return -1;
+	}
+
 	for (i = 0; i < sdp->media_count; ++i) {
 		/* See if there are registered handlers for this media stream type */
 		char media[20];
@@ -2087,6 +2092,16 @@ static int new_invite(void *data)
 	 * so that we will be notified so we can destroy the session properly
 	 */
 
+	if (invite->session->inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {
+		ast_log(LOG_ERROR, "Session already DISCONNECTED [reason=%d (%s)]\n",
+			invite->session->inv_session->cause,
+			pjsip_get_status_text(invite->session->inv_session->cause)->ptr);
+#ifdef HAVE_PJSIP_INV_SESSION_REF
+		pjsip_inv_dec_ref(invite->session->inv_session);
+#endif
+		return -1;
+	}
+
 	switch (get_destination(invite->session, invite->rdata)) {
 	case SIP_GET_DEST_EXTEN_FOUND:
 		/* Things worked. Keep going */
@@ -2097,7 +2112,7 @@ static int new_invite(void *data)
 		} else  {
 			pjsip_inv_terminate(invite->session->inv_session, 416, PJ_TRUE);
 		}
-		return 0;
+		goto end;
 	case SIP_GET_DEST_EXTEN_NOT_FOUND:
 	case SIP_GET_DEST_EXTEN_PARTIAL:
 	default:
@@ -2110,7 +2125,7 @@ static int new_invite(void *data)
 		} else  {
 			pjsip_inv_terminate(invite->session->inv_session, 404, PJ_TRUE);
 		}
-		return 0;
+		goto end;
 	};
 
 	if ((sdp_info = pjsip_rdata_get_sdp_info(invite->rdata)) && (sdp_info->sdp_err == PJ_SUCCESS) && sdp_info->sdp) {
@@ -2120,7 +2135,7 @@ static int new_invite(void *data)
 			} else  {
 				pjsip_inv_terminate(invite->session->inv_session, 488, PJ_TRUE);
 			}
-			return 0;
+			goto end;
 		}
 		/* We are creating a local SDP which is an answer to their offer */
 		local = create_local_sdp(invite->session->inv_session, invite->session, sdp_info->sdp);
@@ -2136,7 +2151,7 @@ static int new_invite(void *data)
 		} else  {
 			pjsip_inv_terminate(invite->session->inv_session, 500, PJ_TRUE);
 		}
-		return 0;
+		goto end;
 	} else {
 		pjsip_inv_set_local_sdp(invite->session->inv_session, local);
 		pjmedia_sdp_neg_set_prefer_remote_codec_order(invite->session->inv_session->neg, PJ_FALSE);
@@ -2153,12 +2168,16 @@ static int new_invite(void *data)
 	/* At this point, we've verified what we can, so let's go ahead and send a 100 Trying out */
 	if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 100, NULL, NULL, &tdata) != PJ_SUCCESS) {
 		pjsip_inv_terminate(invite->session->inv_session, 500, PJ_TRUE);
-		return 0;
+		goto end;
 	}
 	ast_sip_session_send_response(invite->session, tdata);
 
 	handle_incoming_request(invite->session, invite->rdata);
 
+end:
+#ifdef HAVE_PJSIP_INV_SESSION_REF
+	pjsip_inv_dec_ref(invite->session->inv_session);
+#endif
 	return 0;
 }
 
@@ -2179,6 +2198,20 @@ static void handle_new_invite_request(pjsip_rx_data *rdata)
 		return;
 	}
 
+#ifdef HAVE_PJSIP_INV_SESSION_REF
+	if (pjsip_inv_add_ref(inv_session) != PJ_SUCCESS) {
+		ast_log(LOG_ERROR, "Can't increase the session reference counter\n");
+		if (inv_session->state != PJSIP_INV_STATE_DISCONNECTED) {
+			if (pjsip_inv_initial_answer(inv_session, rdata, 500, NULL, NULL, &tdata) == PJ_SUCCESS) {
+				pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
+			} else {
+				internal_pjsip_inv_send_msg(inv_session, endpoint->transport, tdata);
+			}
+		}
+		return;
+	}
+#endif
+
 	session = ast_sip_session_alloc(endpoint, NULL, inv_session, rdata);
 	if (!session) {
 		if (pjsip_inv_initial_answer(inv_session, rdata, 500, NULL, NULL, &tdata) == PJ_SUCCESS) {
@@ -2186,6 +2219,9 @@ static void handle_new_invite_request(pjsip_rx_data *rdata)
 		} else {
 			internal_pjsip_inv_send_msg(inv_session, endpoint->transport, tdata);
 		}
+#ifdef HAVE_PJSIP_INV_SESSION_REF
+		pjsip_inv_dec_ref(inv_session);
+#endif
 		return;
 	}
 
@@ -2196,6 +2232,9 @@ static void handle_new_invite_request(pjsip_rx_data *rdata)
 		} else {
 			internal_pjsip_inv_send_msg(inv_session, endpoint->transport, tdata);
 		}
+#ifdef HAVE_PJSIP_INV_SESSION_REF
+		pjsip_inv_dec_ref(inv_session);
+#endif
 		ao2_cleanup(invite);
 	}
 	ao2_ref(session, -1);
@@ -2467,8 +2506,9 @@ static void handle_outgoing(struct ast_sip_session *session, pjsip_tx_data *tdat
 	}
 }
 
-static void session_end(struct ast_sip_session *session)
+static int session_end(void *vsession)
 {
+	struct ast_sip_session *session = vsession;
 	struct ast_sip_session_supplement *iter;
 
 	/* Stop the scheduled termination */
@@ -2480,6 +2520,7 @@ static void session_end(struct ast_sip_session *session)
 			iter->session_end(session);
 		}
 	}
+	return 0;
 }
 
 /*!
@@ -2617,7 +2658,10 @@ static void session_inv_on_state_changed(pjsip_inv_session *inv, pjsip_event *e)
 	}
 
 	if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
-		session_end(session);
+		if (ast_sip_push_task(session->serializer, session_end, session)) {
+			/* Do it anyway even though this is not the right thread. */
+			session_end(session);
+		}
 	}
 }
 
@@ -2784,7 +2828,11 @@ static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_trans
 			 * Pass the session ref held by session->inv_session to
 			 * session_end_completion().
 			 */
-			session_end_completion(session);
+			if (session
+				&& ast_sip_push_task(session->serializer, session_end_completion, session)) {
+				/* Do it anyway even though this is not the right thread. */
+				session_end_completion(session);
+			}
 			return;
 		}
 		break;
@@ -2909,7 +2957,12 @@ static struct pjmedia_sdp_session *create_local_sdp(pjsip_inv_session *inv, stru
 	static const pj_str_t STR_IP6 = { "IP6", 3 };
 	pjmedia_sdp_session *local;
 
-	if (!(local = PJ_POOL_ZALLOC_T(inv->pool_prov, pjmedia_sdp_session))) {
+	if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
+		ast_log(LOG_ERROR, "Failed to create session SDP. Session has been already disconnected\n");
+		return NULL;
+	}
+
+	if (!inv->pool_prov || !(local = PJ_POOL_ZALLOC_T(inv->pool_prov, pjmedia_sdp_session))) {
 		return NULL;
 	}
 
diff --git a/third-party/pjproject/configure.m4 b/third-party/pjproject/configure.m4
index 67ac04d4d869bf59196f696ee38f2c84b09af037..7a079f6577f5da7ae1a06b5fd059a53e2d32b74e 100644
--- a/third-party/pjproject/configure.m4
+++ b/third-party/pjproject/configure.m4
@@ -45,4 +45,5 @@ AC_DEFUN([PJPROJECT_CONFIGURE],
 	PJPROJECT_SYMBOL_CHECK([PJSIP_EXTERNAL_RESOLVER], [pjsip_endpt_set_ext_resolver], [pjsip.h])
 	AC_DEFINE([HAVE_PJSIP_TLS_TRANSPORT_PROTO], 1, [Define if your system has PJSIP_TLS_TRANSPORT_PROTO])
 	AC_DEFINE([HAVE_PJSIP_EVSUB_GRP_LOCK], 1, [Define if your system has PJSIP_EVSUB_GRP_LOCK])
+	AC_DEFINE([HAVE_PJSIP_INV_SESSION_REF], 1, [Define if your system has PJSIP_INV_SESSION_REF])
 ])
diff --git a/third-party/pjproject/patches/0002-r5435-add-pjsip_inv_session-ref_cnt.patch b/third-party/pjproject/patches/0002-r5435-add-pjsip_inv_session-ref_cnt.patch
new file mode 100644
index 0000000000000000000000000000000000000000..12ae6a0285f422121021eac057da4fbc73687d14
--- /dev/null
+++ b/third-party/pjproject/patches/0002-r5435-add-pjsip_inv_session-ref_cnt.patch
@@ -0,0 +1,212 @@
+When a transport error occured on an INVITE session
+the stack calls on_tsx_state_changed with new state
+PJSIP_INV_STATE_DISCONNECTED and immediately destroys
+the INVITE session.
+At the same time this INVITE session could being processed
+on another thread. This thread could use the session's
+memory pools which were already freed, so we get segfault.
+
+This patch adds a reference counter and new functions:
+pjsip_inv_add_ref and pjsip_inv_dec_ref.
+The INVITE session is destroyed only when the reference
+counter has reached zero.
+
+To avoid race condition an application should call
+pjsip_inv_add_ref/pjsip_inv_dec_ref.
+
+Index: pjsip/include/pjsip-ua/sip_inv.h
+===================================================================
+--- a/pjsip/include/pjsip-ua/sip_inv.h	(revision 5434)
++++ b/pjsip/include/pjsip-ua/sip_inv.h	(revision 5435)
+@@ -383,6 +383,11 @@
+  * Other applications that want to use these pools must understand
+  * that the flip-flop pool's lifetimes are synchronized to the
+  * SDP offer-answer negotiation.
++ *
++ * The lifetime of this session is controlled by the reference counter in this
++ * structure, which is manipulated by calling #pjsip_inv_add_ref and
++ * #pjsip_inv_dec_ref. When the reference counter has reached zero, then
++ * this session will be destroyed.
+  */
+ struct pjsip_inv_session
+ {
+@@ -412,6 +417,7 @@
+     struct pjsip_timer	*timer;			    /**< Session Timers.    */
+     pj_bool_t		 following_fork;	    /**< Internal, following
+ 							 forked media?	    */
++    pj_atomic_t		*ref_cnt;		    /**< Reference counter. */
+ };
+ 
+ 
+@@ -631,6 +637,30 @@
+ 
+ 
+ /**
++ * Add reference counter to the INVITE session. The reference counter controls
++ * the life time of the session, ie. when the counter reaches zero, then it 
++ * will be destroyed.
++ *
++ * @param inv       The INVITE session.
++ * @return          PJ_SUCCESS if the INVITE session reference counter
++ *                  was increased.
++ */
++PJ_DECL(pj_status_t) pjsip_inv_add_ref( pjsip_inv_session *inv );
++
++/**
++ * Decrement reference counter of the INVITE session.
++ * When the session is no longer used, it will be destroyed and
++ * caller is informed with PJ_EGONE return status.
++ *
++ * @param inv       The INVITE session.
++ * @return          PJ_SUCCESS if the INVITE session reference counter
++ *                  was decreased. A status PJ_EGONE will be returned to 
++ *                  inform that session is destroyed.
++ */
++PJ_DECL(pj_status_t) pjsip_inv_dec_ref( pjsip_inv_session *inv );
++
++
++/**
+  * Forcefully terminate and destroy INVITE session, regardless of
+  * the state of the session. Note that this function should only be used
+  * when there is failure in the INVITE session creation. After the
+Index: pjsip/src/pjsip-ua/sip_inv.c
+===================================================================
+--- a/pjsip/src/pjsip-ua/sip_inv.c	(revision 5434)
++++ b/pjsip/src/pjsip-ua/sip_inv.c	(revision 5435)
+@@ -195,6 +195,65 @@
+ }
+ 
+ /*
++ * Add reference to INVITE session.
++ */
++PJ_DEF(pj_status_t) pjsip_inv_add_ref( pjsip_inv_session *inv )
++{
++    PJ_ASSERT_RETURN(inv && inv->ref_cnt, PJ_EINVAL);
++
++    pj_atomic_inc(inv->ref_cnt);
++
++    return PJ_SUCCESS;
++}
++
++static void inv_session_destroy(pjsip_inv_session *inv)
++{
++    if (inv->last_ack) {
++	pjsip_tx_data_dec_ref(inv->last_ack);
++	inv->last_ack = NULL;
++    }
++    if (inv->invite_req) {
++	pjsip_tx_data_dec_ref(inv->invite_req);
++	inv->invite_req = NULL;
++    }
++    if (inv->pending_bye) {
++	pjsip_tx_data_dec_ref(inv->pending_bye);
++	inv->pending_bye = NULL;
++    }
++    pjsip_100rel_end_session(inv);
++    pjsip_timer_end_session(inv);
++    pjsip_dlg_dec_session(inv->dlg, &mod_inv.mod);
++
++    /* Release the flip-flop pools */
++    pj_pool_release(inv->pool_prov);
++    inv->pool_prov = NULL;
++    pj_pool_release(inv->pool_active);
++    inv->pool_active = NULL;
++
++    pj_atomic_destroy(inv->ref_cnt);
++    inv->ref_cnt = NULL;
++}
++
++/*
++ * Decrease INVITE session reference, destroy it when the reference count
++ * reaches zero.
++ */
++PJ_DEF(pj_status_t) pjsip_inv_dec_ref( pjsip_inv_session *inv )
++{
++    pj_atomic_value_t ref_cnt;
++
++    PJ_ASSERT_RETURN(inv && inv->ref_cnt, PJ_EINVAL);
++
++    ref_cnt = pj_atomic_dec_and_get(inv->ref_cnt);
++    pj_assert( ref_cnt >= 0);
++    if (ref_cnt == 0) {
++        inv_session_destroy(inv);
++        return PJ_EGONE;
++    } 
++    return PJ_SUCCESS;    
++}
++
++/*
+  * Set session state.
+  */
+ static void inv_set_state(pjsip_inv_session *inv, pjsip_inv_state state,
+@@ -261,27 +320,7 @@
+     if (inv->state == PJSIP_INV_STATE_DISCONNECTED &&
+ 	prev_state != PJSIP_INV_STATE_DISCONNECTED) 
+     {
+-	if (inv->last_ack) {
+-	    pjsip_tx_data_dec_ref(inv->last_ack);
+-	    inv->last_ack = NULL;
+-	}
+-	if (inv->invite_req) {
+-	    pjsip_tx_data_dec_ref(inv->invite_req);
+-	    inv->invite_req = NULL;
+-	}
+-	if (inv->pending_bye) {
+-	    pjsip_tx_data_dec_ref(inv->pending_bye);
+-	    inv->pending_bye = NULL;
+-	}
+-	pjsip_100rel_end_session(inv);
+-	pjsip_timer_end_session(inv);
+-	pjsip_dlg_dec_session(inv->dlg, &mod_inv.mod);
+-
+-	/* Release the flip-flop pools */
+-	pj_pool_release(inv->pool_prov);
+-	inv->pool_prov = NULL;
+-	pj_pool_release(inv->pool_active);
+-	inv->pool_active = NULL;
++	pjsip_inv_dec_ref(inv);
+     }
+ }
+ 
+@@ -838,6 +877,12 @@
+     inv = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_inv_session);
+     pj_assert(inv != NULL);
+ 
++    status = pj_atomic_create(dlg->pool, 0, &inv->ref_cnt);
++    if (status != PJ_SUCCESS) {
++	pjsip_dlg_dec_lock(dlg);
++	return status;
++    }
++
+     inv->pool = dlg->pool;
+     inv->role = PJSIP_ROLE_UAC;
+     inv->state = PJSIP_INV_STATE_NULL;
+@@ -881,6 +926,7 @@
+     pjsip_100rel_attach(inv);
+ 
+     /* Done */
++    pjsip_inv_add_ref(inv);
+     *p_inv = inv;
+ 
+     pjsip_dlg_dec_lock(dlg);
+@@ -1471,6 +1517,12 @@
+     inv = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_inv_session);
+     pj_assert(inv != NULL);
+ 
++    status = pj_atomic_create(dlg->pool, 0, &inv->ref_cnt);
++    if (status != PJ_SUCCESS) {
++	pjsip_dlg_dec_lock(dlg);
++	return status;
++    }
++
+     inv->pool = dlg->pool;
+     inv->role = PJSIP_ROLE_UAS;
+     inv->state = PJSIP_INV_STATE_NULL;
+@@ -1540,6 +1592,7 @@
+     }
+ 
+     /* Done */
++    pjsip_inv_add_ref(inv);
+     pjsip_dlg_dec_lock(dlg);
+     *p_inv = inv;
+