merge to sofia sip darcs tree. Includes multiple fixes and several merges of changes from the freeswitch tree back to darcs as follows:

Mon Nov 19 22:05:07 EST 2007  Pekka Pessi <first.lastname@nokia.com>
  * test_htable2.c: define struct before using it in prototypes

Fri Jan 11 09:12:01 EST 2008  Bernhard Suttner <suttner at comdasys.com>
  * Using # in SOATAG_HOLD to set media as inactive instead of sendonly

Fri Jan 11 09:15:18 EST 2008  Pekka.Pessi@nokia.com
  * soa_tag.c: documented SOATAG_HOLD() inactive mode

Fri Jan 11 09:28:46 EST 2008  Pekka.Pessi@nokia.com
  * su_addrinfo.c: if su_getaddrinfo() service is NULL, try both with "0" and NULL

Fri Jan 11 09:30:23 EST 2008  Pekka.Pessi@nokia.com
  * Makefile.am: added tests to DIST_SUBDIRS

Fri Jan 11 12:11:12 EST 2008  Pekka.Pessi@nokia.com
  * nta.c: NetModule hack re-prioritizing SRV records
  
  Original hack by Stefan Leuenberger <Stefan.Leuenberger@netmodule.com>.
  
  The hack reprioritizes the SRV records used with transaction in case a
  server refuses connection or it does not answer.

Fri Jan 11 12:12:23 EST 2008  Pekka.Pessi@nokia.com
  * sres.c, sres_cache.c: NetModule hack for re-prioritizing SRV records
    
  Original hack by Stefan Leuenberger <Stefan.Leuenberger@netmodule.com>.
  
  The hack reprioritizes the SRV records used with transaction in case a
  server refuses connection or it does not answer.
  
  New functions sres_cache_set_srv_priority() and
  sres_set_cached_srv_priority().
  
Fri Jan 11 12:15:19 EST 2008  Pekka.Pessi@nokia.com
  * Makefile.am: fixed dist target

Fri Jan 11 12:19:33 EST 2008  Pekka.Pessi@nokia.com
  * tport_internal.h: grammar in doc

Mon Jan 14 06:59:17 EST 2008  Pekka.Pessi@nokia.com
  * su.h: IPv6 fix for Vista SDK
    
  Patch by Michael Jerris

Wed Jan 16 13:20:47 EST 2008  Pekka.Pessi@nokia.com
  * nua: fix sf.net bug #1867753 (avoid duplicating initial route set)

Thu Jan 17 07:48:10 EST 2008  Pekka.Pessi@nokia.com
  * sres.c, sres_cache.c: documented sres_set_cached_srv_priority(), sres_cache_set_srv_priority()

Thu Jan 17 07:51:32 EST 2008  Pekka.Pessi@nokia.com
  * sofia-sip/su_wait.h, su_port.h, su_root.c: documented new functions and types for 1.12.8

Thu Jan 17 07:52:03 EST 2008  Pekka.Pessi@nokia.com
  * sofia-sip/htable2.h: marked new features for release 1.12.8

Thu Jan 17 07:52:33 EST 2008  Pekka.Pessi@nokia.com
  * su_alloc.c: marked new features for release 1.12.8.

Thu Jan 17 07:53:01 EST 2008  Pekka.Pessi@nokia.com
  * AUTHORS: updated

Thu Jan 17 07:53:21 EST 2008  Pekka.Pessi@nokia.com
  * RELEASE: added new features and bug fixes since 1.12.7

Thu Jan 17 07:55:18 EST 2008  Pekka.Pessi@nokia.com
  * libsofia-sip-ua/docs/Doxyfile.aliases: added @NEW_1_12_8 and @VERSION_1_12_8

Thu Jan 17 09:48:48 EST 2008  Pekka Pessi <Pekka.Pessi@nokia.com>
  * autogen.sh: use automake 1.9 unless otherwise specified

Thu Jan 17 11:40:46 EST 2008  Pekka Pessi <Pekka.Pessi@nokia.com>
  * soa_static.c: cleaned inactive hold, added tests

Thu Jan 17 11:41:54 EST 2008  Pekka Pessi <Pekka.Pessi@nokia.com>
  * Makefile.am: added hide_emails.sh to dist

Thu Jan 17 11:42:35 EST 2008  Pekka Pessi <Pekka.Pessi@nokia.com>
  * nua_stack.c: removed noisy debug message from nua_client_request_sendmsg()

Fri Jan 18 11:06:10 EST 2008  Pekka.Pessi@nokia.com
  * nua: Added NUA_ERROR_AT() macro
  
  Made internally generated 900 (and 904) response phrases unique as suggested
  by Jerry Richards.

Mon Jan 21 10:39:50 EST 2008  Stefan Knoblich
  * TLS debug cleanup

Mon Jan 21 12:05:38 EST 2008  Pekka.Pessi@nokia.com
  * tport: build fixes from Freeswitch

Mon Jan 21 12:14:25 EST 2008  Pekka.Pessi@nokia.com
  * su_global_log.c: disable warning on SU_DEBUG[] (Doxygen-only variable)
  
  Patch from Michael Jerris.

Mon Jan 21 12:15:19 EST 2008  Pekka.Pessi@nokia.com
  * sres.c: default log level to the same as SU_DEBUG define
  
  Patch by Michael Jerris

Mon Jan 21 12:16:39 EST 2008  Pekka.Pessi@nokia.com
  * stun.c: default log level to the same as SU_DEBUG define
  
  Patch by Michael Jerris

Mon Jan 21 12:45:04 EST 2008  Stefan Knoblich
  * TLS debug cleanup, 2/2.
  
  Silence openssl messages, part 2 of 2. Changed to TPORT_DEBUG=1 (thanks
  MikeJ). This one converts all ERR_print_errors() calls

Mon Jan 21 13:00:49 EST 2008  Pekka.Pessi@nokia.com
  * nua: removed asserts() on hairy dialog/request handling cases

Mon Jan 21 14:06:35 EST 2008  Pekka.Pessi@nokia.com
  * soa.c: using session state in soa_set_activity()
  
  The media mode bits are set using (local) session description instead of
  remote offer/answer when O/A has been completed.

Mon Jan 21 14:08:08 EST 2008  Pekka.Pessi@nokia.com
  * soa_static.c: soa_sdp_mode_set() now includes wanted media state in offer
  
  The wanted media state is based on original user SDP and SOATAG_HOLD()
  content. Removed soa_sdp_mode_set_is_needed(), using dry-run parameter
  instead.
  
Mon Jan 21 14:09:11 EST 2008  Pekka.Pessi@nokia.com
  * nua_subnotref.c: fixed REFER re-try case
  
  REFER trashed its dialog when it got retried if there was no other dialog
  usages.

Mon Jan 21 14:20:31 EST 2008  Pekka.Pessi@nokia.com
  * nua_stack.c: return specific error phrases from nua_client_init_request()
  
  As suggested by Jerry Richards.

Tue Jan 22 11:15:04 EST 2008  Pekka.Pessi@nokia.com
  * sip_util.c: updated sip_response_terminates_dialog() as per RFC 5057.
  
  Changes handling of 423 in case of SUBSCRIBE.

Tue Jan 22 11:34:01 EST 2008  Pekka.Pessi@nokia.com
  * conformance.docs: added RFC 5057 (sipping-dialogusage)

Tue Jan 22 11:34:16 EST 2008  Pekka.Pessi@nokia.com
  * test_auth_digest.c: testing empty realm

Tue Jan 22 11:35:44 EST 2008  Pekka.Pessi@nokia.com
  * test_soa.c: testing hold with inactive, offered mode and setting remote activity flags while in hold

Tue Jan 22 12:27:41 EST 2008  Pekka.Pessi@nokia.com
  * nta.c: fixed memory corruption in case sending ACK failed
  
  Thanks for Fabio Margarido for reporting this problem.

Tue Jan 22 12:49:02 EST 2008  Pekka.Pessi@nokia.com
  * nua/test_refer.c: run test_challenge_refer() only if we use proxy
  
  Test case is now more deterministic, too.

Tue Jan 22 12:51:59 EST 2008  Pekka.Pessi@nokia.com
  * docs/Makefile.am, docs/conformance.docs: fixed links to RFC 5057.

Tue Jan 22 13:57:38 EST 2008  Pekka.Pessi@nokia.com
  * sres: added ttl parameter to sres_set_cached_srv_priority() and sres_cache_set_srv_priority().

Tue Jan 22 13:59:44 EST 2008  Pekka.Pessi@nokia.com
  * nta.c: added NTATAG_GRAYLIST(). 
  
  Use NTATAG_GRAYLIST() as ttl value for sres_set_cached_srv_priority().

Tue Jan 22 14:04:29 EST 2008  Pekka.Pessi@nokia.com
  * RELEASE: updated.

Tue Jan 22 14:04:29 EST 2008  Pekka.Pessi@nokia.com
  * RELEASE: updated.

Wed Jan 23 06:56:11 EST 2008  Pekka.Pessi@nokia.com
  * sip_extra.c, sip_parser.c: updated documentation

Wed Jan 23 09:47:50 EST 2008  Pekka.Pessi@nokia.com
  * test_nta.c: fixed receiving with sink socket

Wed Jan 23 10:07:30 EST 2008  Pekka Pessi <Pekka.Pessi@nokia.com>
  * soa_static.c: fixed signedness error

Wed Jan 23 10:11:14 EST 2008  Pekka Pessi <Pekka.Pessi@nokia.com>
  * win32 project files: fixed slash direction

Wed Jan 23 10:13:00 EST 2008  Pekka Pessi <Pekka.Pessi@nokia.com>
  * torture_su.c: set blocking on

Wed Jan 23 10:13:36 EST 2008  Pekka Pessi <Pekka.Pessi@nokia.com>
  * test_tport.c: using blocking sockets in test_incomplete()

Wed Jan 23 11:01:11 EST 2008  Pekka.Pessi@nokia.com
  * nta.c: now using RFC3261-compliant dialog-matching

Wed Jan 23 11:05:23 EST 2008  Pekka.Pessi@nokia.com
  * nta.c: ignore tags in nta_leg_by_dialog() if they are empty strings

Wed Jan 23 11:05:58 EST 2008  Pekka.Pessi@nokia.com
  * nta.c: asserting in proper place when handling queue tail

Wed Jan 23 12:11:09 EST 2008  Pekka.Pessi@nokia.com
  * torture_sip.c: added tests for accessing other extra headers beside P-Asserted-Identity/P-Preferred-Identity

Wed Jan 23 13:08:55 EST 2008  Pekka.Pessi@nokia.com
  * nua: terminate dialog when redirected and re-establish it with new request

Wed Jan 23 13:18:16 EST 2008  Pekka.Pessi@nokia.com
  * test_100rel.c: added test for redirect after 100rel response.




git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@7328 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Michael Jerris committed 2008-01-23 18:37:33 +00:00
1 parent c7b311fdcd
commit da29143b60
75 files changed
+1976 -727

No files matched your search

