[svn-commits] russell: branch russell/iax_refcount r79472 - /team/russell/iax_refcount/chan...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Tue Aug 14 14:22:37 CDT 2007


Author: russell
Date: Tue Aug 14 14:22:36 2007
New Revision: 79472

URL: http://svn.digium.com/view/asterisk?view=rev&rev=79472
Log:
Add a pass at reference tracking of iax2_peer objects.  It's not ideal, but the
biggest thing in this patch is that I went through and determined where references
are acquired and released.  The final solution here will probably be pulling in
astobj2 and convert the iax2_peer object and container to that.

Modified:
    team/russell/iax_refcount/channels/chan_iax2.c

Modified: team/russell/iax_refcount/channels/chan_iax2.c
URL: http://svn.digium.com/view/asterisk/team/russell/iax_refcount/channels/chan_iax2.c?view=diff&rev=79472&r1=79471&r2=79472
==============================================================================
--- team/russell/iax_refcount/channels/chan_iax2.c (original)
+++ team/russell/iax_refcount/channels/chan_iax2.c Tue Aug 14 14:22:36 2007
@@ -358,6 +358,9 @@
 	int smoothing;					/*!< Sample over how many units to determine historic ms */
 	
 	struct ast_ha *ha;
+
+	unsigned int ref_count;
+
 	AST_LIST_ENTRY(iax2_peer) entry;
 };
 
@@ -1042,6 +1045,37 @@
 		return csub;
 }
 
+static void ref_peer(struct iax2_peer *peer)
+{
+	ast_atomic_fetchadd_int((int *) &peer->ref_count, +1);
+}
+
+static struct iax2_peer *unref_peer(struct iax2_peer *peer)
+{
+	unsigned int destroy = 0;
+
+	/* "Realtime" peers marked with the TEMPONLY flag are objects with only a 
+	 * single reference.  Once the reference gets released, destroy it. */
+	if (ast_test_flag(peer, IAX_TEMPONLY)) {
+		destroy_peer(peer);
+		return NULL;
+	}
+
+	AST_LIST_LOCK(&peers);
+	/* If we hold the last reference to this peer and it has been marked for deletion,
+	 * then ensure it has been removed from the peer list and then destroy it. */
+	if (ast_atomic_dec_and_test((int *) &peer->ref_count) && ast_test_flag(peer, IAX_DELME)) {
+		AST_LIST_REMOVE(&peers, peer, entry);
+		destroy = 1;
+	}
+	AST_LIST_UNLOCK(&peers);
+
+	if (destroy)
+		destroy_peer(peer);
+
+	return NULL;
+}
+
 /*!
  * \note This funtion calls realtime_peer -> reg_source_db -> iax2_poke_peer -> find_callno,
  *       so do not call it with a pvt lock held.
@@ -1054,6 +1088,7 @@
 	AST_LIST_LOCK(&peers);
 	AST_LIST_TRAVERSE(&peers, peer, entry) {
 		if (!strcasecmp(peer->name, name)) {
+			ref_peer(peer);
 			break;
 		}
 	}
@@ -1086,8 +1121,7 @@
 		peer = realtime_peer(NULL, &sin);
 		if (peer) {
 			ast_copy_string(host, peer->name, len);
-			if (ast_test_flag(peer, IAX_TEMPONLY))
-				destroy_peer(peer);
+			unref_peer(peer);
 			res = 1;
 		}
 	}
@@ -1985,6 +2019,7 @@
 		} else {
 			ast_cli(fd, "SORRY peer %s is not eligible for this operation.\n", argv[3]);
 		}
+		unref_peer(peer);
 	} else {
 		ast_cli(fd, "SORRY peer %s was not found in the cache.\n", argv[3]);
 	}
@@ -2111,8 +2146,7 @@
 		ast_cli(fd, "%s\n",status);
 		ast_cli(fd, "  Qualify      : every %dms when OK, every %dms when UNREACHABLE (sample smoothing %s)\n", peer->pokefreqok, peer->pokefreqnotok, peer->smoothing ? "On" : "Off");
 		ast_cli(fd,"\n");
-		if (ast_test_flag(peer, IAX_TEMPONLY))
-			destroy_peer(peer);
+		unref_peer(peer);
 	} else {
 		ast_cli(fd,"Peer %s not found.\n", argv[3]);
 		ast_cli(fd,"\n");
@@ -2579,6 +2613,7 @@
 				ast_sched_del(sched, peer->expire);
 			peer->expire = ast_sched_add(sched, (global_rtautoclear) * 1000, expire_registry, (void*)peer->name);
 		}
+		peer->ref_count = 1;
 		AST_LIST_LOCK(&peers);
 		AST_LIST_INSERT_HEAD(&peers, peer, entry);
 		AST_LIST_UNLOCK(&peers);
@@ -2684,6 +2719,7 @@
 	struct ast_hostent ahp;
 	struct hostent *hp;
 	struct iax2_peer *peer;
+	int res = -1;
 
 	ast_clear_flag(cai, IAX_SENDANI | IAX_TRUNK);
 	cai->sockfd = defaultsockfd;
@@ -2709,18 +2745,12 @@
 	cai->found = 1;
 	
 	/* if the peer has no address (current or default), return failure */
