summaryrefslogtreecommitdiff
path: root/channels/chan_iax2.c
diff options
context:
space:
mode:
authorRussell Bryant <russell@russellbryant.com>2007-03-29 18:31:35 +0000
committerRussell Bryant <russell@russellbryant.com>2007-03-29 18:31:35 +0000
commit5d4e6a480ad83291f278cbe5d375133554c26ba0 (patch)
treec7737b0a21f86542dcb667f554038d7d0c736c9a /channels/chan_iax2.c
parent921e975d5f19f623b009f1804dbfd010127ff47d (diff)
Fix an issue with hashing iax2 pvt structures that caused random crashes on
systems under heavy load such as IAXtel. (possibly related to issue #9403) git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@59368 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'channels/chan_iax2.c')
-rw-r--r--channels/chan_iax2.c45
1 files changed, 29 insertions, 16 deletions
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c
index 712ecad7f..58ec437af 100644
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -474,6 +474,8 @@ struct iax_rr {
int ooo;
};
+struct iax2_pvt_ref;
+
struct chan_iax2_pvt {
/*! Socket to send/receive on for this call */
int sockfd;
@@ -632,14 +634,19 @@ struct chan_iax2_pvt {
int frames_dropped;
/*! received frame count: (just for stats) */
int frames_received;
-
- AST_LIST_ENTRY(chan_iax2_pvt) entry;
+ struct iax2_pvt_ref *hash_ref;
unsigned short hash;
};
+struct iax2_pvt_ref {
+ struct chan_iax2_pvt *pvt;
+ unsigned int callno;
+ AST_LIST_ENTRY(iax2_pvt_ref) entry;
+};
+
/* Somewhat arbitrary prime number */
-#define PVT_HASH_SIZE 563
-static AST_RWLIST_HEAD(pvt_list, chan_iax2_pvt) pvt_hash_tbl[PVT_HASH_SIZE];
+#define PVT_HASH_SIZE 3373
+static AST_RWLIST_HEAD(pvt_list, iax2_pvt_ref) pvt_hash_tbl[PVT_HASH_SIZE];
static AST_LIST_HEAD_STATIC(queue, iax_frame);
@@ -1274,16 +1281,21 @@ static inline unsigned short peer_hash_val(const struct sockaddr_in *sin, unsign
static inline void hash_on_peer(struct chan_iax2_pvt *pvt)
{
- if (pvt->hash) {
+ if (pvt->hash_ref) {
AST_RWLIST_WRLOCK(&pvt_hash_tbl[pvt->hash]);
- AST_RWLIST_REMOVE(&pvt_hash_tbl[pvt->hash], pvt, entry);
+ AST_RWLIST_REMOVE(&pvt_hash_tbl[pvt->hash], pvt->hash_ref, entry);
AST_RWLIST_UNLOCK(&pvt_hash_tbl[pvt->hash]);
+ } else {
+ if (!(pvt->hash_ref = ast_calloc(1, sizeof(pvt->hash_ref))))
+ return;
+ pvt->hash_ref->pvt = pvt;
}
pvt->hash = peer_hash_val(&pvt->addr, pvt->peercallno);
+ pvt->hash_ref->callno = pvt->callno;
AST_RWLIST_WRLOCK(&pvt_hash_tbl[pvt->hash]);
- AST_RWLIST_INSERT_HEAD(&pvt_hash_tbl[pvt->hash], pvt, entry);
+ AST_RWLIST_INSERT_HEAD(&pvt_hash_tbl[pvt->hash], pvt->hash_ref, entry);
AST_RWLIST_UNLOCK(&pvt_hash_tbl[pvt->hash]);
}
@@ -1295,13 +1307,13 @@ static int find_callno(unsigned short callno, unsigned short dcallno, struct soc
char host[80];
if (new <= NEW_ALLOW) {
unsigned short hash = peer_hash_val(sin, callno);
- const struct chan_iax2_pvt *pvt;
- AST_RWLIST_RDLOCK(&pvt_hash_tbl[hash]);
- AST_RWLIST_TRAVERSE(&pvt_hash_tbl[hash], pvt, entry) {
- ast_mutex_lock(&iaxsl[pvt->callno]);
- if (match(sin, callno, dcallno, pvt))
- res = pvt->callno;
- ast_mutex_unlock(&iaxsl[pvt->callno]);
+ struct iax2_pvt_ref *pvt_ref;
+ AST_RWLIST_WRLOCK(&pvt_hash_tbl[hash]);
+ AST_RWLIST_TRAVERSE(&pvt_hash_tbl[hash], pvt_ref, entry) {
+ ast_mutex_lock(&iaxsl[pvt_ref->callno]);
+ if (match(sin, callno, dcallno, pvt_ref->pvt))
+ res = pvt_ref->callno;
+ ast_mutex_unlock(&iaxsl[pvt_ref->callno]);
if (res > 0)
break;
}
@@ -1844,10 +1856,11 @@ retry:
pvt->owner = NULL;
iax2_destroy_helper(pvt);
- if (pvt->hash) {
+ if (pvt->hash_ref) {
AST_RWLIST_WRLOCK(&pvt_hash_tbl[pvt->hash]);
- AST_RWLIST_REMOVE(&pvt_hash_tbl[pvt->hash], pvt, entry);
+ AST_RWLIST_REMOVE(&pvt_hash_tbl[pvt->hash], pvt->hash_ref, entry);
AST_RWLIST_UNLOCK(&pvt_hash_tbl[pvt->hash]);
+ free(pvt->hash_ref);
}
/* Already gone */