@@ -52,4 +52,7 @@ ALIASES = \
"VERSION_1_12_7=<a href=\"http://sofia-sip.sf.net/relnotes/relnotes-sofia-sip-1.12.7.txt\">1.12.7</a>" \
"NEW_1_12_7=@since New in <a href=\"http://sofia-sip.sf.net/relnotes/relnotes-sofia-sip-1.12.7.txt\">1.12.7</a>" \
"EXP_1_12_7=@since Experimental in <a href=\"http://sofia-sip.sf.net/relnotes/relnotes-sofia-sip-1.12.7.txt\">1.12.7</a>, available if --enable-experimental configuration option is given" \
"VERSION_1_12_8=<a href=\"http://sofia-sip.sf.net/relnotes/relnotes-sofia-sip-1.12.8.txt\">1.12.8</a>" \
"NEW_1_12_8=@since New in <a href=\"http://sofia-sip.sf.net/relnotes/relnotes-sofia-sip-1.12.8.txt\">1.12.8</a>" \
@@ -2,7 +2,6 @@ EXTRA_DIST = Doxyfile.aliases Doxyfile.conf \
docguide.docs \
mainpage.docs \
conformance.docs \
hide_emails.sh \
ChangeLog \
pictures/SIP_basic_incoming_operation.eps \
pictures/SIP_basic_incoming_operation.gif \
@@ -37,7 +36,7 @@ Doxyfile.rfc:
print "RFC"i"=\"<a href="q site i type q">RFC "i"</a>\" "b; \
}}' \
site=http://www.faqs.org/rfcs/rfc type=.html \
from=700 to=4800 \
from=700 to=5500 \
/dev/null > $@
CLEANFILES = Doxyfile.rfc *.doxytags
@@ -49,6 +49,7 @@ below.
<a href="#4168">RFC 4168</a> <br>
<a href="#4320">RFC 4320</a> <br>
<a href="#4488">RFC 4488</a> <br>
<a href="#5057">RFC 5057</a> <br>
</td><td>
<a href="#4566">RFC 4566</a> <br>
<a href="#2327">RFC 2327</a> <br>
@@ -963,6 +964,23 @@ below.
</td>
</tr>
<a name="5057"></a>
<tr valign=top>
<th align="left">
@RFC5057: Multiple Dialog Usages in SIP
</th>
<td>
Sofia-SIP provides function sip_response_terminates_dialog() that
can be used to determine the effect of error response with dialog.
The nua UA engine uses sip_response_terminates_dialog().
</td>
<td>
The client application must either use NUA or
sip_response_terminates_dialog().
</td>
</tr>
</table>
<table border=1 cellpadding=4 cellspacing=0>
@@ -520,6 +520,11 @@ int test_digest_client()
sip_www_authenticate_class,
sip_authentication_info_class
}};
auth_challenger_t pach[1] =
{{ 407, "Proxy Authorization required",
sip_proxy_authenticate_class,
sip_proxy_authentication_info_class
}};
TEST_1(home = su_home_new(sizeof(*home)));
@@ -994,6 +999,46 @@ int test_digest_client()
TEST(as->as_status, 0);
auth_mod_destroy(am); aucs = NULL;
/* Test empty realm */
TEST_1(am = auth_mod_create(root,
AUTHTAG_METHOD("Digest"),
AUTHTAG_REALM(""),
AUTHTAG_DB(testpasswd),
TAG_END()));
reinit_as(as);
auth_mod_check_client(am, as, NULL, ach); TEST(as->as_status, 401);
TEST(auc_challenge(&aucs, home, (msg_auth_t *)as->as_response,
sip_authorization_class), 1);
reinit_as(as);
TEST(auc_all_credentials(&aucs, "Digest", "\"\"", "user1", "secret"), 1);
msg_header_remove(m2, (void *)sip, (void *)sip->sip_authorization);
TEST(auc_authorization(&aucs, m2, (msg_pub_t*)sip, rq->rq_method_name,
(url_t *)"sip:surf3@ims3.so.noklab.net",
sip->sip_payload), 1);
TEST_1(sip->sip_authorization);
auth_mod_check_client(am, as, sip->sip_authorization, ach);
TEST(as->as_status, 0);
aucs = NULL;
reinit_as(as);
auth_mod_check_client(am, as, NULL, pach); TEST(as->as_status, 407);
TEST(auc_challenge(&aucs, home, (msg_auth_t *)as->as_response,
sip_proxy_authorization_class), 1);
reinit_as(as);
TEST(auc_credentials(&aucs, as->as_home, "Digest:\"\":user1:secret"), 1);
msg_header_remove(m2, (void *)sip, (void *)sip->sip_proxy_authorization);
TEST(auc_authorization(&aucs, m2, (msg_pub_t*)sip, rq->rq_method_name,
(url_t *)"sip:surf3@ims3.so.noklab.net",
sip->sip_payload), 1);
TEST_1(sip->sip_proxy_authorization);
auth_mod_check_client(am, as, sip->sip_proxy_authorization, pach);
TEST(as->as_status, 0);
auth_mod_destroy(am); aucs = NULL;
/* Test Basic authentication scheme */
TEST_1(am = auth_mod_create(root,
AUTHTAG_METHOD("Basic"),
+109 -43
View File
@@ -176,9 +176,7 @@ static nta_leg_t *leg_find(nta_agent_t const *sa,
url_t const *request_uri,
sip_call_id_t const *i,
char const *from_tag,
url_t const *from_uri,
char const *to_tag,
url_t const *to_uri);
char const *to_tag);
static nta_leg_t *dst_find(nta_agent_t const *sa, url_t const *u0,
char const *method);
static void leg_recv(nta_leg_t *, msg_t *, sip_t *, tport_t *);
@@ -340,7 +338,7 @@ su_log_t nta_log[] = { SU_LOG_INIT("nta", "NTA_DEBUG", SU_DEBUG) };
* NTATAG_BAD_REQ_MASK(), NTATAG_BAD_RESP_MASK(), NTATAG_BLACKLIST(),
* NTATAG_CANCEL_2543(), NTATAG_CANCEL_487(), NTATAG_CLIENT_RPORT(),
* NTATAG_DEBUG_DROP_PROB(), NTATAG_DEFAULT_PROXY(),
* NTATAG_EXTRA_100(),
* NTATAG_EXTRA_100(), NTATAG_GRAYLIST(),
* NTATAG_MAXSIZE(), NTATAG_MAX_FORWARDS(), NTATAG_MERGE_482(), NTATAG_MCLASS()
* NTATAG_PASS_100(), NTATAG_PASS_408(), NTATAG_PRELOAD(), NTATAG_PROGRESS(),
* NTATAG_REL100(),
@@ -402,6 +400,7 @@ nta_agent_t *nta_agent_create(su_root_t *root,
agent->sa_t4 = NTA_SIP_T4;
agent->sa_t1x64 = 64 * NTA_SIP_T1;
agent->sa_timer_c = 185 * 1000;
agent->sa_graylist = 600;
agent->sa_drop_prob = 0;
agent->sa_is_a_uas = 0;
agent->sa_progress = 60 * 1000;
@@ -896,7 +895,7 @@ void agent_kill_terminator(nta_agent_t *agent)
* NTATAG_BAD_REQ_MASK(), NTATAG_BAD_RESP_MASK(), NTATAG_BLACKLIST(),
* NTATAG_CANCEL_2543(), NTATAG_CANCEL_487(), NTATAG_CLIENT_RPORT(),
* NTATAG_DEBUG_DROP_PROB(), NTATAG_DEFAULT_PROXY(),
* NTATAG_EXTRA_100(),
* NTATAG_EXTRA_100(), NTATAG_GRAYLIST(),
* NTATAG_MAXSIZE(), NTATAG_MAX_FORWARDS(), NTATAG_MERGE_482(), NTATAG_MCLASS()
* NTATAG_PASS_100(), NTATAG_PASS_408(), NTATAG_PRELOAD(), NTATAG_PROGRESS(),
* NTATAG_REL100(),
@@ -946,6 +945,7 @@ int agent_set_params(nta_agent_t *agent, tagi_t *tags)
unsigned sip_t4 = agent->sa_t4;
unsigned sip_t1x64 = agent->sa_t1x64;
unsigned timer_c = agent->sa_timer_c;
unsigned graylist = agent->sa_graylist;
unsigned blacklist = agent->sa_blacklist;
int ua = agent->sa_is_a_uas;
unsigned progress = agent->sa_progress;
@@ -989,6 +989,7 @@ int agent_set_params(nta_agent_t *agent, tagi_t *tags)
NTATAG_DEBUG_DROP_PROB_REF(drop_prob),
NTATAG_DEFAULT_PROXY_REF(proxy),
NTATAG_EXTRA_100_REF(extra_100),
NTATAG_GRAYLIST_REF(graylist),
NTATAG_MAXSIZE_REF(maxsize),
NTATAG_MAX_PROCEEDING_REF(max_proceeding),
NTATAG_MAX_FORWARDS_REF(max_forwards),
@@ -1142,6 +1143,12 @@ int agent_set_params(nta_agent_t *agent, tagi_t *tags)
outgoing_queue_adjust(agent, agent->sa_out.inv_proceeding, timer_c);
}
if (graylist > 24 * 60 * 60)
graylist = 24 * 60 * 60;
agent->sa_graylist = graylist;
if (blacklist > 24 * 60 * 60)
blacklist = 24 * 60 * 60;
agent->sa_blacklist = blacklist;
if (progress == 0)
@@ -1204,7 +1211,7 @@ void agent_set_udp_params(nta_agent_t *self, usize_t udp_mtu)
* NTATAG_CANCEL_2543_REF(), NTATAG_CANCEL_487_REF(),
* NTATAG_CLIENT_RPORT_REF(), NTATAG_CONTACT_REF(),
* NTATAG_DEBUG_DROP_PROB_REF(), NTATAG_DEFAULT_PROXY_REF(),
* NTATAG_EXTRA_100_REF(),
* NTATAG_EXTRA_100_REF(), NTATAG_GRAYLIST_REF(),
* NTATAG_MAXSIZE_REF(), NTATAG_MAX_FORWARDS_REF(), NTATAG_MCLASS_REF(),
* NTATAG_MERGE_482_REF(), NTATAG_MAX_PROCEEDING_REF(),
* NTATAG_PASS_100_REF(), NTATAG_PASS_408_REF(), NTATAG_PRELOAD_REF(),
@@ -1253,6 +1260,7 @@ int agent_get_params(nta_agent_t *agent, tagi_t *tags)
NTATAG_DEBUG_DROP_PROB(agent->sa_drop_prob),
NTATAG_DEFAULT_PROXY(agent->sa_default_proxy),
NTATAG_EXTRA_100(agent->sa_extra_100),
NTATAG_GRAYLIST(agent->sa_graylist),
NTATAG_MAXSIZE(agent->sa_maxsize),
NTATAG_MAX_PROCEEDING(agent->sa_max_proceeding),
NTATAG_MAX_FORWARDS(agent->sa_max_forwards->mf_count),
@@ -2416,8 +2424,8 @@ void agent_recv_request(nta_agent_t *agent,
if ((leg = leg_find(agent,
method_name, url,
sip->sip_call_id,
sip->sip_from->a_tag, sip->sip_from->a_url,
sip->sip_to->a_tag, sip->sip_to->a_url))) {
sip->sip_from->a_tag,
sip->sip_to->a_tag))) {
/* Try existing dialog */
SU_DEBUG_5(("nta: %s (%u) %s\n",
method_name, cseq, "going to existing leg"));
@@ -3991,12 +3999,12 @@ nta_leg_t *nta_leg_by_replaces(nta_agent_t *sa, sip_replaces_t const *rp)
id->i_hash = msg_hash_string(id->i_id = rp->rp_call_id);
leg = leg_find(sa, NULL, NULL, id, from_tag, NULL, to_tag, NULL);
leg = leg_find(sa, NULL, NULL, id, from_tag, to_tag);
if (leg == NULL && strcmp(from_tag, "0") == 0)
leg = leg_find(sa, NULL, NULL, id, NULL, NULL, to_tag, NULL);
leg = leg_find(sa, NULL, NULL, id, NULL, to_tag);
if (leg == NULL && strcmp(to_tag, "0") == 0)
leg = leg_find(sa, NULL, NULL, id, from_tag, NULL, NULL, NULL);
leg = leg_find(sa, NULL, NULL, id, from_tag, NULL);
}
return leg;
@@ -4120,11 +4128,14 @@ int addr_cmp(url_t const *a, url_t const *b)
* @param call_id if non-NULL, must match with @CallID header contents
* @param remote_tag if there is remote tag
* associated with dialog, @a remote_tag must match
* @param remote_uri if there is no remote tag, the remote URI must match
* @param remote_uri ignored
* @param local_tag if non-NULL and there is local tag associated with leg,
* it must math
* @param local_uri if there is no local tag, the local URI must match
* @param local_uri ignored
*
* @note
* If @a remote_tag or @a local_tag is an empty string (""), the tag is
* ignored when matching legs.
*/
nta_leg_t *nta_leg_by_dialog(nta_agent_t const *agent,
url_t const *request_uri,
@@ -4134,7 +4145,7 @@ nta_leg_t *nta_leg_by_dialog(nta_agent_t const *agent,
char const *local_tag,
url_t const *local_uri)
{
void *to_be_freed = NULL, *tbf2 = NULL, *tbf3 = NULL;
void *to_be_freed = NULL;
url_t *url;
url_t url0[1];
nta_leg_t *leg;
@@ -4158,21 +4169,18 @@ nta_leg_t *nta_leg_by_dialog(nta_agent_t const *agent,
agent_aliases(agent, url, NULL); /* canonize url */
}
if (remote_uri && URL_IS_STRING(remote_uri))
request_uri = tbf2 = url_hdup(NULL, remote_uri);
if (remote_tag && remote_tag[0] == '\0')
remote_tag = NULL;
if (local_tag && local_tag[0] == '\0')
local_tag = NULL;
if (local_uri && URL_IS_STRING(local_uri))
local_uri = tbf3 = url_hdup(NULL, local_uri);
leg = leg_find(agent,
NULL, url,
call_id,
remote_tag, remote_uri,
local_tag, local_uri);
remote_tag,
local_tag);
if (to_be_freed) su_free(NULL, to_be_freed);
if (tbf2) su_free(NULL, tbf2);
if (tbf3) su_free(NULL, tbf3);
return leg;
}
@@ -4181,7 +4189,7 @@ nta_leg_t *nta_leg_by_dialog(nta_agent_t const *agent,
* Find a leg corresponding to the request message.
*
* A leg matches to message if leg_match_request() returns true ("Call-ID",
* "To", and "From" match).
* "To"-tag, and "From"-tag match).
*/
static
nta_leg_t *leg_find(nta_agent_t const *sa,
@@ -4189,9 +4197,7 @@ nta_leg_t *leg_find(nta_agent_t const *sa,
url_t const *request_uri,
sip_call_id_t const *i,
char const *from_tag,
url_t const *from_uri,
char const *to_tag,
url_t const *to_uri)
char const *to_tag)
{
hash_value_t hash = i->i_hash;
leg_htable_t const *lht = sa->sa_dialogs;
@@ -4201,10 +4207,9 @@ nta_leg_t *leg_find(nta_agent_t const *sa,
(leg = *ll);
ll = leg_htable_next(lht, ll)) {
sip_call_id_t const *leg_i = leg->leg_id;
url_t const *remote_uri = leg->leg_remote->a_url;
char const *remote_tag = leg->leg_remote->a_tag;
url_t const *local_uri = leg->leg_local->a_url;
char const *local_tag = leg->leg_local->a_tag;
url_t const *leg_url = leg->leg_url;
char const *leg_method = leg->leg_method;
@@ -4212,6 +4217,7 @@ nta_leg_t *leg_find(nta_agent_t const *sa,
continue;
if (strcmp(leg_i->i_id, i->i_id) != 0)
continue;
/* Do not match if the incoming To has tag, but the local does not */
if (!local_tag && to_tag)
continue;
@@ -4226,15 +4232,14 @@ nta_leg_t *leg_find(nta_agent_t const *sa,
/* Do not match if incoming From has no tag but remote has a tag */
if (remote_tag && !from_tag)
continue;
/* Avoid matching with itself */
if (!remote_tag != !from_tag && !local_tag != !to_tag)
continue;
if (local_tag && to_tag ?
strcasecmp(local_tag, to_tag) : addr_cmp(local_uri, to_uri))
if (local_tag && to_tag && strcasecmp(local_tag, to_tag) && to_tag[0])
continue;
if (remote_tag && from_tag ?
strcasecmp(remote_tag, from_tag) : addr_cmp(remote_uri, from_uri))
if (remote_tag && from_tag && strcasecmp(remote_tag, from_tag) && from_tag[0])
continue;
if (leg_url && request_uri && url_cmp(leg_url, request_uri))
@@ -6390,7 +6395,7 @@ static size_t outgoing_timer_c(outgoing_queue_t *q,
char const *timer,
su_duration_t now);
static void outgoing_ack(nta_outgoing_t *orq, msg_t *msg, sip_t *sip);
static void outgoing_ack(nta_outgoing_t *orq, sip_t *sip);
static msg_t *outgoing_ackmsg(nta_outgoing_t *, sip_method_t, char const *,
tagi_t const *tags);
static void outgoing_retransmit(nta_outgoing_t *orq);
@@ -7657,6 +7662,7 @@ void outgoing_queue(outgoing_queue_t *queue,
if (outgoing_is_queued(orq))
outgoing_remove(orq);
assert(orq->orq_next == NULL);
assert(*queue->q_tail == NULL);
orq->orq_timeout = set_timeout(orq->orq_agent, queue->q_timeout);
@@ -7680,7 +7686,7 @@ void outgoing_remove(nta_outgoing_t *orq)
if ((*orq->orq_prev = orq->orq_next))
orq->orq_next->orq_prev = orq->orq_prev;
else
orq->orq_queue->q_tail = orq->orq_prev, assert(!*orq->orq_queue->q_tail);
orq->orq_queue->q_tail = orq->orq_prev;
orq->orq_queue->q_length--;
orq->orq_next = NULL;
@@ -8334,7 +8340,7 @@ int outgoing_recv(nta_outgoing_t *orq,
else {
/* Final response */
if (status >= 300 && !internal)
outgoing_ack(orq, msg, sip);
outgoing_ack(orq, sip);
if (!orq->orq_completed) {
if (outgoing_complete(orq))
@@ -8532,7 +8538,7 @@ static int outgoing_duplicate(nta_outgoing_t *orq,
/** @internal ACK to a final response (300..699).
* These messages are ACK'ed via the original URL (and tport)
*/
void outgoing_ack(nta_outgoing_t *orq, msg_t *msg, sip_t *sip)
void outgoing_ack(nta_outgoing_t *orq, sip_t *sip)
{
nta_outgoing_t *ack;
msg_t *ackmsg;
@@ -8563,7 +8569,7 @@ void outgoing_ack(nta_outgoing_t *orq, msg_t *msg, sip_t *sip)
TAG_END())))
;
else
msg_destroy(msg);
msg_destroy(ackmsg);
}
}
@@ -8836,8 +8842,8 @@ struct sipdns_query
char const *sq_proto;
char const *sq_domain;
char sq_port[6]; /* port number */
uint16_t sq_type;
uint16_t sq_otype; /* origin type of query data (0 means request) */
uint16_t sq_type; /* query type */
uint16_t sq_priority; /* priority or preference */
uint16_t sq_weight; /* preference or weight */
};
@@ -9068,6 +9074,65 @@ outgoing_try_another(nta_outgoing_t *orq)
outgoing_reset_timer(orq);
outgoing_queue(orq->orq_agent->sa_out.resolving, orq);
if (orq->orq_status > 0)
/* PP: don't hack priority if a preliminary response has been received */
;
else if (orq->orq_agent->sa_graylist == 0)
/* PP: priority hacking disabled */
;
/* NetModule hack:
* Move server that did not work to end of queue in sres cache
*
* the next request does not try to use the server that is currently down
*
* @TODO: fix cases with only A or AAAA answering, or all servers down.
*/
else if (sr && sr->sr_target) {
struct sipdns_query *sq;
/* find latest A/AAAA record */
sq = sr->sr_head;
if (!sq || (sr->sr_a_aaaa1 != sr->sr_a_aaaa2 && sq->sq_type == sr->sr_a_aaaa1))
sq = sr->sr_done;
if (sq && sq->sq_otype == sres_type_srv) {
char const *target = sq->sq_domain, *proto = sq->sq_proto;
unsigned prio = sq->sq_priority, maxprio = prio;
SU_DEBUG_5(("nta: no response from %s:%s;transport=%s\n", target, sq->sq_port, proto));
for (sq = sr->sr_head; sq; sq = sq->sq_next)
if (sq->sq_otype == sres_type_srv && sq->sq_priority > maxprio)
maxprio = sq->sq_priority;
for (sq = sr->sr_done; sq; sq = sq->sq_next)
if (sq->sq_otype == sres_type_srv && sq->sq_priority > maxprio)
maxprio = sq->sq_priority;
for (sq = sr->sr_done; sq; sq = sq->sq_next) {
int modified;
if (sq->sq_type != sres_type_srv || strcmp(proto, sq->sq_proto))
continue;
/* modify the SRV record(s) corresponding to the latest A/AAAA record */
modified = sres_set_cached_srv_priority(
orq->orq_agent->sa_resolver,
sq->sq_domain,
target,
sq->sq_port[0] ? (uint16_t)strtoul(sq->sq_port, NULL, 10) : 0,
orq->orq_agent->sa_graylist,
maxprio + 1);
if (modified >= 0)
SU_DEBUG_3(("nta: reduced priority of %d %s SRV records (increase value to %u)\n",
modified, sq->sq_domain, maxprio + 1));
else
SU_DEBUG_3(("nta: failed to reduce %s SRV priority\n", sq->sq_domain));
}
}
}
return outgoing_resolve_next(orq);
}
@@ -9346,6 +9411,7 @@ void outgoing_answer_naptr(sres_context_t *orq,
sq = su_zalloc(home, (sizeof *sq) + rlen);
*tail = sq, tail = &sq->sq_next;
sq->sq_otype = sres_type_naptr;
sq->sq_priority = na->na_prefer;
sq->sq_weight = j;
sq->sq_type = type;
@@ -9446,11 +9512,11 @@ outgoing_answer_srv(sres_context_t *orq, sres_query_t *q,
if (sq) {
*tail = sq, tail = &sq->sq_next;
sq->sq_otype = sres_type_srv;
sq->sq_type = sr->sr_a_aaaa1;
sq->sq_proto = sq0->sq_proto;
sq->sq_domain = memcpy(sq + 1, srv->srv_target, tlen);
snprintf(sq->sq_port, sizeof(sq->sq_port), "%u", srv->srv_port);
sq->sq_priority = srv->srv_priority;
sq->sq_weight = srv->srv_weight;
}
@@ -10143,8 +10209,8 @@ int nta_reliable_leg_prack(nta_reliable_magic_t *magic,
if ((leg = leg_find(irq->irq_agent,
method_name, url,
sip->sip_call_id,
sip->sip_from->a_tag, sip->sip_from->a_url,
sip->sip_to->a_tag, sip->sip_to->a_url))) {
sip->sip_from->a_tag,
sip->sip_to->a_tag))) {
/* Use existing dialog */
SU_DEBUG_5(("nta: %s (%u) %s\n",
method_name, sip->sip_cseq->cs_seq,
@@ -167,6 +167,8 @@ struct nta_agent_s
/** SIP timer C - interval between provisional responses receivedxs */
unsigned sa_timer_c;
/** Graylisting period */
unsigned sa_graylist;
/** Blacklisting period */
unsigned sa_blacklist;
+26 -1
View File
@@ -643,6 +643,31 @@ tag_typedef_t ntatag_progress = UINTTAG_TYPEDEF(progress);
*/
tag_typedef_t ntatag_timer_c = UINTTAG_TYPEDEF(timer_c);
/**@def NTATAG_GRAYLIST(x)
*
* Avoid failed servers.
*
* The NTATAG_GRAYLIST() provides the time that the servers are avoided
* after a request sent to them has been failed. Avoiding means that if a
* domain provides multiple servers, the failed servers are tried last.
*
* @par Used with
* nua_create(), nua_set_params(),
* nta_agent_create(), nta_agent_set_params()
*
* @par Parameter type
* unsigned int
*
* @par Values
* - Number of seconds that server is kept in graylist, from 0 to 86400.
*
* @par Default Value
* - 600 (graylist server for 10 minutes)
*
* @sa NTATAG_BLACKLIST(), NTATAG_TIMEOUT_408()
*/
tag_typedef_t ntatag_graylist = UINTTAG_TYPEDEF(graylist);
/**@def NTATAG_BLACKLIST(x)
*
* Add Retry-After header to error responses returned to application.
@@ -660,7 +685,7 @@ tag_typedef_t ntatag_timer_c = UINTTAG_TYPEDEF(timer_c);
* unsigned int
*
* @par Values
* - Value of delta-seconds in @RetryAfter header
* - Value of @i delta-seconds in @RetryAfter header, from 0 to 86400
*
* @par Default Value
* - 0 (no Retry-After is included)
@@ -203,6 +203,12 @@ NTA_DLL extern tag_typedef_t ntatag_timer_c;
NTA_DLL extern tag_typedef_t ntatag_timer_c_ref;
#define NTATAG_TIMER_C_REF(x) ntatag_timer_c_ref, tag_uint_vr(&(x))
NTA_DLL extern tag_typedef_t ntatag_graylist;
#define NTATAG_GRAYLIST(x) ntatag_graylist, tag_uint_v((x))
NTA_DLL extern tag_typedef_t ntatag_graylist_ref;
#define NTATAG_GRAYLIST_REF(x) ntatag_graylist_ref, tag_uint_vr(&(x))
NTA_DLL extern tag_typedef_t ntatag_blacklist;
#define NTATAG_BLACKLIST(x) ntatag_blacklist, tag_uint_v((x))
+60 -63
View File
@@ -363,8 +363,16 @@ int new_leg_callback_200(agent_t *ag,
return 200;
}
static client_check_f client_check_to_tag;
static client_check_f * const default_checks[];
static client_check_f * const default_checks[] = {
client_check_to_tag,
NULL
};
static client_check_f * const no_default_checks[] = {
NULL
};
int outgoing_callback(client_t *ctx,
nta_outgoing_t *orq,
@@ -1014,14 +1022,6 @@ int save_and_check_tcp(client_t *ctx, nta_outgoing_t *orq, sip_t const *sip)
}
static client_check_f * const default_checks[] = {
client_check_to_tag,
NULL
};
static client_check_f * const no_default_checks[] = {
NULL
};
/* Test transports */
@@ -2256,8 +2256,23 @@ int test_dialog(agent_t *ag)
END();
}
/* Test merging */
static ssize_t recv_udp(agent_t *ag, void *b, size_t size)
{
ssize_t n;
memset(b, size, 0);
for (;;) {
su_root_step(ag->ag_root, 10L);
if (su_wait(ag->ag_sink_wait, 1, 0) == 0) {
n = su_recv(ag->ag_sink_socket, b, size, MSG_TRUNC);
if (n > 0)
return n;
}
}
}
/* Test merging */
int test_merging(agent_t *ag)
{
BEGIN();
@@ -2289,11 +2304,17 @@ int test_merging(agent_t *ag)
size_t len, l1, l2;
su_sockaddr_t *su = ag->ag_su_nta;
socklen_t sulen = ag->ag_su_nta_len;
int n;
#ifndef MSG_TRUNC
#define MSG_TRUNC 0
#endif
/* Empty sink socket */
while (su_wait(ag->ag_sink_wait, 1, 0) == 0)
su_recv(ag->ag_sink_socket, m1, sizeof m1, MSG_TRUNC);
su_setblocking(ag->ag_sink_socket, 0);
while (su_recv(ag->ag_sink_socket, m1, sizeof m1, MSG_TRUNC) >= 0)
;
su_wait(ag->ag_sink_wait, 1, 0);
su_wait(ag->ag_sink_wait, 1, 0);
{
/* RFC 3261 8.2.2.2 Merged Requests:
@@ -2338,16 +2359,9 @@ int test_merging(agent_t *ag)
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++;
}
}
recv_udp(ag, r1, sizeof r1);
recv_udp(ag, r2, sizeof r2);
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);
@@ -2355,6 +2369,9 @@ int test_merging(agent_t *ag)
TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
}
while (su_recv(ag->ag_sink_socket, m1, sizeof m1, MSG_TRUNC) >= 0)
;
{
/*
* Check that request with same call-id, cseq and from-tag
@@ -2392,16 +2409,8 @@ int test_merging(agent_t *ag)
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++;
}
}
recv_udp(ag, r1, sizeof r1);
recv_udp(ag, r2, sizeof r2);
len = strlen("SIP/2.0 200 ");
TEST_1(memcmp(r1, "SIP/2.0 200 ", len) == 0);
@@ -2410,6 +2419,9 @@ int test_merging(agent_t *ag)
TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
}
while (su_recv(ag->ag_sink_socket, m1, sizeof m1, MSG_TRUNC) >= 0)
;
{
/* test with rfc2543 */
@@ -2440,16 +2452,9 @@ int test_merging(agent_t *ag)
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++;
}
}
recv_udp(ag, r1, sizeof r1);
recv_udp(ag, r2, sizeof r2);
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);
@@ -2457,6 +2462,9 @@ int test_merging(agent_t *ag)
TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
}
while (su_recv(ag->ag_sink_socket, m1, sizeof m1, MSG_TRUNC) >= 0)
;
{
/* test with to-tag */
@@ -2487,16 +2495,9 @@ int test_merging(agent_t *ag)
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++;
}
}
recv_udp(ag, r1, sizeof r1);
recv_udp(ag, r2, sizeof r2);
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);
@@ -2504,6 +2505,9 @@ int test_merging(agent_t *ag)
TEST_P(ag->ag_latest_leg, ag->ag_server_leg);
}
while (su_recv(ag->ag_sink_socket, m1, sizeof m1, MSG_TRUNC) >= 0)
;
{
/* test with rfc2543 and to-tag */
@@ -2532,16 +2536,9 @@ int test_merging(agent_t *ag)
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++;
}
}
recv_udp(ag, r1, sizeof r1);
recv_udp(ag, r2, sizeof r2);
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);
@@ -1268,15 +1268,17 @@ static int api_test_dialog_matching(agent_t *ag)
TEST_P(leg = nta_leg_by_dialog(nta, (url_t *)"sip:pc.al.us", i,
"xyzzy", a2->a_url, a1->a_tag, a1->a_url),
dialog1);
#if nomore
/* remote url is required */
TEST_P(leg = nta_leg_by_dialog(nta, (url_t *)"sip:pc.al.us", i,
a2->a_tag, a1->a_url, a1->a_tag, a1->a_url),
NULL);
#endif
TEST_P(leg = nta_leg_by_dialog(nta, (url_t *)"sip:pc.al.us", i,
a2->a_tag, NULL, a1->a_tag, a1->a_url),
dialog1);
/* local url is used if there is no local tag */
/* local url is used if there is no local tag */ /* XXX - not really */
TEST_P(leg = nta_leg_by_dialog(nta, (url_t *)"sip:pc.al.us", i,
a2->a_tag, a2->a_url, NULL, NULL),
NULL);
@@ -183,22 +183,35 @@ void nua_dialog_store_peer_info(nua_owner_t *own,
}
}
/** Remove dialog information. */
int nua_dialog_zap(nua_owner_t *own,
nua_dialog_state_t *ds)
{
/* zap peer info */
nua_dialog_store_peer_info(own, ds, NULL);
/* Local Contact */
msg_header_free(own, (msg_header_t *)ds->ds_ltarget), ds->ds_ltarget = NULL;
/* Leg */
nta_leg_destroy(ds->ds_leg), ds->ds_leg = NULL;
/* Remote tag */
su_free(own, (void *)ds->ds_remote_tag), ds->ds_remote_tag = NULL;
/* Ready to set route/remote target */
ds->ds_route = 0;
return 0;
}
/** Remove dialog (if there is no other usages). */
int nua_dialog_remove(nua_owner_t *own,
nua_dialog_state_t *ds,
nua_dialog_usage_t *usage)
{
if (ds->ds_usage == usage && (usage == NULL || usage->du_next == NULL)) {
nua_dialog_store_peer_info(own, ds, NULL); /* zap peer info */
msg_header_free(own, (msg_header_t *)ds->ds_ltarget), ds->ds_ltarget = NULL;
nta_leg_destroy(ds->ds_leg), ds->ds_leg = NULL;
su_free(own, (void *)ds->ds_remote_tag), ds->ds_remote_tag = NULL;
ds->ds_route = 0;
return nua_dialog_zap(own, ds);
}
return 0;
}
/** @internal Get dialog usage slot. */
nua_dialog_usage_t **
nua_dialog_usage_at(nua_dialog_state_t const *ds,
@@ -422,6 +422,8 @@ void nua_dialog_uas_route(nua_owner_t *, nua_dialog_state_t *ds,
sip_t const *sip, int rtag);
void nua_dialog_store_peer_info(nua_owner_t *, nua_dialog_state_t *ds,
sip_t const *sip);
int nua_dialog_zap(nua_owner_t *own,
nua_dialog_state_t *ds);
int nua_dialog_remove(nua_owner_t *own,
nua_dialog_state_t *ds,
nua_dialog_usage_t *usage);
@@ -545,6 +547,8 @@ su_inline void nua_client_terminating(nua_client_request_t *cr)
int nua_client_init_request(nua_client_request_t *cr);
msg_t *nua_client_request_template(nua_client_request_t *cr);
int nua_client_restart_request(nua_client_request_t *cr,
int terminating,
tagi_t const *tags);
@@ -262,7 +262,7 @@ void nua_stack_authorize(nua_t *nua,
nua_stack_event(nua, nh, NULL, e, SIP_200_OK, NULL);
}
else {
nua_stack_event(nua, nh, NULL, e, NUA_INTERNAL_ERROR, NULL);
nua_stack_event(nua, nh, NULL, e, NUA_ERROR_AT(__FILE__, __LINE__), NULL);
}
}
@@ -775,7 +775,7 @@ static void nua_notify_usage_refresh(nua_handle_t *nh,
return;
}
nua_stack_tevent(nh->nh_nua, nh, NULL, e, NUA_INTERNAL_ERROR,
nua_stack_tevent(nh->nh_nua, nh, NULL, e, NUA_ERROR_AT(__FILE__, __LINE__),
NUTAG_SUBSTATE(nua_substate_terminated),
TAG_END());
@@ -405,7 +405,7 @@ static int nua_publish_client_response(nua_client_request_t *cr,
if (!ex || ex->ex_delta == 0)
SET_STATUS(900, "Received Invalid Expiration Time");
else
SET_STATUS1(NUA_INTERNAL_ERROR);
SET_STATUS1(NUA_ERROR_AT(__FILE__, __LINE__));
}
else
nua_dialog_usage_set_refresh(du, ex->ex_delta);
@@ -428,7 +428,7 @@ static void nua_publish_usage_refresh(nua_handle_t *nh,
}
nua_stack_event(nh->nh_nua, nh, NULL,
nua_r_publish, NUA_INTERNAL_ERROR,
nua_r_publish, NUA_ERROR_AT(__FILE__, __LINE__),
NULL);
nua_dialog_usage_remove(nh, ds, du);
@@ -1046,7 +1046,7 @@ static void nua_register_usage_refresh(nua_handle_t *nh,
}
/* Report that we have de-registered */
nua_stack_event(nua, nh, NULL, nua_r_register, NUA_INTERNAL_ERROR, NULL);
nua_stack_event(nua, nh, NULL, nua_r_register, NUA_ERROR_AT(__FILE__, __LINE__), NULL);
nua_dialog_usage_remove(nh, ds, du);
}
@@ -1091,11 +1091,14 @@ int nua_invite_client_ack(nua_client_request_t *cr, tagi_t const *tags)
assert(cr->cr_orq);
if (!ds->ds_leg) {
nta_outgoing_destroy(cr->cr_orq);
return -1;
/* XXX - fix nua_dialog_usage_remove_at() instead! */
nta_outgoing_destroy(cr->cr_orq);
return -1;
}
assert(ds->ds_leg);
msg = nta_outgoing_getrequest(cr->cr_orq);
sip = sip_object(msg);
+98 -49
View File
@@ -650,7 +650,7 @@ void nua_stack_signal(nua_t *nua, su_msg_r msg, nua_ee_data_t *ee)
}
if (error < 0) {
nua_stack_event(nh->nh_nua, nh, NULL, event, NUA_INTERNAL_ERROR, NULL);
nua_stack_event(nh->nh_nua, nh, NULL, event, NUA_ERROR_AT(__FILE__, __LINE__), NULL);
}
su_msg_destroy(nua->nua_signal);
@@ -1214,9 +1214,9 @@ nua_stack_authenticate(nua_t *nua, nua_handle_t *nh, nua_event_t e,
cr->cr_waiting = cr->cr_wait_for_cred = 0;
if (status < 0)
nua_client_response(cr, 900, "Cannot add credentials", NULL);
nua_client_response(cr, 900, "Operation cannot add credentials", NULL);
else
nua_client_response(cr, 904, "No matching challenge", NULL);
nua_client_response(cr, 904, "Operation has no matching challenge ", NULL);
}
else if (status < 0) {
nua_stack_event(nua, nh, NULL, e, 900, "Cannot add credentials", NULL);
@@ -1984,7 +1984,7 @@ int nua_client_create(nua_handle_t *nh,
return nua_stack_event(nh->nh_nua, nh,
NULL,
event,
NUA_INTERNAL_ERROR,
NUA_ERROR_AT(__FILE__, __LINE__),
NULL);
}
@@ -2125,7 +2125,9 @@ int nua_client_bind(nua_client_request_t *cr, nua_dialog_usage_t *du)
}
if (du->du_cr && cr != du->du_cr) {
/* This should never happen (but it does):
assert(!nua_client_is_queued(du->du_cr));
*/
if (nua_client_is_queued(du->du_cr))
return -1;
if (nua_client_is_reporting(du->du_cr)) {
@@ -2161,7 +2163,7 @@ int nua_client_init_request(nua_client_request_t *cr)
int error = 0;
if (!cr->cr_method_name)
return nua_client_return(cr, NUA_INTERNAL_ERROR, NULL);
return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__), NULL);
if (cr->cr_msg)
return nua_client_request_try(cr);
@@ -2186,12 +2188,22 @@ int nua_client_init_request(nua_client_request_t *cr)
}
if (!cr->cr_methods->crm_template ||
!cr->cr_methods->crm_template(cr, &msg, cr->cr_tags))
msg = nta_msg_create(nua->nua_nta, 0);
cr->cr_methods->crm_template(cr, &msg, cr->cr_tags) == 0)
msg = nua_client_request_template(cr);
sip = sip_object(msg);
if (!sip)
return nua_client_return(cr, NUA_INTERNAL_ERROR, msg);
return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__), msg);
if (nh->nh_tags) {
for (t = nh->nh_tags; t; t = t_next(t)) {
if (t->t_tag == siptag_contact ||
t->t_tag == siptag_contact_str)
has_contact = 1;
else if (t->t_tag == nutag_url)
url = (url_string_t const *)t->t_value;
}
}
/**@par Populating SIP Request Message with Tagged Arguments
*
@@ -2211,30 +2223,6 @@ int nua_client_init_request(nua_client_request_t *cr)
* However, if a tag value is #SIP_NONE (-1 casted as a void pointer),
* the values from previous tags are ignored.
*/
if (nh->nh_tags) {
for (t = nh->nh_tags; t; t = t_next(t)) {
if (t->t_tag == siptag_contact ||
t->t_tag == siptag_contact_str)
has_contact = 1;
else if (t->t_tag == nutag_url)
url = (url_string_t const *)t->t_value;
}
t = nh->nh_tags;
/* Use the From header from the dialog */
if (ds->ds_leg && t->t_tag == siptag_from)
t++;
sip_add_tagis(msg, sip, &t);
}
if (!ds->ds_route) {
sip_route_t *initial_route = NH_PGET(nh, initial_route);
if (initial_route)
sip_add_dup(msg, sip, (sip_header_t *)initial_route);
}
for (t = cr->cr_tags; t; t = t_next(t)) {
if (t->t_tag == siptag_contact ||
t->t_tag == siptag_contact_str)
@@ -2257,7 +2245,7 @@ int nua_client_init_request(nua_client_request_t *cr)
if ((t = cr->cr_tags)) {
if (sip_add_tagis(msg, sip, &t) < 0)
goto error;
return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__), msg);
}
/**
@@ -2277,11 +2265,11 @@ int nua_client_init_request(nua_client_request_t *cr)
if (!ds->ds_leg) {
if (ds->ds_remote_tag && ds->ds_remote_tag[0] &&
sip_to_tag(nh->nh_home, sip->sip_to, ds->ds_remote_tag) < 0)
goto error;
return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__), msg);
if (sip->sip_from == NULL &&
sip_add_dup(msg, sip, (sip_header_t *)nua->nua_from) < 0)
goto error;
return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__), msg);
if (cr->cr_dialog) {
ds->ds_leg = nta_leg_tcreate(nua->nua_nta,
@@ -2292,12 +2280,12 @@ int nua_client_init_request(nua_client_request_t *cr)
SIPTAG_CSEQ(sip->sip_cseq),
TAG_END());
if (!ds->ds_leg)
goto error;
return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__), msg);
if (!sip->sip_from->a_tag &&
sip_from_tag(msg_home(msg), sip->sip_from,
nta_leg_tag(ds->ds_leg, NULL)) < 0)
goto error;
return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__), msg);
}
}
else {
@@ -2306,7 +2294,7 @@ int nua_client_init_request(nua_client_request_t *cr)
}
if (url && nua_client_set_target(cr, (url_t *)url) < 0)
goto error;
return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__), msg);
cr->cr_has_contact = has_contact;
@@ -2315,7 +2303,7 @@ int nua_client_init_request(nua_client_request_t *cr)
if (error < -1)
msg = NULL;
if (error < 0)
goto error;
return nua_client_return(cr, NUA_ERROR_AT(__FILE__, __LINE__), msg);
if (error != 0)
return error;
}
@@ -2325,8 +2313,34 @@ int nua_client_init_request(nua_client_request_t *cr)
return nua_client_request_try(cr);
error:
return nua_client_return(cr, NUA_INTERNAL_ERROR, msg);
}
msg_t *nua_client_request_template(nua_client_request_t *cr)
{
nua_handle_t *nh = cr->cr_owner;
nua_t *nua = nh->nh_nua;
nua_dialog_state_t *ds = nh->nh_ds;
msg_t *msg = nta_msg_create(nua->nua_nta, 0);
sip_t *sip = sip_object(msg);
if (!sip)
return NULL;
if (nh->nh_tags) {
tagi_t const *t = nh->nh_tags;
/* Use the From header from the dialog.
From is always first tag in the handle */
if (ds->ds_leg && t->t_tag == siptag_from)
t++;
/* When the INVITE message (or any other SIP message) is
* created, the tagged values saved with nua_handle() are used first. */
sip_add_tagis(msg, sip, &t);
}
return msg;
}
@@ -2352,6 +2366,7 @@ int nua_client_restart_request(nua_client_request_t *cr,
return nua_client_request_try(cr);
}
return 0;
}
@@ -2415,7 +2430,7 @@ int nua_client_request_try(nua_client_request_t *cr)
}
if (error < 0)
error = nua_client_response(cr, NUA_INTERNAL_ERROR, NULL);
error = nua_client_response(cr, NUA_ERROR_AT(__FILE__, __LINE__), NULL);
assert(error > 0);
return error;
@@ -2453,6 +2468,22 @@ int nua_client_request_sendmsg(nua_client_request_t *cr, msg_t *msg, sip_t *sip)
while (sip->sip_route)
sip_route_remove(msg, sip);
}
else if (!ds->ds_route) {
sip_route_t *initial_route = NH_PGET(nh, initial_route);
if (initial_route) {
initial_route = sip_route_dup(msg_home(msg), initial_route);
if (!initial_route) return -1;
msg_header_prepend(msg, (msg_pub_t*)sip,
/* This should be
(msg_header_t **)&sip->sip_route
* but directly casting pointer &sip->sip_route gives
* spurious type-punning warning */
(msg_header_t **)((char *)sip + offsetof(sip_t, sip_route)),
(msg_header_t *)initial_route);
}
}
/**
* For in-dialog requests, the request URI is taken from the @Contact
@@ -2747,14 +2778,16 @@ int nua_base_client_check_restart(nua_client_request_t *cr,
switch (status) {
case 302:
if (nua_client_set_target(cr, sip->sip_contact->m_url) >= 0)
if (nua_dialog_zap(nh, nh->nh_ds) == 0 &&
nua_client_set_target(cr, sip->sip_contact->m_url) >= 0)
return nua_client_restart(cr, 100, "Redirected");
break;
case 305:
sip_route_init(r);
*r->r_url = *sip->sip_contact->m_url;
if (sip_add_dup(cr->cr_msg, cr->cr_sip, (sip_header_t *)r) >= 0)
if (nua_dialog_zap(nh, nh->nh_ds) == 0 &&
sip_add_dup(cr->cr_msg, cr->cr_sip, (sip_header_t *)r) >= 0)
return nua_client_restart(cr, 100, "Redirected via a proxy");
break;
@@ -2867,10 +2900,11 @@ int nua_client_restart(nua_client_request_t *cr,
int status, char const *phrase)
{
nua_handle_t *nh = cr->cr_owner;
nua_dialog_state_t *ds = nh->nh_ds;
nta_outgoing_t *orq;
int error = -1, terminated, graceful;
msg_t *msg;
sip_t *sip;
msg_t *msg = NULL;
sip_t *sip = NULL;
if (cr->cr_retry_count > NH_PGET(nh, retry_count))
return 0;
@@ -2878,9 +2912,24 @@ int nua_client_restart(nua_client_request_t *cr,
orq = cr->cr_orq, cr->cr_orq = NULL; assert(orq);
terminated = cr->cr_terminated, cr->cr_terminated = 0;
graceful = cr->cr_graceful, cr->cr_graceful = 0;
cr->cr_offer_sent = cr->cr_answer_recv = 0;
cr->cr_offer_recv = cr->cr_answer_sent = 0;
msg = msg_copy(cr->cr_msg);
sip = sip_object(msg);
if (!ds->ds_leg && cr->cr_dialog) {
sip_t const *sip = cr->cr_sip;
ds->ds_leg = nta_leg_tcreate(nh->nh_nua->nua_nta,
nua_stack_process_request, nh,
SIPTAG_CALL_ID(sip->sip_call_id),
SIPTAG_FROM(sip->sip_from),
SIPTAG_TO(sip->sip_to),
SIPTAG_CSEQ(sip->sip_cseq),
TAG_END());
}
if (ds->ds_leg || !cr->cr_dialog) {
msg = msg_copy(cr->cr_msg);
sip = sip_object(msg);
}
if (msg && sip) {
cr->cr_restarting = 1;
@@ -207,6 +207,7 @@ typedef struct nua_event_frame_s nua_event_frame_t;
extern char const nua_internal_error[];
#define NUA_INTERNAL_ERROR 900, nua_internal_error
#define NUA_ERROR_AT(file, line) 900, "Internal error at " file ":" #line
struct nua_s {
su_home_t nua_home[1];
@@ -451,7 +451,7 @@ static void nua_subscribe_usage_refresh(nua_handle_t *nh,
if (!eu->eu_unsolicited)
nua_stack_tevent(nh->nh_nua, nh, NULL,
nua_i_notify, NUA_INTERNAL_ERROR,
nua_i_notify, NUA_ERROR_AT(__FILE__, __LINE__),
NUTAG_SUBSTATE(nua_substate_terminated),
SIPTAG_EVENT(du->du_event),
TAG_END());
@@ -831,22 +831,31 @@ static int nua_refer_client_request(nua_client_request_t *cr,
tagi_t const *tags)
{
nua_handle_t *nh = cr->cr_owner;
nua_dialog_usage_t *du = cr->cr_usage;
nua_dialog_usage_t *du, *du0 = cr->cr_usage;
struct event_usage *eu;
sip_event_t *event;
int error;
cr->cr_usage = NULL;
if (du)
nua_dialog_usage_remove(nh, nh->nh_ds, du);
event = sip_event_format(nh->nh_home, "refer;id=%u", sip->sip_cseq->cs_seq);
if (!event)
return -1;
du = nua_dialog_usage_add(nh, nh->nh_ds, nua_subscribe_usage, event);
if (!du)
return -1;
if (du0 == NULL ||
du0->du_event == NULL ||
du0->du_event->o_id == NULL ||
strcmp(du0->du_event->o_id, event->o_id)) {
du = nua_dialog_usage_add(nh, nh->nh_ds, nua_subscribe_usage, event);
if (!du)
return -1;
}
else {
du = du0, du0 = NULL;
}
if (du0)
nua_dialog_usage_remove(nh, nh->nh_ds, du0);
eu = nua_dialog_usage_private(cr->cr_usage = du);
eu ->eu_refer = 1;
@@ -1793,6 +1793,223 @@ int test_update_by_uas(struct context *ctx)
END();
}
int test_update_failure(struct context *ctx)
{
BEGIN();
#if 0
struct endpoint *a = &ctx->a, *b = &ctx->b;
struct call *a_call = a->call, *b_call = b->call;
struct event *e, *eu, *ei;
enum nua_callstate ustate, istate;
if (print_headings)
printf("TEST NUA-10.4.1: UPDATE failure terminating session\n");
/* Test UPDATE failing:
A B
|-------INVITE------>|
|<----100 Trying-----|
| |
|<-------183---------|
|-------PRACK------->|
|<-------200---------|
| |
|<-------180---------|
| |
+------------------------+
|<------200 OK-------|
|-------UPDATE------>|
| |
|<-------481---------|
| |
|--------ACK-------->|
| |
|<-------BYE---------|
|-------200 OK-------|
| |
*/
a_call->sdp = "m=audio 5008 RTP/AVP 8";
b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
nua_set_params(ctx->a.nua,
NUTAG_EARLY_MEDIA(1),
SIPTAG_SUPPORTED_STR("100rel, precondition, timer"),
TAG_END());
run_a_until(ctx, nua_r_set_params, until_final_response);
nua_set_params(ctx->b.nua,
NUTAG_EARLY_MEDIA(1),
NUTAG_ONLY183_100REL(1),
SIPTAG_SUPPORTED_STR("100rel, precondition, timer"),
NUTAG_APPL_METHOD("UPDATE"),
TAG_END());
run_b_until(ctx, nua_r_set_params, until_final_response);
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
INVITE(a, a_call, a_call->nh,
TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
SOATAG_USER_SDP_STR(a_call->sdp),
SIPTAG_SUPPORTED_STR("100rel"),
TAG_END());
run_ab_until(ctx, -1, save_until_final_response, -1, until_pracked);
/* Client transitions:
INIT -(C1)-> CALLING: nua_invite(), nua_i_state
CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state
PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
*/
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
TEST_1(is_offer_sent(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
TEST(e->data->e_status, 183);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
TEST_1(is_answer_recv(e->data->e_tags));
/* Offer is sent in PRACK */
TEST_1(is_offer_sent(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
TEST(e->data->e_status, 200);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
TEST_1(is_answer_recv(e->data->e_tags));
TEST_1(!is_offer_sent(e->data->e_tags));
/* Send UPDATE */
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
TEST_1(!is_answer_recv(e->data->e_tags));
TEST_1(is_offer_sent(e->data->e_tags));
/* The final response to the UPDATE and INVITE can be received in any order */
eu = event_by_type(e->next, nua_r_update);
ei = event_by_type(e->next, nua_r_invite);
TEST_1(e = eu); TEST_E(e->data->e_event, nua_r_update);
TEST(e->data->e_status, 200);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
ustate = callstate(e->data->e_tags);
TEST_1(is_answer_recv(e->data->e_tags));
TEST_1(!is_offer_sent(e->data->e_tags));
TEST_1(e = ei); TEST_E(e->data->e_event, nua_r_invite);
TEST(e->data->e_status, 180);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
TEST_1(!is_offer_answer_done(e->data->e_tags));
/* Final response to INVITE */
TEST_1(ei = event_by_type(ei->next, nua_r_invite));
TEST_E(ei->data->e_event, nua_r_invite); TEST(ei->data->e_status, 200);
TEST_1(e = ei->next); TEST_E(e->data->e_event, nua_i_state);
istate = callstate(e->data->e_tags);
TEST_1(!is_offer_answer_done(e->data->e_tags));
if (eu == e->next) {
/* 200 OK to UPDATE is received after 200 OK to INVITE */
TEST(ustate, nua_callstate_ready);
TEST(istate, nua_callstate_completing);
}
else {
/* 200 OK to UPDATE is received before 200 OK to INVITE */
TEST(ustate, nua_callstate_proceeding);
TEST(istate, nua_callstate_ready);
}
free_events_in_list(ctx, a->events);
/*
Server transitions:
INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
*/
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
TEST(e->data->e_status, 100);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
/* Responded with 183 Session Progress */
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
TEST_1(is_answer_sent(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_prack);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
TEST_1(is_offer_recv(e->data->e_tags));
TEST_1(is_answer_sent(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_update);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
TEST_1(is_offer_recv(e->data->e_tags));
TEST_1(is_answer_sent(e->data->e_tags));
/* Responded with 180 Ringing */
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
TEST_1(!is_offer_answer_done(e->data->e_tags));
/* Responded with 200 OK */
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
TEST_1(!is_offer_answer_done(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
TEST_1(!is_offer_answer_done(e->data->e_tags));
TEST_1(!e->next);
free_events_in_list(ctx, b->events);
if (print_headings)
printf("TEST NUA-10.4.1: PASSED\n");
if (print_headings)
printf("TEST NUA-10.4.2: terminate call\n");
BYE(b, b_call, b_call->nh, TAG_END());
run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
/* B transitions:
READY --(T2)--> TERMINATING: nua_bye()
TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
*/
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_bye);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
TEST_1(!e->next);
free_events_in_list(ctx, b->events);
/* A: READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state */
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_bye);
TEST(e->data->e_status, 200);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
TEST_1(!e->next);
free_events_in_list(ctx, a->events);
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
if (print_headings)
printf("TEST NUA-10.4.2: PASSED\n");
#endif
END();
}
int cancel_when_pracked(CONDITION_PARAMS);
int alert_call(CONDITION_PARAMS);
@@ -2105,19 +2322,281 @@ int test_180rel_cancel2(struct context *ctx)
END();
}
int redirect_pracked(CONDITION_PARAMS);
int test_180rel_redirected(struct context *ctx)
{
BEGIN();
struct endpoint *a = &ctx->a, *b = &ctx->b;
struct call *a_call = a->call, *b_call = b->call;
struct event *e, *ep, *ei;
sip_t *sip;
if (print_headings)
printf("TEST NUA-10.8.1: Call with 100rel and 180\n");
/* Test for 100rel:
A B
|-------INVITE------>|
|<----100 Trying-----|
| |
|<-------180---------|
|-------PRACK------->|
|<-------200---------|
| |
|<----302 Moved------|
|--------ACK-------->|
| |
|-------INVITE------>|
|<----100 Trying-----|
| |
|<-------180---------|
|-------PRACK------->|
|<-------200---------|
| |
|<------200 OK-------|
|--------ACK-------->|
| |
|<-------BYE---------|
|-------200 OK-------|
| |
*/
a_call->sdp = "m=audio 5008 RTP/AVP 8";
b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
nua_set_params(ctx->a.nua,
NUTAG_EARLY_MEDIA(1),
TAG_END());
run_a_until(ctx, nua_r_set_params, until_final_response);
nua_set_params(ctx->b.nua,
NUTAG_EARLY_MEDIA(1),
NUTAG_SESSION_TIMER(180),
TAG_END());
run_b_until(ctx, nua_r_set_params, until_final_response);
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
INVITE(a, a_call, a_call->nh,
TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
SOATAG_USER_SDP_STR(a_call->sdp),
TAG_END());
run_ab_until(ctx, -1, until_ready, -1, redirect_pracked);
/* Client transitions:
INIT -(C1)-> CALLING: nua_invite(), nua_i_state
CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state, nua_r_prack
PROCEEDING->(redirected)->CALLING: nua_r_invite, nua_i_state
CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state, nua_r_prack
PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
*/
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
TEST_1(is_offer_sent(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
TEST(e->data->e_status, 180);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
TEST_1(is_answer_recv(e->data->e_tags));
TEST_1(!is_offer_sent(e->data->e_tags));
ei = event_by_type(e->next, nua_r_invite); /* 302 */
ep = event_by_type(e->next, nua_r_prack); /* 200 */
if (!ep) {
run_a_until(ctx, -1, save_until_final_response);
ep = event_by_type(e->next, nua_r_prack);
}
TEST_1(e = ep); TEST_E(e->data->e_event, nua_r_prack);
TEST(e->data->e_status, 200);
TEST_1(e = ei); TEST_E(e->data->e_event, nua_r_invite);
TEST(e->data->e_status, 100);
TEST_1(sip = sip_object(e->data->e_msg));
TEST(sip->sip_status->st_status, 302);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
TEST(e->data->e_status, 180);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
TEST_1(is_answer_recv(e->data->e_tags));
TEST_1(!is_offer_sent(e->data->e_tags));
ei = event_by_type(e->next, nua_r_invite);
ep = event_by_type(e->next, nua_r_prack);
if (!ep) {
run_a_until(ctx, -1, save_until_final_response);
ep = event_by_type(e->next, nua_r_prack);
}
TEST_1(e = ep); TEST_E(e->data->e_event, nua_r_prack);
TEST(e->data->e_status, 200);
TEST_1(e = ei); TEST_E(e->data->e_event, nua_r_invite);
TEST(e->data->e_status, 200);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
TEST_1(!is_offer_answer_done(e->data->e_tags));
TEST_1(!e->next || !ep->next);
free_events_in_list(ctx, a->events);
/*
Server transitions:
INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
*/
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
TEST(e->data->e_status, 100);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
TEST_1(is_offer_recv(e->data->e_tags));
/* Responded with 180 Ringing */
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
TEST_1(is_answer_sent(e->data->e_tags));
/* 180 is PRACKed */
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_prack);
/* 302 terminates call */
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* Terminated */
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_invite);
TEST(e->data->e_status, 100);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
TEST_1(is_offer_recv(e->data->e_tags));
/* Responded with 180 Ringing */
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
TEST_1(is_answer_sent(e->data->e_tags));
/* 180 is PRACKed */
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_prack);
/* Does not have effect on call state */
/* Respond with 200 OK */
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
TEST_1(!is_offer_answer_done(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
TEST_1(!is_offer_answer_done(e->data->e_tags));
TEST_1(!e->next);
free_events_in_list(ctx, b->events);
if (print_headings)
printf("TEST NUA-10.8.1: PASSED\n");
if (print_headings)
printf("TEST NUA-10.8.2: terminate call\n");
BYE(b, b_call, b_call->nh, TAG_END());
run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
/* B transitions:
READY --(T2)--> TERMINATING: nua_bye()
TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
*/
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_bye);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
TEST_1(!e->next);
free_events_in_list(ctx, b->events);
/* A: READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state */
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_bye);
TEST(e->data->e_status, 200);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
TEST_1(!e->next);
free_events_in_list(ctx, a->events);
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
if (print_headings)
printf("TEST NUA-10.8.2: PASSED\n");
END();
}
int redirect_pracked(CONDITION_PARAMS)
{
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
return 0;
save_event_in_list(ctx, event, ep, call);
if (event == nua_i_prack) {
if (!ep->flags.bit0) {
sip_contact_t m[1];
ep->flags.bit0 = 1;
*m = *ep->contact;
m->m_url->url_user = "302";
RESPOND(ep, call, nh, SIP_302_MOVED_TEMPORARILY, SIPTAG_CONTACT(m), TAG_END());
return 0;
}
else {
RESPOND(ep, call, nh, SIP_200_OK,
TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
TAG_END());
}
}
switch (callstate(tags)) {
case nua_callstate_received:
RESPOND(ep, call, nh, SIP_180_RINGING,
TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
TAG_END());
return 0;
case nua_callstate_ready:
return 1;
case nua_callstate_terminated:
if (call)
nua_handle_destroy(call->nh), call->nh = NULL;
return 0;
default:
return 0;
}
}
int test_100rel(struct context *ctx)
{
int retval = 0;
retval = test_180rel(ctx); RETURN_ON_SINGLE_FAILURE(retval);
retval = test_prack_auth(ctx); RETURN_ON_SINGLE_FAILURE(retval);
retval = test_183rel(ctx); RETURN_ON_SINGLE_FAILURE(retval);
retval = test_preconditions(ctx); RETURN_ON_SINGLE_FAILURE(retval);
retval = test_preconditions2(ctx); RETURN_ON_SINGLE_FAILURE(retval);
retval = test_update_by_uas(ctx); RETURN_ON_SINGLE_FAILURE(retval);
retval = test_update_failure(ctx); RETURN_ON_SINGLE_FAILURE(retval);
retval = test_180rel_cancel1(ctx); RETURN_ON_SINGLE_FAILURE(retval);
retval = test_180rel_cancel2(ctx); RETURN_ON_SINGLE_FAILURE(retval);
retval = test_180rel_redirected(ctx); RETURN_ON_SINGLE_FAILURE(retval);
nua_set_params(ctx->a.nua,
NUTAG_EARLY_MEDIA(0),
+138 -1
View File
@@ -48,13 +48,14 @@
int test_refer0(struct context *ctx, char const *tests,
int refer_with_id, int notify_by_appl);
int notify_until_terminated(CONDITION_PARAMS);
int test_challenge_refer(struct context *ctx);
int test_refer(struct context *ctx)
{
/* test twice, once without id and once with id */
return
test_challenge_refer(ctx) ||
test_refer0(ctx, "NUA-9.1", 0, 0) ||
test_refer0(ctx, "NUA-9.2", 1, 0) ||
test_refer0(ctx, "NUA-9.3", 0, 1) ||
@@ -713,3 +714,139 @@ int notify_until_terminated(CONDITION_PARAMS)
return 0;
}
}
int authenticate_refer(CONDITION_PARAMS);
int reject_refer_after_notified(CONDITION_PARAMS);
int test_challenge_refer(struct context *ctx)
{
BEGIN();
struct endpoint *a = &ctx->a, *b = &ctx->b, *c = &ctx->c;
struct call *a_call = a->call, *c_call = c->call;
struct event *e;
sip_t const *sip;
sip_refer_to_t r0[1];
if (!ctx->proxy_tests)
return 0;
if (print_headings)
printf("TEST NUA-9.0.1: challenge REFER\n");
nua_set_params(ctx->a.nua, NUTAG_APPL_METHOD("REFER"), TAG_END());
run_a_until(ctx, nua_r_set_params, until_final_response);
*sip_refer_to_init(r0)->r_url = *b->contact->m_url;
r0->r_url->url_headers = "subject=referred";
r0->r_display = "B";
TEST_1(c_call->nh = nua_handle(c->nua, c_call, SIPTAG_TO(a->to), TAG_END()));
REFER(c, c_call, c_call->nh,
SIPTAG_FROM(c->to),
SIPTAG_REFER_TO(r0),
TAG_END());
run_abc_until(ctx, -1, reject_refer_after_notified, -1, NULL, -1, authenticate_refer);
/*
Events in A:
nua_i_refer
*/
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_refer);
TEST(e->data->e_status, 100);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_refer_to);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_notify);
TEST(e->data->e_status, 200);
TEST_1(!e->next);
/*
Events in C after nua_refer():
nua_r_refer
*/
TEST_1(e = c->events->head); TEST_E(e->data->e_event, nua_r_refer);
TEST(e->data->e_status, 100);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_refer);
TEST(e->data->e_status, 407);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_refer);
TEST(e->data->e_status, 100);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
TEST(e->data->e_status, 200);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_refer);
TEST(e->data->e_status, 480);
TEST_1(!e->next);
free_events_in_list(ctx, a->events);
free_events_in_list(ctx, c->events);
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
nua_handle_destroy(c_call->nh), c_call->nh = NULL;
nua_set_params(ctx->a.nua,
NUTAG_APPL_METHOD(NULL),
NUTAG_APPL_METHOD("INVITE, REGISTER, PUBLISH, SUBSCRIBE"),
TAG_END());
run_a_until(ctx, nua_r_set_params, until_final_response);
if (print_headings)
printf("TEST NUA-9.0.1: PASSED\n");
END();
}
int reject_refer_after_notified(CONDITION_PARAMS)
{
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
return 0;
save_event_in_list(ctx, event, ep, call);
if (event == nua_i_refer) {
}
if (event == nua_r_notify) {
/* Respond to refer only after initial notify has been responded */
struct eventlist *list;
struct event *e;
if (call->events)
list = call->events;
else
list = ep->events;
for (e = list->head; e; e = e->next)
if (e->data->e_event == nua_i_refer)
break;
if (e) {
RESPOND(ep, call, nh, SIP_480_TEMPORARILY_UNAVAILABLE,
NUTAG_WITH(e->data->e_msg),
TAG_END());
return 1;
}
return 0;
}
return 0;
}
int authenticate_refer(CONDITION_PARAMS)
{
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
return 0;
save_event_in_list(ctx, event, ep, call);
if (status == 401 || status == 407) {
AUTHENTICATE(ep, call, nh,
NUTAG_AUTH("Digest:\"test-proxy\":charlie:secret"),
TAG_END());
}
return status == 480;
}
+51 -12
View File
@@ -220,9 +220,13 @@ issize_t sip_error_info_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
*
* The parsed Alert-Info header is stored in #sip_alert_info_t structure.
*
* @NEW_1_12_7. In order to use @b Alert-Info header,
* initialize the SIP parser with, e.g.,
* sip_update_default_mclass(sip_extend_mclass(NULL))
* @NEW_1_12_7. In order to use @b Alert-Info header, initialize the SIP
* parser before calling nta_agent_create() or nua_create() with, e.g.,
* sip_update_default_mclass(sip_extend_mclass(NULL)).
*
* The #sip_t structure does not contain a @a sip_alert_info field, but
* sip_alert_info() function should be used for accessing the @b Alert-Info
* header structure.
*/
/**@ingroup sip_alert_info
@@ -283,8 +287,14 @@ issize_t sip_alert_info_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
* @sa sip_update_default_mclass()
*
* @NEW_1_12_7. In order to use @b Reply-To header,
* initialize the SIP parser with, e.g.,
* initialize the SIP parser before calling nta_agent_create() or
* nua_create() with, e.g.,
* sip_update_default_mclass(sip_extend_mclass(NULL)).
*
* @note
* The #sip_t structure does not contain a @a sip_reply_to field, but
* sip_reply_to() function should be used for accessing the @b Reply-To
* header structure.
*/
/**@ingroup sip_reply_to
@@ -933,7 +943,13 @@ char *sip_info_dup_one(sip_header_t *dst,
*
* @sa @RFC3265, draft-niemi-sip-subnot-etags-01.txt
*
* @EXP_1_12_5. Note that #sip_t does not contain @a
* @EXP_1_12_5.
* In order to use @b Suppress-Body-If-Match header,
* initialize the SIP parser with, e.g.,
* sip_update_default_mclass(sip_extend_mclass(NULL)).
*
* @note
* The #sip_t structure does not contain a @a
* sip_suppress_body_if_match field, but sip_suppress_body_if_match()
* function should be used for accessing the @b Suppress-Body-If-Match
* header structure.
@@ -999,10 +1015,15 @@ issize_t sip_suppress_body_if_match_e(char b[], isize_t bsiz,
*
* @sa @RFC3265, draft-niemi-sip-subnot-etag-01
*
* @EXP_1_12_5. Note that #sip_t does not contain @a
* sip_suppress_notify_if_match field, but sip_suppress_notify_if_match()
* function should be used for accessing the @b Suppress-Notify-If-Match
* header structure.
* @EXP_1_12_5.
* In order to use @b Suppress-Notify-If-Match header,
* initialize the SIP parser with, e.g.,
* sip_update_default_mclass(sip_extend_mclass(NULL)).
*
* @note
* The #sip_t struct does not contain @a sip_suppress_notify_if_match field,
* but sip_suppress_notify_if_match() function should be used for accessing
* the @b Suppress-Notify-If-Match header structure.
*/
/**@ingroup sip_suppress_notify_if_match
@@ -1085,8 +1106,14 @@ issize_t sip_suppress_notify_if_match_e(char b[], isize_t bsiz,
* @sa sip_update_default_mclass(), draft-ietf-sip-privacy-04.txt, @RFC3325
*
* @NEW_1_12_7. In order to use @b Remote-Party-ID header,
* initialize the SIP parser with, e.g.,
* initialize the SIP parser before calling nta_agent_create() or
* nua_create() with, e.g.,
* sip_update_default_mclass(sip_extend_mclass(NULL)).
*
* @note
* The #sip_t structure does not contain @a sip_remote_party_id field, but
* sip_remote_party_id() function should be used for accessing the @b
* Remote-Party-ID header structure.
*/
/**@ingroup sip_remote_party_id
@@ -1222,8 +1249,14 @@ static int sip_remote_party_id_update(msg_common_t *h,
* @sa @RFC3325, @PPreferredIdentity
*
* @NEW_1_12_7. In order to use @b P-Asserted-Identity header,
* initialize the SIP parser with, e.g.,
* initialize the SIP parser before calling nta_agent_create() or
* nua_create() with, e.g.,
* sip_update_default_mclass(sip_extend_mclass(NULL)).
*
* @note
* The #sip_t structure does not contain @a sip_p_asserted_identity field,
* but sip_p_asserted_identity() function should be used for accessing the
* @b P-Asserted-Identity header structure.
*/
/**@ingroup sip_p_asserted_identity
@@ -1325,8 +1358,14 @@ char *sip_p_asserted_identity_dup_one(sip_header_t *dst,
* @sa @RFC3325, @PAssertedIdentity
*
* @NEW_1_12_7. In order to use @b P-Preferred-Identity header,
* initialize the SIP parser with, e.g.,
* initialize the SIP parser before calling nta_agent_create() or
* nua_create() with, e.g.,
* sip_update_default_mclass(sip_extend_mclass(NULL)).
*
* @note
* The #sip_t structure does not contain @a sip_p_preferred_identity field,
* but sip_p_preferred_identity() function should be used for accessing the
* @b P-Preferred-Identity header structure.
*/
/**@ingroup sip_p_preferred_identity
@@ -90,6 +90,8 @@ msg_mclass_t const *sip_default_mclass(void)
* @retval 0 when successful
* @retval -1 upon an error
*
* @sa sip_extend_mclass()
*
* @NEW_1_12_7.
*/
int sip_update_default_mclass(msg_mclass_t const *mclass)
@@ -103,12 +105,22 @@ int sip_update_default_mclass(msg_mclass_t const *mclass)
/**Extend SIP parser class with extension headers.
*
* Extend given SIP parser class with extension headers. If the given parser
* class is the default one or NULL, make a clone of it before extending it.
* (message class) is the default one or NULL, make a clone of default
* parser before extending it.
*
* @param input pointer to a SIP message class (may be NULL)
*
* @return Pointer to extended mclass, or NULL upon an error.
*
* @sa
* @AlertInfo,
* @ReplyTo,
* @RemotePartyId,
* @PAssertedIdentity,
* @PPreferredIdentity,
* @SuppressBodyIfMatch,
* @SuppressNotifyIfMatch
*
* @NEW_1_12_7.
*/
msg_mclass_t *sip_extend_mclass(msg_mclass_t *input)
@@ -883,8 +883,7 @@ sip_security_client_select(sip_security_client_t const *client,
* decide whether to gracefully terminate or not, the
* @a *return_graceful_terminate_usage is left unmodified.
*
* @sa
* http://www.ietf.org/internet-drafts/draft-ietf-sipping-dialogusage-02.txt
* @RFC 5057
*/
int sip_response_terminates_dialog(int response_code,
sip_method_t method,
@@ -1060,8 +1059,6 @@ int sip_response_terminates_dialog(int response_code,
usage in an existing dialog, no new usage is created and existing
usages are unaffected.
*/
*return_graceful_terminate_usage = 0;
return 0;
case 423: /** @par 423 Interval Too Brief
@@ -1070,8 +1067,6 @@ int sip_response_terminates_dialog(int response_code,
subscribe usage is not destroyed (or otherwise affected). No
other usages of the dialog are affected.
*/
*return_graceful_terminate_usage = 0;
return sip_method_subscribe == method ? terminate_usage : no_effect;
case 428: /** @par 428 Use Identity Header
@@ -1079,8 +1074,6 @@ int sip_response_terminates_dialog(int response_code,
the usage. The usage is not affected. The dialog is only
affected by a change in its local @CSeq. No other usages of the
dialog are affected. */
*return_graceful_terminate_usage = 0;
return 0;
case 429: /** @par 429 Provide Referrer Identity
@@ -77,6 +77,9 @@ static msg_t *read_message(int flags, char const string[]);
static int test_identity(void)
{
su_home_t *home;
sip_alert_info_t *ai;
sip_reply_to_t *rplyto;
sip_remote_party_id_t *rpid;
sip_p_asserted_identity_t *paid;
sip_p_preferred_identity_t *ppid;
@@ -115,15 +118,21 @@ static int test_identity(void)
"Call-ID: 0ha0isndaksdj@10.1.2.3\r\n"
"CSeq: 8 SUBSCRIBE\r\n"
"Via: SIP/2.0/UDP 135.180.130.133\r\n"
"Alert-Info: <http://test.com/tune>;walz, <http://test.com/buzz>\r\n"
"Reply-To: Arska <sip:arska@gov.ca.us>;humppa\r\n"
"P-Asserted-Identity: <sip:test@test.domain.com>\r\n"
"P-Preferred-Identity: <sip:test@test.domain.com>, <tel:+358708008000>\r\n"
"Remote-Party-ID: <sip:test2@test.domain.com>\r\n"
"Content-Length: 0\r\n"
"\r\n");
sip = sip_object(msg);
TEST_1(!sip_alert_info(sip));
TEST_1(!sip_reply_to(sip));
TEST_1(!sip_p_asserted_identity(sip));
TEST_1(!sip_p_preferred_identity(sip));
TEST_1(!sip_remote_party_id(sip));
msg_destroy(msg);
@@ -139,13 +148,22 @@ static int test_identity(void)
"Call-ID: 0ha0isndaksdj@10.1.2.3\r\n"
"CSeq: 8 SUBSCRIBE\r\n"
"Via: SIP/2.0/UDP 135.180.130.133\r\n"
"Alert-Info: <http://test.com/tune>;walz, <http://test.com/buzz>\r\n"
"Reply-To: Arska <sip:arska@gov.ca.us>;humppa\r\n"
"P-Asserted-Identity: <sip:test@test.domain.com>\r\n"
"P-Preferred-Identity: <sip:test@test.domain.com>, <tel:+358708008000>\r\n"
"Remote-Party-ID: <sip:test2@test.domain.com>\r\n"
"Content-Length: 0\r\n"
"\r\n");
sip = sip_object(msg);
TEST_1(!sip_alert_info(sip));
TEST_1(!sip_reply_to(sip));
TEST_1(sip_p_asserted_identity(sip));
TEST_1(sip_p_preferred_identity(sip));
TEST_1(!sip_remote_party_id(sip));
TEST_1(home = msg_home(msg));
TEST_1((paid = sip_p_asserted_identity_make(home, "sip:joe@example.com")));
@@ -161,6 +179,34 @@ static int test_identity(void)
/* Now with extensions */
TEST_1(test_mclass = msg_mclass_clone(def1, 0, 0));
msg = read_message(MSG_DO_EXTRACT_COPY,
"BYE sip:foo@bar SIP/2.0\r\n"
"To: <sip:foo@bar>;tag=deadbeef\r\n"
"From: <sip:bar@foo>;\r\n"
"Call-ID: 0ha0isndaksdj@10.1.2.3\r\n"
"CSeq: 8 SUBSCRIBE\r\n"
"Via: SIP/2.0/UDP 135.180.130.133\r\n"
"Alert-Info: <http://test.com/tune>;walz, <http://test.com/buzz>\r\n"
"Reply-To: Arska <sip:arska@gov.ca.us>;humppa\r\n"
"P-Asserted-Identity: <sip:test@test.domain.com>\r\n"
"P-Preferred-Identity: <sip:test@test.domain.com>, <tel:+358708008000>\r\n"
"Remote-Party-ID: <sip:test2@test.domain.com>\r\n"
"Content-Length: 0\r\n"
"\r\n");
sip = sip_object(msg);
TEST_1(ai = sip_alert_info(sip));
TEST_S(ai->ai_url->url_host, "test.com");
TEST_1(rplyto = sip_reply_to(sip));
TEST_S(rplyto->rplyto_url->url_host, "gov.ca.us");
TEST_1(paid = sip_p_asserted_identity(sip));
TEST_1(ppid = sip_p_preferred_identity(sip));
TEST_1(rpid = sip_remote_party_id(sip));
TEST_S(rpid->rpid_url->url_host, "test.domain.com");
msg_destroy(msg);
{
su_home_t *home = su_home_clone(NULL, sizeof *home);
+53 -41
View File
@@ -70,10 +70,6 @@ static char const __func__[] = "soa";
/* ======================================================================== */
/* Internal prototypes */
void soa_set_activity(soa_session_t *ss,
sdp_media_t const *,
int remote);
su_inline int soa_media_is_ready(soa_session_t const *ss);
enum soa_sdp_kind {
@@ -1171,7 +1167,7 @@ int soa_base_set_remote_sdp(soa_session_t *ss,
if (!new_version)
return 0;
soa_set_activity(ss, sdp->sdp_media, 1);
soa_set_activity(ss, sdp->sdp_media, soa_activity_remote);
ss->ss_remote_version++;
@@ -1454,7 +1450,7 @@ int soa_base_generate_offer(soa_session_t *ss,
if (!sdp)
return -1;
soa_set_activity(ss, sdp->sdp_media, 0);
soa_set_activity(ss, sdp->sdp_media, soa_activity_local); /* Wanted activity */
ss->ss_offer_sent = 1;
ss->ss_answer_recv = 0;
@@ -1542,8 +1538,7 @@ int soa_base_generate_answer(soa_session_t *ss,
su_free(ss->ss_home, ss->ss_rsession);
ss->ss_rsession = rsession;
soa_set_activity(ss, l_sdp->sdp_media, 0);
soa_set_activity(ss, r_sdp->sdp_media, 1);
soa_set_activity(ss, l_sdp->sdp_media, soa_activity_session);
ss->ss_offer_recv = 1;
ss->ss_answer_sent = 1;
@@ -1624,8 +1619,7 @@ int soa_base_process_answer(soa_session_t *ss,
su_free(ss->ss_home, ss->ss_rsession);
ss->ss_rsession = rsession;
soa_set_activity(ss, l_sdp->sdp_media, 0);
soa_set_activity(ss, r_sdp->sdp_media, 1);
soa_set_activity(ss, l_sdp->sdp_media, soa_activity_session);
ss->ss_answer_recv = 1;
ss->ss_complete = 1;
@@ -1692,7 +1686,7 @@ int soa_base_process_reject(soa_session_t *ss,
if (!l_sdp)
return -1;
soa_set_activity(ss, l_sdp->sdp_media, 0);
soa_set_activity(ss, l_sdp->sdp_media, soa_activity_session);
ss->ss_offer_sent = 0;
@@ -1783,8 +1777,7 @@ void soa_base_terminate(soa_session_t *ss, char const *option)
ss->ss_oa_rounds = 0;
soa_description_free(ss, ss->ss_remote);
soa_set_activity(ss, NULL, 0);
soa_set_activity(ss, NULL, 1);
soa_set_activity(ss, NULL, soa_activity_session);
}
/** Return true if the SDP Offer/Answer negotation is complete.
@@ -1889,56 +1882,75 @@ int soa_media_is_ready(soa_session_t const *ss)
void soa_set_activity(soa_session_t *ss,
sdp_media_t const *m,
int remote)
enum soa_activity activity)
{
struct soa_media_activity *ma;
sdp_connection_t const *c;
int mode;
int ma_audio = SOA_ACTIVE_DISABLED;
int ma_video = SOA_ACTIVE_DISABLED;
int ma_chat = SOA_ACTIVE_DISABLED;
int ma_image = SOA_ACTIVE_DISABLED;
int *p;
int mode, swap;
int l_audio = SOA_ACTIVE_DISABLED, r_audio = SOA_ACTIVE_DISABLED;
int l_video = SOA_ACTIVE_DISABLED, r_video = SOA_ACTIVE_DISABLED;
int l_chat = SOA_ACTIVE_DISABLED, r_chat = SOA_ACTIVE_DISABLED;
int l_image = SOA_ACTIVE_DISABLED, r_image = SOA_ACTIVE_DISABLED;
remote = !!remote;
ma = remote ? ss->ss_remote_activity : ss->ss_local_activity;
int *l, *r;
for (; m; m = m->m_next) {
if (m->m_type == sdp_media_audio)
p = &ma_audio;
l = &l_audio, r = &r_audio;
else if (m->m_type == sdp_media_video)
p = &ma_video;
l = &l_video, r = &r_video;
else if (m->m_type == sdp_media_image)
p = &ma_image;
l = &l_image, r = &r_image;
else if (strcasecmp(m->m_type_name, "message") == 0)
p = &ma_chat;
l = &l_chat, r = &r_chat;
else
continue;
if (m->m_rejected) {
if (*p < 0)
*p = SOA_ACTIVE_REJECTED;
if (*l < 0) *l = SOA_ACTIVE_REJECTED;
if (*r < 0) *r = SOA_ACTIVE_REJECTED;
continue;
}
mode = m->m_mode;
mode = m->m_mode, swap = ((mode << 1) & 2) | ((mode >> 1) & 1);
c = sdp_media_connections((sdp_media_t *)m);
if (remote != (c && c->c_mcast))
mode = ((mode << 1) & 2) | ((mode >> 1) & 1);
if (*p < 0)
*p = mode;
else
*p |= mode;
switch (activity) {
case soa_activity_local:
*l &= SOA_ACTIVE_SENDRECV;
*l |= c && c->c_mcast ? swap : mode;
break;
case soa_activity_remote:
*r &= SOA_ACTIVE_SENDRECV;
*r = c && c->c_mcast ? mode : swap;
break;
case soa_activity_session:
*l &= SOA_ACTIVE_SENDRECV;
*l |= c && c->c_mcast ? swap : mode;
*r &= SOA_ACTIVE_SENDRECV;
*r = c && c->c_mcast ? swap : mode;
break;
}
}
ma->ma_audio = ma_audio;
ma->ma_video = ma_video;
ma->ma_image = ma_image;
ma->ma_chat = ma_chat;
if (activity == soa_activity_local ||
activity == soa_activity_session) {
ma = ss->ss_local_activity;
ma->ma_audio = l_audio;
ma->ma_video = l_video;
ma->ma_image = l_image;
ma->ma_chat = l_chat;
}
if (activity == soa_activity_remote ||
activity == soa_activity_session) {
ma = ss->ss_remote_activity;
ma->ma_audio = r_audio;
ma->ma_video = r_video;
ma->ma_image = r_image;
ma->ma_chat = r_chat;
}
}
/* ----------------------------------------------------------------------*/
+65 -56
View File
@@ -974,58 +974,28 @@ int soa_sdp_reject(su_home_t *home,
return 0;
}
/** Check if @a session mode should be changed. */
/** Update mode within session.
*
* @sa soatag_hold
*
* @retval 1 if session was changed (or to be changed, if @a dryrun is nonzero)
*/
static
int soa_sdp_mode_set_is_needed(sdp_session_t const *session,
sdp_session_t const *remote,
char const *hold)
{
sdp_media_t const *sm, *rm, *rm_next;
int hold_all;
sdp_mode_t recv_mode;
SU_DEBUG_7(("soa_sdp_mode_set_is_needed(%p, %p, \"%s\"): called\n",
(void *)session, (void *)remote, hold ? hold : ""));
if (!session )
return 0;
hold_all = str0cmp(hold, "*") == 0;
rm = remote ? remote->sdp_media : NULL, rm_next = NULL;
for (sm = session->sdp_media; sm; sm = sm->m_next, rm = rm_next) {
rm_next = rm ? rm->m_next : NULL;
if (sm->m_rejected)
continue;
if (rm) {
/* Mode bits do not match */
if (((rm->m_mode & sdp_recvonly) == sdp_recvonly)
!= ((sm->m_mode & sdp_sendonly) == sdp_sendonly))
return 1;
}
recv_mode = sm->m_mode & sdp_recvonly;
if (recv_mode && hold &&
(hold_all || strcasestr(hold, sm->m_type_name)))
return 1;
}
return 0;
}
/** Update mode within session */
static
int soa_sdp_mode_set(sdp_session_t *session,
int soa_sdp_mode_set(sdp_session_t const *user,
int const *s2u,
sdp_session_t *session,
sdp_session_t const *remote,
char const *hold)
char const *hold,
int dryrun)
{
sdp_media_t *sm;
sdp_media_t const *rm, *rm_next;
sdp_media_t const *rm, *rm_next, *um;
int retval = 0, i, j;
int hold_all;
int inactive_all;
int inactive = 0;
char const *hold_media = NULL;
sdp_mode_t send_mode, recv_mode;
SU_DEBUG_7(("soa_sdp_mode_set(%p, %p, \"%s\"): called\n",
@@ -1037,25 +1007,58 @@ int soa_sdp_mode_set(sdp_session_t *session,
rm = remote ? remote->sdp_media : NULL, rm_next = NULL;
hold_all = str0cmp(hold, "*") == 0;
inactive_all = str0cmp(hold, "#") == 0;
for (sm = session->sdp_media; sm; sm = sm->m_next, rm = rm_next) {
i = 0;
for (sm = session->sdp_media; sm; sm = sm->m_next, rm = rm_next, i++) {
rm_next = rm ? rm->m_next : NULL;
inactive = 0;
if (sm->m_rejected)
continue;
send_mode = sdp_sendonly;
assert(s2u);
for (j = 0, um = user->sdp_media; j != s2u[i]; um = um->m_next, j++)
assert(um);
assert(um);
send_mode = um->m_mode & sdp_sendonly;
if (rm)
send_mode = (rm->m_mode & sdp_recvonly) ? sdp_sendonly : 0;
recv_mode = sm->m_mode & sdp_recvonly;
if (recv_mode && hold && (hold_all || strcasestr(hold, sm->m_type_name)))
recv_mode = 0;
recv_mode = um->m_mode & sdp_recvonly;
sm->m_mode = recv_mode | send_mode;
if (rm && rm->m_mode == sdp_inactive) {
send_mode = recv_mode = 0;
}
else if (inactive_all) {
send_mode = recv_mode = 0;
}
else if (hold_all) {
recv_mode = 0;
}
else if (hold && (hold_media = strcasestr(hold, sm->m_type_name))) {
recv_mode = 0;
hold_media += strlen(sm->m_type_name);
hold_media += strspn(hold_media, " \t");
if (hold_media[0] == '=') {
hold_media += strspn(hold, " \t");
if (strncasecmp(hold_media, "inactive", strlen("inactive")) == 0)
recv_mode = send_mode = 0;
}
}
if (sm->m_mode != (unsigned)(recv_mode | send_mode))
retval = 1;
if (!dryrun) {
sm->m_mode = recv_mode | send_mode;
}
}
return 0;
return retval;
}
enum offer_answer_action {
@@ -1213,16 +1216,22 @@ static int offer_answer_step(soa_session_t *ss,
/* Step D: Set media mode bits */
switch (action) {
int const *s2u_;
case generate_offer:
case generate_answer:
case process_answer:
if (soa_sdp_mode_set_is_needed(local, remote, ss->ss_hold)) {
s2u_ = s2u;
if (!s2u_) s2u_ = sss->sss_s2u;
if (soa_sdp_mode_set(user, s2u_, local, remote, ss->ss_hold, 1)) {
if (local != local0) {
*local0 = *local, local = local0;
DUP_LOCAL(local);
}
soa_sdp_mode_set(local, remote, ss->ss_hold);
soa_sdp_mode_set(user, s2u_, local, remote, ss->ss_hold, 0);
}
break;
default:
+16 -6
View File
@@ -585,12 +585,22 @@ tag_typedef_t soatag_srtp_integrity = BOOLTAG_TYPEDEF(srtp_integrity);
/**@def SOATAG_HOLD(x)
*
* Hold media stream or streams. When putting a SIP session on hold, the
* application can include, e.g., SOATAG_HOLD("audio") or
* SOATAG_HOLD("video") or SOATAG_HOLD("audio, video") or SOATAG_HOLD("*")
* as @soa parameters. When resuming the session, it can include
* SOATAG_HOLD(NULL). Note that last SOATAG_HOLD() in the tag list will
* override the SOATAG_HOLD() tags before it.
* Hold media stream or streams.
*
* The hold media stream will have the attribute a=sendonly (meaning that
* some hold announcements or pause music is sent to the held party but that
* the held party should not generate any media) or a=inactive (meaning that
* no media is sent).
*
* When putting a SIP session on hold with sendonly, the application can
* include, e.g., SOATAG_HOLD("audio") or SOATAG_HOLD("video") or
* SOATAG_HOLD("audio, video") or SOATAG_HOLD("*") as @soa parameters. When
* using inactive instead, the application should use "#" or
* "audio=inactive" instead. When resuming the session, application should
* include the tag SOATAG_HOLD(NULL).
*
* Note that last SOATAG_HOLD() in the tag list will override the
* SOATAG_HOLD() tags before it.
*
* @par Used with
* soa_set_params(), soa_get_params(), soa_get_paramlist() \n
@@ -238,8 +238,11 @@ SOFIAPUBFUN int soa_has_received_sdp(soa_session_t const *ss);
SOFIAPUBFUN int soa_set_status(soa_session_t *ss,
int status, char const *phrase);
enum soa_activity { soa_activity_local, soa_activity_remote, soa_activity_session };
SOFIAPUBFUN void soa_set_activity(soa_session_t *ss,
sdp_media_t const *m, int remote);
sdp_media_t const *m,
enum soa_activity activity);
SOFIAPUBFUN int soa_description_set(soa_session_t *ss,
struct soa_description *ssd,
+52 -5
View File
@@ -451,20 +451,67 @@ int test_static_offer_answer(struct context *ctx)
TEST(soa_is_audio_active(a), SOA_ACTIVE_SENDONLY);
TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_SENDONLY);
/* 'A' will release hold. */
TEST(soa_set_params(a, SOATAG_HOLD(NULL), TAG_END()), 1);
/* 'A' will put call inactive */
offer = NONE;
TEST(soa_set_params(a, SOATAG_HOLD("#"), TAG_END()), 1);
TEST(soa_generate_offer(a, 1, test_completed), 0);
TEST(soa_get_local_sdp(a, NULL, &offer, &offerlen), 1);
TEST_1(offer != NULL && offer != NONE);
TEST_1(!strstr(offer, "a=sendonly"));
TEST_1(strstr(offer, "a=inactive"));
TEST(soa_set_remote_sdp(b, 0, offer, offerlen), 1);
TEST(soa_generate_answer(b, test_completed), 0);
TEST_1(soa_is_complete(b));
TEST(soa_activate(b, NULL), 0);
TEST(soa_get_local_sdp(b, NULL, &answer, &answerlen), 1);
TEST_1(answer != NULL && answer != NONE);
TEST_1(!strstr(answer, "a=recvonly"));
TEST_1(strstr(answer, "a=inactive"));
TEST(soa_set_remote_sdp(a, 0, answer, -1), 1);
TEST(soa_process_answer(a, test_completed), 0);
TEST(soa_activate(a, NULL), 0);
TEST(soa_is_audio_active(a), SOA_ACTIVE_INACTIVE);
TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_INACTIVE);
/* B will send an offer to A, but there is no change in O/A status */
TEST(soa_generate_offer(b, 1, test_completed), 0);
TEST(soa_get_local_sdp(b, NULL, &offer, &offerlen), 1);
TEST_1(offer != NULL && offer != NONE);
TEST_1(!strstr(offer, "a=inactive"));
printf("offer:\n%s", offer);
TEST(soa_set_remote_sdp(a, 0, offer, offerlen), 1);
TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_SENDRECV);
TEST(soa_generate_answer(a, test_completed), 0);
TEST(soa_is_audio_active(a), SOA_ACTIVE_INACTIVE);
TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_INACTIVE);
TEST_1(soa_is_complete(a));
TEST(soa_activate(a, NULL), 0);
TEST(soa_get_local_sdp(a, NULL, &answer, &answerlen), 1);
TEST_1(answer != NULL && answer != NONE);
TEST_1(strstr(answer, "a=inactive"));
printf("answer:\n%s", answer);
TEST(soa_set_remote_sdp(b, 0, answer, -1), 1);
TEST(soa_process_answer(b, test_completed), 0);
TEST(soa_activate(b, NULL), 0);
TEST(soa_is_audio_active(b), SOA_ACTIVE_INACTIVE);
TEST(soa_is_remote_audio_active(b), SOA_ACTIVE_INACTIVE);
/* 'A' will release hold. */
TEST(soa_set_params(a, SOATAG_HOLD(NULL), TAG_END()), 1);
TEST(soa_generate_offer(a, 1, test_completed), 0);
TEST(soa_get_local_sdp(a, NULL, &offer, &offerlen), 1);
TEST_1(offer != NULL && offer != NONE);
TEST_1(!strstr(offer, "a=sendonly") && !strstr(offer, "a=inactive"));
TEST(soa_set_remote_sdp(b, 0, offer, offerlen), 1);
TEST(soa_generate_answer(b, test_completed), 0);
TEST_1(soa_is_complete(b));
TEST(soa_activate(b, NULL), 0);
TEST(soa_get_local_sdp(b, NULL, &answer, &answerlen), 1);
TEST_1(answer != NULL && answer != NONE);
TEST_1(!strstr(answer, "a=recvonly") && !strstr(answer, "a=inactive"));
TEST(soa_set_remote_sdp(a, 0, answer, -1), 1);
TEST(soa_process_answer(a, test_completed), 0);
TEST(soa_activate(a, NULL), 0);
@@ -1329,7 +1376,7 @@ int test_asynch_offer_answer(struct context *ctx)
{
BEGIN();
#if 0
#if 0 /* This has never been implemented */
int n;
char const *caps = NONE, *offer = NONE, *answer = NONE;
@@ -218,6 +218,16 @@ sres_record_t **sres_cached_answers_sockaddr(sres_resolver_t *res,
uint16_t type,
struct sockaddr const *addr);
/**Modify the priority of the specified SRV records. */
SRESPUBFUN
int sres_set_cached_srv_priority(sres_resolver_t *res,
char const *domain,
char const *target,
uint16_t port,
uint32_t newttl,
uint16_t newprio);
/** Send a query, wait for answer, return results. */
SRESPUBFUN
int sres_blocking_query(sres_resolver_t *res,
@@ -102,6 +102,14 @@ SRESPUBFUN void sres_cache_free_record(sres_cache_t *cache, void *rr);
/** Store a record to cache */
SRESPUBFUN void sres_cache_store(sres_cache_t *, sres_record_t *, time_t now);
/** Modify the priority in the specified SRV record */
SRESPUBFUN int sres_cache_set_srv_priority(sres_cache_t *,
char const *domain,
char const *target,
uint16_t port,
uint32_t newttl,
uint16_t newprio);
#ifdef __cplusplus
}
#endif
@@ -1347,6 +1347,47 @@ sres_cached_answers_sockaddr(sres_resolver_t *res,
return result;
}
/** Set the priority of the matching cached SRV record.
*
* The SRV records with the domain name, target and port are matched and
* their priority value is adjusted. This function is used to implement
* greylisting of SIP servers.
*
* @param res pointer to resolver
* @param domain domain name of the SRV record(s) to modify
* @param target SRV target of the SRV record(s) to modify
* @param port port number of SRV record(s) to modify
* (in host byte order)
* @param ttl new ttl for SRV records of the domain
* @param priority new priority value (0=highest, 65535=lowest)
*
* @sa sres_cache_set_srv_priority()
*
* @NEW_1_12_8
*/
int sres_set_cached_srv_priority(sres_resolver_t *res,
char const *domain,
char const *target,
uint16_t port,
uint32_t ttl,
uint16_t priority)
{
char rooted_domain[SRES_MAXDNAME];
if (res == NULL || res->res_cache == NULL)
return su_seterrno(EFAULT);
domain = sres_toplevel(rooted_domain, sizeof rooted_domain, domain);
if (!domain)
return -1;
return sres_cache_set_srv_priority(res->res_cache,
domain, target, port,
ttl, priority);
}
/** Sort answers. */
int
sres_sort_answers(sres_resolver_t *res, sres_record_t **answers)
@@ -471,6 +471,75 @@ void sres_cache_clean(sres_cache_t *cache, time_t now)
}
}
/** Set the priority of the matching cached SRV record.
*
* The SRV records with the domain name, target and port are matched and
* their priority value is adjusted. This function is used to implement
* greylisting of SIP servers.
*
* @param cache pointer to DNS cache object
* @param domain domain name of the SRV record(s) to modify
* (including final dot)
* @param target SRV target of the SRV record(s) to modify
* @param port port number of SRV record(s) to modify
* (in host byte order)
* @param ttl new ttl
* @param priority new priority value (0=highest, 65535=lowest)
*
* @sa sres_set_cached_srv_priority()
*
* @NEW_1_12_8
*/
int sres_cache_set_srv_priority(sres_cache_t *cache,
char const *domain,
char const *target,
uint16_t port,
uint32_t ttl,
uint16_t priority)
{
int ret = 0;
unsigned hash;
sres_rr_hash_entry_t **iter;
time_t expires;
if (cache == NULL || domain == NULL || target == NULL)
return -1;
hash = sres_hash_key(domain);
if (!LOCK(cache))
return -1;
time(&expires);
expires += ttl;
for (iter = sres_htable_hash(cache->cache_hash, hash);
iter && *iter;
iter = sres_htable_next(cache->cache_hash, iter)) {
sres_record_t *rr = (*iter)->rr;
if (rr && rr->sr_name &&
sres_type_srv == rr->sr_type &&
strcasecmp(rr->sr_name, domain) == 0) {
(*iter)->rr_expires = expires;
if ((port == 0 || rr->sr_srv->srv_port == port) &&
rr->sr_srv->srv_target &&
strcasecmp(rr->sr_srv->srv_target, target) == 0) {
/* record found --> change priority of server */
rr->sr_srv->srv_priority = priority;
ret++;
}
}
}
UNLOCK(cache);
/** @return number of modified entries or -1 upon an error. */
return ret;
}
HTABLE_BODIES_WITH(sres_htable, ht, sres_rr_hash_entry_t, SRES_HENTRY_HASH,
unsigned, size_t);
@@ -34,30 +34,29 @@
* always storing a pointer to element). It can be used without
* <sofia-sip/su_alloc.h>.
*
* This file contain a hash table template for C. The hash tables are
* resizeable, and they usually contain pointers to entries. The
* declaration for template datatypes is instantiated with macro
* HTABLE2_DECLARE(). The prototypes for hashing functions are instantiated
* with macro HTABLE2_PROTOS(). The implementation is instantiated with
* macro HTABLE2_BODIES().
* This file contain a hash table template for C. The hash tables are
* resizeable, and they usually contain pointers to entries. The declaration
* for template datatypes is instantiated with macro HTABLE2_DECLARE2(). The
* prototypes for hashing functions are instantiated with macro
* HTABLE2_PROTOS2(). The implementation is instantiated with macro
* HTABLE2_BODIES2().
*
* The hash table template is most efficient when the hash value is
* precalculated and stored in each entry. The hash "function" given to the
* HTABLE2_BODIES() would then be something like macro
* HTABLE2_BODIES2() would then be something like macro
* @code
* #define HTABLE2_ENTRY_HASH(e) ((e).e_hash_value)
* #define ENTRY_HASH(e) ((e).e_hash_value)
* @endcode
*
* When a entry with new identical hash key is added to the table, it can be
* either @e inserted (before any other entry with same key value) or
* @e appended.
* When a entry with new identical key is added to the table, it can be
* either @e inserted (before any other entry with same key value) or @e
* appended.
*
* Example code can be found from <htable_test.c>.
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>.
*
* @date Created: Tue Sep 25 17:42:40 2001 ppessi
*
*/
typedef unsigned long hash_value_t;
@@ -75,6 +74,8 @@ typedef unsigned long hash_value_t;
* @param sname name of struct
* @param pr hash table field prefix
* @param entrytype entry type
*
* @NEW_1_12_8
*/
#define HTABLE2_DECLARE2(type, sname, pr, entrytype, size_t) \
typedef struct sname { \
@@ -101,6 +102,8 @@ typedef struct sname { \
* @param prefix function prefix
* @param pr hash table field prefix (not used)
* @param entrytype entry type
*
* @NEW_1_12_8
*/
#define HTABLE2_PROTOS2(type, prefix, pr, entrytype, size_t) \
HTABLE2_SCOPE int prefix##_resize(void *a, type *, size_t); \
@@ -131,6 +134,8 @@ HTABLE2_SCOPE int prefix##_remove(type *, entrytype const)
* @param reclaim function or macro zeroing entry
* @param is_equal equality test
* @param halloc function allocating or freeing memory
*
* @NEW_1_12_8
*/
#define HTABLE2_BODIES2(type, prefix, pr, entrytype, size_t, \
hfun, is_used, reclaim, is_equal, halloc) \
@@ -126,7 +126,7 @@ struct addrinfo {
#define AI_MASK (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST)
#endif
/** RFC 1576 address info structure. */
/** @RFC1576 address info structure. */
typedef struct addrinfo su_addrinfo_t;
/** Translate address and service. */
@@ -398,8 +398,8 @@ typedef void su_msg_function(su_root_magic_t *magic,
su_msg_r msg,
su_msg_arg_t *arg);
/** Message deinitialize. */
typedef void su_msg_deinit_func(su_msg_arg_t *arg);
/** Message deinitializer function type. @NEW_1_12_8 */
typedef void su_msg_deinit_function(su_msg_arg_t *arg);
/** Message delivery function pointer type. */
typedef su_msg_function *su_msg_f;
@@ -529,7 +529,7 @@ SOFIAPUBFUN int su_msg_create(su_msg_r msg,
su_task_r const to, su_task_r const from,
su_msg_f wakeup, isize_t size);
SOFIAPUBFUN int su_msg_report(su_msg_r msg, su_msg_f report);
SOFIAPUBFUN int su_msg_deinitializer(su_msg_r msg, su_msg_deinit_func *);
SOFIAPUBFUN int su_msg_deinitializer(su_msg_r msg, su_msg_deinit_function *);
SOFIAPUBFUN int su_msg_reply(su_msg_r reply, su_msg_cr msg,
su_msg_f wakeup, isize_t size);
SOFIAPUBFUN void su_msg_destroy(su_msg_r msg);
@@ -893,6 +893,7 @@ int su_getaddrinfo(char const *node, char const *service,
{
int retval;
su_addrinfo_t *ai;
char const *realservice = service;
if (!service || service[0] == '\0')
service = "0";
@@ -932,6 +933,9 @@ int su_getaddrinfo(char const *node, char const *service,
retval = getaddrinfo(node, service, hints, res);
if (service != realservice && retval == EAI_SERVICE)
retval = getaddrinfo(node, realservice, hints, res);
if (retval == 0) {
for (ai = *res; ai; ai = ai->ai_next) {
if (ai->ai_protocol)
+20 -2
View File
@@ -1494,7 +1494,10 @@ int su_home_mutex_lock(su_home_t *home)
return 0;
}
/** Release exclusive lock on home and decrease refcount (if home is threadsafe) */
/** Release exclusive lock on home and decrease refcount (if home is threadsafe).
*
* @sa su_home_unlock().
*/
int su_home_mutex_unlock(su_home_t *home)
{
if (home == NULL)
@@ -1516,9 +1519,15 @@ int su_home_mutex_unlock(su_home_t *home)
/** Obtain exclusive lock on home without increasing refcount.
*
* Unless su_home_threadsafe() has been used to intialize locking on home
* object the function just returns -1.
*
* @return 0 if successful, -1 if not threadsafe, error code otherwise.
*
* @sa su_home_mutex_lock(), su_home_unlock(), su_home_trylock().
*
* @NEW_1_12_8
*/
int su_home_lock(su_home_t *home)
{
@@ -1537,6 +1546,9 @@ int su_home_lock(su_home_t *home)
* @return 0 if successful, -1 if not threadsafe,
* EBUSY if already locked, error code otherwise.
*
* @sa su_home_lock(), su_home_unlock().
*
* @NEW_1_12_8
*/
int su_home_trylock(su_home_t *home)
{
@@ -1550,9 +1562,15 @@ int su_home_trylock(su_home_t *home)
}
/** Release exclusive lock on home.
/** Release exclusive lock on home.
*
* Release lock without decreasing refcount.
*
* @return 0 if successful, -1 if not threadsafe, error code otherwise.
*
* @sa su_home_lock(), su_home_trylock(), su_home_mutex_unlock().
*
* @NEW_1_12_8
*/
int su_home_unlock(su_home_t *home)
{
@@ -38,6 +38,7 @@
#include <sofia-sip/su_log.h>
#include <sofia-sip/su_debug.h>
#ifdef DOXYGEN_ONLY
/**@var SU_DEBUG
*
* Environment variable determining the debug log level for @b su module.
+1 -1
View File
@@ -67,7 +67,7 @@ struct su_msg_s {
su_task_r sum_from;
su_msg_f sum_func;
su_msg_f sum_report;
su_msg_deinit_func *sum_deinit;
su_msg_deinit_function *sum_deinit;
su_msg_arg_t sum_data[1]; /* minimum size, may be extended */
};
+9 -2
View File
@@ -885,6 +885,8 @@ int su_root_has_thread(su_root_t *root)
*
* @retval 0 if successful,
* @retval -1 if message allocation fails.
*
* @NEW_1_12_8
*/
int su_msg_new(su_msg_r rmsg, size_t size)
{
@@ -957,9 +959,11 @@ int su_msg_report(su_msg_r msg,
*
* @param rmsg message reference
* @param deinit pointer to deinitializer function
*
* @NEW_1_12_8
*/
int su_msg_deinitializer(su_msg_r rmsg,
su_msg_deinit_func *deinit)
su_msg_deinit_function *deinit)
{
if (rmsg && rmsg[0]) {
rmsg[0]->sum_deinit = deinit;
@@ -1156,7 +1160,10 @@ int su_msg_send(su_msg_r rmsg)
return 0;
}
/** Send message to the @a to_task and mark @a from_task as sender */
/** Send message to the @a to_task and mark @a from_task as sender.
*
* @NEW_1_12_8
*/
SOFIAPUBFUN int su_msg_send_to(su_msg_r rmsg,
su_task_r const to_task,
su_msg_f wakeup)
@@ -83,15 +83,15 @@ int main(int argc, char *argv[])
typedef struct hentry_s entry_t;
HTABLE2_DECLARE2(htable2_t, htable2_s, ht2_, entry_t, size_t);
HTABLE2_PROTOS2(htable2_t, htable2, ht2_, entry_t, size_t);
struct hentry_s
{
unsigned long e_hash;
hash_value_t e_hash;
unsigned long e_n;
};
HTABLE2_DECLARE2(htable2_t, htable2_s, ht2_, entry_t, size_t);
HTABLE2_PROTOS2(htable2_t, htable2, ht2_, entry_t, size_t);
#define HENTRY_HASH(e) ((e).e_hash)
#define HENTRY_IS_USED(e) ((e).e_n != 0)
#define HENTRY_REMOVE(e) ((e)->e_n = 0, (e)->e_hash = 0)
@@ -155,7 +155,7 @@ static int test_sockaddr(void)
int test_sendrecv(void)
{
su_socket_t s, l, a;
int n;
ssize_t n;
su_sockaddr_t su, csu;
socklen_t sulen = sizeof su.su_sin, csulen = sizeof csu.su_sin;
char b1[8], b2[8], b3[8];
@@ -172,6 +172,7 @@ int test_sendrecv(void)
BEGIN();
s = su_socket(AF_INET, SOCK_DGRAM, 0); TEST_1(s != -1);
su_setblocking(s, 1);
memset(&su, 0, sulen);
su.su_len = sulen;
@@ -209,6 +210,8 @@ int test_sendrecv(void)
TEST(connect(s, &su.su_sa, sulen), 0);
a = accept(l, &csu.su_sa, &csulen); TEST_1(a != -1);
TEST(su_setblocking(a, 1), 0);
n = su_vsend(s, sv, 3, 0, NULL, 0); TEST(n, 8 + 8 + 6);
n = su_vrecv(a, rv, 3, 0, NULL, NULL); TEST(n, 8 + 8 + 6);
@@ -1009,18 +1009,19 @@ static int test_incomplete(tp_test_t *tt)
s = su_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
TEST_1(s != SOCKET_ERROR);
su_setblocking(s, 1);
connected = connect(s, ai->ai_addr, (socklen_t)ai->ai_addrlen);
su_root_step(tt->tt_root, 50);
TEST(send(s, "F", 1, 0), 1);
TEST(su_send(s, "F", 1, 0), 1);
su_root_step(tt->tt_root, 50);
TEST(send(s, "O", 1, 0), 1);
TEST(su_send(s, "O", 1, 0), 1);
su_root_step(tt->tt_root, 50);
TEST(send(s, "O", 1, 0), 1);
TEST(su_send(s, "O", 1, 0), 1);
su_root_step(tt->tt_root, 50);
TEST(send(s, " ", 1, 0), 1);
TEST(su_send(s, " ", 1, 0), 1);
su_root_step(tt->tt_root, 50);
tt->tt_received = 0;
@@ -371,7 +371,7 @@ struct tport_vtable
int tport_register_type(tport_vtable_t const *vtp);
/** @internal Test if transport is needs connect() before sending. */
/** @internal Test if transport needs connect() before sending. */
su_inline int tport_is_connection_oriented(tport_t const *self)
{
return self->tp_conn_orient;