-	if (!(peer->addr.sin_addr.s_addr || peer->defaddr.sin_addr.s_addr)) {
-		if (ast_test_flag(peer, IAX_TEMPONLY))
-			destroy_peer(peer);
-		return -1;
-	}
+	if (!(peer->addr.sin_addr.s_addr || peer->defaddr.sin_addr.s_addr))
+		goto return_unref;
 
 	/* if the peer is being monitored and is currently unreachable, return failure */
-	if (peer->maxms && ((peer->lastms > peer->maxms) || (peer->lastms < 0))) {
-		if (ast_test_flag(peer, IAX_TEMPONLY))
-			destroy_peer(peer);
-		return -1;
-	}
+	if (peer->maxms && ((peer->lastms > peer->maxms) || (peer->lastms < 0)))
+		goto return_unref;
 
 	ast_copy_flags(cai, peer, IAX_SENDANI | IAX_TRUNK | IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF);
 	cai->maxtime = peer->maxms;
@@ -2748,9 +2778,7 @@
 			*key++ = '\0';
 		if (!key || ast_db_get(family, key, cai->secret, sizeof(cai->secret))) {
 			ast_log(LOG_WARNING, "Unable to retrieve database password for family/key '%s'!\n", peer->dbsecret);
-			if (ast_test_flag(peer, IAX_TEMPONLY))
-				destroy_peer(peer);
-			return -1;
+			goto return_unref;
 		}
 	}
 
@@ -2762,10 +2790,12 @@
 		sin->sin_port = peer->defaddr.sin_port;
 	}
 
-	if (ast_test_flag(peer, IAX_TEMPONLY))
-		destroy_peer(peer);
-
-	return 0;
+	res = 0;
+
+return_unref:
+	unref_peer(peer);
+
+	return res;
 }
 
 static void __auto_congest(void *nothing)
@@ -5043,6 +5073,7 @@
 	char *keyn;
 	int x;
 	int expire = 0;
+	int res = -1;
 
 	ast_clear_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED | IAX_STATE_UNCHANGED);
 	/* iaxs[callno]->peer[0] = '\0'; not necc. any more-- stringfield is pre-inited to null string */
