Merge current sofia-sip darcs tree:

Thu Dec 13 09:15:04 EST 2007  Pekka.Pessi@nokia.com
  * libsofia-sip-ua/docs/hide_emails.sh: moved to scripts/ subdir

Thu Dec 13 09:15:34 EST 2007  Pekka.Pessi@nokia.com
  * check_sofia.c: pass xml result file as optional parameter to check_sofia

Thu Dec 20 08:13:37 EST 2007  Pekka.Pessi@nokia.com
  * stun.c: try to avoid using stun handle after returning from discovery callback
  
  Crash reported and partial patch by Daniele Rondina.

Thu Jan  3 07:11:27 EST 2008  Pekka.Pessi@nokia.com
  * tport_type_udp.c: using SO_RCVBUFFORCE and SO_SNDBUFFORCE to set rmem/wmem on udp sockets
  
  Referring reader to Linux sysctls to TPTAG_UDP_RMEM and TPTAG_UDP_WMEM
  documentation.

Thu Jan  3 07:11:47 EST 2008  Pekka.Pessi@nokia.com
  * m4/sac-su2.m4: checks for SO_RCVBUFFORCE and SO_SNDBUFFORCE

Thu Jan  3 08:19:04 EST 2008  Pekka.Pessi@nokia.com
  * nta.c: calculate next timeout only after completing current timeout
    
  Thanks to Mike Jerris for reporting this problem.

Thu Jan  3 11:02:11 EST 2008  Pekka.Pessi@nokia.com
  * sac-su2.m4: checking for IP_ADD_MEMBERSHIP and IP_MULTICAST_LOOP

Thu Jan  3 12:08:39 EST 2008  Pekka.Pessi@nokia.com
  * tport_type_udp.c: when binding to multicast address, join to the group, too.
  
  Use "canonic" IP address (from host-part of the SIP URI) to specify
  interface.

Mon Nov 19 15:01:09 EST 2007  Pekka Pessi <first.lastname@nokia.com>
  * tport_type_udp.c: made IP_ADD_MEMBERSHIP as portable

Fri Jan  4 13:19:01 EST 2008  Pekka.Pessi@nokia.com
  * test_nta.c: added check for request merging (with both 3261 and 2543 proxies)

Fri Jan  4 13:20:35 EST 2008  Pekka.Pessi@nokia.com
  * nta.c: fixed request merging with RFC 2543 proxies
    
  Updated matching of PRACKs with outstanding 100rel, too.

Fri Jan  4 15:27:01 EST 2008  Pekka.Pessi@nokia.com
  * nta.c: follow more closely RFC 3261 request matching rules

Fri Jan  4 15:31:22 EST 2008  Pekka.Pessi@nokia.com
  * nua_session.c: do not clear soa when an overlapping INVITE is received
  
Fri Jan  4 15:32:58 EST 2008  Pekka.Pessi@nokia.com
  * nua/outbound.c: reduce logging

Fri Jan  4 16:51:00 EST 2008  Pekka.Pessi@nokia.com
  * nua_subnotref.c: accept NOTIFY without Event header

Fri Jan  4 16:53:20 EST 2008  Pekka.Pessi@nokia.com
  * nua_notifier.c: fix problem handing expiration time if NOTIFY is sent before SUBSCRIBE has been responded

Fri Jan  4 16:54:08 EST 2008  Pekka.Pessi@nokia.com
  * nua_notifier.c: allow notifier handle to be shut down if SUBSCRIBE has been accpeted but no NOTIFY has been sent



git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@7109 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Michael Jerris 2008-01-06 20:15:11 +00:00
parent 73cbaf9eb8
commit d93a42df14
15 changed files with 678 additions and 244 deletions

View File

@ -1 +1 @@
Thu Oct 11 15:56:47 EDT 2007
Sun Jan 6 15:11:42 EST 2008

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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 <sip:evel@forker.com>;tag=test_nta-%s\r\n"
"To: Bob the Builder <sip:bob@example.net>%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();

View File

@ -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;
}

View File

@ -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)) {

View File

@ -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) {

View File

@ -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;
}

View File

@ -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:

View File

@ -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().
*/

View File

@ -35,6 +35,7 @@
#include "config.h"
#include "tport_internal.h"
#include "sofia-sip/hostdomain.h"
#if HAVE_IP_RECVERR || HAVE_IPV6_RECVERR
#include <linux/types.h>
@ -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
<sip:88.77.66.55:5060;maddr=224.0.1.75;transport=udp> */
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];

View File

@ -273,6 +273,28 @@ AC_DEFINE([HAVE_MSG_TRUNC],1,[Define to 1 if you have MSG_TRUNC flag]),,[
#include <sys/types.h>
#include <sys/socket.h>])
AC_CHECK_DECL([SO_RCVBUFFORCE],
AC_DEFINE([HAVE_SO_RCVBUFFORCE],1,[Define to 1 if you have socket option SO_RCVBUFFORCE]),,[
#include <sys/types.h>
#include <sys/socket.h>])
AC_CHECK_DECL([SO_SNDBUFFORCE],
AC_DEFINE([HAVE_SO_SNDBUFFORCE],1,[Define to 1 if you have socket option SO_SNDBUFFORCE]),,[
#include <sys/types.h>
#include <sys/socket.h>])
AC_CHECK_DECL([IP_ADD_MEMBERSHIP],
AC_DEFINE([HAVE_IP_ADD_MEMBERSHIP],1,[Define to 1 if you have IP_ADD_MEMBERSHIP]),,[
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>])
AC_CHECK_DECL([IP_MULTICAST_LOOP],
AC_DEFINE([HAVE_IP_MULTICAST_LOOP],1,[Define to 1 if you have IP_MULTICAST_LOOP]),,[
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>])
AC_CACHE_CHECK([for struct addrinfo],
[ac_cv_struct_addrinfo],[
ac_cv_struct_addrinfo=no

View File

@ -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);