aboutsummaryrefslogtreecommitdiffstats
path: root/channels/chan_iax2.c
diff options
context:
space:
mode:
authorrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2007-06-04 15:47:40 +0000
committerrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2007-06-04 15:47:40 +0000
commit2c93eab1763912b5be3fcef0d2929e321dd247fe (patch)
tree1fbf6046ea707ecbe10f27f3e78cba12f6d9dbc2 /channels/chan_iax2.c
parent1f809c72ab687ada19c1f8e42a7d29a1285f24bc (diff)
Resolve a deadlock in chan_iax2. When handling an implicit ACK to a frame that
was marked as the final transmission for a call, don't call iax2_destroy() for that call while the global frame queue is still locked. There is a very nice explanation of the deadlock in the report. (issue #9663, thorough report and patch from stevedavies, additional positive test reports from mihai and joff_oconnell) git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.4@67020 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels/chan_iax2.c')
-rw-r--r--channels/chan_iax2.c14
1 files changed, 9 insertions, 5 deletions
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c
index 767df2ffb..b5e01c09f 100644
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -6592,6 +6592,7 @@ static int socket_process(struct iax2_thread *thread)
((f.subclass != IAX_COMMAND_INVAL) ||
(f.frametype != AST_FRAME_IAX))) {
unsigned char x;
+ int call_to_destroy;
/* XXX This code is not very efficient. Surely there is a better way which still
properly handles boundary conditions? XXX */
/* First we have to qualify that the ACKed value is within our window */
@@ -6605,20 +6606,23 @@ static int socket_process(struct iax2_thread *thread)
/* Ack the packet with the given timestamp */
if (option_debug && iaxdebug)
ast_log(LOG_DEBUG, "Cancelling transmission of packet %d\n", x);
+ call_to_destroy = 0;
AST_LIST_LOCK(&iaxq.queue);
AST_LIST_TRAVERSE(&iaxq.queue, cur, list) {
/* If it's our call, and our timestamp, mark -1 retries */
if ((fr->callno == cur->callno) && (x == cur->oseqno)) {
cur->retries = -1;
/* Destroy call if this is the end */
- if (cur->final) {
- if (iaxdebug && option_debug)
- ast_log(LOG_DEBUG, "Really destroying %d, having been acked on final message\n", fr->callno);
- iax2_destroy(fr->callno);
- }
+ if (cur->final)
+ call_to_destroy = fr->callno;
}
}
AST_LIST_UNLOCK(&iaxq.queue);
+ if (call_to_destroy) {
+ if (iaxdebug && option_debug)
+ ast_log(LOG_DEBUG, "Really destroying %d, having been acked on final message\n", call_to_destroy);
+ iax2_destroy(call_to_destroy);
+ }
}
/* Note how much we've received acknowledgement for */
if (iaxs[fr->callno])