Index: asterisk-1.6.2.18/channels/chan_sip.c =================================================================== --- asterisk-1.6.2.18.orig/channels/chan_sip.c 2011-05-19 14:30:23.000000000 +0100 +++ asterisk-1.6.2.18/channels/chan_sip.c 2011-05-19 14:31:31.000000000 +0100 @@ -22738,6 +22738,12 @@ } } ast_free(req); + if (p->owner && nounlock) { + /* We have an owner channel, which has been unlocked for some reason, so our pre-requisite + * for running handle_incoming() is no-longer met... Bail now. + */ + break; + } } } @@ -22747,6 +22753,7 @@ int recount = 0; int nounlock = 0; int lockretry; + int retry; for (lockretry = 10; lockretry > 0; lockretry--) { sip_pvt_lock(p); @@ -22765,7 +22772,7 @@ } if (!lockretry) { - int retry = !AST_LIST_EMPTY(&p->request_queue); + retry = !AST_LIST_EMPTY(&p->request_queue); /* we couldn't get the owner lock, which is needed to process the queued requests, so return a non-zero value, which will @@ -22780,8 +22787,12 @@ }; process_request_queue(p, &recount, &nounlock); - p->request_queue_sched_id = -1; + /* If one of the inbound packets caused a channel unlock, then we may not fully drain the queue */ + retry = !AST_LIST_EMPTY(&p->request_queue); + if (!retry) { + p->request_queue_sched_id = -1; + } if (p->owner && !nounlock) { ast_channel_unlock(p->owner); } @@ -22791,9 +22802,10 @@ ast_update_use_count(); } - dialog_unref(p, "The ref to a dialog passed to this sched callback is going out of scope; unref it."); - - return 0; + if (!retry) { + dialog_unref(p, "The ref to a dialog passed to this sched callback is going out of scope; unref it."); + } + return retry; } static int queue_request(struct sip_pvt *p, const struct sip_request *req) @@ -22964,8 +22976,22 @@ AST_SCHED_DEL_UNREF(sched, p->request_queue_sched_id, dialog_unref(p, "when you delete the request_queue_sched_id sched, you should dec the refcount for the stored dialog ptr")); process_request_queue(p, &recount, &nounlock); } - - if (handle_incoming(p, req, sin, &recount, &nounlock) == -1) { + if( !AST_LIST_EMPTY(&p->request_queue) || (p->owner && nounlock) ) { + /* Our p->owner is not locked for some reason, or we could not flush the queue + * Queue the packet we just received for later */ + if (queue_request(p, req)) { + /* the queue request has failed! */ + ast_log(LOG_ERROR, "Channel %s became unlocked, and request was unable to be queued.\n", S_OR(p->owner->name, "- no channel name ??? - ")); + ast_log(LOG_ERROR, "SIP transaction failed: %s \n", p->callid); + if (req->method != SIP_ACK) + transmit_response(p, "503 Server error", req); /* We must respond according to RFC 3261 sec 12.2 */ + + /* If the queue still has entries, try to reschedule */ + if (!AST_LIST_EMPTY(&p->request_queue) && (p->request_queue_sched_id = ast_sched_add(sched, 10, scheduler_process_request_queue, dialog_ref(p, "Increment refcount to pass dialog pointer to sched callback"))) == -1) { + dialog_unref(p, "Decrement refcount due to sched_add failure"); + } + } + } else if (handle_incoming(p, req, sin, &recount, &nounlock) == -1) { /* Request failed */ ast_debug(1, "SIP message could not be handled, bad request: %-70.70s\n", p->callid[0] ? p->callid : ""); }