From c614fc203532a30189ae72501b5adfe90a35faf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Luis=20Aracil=20Boned?= Date: Mon, 6 Jul 2026 00:30:40 +0200 Subject: [PATCH] nta: do not abort on an outgoing transaction re-queued without progress outgoing_timer_bf() asserted that, after handling a B/F timeout, the transaction had either left the queue head or had its timeout advanced past now. outgoing_timeout() can re-queue the same orq at the head (via outgoing_try_another -> resolve/send/trying). Normally that re-queue sets a future timeout, but under load the same orq can be back at the head with a non-advanced timeout, and the assert then abort()s the whole process. Replace the assert with an anti-spin guard: if the same orq is back at the head with a non-advanced timeout, log it and stop this timer pass. The agent timer reschedules to now+1 while a head timeout is still due, so the transaction is retried on the next timer turn instead of spinning here or aborting. Fixes #57. --- libsofia-sip-ua/nta/nta.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/libsofia-sip-ua/nta/nta.c b/libsofia-sip-ua/nta/nta.c index e5f788d7..c0896bd5 100644 --- a/libsofia-sip-ua/nta/nta.c +++ b/libsofia-sip-ua/nta/nta.c @@ -9172,7 +9172,17 @@ size_t outgoing_timer_bf(outgoing_queue_t *q, else outgoing_terminate(orq); - assert(q->q_head != orq || (int32_t)(orq->orq_timeout - now) > 0); + /* Anti-spin guard: outgoing_timeout() may re-queue orq at the head of the + * same queue (retry/resolve-next). Normally the re-queue sets a future + * timeout; if the same orq is back at the head with a non-advanced timeout, + * continuing would spin on it. Stop this pass and let the next timer turn + * retry it (agent_timer reschedules to now+1 for a still-due head) rather + * than aborting the process (this was an assert()). */ + if (q->q_head == orq && (int32_t)(orq->orq_timeout - now) <= 0) { + SU_DEBUG_3(("nta: timer %s: %s (%u) re-queued without progress, deferring to next timer turn\n", + timer, orq->orq_method_name, orq->orq_cseq->cs_seq)); + break; + } } return timeout;