@@ -5069,23 +5100,19 @@
 	if (!p || !iaxs[callno]) {
 		if (authdebug && !p)
 			ast_log(LOG_NOTICE, "No registration for peer '%s' (from %s)\n", peer, ast_inet_ntoa(sin->sin_addr));
-		return -1;
+		goto return_unref;
 	}
 
 	if (!ast_test_flag(p, IAX_DYNAMIC)) {
 		if (authdebug)
 			ast_log(LOG_NOTICE, "Peer '%s' is not dynamic (from %s)\n", peer, ast_inet_ntoa(sin->sin_addr));
-		if (ast_test_flag(p, IAX_TEMPONLY))
-			destroy_peer(p);
-		return -1;
+		goto return_unref;
 	}
 
 	if (!ast_apply_ha(p->ha, sin)) {
 		if (authdebug)
 			ast_log(LOG_NOTICE, "Host %s denied access to register peer '%s'\n", ast_inet_ntoa(sin->sin_addr), p->name);
-		if (ast_test_flag(p, IAX_TEMPONLY))
-			destroy_peer(p);
-		return -1;
+		goto return_unref;
 	}
 	if (!inaddrcmp(&p->addr, sin))
 		ast_set_flag(&iaxs[callno]->state, IAX_STATE_UNCHANGED);
@@ -5111,16 +5138,12 @@
 			if (!keyn) {
 				if (authdebug)
 					ast_log(LOG_NOTICE, "Host %s failed RSA authentication with inkeys '%s'\n", peer, p->inkeys);
-				if (ast_test_flag(p, IAX_TEMPONLY))
-					destroy_peer(p);
-				return -1;
+				goto return_unref;
 			}
 		} else {
 			if (authdebug)
 				ast_log(LOG_NOTICE, "Host '%s' trying to do RSA authentication, but we have no inkeys\n", peer);
-			if (ast_test_flag(p, IAX_TEMPONLY))
-				destroy_peer(p);
-			return -1;
+			goto return_unref;
 		}
 	} else if (!ast_strlen_zero(md5secret) && (p->authmethods & IAX_AUTH_MD5) && !ast_strlen_zero(iaxs[callno]->challenge)) {
 		struct MD5Context md5;
@@ -5144,26 +5167,20 @@
 		} else {
 			if (authdebug)
 				ast_log(LOG_NOTICE, "Host %s failed MD5 authentication for '%s' (%s != %s)\n", ast_inet_ntoa(sin->sin_addr), p->name, requeststr, md5secret);
-			if (ast_test_flag(p, IAX_TEMPONLY))
-				destroy_peer(p);
-			return -1;
+			goto return_unref;
 		}
 	} else if (!ast_strlen_zero(secret) && (p->authmethods & IAX_AUTH_PLAINTEXT)) {
 		/* They've provided a plain text password and we support that */
 		if (strcmp(secret, p->secret)) {
 			if (authdebug)
 				ast_log(LOG_NOTICE, "Host %s did not provide proper plaintext password for '%s'\n", ast_inet_ntoa(sin->sin_addr), p->name);
-			if (ast_test_flag(p, IAX_TEMPONLY))
-				destroy_peer(p);
-			return -1;
+			goto return_unref;
 		} else
 			ast_set_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED);
 	} else if (!ast_strlen_zero(md5secret) || !ast_strlen_zero(secret)) {
 		if (authdebug)
 			ast_log(LOG_NOTICE, "Inappropriate authentication received\n");
-		if (ast_test_flag(p, IAX_TEMPONLY))
-			destroy_peer(p);
-		return -1;
+		goto return_unref;
 	}
 	ast_string_field_set(iaxs[callno], peer, peer);
 	/* Choose lowest expiry number */
@@ -5172,10 +5189,12 @@
 
 	ast_device_state_changed("IAX2/%s", p->name); /* Activate notification */
 
-	if (ast_test_flag(p, IAX_TEMPONLY))
-		destroy_peer(p);
-
-	return 0;
+	res = 0;
+
+return_unref:
+	unref_peer(p);
+
+	return res;
 }
 
 static int authenticate(const char *challenge, const char *secret, const char *keyn, int authmethods, struct iax_ie_data *ied, struct sockaddr_in *sin, aes_encrypt_ctx *ecx, aes_decrypt_ctx *dcx)
@@ -5284,11 +5303,12 @@
 			ast_mutex_unlock(&iaxsl[callno]);
 			if ((peer = realtime_peer(peer_name, NULL))) {
 				ast_mutex_lock(&iaxsl[callno]);
-				if (!(p = iaxs[callno]))
+				if (!(p = iaxs[callno])) {
+					unref_peer(peer);
 					return -1;
+				}
 				res = authenticate(p->challenge, peer->secret,peer->outkey, authmethods, &ied, sin, &p->ecx, &p->dcx);
-				if (ast_test_flag(peer, IAX_TEMPONLY))
-					destroy_peer(peer);
+				unref_peer(peer);
 			}
 			if (!peer) {
 				ast_mutex_lock(&iaxsl[callno]);
@@ -5598,6 +5618,7 @@
 	AST_LIST_LOCK(&peers);
 	AST_LIST_TRAVERSE_SAFE_BEGIN(&peers, p, entry) {
 		if (!strcasecmp(p->name, name)) {
+			ref_peer(p);
 			p->expire = -1;
 			break;
 		}
@@ -5624,10 +5645,10 @@
 	if (iax2_regfunk)
 		iax2_regfunk(p->name, 0);
 
-	if (ast_test_flag(p, IAX_RTAUTOCLEAR)) {
+	if (ast_test_flag(p, IAX_RTAUTOCLEAR))
 		ast_set_flag(p, IAX_DELME);
-		prune_peers();
-	}
+	
+	unref_peer(p);
 }
 
 static int expire_registry(void *data)
@@ -5688,6 +5709,7 @@
 	char data[80];
 	int version;
 	const char *peer_name;
+	int res = -1;
 
 	memset(&ied, 0, sizeof(ied));
 
@@ -5701,11 +5723,8 @@
 		return -1;
 	}
 	ast_mutex_lock(&iaxsl[callno]);
