diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index 8cfaf4e7b7e8f9565d4a5eb55a34b465b849e98a..d9303405498ca0fda681020cb7d9e02f6e5b8aa4 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -1484,7 +1484,7 @@ static int make_trunk(unsigned short callno, int locked) * * \note Calling this function while holding another pvt lock can cause a deadlock. */ -static int find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd) +static int __find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd, int return_locked) { int res = 0; int x; @@ -1560,12 +1560,23 @@ static int find_callno(unsigned short callno, unsigned short dcallno, struct soc ast_mutex_unlock(&iaxsl[x]); return 0; } - ast_mutex_unlock(&iaxsl[x]); + if (!return_locked) + ast_mutex_unlock(&iaxsl[x]); res = x; } return res; } +static int find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd) { + + return __find_callno(callno, dcallno, sin, new, sockfd, 0); +} + +static int find_callno_locked(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd) { + + return __find_callno(callno, dcallno, sin, new, sockfd, 1); +} + static void iax2_frame_free(struct iax_frame *fr) { AST_SCHED_DEL(sched, fr->retrans); @@ -3888,6 +3899,13 @@ static struct ast_channel *ast_iax2_new(int callno, int state, int capability) ast_mutex_unlock(&iaxsl[callno]); tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, i->amaflags, "IAX2/%s-%d", i->host, i->callno); ast_mutex_lock(&iaxsl[callno]); + if (!iaxs[callno]) { + if (tmp) { + ast_channel_free(tmp); + } + ast_mutex_unlock(&iaxsl[callno]); + return NULL; + } iax2_ami_channelupdate(i); if (!tmp) return NULL; @@ -7589,12 +7607,10 @@ static int socket_process_meta(int packet_len, struct ast_iax2_meta_hdr *meta, s /* Stop if we don't have enough data */ if (len > packet_len) break; - fr->callno = find_callno(callno & ~IAX_FLAG_FULL, 0, sin, NEW_PREVENT, sockfd); + fr->callno = find_callno_locked(callno & ~IAX_FLAG_FULL, 0, sin, NEW_PREVENT, sockfd); if (!fr->callno) continue; - ast_mutex_lock(&iaxsl[fr->callno]); - /* If it's a valid call, deliver the contents. If not, we drop it, since we don't have a scallno to use for an INVAL */ /* Process as a mini frame */ @@ -7973,7 +7989,9 @@ static int socket_process(struct iax2_thread *thread) if (call_to_destroy) { if (iaxdebug) ast_debug(1, "Really destroying %d, having been acked on final message\n", call_to_destroy); + ast_mutex_lock(&iaxsl[call_to_destroy]); iax2_destroy(call_to_destroy); + ast_mutex_unlock(&iaxsl[call_to_destroy]); } } /* Note how much we've received acknowledgement for */ @@ -9389,13 +9407,14 @@ static int iax2_do_register(struct iax2_registry *reg) if (!reg->callno) { ast_debug(1, "Allocate call number\n"); - reg->callno = find_callno(0, 0, ®->addr, NEW_FORCE, defaultsockfd); + reg->callno = find_callno_locked(0, 0, ®->addr, NEW_FORCE, defaultsockfd); if (reg->callno < 1) { ast_log(LOG_WARNING, "Unable to create call for registration\n"); return -1; } else ast_debug(1, "Registration created on call %d\n", reg->callno); iaxs[reg->callno]->reg = reg; + ast_mutex_unlock(&iaxsl[reg->callno]); } /* Setup the next registration a little early */ reg->expire = iax2_sched_replace(reg->expire, sched, @@ -9439,11 +9458,10 @@ static int iax2_provision(struct sockaddr_in *end, int sockfd, char *dest, const memset(&ied, 0, sizeof(ied)); iax_ie_append_raw(&ied, IAX_IE_PROVISIONING, provdata.buf, provdata.pos); - callno = find_callno(0, 0, &sin, NEW_FORCE, cai.sockfd); + callno = find_callno_locked(0, 0, &sin, NEW_FORCE, cai.sockfd); if (!callno) return -1; - ast_mutex_lock(&iaxsl[callno]); if (iaxs[callno]) { /* Schedule autodestruct in case they don't ever give us anything back */ iaxs[callno]->autoid = iax2_sched_replace(iaxs[callno]->autoid, @@ -9675,15 +9693,13 @@ static struct ast_channel *iax2_request(const char *type, int format, void *data if (pds.port) sin.sin_port = htons(atoi(pds.port)); - callno = find_callno(0, 0, &sin, NEW_FORCE, cai.sockfd); + callno = find_callno_locked(0, 0, &sin, NEW_FORCE, cai.sockfd); if (callno < 1) { ast_log(LOG_WARNING, "Unable to create call\n"); *cause = AST_CAUSE_CONGESTION; return NULL; } - ast_mutex_lock(&iaxsl[callno]); - /* If this is a trunk, update it now */ ast_copy_flags(iaxs[callno], &cai, IAX_TRUNK | IAX_SENDANI | IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF); if (ast_test_flag(&cai, IAX_TRUNK)) { @@ -11044,13 +11060,12 @@ static int cache_get_callno_locked(const char *data) ast_debug(1, "peer: %s, username: %s, password: %s, context: %s\n", pds.peer, pds.username, pds.password, pds.context); - callno = find_callno(0, 0, &sin, NEW_FORCE, cai.sockfd); + callno = find_callno_locked(0, 0, &sin, NEW_FORCE, cai.sockfd); if (callno < 1) { ast_log(LOG_WARNING, "Unable to create call\n"); return -1; } - ast_mutex_lock(&iaxsl[callno]); ast_string_field_set(iaxs[callno], dproot, data); iaxs[callno]->capability = IAX_CAPABILITY_FULLBANDWIDTH;