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:
parent
73cbaf9eb8
commit
d93a42df14
|
@ -1 +1 @@
|
|||
Thu Oct 11 15:56:47 EDT 2007
|
||||
Sun Jan 6 15:11:42 EST 2008
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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().
|
||||
*/
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue