[asterisk-commits] russell: branch russell/iax_refcount r79472 - /team/russell/iax_refcount/chan...
SVN commits to the Asterisk project
asterisk-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 asterisk-commits
mailing list