diff --git a/libs/sofia-sip/.update b/libs/sofia-sip/.update index 02979eb6b0..980f2b1982 100644 --- a/libs/sofia-sip/.update +++ b/libs/sofia-sip/.update @@ -1 +1 @@ -Thu Oct 11 15:56:47 EDT 2007 +Sun Jan 6 15:11:42 EST 2008 diff --git a/libs/sofia-sip/libsofia-sip-ua-glib/Makefile.am b/libs/sofia-sip/libsofia-sip-ua-glib/Makefile.am index e96e3ec028..43f707d934 100644 --- a/libs/sofia-sip/libsofia-sip-ua-glib/Makefile.am +++ b/libs/sofia-sip/libsofia-sip-ua-glib/Makefile.am @@ -40,7 +40,7 @@ doxygen: built-sources && ${DOXYGEN} \ && popd > /dev/null ; \ done - ${top_srcdir}/libsofia-sip-ua/docs/hide_emails.sh docs/html + ${top_srcdir}/scripts/hide_emails.sh docs/html PHONY = doxygen diff --git a/libs/sofia-sip/libsofia-sip-ua/Makefile.am b/libs/sofia-sip/libsofia-sip-ua/Makefile.am index d3fef2f1c7..4238f911aa 100644 --- a/libs/sofia-sip/libsofia-sip-ua/Makefile.am +++ b/libs/sofia-sip/libsofia-sip-ua/Makefile.am @@ -101,7 +101,7 @@ doxygen: built-sources docs/$$d.doxytags > docs/$$d.doxytags.tmp && \ mv -f docs/$$d.doxytags.tmp docs/$$d.doxytags ; \ done - ${srcdir}/docs/hide_emails.sh docs/html + ${top_srcdir}/scripts/hide_emails.sh docs/html if HAVE_LCOV include $(top_srcdir)/rules/lcov.am diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/nta.c b/libs/sofia-sip/libsofia-sip-ua/nta/nta.c index 09cc70b217..2fb7dccfd3 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nta/nta.c +++ b/libs/sofia-sip/libsofia-sip-ua/nta/nta.c @@ -202,11 +202,12 @@ static void incoming_queue_adjust(nta_agent_t *sa, incoming_queue_t *queue, unsigned timeout); -su_inline -nta_incoming_t *incoming_find(nta_agent_t const *agent, sip_t const *sip, - sip_via_t const *v, - nta_incoming_t **merge, - nta_incoming_t **ack); +static nta_incoming_t *incoming_find(nta_agent_t const *agent, + sip_t const *sip, + sip_via_t const *v, + nta_incoming_t **merge, + nta_incoming_t **ack, + nta_incoming_t **cancel); static int incoming_reply(nta_incoming_t *irq, msg_t *msg, sip_t *sip); su_inline int incoming_recv(nta_incoming_t *irq, msg_t *msg, sip_t *sip, tport_t *tport); @@ -214,10 +215,11 @@ su_inline int incoming_ack(nta_incoming_t *irq, msg_t *msg, sip_t *sip, tport_t *tport); su_inline int incoming_cancel(nta_incoming_t *irq, msg_t *msg, sip_t *sip, tport_t *tport); -su_inline int incoming_merge(nta_incoming_t *irq, msg_t *msg, sip_t *sip, - tport_t *tport); +static void request_merge(nta_agent_t *, + msg_t *msg, sip_t *sip, tport_t *tport, + char const *to_tag); su_inline int incoming_timestamp(nta_incoming_t *, msg_t *, sip_t *); -su_inline su_duration_t incoming_timer(nta_agent_t *, su_duration_t); +static void incoming_timer(nta_agent_t *); static nta_reliable_t *reliable_mreply(nta_incoming_t *, nta_prack_f *, nta_reliable_magic_t *, @@ -225,7 +227,8 @@ static nta_reliable_t *reliable_mreply(nta_incoming_t *, static int reliable_send(nta_incoming_t *, nta_reliable_t *, msg_t *, sip_t *); static int reliable_final(nta_incoming_t *irq, msg_t *msg, sip_t *sip); static msg_t *reliable_response(nta_incoming_t *irq); -static int reliable_recv(nta_incoming_t *, msg_t *, sip_t *, tport_t *); +static nta_reliable_t *reliable_find(nta_agent_t const *, sip_t const *); +static int reliable_recv(nta_reliable_t *rel, msg_t *, sip_t *, tport_t *); static void reliable_flush(nta_incoming_t *irq); static void reliable_timeout(nta_incoming_t *irq, int timeout); @@ -251,7 +254,7 @@ static nta_outgoing_t *outgoing_find(nta_agent_t const *sa, sip_via_t const *v); static int outgoing_recv(nta_outgoing_t *orq, int status, msg_t *, sip_t *); static void outgoing_default_recv(nta_outgoing_t *, int, msg_t *, sip_t *); -su_inline su_duration_t outgoing_timer(nta_agent_t *, su_duration_t); +static void outgoing_timer(nta_agent_t *); static int outgoing_recv_reliable(nta_outgoing_t *orq, msg_t *msg, sip_t *sip); /* Internal message passing */ @@ -725,9 +728,6 @@ int agent_timer_init(nta_agent_t *agent) return -(agent->sa_timer == NULL); } -#define NEXT_TIMEOUT(next, p, f, now) \ - (p && p->f - (next) < 0 ? (p->f - (now) > 0 ? p->f : (now)) : (next)) - /** * Agent timer routine. */ @@ -739,20 +739,43 @@ void agent_timer(su_root_magic_t *rm, su_timer_t *timer, nta_agent_t *agent) now += now == 0; + agent->sa_next = 0; + agent->sa_now = stamp; agent->sa_millisec = now; - agent->sa_next = 0; agent->sa_in_timer = 1; - next = now + SU_DURATION_MAX; - next = outgoing_timer(agent, next); - next = incoming_timer(agent, next); + outgoing_timer(agent); + incoming_timer(agent); + /* agent->sa_now is used only if sa_millisec != 0 */ agent->sa_millisec = 0; agent->sa_in_timer = 0; + /* Calculate next timeout */ + next = now + SU_DURATION_MAX; + +#define NEXT_TIMEOUT(next, p, f, now) \ + (void)(p && p->f - (next) < 0 && ((next) = (p->f - (now) > 0 ? p->f : (now)))) + + NEXT_TIMEOUT(next, agent->sa_out.re_list, orq_retry, now); + NEXT_TIMEOUT(next, agent->sa_out.inv_completed->q_head, orq_timeout, now); + NEXT_TIMEOUT(next, agent->sa_out.completed->q_head, orq_timeout, now); + NEXT_TIMEOUT(next, agent->sa_out.inv_calling->q_head, orq_timeout, now); + if (agent->sa_out.inv_proceeding->q_timeout) + NEXT_TIMEOUT(next, agent->sa_out.inv_proceeding->q_head, orq_timeout, now); + NEXT_TIMEOUT(next, agent->sa_out.trying->q_head, orq_timeout, now); + + NEXT_TIMEOUT(next, agent->sa_in.preliminary->q_head, irq_timeout, now); + NEXT_TIMEOUT(next, agent->sa_in.inv_completed->q_head, irq_timeout, now); + NEXT_TIMEOUT(next, agent->sa_in.inv_confirmed->q_head, irq_timeout, now); + NEXT_TIMEOUT(next, agent->sa_in.completed->q_head, irq_timeout, now); + NEXT_TIMEOUT(next, agent->sa_in.re_list, irq_retry, now); + if (agent->sa_next) - next = NEXT_TIMEOUT(next, agent, sa_next, now); + NEXT_TIMEOUT(next, agent, sa_next, now); + +#undef NEXT_TIMEOUT if (next == now + SU_DURATION_MAX) { /* Do not set timer */ @@ -2199,7 +2222,7 @@ void agent_recv_request(nta_agent_t *agent, tport_t *tport) { nta_leg_t *leg; - nta_incoming_t *irq, *merge = NULL, *ack = NULL; + nta_incoming_t *irq, *merge = NULL, *ack = NULL, *cancel = NULL; sip_method_t method = sip->sip_request->rq_method; char const *method_name = sip->sip_request->rq_method_name; url_t url[1]; @@ -2337,7 +2360,15 @@ void agent_recv_request(nta_agent_t *agent, } /* First, try existing incoming requests */ - irq = incoming_find(agent, sip, sip->sip_via, &merge, &ack); + irq = incoming_find(agent, sip, sip->sip_via, + agent->sa_merge_482 && + !sip->sip_to->a_tag && + method != sip_method_ack + ? &merge + : NULL, + method == sip_method_ack ? &ack : NULL, + method == sip_method_cancel ? &cancel : NULL); + if (irq) { /* Match - this is a retransmission */ SU_DEBUG_5(("nta: %s (%u) going to existing %s transaction\n", @@ -2346,31 +2377,36 @@ void agent_recv_request(nta_agent_t *agent, return; } else if (ack) { - /* Match - this is an ACK or CANCEL or PRACK */ SU_DEBUG_5(("nta: %s (%u) is going to %s (%u)\n", method_name, cseq, - ack->irq_rq->rq_method_name, ack->irq_cseq->cs_seq)); - if (method == sip_method_ack) { - if (incoming_ack(ack, msg, sip, tport) >= 0) - return; - } - else if (method == sip_method_cancel) { - if (incoming_cancel(ack, msg, sip, tport) >= 0) - return; - } - else if (method == sip_method_prack) { - if (reliable_recv(ack, msg, sip, tport) >= 0) - return; - } - else { - assert(!method); - } + ack->irq_cseq->cs_method_name, ack->irq_cseq->cs_seq)); + if (incoming_ack(ack, msg, sip, tport) >= 0) + return; + } + else if (cancel) { + SU_DEBUG_5(("nta: %s (%u) is going to %s (%u)\n", + method_name, cseq, + cancel->irq_cseq->cs_method_name, cancel->irq_cseq->cs_seq)); + if (incoming_cancel(cancel, msg, sip, tport) >= 0) + return; } else if (merge) { SU_DEBUG_5(("nta: %s (%u) %s\n", method_name, cseq, "is a merged request")); - if (incoming_merge(merge, msg, sip, tport) >= 0) + request_merge(agent, msg, sip, tport, merge->irq_tag); + return; + } + + if (method == sip_method_prack && sip->sip_rack) { + nta_reliable_t *rel = reliable_find(agent, sip); + if (rel) { + SU_DEBUG_5(("nta: %s (%u) is going to %s (%u)\n", + method_name, cseq, + rel->rel_irq->irq_cseq->cs_method_name, + rel->rel_irq->irq_cseq->cs_seq)); + reliable_recv(rel, msg, sip, tport); return; + } } *url = *sip->sip_request->rq_url; @@ -5176,48 +5212,41 @@ nta_incoming_t *nta_incoming_find(nta_agent_t const *agent, sip_via_t const *v) { if (agent && sip && v) - return incoming_find(agent, sip, v, NULL, NULL); + return incoming_find(agent, sip, v, NULL, NULL, NULL); else return NULL; } -su_inline -int addr_match(sip_addr_t const *a, char const *a_tag, sip_addr_t const *b) -{ - if (a_tag && b->a_tag) - return strcasecmp(a_tag, b->a_tag) == 0; - else if (a->a_tag && b->a_tag) - return strcasecmp(a->a_tag, b->a_tag) == 0; - else - return - str0casecmp(a->a_host, b->a_host) == 0 && - str0cmp(a->a_user, b->a_user) == 0; -} - /** Find a matching server transaction object. * - * + * Check also for requests to merge, to ACK, or to CANCEL. */ -su_inline -nta_incoming_t *incoming_find(nta_agent_t const *agent, - sip_t const *sip, - sip_via_t const *v, - nta_incoming_t **return_merge, - nta_incoming_t **return_ack) +static nta_incoming_t *incoming_find(nta_agent_t const *agent, + sip_t const *sip, + sip_via_t const *v, + nta_incoming_t **return_merge, + nta_incoming_t **return_ack, + nta_incoming_t **return_cancel) { sip_cseq_t const *cseq = sip->sip_cseq; sip_call_id_t const *i = sip->sip_call_id; sip_to_t const *to = sip->sip_to; sip_from_t const *from = sip->sip_from; sip_request_t *rq = sip->sip_request; - int is_uas_ack = return_ack && - agent->sa_is_a_uas && rq->rq_method == sip_method_ack; incoming_htable_t const *iht = agent->sa_incoming; hash_value_t hash = NTA_HASH(i, cseq->cs_seq); + char const *magic_branch; - nta_incoming_t **ii, *irq, *maybe; + nta_incoming_t **ii, *irq; - for (ii = incoming_htable_hash(iht, hash), maybe = NULL; + int is_uas_ack = return_ack && agent->sa_is_a_uas; + + if (v->v_branch && strncasecmp(v->v_branch, "z9hG4bK", 7) == 0) + magic_branch = v->v_branch + 7; + else + magic_branch = NULL; + + for (ii = incoming_htable_hash(iht, hash); (irq = *ii); ii = incoming_htable_next(iht, ii)) { if (hash != irq->irq_hash || @@ -5229,96 +5258,84 @@ nta_incoming_t *incoming_find(nta_agent_t const *agent, if (str0casecmp(irq->irq_from->a_tag, from->a_tag)) continue; - if (str0casecmp(irq->irq_via->v_branch, v->v_branch) != 0 || - strcasecmp(irq->irq_via->v_host, v->v_host) != 0) { - if (!agent->sa_is_a_uas) - continue; - - if (is_uas_ack && - irq->irq_method == sip_method_invite && - 200 <= irq->irq_status && irq->irq_status < 300 && - addr_match(irq->irq_to, irq->irq_tag, to)) - *return_ack = irq; - /* RFC3261 - section 8.2.2.2 Merged Requests */ - else if (return_merge && agent->sa_merge_482 && - irq->irq_cseq->cs_method == cseq->cs_method && - (irq->irq_cseq->cs_method != sip_method_unknown || - strcmp(irq->irq_cseq->cs_method_name, - cseq->cs_method_name) == 0)) { - *return_merge = irq; - continue; + if (is_uas_ack && + irq->irq_method == sip_method_invite && + 200 <= irq->irq_status && irq->irq_status < 300 && + str0casecmp(irq->irq_tag, to->a_tag) == 0) { + *return_ack = irq; + return NULL; + } + + if (magic_branch) { + /* RFC3261 17.2.3: + * + * The request matches a transaction if branch and sent-by in topmost + * the method of the request matches the one that created the + * transaction, except for ACK, where the method of the request + * that created the transaction is INVITE. + */ + + if (irq->irq_via->v_branch && + strcasecmp(irq->irq_via->v_branch + 7, magic_branch) == 0 && + strcasecmp(irq->irq_via->v_host, v->v_host) == 0 && + str0cmp(irq->irq_via->v_port, v->v_port) == 0) { + if (irq->irq_method == cseq->cs_method && + strcmp(irq->irq_cseq->cs_method_name, + cseq->cs_method_name) == 0) + return irq; + if (return_ack && irq->irq_method == sip_method_invite) + return *return_ack = irq, NULL; + if (return_cancel && irq->irq_method != sip_method_ack) + return *return_cancel = irq, NULL; } - else - continue; } + else { + /* No magic branch */ - if (is_uas_ack) { - if (!addr_match(irq->irq_to, irq->irq_tag, to)) - continue; - } - else if (irq->irq_tag_set || !irq->irq_tag) { - if (str0casecmp(irq->irq_to->a_host, to->a_host) != 0 || - str0cmp(irq->irq_to->a_user, to->a_user) != 0) - continue; - } - else if (str0casecmp(irq->irq_to->a_tag, to->a_tag)) - continue; + /* INVITE request matches a transaction if + the Request-URI, To tag, From tag, Call-ID, CSeq, and + top Via header match */ - if (!is_uas_ack && url_cmp(irq->irq_rq->rq_url, rq->rq_url)) - continue; + /* From tag, Call-ID, and CSeq number has been matched above */ -#if 0 - if (irq->irq_terminated) - continue; -#endif + /* Match To tag */ + if (str0casecmp(irq->irq_to->a_tag, to->a_tag) && + /* Ignore failing match if tag has been set */ + /* and retransmitted request had no to tag */ + !(irq->irq_tag_set && to->a_tag == NULL)) + ; + /* Match top Via header field */ + else if (str0casecmp(irq->irq_via->v_branch, v->v_branch) == 0 && + strcasecmp(irq->irq_via->v_host, v->v_host) == 0 && + str0cmp(irq->irq_via->v_port, v->v_port) == 0) + ; + /* Match Request-URI */ + else if (url_cmp(irq->irq_rq->rq_url, rq->rq_url)) + ; + else { + /* Match CSeq */ + if (irq->irq_method == cseq->cs_method && + strcmp(irq->irq_cseq->cs_method_name, + cseq->cs_method_name) == 0) + return irq; /* found */ - if (irq->irq_method == rq->rq_method) - break; /* found */ + if (return_ack && irq->irq_method == sip_method_invite) + *return_ack = irq; + else if (return_cancel && irq->irq_method != sip_method_ack) + *return_cancel = irq; + } + } - if (!return_ack) - continue; - - if (irq->irq_method == sip_method_invite) { - if (rq->rq_method == sip_method_cancel) - *return_ack = irq; - else if (rq->rq_method == sip_method_ack) - *return_ack = irq; - } - else if (rq->rq_method == sip_method_cancel && !irq->irq_terminated) - *return_ack = irq; - } - - if (irq) - return irq; - - /* Check PRACKed requests */ - if (return_ack && rq->rq_method == sip_method_prack && sip->sip_rack) { - sip_rack_t const *rack = sip->sip_rack; - hash = NTA_HASH(i, rack->ra_cseq); - - for (ii = incoming_htable_hash(iht, hash); - (irq = *ii); - ii = incoming_htable_next(iht, ii)) { - if (hash != irq->irq_hash) - continue; - if (irq->irq_call_id->i_hash != i->i_hash) - continue; - if (strcmp(irq->irq_call_id->i_id, i->i_id)) - continue; - if (irq->irq_cseq->cs_seq != rack->ra_cseq) - continue; - if (!addr_match(irq->irq_to, NULL, to) || - !addr_match(irq->irq_from, NULL, from)) - continue; - if (!irq->irq_from->a_tag != !from->a_tag) - continue; - *return_ack = irq; - - return NULL; + /* RFC3261 - section 8.2.2.2 Merged Requests */ + if (return_merge) { + if (irq->irq_cseq->cs_method == cseq->cs_method && + strcmp(irq->irq_cseq->cs_method_name, + cseq->cs_method_name) == 0) + *return_merge = irq, return_merge = NULL; } } - return irq; + return NULL; } /** Process retransmitted requests. */ @@ -5397,23 +5414,26 @@ int incoming_ack(nta_incoming_t *irq, msg_t *msg, sip_t *sip, tport_t *tport) return 0; } +/** Respond to the CANCEL. */ su_inline int incoming_cancel(nta_incoming_t *irq, msg_t *msg, sip_t *sip, tport_t *tport) { nta_agent_t *agent = irq->irq_agent; - /* Respond to the CANCEL */ - - if (200 <= irq->irq_status && irq->irq_status < 300) { - nta_msg_treply(agent, msg_ref_create(msg), SIP_481_NO_TRANSACTION, + /* According to the spec, this INVITE has been destroyed */ + if (irq->irq_method == sip_method_invite && + 200 <= irq->irq_status && irq->irq_status < 300) { + nta_msg_treply(agent, msg, SIP_481_NO_TRANSACTION, NTATAG_TPORT(tport), TAG_END()); + return 0; } - else - nta_msg_treply(agent, msg_ref_create(msg), SIP_200_OK, - NTATAG_TPORT(tport), - TAG_END()); + + nta_msg_treply(agent, msg_ref_create(msg), SIP_200_OK, + NTATAG_TPORT(tport), + SIPTAG_TO(irq->irq_to), + TAG_END()); /* We have already sent final response */ if (irq->irq_completed || irq->irq_method != sip_method_invite) { @@ -5436,29 +5456,28 @@ int incoming_cancel(nta_incoming_t *irq, msg_t *msg, sip_t *sip, return 0; } -/** Process merged requests */ -su_inline -int incoming_merge(nta_incoming_t *irq, msg_t *msg, sip_t *sip, tport_t *tport) +/** Merge request */ +static +void request_merge(nta_agent_t *agent, + msg_t *msg, sip_t *sip, tport_t *tport, + char const *to_tag) { - nta_agent_t *agent = irq->irq_agent; + nta_incoming_t *irq; agent->sa_stats->as_merged_request++; - irq = incoming_create(irq->irq_agent, msg, sip, tport, irq->irq_tag); + irq = incoming_create(agent, msg, sip, tport, to_tag); - if (!irq) { - SU_DEBUG_3(("nta: incoming_merge(): cannot create transaction for %s\n", + if (irq) { + nta_incoming_treply(irq, 482, "Request merged", TAG_END()); + nta_incoming_destroy(irq); + } else { + SU_DEBUG_3(("nta: request_merge(): cannot create transaction for %s\n", sip->sip_request->rq_method_name)); nta_msg_treply(agent, msg, 482, "Request merged", NTATAG_TPORT(tport), TAG_END()); - return 0; } - - nta_incoming_treply(irq, 482, "Request merged", TAG_END()); - nta_incoming_destroy(irq); - - return 0; } /**@typedef nta_ack_cancel_f @@ -6097,8 +6116,7 @@ enum { }; /** @internal Timer routine for the incoming request. */ -su_inline -su_duration_t incoming_timer(nta_agent_t *sa, su_duration_t next) +static void incoming_timer(nta_agent_t *sa) { su_duration_t now = sa->sa_millisec; nta_incoming_t *irq, *irq_next; @@ -6166,8 +6184,6 @@ su_duration_t incoming_timer(nta_agent_t *sa, su_duration_t next) } } - next = NEXT_TIMEOUT(next, irq, irq_retry, now); - while ((irq = sa->sa_in.final_failed->q_head)) { incoming_remove(irq); irq->irq_final_failed = 0; @@ -6215,8 +6231,6 @@ su_duration_t incoming_timer(nta_agent_t *sa, su_duration_t next) reliable_timeout(irq, 1); } - next = NEXT_TIMEOUT(next, irq, irq_timeout, now); - while ((irq = sa->sa_in.inv_completed->q_head)) { assert(irq->irq_status >= 200); assert(irq->irq_timeout); @@ -6245,8 +6259,6 @@ su_duration_t incoming_timer(nta_agent_t *sa, su_duration_t next) } } - next = NEXT_TIMEOUT(next, irq, irq_timeout, now); - while ((irq = sa->sa_in.inv_confirmed->q_head)) { assert(irq->irq_timeout); assert(irq->irq_status >= 200); @@ -6268,8 +6280,6 @@ su_duration_t incoming_timer(nta_agent_t *sa, su_duration_t next) incoming_free_queue(rq, irq); } - next = NEXT_TIMEOUT(next, irq, irq_timeout, now); - while ((irq = sa->sa_in.completed->q_head)) { assert(irq->irq_status >= 200); assert(irq->irq_timeout); @@ -6292,8 +6302,6 @@ su_duration_t incoming_timer(nta_agent_t *sa, su_duration_t next) incoming_free_queue(rq, irq); } - next = NEXT_TIMEOUT(next, irq, irq_timeout, now); - for (irq = sa->sa_in.terminated->q_head; irq; irq = irq_next) { irq_next = irq->irq_next; if (irq->irq_destroyed) @@ -6312,8 +6320,6 @@ su_duration_t incoming_timer(nta_agent_t *sa, su_duration_t next) timeout, unconfirmed, terminated, unterminated, destroyed, total)); - - return next; } /** Mass destroy server transactions */ @@ -7864,8 +7870,7 @@ void outgoing_destroy(nta_outgoing_t *orq) /** @internal Outgoing transaction timer routine. * */ -su_inline -su_duration_t outgoing_timer(nta_agent_t *sa, su_duration_t next) +static void outgoing_timer(nta_agent_t *sa) { su_duration_t now = sa->sa_millisec; nta_outgoing_t *orq; @@ -7877,7 +7882,6 @@ su_duration_t outgoing_timer(nta_agent_t *sa, su_duration_t next) sa->sa_out.inv_calling->q_length; size_t completed = sa->sa_out.completed->q_length + sa->sa_out.inv_completed->q_length; - outgoing_queue_t *proceeding = sa->sa_out.inv_proceeding; outgoing_queue_init(sa->sa_out.free = rq, 0); @@ -7920,25 +7924,15 @@ su_duration_t outgoing_timer(nta_agent_t *sa, su_duration_t next) su_root_yield(sa->sa_root); /* Handle received packets */ } - next = NEXT_TIMEOUT(next, orq, orq_retry, now); - terminated = outgoing_timer_dk(sa->sa_out.inv_completed, "D", now) + outgoing_timer_dk(sa->sa_out.completed, "K", now); - next = NEXT_TIMEOUT(next, sa->sa_out.inv_completed->q_head, orq_timeout, now); - next = NEXT_TIMEOUT(next, sa->sa_out.completed->q_head, orq_timeout, now); - timeout = outgoing_timer_bf(sa->sa_out.inv_calling, "B", now) - + outgoing_timer_c(proceeding, "C", now) + + outgoing_timer_c(sa->sa_out.inv_proceeding, "C", now) + outgoing_timer_bf(sa->sa_out.trying, "F", now); - next = NEXT_TIMEOUT(next, sa->sa_out.inv_calling->q_head, orq_timeout, now); - if (proceeding->q_timeout) - next = NEXT_TIMEOUT(next, proceeding->q_head, orq_timeout, now); - next = NEXT_TIMEOUT(next, sa->sa_out.trying->q_head, orq_timeout, now); - destroyed = outgoing_mass_destroy(sa, rq); sa->sa_out.free = NULL; @@ -7954,8 +7948,6 @@ su_duration_t outgoing_timer(nta_agent_t *sa, su_duration_t next) terminated, completed, destroyed, total)); } - - return next; } /** @internal Retransmit the outgoing request. */ @@ -8246,13 +8238,8 @@ nta_outgoing_t *outgoing_find(nta_agent_t const *sa, continue; if (str0casecmp(orq->orq_from->a_tag, sip->sip_from->a_tag)) continue; - if (!addr_match(orq->orq_to, NULL, sip->sip_to)) - continue; - if (orq->orq_method == method ? - /* Don't match if request To has a tag and response has no To tag */ - orq->orq_to->a_tag && !sip->sip_to->a_tag : - /* Don't (with ACK) if request/response tag mismatch */ - !orq->orq_to->a_tag != !sip->sip_to->a_tag) + if (orq->orq_to->a_tag && + str0casecmp(orq->orq_to->a_tag, sip->sip_to->a_tag)) continue; if (orq->orq_method == sip_method_ack) { @@ -9851,7 +9838,7 @@ nta_reliable_t *reliable_mreply(nta_incoming_t *irq, nta_agent_t *agent; agent = irq->irq_agent; - + if (callback == NULL) callback = nta_reliable_destroyed; @@ -9976,24 +9963,54 @@ msg_t *reliable_response(nta_incoming_t *irq) return rel->rel_unsent; } +/* Find un-PRACKed responses */ +static +nta_reliable_t *reliable_find(nta_agent_t const *agent, + sip_t const *sip) +{ + incoming_htable_t const *iht = agent->sa_incoming; + nta_incoming_t *irq, **ii; + sip_call_id_t const *i = sip->sip_call_id; + sip_rack_t const *rack = sip->sip_rack; + hash_value_t hash = NTA_HASH(i, rack->ra_cseq); + + /* XXX - add own hash table for 100rel */ + + for (ii = incoming_htable_hash(iht, hash); + (irq = *ii); + ii = incoming_htable_next(iht, ii)) { + + if (hash == irq->irq_hash && + irq->irq_call_id->i_hash == i->i_hash && + irq->irq_cseq->cs_seq == rack->ra_cseq && + irq->irq_method == sip_method_invite && + strcmp(irq->irq_call_id->i_id, i->i_id) == 0 && + (irq->irq_to->a_tag == NULL || + str0casecmp(irq->irq_to->a_tag, sip->sip_to->a_tag) == 0) && + str0casecmp(irq->irq_from->a_tag, sip->sip_from->a_tag) == 0) { + + nta_reliable_t const *rel; + + /* Found matching INVITE */ + for (rel = irq->irq_reliable; rel; rel = rel->rel_next) + if (rel->rel_rseq == rack->ra_response) + return (nta_reliable_t *)rel; + + return NULL; + } + } + + return NULL; +} + /** Process incoming PRACK with matching @RAck field */ static -int reliable_recv(nta_incoming_t *irq, msg_t *msg, sip_t *sip, tport_t *tp) +int reliable_recv(nta_reliable_t *rel, msg_t *msg, sip_t *sip, tport_t *tp) { - sip_rack_t *rack = sip->sip_rack; - nta_reliable_t *rel; + nta_incoming_t *irq = rel->rel_irq; nta_incoming_t *pr_irq; int status; - for (rel = irq->irq_reliable; rel; rel = rel->rel_next) - if (rel->rel_pracked) - return -1; - else if (rel->rel_rseq == rack->ra_response) - break; - - if (!rel) - return -1; /* Process normally */ - rel->rel_pracked = 1; msg_ref_destroy(rel->rel_unsent), rel->rel_unsent = NULL; diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/test_nta.c b/libs/sofia-sip/libsofia-sip-ua/nta/test_nta.c index 8314f8279e..1246e2925b 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nta/test_nta.c +++ b/libs/sofia-sip/libsofia-sip-ua/nta/test_nta.c @@ -176,10 +176,13 @@ struct agent_t { msg_t *ag_probe_msg; + su_sockaddr_t ag_su_nta[1]; + socklen_t ag_su_nta_len; /* Dummy servers */ char const *ag_sink_port; su_socket_t ag_sink_socket, ag_down_socket; + su_wait_t ag_sink_wait[1]; }; static int test_init(agent_t *ag, char const *resolv_conf); @@ -558,8 +561,11 @@ int test_init(agent_t *ag, char const *resolv_conf) TEST_1(bind(s, &su.su_sa, sulen) < 0 ? (perror("bind"), 0) : 1); TEST_1(getsockname(s, &su.su_sa, &sulen) == 0); - ag->ag_sink_port = su_sprintf(ag->ag_home, "%u", ntohs(su.su_sin.sin_port)); ag->ag_sink_socket = s; + su_wait_init(ag->ag_sink_wait); + su_wait_create(ag->ag_sink_wait, ag->ag_sink_socket, SU_WAIT_IN); + + ag->ag_sink_port = su_sprintf(ag->ag_home, "%u", ntohs(su.su_sin.sin_port)); /* Down server */ s = su_socket(af, SOCK_STREAM, 0); TEST_1(s != INVALID_SOCKET); @@ -591,13 +597,38 @@ int test_init(agent_t *ag, char const *resolv_conf) sip_to_t to[1]; sip_contact_t m[1]; + su_sockaddr_t *su = ag->ag_su_nta; + sip_from_init(from); sip_to_init(to); sip_contact_init(m); + TEST_1(ag->ag_contact = nta_agent_contact(ag->ag_agent)); *m->m_url = *ag->ag_contact->m_url; + + if (host_is_ip4_address(m->m_url->url_host)) { + inet_pton(su->su_family = AF_INET, + m->m_url->url_host, + &su->su_sin.sin_addr); + ag->ag_su_nta_len = (sizeof su->su_sin); + } + else { + TEST_1(host_is_ip_address(m->m_url->url_host)); + inet_pton(su->su_family = AF_INET6, + m->m_url->url_host, + &su->su_sin6.sin6_addr); + ag->ag_su_nta_len = (sizeof su->su_sin6); + } + + su->su_port = htons(5060); + if (m->m_url->url_port && strlen(m->m_url->url_port)) { + unsigned long port = strtoul(m->m_url->url_port, NULL, 10); + su->su_port = htons(port); + } + TEST_1(su->su_port != 0); + m->m_url->url_user = "bob"; TEST_1(ag->ag_m_bob = sip_contact_dup(ag->ag_home, m)); @@ -651,11 +682,12 @@ int test_init(agent_t *ag, char const *resolv_conf) NTATAG_ALIASES(ag->ag_aliases), NTATAG_REL100(1), NTATAG_UA(1), + NTATAG_MERGE_482(1), NTATAG_USE_NAPTR(1), NTATAG_USE_SRV(1), NTATAG_MAX_FORWARDS(20), TAG_END()); - TEST(err, 6); + TEST(err, 7); err = nta_agent_set_params(ag->ag_agent, NTATAG_ALIASES(ag->ag_aliases), @@ -723,7 +755,11 @@ int test_deinit(agent_t *ag) nta_agent_destroy(ag->ag_agent); su_root_destroy(ag->ag_root); - su_free(ag->ag_home, (void *)ag->ag_sink_port), ag->ag_sink_port = NULL; + if (ag->ag_sink_port) { + su_free(ag->ag_home, (void *)ag->ag_sink_port), ag->ag_sink_port = NULL; + su_wait_destroy(ag->ag_sink_wait); + su_close(ag->ag_sink_socket); + } free(ag->ag_mclass), ag->ag_mclass = NULL; @@ -1206,6 +1242,9 @@ int test_tports(agent_t *ag) ctx->c_extra = &used_tport; + *url = *ag->ag_aliases->m_url; + url->url_user = "alice"; + TEST(tport_shutdown(tcp_tport, 1), 0); /* Not going to send anymore */ TEST_1(pl = test_payload(ag->ag_home, 512)); @@ -2217,6 +2256,302 @@ int test_dialog(agent_t *ag) END(); } +/* Test merging */ + +int test_merging(agent_t *ag) +{ + BEGIN(); + + /* + * Test merging: send two messages with same + * from tag/call-id/cseq number to nta, + * expect 200 and 408. + */ + + char const rfc3261prefix[] = "z9hG4bK"; + + char const template[] = + "%s " URL_PRINT_FORMAT " SIP/2.0\r\n" + "Via: SIP/2.0/UDP 127.0.0.1:%s;branch=%s.%p\r\n" + "Via: SIP/2.0/TCP fake.address.for.via.example.net;branch=z9hG4bK.%p\r\n" + "CSeq: %u %s\r\n" + "Call-ID: dfsjfhsduifhsjfsfjkfsd.%p@dfsdhfsjkhsdjk\r\n" + "From: Evil Forker ;tag=test_nta-%s\r\n" + "To: Bob the Builder %s\r\n" + "Content-Length: 0\r\n" + "\r\n"; + + url_t u1[1], u2[2]; + + char m1[1024], m2[1024]; + char r1[1024], r2[1024]; + + size_t len, l1, l2; + su_sockaddr_t *su = ag->ag_su_nta; + socklen_t sulen = ag->ag_su_nta_len; + int n; + + /* Empty sink socket */ + while (su_wait(ag->ag_sink_wait, 1, 0) == 0) + su_recv(ag->ag_sink_socket, m1, sizeof m1, MSG_TRUNC); + + { + /* RFC 3261 8.2.2.2 Merged Requests: + + If the request has no tag in the To header field, the UAS core MUST + check the request against ongoing transactions. If the From tag, + Call-ID, and CSeq exactly match those associated with an ongoing + transaction, but the request does not match that transaction (based + on the matching rules in Section 17.2.3), the UAS core SHOULD + generate a 482 (Loop Detected) response and pass it to the server + transaction. + */ + nta_leg_bind(ag->ag_server_leg, leg_callback_200, ag); + ag->ag_expect_leg = ag->ag_server_leg; + ag->ag_latest_leg = NULL; + + *u1 = *ag->ag_m_bob->m_url; + snprintf(m1, sizeof m1, + template, + "MESSAGE", URL_PRINT_ARGS(u1), + /* Via */ ag->ag_sink_port, rfc3261prefix, (void *)m1, + /* 2nd Via */ (void *)ag, + /* CSeq */ 13, "MESSAGE", + /* Call-ID */ (void *)ag, + /* From tag */ "2.5.1", + /* To tag */ ""); + l1 = strlen(m1); + + *u2 = *ag->ag_m_bob->m_url; + + snprintf(m2, sizeof m2, + template, + "MESSAGE", URL_PRINT_ARGS(u2), + /* Via */ ag->ag_sink_port, rfc3261prefix, (void *)m2, + /* 2nd Via */ (void *)ag, + /* CSeq */ 13, "MESSAGE", + /* Call-ID */ (void *)ag, + /* From tag */ "2.5.1", + /* To tag */ ""); + l2 = strlen(m2); + + TEST_1((size_t)su_sendto(ag->ag_sink_socket, m1, l1, 0, su, sulen) == l1); + TEST_1((size_t)su_sendto(ag->ag_sink_socket, m2, l2, 0, su, sulen) == l2); + + for (n = 0; n < 2; ) { + su_root_step(ag->ag_root, 10L); + if (su_wait(ag->ag_sink_wait, 1, 0) == 0) { + if (n == 0) + su_recv(ag->ag_sink_socket, r1, sizeof r1, MSG_TRUNC); + else + su_recv(ag->ag_sink_socket, r2, sizeof r2, MSG_TRUNC); + n++; + } + } + len = strlen("SIP/2.0 200 "); + TEST_1(memcmp(r1, "SIP/2.0 200 ", len) == 0); + TEST_1(memcmp(r2, "SIP/2.0 482 ", len) == 0); + + TEST_P(ag->ag_latest_leg, ag->ag_server_leg); + } + + { + /* + * Check that request with same call-id, cseq and from-tag + * are not merged if the method is different. + */ + nta_leg_bind(ag->ag_server_leg, leg_callback_200, ag); + ag->ag_expect_leg = ag->ag_server_leg; + ag->ag_latest_leg = NULL; + + *u1 = *ag->ag_m_bob->m_url; + snprintf(m1, sizeof m1, + template, + "MESSAGE", URL_PRINT_ARGS(u1), + /* Via */ ag->ag_sink_port, rfc3261prefix, (void *)m1, + /* 2nd Via */ (void *)ag, + /* CSeq */ 14, "MESSAGE", + /* Call-ID */ (void *)ag, + /* From tag */ "2.5.2", + /* To tag */ ""); + l1 = strlen(m1); + + *u2 = *ag->ag_m_bob->m_url; + + snprintf(m2, sizeof m2, + template, + "OPTIONS", URL_PRINT_ARGS(u2), + /* Via */ ag->ag_sink_port, rfc3261prefix, (void *)m2, + /* 2nd Via */ (void *)ag, + /* CSeq */ 14, "OPTIONS", + /* Call-ID */ (void *)ag, + /* From tag */ "2.5.2", + /* To tag */ ""); + l2 = strlen(m2); + + TEST_1((size_t)su_sendto(ag->ag_sink_socket, m1, l1, 0, su, sulen) == l1); + TEST_1((size_t)su_sendto(ag->ag_sink_socket, m2, l2, 0, su, sulen) == l2); + + for (n = 0; n < 2; ) { + su_root_step(ag->ag_root, 10L); + if (su_wait(ag->ag_sink_wait, 1, 0) == 0) { + if (n == 0) + su_recv(ag->ag_sink_socket, r1, sizeof r1, MSG_TRUNC); + else + su_recv(ag->ag_sink_socket, r2, sizeof r2, MSG_TRUNC); + n++; + } + } + + len = strlen("SIP/2.0 200 "); + TEST_1(memcmp(r1, "SIP/2.0 200 ", len) == 0); + TEST_1(memcmp(r2, "SIP/2.0 482 ", len) != 0); + + TEST_P(ag->ag_latest_leg, ag->ag_server_leg); + } + + { + /* test with rfc2543 */ + + snprintf(m1, sizeof m1, + template, + "MASSAGE", URL_PRINT_ARGS(u1), + /* Via */ ag->ag_sink_port, "0.", (void *)0, + /* 2nd Via */ (void *)ag, + /* CSeq */ 14, "MASSAGE", + /* Call-ID */ (void *)(ag + 1), + /* From tag */ "2.5.3", + /* To tag */ ""); + l1 = strlen(m1); + + u2->url_user = "bob+2"; + + snprintf(m2, sizeof m2, + template, + "MASSAGE", URL_PRINT_ARGS(u2), + /* Via */ ag->ag_sink_port, "0.", (void *)0, + /* 2nd Via */ (void *)ag, + /* CSeq */ 14, "MASSAGE", + /* Call-ID */ (void *)(ag + 1), + /* From tag */ "2.5.3", + /* To tag */ ""); + l2 = strlen(m2); + + TEST_1((size_t)su_sendto(ag->ag_sink_socket, m1, l1, 0, su, sulen) == l1); + TEST_1((size_t)su_sendto(ag->ag_sink_socket, m2, l2, 0, su, sulen) == l2); + + for (n = 0; n < 2; ) { + su_root_step(ag->ag_root, 10L); + if (su_wait(ag->ag_sink_wait, 1, 0) == 0) { + if (n == 0) + su_recv(ag->ag_sink_socket, r1, sizeof r1, MSG_TRUNC); + else + su_recv(ag->ag_sink_socket, r2, sizeof r2, MSG_TRUNC); + n++; + } + } + l1 = strlen("SIP/2.0 200 "); + TEST_1(memcmp(r1, "SIP/2.0 200 ", l1) == 0); + TEST_1(memcmp(r2, "SIP/2.0 482 ", l1) == 0); + + TEST_P(ag->ag_latest_leg, ag->ag_server_leg); + } + + { + /* test with to-tag */ + + snprintf(m1, sizeof m1, + template, + "MESSAGE", URL_PRINT_ARGS(u1), + /* Via */ ag->ag_sink_port, rfc3261prefix, (void *)m1, + /* 2nd Via */ (void *)ag, + /* CSeq */ 15, "MESSAGE", + /* Call-ID */ (void *)(ag + 2), + /* From tag */ "2.5.4", + /* To tag */ ";tag=in-dialog"); + l1 = strlen(m1); + + u2->url_user = "bob+2"; + + snprintf(m2, sizeof m2, + template, + "MESSAGE", URL_PRINT_ARGS(u2), + /* Via */ ag->ag_sink_port, rfc3261prefix, (void *)m2, + /* 2nd Via */ (void *)ag, + /* CSeq */ 15, "MESSAGE", + /* Call-ID */ (void *)(ag + 2), + /* From tag */ "2.5.4", + /* To tag */ ";tag=in-dialog"); + l2 = strlen(m2); + + TEST_1((size_t)su_sendto(ag->ag_sink_socket, m1, l1, 0, su, sulen) == l1); + TEST_1((size_t)su_sendto(ag->ag_sink_socket, m2, l2, 0, su, sulen) == l2); + + for (n = 0; n < 2; ) { + su_root_step(ag->ag_root, 10L); + if (su_wait(ag->ag_sink_wait, 1, 0) == 0) { + if (n == 0) + su_recv(ag->ag_sink_socket, r1, sizeof r1, MSG_TRUNC); + else + su_recv(ag->ag_sink_socket, r2, sizeof r2, MSG_TRUNC); + n++; + } + } + l1 = strlen("SIP/2.0 200 "); + TEST_1(memcmp(r1, "SIP/2.0 200 ", l1) == 0); + TEST_1(memcmp(r2, "SIP/2.0 482 ", l1) != 0); + + TEST_P(ag->ag_latest_leg, ag->ag_server_leg); + } + + { + /* test with rfc2543 and to-tag */ + + snprintf(m1, sizeof m1, + template, + "MESSAGE", URL_PRINT_ARGS(u1), + /* Via */ ag->ag_sink_port, "0.", (void *)0, + /* 2nd Via */ (void *)ag, + /* CSeq */ 15, "MESSAGE", + /* Call-ID */ (void *)(ag + 2), + /* From tag */ "2.5.5", + /* To tag */ ";tag=in-dialog"); + l1 = strlen(m1); + + snprintf(m2, sizeof m2, + template, + "MESSAGE", URL_PRINT_ARGS(u2), + /* Via */ ag->ag_sink_port, "0.", (void *)0, + /* 2nd Via */ (void *)ag, + /* CSeq */ 15, "MESSAGE", + /* Call-ID */ (void *)(ag + 2), + /* From tag */ "2.5.5", + /* To tag */ ";tag=in-dialog"); + l2 = strlen(m2); + + TEST_1((size_t)su_sendto(ag->ag_sink_socket, m1, l1, 0, su, sulen) == l1); + TEST_1((size_t)su_sendto(ag->ag_sink_socket, m2, l2, 0, su, sulen) == l2); + + for (n = 0; n < 2; ) { + su_root_step(ag->ag_root, 10L); + if (su_wait(ag->ag_sink_wait, 1, 0) == 0) { + if (n == 0) + su_recv(ag->ag_sink_socket, r1, sizeof r1, MSG_TRUNC); + else + su_recv(ag->ag_sink_socket, r2, sizeof r2, MSG_TRUNC); + n++; + } + } + l1 = strlen("SIP/2.0 200 "); + TEST_1(memcmp(r1, "SIP/2.0 200 ", l1) == 0); + TEST_1(memcmp(r2, "SIP/2.0 482 ", l1) != 0); + + TEST_P(ag->ag_latest_leg, ag->ag_server_leg); + } + + END(); +} + /* ---------------------------------------------------------------------- */ /* Test INVITE, dialogs */ @@ -3485,6 +3820,7 @@ int main(int argc, char *argv[]) if (retval == 0) { retval |= test_bad_messages(ag); SINGLE_FAILURE_CHECK(); retval |= test_reinit(ag); SINGLE_FAILURE_CHECK(); + retval |= test_merging(ag); SINGLE_FAILURE_CHECK(); retval |= test_tports(ag); SINGLE_FAILURE_CHECK(); retval |= test_destroy_incoming(ag); SINGLE_FAILURE_CHECK(); retval |= test_resolv(ag, argv[i]); SINGLE_FAILURE_CHECK(); diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_notifier.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_notifier.c index 723c1a2f02..26e4ccf9b0 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_notifier.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/nua_notifier.c @@ -498,10 +498,18 @@ static int nua_notify_client_init(nua_client_request_t *cr, else if (nu->nu_requested >= now + expires) nu->nu_expires = nu->nu_requested = now + expires; } + else { + if (nu->nu_requested >= nu->nu_expires) + nu->nu_expires = nu->nu_requested; + } + } else { enum nua_substate substate = nu->nu_substate; + if (nu->nu_requested >= nu->nu_expires) + nu->nu_expires = nu->nu_requested; + if (nu->nu_expires > now) { tagi_t const *t = tl_find_last(tags, nutag_substate); if (t) @@ -794,8 +802,11 @@ static int nua_notify_usage_shutdown(nua_handle_t *nh, return 0; } else { - if (nua_client_create(nh, nua_r_notify, - &nua_notify_client_methods, NULL) >= 0) + if (nua_client_tcreate(nh, nua_r_notify, + &nua_notify_client_methods, + SIPTAG_EVENT(du->du_event), + NUTAG_SUBSTATE(nua_substate_terminated), + TAG_END()) >= 0) return 0; } diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c index f2214e8f47..aa2a2d9b21 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c @@ -2023,7 +2023,8 @@ int nua_invite_server_respond(nua_server_request_t *sr, tagi_t const *tags) reliable = 1, early_answer = 1; } else if (!nh->nh_soa || sr->sr_status >= 300) { - + if (sr->sr_neutral) + return nua_base_server_respond(sr, tags); } else if (tags && 100 < sr->sr_status && sr->sr_status < 200 && !NHP_ISSET(nh->nh_prefs, early_answer)) { diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_subnotref.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_subnotref.c index 4f0e5b3b60..948e2a2218 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_subnotref.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/nua_subnotref.c @@ -581,7 +581,7 @@ int nua_notify_server_preprocess(nua_server_request_t *sr) sr->sr_usage = du; eu = nua_dialog_usage_private(du); assert(eu); eu->eu_notified++; - if (!o->o_id) + if (!o || !o->o_id) eu->eu_no_id = 1; if (subs == NULL) { diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/outbound.c b/libs/sofia-sip/libsofia-sip-ua/nua/outbound.c index 73a41fa495..1d2244e5cf 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/outbound.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/outbound.c @@ -503,13 +503,13 @@ int outbound_nat_detect(outbound_t *ob, } if (!nat_detected) { - SU_DEBUG_1(("outbound(%p): detected NAT: %s != %s\n", + SU_DEBUG_5(("outbound(%p): detected NAT: %s != %s\n", (void *)ob->ob_owner, v->v_host, received)); if (ob->ob_oo && ob->ob_oo->oo_status) ob->ob_oo->oo_status(ob->ob_owner, ob, 101, "NAT detected", TAG_END()); } else { - SU_DEBUG_1(("outbound(%p): NAT binding changed: " + SU_DEBUG_5(("outbound(%p): NAT binding changed: " "[%s]:%s != [%s]:%s\n", (void *)ob->ob_owner, nat_detected, nat_port, received, rport)); if (ob->ob_oo && ob->ob_oo->oo_status) @@ -860,8 +860,6 @@ static int response_to_keepalive_options(outbound_t *ob, else loglevel = 3, failed = 1; - loglevel = 1; /* XXX ... for now */ - if (loglevel >= SU_LOG->log_level) { sip_contact_t const *m = ob->ob_rcontact; @@ -886,7 +884,7 @@ static int response_to_keepalive_options(outbound_t *ob, ob->ob_oo->oo_probe_error(ob->ob_owner, ob, status, phrase, TAG_END()); } else if (status == 408) { - SU_DEBUG_1(("outbound(%p): keepalive timeout\n", (void *)ob->ob_owner)); + SU_DEBUG_3(("outbound(%p): keepalive timeout\n", (void *)ob->ob_owner)); ob->ob_oo->oo_keepalive_error(ob->ob_owner, ob, status, phrase, TAG_END()); return 0; } @@ -979,7 +977,7 @@ int outbound_process_request(outbound_t *ob, return 0; if (ob->ob_keepalive.validating) { - SU_DEBUG_1(("outbound(%p): registration check OPTIONS received\n", + SU_DEBUG_5(("outbound(%p): registration check OPTIONS received\n", (void *)ob->ob_owner)); ob->ob_keepalive.validated = 1; } diff --git a/libs/sofia-sip/libsofia-sip-ua/stun/stun.c b/libs/sofia-sip/libsofia-sip-ua/stun/stun.c index 888a246408..39213d53ed 100644 --- a/libs/sofia-sip/libsofia-sip-ua/stun/stun.c +++ b/libs/sofia-sip/libsofia-sip-ua/stun/stun.c @@ -1895,23 +1895,23 @@ static int process_test_lifetime(stun_request_t *req, stun_msg_t *binding_respon if ((req->sr_state == stun_req_timeout) && (req->sr_from_y == -1)) { SU_DEBUG_0(("%s: lifetime determination failed.\n", __func__)); sd->sd_state = stun_discovery_timeout; + req->sr_state = stun_req_dispose_me; /* Use per discovery specific callback */ if (sd->sd_callback) sd->sd_callback(sd->sd_magic, sh, sd, action, sd->sd_state); - req->sr_state = stun_req_dispose_me; return 0; } if (abs(sd->sd_lt_cur - sd->sd_lt) <= STUN_LIFETIME_CI) { sd->sd_state = stun_discovery_done; + req->sr_state = stun_req_dispose_me; /* Use per discovery specific callback */ if (sd->sd_callback) sd->sd_callback(sd->sd_magic, sh, sd, action, sd->sd_state); - req->sr_state = stun_req_dispose_me; return 0; } @@ -1998,12 +1998,11 @@ static int action_bind(stun_request_t *req, stun_msg_t *binding_response) memcpy(sd->sd_addr_seen_outside, sa, sizeof(su_sockaddr_t)); sd->sd_state = stun_discovery_done; + req->sr_state = stun_req_dispose_me; if (sd->sd_callback) sd->sd_callback(sd->sd_magic, sh, sd, action, sd->sd_state); - req->sr_state = stun_req_dispose_me; - return 0; } @@ -2053,9 +2052,9 @@ static void priv_mark_discovery_done(stun_discovery_t *sd, stun_request_t *req) { sd->sd_state = stun_discovery_done; + req->sr_state = stun_req_dispose_me; if (sd->sd_callback) sd->sd_callback(sd->sd_magic, sh, sd, action, sd->sd_state); - req->sr_state = stun_req_dispose_me; } /** @@ -2290,12 +2289,12 @@ static void stun_sendto_timer_cb(su_root_magic_t *magic, switch (action) { case stun_action_binding_request: sd->sd_state = stun_discovery_timeout; + req->sr_state = stun_req_dispose_me; /* Use per discovery specific callback */ if (sd->sd_callback) sd->sd_callback(sd->sd_magic, sh, sd, action, sd->sd_state); - req->sr_state = stun_req_dispose_me; break; case stun_action_test_nattype: diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/tport_tag.c b/libs/sofia-sip/libsofia-sip-ua/tport/tport_tag.c index 3b07eee841..723988f945 100644 --- a/libs/sofia-sip/libsofia-sip-ua/tport/tport_tag.c +++ b/libs/sofia-sip/libsofia-sip-ua/tport/tport_tag.c @@ -311,6 +311,10 @@ tag_typedef_t tptag_debug_drop = UINTTAG_TYPEDEF(debug_drop); * * This is a parameter suitable for tuning. * + * On Linux systems, the default value for receive buffer is set with + * the sysctl "net.core.rmem_default", and the maximum value is set with + * the sysctl "net.core.rmem_max". + * * Use with tport_tbind(), nua_create(), nta_agent_create(), * nta_agent_add_tport(), nth_engine_create(), or initial nth_site_create(). */ @@ -322,6 +326,10 @@ tag_typedef_t tptag_udp_rmem = UINTTAG_TYPEDEF(udp_rmem); * * This is a parameter suitable for tuning. * + * On Linux systems, the default value for receive buffer is set with + * the sysctl "net.core.wmem_default", and the maximum value is set with + * the sysctl "net.core.wmem_max". + * * Use with tport_tbind(), nua_create(), nta_agent_create(), * nta_agent_add_tport(), nth_engine_create(), or initial nth_site_create(). */ diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_udp.c b/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_udp.c index d843fb7cfb..a4cbc75221 100644 --- a/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_udp.c +++ b/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_udp.c @@ -35,6 +35,7 @@ #include "config.h" #include "tport_internal.h" +#include "sofia-sip/hostdomain.h" #if HAVE_IP_RECVERR || HAVE_IPV6_RECVERR #include @@ -113,6 +114,8 @@ int tport_udp_init_primary(tport_primary_t *pri, unsigned rmem = 0, wmem = 0; int events = SU_WAIT_IN; int s; + su_sockaddr_t *su = (su_sockaddr_t *)ai->ai_addr; + int const one = 1; (void)one; s = su_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (s == INVALID_SOCKET) @@ -125,20 +128,51 @@ int tport_udp_init_primary(tport_primary_t *pri, tport_set_tos(s, ai, pri->pri_params->tpp_tos); +#if HAVE_IP_ADD_MEMBERSHIP + if (ai->ai_family == AF_INET && + IN_MULTICAST(ntohl(su->su_sin.sin_addr.s_addr))) { + /* Try to join to the multicast group */ + /* Bind to the SIP address like + */ + struct ip_mreq imr[1]; + struct in_addr iface; + + memset(imr, 0, sizeof imr); + + imr->imr_multiaddr = su->su_sin.sin_addr; + + if (host_is_ip4_address(tpn->tpn_canon) && + inet_pton(AF_INET, tpn->tpn_canon, &iface) > 0) { + imr->imr_interface = iface; + } + + if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, imr, (sizeof imr)) < 0) { + SU_DEBUG_3(("setsockopt(%s): %s\n", + "IP_ADD_MEMBERSHIP", su_strerror(su_errno()))); + } +#if HAVE_IP_MULTICAST_LOOP + else + if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, &one, sizeof one) < 0) { + SU_DEBUG_3(("setsockopt(%s): %s\n", + "IP_MULTICAST_LOOP", su_strerror(su_errno()))); + } +#endif + } +#endif + #if HAVE_IP_RECVERR if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6) { - int const one = 1; - if (setsockopt(s, SOL_IP, IP_RECVERR, &one, sizeof(one)) < 0) { + if (setsockopt(s, IPPROTO_IP, IP_RECVERR, &one, sizeof(one)) < 0) { if (ai->ai_family == AF_INET) - SU_DEBUG_3(("setsockopt(IPVRECVERR): %s\n", su_strerror(su_errno()))); + SU_DEBUG_3(("setsockopt(%s): %s\n", + "IPVRECVERR", su_strerror(su_errno()))); } events |= SU_WAIT_ERR; } #endif #if HAVE_IPV6_RECVERR if (ai->ai_family == AF_INET6) { - int const one = 1; - if (setsockopt(s, SOL_IPV6, IPV6_RECVERR, &one, sizeof(one)) < 0) + if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVERR, &one, sizeof(one)) < 0) SU_DEBUG_3(("setsockopt(IPV6_RECVERR): %s\n", su_strerror(su_errno()))); events |= SU_WAIT_ERR; } @@ -150,12 +184,18 @@ int tport_udp_init_primary(tport_primary_t *pri, TAG_END()); if (rmem != 0 && +#if HAVE_SO_RCVBUFFORCE + setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, (void *)&rmem, sizeof rmem) < 0 && +#endif setsockopt(s, SOL_SOCKET, SO_RCVBUF, (void *)&rmem, sizeof rmem) < 0) { SU_DEBUG_3(("setsockopt(SO_RCVBUF): %s\n", su_strerror(su_errno()))); } if (wmem != 0 && +#if HAVE_SO_SNDBUFFORCE + setsockopt(s, SOL_SOCKET, SO_SNDBUFFORCE, (void *)&wmem, sizeof wmem) < 0 && +#endif setsockopt(s, SOL_SOCKET, SO_SNDBUF, (void *)&wmem, sizeof wmem) < 0) { SU_DEBUG_3(("setsockopt(SO_SNDBUF): %s\n", su_strerror(su_errno()))); @@ -409,10 +449,10 @@ int tport_udp_error(tport_t const *self, su_sockaddr_t name[1]) for (c = CMSG_FIRSTHDR(msg); c; c = CMSG_NXTHDR(msg, c)) { if (0 #if HAVE_IP_RECVERR - || (c->cmsg_level == SOL_IP && c->cmsg_type == IP_RECVERR) + || (c->cmsg_level == IPPROTO_IP && c->cmsg_type == IP_RECVERR) #endif #if HAVE_IPV6_RECVERR - || (c->cmsg_level == SOL_IPV6 && c->cmsg_type == IPV6_RECVERR) + || (c->cmsg_level == IPPROTO_IPV6 && c->cmsg_type == IPV6_RECVERR) #endif ) { char info[128]; diff --git a/libs/sofia-sip/m4/sac-su2.m4 b/libs/sofia-sip/m4/sac-su2.m4 index 0f4d6a3640..f85146eb82 100644 --- a/libs/sofia-sip/m4/sac-su2.m4 +++ b/libs/sofia-sip/m4/sac-su2.m4 @@ -273,6 +273,28 @@ AC_DEFINE([HAVE_MSG_TRUNC],1,[Define to 1 if you have MSG_TRUNC flag]),,[ #include #include ]) +AC_CHECK_DECL([SO_RCVBUFFORCE], +AC_DEFINE([HAVE_SO_RCVBUFFORCE],1,[Define to 1 if you have socket option SO_RCVBUFFORCE]),,[ +#include +#include ]) + +AC_CHECK_DECL([SO_SNDBUFFORCE], +AC_DEFINE([HAVE_SO_SNDBUFFORCE],1,[Define to 1 if you have socket option SO_SNDBUFFORCE]),,[ +#include +#include ]) + +AC_CHECK_DECL([IP_ADD_MEMBERSHIP], +AC_DEFINE([HAVE_IP_ADD_MEMBERSHIP],1,[Define to 1 if you have IP_ADD_MEMBERSHIP]),,[ +#include +#include +#include ]) + +AC_CHECK_DECL([IP_MULTICAST_LOOP], +AC_DEFINE([HAVE_IP_MULTICAST_LOOP],1,[Define to 1 if you have IP_MULTICAST_LOOP]),,[ +#include +#include +#include ]) + AC_CACHE_CHECK([for struct addrinfo], [ac_cv_struct_addrinfo],[ ac_cv_struct_addrinfo=no diff --git a/libs/sofia-sip/libsofia-sip-ua/docs/hide_emails.sh b/libs/sofia-sip/scripts/hide_emails.sh similarity index 100% rename from libs/sofia-sip/libsofia-sip-ua/docs/hide_emails.sh rename to libs/sofia-sip/scripts/hide_emails.sh diff --git a/libs/sofia-sip/tests/check_sofia.c b/libs/sofia-sip/tests/check_sofia.c index f8fd707216..c2c528e27d 100644 --- a/libs/sofia-sip/tests/check_sofia.c +++ b/libs/sofia-sip/tests/check_sofia.c @@ -51,7 +51,9 @@ int main(int argc, char *argv[]) suite = suite_for_nua(); runner = srunner_create(suite); - srunner_set_xml(runner, "/tmp/result.xml"); + if (argv[1]) { + srunner_set_xml(runner, argv[1]); + } srunner_run_all(runner, CK_NORMAL); failed = srunner_ntests_failed(runner);