[asterisk-commits] res pjsip outbound registration: Fix double unref on error r... (asterisk[master])

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Thu Apr 30 10:49:31 CDT 2015


Mark Michelson has submitted this change and it was merged.

Change subject: res_pjsip_outbound_registration: Fix double unref on error return.
......................................................................


res_pjsip_outbound_registration: Fix double unref on error return.

When the PJSIP pjsip_regc_send function is invoked and an error
status returned the caller currently decrements the reference count
of the client state that it just incremented, assuming the
registration callback would not have been invoked. In practice
this is not correct. If the failure happens after the transaction
has been set up the callback will still be invoked. This will
cause the reference count to be incorrectly decremented twice, once
by the registration callback and second by the caller of
pjsip_regc_send.

This change makes it so that whether the callback is invoked or
not is known by the caller of pjsip_regc_send. Depending on
this it can know whether it is responsible for decrementing the
reference count of the client state or not.

ASTERISK-25037 #close
Reported by: Joshua Colp

Change-Id: I749dc12f3a22115c49c5d7d95ff42a5fa45319de
---
M res/res_pjsip_outbound_registration.c
1 file changed, 40 insertions(+), 12 deletions(-)

Approvals:
  Mark Michelson: Looks good to me, approved; Verified
  Matt Jordan: Looks good to me, but someone else must approve



diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c
index c2eb62b..1dd5f58 100644
--- a/res/res_pjsip_outbound_registration.c
+++ b/res/res_pjsip_outbound_registration.c
@@ -33,6 +33,7 @@
 #include "asterisk/taskprocessor.h"
 #include "asterisk/cli.h"
 #include "asterisk/stasis_system.h"
+#include "asterisk/threadstorage.h"
 #include "res_pjsip/include/res_pjsip_private.h"
 
 /*** DOCUMENTATION
@@ -194,6 +195,9 @@
 		</description>
 	</manager>
  ***/
+
+/*! \brief Some thread local storage used to determine if the running thread invoked the callback */
+AST_THREADSTORAGE(register_callback_invoked);
 
 /*! \brief Amount of buffer time (in seconds) before expiration that we re-register at */
 #define REREGISTER_BUFFER_TIME 10
@@ -429,6 +433,33 @@
 
 static pj_str_t PATH_NAME = { "path", 4 };
 
+/*! \brief Helper function which sends a message and cleans up, if needed, on failure */
+static pj_status_t registration_client_send(struct sip_outbound_registration_client_state *client_state,
+	pjsip_tx_data *tdata)
+{
+	pj_status_t status;
+	int *callback_invoked;
+
+	callback_invoked = ast_threadstorage_get(&register_callback_invoked, sizeof(int));
+	if (!callback_invoked) {
+		return PJ_ENOMEM;
+	}
+	*callback_invoked = 0;
+
+	/* Due to the message going out the callback may now be invoked, so bump the count */
+	ao2_ref(client_state, +1);
+	status = pjsip_regc_send(client_state->client, tdata);
+
+	/* If the attempt to send the message failed and the callback was not invoked we need to
+	 * drop the reference we just added
+	 */
+	if ((status != PJ_SUCCESS) && !(*callback_invoked)) {
+		ao2_ref(client_state, -1);
+	}
+
+	return status;
+}
+
 /*! \brief Callback function for registering */
 static int handle_client_registration(void *data)
 {
@@ -466,11 +497,7 @@
 		pj_strassign(&hdr->values[hdr->count++], &PATH_NAME);
 	}
 
-	/* Due to the registration the callback may now get called, so bump the ref count */
-	ao2_ref(client_state, +1);
-	if (pjsip_regc_send(client_state->client, tdata) != PJ_SUCCESS) {
-		ao2_ref(client_state, -1);
-	}
+	registration_client_send(client_state, tdata);
 
 	return 0;
 }
@@ -650,13 +677,11 @@
 		pjsip_tx_data *tdata;
 		if (!ast_sip_create_request_with_auth(&response->client_state->outbound_auths,
 				response->rdata, response->old_request, &tdata)) {
-			ao2_ref(response->client_state, +1);
 			response->client_state->auth_attempted = 1;
 			ast_debug(1, "Sending authenticated REGISTER to server '%s' from client '%s'\n",
 					server_uri, client_uri);
-			if (pjsip_regc_send(response->client_state->client, tdata) != PJ_SUCCESS) {
+			if (registration_client_send(response->client_state, tdata) != PJ_SUCCESS) {
 				response->client_state->auth_attempted = 0;
-				ao2_cleanup(response->client_state);
 			}
 			return 0;
 		} else {
@@ -732,8 +757,14 @@
 	RAII_VAR(struct sip_outbound_registration_client_state *, client_state, param->token, ao2_cleanup);
 	struct registration_response *response;
 	pjsip_regc_info info;
+	int *callback_invoked;
 
+	callback_invoked = ast_threadstorage_get(&register_callback_invoked, sizeof(int));
+
+	ast_assert(callback_invoked != NULL);
 	ast_assert(client_state != NULL);
+
+	*callback_invoked = 1;
 
 	response = ao2_alloc(sizeof(*response), registration_response_destroy);
 	if (!response) {
@@ -1202,10 +1233,7 @@
 		return 0;
 	}
 
-	ao2_ref(state->client_state, +1);
-	if (pjsip_regc_send(client, tdata) != PJ_SUCCESS) {
-		ao2_cleanup(state->client_state);
-	}
+	registration_client_send(state->client_state, tdata);
 
 	return 0;
 }

-- 
To view, visit https://gerrit.asterisk.org/307
To unsubscribe, visit https://gerrit.asterisk.org/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I749dc12f3a22115c49c5d7d95ff42a5fa45319de
Gerrit-PatchSet: 1
Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-Owner: Joshua Colp <jcolp at digium.com>
Gerrit-Reviewer: Mark Michelson <mmichelson at digium.com>
Gerrit-Reviewer: Matt Jordan <mjordan at digium.com>



More information about the asterisk-commits mailing list