-	if (!iaxs[callno]) {
-		if (ast_test_flag(p, IAX_TEMPONLY))
-			destroy_peer(p);
-		return -1;
-	}
+	if (!iaxs[callno])
+		goto return_unref;
 
 	if (ast_test_flag((&globalflags), IAX_RTUPDATE) && (ast_test_flag(p, IAX_TEMPONLY|IAX_RTCACHEFRIENDS))) {
 		if (sin->sin_addr.s_addr) {
@@ -5746,9 +5765,8 @@
 
 	/* Make sure our call still exists, an INVAL at the right point may make it go away */
 	if (!iaxs[callno]) {
-		if (ast_test_flag(p, IAX_TEMPONLY))
-			destroy_peer(p);
-		return 0;
+		res = 0;
+		goto return_unref;
 	}
 
 	/* Store socket fd */
@@ -5795,9 +5813,13 @@
 	version = iax_check_version(devtype);
 	if (version) 
 		iax_ie_append_short(&ied, IAX_IE_FIRMWAREVER, version);
-	if (ast_test_flag(p, IAX_TEMPONLY))
-		destroy_peer(p);
-	return send_command_final(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_REGACK, 0, ied.buf, ied.pos, -1);
+
+	res = 0;
+
+return_unref:
+	unref_peer(p);
+
+	return res ? res : send_command_final(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_REGACK, 0, ied.buf, ied.pos, -1);
 }
 
 static int registry_authrequest(int callno)
@@ -5806,6 +5828,7 @@
 	struct iax2_peer *p;
 	char challenge[10];
 	const char *peer_name;
+	int res = -1;
 
 	peer_name = ast_strdupa(iaxs[callno]->peer);
 
@@ -5813,28 +5836,27 @@
 	ast_mutex_unlock(&iaxsl[callno]);
 	p = find_peer(peer_name, 1);
 	ast_mutex_lock(&iaxsl[callno]);
-	if (!iaxs[callno]) {
-		if (p && ast_test_flag(p, IAX_TEMPONLY))
-			destroy_peer(p);
-		return -1;
-	}
-	if (p) {
-		memset(&ied, 0, sizeof(ied));
-		iax_ie_append_short(&ied, IAX_IE_AUTHMETHODS, p->authmethods);
-		if (p->authmethods & (IAX_AUTH_RSA | IAX_AUTH_MD5)) {
-			/* Build the challenge */
-			snprintf(challenge, sizeof(challenge), "%d", (int)ast_random());
-			ast_string_field_set(iaxs[callno], challenge, challenge);
-			/* snprintf(iaxs[callno]->challenge, sizeof(iaxs[callno]->challenge), "%d", (int)ast_random()); */
-			iax_ie_append_str(&ied, IAX_IE_CHALLENGE, iaxs[callno]->challenge);
-		}
-		iax_ie_append_str(&ied, IAX_IE_USERNAME, peer_name);
-		if (ast_test_flag(p, IAX_TEMPONLY))
-			destroy_peer(p);
-		return send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_REGAUTH, 0, ied.buf, ied.pos, -1);;
-	} 
-	ast_log(LOG_WARNING, "No such peer '%s'\n", peer_name);
-	return 0;
+	if (!iaxs[callno])
+		goto return_unref;
+	if (!p) {
+		ast_log(LOG_WARNING, "No such peer '%s'\n", peer_name);
+		goto return_unref;
+	}
+	
+	memset(&ied, 0, sizeof(ied));
+	iax_ie_append_short(&ied, IAX_IE_AUTHMETHODS, p->authmethods);
+	if (p->authmethods & (IAX_AUTH_RSA | IAX_AUTH_MD5)) {
+		/* Build the challenge */
+		snprintf(challenge, sizeof(challenge), "%d", (int)ast_random());
+		ast_string_field_set(iaxs[callno], challenge, challenge);
+		iax_ie_append_str(&ied, IAX_IE_CHALLENGE, iaxs[callno]->challenge);
+	}
+	iax_ie_append_str(&ied, IAX_IE_USERNAME, peer_name);
+
+return_unref:
+	unref_peer(p);
+
+	return res ? res : send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_REGAUTH, 0, ied.buf, ied.pos, -1);;
 }
 
 static int registry_rerequest(struct iax_ies *ies, int callno, struct sockaddr_in *sin)
@@ -9197,16 +9219,18 @@
 	free(peer);
 }
 
-static void prune_peers(void){
+static void prune_peers(void)
+{
 	/* Prune peers who still are supposed to be deleted */
 	struct iax2_peer *peer = NULL;
 
 	AST_LIST_LOCK(&peers);
 	AST_LIST_TRAVERSE_SAFE_BEGIN(&peers, peer, entry) {
-		if (ast_test_flag(peer, IAX_DELME)) {
-			destroy_peer(peer);
+		/* Just remove the peer from the list.  If it is still in the list, then
+		 * someone still has a reference to it.  When they release the reference,
+		 * the peer will get destroyed. */
+		if (ast_test_flag(peer, IAX_DELME))
 			AST_LIST_REMOVE_CURRENT(&peers, entry);
-		}
 	}
 	AST_LIST_TRAVERSE_SAFE_END
 	AST_LIST_UNLOCK(&peers);
@@ -10029,8 +10053,7 @@
 		}
 	}
 
-	if (ast_test_flag(peer, IAX_TEMPONLY))
-		destroy_peer(peer);
+	unref_peer(peer);
 
 	return 0;
 }
@@ -10091,8 +10114,7 @@
 			res = AST_DEVICE_UNKNOWN;	
 	}
 
-	if (ast_test_flag(p, IAX_TEMPONLY))
-		destroy_peer(p);
+	unref_peer(p);
 
 	return res;
 }




More information about the svn-commits mailing list