a little update to the sofia-sip library

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4939 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Michael Jerris committed 2007-04-15 02:03:41 +00:00
1 parent fabed21ea8
commit 853936abd3
270 files changed
+37121 -11402

No files matched your search

+8
View File
@@ -1,3 +1,11 @@
2007-02-09 Kai Vehmanen <kai.vehmanen@nokia.com>
* libsofia-sip-ua interface v4 frozen (4:0:4) for the 1.12.5 release
2006-10-12 Kai Vehmanen <kai.vehmanen@nokia.com>
* libsofia-sip-ua interface v3 frozen (3:0:3) for the 1.12.3 release
2006-09-26 Kai Vehmanen <kai.vehmanen@nokia.com>
* libsofia-sip-ua interface v2 frozen (2:0:2) for the 1.12.2 release
+20 -22
View File
@@ -9,12 +9,25 @@
AUTOMAKE_OPTIONS = foreign
# select whicn optional sofia-sip modules have been enabled
# in the build
OPT_LIBADD =
OPT_SUBDIRS_STUN =
OPT_SUBDIRS_NTH =
if HAVE_STUN
OPT_LIBADD += stun/libstun.la
OPT_SUBDIRS_STUN += stun
endif
if HAVE_NTH
OPT_LIBADD += nth/libnth.la http/libhttp.la
OPT_SUBDIRS_NTH += nth http
endif
# note: order does matter in the subdir list
SUBDIRS = su features bnf sresolv sdp url msg sip stun ipt soa \
tport http nta nea iptsec nth nua
SUBDIRS = su features bnf sresolv sdp url msg sip $(OPT_SUBDIRS_STUN) ipt soa \
tport nta nea iptsec $(OPT_SUBDIRS_NTH) nua
DIST_SUBDIRS = $(SUBDIRS) docs
EXTRA_DIST = sofia.am
DOXYGEN = doxygen
lib_LTLIBRARIES = libsofia-sip-ua.la
@@ -27,37 +40,22 @@ libsofia_sip_ua_la_LIBADD = bnf/libbnf.la \
msg/libmsg.la \
nea/libnea.la \
nta/libnta.la \
nth/libnth.la \
nua/libnua.la \
http/libhttp.la \
sdp/libsdp.la \
sip/libsip.la \
soa/libsoa.la \
sresolv/libsresolv.la \
su/libsu.la \
stun/libstun.la \
tport/libtport.la \
url/liburl.la
url/liburl.la \
$(OPT_LIBADD)
# set the libtool version info version:revision:age for libsofia-sip-ua
# - soname to 'libsofia-sip-ua.so.(CUR-AGE)'
libsofia_sip_ua_la_LDFLAGS = \
-version-info $(LIBVER_SOFIA_SIP_UA_CUR):$(LIBVER_SOFIA_SIP_UA_REV):$(LIBVER_SOFIA_SIP_UA_AGE)
if ENABLE_COVERAGE
COVERAGE_RECURSIVE = coverage-recursive
coverage: $(COVERAGE_RECURSIVE)
endif
all-recursive: built-sources-recursive
built-sources: built-sources-recursive
clean-built-sources: clean-built-sources-recursive
built-sources-recursive clean-built-sources-recursive $(COVERAGE_RECURSIVE):
target=`echo $@ | sed s/-recursive//`; \
list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
echo "Making $@ in $$subdir"; \
(cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$target) \
done;
include $(top_srcdir)/rules/recursive.am
doxygen: built-sources
@echo Generating empty doxytags
@@ -43,4 +43,5 @@ TESTS = torture_bnf
# ----------------------------------------------------------------------
# Sofia specific rules
include ../sofia.am
include $(top_srcdir)/rules/sofia.am
+2 -2
View File
@@ -377,7 +377,7 @@ int canonize_ip6_address(char *host, char *hexparts[9])
if (i == maxparts + 1) {
/* There is an extra doublecolon */
for (j = doublecolon; j <= i; j++)
for (j = doublecolon; j + 1 < i; j++)
hexparts[j] = hexparts[j + 1];
i--;
}
@@ -825,9 +825,9 @@ static size_t convert_ip_address(char const *s,
{
size_t len;
int canonize = 0;
char buf[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
#if SU_HAVE_IN6
char buf[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
len = span_ip6_reference(s);
if (len) {
@@ -340,9 +340,10 @@ int host_test(void)
END();
}
void usage(void)
void usage(int exitcode)
{
fprintf(stderr, "usage: %s [-v]\n", name);
fprintf(stderr, "usage: %s [-v] [-a]\n", name);
exit(exitcode);
}
int main(int argc, char *argv[])
@@ -353,8 +354,10 @@ int main(int argc, char *argv[])
for (i = 1; argv[i]; i++) {
if (strcmp(argv[i], "-v") == 0)
test_flags |= tst_verbatim;
else if (strcmp(argv[i], "-a") == 0)
test_flags |= tst_abort;
else
usage();
usage(1);
}
retval |= bnf_test(); fflush(stdout);
@@ -45,4 +45,8 @@ ALIASES = \
"VERSION_1_12_4=<a href=\"http://sofia-sip.sf.net/relnotes/relnotes-sofia-sip-1.12.4.txt\">1.12.4</a>" \
"VERSION_1_12_5=<a href=\"http://sofia-sip.sf.net/relnotes/relnotes-sofia-sip-1.12.5.txt\">1.12.5</a>" \
"NEW_1_12_5=@since New in <a href=\"http://sofia-sip.sf.net/relnotes/relnotes-sofia-sip-1.12.5.txt\">1.12.5</a>" \
"EXP_1_12_5=@since Experimental in <a href=\"http://sofia-sip.sf.net/relnotes/relnotes-sofia-sip-1.12.5.txt\">1.12.5</a>, available if --enable-experimental configuration option is given" \
"VERSION_1_12_6=<a href=\"http://sofia-sip.sf.net/relnotes/relnotes-sofia-sip-1.12.6.txt\">1.12.6</a>" \
"NEW_1_12_6=@since New in <a href=\"http://sofia-sip.sf.net/relnotes/relnotes-sofia-sip-1.12.6.txt\">1.12.6</a>" \
"EXP_1_12_6=@since Experimental in <a href=\"http://sofia-sip.sf.net/relnotes/relnotes-sofia-sip-1.12.6.txt\">1.12.6</a>, available if --enable-experimental configuration option is given" \
@@ -47,4 +47,4 @@ CLEANFILES = Doxyfile.rfc
# ----------------------------------------------------------------------
# Sofia specific rules
include ../sofia.am
include $(top_srcdir)/rules/sofia.am
@@ -31,4 +31,5 @@ EXTRA_DIST = Doxyfile features.docs
# ----------------------------------------------------------------------
# Sofia specific rules
include ../sofia.am
include $(top_srcdir)/rules/sofia.am
+20 -20
View File
@@ -30,17 +30,17 @@ PUBLIC_H = sofia-sip/http.h sofia-sip/http_header.h \
sofia-sip/http_status.h sofia-sip/http_hclasses.h
BUILT_H = sofia-sip/http_protos.h sofia-sip/http_tag.h
BUILT_C = http_tag.c http_tag_ref.c http_parser_table.c
BUILT_C = http_tag.c http_parser_table.c
BUILT_SOURCES = $(BUILT_H) $(BUILT_C)
BUILT_SOURCES = $(BUILT_H) $(BUILT_C) http_tag_ref.c
nobase_include_sofia_HEADERS = $(BUILT_H) $(PUBLIC_H)
libhttp_la_SOURCES = $(INTERNAL_H) \
http_parser.c http_header.c \
http_basic.c http_extra.c \
http_basic.c http_extra.c http_inlined.c \
http_status.c http_tag_class.c \
$(BUILT_C)
$(BUILT_SOURCES)
COVERAGE_INPUT = $(libhttp_la_SOURCES) $(include_sofia_HEADERS)
@@ -48,6 +48,7 @@ LDADD = libhttp.la \
../bnf/libbnf.la \
../msg/libmsg.la \
../url/liburl.la \
../ipt/libipt.la \
../su/libsu.la
test_http_LDFLAGS = -static
@@ -64,30 +65,29 @@ EXTRA_DIST = Doxyfile http.docs \
# ----------------------------------------------------------------------
# Sofia specific rules
include ../sofia.am
include $(top_srcdir)/rules/sofia.am
TAG_DLL_FLAGS = DLLREF=1
MSG_PARSER_AWK = $(srcdir)/../msg/msg_parser.awk
MSG_PARSER_AWK = ${srcdir}/../msg/msg_parser.awk
AWK_HTTP_AWK = $(AWK) -f $(MSG_PARSER_AWK) module=http
AWK_HTTP_AWK = ${AWK} -f ${MSG_PARSER_AWK} module=http
sofia-sip/http_tag.h: sofia-sip/http_tag.h.in $(MSG_PARSER_AWK)
sofia-sip/http_protos.h: sofia-sip/http_protos.h.in $(MSG_PARSER_AWK)
http_tag.c: http_tag.c.in $(MSG_PARSER_AWK)
http_parser_table.c: http_parser_table.c.in $(MSG_PARSER_AWK)
SS_HTTP_H = ${srcdir}/sofia-sip/http.h
sofia-sip/http_protos.h: sofia-sip/http.h
${BUILT_H} ${BUILT_C}: ${srcdir}/sofia-sip/http.h ${MSG_PARSER_AWK}
sofia-sip/http_protos.h: ${srcdir}/sofia-sip/http_protos.h.in
@-mkdir sofia-sip 2>/dev/null || true
$(AWK_HTTP_AWK) PR=$@ TEMPLATE=$(srcdir)/sofia-sip/http_protos.h.in $<
${AWK_HTTP_AWK} PR=$@ TEMPLATE=${srcdir}/$@.in ${SS_HTTP_H}
sofia-sip/http_tag.h: sofia-sip/http.h
sofia-sip/http_tag.h: ${srcdir}/sofia-sip/http_tag.h.in
@-mkdir sofia-sip 2>/dev/null || true
$(AWK_HTTP_AWK) PR=$@ TEMPLATE=$(srcdir)/sofia-sip/http_tag.h.in $<
${AWK_HTTP_AWK} PR=$@ TEMPLATE=${srcdir}/$@.in ${SS_HTTP_H}
http_tag.c: sofia-sip/http.h
$(AWK_HTTP_AWK) PR=$@ TEMPLATE=$(srcdir)/http_tag.c.in $<
http_tag.c: ${srcdir}/http_tag.c.in
${AWK_HTTP_AWK} PR=$@ TEMPLATE=${srcdir}/$@.in ${SS_HTTP_H}
http_parser_table.c: sofia-sip/http.h
$(AWK_HTTP_AWK) PT=$@ TEMPLATE=$(srcdir)/http_parser_table.c.in \
MC_HASH_SIZE=127 $<
http_parser_table.c: ${srcdir}/http_parser_table.c.in
${AWK_HTTP_AWK} PT=$@ TEMPLATE=${srcdir}/$@.in \
MC_HASH_SIZE=127 ${SS_HTTP_H}
@@ -55,6 +55,7 @@
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <limits.h>
/* ====================================================================== */
@@ -1196,7 +1197,7 @@ char *http_range_dup_one(msg_header_t *dst, msg_header_t const *src,
http_range_t const *o = (http_range_t const *)src;
char *end = b + xtra;
b = msg_params_dup((char const * const **)&rng->rng_specs,
b = msg_params_dup((msg_param_t const **)&rng->rng_specs,
o->rng_specs, b, xtra);
MSG_STRING_DUP(b, rng->rng_unit, o->rng_unit);
@@ -0,0 +1,52 @@
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@nokia.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
/**@CFILE http_inlined.c
*
* Expand inlined http functions non-inline.
*
*/
#include "config.h"
#include <sofia-sip/su_config.h>
#if SU_HAVE_INLINE
extern int xyzzy;
#else
#include "sofia-sip/msg_header.h"
#include "sofia-sip/su_tag.h"
#undef SU_HAVE_INLINE
#undef su_inline
#define SU_HAVE_INLINE 1
#define su_inline
#include "sofia-sip/http_header.h"
#endif
@@ -61,9 +61,9 @@ char const http_version_1_0[] = "HTTP/1.0";
/** HTTP version 0.9 is an empty string. */
char const http_version_0_9[] = "";
msg_mclass_t *http_default_mclass(void)
msg_mclass_t const *http_default_mclass(void)
{
extern msg_mclass_t http_mclass[];
extern msg_mclass_t const http_mclass[];
return http_mclass;
}
@@ -95,7 +95,7 @@ SOFIAPUBVAR char const http_version_1_1[];
*/
/** HTTP parser description. */
SOFIAPUBFUN msg_mclass_t *http_default_mclass(void);
SOFIAPUBFUN msg_mclass_t const *http_default_mclass(void);
/** Complete a HTTP request. */
SOFIAPUBFUN int http_request_complete(msg_t *msg);
@@ -76,14 +76,7 @@ static int http_tag_test(void);
static int test_query_parser(void);
static msg_t *read_message(char const string[]);
msg_mclass_t *test_mclass = NULL;
void usage(void)
{
fprintf(stderr,
"usage: %s [-v]\n",
name);
}
msg_mclass_t const *test_mclass = NULL;
char *lastpart(char *path)
{
@@ -95,6 +88,14 @@ char *lastpart(char *path)
int tstflags;
void usage(int exitcode)
{
fprintf(stderr,
"usage: %s [-v] [-a]\n",
name);
exit(exitcode);
}
int main(int argc, char *argv[])
{
int retval = 0;
@@ -105,8 +106,10 @@ int main(int argc, char *argv[])
for (i = 1; argv[i]; i++) {
if (strcmp(argv[i], "-v") == 0)
tstflags |= tst_verbatim;
else if (strcmp(argv[i], "-a") == 0)
tstflags |= tst_abort;
else
usage();
usage(1);
}
if (!test_mclass)
@@ -51,4 +51,5 @@ EXTRA_DIST += Doxyfile ipt.docs
# ----------------------------------------------------------------------
# Sofia specific rules
include ../sofia.am
include $(top_srcdir)/rules/sofia.am
@@ -57,6 +57,9 @@ SOFIAPUBFUN isize_t base64_e(char buf[], isize_t bsiz, void *data, isize_t dsiz)
/** Calculate size of n bytes encoded in base64 */
#define BASE64_SIZE(n) ((((n) + 2) / 3) * 4)
/** Calculate size of n bytes encoded in base64 sans trailing =. @NEW_1_12_5 */
#define BASE64_MINSIZE(n) ((n * 4 + 2) / 3)
SOFIA_END_DECLS
#endif /* !BASE_64 */
@@ -43,56 +43,39 @@
SOFIA_BEGIN_DECLS
#if SU_HAVE_INLINE
su_inline
#else
SOFIAPUBFUN
#endif
int
str0cmp(char const *a, char const *b),
str0ncmp(char const *a, char const *b, size_t n),
str0casecmp(char const *a, char const *b),
str0ncasecmp(char const *a, char const *b, size_t n);
#if SU_HAVE_INLINE
su_inline
#else
SOFIAPUBFUN
#endif
size_t
strnspn(char const *s, size_t size, char const *term),
strncspn(char const *s, size_t ssize, char const *reject);
#if SU_HAVE_INLINE
int str0cmp(char const *a, char const *b)
su_inline int str0cmp(char const *a, char const *b)
{
if (a == NULL) a = "";
if (b == NULL) b = "";
return strcmp(a, b);
}
int str0ncmp(char const *a, char const *b, size_t n)
su_inline int str0ncmp(char const *a, char const *b, size_t n)
{
if (a == NULL) a = "";
if (b == NULL) b = "";
return strncmp(a, b, n);
}
int str0casecmp(char const *a, char const *b)
su_inline int str0casecmp(char const *a, char const *b)
{
if (a == NULL) a = "";
if (b == NULL) b = "";
return strcasecmp(a, b);
}
int str0ncasecmp(char const *a, char const *b, size_t n)
su_inline int str0ncasecmp(char const *a, char const *b, size_t n)
{
if (a == NULL) a = "";
if (b == NULL) b = "";
return strncasecmp(a, b, n);
}
size_t strnspn(char const *s, size_t ssize, char const *term)
#if !SU_HAVE_INLINE
SOFIAPUBFUN size_t strnspn(char const *s, size_t size, char const *term);
SOFIAPUBFUN size_t strncspn(char const *s, size_t ssize, char const *reject);
#else
su_inline size_t strnspn(char const *s, size_t ssize, char const *term)
{
size_t n;
size_t tsize = strlen(term);
@@ -123,7 +106,7 @@ size_t strnspn(char const *s, size_t ssize, char const *term)
return n;
}
size_t strncspn(char const *s, size_t ssize, char const *reject)
su_inline size_t strncspn(char const *s, size_t ssize, char const *reject)
{
size_t n;
size_t rsize = strlen(reject);
@@ -161,11 +161,12 @@ int test_decoding(void)
}
void usage(void)
void usage(int exitcode)
{
fprintf(stderr,
"usage: %s [-v]\n",
"usage: %s [-v] [-a]\n",
name);
exit(exitcode);
}
int main(int argc, char *argv[])
@@ -176,8 +177,10 @@ int main(int argc, char *argv[])
for (i = 1; argv[i]; i++) {
if (strcmp(argv[i], "-v") == 0)
tstflags |= tst_verbatim;
else if (strcmp(argv[i], "-a") == 0)
tstflags |= tst_abort;
else
usage();
usage(1);
}
retval |= test_encoding(); fflush(stdout);
@@ -11,6 +11,7 @@ TAGFILES += ../docs/bnf.doxytags=../bnf
TAGFILES += ../docs/url.doxytags=../url
TAGFILES += ../docs/msg.doxytags=../msg
TAGFILES += ../docs/sip.doxytags=../sip
TAGFILES += ../docs/http.doxytags=../http
TAGFILES += ../docs/sresolv.doxytags=../sresolv
TAGFILES += ../docs/tport.doxytags=../tport
TAGFILES += ../docs/nta.doxytags=../nta
@@ -18,3 +19,6 @@ TAGFILES += ../docs/nta.doxytags=../nta
GENERATE_TAGFILE = ../docs/iptsec.doxytags
ALIASES +=
PREDEFINED += SOFIA_EXTEND_AUTH_CLIENT=1
@@ -35,29 +35,18 @@ nobase_include_sofia_HEADERS = \
sofia-sip/auth_common.h \
sofia-sip/auth_client.h sofia-sip/auth_digest.h \
sofia-sip/auth_module.h sofia-sip/auth_plugin.h \
sofia-sip/auth_client_plugin.h \
$(NTLM_HEADER)
sofia-sip/auth_client_plugin.h
libiptsec_la_SOURCES = iptsec_debug.h \
auth_client.c auth_common.c auth_digest.c \
auth_module.c auth_tag.c auth_tag_ref.c \
auth_plugin.c auth_plugin_delayed.c \
auth_module_http.c auth_module_sip.c \
$(NTLM_SOURCE) \
auth_module_sip.c \
iptsec_debug.c
NTLM_HEADER = sofia-sip/auth_ntlm.h
if HAVE_NTLM
NTLM_SOURCE = auth_ntlm.c auth_client_ntlm.c auth_plugin_ntlm.c
endif
EXTRA_libiptsec_la_SOURCES = \
auth_ntlm.c auth_client_ntlm.c auth_plugin_ntlm.c
COVERAGE_INPUT = $(libiptsec_la_SOURCES) $(include_sofia_HEADERS)
LDADD = libiptsec.la \
../http/libhttp.la \
../nta/libnta.la \
../sip/libsip.la \
../msg/libmsg.la \
@@ -68,13 +57,31 @@ LDADD = libiptsec.la \
test_auth_digest_LDFLAGS = -static
if HAVE_NTLM
nobase_include_sofia_HEADERS += $(NTLM_HEADER)
libiptsec_la_SOURCES += $(NTLM_SOURCE)
endif
if HAVE_NTH
libiptsec_la_SOURCES += $(HTTP_SOURCE)
LDADD += ../http/libhttp.la
endif
HTTP_SOURCE = auth_module_http.c
NTLM_HEADER = sofia-sip/auth_ntlm.h
NTLM_SOURCE = auth_ntlm.c auth_client_ntlm.c auth_plugin_ntlm.c
EXTRA_libiptsec_la_SOURCES = \
$(NTLM_HEADER) $(NTLM_SOURCE) $(HTTP_SOURCE)
# ----------------------------------------------------------------------
# Install and distribution rules
EXTRA_DIST = Doxyfile iptsec.docs testpasswd \
auth_module_sip.c auth_module_http.c $(BUILT_SOURCES)
EXTRA_DIST = Doxyfile iptsec.docs testpasswd $(BUILT_SOURCES)
# ----------------------------------------------------------------------
# Sofia specific rules
include ../sofia.am
include $(top_srcdir)/rules/sofia.am
@@ -31,6 +31,8 @@
#include "config.h"
#define SOFIA_EXTEND_AUTH_CLIENT 1
#include <sofia-sip/su.h>
#include <sofia-sip/su_md5.h>
@@ -77,9 +79,7 @@ static int ca_credentials(auth_client_t *ca,
char const *user,
char const *pass);
static int ca_clear_credentials(auth_client_t *ca,
char const *scheme,
char const *realm);
static int ca_clear_credentials(auth_client_t *ca);
/** Initialize authenticators.
@@ -178,29 +178,31 @@ int ca_challenge(auth_client_t *ca,
return -1;
if (!ca->ca_credential_class)
stale = 1, ca->ca_credential_class = credential_class;
stale = 2, ca->ca_credential_class = credential_class;
return stale ? 2 : 1;
return stale > 1 ? 2 : 1;
}
/** Store authentication info to authenticators.
*
* The function auc_info() feeds the authentication data from the
* authentication info @a info to the list of authenticators @a auc_list.
* The function auc_info() feeds the authentication data from the @b
* Authentication-Info header @a info to the list of authenticators @a
* auc_list.
*
* @param[in,out] auc_list list of authenticators to be updated
* @param[in] info info to be processed
* @param[in] crcl corresponding credential class
* @param[in] info info header to be processed
* @param[in] credential_class corresponding credential class
*
* The authentication info can be in either Authentication-Info or in
* Proxy-Authentication-Info headers.
* If the header is Authentication-Info, the @a crcl should be
* #sip_authorization_class or #http_authorization_class.
* Likewise, If the header is Proxy-Authentication-Info, the @a crcl should
* be #sip_proxy_authorization_class or #http_proxy_authorization_class.
* The authentication info can be in either @AuthenticationInfo or in
* @ProxyAuthenticationInfo headers. If the header is @AuthenticationInfo,
* the @a credential_class should be #sip_authorization_class or
* #http_authorization_class. Likewise, If the header is
* @ProxyAuthenticationInfo, the @a credential_class should be
* #sip_proxy_authorization_class or #http_proxy_authorization_class.
* The authentication into usually contains next nonce or mutual
* authentication information. We handle only nextnonce parameter.
* The authentication into header usually contains next nonce or mutual
* authentication information. Currently, only the nextnonce parameter is
* processed.
*
* @bug
* The result can be quite unexpected if there are more than one
@@ -210,9 +212,11 @@ int ca_challenge(auth_client_t *ca,
* @retval number of challenges to updated
* @retval 0 when there was no challenge to update
* @retval -1 upon an error
*
* @NEW_1_12_5
*/
int auc_info(auth_client_t **auc_list,
msg_auth_info_t const *ai,
msg_auth_info_t const *info,
msg_hclass_t *credential_class)
{
auth_client_t *ca;
@@ -222,7 +226,7 @@ int auc_info(auth_client_t **auc_list,
/* Update matching authenticator */
for (ca = *auc_list; ca; ca = ca->ca_next) {
int updated = ca_info(ca, ai, credential_class);
int updated = ca_info(ca, info, credential_class);
if (updated < 0)
return -1;
if (updated >= 1)
@@ -241,12 +245,12 @@ int auc_info(auth_client_t **auc_list,
*/
static
int ca_info(auth_client_t *ca,
msg_auth_info_t const *ai,
msg_auth_info_t const *info,
msg_hclass_t *credential_class)
{
assert(ca); assert(ai);
assert(ca); assert(info);
if (!ca || !ai)
if (!ca || !info)
return -1;
if (!ca->ca_credential_class)
@@ -261,7 +265,7 @@ int ca_info(auth_client_t *ca,
|| !ca->ca_auc->auc_info)
return 0;
return ca->ca_auc->auc_info(ca, ai);
return ca->ca_auc->auc_info(ca, info);
}
@@ -336,8 +340,8 @@ int auc_credentials(auth_client_t **auc_list, su_home_t *home,
* @param[in] user username
* @param[in] pass password
*
* @retval number of matching clients
* @retval 0 when no matching client was found
* @retval number of updated clients
* @retval 0 when no client was updated
* @retval -1 upon an error
*/
int auc_all_credentials(auth_client_t **auc_list,
@@ -371,6 +375,9 @@ int ca_credentials(auth_client_t *ca,
char const *user,
char const *pass)
{
char *new_user, *new_pass;
char *old_user, *old_pass;
assert(ca);
if (!ca || !ca->ca_scheme || !ca->ca_realm)
@@ -380,12 +387,24 @@ int ca_credentials(auth_client_t *ca,
(realm != NULL && strcmp(realm, ca->ca_realm)))
return -1;
ca->ca_user = su_strdup(ca->ca_home, user);
ca->ca_pass = su_strdup(ca->ca_home, pass);
old_user = ca->ca_user, old_pass = ca->ca_pass;
if (!ca->ca_user || !ca->ca_pass)
if (str0cmp(user, old_user) == 0 && str0cmp(pass, old_pass) == 0)
return 0;
new_user = su_strdup(ca->ca_home, user);
new_pass = su_strdup(ca->ca_home, pass);
if (!new_user || !new_pass)
return -1;
ca->ca_user = new_user, ca->ca_pass = new_pass;
if (AUTH_CLIENT_IS_EXTENDED(ca))
ca->ca_clear = 0;
su_free(ca->ca_home, old_user);
su_free(ca->ca_home, old_pass);
return 1;
}
@@ -412,12 +431,15 @@ int auc_copy_credentials(auth_client_t **dst,
char *u, *p;
if (!ca->ca_user || !ca->ca_pass)
continue;
if (AUTH_CLIENT_IS_EXTENDED(ca) && ca->ca_clear)
continue;
if (!ca->ca_scheme[0] || strcmp(ca->ca_scheme, d->ca_scheme))
continue;
if (!ca->ca_realm[0] || strcmp(ca->ca_realm, d->ca_realm))
continue;
if (d->ca_user && strcmp(d->ca_user, ca->ca_user) == 0 &&
if (!(AUTH_CLIENT_IS_EXTENDED(d) && d->ca_clear) &&
d->ca_user && strcmp(d->ca_user, ca->ca_user) == 0 &&
d->ca_pass && strcmp(d->ca_pass, ca->ca_pass) == 0) {
retval++;
break;
@@ -431,6 +453,9 @@ int auc_copy_credentials(auth_client_t **dst,
if (d->ca_user) su_free(d->ca_home, (void *)d->ca_user);
if (d->ca_pass) su_free(d->ca_home, (void *)d->ca_pass);
d->ca_user = u, d->ca_pass = p;
if (AUTH_CLIENT_IS_EXTENDED(d))
d->ca_clear = 0;
retval++;
break;
}
@@ -453,13 +478,24 @@ int auc_copy_credentials(auth_client_t **dst,
* @retval -1 upon an error
*/
int auc_clear_credentials(auth_client_t **auc_list,
char const *scheme,
char const *realm)
char const *scheme,
char const *realm)
{
int retval = 0;
int match;
for (; *auc_list; auc_list = &(*auc_list)->ca_next) {
int match = ca_clear_credentials(*auc_list, scheme, realm);
auth_client_t *ca = *auc_list;
if (!AUTH_CLIENT_IS_EXTENDED(ca))
continue;
if ((scheme != NULL && strcasecmp(scheme, ca->ca_scheme)) ||
(realm != NULL && strcmp(realm, ca->ca_realm)))
continue;
match = ca->ca_auc->auc_clear(*auc_list);
if (match < 0) {
retval = -1;
break;
@@ -472,21 +508,14 @@ int auc_clear_credentials(auth_client_t **auc_list,
}
static
int ca_clear_credentials(auth_client_t *ca,
char const *scheme,
char const *realm)
int ca_clear_credentials(auth_client_t *ca)
{
assert(ca);
assert(ca); assert(ca->ca_home->suh_size >= (int)(sizeof *ca));
if (!ca || !ca->ca_scheme || !ca->ca_realm)
if (!ca)
return -1;
if ((scheme != NULL && strcasecmp(scheme, ca->ca_scheme)) ||
(realm != NULL && strcmp(realm, ca->ca_realm)))
return -1;
su_free(ca->ca_home, (void *)ca->ca_user), ca->ca_user = NULL;
su_free(ca->ca_home, (void *)ca->ca_pass), ca->ca_pass = NULL;
ca->ca_clear = 1;
return 1;
}
@@ -495,6 +524,8 @@ int ca_clear_credentials(auth_client_t *ca,
*
* @retval 1 when authorization can proceed
* @retval 0 when there is not enough credentials
*
* @NEW_1_12_5
*/
int auc_has_authorization(auth_client_t **auc_list)
{
@@ -507,6 +538,8 @@ int auc_has_authorization(auth_client_t **auc_list)
for (ca = *auc_list; ca; ca = ca->ca_next) {
if (!ca->ca_user || !ca->ca_pass || !ca->ca_credential_class)
return 0;
if (AUTH_CLIENT_IS_EXTENDED(ca) && ca->ca_clear)
return 0;
}
return 1;
@@ -564,8 +597,11 @@ int auc_authorization(auth_client_t **auc_list, msg_t *msg, msg_pub_t *pub,
if (!ca->ca_auc)
continue;
if (ca->ca_auc->auc_authorize(ca, home, method, url, body, &h) < 0
|| msg_header_insert(msg, pub, h) < 0)
if (ca->ca_auc->auc_authorize(ca, home, method, url, body, &h) < 0)
return -1;
if (h == NULL)
continue;
if (msg_header_insert(msg, pub, h) < 0)
return -1;
}
@@ -633,14 +669,15 @@ static int auc_basic_authorization(auth_client_t *ca,
msg_payload_t const *body,
msg_header_t **);
const auth_client_plugin_t ca_basic_plugin =
static const auth_client_plugin_t ca_basic_plugin =
{
/* auc_plugin_size: */ sizeof ca_basic_plugin,
/* auc_size: */ sizeof (auth_client_t),
/* auc_name: */ "Basic",
/* auc_challenge: */ NULL,
/* auc_authorize: */ auc_basic_authorization,
/* auc_info: */ NULL
/* auc_info: */ NULL,
/* auc_clear: */ ca_clear_credentials
};
/**Create a basic authorization header.
@@ -677,6 +714,9 @@ int auc_basic_authorization(auth_client_t *ca,
if (user == NULL || pass == NULL)
return -1;
if (AUTH_CLIENT_IS_EXTENDED(ca) && ca->ca_clear)
return 0;
ulen = strlen(user), plen = strlen(pass), uplen = ulen + 1 + plen;
b64len = BASE64_SIZE(uplen);
basiclen = strlen("Basic ") + b64len;
@@ -731,7 +771,7 @@ static int auc_digest_authorization(auth_client_t *ca,
msg_payload_t const *body,
msg_header_t **);
static int auc_digest_info(auth_client_t *ca,
msg_auth_info_t const *ai);
msg_auth_info_t const *info);
static const auth_client_plugin_t ca_digest_plugin =
{
@@ -740,10 +780,15 @@ static const auth_client_plugin_t ca_digest_plugin =
/* auc_name: */ "Digest",
/* auc_challenge: */ auc_digest_challenge,
/* auc_authorize: */ auc_digest_authorization,
/* auc_info: */ auc_digest_info
/* auc_info: */ auc_digest_info,
/* auc_clear: */ ca_clear_credentials
};
/** Store a digest authorization challenge.
*
* @retval 2 if credentials need to be (re)sent
* @retval 1 if challenge was updated
* @retval -1 upon an error
*/
static int auc_digest_challenge(auth_client_t *ca, msg_auth_t const *ch)
{
@@ -761,27 +806,18 @@ static int auc_digest_challenge(auth_client_t *ca, msg_auth_t const *ch)
if (ac->ac_qop && !ac->ac_auth && !ac->ac_auth_int)
goto error;
stale = ac->ac_stale || str0cmp(ac->ac_nonce, cda->cda_ac->ac_nonce);
stale = ac->ac_stale || cda->cda_ac->ac_nonce == NULL;
if (ac->ac_qop && (cda->cda_cnonce == NULL || ac->ac_stale)) {
su_guid_t guid[1];
char *cnonce;
char *e;
size_t b64len = BASE64_MINSIZE(sizeof(guid)) + 1;
if (cda->cda_cnonce != NULL)
/* Free the old one if we are updating after stale=true */
su_free(home, (void *)cda->cda_cnonce);
su_guid_generate(guid);
cda->cda_cnonce = cnonce = su_alloc(home, BASE64_SIZE(sizeof(guid)) + 1);
base64_e(cnonce, BASE64_SIZE(sizeof(guid)) + 1, guid, sizeof(guid));
/* somewhere else in the code the '=' chars are stripped in the header
we need to strip it now before the digest is created or we're in trouble
cos they won't match.....
*/
e = cnonce + strlen(cnonce) - 1;
while(*e == '=') {
*e-- = '\0';
}
cda->cda_cnonce = cnonce = su_alloc(home, b64len);
base64_e(cnonce, b64len, guid, sizeof(guid));
cda->cda_ncount = 0;
}
@@ -797,14 +833,14 @@ static int auc_digest_challenge(auth_client_t *ca, msg_auth_t const *ch)
}
static int auc_digest_info(auth_client_t *ca,
msg_auth_info_t const *ai)
msg_auth_info_t const *info)
{
auth_digest_client_t *cda = (auth_digest_client_t *)ca;
su_home_t *home = ca->ca_home;
char const *nextnonce = NULL;
issize_t n;
n = auth_get_params(home, ai->ai_params,
n = auth_get_params(home, info->ai_params,
"nextnonce=", &nextnonce,
NULL);
@@ -825,9 +861,9 @@ static int auc_digest_info(auth_client_t *ca,
* sip_authorization_class or sip_proxy_authorization_class, as well as
* http_authorization_class or http_proxy_authorization_class.
*
* @return
* Returns a pointer to newly created authorization header, or NULL upon an
* error.
* @retval 1 when authorization headers has been created
* @retval 0 when there is no credentials
* @retval -1 upon an error
*/
static
int auc_digest_authorization(auth_client_t *ca,
@@ -853,6 +889,9 @@ int auc_digest_authorization(auth_client_t *ca,
auth_response_t ar[1] = {{ 0 }};
char ncount[17];
if (!user || !pass || (AUTH_CLIENT_IS_EXTENDED(ca) && ca->ca_clear))
return 0;
ar->ar_size = sizeof(ar);
ar->ar_username = user;
ar->ar_realm = ac->ac_realm;
@@ -76,6 +76,7 @@ static char const __func__[] = "auth_mod";
char const auth_internal_server_error[] = "Internal server error";
static void auth_call_scheme_destructor(void *);
static void auth_md5_hmac_key(auth_mod_t *am);
HTABLE_PROTOS_WITH(auth_htable, aht, auth_passwd_t, usize_t, unsigned);
@@ -94,7 +95,7 @@ auth_mod_t *auth_mod_alloc(auth_scheme_t *scheme,
if ((am = su_home_new(scheme->asch_size))) {
am->am_scheme = scheme;
am->am_refcount = 1;
su_home_destructor(am->am_home, auth_call_scheme_destructor);
}
return am;
@@ -246,10 +247,14 @@ int auth_init_default(auth_mod_t *am,
/** Destroy (a reference to) an authentication module. */
void auth_mod_destroy(auth_mod_t *am)
{
if (am && am->am_refcount != 0 && --am->am_refcount == 0) {
am->am_scheme->asch_destroy(am);
su_home_zap(am->am_home);
}
su_home_unref(am->am_home);
}
/** Call scheme-specific destructor function. */
static void auth_call_scheme_destructor(void *arg)
{
auth_mod_t *am = arg;
am->am_scheme->asch_destroy(am);
}
/** Do-nothing destroy function.
@@ -264,18 +269,13 @@ void auth_destroy_default(auth_mod_t *am)
/** Create a new reference to authentication module. */
auth_mod_t *auth_mod_ref(auth_mod_t *am)
{
if (!am || am->am_refcount == 0)
return NULL;
am->am_refcount++;
return am;
return (auth_mod_t *)su_home_ref(am->am_home);
}
/** Destroy a reference to an authentication module. */
void auth_mod_unref(auth_mod_t *am)
{
auth_mod_destroy(am);
su_home_unref(am->am_home);
}
/** Get authenticatin module name. @NEW_1_12_4. */
@@ -608,7 +608,7 @@ struct nonce {
uint8_t digest[6];
};
#define AUTH_DIGEST_NONCE_LEN (BASE64_SIZE(sizeof (struct nonce)) + 1)
#define AUTH_DIGEST_NONCE_LEN (BASE64_MINSIZE(sizeof (struct nonce)) + 1)
/** Authenticate a request with @b Digest authentication scheme.
*
@@ -950,7 +950,8 @@ int auth_readdb_if_needed(auth_mod_t *am)
#include <sys/file.h>
#endif
#define auth_apw_local auth_readdb_internal
/* This is just a magic value */
#define auth_apw_local ((void *)(intptr_t)auth_readdb_internal)
/** Read authentication database */
static
@@ -126,7 +126,7 @@ static int delayed_auth_init(auth_mod_t *am,
struct auth_splugin_t
{
void const *asp_tag;
void const *asp_cookie;
auth_splugin_t *asp_next;
auth_splugin_t **asp_prev;
auth_mod_t *asp_am;
@@ -136,6 +136,8 @@ struct auth_splugin_t
int asp_canceled;
};
/* This is unique identifier */
#define delayed_asp_cookie ((void const *)(intptr_t)delayed_auth_cancel)
static void delayed_auth_method_recv(su_root_magic_t *rm,
su_msg_r msg,
@@ -162,7 +164,7 @@ static void delayed_auth_method(auth_mod_t *am,
asp = su_msg_data(mamc); assert(asp);
asp->asp_tag = delayed_auth_cancel;
asp->asp_cookie = delayed_asp_cookie;
asp->asp_am = am;
asp->asp_as = as;
asp->asp_header = auth;
@@ -216,7 +218,7 @@ static void delayed_auth_cancel(auth_mod_t *am, auth_status_t *as)
(void)ap; /* xyzzy */
if (as->as_plugin && as->as_plugin->asp_tag == delayed_auth_cancel)
if (as->as_plugin && as->as_plugin->asp_cookie == delayed_asp_cookie)
as->as_plugin->asp_canceled = 1;
as->as_status = 500, as->as_phrase = "Authentication canceled";
@@ -29,6 +29,9 @@
/**@file sofia-sip/auth_client_plugin.h
* @brief Client-side plugin interface for authentication
*
* @note For extensions in 1.12.6 or later,
* you have to #define SOFIA_EXTEND_AUTH_CLIENT to 1.
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
*
* @date Created: Fri May 19 16:18:21 EEST 2006
@@ -58,6 +61,10 @@ struct auth_client_s {
char *ca_pass;
msg_hclass_t *ca_credential_class;
#if SOFIA_EXTEND_AUTH_CLIENT
int ca_clear;
#endif
};
struct auth_client_plugin
@@ -81,8 +88,19 @@ struct auth_client_plugin
/** Store nextnonce from Authentication-Info or Proxy-Authentication-Info. */
int (*auc_info)(auth_client_t *ca, msg_auth_info_t const *ai);
#if SOFIA_EXTEND_AUTH_CLIENT
/** Clear credentials (user/pass). @NEW_1_12_6 */
int (*auc_clear)(auth_client_t *ca);
#endif
};
/** Check if authentication client has been extended. @NEW_1_12_6 */
#define AUTH_CLIENT_IS_EXTENDED(ca) \
((ca)->ca_auc->auc_plugin_size > \
(int)offsetof(auth_client_plugin_t, auc_clear) \
&& (ca)->ca_auc->auc_clear != NULL)
SOFIA_END_DECLS
#endif /* !defined AUTH_CLIENT_PLUGIN_H */
@@ -105,7 +105,7 @@ struct auth_scheme
typedef struct
{
unsigned apw_index; /**< Key to hash table */
void const *apw_type; /**< Magic pointer */
void const *apw_type; /**< Magic identifier */
char const *apw_user; /**< Username */
char const *apw_realm; /**< Realm */
@@ -124,7 +124,7 @@ struct stat;
struct auth_mod_t
{
su_home_t am_home[1];
unsigned am_refcount; /**< Number of references to this module */
unsigned _am_refcount; /**< Not used */
/* User database / cache */
char const *am_db; /**< User database file name */
@@ -769,8 +769,6 @@ int test_digest_client()
{
char const *nonce1, *nextnonce, *nonce2;
reinit_as(as); auth_mod_destroy(am); aucs = NULL;
TEST_1(am = auth_mod_create(NULL,
AUTHTAG_METHOD("Digest"),
AUTHTAG_REALM("ims3.so.noklab.net"),
@@ -1164,9 +1162,10 @@ int test_module_io()
extern su_log_t iptsec_log[];
static
void usage(void)
void usage(int exitcode)
{
fprintf(stderr, "usage: %s [-v] [-l n]\n", name);
fprintf(stderr, "usage: %s [-v] [-a] [-l n]\n", name);
exit(exitcode);
}
int main(int argc, char *argv[])
@@ -1179,8 +1178,10 @@ int main(int argc, char *argv[])
su_init();
for (i = 1; argv[i]; i++) {
if (argv[i] && strcmp(argv[i], "-v") == 0)
if (strcmp(argv[i], "-v") == 0)
tstflags |= tst_verbatim;
else if (strcmp(argv[i], "-a") == 0)
tstflags |= tst_abort;
else if (strncmp(argv[i], "-l", 2) == 0) {
int level = 3;
char *rest = NULL;
@@ -1193,11 +1194,11 @@ int main(int argc, char *argv[])
level = 3, rest = "";
if (rest == NULL || *rest)
usage();
usage(1);
su_log_set_level(iptsec_log, level);
} else {
usage();
usage(1);
}
}
+27 -21
View File
@@ -35,10 +35,12 @@ INTERNAL_H = msg_internal.h test_class.h
nobase_include_sofia_HEADERS = \
$(GENERATED_H) $(PUBLIC_H)
BUILT_SOURCES = $(GENERATED_H) msg_mime_table.c test_table.c test_protos.h
GENERATED_HC = $(GENERATED_H) msg_mime_table.c test_table.c test_protos.h
libmsg_la_SOURCES = $(INTERNAL_H) \
msg.c msg_tag.c \
BUILT_SOURCES = $(GENERATED_HC)
libmsg_la_SOURCES = msg_internal.h \
msg.c msg_tag.c msg_inlined.c \
msg_mime.c msg_mime_table.c \
msg_header_copy.c msg_header_make.c \
msg_parser.c msg_mclass.c msg_parser_util.c \
@@ -46,11 +48,13 @@ libmsg_la_SOURCES = $(INTERNAL_H) \
COVERAGE_INPUT = $(libmsg_la_SOURCES) $(include_sofia_HEADERS)
libtest_msg_a_SOURCES = test_class.c test_table.c test_protos.h
libtest_msg_a_SOURCES = test_class.c test_class.h \
test_table.c test_inlined.c test_protos.h
LDADD = libtest_msg.a libmsg.la \
../bnf/libbnf.la \
../url/liburl.la \
../ipt/libipt.la \
../su/libsu.la
test_msg_LDFLAGS = -static
@@ -77,41 +81,43 @@ TESTS = test_msg
# ----------------------------------------------------------------------
# Sofia specific rules
include ../sofia.am
include $(top_srcdir)/rules/sofia.am
MSG_PARSER_AWK = $(srcdir)/msg_parser.awk
AWK_MSG_AWK = $(AWK) -f $(MSG_PARSER_AWK)
test_protos.h: test_protos.h.in $(MSG_PARSER_AWK)
test_table.c: test_table.c.in $(MSG_PARSER_AWK)
${GENERATED_HC}: ${MSG_PARSER_AWK}
sofia-sip/msg_mime_protos.h: sofia-sip/msg_mime_protos.h.in
sofia-sip/msg_protos.h: sofia-sip/msg_protos.h.in
msg_mime_table.c: msg_mime_table.c.in $(MSG_PARSER_AWK)
TEST_CLASS_H = ${srcdir}/test_class.h
sofia-sip/msg_mime_protos.h sofia-sip/msg_protos.h: $(MSG_PARSER_AWK)
test_protos.h test_table.c: ${TEST_CLASS_H}
test_protos.h: test_class.h
test_protos.h: ${srcdir}/test_protos.h.in
$(AWK_MSG_AWK) module=msg_test NO_MIDDLE=1 NO_LAST=1 \
PR=$@ TEMPLATE=$(srcdir)/test_protos.h.in $<
PR=$@ TEMPLATE=$(srcdir)/$@.in ${TEST_CLASS_H}
test_table.c: test_class.h
test_table.c: ${srcdir}/test_table.c.in
$(AWK_MSG_AWK) module=msg_test prefix=msg \
MC_HASH_SIZE=127 multipart=msg_multipart \
PT=$@ TEMPLATE=$(srcdir)/test_table.c.in $<
PT=$@ TEMPLATE=$(srcdir)/$@.in ${TEST_CLASS_H}
sofia-sip/msg_protos.h: sofia-sip/msg_mime.h
SS_MIME_H = ${srcdir}/sofia-sip/msg_mime.h
sofia-sip/msg_protos.h sofia-sip/msg_mime_protos.h: ${SS_MIME_H}
msg_mime_table.c: ${SS_MIME_H}
sofia-sip/msg_protos.h: ${srcdir}/sofia-sip/msg_protos.h.in
@-mkdir sofia-sip 2>/dev/null || true
$(AWK_MSG_AWK) module=msg NO_FIRST=1 NO_MIDDLE=1 \
PR=$@ TEMPLATE=$(srcdir)/sofia-sip/msg_protos.h.in $<
PR=$@ TEMPLATE=$(srcdir)/$@.in ${SS_MIME_H}
sofia-sip/msg_mime_protos.h: sofia-sip/msg_mime.h
sofia-sip/msg_mime_protos.h: ${srcdir}/sofia-sip/msg_mime_protos.h.in
@-mkdir sofia-sip 2>/dev/null || true
$(AWK_MSG_AWK) module=msg NO_FIRST=1 NO_LAST=1 \
PR=$@ TEMPLATE=$(srcdir)/sofia-sip/msg_mime_protos.h.in $<
PR=$@ TEMPLATE=$(srcdir)/$@.in ${SS_MIME_H}
msg_mime_table.c: sofia-sip/msg_mime.h
msg_mime_table.c: ${srcdir}/msg_mime_table.c.in
$(AWK_MSG_AWK) module=msg_multipart \
tprefix=msg prefix=mp MC_HASH_SIZE=127 \
PT=$@ TEMPLATE=$(srcdir)/msg_mime_table.c.in $<
PT=$@ TEMPLATE=$(srcdir)/$@.in ${SS_MIME_H}
@@ -0,0 +1,47 @@
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2007 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@nokia.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
/**@CFILE msg_inlined.c
*
* Expand inlined msg functions non-inline.
*
*/
#include "config.h"
#include <sofia-sip/su_config.h>
#if SU_HAVE_INLINE
extern int xyzzy;
#else
#undef SU_HAVE_INLINE
#undef su_inline
#define SU_HAVE_INLINE 1
#define su_inline
#include "sofia-sip/msg_header.h"
#include "sofia-sip/msg_mime_protos.h"
#endif
@@ -54,11 +54,13 @@ BEGIN {
split("", NAMES);
split("", Comments);
split("", COMMENTS);
split("", experimental);
# indexed by the C name of the header
split("", Since); # Non-NUL if extra
split("", Extra); # Offset in extra headers
without_experimental = 0;
template="";
template1="";
template2="";
@@ -78,13 +80,18 @@ function name_hash (name)
{
hash = 0;
len = split(name, chars, "");
len = length(name);
for (i = 1; i <= len; i++) {
c = tolower(chars[i]);
c = tolower(substr(name, i, 1));
hash = (38501 * (hash + index(ascii, c))) % 65536;
}
if (hash == 0) {
print "*** msg_parser.awk: calculating hash failed\n";
exit(5);
}
if (0) {
# Test that hash algorithm above agrees with the C version
pipe = ("../msg/msg_name_hash " name);
@@ -155,11 +162,24 @@ function protos (name, comment, hash, since)
Extra[name] = extra++;
}
expr = (without_experimental > 0 && do_hash);
if (expr) {
printf "%s is experimental\n", Comment;
}
experimental[N] = expr;
if (PR) {
if (expr) {
print "#if SU_HAVE_EXPERIMENTAL" > PR;
}
replace(template, hash, name, NAME, comment, Comment, COMMENT, since);
replace(template1, hash, name, NAME, comment, Comment, COMMENT, since);
replace(template2, hash, name, NAME, comment, Comment, COMMENT, since);
replace(template3, hash, name, NAME, comment, Comment, COMMENT, since);
if (expr) {
print "#endif /* SU_HAVE_EXPERIMENTAL */" > PR;
}
}
}
@@ -210,8 +230,19 @@ function process_footer (text)
for (i = 1; i <= n; i++) {
l = lines[i];
if (match(tolower(l), /#(xxxxxx(x_xxxxxxx)?|hash)#/)) {
expr = 0;
for (j = 1; j <= N; j++) {
l = lines[i];
if (expr != experimental[j]) {
expr = experimental[j];
if (expr) {
print "#if SU_HAVE_EXPERIMENTAL" > PR;
}
else {
print "#endif /* SU_HAVE_EXPERIMENTAL */" > PR;
}
}
gsub(/#hash#/, hashes[j], l);
gsub(/#xxxxxxx_xxxxxxx#/, comments[j], l);
gsub(/#Xxxxxxx_Xxxxxxx#/, Comments[j], l);
@@ -220,6 +251,10 @@ function process_footer (text)
gsub(/#XXXXXX#/, NAMES[j], l);
print l > PR;
}
if (expr) {
print "#endif /* SU_HAVE_EXPERIMENTAL */" > PR;
}
} else {
print l > PR;
}
@@ -333,10 +368,11 @@ function templates ()
}
/^#### EXTRA HEADER LIST STARTS HERE ####$/ { HLIST=1; templates(); }
HLIST && /^#### EXPERIMENTAL HEADER LIST STARTS HERE ####$/ {
without_experimental=total; }
HLIST && /^[a-z]/ { protos($1, $0, 0, $2); headers[total++] = $1; }
/^#### EXTRA HEADER LIST ENDS HERE ####$/ { HLIST=0; }
/^ *\/\* === Headers start here \*\// { in_header_list=1; templates(); }
/^ *\/\* === Headers end here \*\// { in_header_list=0; }
@@ -366,10 +402,13 @@ in_header_list && /^ (sip|rtsp|http|msg|mp)_[a-z_0-9]+_t/ {
END {
if (failed) { exit };
if (without_experimental == 0)
without_experimental = total;
if (!NO_LAST) {
protos("unknown", "/**< Unknown headers */", -3);
protos("error", "/**< Erroneous headers */", -4);
protos("separator", "/**< Separator line between headers and payload */", -5);
protos("separator", "/**< Separator line between headers and body */", -5);
protos("payload", "/**< Message payload */", -6);
if (multipart)
protos("multipart", "/**< Multipart payload */", -7);
@@ -397,6 +436,10 @@ END {
gsub(/#DATE#/, "@date Generated: " date, header);
print header > PT;
print "" > PT;
print "#define msg_offsetof(s, f) ((unsigned short)offsetof(s ,f))" > PT;
print "" > PT;
if (MC_SHORT_SIZE) {
printf("static msg_href_t const " \
"%s_short_forms[MC_SHORT_SIZE] = \n{\n",
@@ -408,7 +451,7 @@ END {
n = shorts[i];
flags = header_flags[n]; if (flags) flags = ",\n " flags;
printf(" { /* %s */ %s_%s_class, offsetof(%s_t, %s_%s)%s }%s\n",
printf(" { /* %s */ %s_%s_class, msg_offsetof(%s_t, %s_%s)%s }%s\n",
substr(lower_case, i, 1),
tprefix, n, module, prefix, n, flags, c) \
> PT;
@@ -426,7 +469,16 @@ END {
if (extra > 0) {
printf("struct %s {\n", extra_struct) > PT;
printf(" %s base;\n", module_struct) > PT;
printf(" msg_header_t *extra[%u];\n", extra) > PT;
if (total - without_experimental < extra) {
printf(" msg_header_t *extra[%u];\n",
extra - (total - without_experimental)) > PT;
}
if (total - without_experimental > 0) {
print "#if SU_HAVE_EXPERIMENTAL" > PT;
printf(" msg_header_t *experimental[%u];\n",
total - without_experimental) > PT;
print "#endif" > PT;
}
printf("};\n\n") > PT;
module_struct = "struct " extra_struct;
}
@@ -450,11 +502,11 @@ END {
len = split("request status separator payload unknown error", unnamed, " ");
for (i = 1; i <= len; i++) {
printf(" {{ %s_%s_class, offsetof(%s_t, %s_%s) }},\n",
printf(" {{ %s_%s_class, msg_offsetof(%s_t, %s_%s) }},\n",
tprefix, unnamed[i], module, prefix, unnamed[i]) > PT;
}
if (multipart) {
printf(" {{ %s_class, offsetof(%s_t, %s_multipart) }},\n",
printf(" {{ %s_class, msg_offsetof(%s_t, %s_multipart) }},\n",
multipart, module, prefix) > PT;
} else {
printf(" {{ NULL, 0 }},\n") > PT;
@@ -465,7 +517,13 @@ END {
else {
printf(" NULL, \n") > PT;
}
printf(" %d, %d, \n", MC_HASH_SIZE, total) > PT;
printf(" %d, \n", MC_HASH_SIZE) > PT;
printf ("#if SU_HAVE_EXPERIMENTAL\n" \
" %d,\n" \
"#else\n" \
" %d,\n" \
"#endif\n", \
total, without_experimental) > PT;
printf(" {\n") > PT;
for (i = 0; i < total; i++) {
@@ -484,6 +542,7 @@ END {
}
header_hash[j] = n;
experimental2[j] = (i >= without_experimental);
}
for (i = 0; i < MC_HASH_SIZE; i++) {
@@ -492,14 +551,23 @@ END {
n = header_hash[i];
flags = header_flags[n]; if (flags) flags = ",\n " flags;
if (experimental2[i]) {
print "#if SU_HAVE_EXPERIMENTAL" > PT;
}
if (Since[n]) {
printf(" { %s_%s_class, offsetof(struct %s, extra[%u])%s }%s\n",
printf(" { %s_%s_class,\n" \
" msg_offsetof(struct %s, extra[%u])%s }%s\n",
tprefix, n, extra_struct, Extra[n], flags, c) > PT;
}
else {
printf(" { %s_%s_class, offsetof(%s_t, %s_%s)%s }%s\n",
printf(" { %s_%s_class, msg_offsetof(%s_t, %s_%s)%s }%s\n",
tprefix, n, module, prefix, n, flags, c) > PT;
}
if (experimental2[i]) {
printf("#else\n { NULL, 0 }%s\n#endif\n", c) > PT;
}
}
else {
printf(" { NULL, 0 }%s\n", c) > PT;
@@ -1974,6 +1974,8 @@ msg_t *msg_make(msg_mclass_t const *mc, int flags,
return NULL;
msg = msg_create(mc, flags);
if (msg == NULL)
return NULL;
su_home_preload(msg_home(msg), 1, len + 1024);
@@ -56,7 +56,8 @@ SOFIA_BEGIN_DECLS
* 1) Header class definitions.
*/
#if HAVE_STRUCT_KEYWORDS
/* Do not use keywords until you fix msg_kind_foo_critical thing! */ \
#if HAVE_STRUCT_KEYWORDS && 0
/** Define a header class */
#define MSG_HEADER_CLASS(pr, c, l, s, params, kind, dup, upd) \
{{ \
@@ -74,6 +75,7 @@ SOFIA_BEGIN_DECLS
hc_kind: msg_kind_##kind, \
}}
#else
/** Define a header class */
#define MSG_HEADER_CLASS(pr, c, l, s, params, kind, dup, upd) \
{{ \
pr##c##_hash, \
@@ -198,9 +200,11 @@ SOFIAPUBFUN issize_t msg_parse_next_field(su_home_t *home, msg_header_t *prev,
/** Duplicate string. @HI */
#define MSG_STRING_DUP(p, d, s) \
(void)((s)?((p)=(char*)memccpy((void *)((d)=(char*)p),(s),0,SIZE_MAX))\
(void)((s)?((p)=(char*)memccpy((void *)((d)=(char*)p),(s),0,INT_MAX))\
:((d)=NULL))
/* Solaris has broken memccpy - it considers last argument as signed */
/** Calculate string size. @HI */
#define MSG_STRING_SIZE(s) ((s) ? (strlen(s) + 1) : 0)
@@ -0,0 +1,46 @@
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2007 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@nokia.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
/**@CFILE test_inlined.c
*
* Expand inlined test functions non-inline.
*
*/
#include "config.h"
#include <sofia-sip/su_config.h>
#if SU_HAVE_INLINE
extern int xyzzy;
#else
#undef SU_HAVE_INLINE
#undef su_inline
#define SU_HAVE_INLINE 1
#define su_inline
#include "test_protos.h"
#endif
@@ -59,11 +59,6 @@ static int test_flags = 0;
char const name[] = "test_msg";
void usage(void)
{
fprintf(stderr, "usage: %s [-v]\n", name);
}
static int msg_time_test(void)
{
char buf[32];
@@ -138,7 +133,6 @@ static int msg_time_test(void)
}
END();
return 0;
}
static int addr_test(void)
@@ -1688,6 +1682,12 @@ static int random_test(void)
END();
}
void usage(int exitcode)
{
fprintf(stderr, "usage: %s [-v] [-a]\n", name);
exit(exitcode);
}
int main(int argc, char *argv[])
{
int retval = 0;
@@ -1696,8 +1696,10 @@ int main(int argc, char *argv[])
for (i = 1; argv[i]; i++) {
if (strcmp(argv[i], "-v") == 0)
test_flags |= tst_verbatim;
else if (strcmp(argv[i], "-a") == 0)
test_flags |= tst_abort;
else
usage();
usage(1);
}
retval |= msg_time_test(); fflush(stdout);
@@ -59,4 +59,5 @@ EXTRA_DIST = Doxyfile nea.docs $(BUILT_SOURCES)
# ----------------------------------------------------------------------
# Sofia specific rules
include ../sofia.am
include $(top_srcdir)/rules/sofia.am
@@ -496,14 +496,14 @@ nea_server_t *nea_server_create(nta_agent_t *agent,
nes->nes_eventity_uri &&
(nes->nes_leg || leg == NULL) &&
nes->nes_timer) {
SU_DEBUG_5(("nea_server_create(%p): success\n", nes));
SU_DEBUG_5(("nea_server_create(%p): success\n", (void *)nes));
su_timer_set(nes->nes_timer, nes_event_timer, nes);
nes->nes_callback = callback;
nes->nes_context = context;
}
else {
SU_DEBUG_5(("nea_server_create(%p): failed\n", nes));
SU_DEBUG_5(("nea_server_create(%p): failed\n", (void *)nes));
nea_server_destroy(nes), nes = NULL;
}
}
@@ -551,11 +551,11 @@ int nea_server_shutdown(nea_server_t *nes,
return 500;
if (nes->nes_in_callback) {
SU_DEBUG_5(("nea_server_shutdown(%p) while in callback\n", nes));
SU_DEBUG_5(("nea_server_shutdown(%p) while in callback\n", (void *)nes));
return 100;
}
SU_DEBUG_5(("nea_server_shutdown(%p)\n", nes));
SU_DEBUG_5(("nea_server_shutdown(%p)\n", (void *)nes));
in_callback = nes->nes_in_callback; nes->nes_in_callback = 1;
@@ -585,12 +585,12 @@ void nea_server_destroy(nea_server_t *nes)
return;
if (nes->nes_in_callback) {
SU_DEBUG_5(("nea_server_destroy(%p) while in callback\n", nes));
SU_DEBUG_5(("nea_server_destroy(%p) while in callback\n", (void *)nes));
nes->nes_pending_destroy = 1;
return;
}
SU_DEBUG_5(("nea_server_destroy(%p)\n", nes));
SU_DEBUG_5(("nea_server_destroy(%p)\n", (void *)nes));
nta_leg_destroy(nes->nes_leg), nes->nes_leg = NULL;
@@ -837,8 +837,8 @@ int nea_view_update(nea_server_t *nes,
if (evq->evq_content_type)
nea_view_queue(nes, evv, evq);
SU_DEBUG_7(("nea_server_update(%p): %s (%s)\n",
nes, ev->ev_event->o_type, evv->evv_content_type->c_type));
SU_DEBUG_7(("nea_server_update(%p): %s (%s)\n", (void *)nes,
ev->ev_event->o_type, evv->evv_content_type->c_type));
return 1;
}
@@ -1019,7 +1019,8 @@ int nea_server_notify(nea_server_t *nes, nea_event_t *ev)
nea_sub_t *s;
int notified = 0, throttled = nes->nes_throttled;
SU_DEBUG_7(("nea_server_notify(%p): %s\n", nes, ev ? ev->ev_event->o_type: ""));
SU_DEBUG_7(("nea_server_notify(%p): %s\n", (void *)nes,
ev ? ev->ev_event->o_type: ""));
++nes->nes_in_list;
@@ -73,7 +73,7 @@ EXTRA_DIST = Doxyfile nta.docs sl_utils.docs \
# ----------------------------------------------------------------------
# Sofia specific rules
include ../sofia.am
include $(top_srcdir)/rules/sofia.am
# Generate list of nta tags
TAG_DLL_FLAGS = LIST=nta_tag_list
File diff suppressed because it is too large. Load diff
+20 -18
View File
@@ -343,8 +343,8 @@ int nta_check_accept(nta_incoming_t *irq,
/**Check @SessionExpires header.
*
* If the proposed session-expiration time is smaller than @MinSE or our
* minimal session expiration time, respond with 422 containing our minimal
* session expiration time in @MinSE header.
* minimal session expiration time, respond with 422 containing shortest
* acceptable session expiration time in @MinSE header.
*
* @param irq incoming transaction object (may be NULL).
* @param sip contents of the SIP message
@@ -359,26 +359,28 @@ int nta_check_session_expires(nta_incoming_t *irq,
sip_time_t my_min_se,
tag_type_t tag, tag_value_t value, ...)
{
if ((sip->sip_min_se &&
sip->sip_session_expires->x_delta < sip->sip_min_se->min_delta)
|| sip->sip_session_expires->x_delta < my_min_se) {
unsigned long min_se = my_min_se;
if (sip->sip_min_se && min_se < sip->sip_min_se->min_delta)
min_se = sip->sip_min_se->min_delta;
if (sip->sip_session_expires->x_delta >= min_se)
return 0;
if (irq) {
ta_list ta;
sip_min_se_t min_se0[1];
sip_min_se_t min_se[1];
ta_start(ta, tag, value);
sip_min_se_init(min_se)->min_delta = my_min_se;
sip_min_se_init(min_se0)->min_delta = min_se;
if (irq) {
ta_start(ta, tag, value);
nta_incoming_treply(irq,
SIP_422_SESSION_TIMER_TOO_SMALL,
SIPTAG_MIN_SE(min_se),
ta_tags(ta));
ta_end(ta);
}
return 422;
nta_incoming_treply(irq,
SIP_422_SESSION_TIMER_TOO_SMALL,
SIPTAG_MIN_SE(min_se0),
ta_tags(ta));
ta_end(ta);
}
return 0;
return 422;
}
@@ -98,16 +98,17 @@ struct nta_agent_s
nta_agent_magic_t *sa_magic;
nta_message_f *sa_callback;
uint32_t sa_nw_updates; /* Shall we enable network detector? */
nta_update_magic_t *sa_update_magic;
nta_update_tport_f *sa_update_tport;
su_time_t sa_now; /**< Timestamp in microsecond resolution. */
su_duration_t sa_next; /**< Timestamp for next agent_timer. */
su_time_t sa_now; /**< Timestamp in microsecond resolution. */
uint32_t sa_millisec; /**< Timestamp in milliseconds resolution. */
uint32_t sa_nw_updates; /* Shall we enable network detector? */
uint32_t sa_flags; /**< Message flags */
msg_mclass_t *sa_mclass;
msg_mclass_t const *sa_mclass;
sip_contact_t *sa_contact;
sip_via_t *sa_vias; /**< @Via headers for all transports */
@@ -223,6 +224,9 @@ struct nta_agent_s
/** If true, automatically create compartments */
unsigned sa_auto_comp:1;
/** Set when executing timer */
unsigned sa_in_timer:1;
unsigned :0;
/** Messages memory preload. */
@@ -342,6 +346,11 @@ struct nta_leg_s
unsigned leg_loose_route : 1; /**< Topmost route in set is LR */
#endif
unsigned leg_local_is_to : 1; /**< Backwards-compatibility. */
unsigned leg_tagged : 1; /**< Tagged after creation.
*
* Request missing To tag matches it
* even after tagging.
*/
unsigned:0;
nta_request_f *leg_callback;
nta_leg_magic_t *leg_magic;
@@ -463,12 +472,17 @@ struct nta_outgoing_s
sip_method_t orq_method;
char const *orq_method_name;
url_t const *orq_url; /**< Original RequestURI */
sip_from_t const *orq_from;
sip_to_t const *orq_to;
char const *orq_tag; /**< Tag from final response. */
sip_cseq_t const *orq_cseq;
sip_call_id_t const *orq_call_id;
char const *orq_tag; /**< Tag from final response. */
msg_t *orq_request;
msg_t *orq_response;
su_time_t orq_sent; /**< When request was sent? */
unsigned orq_delay; /**< RTT estimate */
@@ -501,11 +515,9 @@ struct nta_outgoing_s
unsigned orq_sigcomp_new:1; /**< Create compartment if needed */
unsigned orq_sigcomp_zap:1; /**< Reset SigComp after completing */
unsigned orq_must_100rel : 1;
unsigned orq_timestamp : 1; /**< insert @Timestamp header. */
unsigned orq_timestamp : 1; /**< Insert @Timestamp header. */
unsigned : 0; /* pad */
uint32_t orq_rseq; /**< Latest incoming rseq */
#if HAVE_SOFIA_SRESOLV
sipdns_resolver_t *orq_resolver;
#endif
@@ -522,12 +534,10 @@ struct nta_outgoing_s
char const *orq_branch; /**< Transaction branch */
char const *orq_via_branch; /**< @Via branch */
url_t const *orq_url; /**< Original RequestURI */
msg_t *orq_request;
msg_t *orq_response;
nta_outgoing_t *orq_cancel; /**< CANCEL transaction */
uint32_t orq_rseq; /**< Latest incoming rseq */
};
/* Virtual function table for plugging in SigComp */
+32 -32
View File
@@ -110,38 +110,38 @@ tag_typedef_t ntatag_rseq = UINTTAG_TYPEDEF(rseq);
/* Status */
tag_typedef_t ntatag_s_irq_hash = UINTTAG_TYPEDEF(s_irq_hash);
tag_typedef_t ntatag_s_orq_hash = UINTTAG_TYPEDEF(s_orq_hash);
tag_typedef_t ntatag_s_leg_hash = UINTTAG_TYPEDEF(s_leg_hash);
tag_typedef_t ntatag_s_irq_hash_used = UINTTAG_TYPEDEF(s_irq_hash_used);
tag_typedef_t ntatag_s_orq_hash_used = UINTTAG_TYPEDEF(s_orq_hash_used);
tag_typedef_t ntatag_s_leg_hash_used = UINTTAG_TYPEDEF(s_leg_hash_used);
tag_typedef_t ntatag_s_recv_msg = UINTTAG_TYPEDEF(s_recv_msg);
tag_typedef_t ntatag_s_recv_request = UINTTAG_TYPEDEF(s_recv_request);
tag_typedef_t ntatag_s_recv_response = UINTTAG_TYPEDEF(s_recv_response);
tag_typedef_t ntatag_s_bad_message = UINTTAG_TYPEDEF(s_bad_message);
tag_typedef_t ntatag_s_bad_request = UINTTAG_TYPEDEF(s_bad_request);
tag_typedef_t ntatag_s_bad_response = UINTTAG_TYPEDEF(s_bad_response);
tag_typedef_t ntatag_s_drop_request = UINTTAG_TYPEDEF(s_drop_request);
tag_typedef_t ntatag_s_drop_response = UINTTAG_TYPEDEF(s_drop_response);
tag_typedef_t ntatag_s_client_tr = UINTTAG_TYPEDEF(s_client_tr);
tag_typedef_t ntatag_s_server_tr = UINTTAG_TYPEDEF(s_server_tr);
tag_typedef_t ntatag_s_dialog_tr = UINTTAG_TYPEDEF(s_dialog_tr);
tag_typedef_t ntatag_s_acked_tr = UINTTAG_TYPEDEF(s_acked_tr);
tag_typedef_t ntatag_s_canceled_tr = UINTTAG_TYPEDEF(s_canceled_tr);
tag_typedef_t ntatag_s_trless_request = UINTTAG_TYPEDEF(s_trless_request);
tag_typedef_t ntatag_s_trless_to_tr = UINTTAG_TYPEDEF(s_trless_to_tr);
tag_typedef_t ntatag_s_trless_response = UINTTAG_TYPEDEF(s_trless_response);
tag_typedef_t ntatag_s_trless_200 = UINTTAG_TYPEDEF(s_trless_200);
tag_typedef_t ntatag_s_merged_request = UINTTAG_TYPEDEF(s_merged_request);
tag_typedef_t ntatag_s_sent_msg = UINTTAG_TYPEDEF(s_sent_msg);
tag_typedef_t ntatag_s_sent_request = UINTTAG_TYPEDEF(s_sent_request);
tag_typedef_t ntatag_s_sent_response = UINTTAG_TYPEDEF(s_sent_response);
tag_typedef_t ntatag_s_retry_request = UINTTAG_TYPEDEF(s_retry_request);
tag_typedef_t ntatag_s_retry_response = UINTTAG_TYPEDEF(s_retry_response);
tag_typedef_t ntatag_s_recv_retry = UINTTAG_TYPEDEF(s_recv_retry);
tag_typedef_t ntatag_s_tout_request = UINTTAG_TYPEDEF(s_tout_request);
tag_typedef_t ntatag_s_tout_response = UINTTAG_TYPEDEF(s_tout_response);
tag_typedef_t ntatag_s_irq_hash = USIZETAG_TYPEDEF(s_irq_hash);
tag_typedef_t ntatag_s_orq_hash = USIZETAG_TYPEDEF(s_orq_hash);
tag_typedef_t ntatag_s_leg_hash = USIZETAG_TYPEDEF(s_leg_hash);
tag_typedef_t ntatag_s_irq_hash_used = USIZETAG_TYPEDEF(s_irq_hash_used);
tag_typedef_t ntatag_s_orq_hash_used = USIZETAG_TYPEDEF(s_orq_hash_used);
tag_typedef_t ntatag_s_leg_hash_used = USIZETAG_TYPEDEF(s_leg_hash_used);
tag_typedef_t ntatag_s_recv_msg = USIZETAG_TYPEDEF(s_recv_msg);
tag_typedef_t ntatag_s_recv_request = USIZETAG_TYPEDEF(s_recv_request);
tag_typedef_t ntatag_s_recv_response = USIZETAG_TYPEDEF(s_recv_response);
tag_typedef_t ntatag_s_bad_message = USIZETAG_TYPEDEF(s_bad_message);
tag_typedef_t ntatag_s_bad_request = USIZETAG_TYPEDEF(s_bad_request);
tag_typedef_t ntatag_s_bad_response = USIZETAG_TYPEDEF(s_bad_response);
tag_typedef_t ntatag_s_drop_request = USIZETAG_TYPEDEF(s_drop_request);
tag_typedef_t ntatag_s_drop_response = USIZETAG_TYPEDEF(s_drop_response);
tag_typedef_t ntatag_s_client_tr = USIZETAG_TYPEDEF(s_client_tr);
tag_typedef_t ntatag_s_server_tr = USIZETAG_TYPEDEF(s_server_tr);
tag_typedef_t ntatag_s_dialog_tr = USIZETAG_TYPEDEF(s_dialog_tr);
tag_typedef_t ntatag_s_acked_tr = USIZETAG_TYPEDEF(s_acked_tr);
tag_typedef_t ntatag_s_canceled_tr = USIZETAG_TYPEDEF(s_canceled_tr);
tag_typedef_t ntatag_s_trless_request = USIZETAG_TYPEDEF(s_trless_request);
tag_typedef_t ntatag_s_trless_to_tr = USIZETAG_TYPEDEF(s_trless_to_tr);
tag_typedef_t ntatag_s_trless_response = USIZETAG_TYPEDEF(s_trless_response);
tag_typedef_t ntatag_s_trless_200 = USIZETAG_TYPEDEF(s_trless_200);
tag_typedef_t ntatag_s_merged_request = USIZETAG_TYPEDEF(s_merged_request);
tag_typedef_t ntatag_s_sent_msg = USIZETAG_TYPEDEF(s_sent_msg);
tag_typedef_t ntatag_s_sent_request = USIZETAG_TYPEDEF(s_sent_request);
tag_typedef_t ntatag_s_sent_response = USIZETAG_TYPEDEF(s_sent_response);
tag_typedef_t ntatag_s_retry_request = USIZETAG_TYPEDEF(s_retry_request);
tag_typedef_t ntatag_s_retry_response = USIZETAG_TYPEDEF(s_retry_response);
tag_typedef_t ntatag_s_recv_retry = USIZETAG_TYPEDEF(s_recv_retry);
tag_typedef_t ntatag_s_tout_request = USIZETAG_TYPEDEF(s_tout_request);
tag_typedef_t ntatag_s_tout_response = USIZETAG_TYPEDEF(s_tout_response);
/* Internal */
tag_typedef_t ntatag_delay_sending = BOOLTAG_TYPEDEF(delay_sending);
@@ -1,4 +1,4 @@
#! /bin/bash
#! /bin/sh
#
# Run nta_test with our own name server
#
@@ -50,11 +50,11 @@ export PATH
me6="::1"
if ../su/localinfo -6 -n -g -s >& /dev/null ; then
if ../su/localinfo -6 -n -g -s > /dev/null 2>&1 ; then
ipv6=true aaaa=aaaa v6flag=-6
me6=$(../su/localinfo -6 -n -s -g | awk '{print $1; exit(0); }')
else
if ! ../su/localinfo '--help' >& /dev/null ; then
if ! ../su/localinfo '--help' > /dev/null 2>&1 ; then
echo "warning: $0: missing 'localinfo', cannot test IPv6"
else
echo "warning: $0: no valid IPv6 addresses available"
@@ -62,7 +62,7 @@ else
ipv6=false aaaa=a
fi
if type named >& /dev/null && ./portbind --help >& /dev/null
if type named > /dev/null 2>&1 && ./portbind --help > /dev/null 2>&1
then
port=$(./portbind $v6flag) sink=$port
@@ -299,6 +299,9 @@ int nta_incoming_complete_response(nta_incoming_t *irq,
char const *phrase,
tag_type_t tag, tag_value_t value, ...);
SOFIAPUBFUN
msg_t *nta_incoming_create_response(nta_incoming_t *irq, int status, char const *phrase);
SOFIAPUBFUN
int nta_incoming_treply(nta_incoming_t *ireq,
int status, char const *phrase,
@@ -59,10 +59,10 @@ NTA_DLL extern tag_typedef_t ntatag_any;
NTA_DLL extern tag_typedef_t ntatag_mclass;
/** Message class used by NTA. @HI */
#define NTATAG_MCLASS(x) ntatag_mclass, tag_ptr_v((x))
#define NTATAG_MCLASS(x) ntatag_mclass, tag_cptr_v((x))
NTA_DLL extern tag_typedef_t ntatag_mclass_ref;
#define NTATAG_MCLASS_REF(x) ntatag_mclass_ref, tag_ptr_vr(&(x), (x))
#define NTATAG_MCLASS_REF(x) ntatag_mclass_ref, tag_cptr_vr(&(x), (x))
NTA_DLL extern tag_typedef_t ntatag_bad_req_mask;
/** Mask for bad request messages.
@@ -464,223 +464,223 @@ NTA_DLL extern tag_typedef_t ntatag_rseq_ref;
/* Tags for statistics. */
NTA_DLL extern tag_typedef_t ntatag_s_irq_hash;
#define NTATAG_S_IRQ_HASH(x) ntatag_s_irq_hash, tag_uint_v(x)
#define NTATAG_S_IRQ_HASH(x) ntatag_s_irq_hash, tag_usize_v(x)
NTA_DLL extern tag_typedef_t ntatag_s_irq_hash_ref;
#define NTATAG_S_IRQ_HASH_REF(x) ntatag_s_irq_hash_ref, tag_uint_vr(&(x))
#define NTATAG_S_IRQ_HASH_REF(x) ntatag_s_irq_hash_ref, tag_usize_vr(&(x))
NTA_DLL extern tag_typedef_t ntatag_s_orq_hash;
#define NTATAG_S_ORQ_HASH(x) ntatag_s_orq_hash, tag_uint_v(x)
#define NTATAG_S_ORQ_HASH(x) ntatag_s_orq_hash, tag_usize_v(x)
NTA_DLL extern tag_typedef_t ntatag_s_orq_hash_ref;
#define NTATAG_S_ORQ_HASH_REF(x) ntatag_s_orq_hash_ref, tag_uint_vr(&(x))
#define NTATAG_S_ORQ_HASH_REF(x) ntatag_s_orq_hash_ref, tag_usize_vr(&(x))
NTA_DLL extern tag_typedef_t ntatag_s_leg_hash;
#define NTATAG_S_LEG_HASH(x) ntatag_s_leg_hash, tag_uint_v(x)
#define NTATAG_S_LEG_HASH(x) ntatag_s_leg_hash, tag_usize_v(x)
NTA_DLL extern tag_typedef_t ntatag_s_leg_hash_ref;
#define NTATAG_S_LEG_HASH_REF(x) ntatag_s_leg_hash_ref, tag_uint_vr(&(x))
#define NTATAG_S_LEG_HASH_REF(x) ntatag_s_leg_hash_ref, tag_usize_vr(&(x))
NTA_DLL extern tag_typedef_t ntatag_s_irq_hash_used;
#define NTATAG_S_IRQ_HASH_USED(x) ntatag_s_irq_hash_used, tag_uint_v(x)
#define NTATAG_S_IRQ_HASH_USED(x) ntatag_s_irq_hash_used, tag_usize_v(x)
NTA_DLL extern tag_typedef_t ntatag_s_irq_hash_used_ref;
#define NTATAG_S_IRQ_HASH_USED_REF(x) \
ntatag_s_irq_hash_used_ref, tag_uint_vr(&(x))
ntatag_s_irq_hash_used_ref, tag_usize_vr(&(x))
NTA_DLL extern tag_typedef_t ntatag_s_orq_hash_used;
#define NTATAG_S_ORQ_HASH_USED(x) ntatag_s_orq_hash_used, tag_uint_v(x)
#define NTATAG_S_ORQ_HASH_USED(x) ntatag_s_orq_hash_used, tag_usize_v(x)
NTA_DLL extern tag_typedef_t ntatag_s_orq_hash_used_ref;
#define NTATAG_S_ORQ_HASH_USED_REF(x) \
ntatag_s_orq_hash_used_ref, tag_uint_vr(&(x))
ntatag_s_orq_hash_used_ref, tag_usize_vr(&(x))
NTA_DLL extern tag_typedef_t ntatag_s_leg_hash_used;
#define NTATAG_S_LEG_HASH_USED(x) ntatag_s_leg_hash_used, tag_uint_v(x)
#define NTATAG_S_LEG_HASH_USED(x) ntatag_s_leg_hash_used, tag_usize_v(x)
NTA_DLL extern tag_typedef_t ntatag_s_leg_hash_used_ref;
#define NTATAG_S_LEG_HASH_USED_REF(x) \
ntatag_s_leg_hash_used_ref, tag_uint_vr(&(x))
ntatag_s_leg_hash_used_ref, tag_usize_vr(&(x))
NTA_DLL extern tag_typedef_t ntatag_s_recv_msg;
#define NTATAG_S_RECV_MSG(x) ntatag_s_recv_msg, tag_uint_v(x)
#define NTATAG_S_RECV_MSG(x) ntatag_s_recv_msg, tag_usize_v(x)
NTA_DLL extern tag_typedef_t ntatag_s_recv_msg_ref;
#define NTATAG_S_RECV_MSG_REF(x) ntatag_s_recv_msg_ref, tag_uint_vr(&(x))
#define NTATAG_S_RECV_MSG_REF(x) ntatag_s_recv_msg_ref, tag_usize_vr(&(x))
NTA_DLL extern tag_typedef_t ntatag_s_recv_request;
#define NTATAG_S_RECV_REQUEST(x) ntatag_s_recv_request, tag_uint_v(x)
#define NTATAG_S_RECV_REQUEST(x) ntatag_s_recv_request, tag_usize_v(x)
NTA_DLL extern tag_typedef_t ntatag_s_recv_request_ref;
#define NTATAG_S_RECV_REQUEST_REF(x)\
ntatag_s_recv_request_ref, tag_uint_vr(&(x))
ntatag_s_recv_request_ref, tag_usize_vr(&(x))
NTA_DLL extern tag_typedef_t ntatag_s_recv_response;
#define NTATAG_S_RECV_RESPONSE(x) ntatag_s_recv_response, tag_uint_v(x)
#define NTATAG_S_RECV_RESPONSE(x) ntatag_s_recv_response, tag_usize_v(x)
NTA_DLL extern tag_typedef_t ntatag_s_recv_response_ref;
#define NTATAG_S_RECV_RESPONSE_REF(x)\
ntatag_s_recv_response_ref, tag_uint_vr(&(x))
ntatag_s_recv_response_ref, tag_usize_vr(&(x))
NTA_DLL extern tag_typedef_t ntatag_s_bad_message;
#define NTATAG_S_BAD_MESSAGE(x) ntatag_s_bad_message, tag_uint_v(x)
#define NTATAG_S_BAD_MESSAGE(x) ntatag_s_bad_message, tag_usize_v(x)
NTA_DLL extern tag_typedef_t ntatag_s_bad_message_ref;
#define NTATAG_S_BAD_MESSAGE_REF(x)\
ntatag_s_bad_message_ref, tag_uint_vr(&(x))
ntatag_s_bad_message_ref, tag_usize_vr(&(x))
NTA_DLL extern tag_typedef_t ntatag_s_bad_request;
#define NTATAG_S_BAD_REQUEST(x) ntatag_s_bad_request, tag_uint_v(x)
#define NTATAG_S_BAD_REQUEST(x) ntatag_s_bad_request, tag_usize_v(x)
NTA_DLL extern tag_typedef_t ntatag_s_bad_request_ref;
#define NTATAG_S_BAD_REQUEST_REF(x)\
ntatag_s_bad_request_ref, tag_uint_vr(&(x))
ntatag_s_bad_request_ref, tag_usize_vr(&(x))
NTA_DLL extern tag_typedef_t ntatag_s_bad_response;
#define NTATAG_S_BAD_RESPONSE(x) ntatag_s_bad_response, tag_uint_v(x)
#define NTATAG_S_BAD_RESPONSE(x) ntatag_s_bad_response, tag_usize_v(x)
NTA_DLL extern tag_typedef_t ntatag_s_bad_response_ref;
#define NTATAG_S_BAD_RESPONSE_REF(x)\
ntatag_s_bad_response_ref, tag_uint_vr(&(x))
ntatag_s_bad_response_ref, tag_usize_vr(&(x))
NTA_DLL extern tag_typedef_t ntatag_s_drop_request;
#define NTATAG_S_DROP_REQUEST(x) ntatag_s_drop_request, tag_uint_v(x)
#define NTATAG_S_DROP_REQUEST(x) ntatag_s_drop_request, tag_usize_v(x)
NTA_DLL extern tag_typedef_t ntatag_s_drop_request_ref;
#define NTATAG_S_DROP_REQUEST_REF(x)\
ntatag_s_drop_request_ref, tag_uint_vr(&(x))
ntatag_s_drop_request_ref, tag_usize_vr(&(x))
NTA_DLL extern tag_typedef_t ntatag_s_drop_response;
#define NTATAG_S_DROP_RESPONSE(x) ntatag_s_drop_response, tag_uint_v(x)
#define NTATAG_S_DROP_RESPONSE(x) ntatag_s_drop_response, tag_usize_v(x)
NTA_DLL extern tag_typedef_t ntatag_s_drop_response_ref;
#define NTATAG_S_DROP_RESPONSE_REF(x)\
ntatag_s_drop_response_ref, tag_uint_vr(&(x))
ntatag_s_drop_response_ref, tag_usize_vr(&(x))
NTA_DLL extern tag_typedef_t ntatag_s_client_tr;
#define NTATAG_S_CLIENT_TR(x) ntatag_s_client_tr, tag_uint_v(x)
#define NTATAG_S_CLIENT_TR(x) ntatag_s_client_tr, tag_usize_v(x)
NTA_DLL extern tag_typedef_t ntatag_s_client_tr_ref;
#define NTATAG_S_CLIENT_TR_REF(x)\
ntatag_s_client_tr_ref, tag_uint_vr(&(x))
ntatag_s_client_tr_ref, tag_usize_vr(&(x))
NTA_DLL extern tag_typedef_t ntatag_s_server_tr;
#define NTATAG_S_SERVER_TR(x) ntatag_s_server_tr, tag_uint_v(x)
#define NTATAG_S_SERVER_TR(x) ntatag_s_server_tr, tag_usize_v(x)
NTA_DLL extern tag_typedef_t ntatag_s_server_tr_ref;
#define NTATAG_S_SERVER_TR_REF(x)\
ntatag_s_server_tr_ref, tag_uint_vr(&(x))
ntatag_s_server_tr_ref, tag_usize_vr(&(x))
NTA_DLL extern tag_typedef_t ntatag_s_dialog_tr;
#define NTATAG_S_DIALOG_TR(x) ntatag_s_dialog_tr, tag_uint_v(x)
#define NTATAG_S_DIALOG_TR(x) ntatag_s_dialog_tr, tag_usize_v(x)
NTA_DLL extern tag_typedef_t ntatag_s_dialog_tr_ref;
#define NTATAG_S_DIALOG_TR_REF(x)\
ntatag_s_dialog_tr_ref, tag_uint_vr(&(x))
ntatag_s_dialog_tr_ref, tag_usize_vr(&(x))
NTA_DLL extern tag_typedef_t ntatag_s_acked_tr;
#define NTATAG_S_ACKED_TR(x) ntatag_s_acked_tr, tag_uint_v(x)
#define NTATAG_S_ACKED_TR(x) ntatag_s_acked_tr, tag_usize_v(x)
NTA_DLL extern tag_typedef_t ntatag_s_acked_tr_ref;
#define NTATAG_S_ACKED_TR_REF(x) ntatag_s_acked_tr_ref, tag_uint_vr(&(x))
#define NTATAG_S_ACKED_TR_REF(x) ntatag_s_acked_tr_ref, tag_usize_vr(&(x))
NTA_DLL extern tag_typedef_t ntatag_s_canceled_tr;
#define NTATAG_S_CANCELED_TR(x) ntatag_s_canceled_tr, tag_uint_v(x)
#define NTATAG_S_CANCELED_TR(x) ntatag_s_canceled_tr, tag_usize_v(x)
NTA_DLL extern tag_typedef_t ntatag_s_canceled_tr_ref;
#define NTATAG_S_CANCELED_TR_REF(x) \
ntatag_s_canceled_tr_ref, tag_uint_vr(&(x))
ntatag_s_canceled_tr_ref, tag_usize_vr(&(x))
NTA_DLL extern tag_typedef_t ntatag_s_trless_request;
#define NTATAG_S_TRLESS_REQUEST(x) ntatag_s_trless_request, tag_uint_v(x)
#define NTATAG_S_TRLESS_REQUEST(x) ntatag_s_trless_request, tag_usize_v(x)
NTA_DLL extern tag_typedef_t ntatag_s_trless_request_ref;
#define NTATAG_S_TRLESS_REQUEST_REF(x)\
ntatag_s_trless_request_ref, tag_uint_vr(&(x))
ntatag_s_trless_request_ref, tag_usize_vr(&(x))
NTA_DLL extern tag_typedef_t ntatag_s_trless_to_tr;
#define NTATAG_S_TRLESS_TO_TR(x) ntatag_s_trless_to_tr, tag_uint_v(x)
#define NTATAG_S_TRLESS_TO_TR(x) ntatag_s_trless_to_tr, tag_usize_v(x)
NTA_DLL extern tag_typedef_t ntatag_s_trless_to_tr_ref;
#define NTATAG_S_TRLESS_TO_TR_REF(x)\
ntatag_s_trless_to_tr_ref, tag_uint_vr(&(x))
ntatag_s_trless_to_tr_ref, tag_usize_vr(&(x))
NTA_DLL extern tag_typedef_t ntatag_s_trless_response;
#define NTATAG_S_TRLESS_RESPONSE(x) ntatag_s_trless_response, tag_uint_v(x)
#define NTATAG_S_TRLESS_RESPONSE(x) ntatag_s_trless_response, tag_usize_v(x)
NTA_DLL extern tag_typedef_t ntatag_s_trless_response_ref;
#define NTATAG_S_TRLESS_RESPONSE_REF(x)\
ntatag_s_trless_response_ref, tag_uint_vr(&(x))
ntatag_s_trless_response_ref, tag_usize_vr(&(x))
NTA_DLL extern tag_typedef_t ntatag_s_trless_200;
#define NTATAG_S_TRLESS_200(x) ntatag_s_trless_200, tag_uint_v(x)
#define NTATAG_S_TRLESS_200(x) ntatag_s_trless_200, tag_usize_v(x)
NTA_DLL extern tag_typedef_t ntatag_s_trless_200_ref;
#define NTATAG_S_TRLESS_200_REF(x)\
ntatag_s_trless_200_ref, tag_uint_vr(&(x))
ntatag_s_trless_200_ref, tag_usize_vr(&(x))
NTA_DLL extern tag_typedef_t ntatag_s_merged_request;
#define NTATAG_S_MERGED_REQUEST(x) ntatag_s_merged_request, tag_uint_v(x)
#define NTATAG_S_MERGED_REQUEST(x) ntatag_s_merged_request, tag_usize_v(x)
NTA_DLL extern tag_typedef_t ntatag_s_merged_request_ref;
#define NTATAG_S_MERGED_REQUEST_REF(x)\
ntatag_s_merged_request_ref, tag_uint_vr(&(x))
ntatag_s_merged_request_ref, tag_usize_vr(&(x))
NTA_DLL extern tag_typedef_t ntatag_s_sent_msg;
#define NTATAG_S_SENT_MSG(x) ntatag_s_sent_msg, tag_uint_v(x)
#define NTATAG_S_SENT_MSG(x) ntatag_s_sent_msg, tag_usize_v(x)
NTA_DLL extern tag_typedef_t ntatag_s_sent_msg_ref;
#define NTATAG_S_SENT_MSG_REF(x)\
ntatag_s_sent_msg_ref, tag_uint_vr(&(x))
ntatag_s_sent_msg_ref, tag_usize_vr(&(x))
NTA_DLL extern tag_typedef_t ntatag_s_sent_request;
#define NTATAG_S_SENT_REQUEST(x) ntatag_s_sent_request, tag_uint_v(x)
#define NTATAG_S_SENT_REQUEST(x) ntatag_s_sent_request, tag_usize_v(x)
NTA_DLL extern tag_typedef_t ntatag_s_sent_request_ref;
#define NTATAG_S_SENT_REQUEST_REF(x)\
ntatag_s_sent_request_ref, tag_uint_vr(&(x))
ntatag_s_sent_request_ref, tag_usize_vr(&(x))
NTA_DLL extern tag_typedef_t ntatag_s_sent_response;
#define NTATAG_S_SENT_RESPONSE(x) ntatag_s_sent_response, tag_uint_v(x)
#define NTATAG_S_SENT_RESPONSE(x) ntatag_s_sent_response, tag_usize_v(x)
NTA_DLL extern tag_typedef_t ntatag_s_sent_response_ref;
#define NTATAG_S_SENT_RESPONSE_REF(x)\
ntatag_s_sent_response_ref, tag_uint_vr(&(x))
ntatag_s_sent_response_ref, tag_usize_vr(&(x))
NTA_DLL extern tag_typedef_t ntatag_s_retry_request;
#define NTATAG_S_RETRY_REQUEST(x) ntatag_s_retry_request, tag_uint_v(x)
#define NTATAG_S_RETRY_REQUEST(x) ntatag_s_retry_request, tag_usize_v(x)
NTA_DLL extern tag_typedef_t ntatag_s_retry_request_ref;
#define NTATAG_S_RETRY_REQUEST_REF(x)\
ntatag_s_retry_request_ref, tag_uint_vr(&(x))
ntatag_s_retry_request_ref, tag_usize_vr(&(x))
NTA_DLL extern tag_typedef_t ntatag_s_retry_response;
#define NTATAG_S_RETRY_RESPONSE(x) ntatag_s_retry_response, tag_uint_v(x)
#define NTATAG_S_RETRY_RESPONSE(x) ntatag_s_retry_response, tag_usize_v(x)
NTA_DLL extern tag_typedef_t ntatag_s_retry_response_ref;
#define NTATAG_S_RETRY_RESPONSE_REF(x)\
ntatag_s_retry_response_ref, tag_uint_vr(&(x))
ntatag_s_retry_response_ref, tag_usize_vr(&(x))
NTA_DLL extern tag_typedef_t ntatag_s_recv_retry;
#define NTATAG_S_RECV_RETRY(x) ntatag_s_recv_retry, tag_uint_v(x)
#define NTATAG_S_RECV_RETRY(x) ntatag_s_recv_retry, tag_usize_v(x)
NTA_DLL extern tag_typedef_t ntatag_s_recv_retry_ref;
#define NTATAG_S_RECV_RETRY_REF(x)\
ntatag_s_recv_retry_ref, tag_uint_vr(&(x))
ntatag_s_recv_retry_ref, tag_usize_vr(&(x))
NTA_DLL extern tag_typedef_t ntatag_s_tout_request;
#define NTATAG_S_TOUT_REQUEST(x) ntatag_s_tout_request, tag_uint_v(x)
#define NTATAG_S_TOUT_REQUEST(x) ntatag_s_tout_request, tag_usize_v(x)
NTA_DLL extern tag_typedef_t ntatag_s_tout_request_ref;
#define NTATAG_S_TOUT_REQUEST_REF(x)\
ntatag_s_tout_request_ref, tag_uint_vr(&(x))
ntatag_s_tout_request_ref, tag_usize_vr(&(x))
NTA_DLL extern tag_typedef_t ntatag_s_tout_response;
#define NTATAG_S_TOUT_RESPONSE(x) ntatag_s_tout_response, tag_uint_v(x)
#define NTATAG_S_TOUT_RESPONSE(x) ntatag_s_tout_response, tag_usize_v(x)
NTA_DLL extern tag_typedef_t ntatag_s_tout_response_ref;
#define NTATAG_S_TOUT_RESPONSE_REF(x)\
ntatag_s_tout_response_ref, tag_uint_vr(&(x))
ntatag_s_tout_response_ref, tag_usize_vr(&(x))
SOFIA_END_DECLS
+25 -16
View File
@@ -654,7 +654,7 @@ int readfile(FILE *f, void **contents)
*contents = buffer;
return len;
return (int)len;
}
#if HAVE_DIRENT_H
@@ -663,6 +663,8 @@ int readfile(FILE *f, void **contents)
static int test_bad_messages(agent_t *ag)
{
BEGIN();
#if HAVE_DIRENT_H
DIR *dir;
struct dirent *d;
@@ -687,13 +689,10 @@ static int test_bad_messages(agent_t *ag)
if (dir == NULL) {
fprintf(stderr, "test_nta: cannot find sip torture messages\n");
fprintf(stderr, "test_nta: tried %s\n", name);
return 0;
}
offset = strlen(name);
BEGIN();
TEST_1(ag->ag_default_leg = nta_leg_tcreate(ag->ag_agent,
leg_callback_500,
ag,
@@ -713,14 +712,14 @@ static int test_bad_messages(agent_t *ag)
TEST(su_getaddrinfo(host, port, hints, &ai), 0); TEST_1(ai);
s = su_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); TEST_1(s != -1);
memset(su, 0, sulen = sizeof su);
memset(su, 0, sulen = ai->ai_addrlen);
su->su_len = sizeof su; su->su_family = ai->ai_family;
TEST_1(bind(s, &su->su_sa, sulen) == 0);
TEST_1(getsockname(s, &su->su_sa, &sulen) == 0);
sprintf(via, "v: SIP/2.0/UDP is.invalid:%u\r\n", ntohs(su->su_port));
vlen = strlen(via);
for (d = readdir(dir); d; d = readdir(dir)) {
for (d = dir ? readdir(dir) : NULL; d; d = readdir(dir)) {
size_t len = strlen(d->d_name);
FILE *f;
int blen, n;
@@ -733,6 +732,7 @@ static int test_bad_messages(agent_t *ag)
strncpy(name + offset, d->d_name, PATH_MAX - offset);
TEST_1(f = fopen(name, "rb"));
TEST_1((blen = readfile(f, &buffer)) > 0);
fclose(f);
r = buffer;
if (strncmp(r, "JUNK ", 5) == 0) {
@@ -751,6 +751,12 @@ static int test_bad_messages(agent_t *ag)
su_root_step(ag->ag_root, 1);
}
TEST_SIZE(su_sendto(s, "\r\n\r\n", 4, 0, (void *)ai->ai_addr, ai->ai_addrlen), 4);
su_root_step(ag->ag_root, 1);
TEST_SIZE(su_sendto(s, "", 0, 0, ai->ai_addr, ai->ai_addrlen), 0);
su_close(s);
for (i = 0; i < 20; i++)
@@ -758,12 +764,12 @@ static int test_bad_messages(agent_t *ag)
nta_leg_destroy(ag->ag_default_leg), ag->ag_default_leg = NULL;
closedir(dir);
if (dir)
closedir(dir);
#endif /* HAVE_DIRENT_H */
END();
#else
return 0;
#endif /* HAVE_DIRENT_H */
}
static unsigned char const code[] =
@@ -3357,6 +3363,7 @@ char const nta_test_usage[] =
"usage: %s OPTIONS\n"
"where OPTIONS are\n"
" -v | --verbose be verbose\n"
" -a | --abort abort() on error\n"
" -q | --quiet be quiet\n"
" -1 quit on first error\n"
" -l level set logging level (0 by default)\n"
@@ -3368,10 +3375,10 @@ char const nta_test_usage[] =
#endif
;
void usage(void)
void usage(int exitcode)
{
fprintf(stderr, nta_test_usage, name);
exit(1);
exit(exitcode);
}
int main(int argc, char *argv[])
@@ -3384,6 +3391,8 @@ int main(int argc, char *argv[])
for (i = 1; argv[i]; i++) {
if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0)
tstflags |= tst_verbatim;
else if (strcmp(argv[i], "-a") == 0 || strcmp(argv[i], "--abort") == 0)
tstflags |= tst_abort;
else if (strcmp(argv[i], "-q") == 0 || strcmp(argv[i], "--quiet") == 0)
tstflags &= ~tst_verbatim;
else if (strcmp(argv[i], "-1") == 0)
@@ -3400,7 +3409,7 @@ int main(int argc, char *argv[])
level = 3, rest = "";
if (rest == NULL || *rest)
usage();
usage(1);
su_log_set_level(nta_log, level);
su_log_set_level(tport_log, level);
@@ -3411,7 +3420,7 @@ int main(int argc, char *argv[])
else if (argv[i + 1])
ag->ag_obp = (url_string_t *)(argv[++i]);
else
usage();
usage(1);
}
else if (strncmp(argv[i], "-m", 2) == 0) {
if (argv[i][2])
@@ -3419,7 +3428,7 @@ int main(int argc, char *argv[])
else if (argv[i + 1])
ag->ag_m = argv[++i];
else
usage();
usage(1);
}
else if (strcmp(argv[i], "--attach") == 0) {
o_attach = 1;
@@ -3434,7 +3443,7 @@ int main(int argc, char *argv[])
break;
}
else
usage();
usage(1);
}
if (o_attach) {
@@ -559,18 +559,18 @@ int api_test_stats(agent_t *ag)
nta_agent_t *nta;
uint32_t irq_hash = -1, orq_hash = -1, leg_hash = -1;
uint32_t recv_msg = -1, sent_msg = -1;
uint32_t recv_request = -1, recv_response = -1;
uint32_t bad_message = -1, bad_request = -1, bad_response = -1;
uint32_t drop_request = -1, drop_response = -1;
uint32_t client_tr = -1, server_tr = -1, dialog_tr = -1;
uint32_t acked_tr = -1, canceled_tr = -1;
uint32_t trless_request = -1, trless_to_tr = -1, trless_response = -1;
uint32_t trless_200 = -1, merged_request = -1;
uint32_t sent_request = -1, sent_response = -1;
uint32_t retry_request = -1, retry_response = -1, recv_retry = -1;
uint32_t tout_request = -1, tout_response = -1;
usize_t irq_hash = -1, orq_hash = -1, leg_hash = -1;
usize_t recv_msg = -1, sent_msg = -1;
usize_t recv_request = -1, recv_response = -1;
usize_t bad_message = -1, bad_request = -1, bad_response = -1;
usize_t drop_request = -1, drop_response = -1;
usize_t client_tr = -1, server_tr = -1, dialog_tr = -1;
usize_t acked_tr = -1, canceled_tr = -1;
usize_t trless_request = -1, trless_to_tr = -1, trless_response = -1;
usize_t trless_200 = -1, merged_request = -1;
usize_t sent_request = -1, sent_response = -1;
usize_t retry_request = -1, retry_response = -1, recv_retry = -1;
usize_t tout_request = -1, tout_response = -1;
TEST_1(nta = nta_agent_create(ag->ag_root, (url_string_t *)"sip:*:*",
NULL, NULL, TAG_END()));
@@ -1238,6 +1238,7 @@ char const nta_test_api_usage[] =
"usage: %s OPTIONS\n"
"where OPTIONS are\n"
" -v | --verbose be verbose\n"
" -a | --abort abort() on error\n"
" -q | --quiet be quiet\n"
" -1 quit on first error\n"
" -l level set logging level (0 by default)\n"
@@ -1247,10 +1248,10 @@ char const nta_test_api_usage[] =
#endif
;
void usage(void)
void usage(int exitcode)
{
fprintf(stderr, nta_test_api_usage, name);
exit(1);
exit(exitcode);
}
int main(int argc, char *argv[])
@@ -1261,9 +1262,11 @@ int main(int argc, char *argv[])
agent_t ag[1] = {{ { SU_HOME_INIT(ag) }, 0, NULL }};
for (i = 1; argv[i]; i++) {
if (strcmp(argv[i], "-v") == 0)
if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0)
tstflags |= tst_verbatim;
else if (strcmp(argv[i], "-q") == 0)
else if (strcmp(argv[i], "-a") == 0 || strcmp(argv[i], "--abort") == 0)
tstflags |= tst_abort;
else if (strcmp(argv[i], "-q") == 0 || strcmp(argv[i], "--quiet") == 0)
tstflags &= ~tst_verbatim;
else if (strcmp(argv[i], "-1") == 0)
quit_on_single_failure = 1;
@@ -1279,7 +1282,7 @@ int main(int argc, char *argv[])
level = 3, rest = "";
if (rest == NULL || *rest)
usage();
usage(1);
su_log_set_level(nta_log, level);
su_log_set_level(tport_log, level);
@@ -1297,14 +1300,14 @@ int main(int argc, char *argv[])
break;
}
else
usage();
usage(1);
}
if (o_attach) {
char line[10];
char *response, line[10];
printf("nua_test: pid %lu\n", (unsigned long)getpid());
printf("<Press RETURN to continue>\n");
fgets(line, sizeof line, stdin);
response = fgets(line, sizeof line, stdin);
}
#if HAVE_ALARM
else if (o_alarm) {
@@ -63,4 +63,4 @@ EXTRA_DIST = Doxyfile nth.docs $(BUILT_SOURCES) \
# ----------------------------------------------------------------------
# Sofia specific rules
include ../sofia.am
include $(top_srcdir)/rules/sofia.am
@@ -38,7 +38,10 @@
#include <string.h>
#include <stdio.h>
#include <assert.h>
#if HAVE_SIGNAL
#include <signal.h>
#endif
typedef struct context_s context_t;
#define NTH_SITE_MAGIC_T context_t
@@ -77,7 +80,10 @@ static int request(context_t *context,
http_t const *http,
char const *path);
su_msg_r server_intr_msg = SU_MSG_R_INIT;
#if HAVE_SIGNAL
static RETSIGTYPE server_intr_handler(int signum);
#endif
static void server_break(context_t *c, su_msg_r msg, su_msg_arg_t *arg);
static msg_payload_t *read_payload(su_home_t *home, char const *fname);
@@ -140,12 +146,12 @@ int main(int argc, char *argv[])
su_root_task(context->c_root),
server_break, 0);
#if HAVE_SIGNAL
signal(SIGINT, server_intr_handler);
#ifndef _WIN32
signal(SIGPIPE, server_intr_handler);
#if HAVE_SIGQUIT
signal(SIGQUIT, server_intr_handler);
signal(SIGHUP, server_intr_handler);
#endif
#endif
if (context->c_root) {
@@ -1094,7 +1094,7 @@ int hc_reply(nth_client_t * hc, int status, char const *phrase)
assert(status >= 400);
SU_DEBUG_5(("nth: hc_reply(%p, %u, %s)\n", hc, status, phrase));
SU_DEBUG_5(("nth: hc_reply(%p, %u, %s)\n", (void *)hc, status, phrase));
if (hc->hc_pending) {
tport_release(hc->hc_tport, hc->hc_pending, hc->hc_request, NULL, hc,
@@ -704,7 +704,7 @@ server_t *server_create(url_t const *url,
tag_type_t tag, tag_value_t value, ...)
{
server_t *srv;
msg_mclass_t *mclass = NULL;
msg_mclass_t const *mclass = NULL;
tp_name_t tpn[1] = {{ NULL }};
su_root_t *root = NULL;
http_server_t const *server = NULL;
@@ -109,7 +109,7 @@ su_inline tag_value_t nthtag_template_vr(struct nth_client_s const **vp)
{return(tag_value_t)vp;}
#else
#define nthtag_template_v(v) ((tag_value_t)(v))
#define nthtag_template_vr(vp) ((tag_value_t)&(vp))
#define nthtag_template_vr(vp) ((tag_value_t)(vp))
#endif
NTH_DLL extern tag_typedef_t nthtag_template;
@@ -126,7 +126,7 @@ su_inline tag_value_t nthtag_message_vr(struct msg_s **vp)
{ return(tag_value_t)vp; }
#else
#define nthtag_message_v(v) ((tag_value_t)(v))
#define nthtag_message_vr(vp) ((tag_value_t)&(vp))
#define nthtag_message_vr(vp) ((tag_value_t)(vp))
#endif
NTH_DLL extern tag_typedef_t nthtag_message;
@@ -142,7 +142,7 @@ su_inline tag_value_t nthtag_authentication_v(struct auth_client_s **v) { return
su_inline tag_value_t nthtag_authentication_vr(struct auth_client_s ***vp) {return(tag_value_t)vp;}
#else
#define nthtag_authentication_v(v) ((tag_value_t)(v))
#define nthtag_authentication_vr(vp) ((tag_value_t)&(vp))
#define nthtag_authentication_vr(vp) ((tag_value_t)(vp))
#endif
NTH_DLL extern tag_typedef_t nthtag_authentication;
@@ -893,10 +893,10 @@ static RETSIGTYPE sig_alarm(int s)
}
#endif
void usage(void)
void usage(int exitcode)
{
fprintf(stderr, "usage: %s [-v|-q] [-p proxy-uri]\n", name);
exit(1);
fprintf(stderr, "usage: %s [-v|-q] [-a] [-p proxy-uri]\n", name);
exit(exitcode);
}
int main(int argc, char **argv)
@@ -915,6 +915,8 @@ int main(int argc, char **argv)
for (i = 1; argv[i]; i++) {
if (strcmp(argv[i], "-v") == 0)
tstflags |= tst_verbatim;
else if (strcmp(argv[i], "-a") == 0)
tstflags |= tst_abort;
else if (strcmp(argv[i], "-q") == 0)
tstflags &= ~tst_verbatim;
else if (strcmp(argv[i], "-p") == 0 && argv[i + 1])
@@ -931,7 +933,7 @@ int main(int argc, char **argv)
break;
}
else
usage();
usage(1);
}
t->t_srcdir = srcdir;
@@ -30,6 +30,9 @@ ALIASES += nua="@ref index \"nua\""
ALIASES += NUA_EVENT="@var nua_event_e::"
ALIASES += END_NUA_EVENT="@par &nbsp;"
ALIASES += \
NUA_HPARAM_CALLS="nua_invite(), nua_respond(), nua_ack(), nua_prack(), nua_update(), nua_info(), nua_bye(), nua_options(), nua_message(), nua_register(), nua_publish(), nua_refer(),nua_subscribe(), nua_notify(), nua_refer(), nua_notifier()"
VERBATIM_HEADERS = NO
@INCLUDE = ../sip/sip.doxyaliases
@@ -80,6 +80,7 @@ test_nua_SOURCES = test_nua.c test_nua.h test_ops.c \
test_init.c \
test_nua_api.c test_nua_params.c \
test_register.c test_basic_call.c \
test_offer_answer.c \
test_call_reject.c test_cancel_bye.c \
test_call_hold.c test_session_timer.c \
test_refer.c test_100rel.c \
@@ -96,6 +97,6 @@ EXTRA_DIST = Doxyfile nua.docs $(BUILT_SOURCES)
# ----------------------------------------------------------------------
# Sofia specific rules
include ../sofia.am
include $(top_srcdir)/rules/sofia.am
TAG_DLL_FLAGS = LIST=nua_tag_list
+104 -72
View File
@@ -67,7 +67,7 @@ char const nua_version[] = VERSION;
*
* The NUA_DEBUG environment variable is used to determine the debug logging
* level for @nua module. The default level is 3.
*
*
* @sa <sofia-sip/su_debug.h>, nua_log, SOFIA_DEBUG
*/
extern char const NUA_DEBUG[];
@@ -76,8 +76,8 @@ extern char const NUA_DEBUG[];
#define SU_DEBUG 3
#endif
/**Debug log for @nua module.
*
/**Debug log for @nua module.
*
* The nua_log is the log object used by @nua module. The level of
* #nua_log is set using #NUA_DEBUG environment variable.
*/
@@ -104,16 +104,17 @@ su_log_t nua_log[] = { SU_LOG_INIT("nua", "NUA_DEBUG", SU_DEBUG) };
* NUTAG_UICC() \n
* NUTAG_CERTIFICATE_DIR() \n
* and all tags listed in nua_set_params(), \n
* and all relevant NTATAG_* are passed to NTA.
* and all relevant NTATAG_* are passed to NTA \n
* and all tport tags listed in <sofia-sip/tport_tag.h>
*
* @note
* From the @VERSION_1_12_2 all the nua_set_params() tags are processed.
* From the @VERSION_1_12_2 all the nua_set_params() tags are processed.
* Previously all nutags except NUTAG_SOA_NAME() and NUTAG_MEDIA_ENABLE()
* were ignored.
*
* @note
* Both the NUTAG_URL() and NUTAG_SIPS_URL() are used to pass arguments to
* nta_agent_add_tport().
* nta_agent_add_tport().
*
* @par Events:
* none
@@ -187,9 +188,9 @@ void nua_shutdown(nua_t *nua)
/** Destroy the @nua stack.
*
* Before calling nua_destroy() the application
* Before calling nua_destroy() the application
* should call nua_shutdown and wait for successful #nua_r_shutdown event.
* Shuts down and destroys the @nua stack. Ongoing calls, registrations,
* Shuts down and destroys the @nua stack. Ongoing calls, registrations,
* and subscriptions are left as they are.
*
* @param nua Pointer to @nua stack object
@@ -211,7 +212,8 @@ void nua_destroy(nua_t *nua)
if (nua) {
if (!nua->nua_shutdown_final) {
SU_DEBUG_0(("nua_destroy(%p): FATAL: nua_shutdown not completed\n", nua));
SU_DEBUG_0(("nua_destroy(%p): FATAL: nua_shutdown not completed\n",
(void *)nua));
assert(nua->nua_shutdown);
return;
}
@@ -242,7 +244,7 @@ nua_magic_t *nua_magic(nua_t *nua)
/** Obtain default operation handle of the @nua stack object.
*
* A default operation can be used for operations where the
* A default operation can be used for operations where the
* ultimate result is not important or can be discarded.
*
* @param nua Pointer to @nua stack object
@@ -262,7 +264,7 @@ nua_handle_t *nua_default(nua_t *nua)
return nua ? nua->nua_handles : NULL;
}
/** Create an operation handle
/** Create an operation handle
*
* Allocates a new operation handle and associated storage.
*
@@ -275,7 +277,7 @@ nua_handle_t *nua_default(nua_t *nua)
*
* @par Related tags:
* Duplicates the provided tags for use with every operation. Note that
* NUTAG_URL() is converted to SIPTAG_TO() if there is no SIPTAG_TO().
* NUTAG_URL() is converted to SIPTAG_TO() if there is no SIPTAG_TO().
* And also vice versa, request-URI is taken from SIPTAG_TO() if there
* is no NUTAG_URL(). Note that certain SIP headers cannot be saved with
* the handle. They include @ContentLength, @CSeq, @RSeq, @RAck, and
@@ -302,7 +304,7 @@ nua_handle_t *nua_handle(nua_t *nua, nua_hmagic_t *hmagic,
ta_start(ta, tag, value);
nh = nh_create_handle(nua, hmagic, ta_args(ta));
if (nh)
nh->nh_ref_by_user = 1;
@@ -312,7 +314,7 @@ nua_handle_t *nua_handle(nua_t *nua, nua_hmagic_t *hmagic,
return nh;
}
/** Bind a callback context to an operation handle.
/** Bind a callback context to an operation handle.
*
* @param nh Pointer to operation handle
* @param hmagic Pointer to callback context
@@ -334,7 +336,7 @@ void nua_handle_bind(nua_handle_t *nh, nua_hmagic_t *hmagic)
nh->nh_magic = hmagic;
}
/** Fetch a callback context from an operation handle.
/** Fetch a callback context from an operation handle.
*
* @param nh Pointer to operation handle
*
@@ -356,7 +358,7 @@ nua_hmagic_t *nua_handle_magic(nua_handle_t *nh)
if (NH_IS_VALID(nh))
magic = nh->nh_magic;
return magic;
}
@@ -369,8 +371,8 @@ nua_hmagic_t *nua_handle_magic(nua_handle_t *nh)
*
* @param nh Pointer to operation handle
*
* @retval 0 no invite in operation or operation handle is invalid
* @retval 1 operation has invite
* @retval 0 no invite in operation or operation handle is invalid
* @retval 1 operation has invite
*
* @par Related tags:
* none
@@ -383,15 +385,15 @@ int nua_handle_has_invite(nua_handle_t const *nh)
return nh ? nh->nh_has_invite : 0;
}
/**Check if operation handle has active event subscriptions.
/**Check if operation handle has active event subscriptions.
*
* Active subscription can be established either by nua_subscribe() or
* nua_refer() calls.
*
* @param nh Pointer to operation handle
*
* @retval 0 no event subscriptions in operation or
* operation handle is invalid
* @retval 0 no event subscriptions in operation or
* operation handle is invalid
* @retval !=0 operation has event subscriptions
*
* @par Related tags:
@@ -416,7 +418,7 @@ int nua_handle_has_events(nua_handle_t const *nh)
*
* @param nh Pointer to operation handle
*
* @retval 0 no active registration in operation or
* @retval 0 no active registration in operation or
* operation handle is invalid
* @retval 1 operation has registration
*
@@ -433,12 +435,12 @@ int nua_handle_has_registrations(nua_handle_t const *nh)
return nh && nh->nh_ds->ds_has_register;
}
/** Check if operation handle has been used with outgoing SUBSCRIBE of REFER request.
/** Check if operation handle has been used with outgoing SUBSCRIBE of REFER request.
*
* @param nh Pointer to operation handle
*
* @retval 0 no active subscription in operation or
* operation handle is invalid
* @retval 0 no active subscription in operation or
* operation handle is invalid
* @retval 1 operation has subscription.
*
* @par Related tags:
@@ -470,7 +472,7 @@ int nua_handle_has_register(nua_handle_t const *nh)
return nh ? nh->nh_has_register : 0;
}
/** Check if operation handle has an active call
/** Check if operation handle has an active call
*
* @param nh Pointer to operation handle
*
@@ -488,17 +490,17 @@ int nua_handle_has_active_call(nua_handle_t const *nh)
return nh ? nh->nh_active_call : 0;
}
/** Check if operation handle has a call on hold
/** Check if operation handle has a call on hold
*
* Please note that this status is not affected by remote end putting
* this end on hold. Remote end can put each media separately on hold
* and status is reflected on SOATAG_ACTIVE_AUDIO(), SOATAG_ACTIVE_VIDEO()
* Please note that this status is not affected by remote end putting
* this end on hold. Remote end can put each media separately on hold
* and status is reflected on SOATAG_ACTIVE_AUDIO(), SOATAG_ACTIVE_VIDEO()
* and SOATAG_ACTIVE_CHAT() tag values in #nua_i_state event.
*
* @param nh Pointer to operation handle
*
* @retval 0 if no call on hold in operation or operation handle is invalid
* @retval 1 if operation has call on hold, for example nua_invite() or
* @retval 0 if no call on hold in operation or operation handle is invalid
* @retval 1 if operation has call on hold, for example nua_invite() or
* nua_update() has been called with SOATAG_HOLD() with non-NULL
* argument.
*
@@ -515,14 +517,14 @@ int nua_handle_has_call_on_hold(nua_handle_t const *nh)
/** Get the remote address (From/To header) of operation handle
*
* Remote address is used as To header in outgoing operations and
* Remote address is used as To header in outgoing operations and
* derived from From: header in incoming operations.
*
* @param nh Pointer to operation handle
*
* @retval NULL no remote address for operation or operation handle invalid
* @retval !=NULL pointer to remote address for operation
*
*
* @par Related tags:
* none
*
@@ -536,14 +538,14 @@ sip_to_t const *nua_handle_remote(nua_handle_t const *nh)
/** Get the local address (From/To header) of operation handle
*
* Local address is used as From header in outgoing operations and
* Local address is used as From header in outgoing operations and
* derived from To: header in incoming operations.
*
* @param nh Pointer to operation handle
*
* @retval NULL no local address for operation or operation handle invalid
* @retval !=NULL pointer to local address for operation
*
*
* @par Related tags:
* none
*
@@ -590,7 +592,7 @@ void nua_get_params(nua_t *nua, tag_type_t tag, tag_value_t value, ...)
ta_end(ta); \
} \
else { \
SU_DEBUG_1(("nua: " #event " with invalid handle %p\n", nh)); \
SU_DEBUG_1(("nua: " #event " with invalid handle %p\n", (void *)nh)); \
}
/* Documented with nua_stack_set_params() */
@@ -658,18 +660,18 @@ void nua_method(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
NUA_SIGNAL(nh, nua_r_method, tag, value);
}
/** Send a chat message.
/** Send a chat message.
*
* A chat channel can be established during call setup using "message" media.
* An active chat channel is indicated using #nua_i_state event containing
* SOATAG_ACTIVE_CHAT() tag. Chat messages can be sent using this channel with
* nua_chat() function. Currently this is implemented using SIP MESSAGE
* A chat channel can be established during call setup using "message" media.
* An active chat channel is indicated using #nua_i_state event containing
* SOATAG_ACTIVE_CHAT() tag. Chat messages can be sent using this channel with
* nua_chat() function. Currently this is implemented using SIP MESSAGE
* requests but in future MSRP (message session protocol) will replace it.
*
* @param nh Pointer to operation handle
* @param tag, value, ... List of tagged parameters
*
* @return
* @return
* nothing
*
* @par Related Tags:
@@ -707,18 +709,18 @@ void nua_notify(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
/* nua_r_notify is documented with process_response_to_notify() */
/** Create an event server.
/** Create an event server.
*
* This function create an event server taking care of sending NOTIFY
* requests and responding to further SUBSCRIBE requests. The event
* server can accept multiple subscriptions from several sources and
* takes care for distributing the notifications. Unlike other functions
* This function create an event server taking care of sending NOTIFY
* requests and responding to further SUBSCRIBE requests. The event
* server can accept multiple subscriptions from several sources and
* takes care for distributing the notifications. Unlike other functions
* this call only accepts the SIP tags listed below.
*
* @param nh Pointer to operation handle
* @param tag, value, ... List of tagged parameters
*
* @return
* @return
* nothing
*
* @par Related Tags:
@@ -736,7 +738,7 @@ void nua_notifier(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
NUA_SIGNAL(nh, nua_r_notifier, tag, value);
}
/** Terminate an event server.
/** Terminate an event server.
*
* Terminate an event server with matching event and content type. The event
* server was created earlier with nua_notifier() function.
@@ -744,7 +746,7 @@ void nua_notifier(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
* @param nh Pointer to operation handle
* @param tag, value, ... List of tagged parameters
*
* @return
* @return
* nothing
*
* @par Related Tags:
@@ -809,7 +811,7 @@ void nua_update(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
* @param nh Pointer to operation handle
* @param tag, value, ... List of tagged parameters
*
* @return
* @return
* nothing
*
* @par Related Tags:
@@ -827,7 +829,7 @@ void nua_authenticate(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
*
* After creating a local presence server by nua_notifier(), an incoming
* SUBSCRIBE request causes #nua_i_subscription event. Each subscriber is
* identified with NEATAG_SUB() tag in the #nua_i_subscription event.
* identified with NEATAG_SUB() tag in the #nua_i_subscription event.
* Application can either authorize the subscriber with
* NUTAG_SUBSTATE(#nua_substate_active) or terminate the subscription with
* NUTAG_SUBSTATE(#nua_substate_terminated).
@@ -835,7 +837,7 @@ void nua_authenticate(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
* @param nh Pointer to operation handle
* @param tag, value, ... List of tagged parameters
*
* @return
* @return
* nothing
*
* @par Related Tags:
@@ -875,11 +877,11 @@ void nua_respond(nua_handle_t *nh,
ta_end(ta);
}
else {
SU_DEBUG_1(("nua: respond with invalid handle %p\n", nh));
SU_DEBUG_1(("nua: respond with invalid handle %p\n", (void *)nh));
}
}
/** Destroy a handle
/** Destroy a handle
*
* Terminate the protocol state associated with an operation handle. The
* stack discards resources and terminates the ongoing dialog usage,
@@ -893,7 +895,7 @@ void nua_respond(nua_handle_t *nh,
*
* @param nh Pointer to operation handle
*
* @return
* @return
* nothing
*
* @par Related Tags:
@@ -954,11 +956,14 @@ void nua_signal(nua_t *nua, nua_handle_t *nh, msg_t *msg, int always,
e->e_status = status;
e->e_phrase = phrase;
if (su_msg_send(sumsg) != 0)
SU_DEBUG_7(("nua(%p): signal %s\n", (void *)nh,
nua_event_name(event) + 4));
if (su_msg_send(sumsg) != 0 && event != nua_r_destroy)
nua_handle_unref(nh);
}
}
else {
/* XXX - we should return error code to application */
/* XXX - we should return error code to application but we just abort() */
assert(ENOMEM == 0);
}
@@ -981,8 +986,16 @@ void nua_event(nua_t *root_magic, su_msg_r sumsg, event_t *e)
}
if (!nh || !nh->nh_valid) { /* Handle has been destroyed */
if (nua_log->log_level >= 7) {
char const *name = nua_event_name(e->e_event) + 4;
SU_DEBUG_7(("nua(%p): event %s dropped\n", (void *)nh, name));
}
if (nh && !NH_IS_DEFAULT(nh) && nua_handle_unref(nh)) {
SU_DEBUG_9(("nua(%p): freed by application\n", nh));
#if HAVE_NUA_HANDLE_DEBUG
SU_DEBUG_0(("nua(%p): freed by application\n", (void *)nh));
#else
SU_DEBUG_9(("nua(%p): freed by application\n", (void *)nh));
#endif
}
if (e->e_msg)
msg_destroy(e->e_msg), e->e_msg = NULL;
@@ -1011,7 +1024,11 @@ void nua_event(nua_t *root_magic, su_msg_r sumsg, event_t *e)
e->e_tags);
if (nh && !NH_IS_DEFAULT(nh) && nua_handle_unref(nh)) {
SU_DEBUG_9(("nua(%p): freed by application\n", nh));
#if HAVE_NUA_HANDLE_DEBUG
SU_DEBUG_0(("nua(%p): freed by application\n", (void *)nh));
#else
SU_DEBUG_9(("nua(%p): freed by application\n", (void *)nh));
#endif
}
if (!su_msg_is_non_null(nua->nua_current))
@@ -1066,7 +1083,7 @@ void nua_destroy_event(nua_saved_event_t saved[1])
msg_destroy(e->e_msg), e->e_msg = NULL;
if (nh && !NH_IS_DEFAULT(nh) && nua_handle_unref(nh)) {
SU_DEBUG_9(("nua(%p): freed by application\n", nh));
SU_DEBUG_9(("nua(%p): freed by application\n", (void *)nh));
}
su_msg_destroy(saved);
@@ -1093,21 +1110,36 @@ static int nua_stack_handle_make_replaces_call(void *arg)
/**Generate a @Replaces header for handle.
*
* A @Replaces header contains the @CallID value, @From and @To tags
* corresponding to SIP dialog associated with handle @a nh. Note that the
* @Replaces matches with dialog of the remote peer,
* nua_handle_by_replaces() does not return same handle (unless you swap
* rp_from_tag and rp_to_tag in @Replaces header).
*
* A @Replaces header is used in attended transfer, among other things.
*
* @param nh pointer to operation handle
* @param home memory home used to allocate the header
* @param early_only if true, include "early-only" parameter in @Replaces, too
*
* @return A newly created @Replaces header.
*
* @since New in @VERSION_1_12_4.
*
* @sa nua_handle_by_replaces(), @Replaces, @RFC3891, nua_refer(),
* #nua_i_refer, @ReferTo, nta_leg_make_replaces()
* @sa nua_handle_by_replaces(), @Replaces, @RFC3891, @RFC3515, nua_refer(),
* #nua_i_refer(), @ReferTo, nta_leg_make_replaces(),
* sip_headers_as_url_query()
*/
sip_replaces_t *nua_handle_make_replaces(nua_handle_t *nh,
sip_replaces_t *nua_handle_make_replaces(nua_handle_t *nh,
su_home_t *home,
int early_only)
{
if (nh && nh->nh_valid && nh->nh_nua) {
struct nua_stack_handle_make_replaces_args a = { NULL, nh, home, early_only };
if (su_task_execute(nh->nh_nua->nua_server,
nua_stack_handle_make_replaces_call, (void *)&a,
if (su_task_execute(nh->nh_nua->nua_server,
nua_stack_handle_make_replaces_call, (void *)&a,
NULL) == 0) {
return a.retval;
}
@@ -1134,9 +1166,9 @@ static int nua_stack_handle_by_replaces_call(void *arg)
*
* @since New in @VERSION_1_12_4.
*
* @note
* @note
* You should release the reference with nua_handle_unref() when you are
* done with handle.
* done with the handle.
*
* @sa nua_handle_make_replaces(), @Replaces, @RFC3891, nua_refer(),
* #nua_i_refer, @ReferTo, nta_leg_by_replaces()
@@ -1146,8 +1178,8 @@ nua_handle_t *nua_handle_by_replaces(nua_t *nua, sip_replaces_t const *r)
if (nua) {
struct nua_stack_handle_by_replaces_args a = { NULL, nua, r };
if (su_task_execute(nua->nua_server,
nua_stack_handle_by_replaces_call, (void *)&a,
if (su_task_execute(nua->nua_server,
nua_stack_handle_by_replaces_call, (void *)&a,
NULL) == 0) {
nua_handle_t *nh = a.retval;
+16 -12
View File
@@ -1124,7 +1124,7 @@ follows:
<td>terminating</td>
<td>Process answer</td>
<td>
If there was an failure in SDP negotiation or other failure with media,
If there was a failure in SDP negotiation or other failure with media,
the stack will automatically terminate the call. The BYE follows
immediatelhy after the ACK.
</td></tr>
@@ -1262,7 +1262,7 @@ does not include the extensions like @b 100rel or @b UPDATE.
| +---------------| | : | :
| | +------------+ : | :
| | | : | :
| | nua_respond/18X (2) : | :
| | nua_respond/18X (2a) : | :
| | | : | :
| | V V | :
| | +------------+ | :
@@ -2029,7 +2029,8 @@ NUTAG_AUTOANSWER(0) on B side, NUTAG_AUTOACK(0) on A side.
* Always present
* @param nh Pointer to operation handle.
* @param hmagic Pointer to callback context from nua_handle().
* @param sip Parsed incoming message. May be NULL.
* @param sip Headers in parsed incoming message. May be NULL.
* See also nua_current_request().
* @param tags Tag list containing more information about the state of NUA.
* May be empty.
*
@@ -2038,17 +2039,22 @@ NUTAG_AUTOANSWER(0) on B side, NUTAG_AUTOACK(0) on A side.
* individual event.
*
* The events can be divided into the following categories: \n
* @par Indications:
* @par Status or Error Indications:
* #nua_i_active \n
* #nua_i_error \n
* #nua_i_fork \n
* #nua_i_media_error \n
* #nua_i_subscription \n
* #nua_i_state \n
* #nua_i_terminated
*
* @par SIP requests:
* #nua_i_ack \n
* #nua_i_bye \n
* #nua_i_cancel \n
* #nua_i_chat \n
* #nua_i_error \n
* #nua_i_fork \n
* #nua_i_info \n
* #nua_i_invite \n
* #nua_i_media_error \n
* #nua_i_message \n
* #nua_i_method \n
* #nua_i_notify \n
@@ -2058,9 +2064,6 @@ NUTAG_AUTOANSWER(0) on B side, NUTAG_AUTOACK(0) on A side.
* #nua_i_refer \n
* #nua_i_register \n
* #nua_i_subscribe \n
* #nua_i_subscription \n
* #nua_i_state \n
* #nua_i_terminated \n
* #nua_i_update
*
* @par Responses:
@@ -2122,7 +2125,8 @@ NUTAG_AUTOANSWER(0) on B side, NUTAG_AUTOACK(0) on A side.
*
* Outgoing call has been forked.
*
* This is sent when an INVITE request is answered with multiple 200 responses.
* This is sent when an INVITE request is answered with multiple 2XX series
* responses.
*
* @param status response status code
* @param phrase a short textual description of @a status code
@@ -2219,7 +2223,7 @@ NUTAG_AUTOANSWER(0) on B side, NUTAG_AUTOACK(0) on A side.
* @param nh operation handle associated with the notifier
* @param hmagic operation magic associated with the notifier
* @param sip response to MESSAGE request or NULL upon an error
* (error code and message are in status an phrase parameters)
* (error code and message are in status and phrase parameters)
* @param tags empty
*
* @sa nua_chat(), #nua_r_message
@@ -110,13 +110,14 @@ nua_handle_t *nh_create_handle(nua_t *nua,
assert(nua->nua_home);
if ((nh = su_home_clone(nua->nua_home, sizeof(*nh)))) {
nh->nh_valid = nua_handle;
nh->nh_valid = nua_valid_handle_cookie;
nh->nh_nua = nua;
nh->nh_magic = hmagic;
nh->nh_prefs = nua->nua_dhandle->nh_prefs;
if (nua_handle_save_tags(nh, tags) < 0) {
SU_DEBUG_5(("nua(%p): creating handle %p failed\n", nua, nh));
SU_DEBUG_5(("nua(%p): creating handle %p failed\n",
(void *)nua, (void *)nh));
su_home_unref(nh->nh_home), nh = NULL;
}
@@ -136,7 +137,7 @@ nua_handle_t *nh_create_handle(nua_t *nua,
}
else {
_handle_lifetime = 2;
SU_DEBUG_0(("nh_handle_create(%p)\n", nh));
SU_DEBUG_0(("nh_handle_create(%p)\n", (void *)nh));
su_home_destructor(nh->nh_home, nh_destructor);
}
}
@@ -159,10 +160,12 @@ extern char const _NUA_HANDLE_DEBUG[];
static void nh_destructor(void *arg)
{
nua_handle_t *nh = arg;
SU_DEBUG_0(("nh_destructor(%p)\n", nh));
SU_DEBUG_0(("nh_destructor(%p)\n", (void *)nh));
}
#undef nua_handle_ref
#undef nua_handle_unref
/** Make a new reference to handle.
*
* The handles use reference counting for memory management. In addition to
@@ -180,7 +183,6 @@ nua_handle_t *nua_handle_ref(nua_handle_t *nh)
return (nua_handle_t *)su_home_ref(nh->nh_home);
}
/** Destroy reference to handle.
*
* The handles use reference counting for memory management. In addition to
@@ -214,6 +216,50 @@ char const *nua_generate_instance_identifier(su_home_t *home)
return su_strdup(home, str);
}
/** Check if event is a request that can be responded with nua_respond().
*
* Note that if event status is 200 or greater, it already has been
* responded. This function is provided for compatibility with future
* versions of nua. An unknown event can always be handled in the event
* callback like this:
* @code
* switch (event) {
* ...
* default:
* if (status < 200 && nua_event_is_incoming_request(event))
* nua_respond(nh, SIP_501_NOT_IMPLEMENTED,
* NUTAG_WITH_THIS(nua), TAG_END());
* if (hmagic == NULL)
* nua_handle_destroy(nh);
* return;
* ...
* @endcode
*
* @sa #nua_event_t, nua_respond()
*
* @NEW_1_12_6
*/
int nua_event_is_incoming_request(nua_event_t event)
{
switch (event) {
case nua_i_invite: return 1;
case nua_i_cancel: return 1;
case nua_i_register: return 1;
case nua_i_bye: return 1;
case nua_i_options: return 1;
case nua_i_refer: return 1;
case nua_i_publish: return 1;
case nua_i_prack: return 1;
case nua_i_info: return 1;
case nua_i_update: return 1;
case nua_i_message: return 1;
case nua_i_subscribe: return 1;
case nua_i_notify: return 1;
case nua_i_method: return 1;
default: return 0;
}
}
/** Get name for a NUA event. */
char const *nua_event_name(nua_event_t event)
{
@@ -301,3 +347,34 @@ char const *nua_callstate_name(enum nua_callstate state)
default: return "UNKNOWN";
}
}
/** Return name of subscription state. @NEW_1_12_5. */
char const *nua_substate_name(enum nua_substate substate)
{
switch (substate) {
case nua_substate_embryonic:
/*FALLTHROUGH*/
case nua_substate_pending:
return "pending";
case nua_substate_terminated:
return "terminated";
case nua_substate_active:
/*FALLTHROUGH*/
default:
return "active";
}
}
/** Convert string to enum nua_substate. @NEW_1_12_5. */
enum nua_substate nua_substate_make(char const *sip_substate)
{
if (sip_substate == NULL)
return nua_substate_active;
else if (strcasecmp(sip_substate, "terminated") == 0)
return nua_substate_terminated;
else if (strcasecmp(sip_substate, "pending") == 0)
return nua_substate_pending;
else /* if (strcasecmp(sip_substate, "active") == 0) */
return nua_substate_active;
}
+85 -66
View File
@@ -269,7 +269,7 @@ nua_dialog_usage_t *nua_dialog_usage_add(nua_owner_t *own,
du = *prev_du;
if (du) { /* Already exists */
SU_DEBUG_5(("nua(%p): adding already existing %s usage%s%s\n",
own, nua_dialog_usage_name(du),
(void *)own, nua_dialog_usage_name(du),
event ? " with event " : "", event ? event->o_type : ""));
if (prev_du != &ds->ds_usage) {
@@ -297,7 +297,7 @@ nua_dialog_usage_t *nua_dialog_usage_add(nua_owner_t *own,
}
SU_DEBUG_5(("nua(%p): adding %s usage%s%s\n",
own, nua_dialog_usage_name(du),
(void *)own, nua_dialog_usage_name(du),
o ? " with event " : "", o ? o->o_type :""));
su_home_ref(own);
@@ -345,6 +345,24 @@ void nua_dialog_usage_remove_at(nua_owner_t *own,
nua_client_request_t *cr, *cr_next;
nua_server_request_t *sr, *sr_next;
*at = du->du_next;
o = du->du_event;
SU_DEBUG_5(("nua(%p): removing %s usage%s%s\n",
(void *)own, nua_dialog_usage_name(du),
o ? " with event " : "", o ? o->o_type :""));
du->du_class->usage_remove(own, ds, du);
/* Destroy saved client request */
if (nua_client_is_bound(du->du_cr)) {
nua_client_bind(cr = du->du_cr, NULL);
if (!nua_client_is_queued(cr) &&
!nua_client_is_reporting(cr))
nua_client_request_destroy(cr);
}
/* Clean references from queued client requests */
for (cr = ds->ds_cr; cr; cr = cr_next) {
cr_next = cr->cr_next;
if (cr->cr_usage == du)
@@ -357,29 +375,19 @@ void nua_dialog_usage_remove_at(nua_owner_t *own,
nua_server_request_destroy(sr);
}
*at = du->du_next;
o = du->du_event;
SU_DEBUG_5(("nua(%p): removing %s usage%s%s\n",
own, nua_dialog_usage_name(du),
o ? " with event " : "", o ? o->o_type :""));
du->du_class->usage_remove(own, ds, du);
msg_destroy(du->du_msg), du->du_msg = NULL;
su_home_unref(own);
su_free(own, du);
}
/* Zap dialog if there is no more usages */
if (ds->ds_usage == 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;
/* Zap dialog if there are no more usages */
if (ds->ds_terminating)
;
else if (ds->ds_usage == NULL) {
nua_dialog_remove(own, ds, NULL);
ds->ds_has_events = 0;
ds->ds_terminated = 0;
return;
}
else if (!ds->ds_terminated) {
else {
nua_dialog_log_usage(own, ds);
}
}
@@ -412,7 +420,7 @@ void nua_dialog_log_usage(nua_owner_t *own, nua_dialog_state_t *ds)
}
}
SU_DEBUG_3(("nua(%p): handle with %s%s%s\n", own,
SU_DEBUG_3(("nua(%p): handle with %s%s%s\n", (void *)own,
ds->ds_has_session ? "session and " : "",
ds->ds_has_events ? "events " : "",
buffer));
@@ -423,49 +431,16 @@ void nua_dialog_log_usage(nua_owner_t *own, nua_dialog_state_t *ds)
void nua_dialog_deinit(nua_owner_t *own,
nua_dialog_state_t *ds)
{
ds->ds_terminating = 1;
while (ds->ds_usage) {
nua_dialog_usage_remove_at(own, ds, &ds->ds_usage);
}
}
nua_dialog_remove(own, ds, NULL);
/** @internal Dialog has been terminated. Remove all usages. */
void nua_dialog_terminated(nua_owner_t *own,
struct nua_dialog_state *ds,
int status,
char const *phrase)
{
ds->ds_terminated = 1;
while (ds->ds_usage) {
#if 0
int call = 0;
if (ds->ds_usage->du_kind == nua_session_usage)
call = 1; /* Delay sending the event */
else
/* XXX */;
#endif
nua_dialog_usage_remove_at(own, ds, &ds->ds_usage);
}
}
/**@internal
* Set expiration time.
*/
void nua_dialog_usage_set_expires(nua_dialog_usage_t *du,
unsigned delta)
{
if (delta) {
sip_time_t now = sip_now(), expires = now + delta;
if (expires < now)
expires = SIP_TIME_MAX;
du->du_expires = expires;
nua_dialog_usage_set_refresh(du, delta);
}
else
du->du_expires = 0, du->du_refresh = 0;
ds->ds_has_events = 0;
ds->ds_terminating = 0;
}
/**@internal
@@ -521,10 +496,20 @@ void nua_dialog_usage_refresh_range(nua_dialog_usage_t *du,
du->du_refresh = target;
}
/** Set absolute refresh time */
void nua_dialog_usage_refresh_at(nua_dialog_usage_t *du,
sip_time_t target)
{
SU_DEBUG_7(("nua(): refresh %s after %lu seconds\n",
nua_dialog_usage_name(du), target - sip_now()));
du->du_refresh = target;
}
/**@internal Do not refresh. */
void nua_dialog_usage_reset_refresh(nua_dialog_usage_t *du)
{
du->du_refresh = 0;
if (du)
du->du_refresh = 0;
}
/** @internal Refresh usage or shutdown usage if @a now is 0. */
@@ -537,18 +522,52 @@ void nua_dialog_usage_refresh(nua_owner_t *owner,
du->du_refresh = 0;
if (now > 0) {
if (du->du_class->usage_refresh) {
du->du_class->usage_refresh(owner, ds, du, now);
return;
}
assert(du->du_class->usage_refresh);
du->du_class->usage_refresh(owner, ds, du, now);
}
else {
du->du_shutdown = 1;
if (du->du_class->usage_shutdown) {
du->du_class->usage_shutdown(owner, ds, du);
return;
}
assert(du->du_class->usage_shutdown);
du->du_class->usage_shutdown(owner, ds, du);
}
}
}
/** Terminate all dialog usages gracefully. */
int nua_dialog_shutdown(nua_owner_t *owner, nua_dialog_state_t *ds)
{
nua_dialog_usage_t *du;
ds->ds_terminating = 1;
do {
for (du = ds->ds_usage; du; du = du->du_next) {
if (!du->du_shutdown) {
nua_dialog_usage_shutdown(owner, ds, du);
break;
}
}
} while (du);
return 1;
}
/** (Gracefully) terminate usage.
*
* @retval >0 shutdown done
* @retval 0 shutdown in progress
* @retval <0 try again later
*/
int nua_dialog_usage_shutdown(nua_owner_t *owner,
nua_dialog_state_t *ds,
nua_dialog_usage_t *du)
{
if (du) {
du->du_refresh = 0;
du->du_shutdown = 1;
assert(du->du_class->usage_shutdown);
return du->du_class->usage_shutdown(owner, ds, du);
}
else
return 200;
}
+405 -48
View File
@@ -48,49 +48,93 @@ typedef NUA_OWNER_T nua_owner_t;
#include <sofia-sip/nta.h>
#endif
typedef su_msg_r nua_saved_signal_t;
typedef struct nua_server_request nua_server_request_t;
typedef struct nua_client_request nua_client_request_t;
/** Respond to an incoming request. */
typedef int nua_server_respond_f(nua_server_request_t *, tagi_t const *);
typedef struct {
sip_method_t sm_method;
char const *sm_method_name;
/** Restart an outgoing request. */
typedef void nua_creq_restart_f(nua_owner_t *, tagi_t *tags);
int sm_event;
struct {
unsigned create_dialog:1, in_dialog:1, target_refresh:1, add_contact:1;
unsigned :0;
} sm_flags;
/** Initialize server-side request. */
int (*sm_init)(nua_server_request_t *sr);
/** Preprocess server-side request (after handle has been created). */
int (*sm_preprocess)(nua_server_request_t *sr);
/** Update server-side request parameters */
int (*sm_params)(nua_server_request_t *sr, tagi_t const *tags);
/** Respond to server-side request. */
int (*sm_respond)(nua_server_request_t *sr, tagi_t const *tags);
/** Report server-side request to application. */
int (*sm_report)(nua_server_request_t *sr, tagi_t const *tags);
} nua_server_methods_t;
/** Server side transaction */
struct nua_server_request {
struct nua_server_request *sr_next, **sr_prev;
nua_server_methods_t const *sr_methods;
nua_owner_t *sr_owner; /**< Backpointer to handle */
nua_dialog_usage_t *sr_usage; /**< Backpointer to usage */
/** When the application responds to an request with
* nua_respond(), the sr_respond() is called
*/
nua_server_respond_f *sr_respond;
nta_incoming_t *sr_irq; /**< Server transaction object */
msg_t *sr_msg; /**< Request message */
struct {
msg_t *msg; /**< Request message */
sip_t const *sip; /**< Headers in request message */
} sr_request;
struct {
msg_t *msg; /**< Response message */
sip_t *sip; /**< Headers in response message */
} sr_response;
sip_method_t sr_method; /**< Request method */
int sr_application; /**< Status by application */
int sr_status; /**< Status code */
char const *sr_phrase; /**< Status phrase */
unsigned sr_auto:1; /**< Autoresponse - no event has been sent */
unsigned sr_event:1; /**< Reported to application */
unsigned sr_initial:1; /**< Handle was created by this request */
unsigned sr_add_contact:1; /**< Add Contact header to the response */
unsigned sr_target_refresh:1; /**< Refresh target */
unsigned sr_terminating:1; /**< Terminate usage after final response */
unsigned sr_gracefully:1; /**< Terminate usage gracefully */
unsigned sr_neutral:1; /**< No effect on session or other usage */
/* Flags used with 100rel */
unsigned sr_100rel:1, sr_pracked:1;
/* Flags used with offer-answer */
unsigned sr_offer_recv:1; /**< We have received an offer */
unsigned sr_answer_sent:2; /**< We have answered (reliably, if >1) */
unsigned sr_offer_sent:1; /**< We have offered SDP */
unsigned sr_offer_sent:2; /**< We have offered SDP (reliably, if >1) */
unsigned sr_answer_recv:1; /**< We have received SDP answer */
};
unsigned :0;
#define SR_INIT(sr) \
((void)memset((sr), 0, sizeof (sr)[0]), \
(void)(SR_STATUS1((sr), SIP_100_TRYING)), \
sr)
char const *sr_sdp; /**< SDP received from client */
size_t sr_sdp_len; /**< SDP length */
/**< Save 200 OK nua_respond() signal until PRACK has been received */
nua_saved_signal_t sr_signal;
};
#define SR_STATUS(sr, status, phrase) \
((sr)->sr_phrase = (phrase), (sr)->sr_status = (status))
@@ -104,46 +148,194 @@ int sr_status(nua_server_request_t *sr, int status, char const *phrase)
return (void)(sr->sr_phrase = phrase), (sr->sr_status = status);
}
/** Methods for client request */
typedef struct {
sip_method_t crm_method;
char const *crm_method_name;
size_t crm_extra; /**< Size of private data */
struct {
unsigned create_dialog:1, in_dialog:1, target_refresh:1;
unsigned:0;
} crm_flags;
/** Generate a request message.
*
* @retval 1 when request message has been created
* @retval 0 when request message should be created in normal fashion
* @retval -1 upon an error
*/
int (*crm_template)(nua_client_request_t *cr,
msg_t **return_msg,
tagi_t const *tags);
/**@a crm_init is called when a client request is sent first time.
*
* @retval 1 when request has been responded
* @retval 0 when request should be sent in normal fashion
* @retval -1 upon an error
*/
int (*crm_init)(nua_client_request_t *, msg_t *msg, sip_t *sip,
tagi_t const *tags);
/** @a crm_send is called each time when a client request is sent.
*
* @retval 1 when request has been responded
* @retval 0 when request has been sent
* @retval -1 upon an error (request message has not been destroyed)
* @retval -2 upon an error (request message has been destroyed)
*/
int (*crm_send)(nua_client_request_t *,
msg_t *msg, sip_t *sip,
tagi_t const *tags);
/** @a crm_check_restart is called each time when a response is received.
*
* It is used to restart reqquest after responses with method-specific
* status code or method-specific way of restarting the request.
*
* @retval 1 when request has been restarted
* @retval 0 when response should be processed normally
*/
int (*crm_check_restart)(nua_client_request_t *,
int status, char const *phrase,
sip_t const *sip);
/** @a crm_recv is called each time a final response is received.
*
* A final response is in range 200 .. 699 (or internal response) and it
* cannot be restarted.
*
* crm_recv() should call nua_base_client_response() or
* nua_base_client_tresponse(). The return values below are documented with
* nua_base_client_response(), too.
*
* @retval 0 if response was preliminary
* @retval 1 if response was final
* @retval 2 if response destroyed the handle, too.
*/
int (*crm_recv)(nua_client_request_t *,
int status, char const *phrase,
sip_t const *sip);
/** @a crm_preliminary is called each time a preliminary response is received.
*
* A preliminary response is in range 101 .. 199.
*
* crm_preliminary() should call nua_base_client_response() or
* nua_base_client_tresponse().
*
* @retval 0 if response was preliminary
* @retval 1 if response was final
* @retval 2 if response destroyed the handle, too.
*/
int (*crm_preliminary)(nua_client_request_t *,
int status, char const *phrase,
sip_t const *sip);
/** @a crm_report is called each time a response is received and it is
* reported to the application.
*
* The status and phrase may be different from the status and phrase
* received from the network, e.g., when the request is restarted.
*
* @return The return value should be 0. It is currently ignored.
*/
int (*crm_report)(nua_client_request_t *,
int status, char const *phrase,
sip_t const *sip,
nta_outgoing_t *orq,
tagi_t const *tags);
/** @a crm_deinit is called when a client-side request is destroyed.
*
* @return The return value should be 0. It is currently ignored.
*/
int (*crm_deinit)(nua_client_request_t *);
} nua_client_methods_t;
/* Client-side request. Documented by nua_client_create() */
struct nua_client_request
{
nua_client_request_t *cr_next; /**< Linked list of requests */
/*nua_event_t*/ int cr_event; /**< Request event */
nua_creq_restart_f *cr_restart;
nta_outgoing_t *cr_orq;
msg_t *cr_msg;
nua_client_request_t *cr_next, **cr_prev; /**< Linked list of requests */
nua_owner_t *cr_owner;
nua_dialog_usage_t *cr_usage;
nua_saved_signal_t cr_signal;
tagi_t const *cr_tags;
nua_client_methods_t const *cr_methods;
msg_t *cr_msg;
sip_t *cr_sip;
nta_outgoing_t *cr_orq;
/*nua_event_t*/ int cr_event; /**< Request event */
sip_method_t cr_method;
char const *cr_method_name;
url_t *cr_target;
uint32_t cr_seq;
unsigned short cr_status; /**< Latest status */
unsigned short cr_retry_count; /**< Retry count for this request */
/* Flags used with offer-answer */
unsigned short cr_answer_recv; /**< Recv answer in response
* with this status.
*/
unsigned cr_offer_sent:1; /**< Sent offer in this request */
unsigned cr_offer_sent:1; /**< Sent offer in this request */
unsigned cr_offer_recv:1; /**< Recv offer in a response */
unsigned cr_answer_sent:1; /**< Sent answer in (PR)ACK */
unsigned cr_offer_recv:1; /**< Recv offer in a response */
unsigned cr_answer_sent:1; /**< Sent answer in (PR)ACK */
unsigned cr_has_contact:1; /**< Request has application contact */
/* Flags with usage */
unsigned cr_neutral:1; /**< No effect on session or other usage */
/* Lifelong flags? */
unsigned cr_auto:1; /**< Request was generated by stack */
unsigned cr_has_contact:1; /**< Request has user Contact */
unsigned cr_contactize:1; /**< Request needs Contact */
unsigned cr_dialog:1; /**< Request can initiate dialog */
/* Current state */
unsigned cr_challenged:1; /**< Request was challenged */
unsigned cr_wait_for_cred:1; /**< Request is pending authentication */
unsigned cr_restarting:1; /**< Request is being restarted */
unsigned cr_reporting:1; /**< Reporting in progress */
unsigned cr_terminating:1; /**< Request terminates the usage */
signed int cr_terminated:2; /**< Response terminated usage (1) or
whole dialog (-1) */
unsigned cr_graceful:1; /**< Graceful termination required */
};
struct nua_dialog_state
{
nua_client_request_t ds_cr[1];
nua_server_request_t *ds_sr;
/** Dialog usages. */
nua_dialog_usage_t *ds_usage;
/** Client requests */
nua_client_request_t *ds_cr;
/** Server requests */
nua_server_request_t *ds_sr;
/* Dialog and subscription state */
unsigned ds_reporting:1; /**< We are reporting */
unsigned ds_route:1; /**< We have route */
unsigned ds_terminated:1; /**< Being terminated */
unsigned ds_terminating:1; /**< Being terminated */
unsigned ds_has_session:1; /**< We have session */
unsigned ds_has_register:1; /**< We have registration */
unsigned ds_has_publish:1; /**< We have publish */
unsigned ds_has_referrals:1; /**< We have (or have had) referrals */
unsigned ds_got_session:1; /**< We have (or have had) session */
unsigned ds_got_referrals:1; /**< We have (or have had) referrals */
unsigned :0;
@@ -196,8 +388,8 @@ typedef struct {
struct nua_dialog_usage {
nua_dialog_usage_t *du_next;
nua_usage_class const *du_class;
nua_client_request_t *du_cr; /**< Client request bound with usage */
unsigned du_terminating:1; /**< Now trying to terminate usage */
unsigned du_ready:1; /**< Established usage */
unsigned du_shutdown:1; /**< Shutdown in progress */
unsigned:0;
@@ -206,13 +398,11 @@ struct nua_dialog_usage {
* Non-zero if the usage is established, SIP_TIME_MAX if there no
* expiration time.
*/
sip_time_t du_expires;
sip_time_t du_refresh; /**< When to refresh */
sip_event_t const *du_event; /**< Event of usage */
msg_t *du_msg; /**< Template message */
};
void nua_dialog_uac_route(nua_owner_t *, nua_dialog_state_t *ds,
@@ -225,6 +415,11 @@ int nua_dialog_remove(nua_owner_t *own,
nua_dialog_state_t *ds,
nua_dialog_usage_t *usage);
static inline int nua_dialog_is_reporting(nua_dialog_state_t const *ds)
{
return ds && ds->ds_reporting;
}
char const *nua_dialog_usage_name(nua_dialog_usage_t const *du);
nua_dialog_usage_t *nua_dialog_usage_add(nua_owner_t *,
@@ -243,18 +438,16 @@ void nua_dialog_usage_remove(nua_owner_t *,
void nua_dialog_deinit(nua_owner_t *own,
nua_dialog_state_t *ds);
void nua_dialog_terminated(nua_owner_t *,
struct nua_dialog_state *ds,
int status,
char const *phrase);
void nua_dialog_usage_set_expires(nua_dialog_usage_t *du, unsigned delta);
int nua_dialog_shutdown(nua_owner_t *owner, nua_dialog_state_t *ds);
void nua_dialog_usage_set_refresh(nua_dialog_usage_t *du, unsigned delta);
void nua_dialog_usage_refresh_range(nua_dialog_usage_t *du,
unsigned min, unsigned max);
void nua_dialog_usage_refresh_at(nua_dialog_usage_t *du,
sip_time_t target);
void nua_dialog_usage_reset_refresh(nua_dialog_usage_t *du);
void nua_dialog_usage_refresh(nua_owner_t *owner,
@@ -262,6 +455,10 @@ void nua_dialog_usage_refresh(nua_owner_t *owner,
nua_dialog_usage_t *du,
sip_time_t now);
int nua_dialog_usage_shutdown(nua_owner_t *owner,
nua_dialog_state_t *ds,
nua_dialog_usage_t *du);
static inline
int nua_dialog_is_established(nua_dialog_state_t const *ds)
{
@@ -287,18 +484,178 @@ nua_dialog_usage_t *nua_dialog_usage_public(void const *p)
/* ---------------------------------------------------------------------- */
void nua_server_request_destroy(nua_server_request_t *sr);
int nua_client_create(nua_owner_t *owner,
int event,
nua_client_methods_t const *methods,
tagi_t const *tags);
int nua_server_respond(nua_server_request_t *sr,
int status, char const *phrase,
int nua_client_tcreate(nua_owner_t *nh,
int event,
nua_client_methods_t const *methods,
tag_type_t tag, tag_value_t value, ...);
msg_t *nua_server_response(nua_server_request_t *sr,
int status, char const *phrase,
tag_type_t tag, tag_value_t value, ...);
static inline
void *nua_private_client_request(nua_client_request_t const *cr)
{
return (void *)(cr + 1);
}
int nua_default_respond(nua_server_request_t *sr,
tagi_t const *tags);
void nua_client_request_destroy(nua_client_request_t *);
int nua_client_request_queue(nua_client_request_t *cr);
static inline int nua_client_is_queued(nua_client_request_t const *cr)
{
return cr && cr->cr_prev;
}
nua_client_request_t *nua_client_request_remove(nua_client_request_t *cr);
int nua_client_bind(nua_client_request_t *cr, nua_dialog_usage_t *du);
static inline int nua_client_is_bound(nua_client_request_t const *cr)
{
return cr && cr->cr_usage && cr->cr_usage->du_cr == cr;
}
static inline int nua_client_is_reporting(nua_client_request_t const *cr)
{
return cr && cr->cr_reporting;
}
/** Mark client request as a terminating one */
static inline void nua_client_terminating(nua_client_request_t *cr)
{
cr->cr_terminating = 1;
}
int nua_client_init_request(nua_client_request_t *cr);
int nua_client_restart_request(nua_client_request_t *cr,
int terminating,
tagi_t const *tags);
int nua_client_resend_request(nua_client_request_t *cr,
int terminating);
int nua_base_client_request(nua_client_request_t *cr,
msg_t *msg,
sip_t *sip,
tagi_t const *tags);
int nua_base_client_trequest(nua_client_request_t *cr,
msg_t *msg,
sip_t *sip,
tag_type_t tag, tag_value_t value, ...);
extern nta_response_f nua_client_orq_response;
int nua_client_return(nua_client_request_t *cr,
int status,
char const *phrase,
msg_t *to_be_destroyed);
int nua_client_response(nua_client_request_t *cr,
int status,
char const *phrase,
sip_t const *sip);
int nua_client_check_restart(nua_client_request_t *cr,
int status,
char const *phrase,
sip_t const *sip);
int nua_base_client_check_restart(nua_client_request_t *cr,
int status,
char const *phrase,
sip_t const *sip);
int nua_client_restart(nua_client_request_t *cr,
int status, char const *phrase);
int nua_base_client_response(nua_client_request_t *cr,
int status, char const *phrase,
sip_t const *sip,
tagi_t const *tags);
int nua_base_client_tresponse(nua_client_request_t *cr,
int status, char const *phrase,
sip_t const *sip,
tag_type_t tag, tag_value_t value, ...);
int nua_client_set_target(nua_client_request_t *cr, url_t const *target);
int nua_client_report(nua_client_request_t *cr,
int status, char const *phrase,
sip_t const *sip,
nta_outgoing_t *orq,
tagi_t const *tags);
nua_client_request_t *nua_client_request_pending(nua_client_request_t const *);
int nua_client_next_request(nua_client_request_t *cr, int invite);
/* ---------------------------------------------------------------------- */
extern nua_server_methods_t const
nua_extension_server_methods,
nua_invite_server_methods, /**< INVITE */
nua_bye_server_methods, /**< BYE */
nua_options_server_methods, /**< OPTIONS */
nua_register_server_methods, /**< REGISTER */
nua_info_server_methods, /**< INFO */
nua_prack_server_methods, /**< PRACK */
nua_update_server_methods, /**< UPDATE */
nua_message_server_methods, /**< MESSAGE */
nua_subscribe_server_methods, /**< SUBSCRIBE */
nua_notify_server_methods, /**< NOTIFY */
nua_refer_server_methods, /**< REFER */
nua_publish_server_methods; /**< PUBLISH */
/** Return true if we have not sent final response to request */
static inline
int nua_server_request_is_pending(nua_server_request_t const *sr)
{
return sr && sr->sr_response.msg;
}
static inline
int nua_server_request_status(nua_server_request_t const *sr)
{
return sr ? nta_incoming_status(sr->sr_irq) : 500;
}
void nua_server_request_destroy(nua_server_request_t *sr);
int nua_base_server_init(nua_server_request_t *sr);
#define nua_base_server_init NULL
int nua_base_server_preprocess(nua_server_request_t *sr);
#define nua_base_server_preprocess NULL
int nua_server_params(nua_server_request_t *sr, tagi_t const *tags);
int nua_base_server_params(nua_server_request_t *sr, tagi_t const *tags);
#define nua_base_server_params NULL
int nua_server_trespond(nua_server_request_t *sr,
tag_type_t tag, tag_value_t value, ...);
int nua_server_respond(nua_server_request_t *sr, tagi_t const *tags);
int nua_base_server_trespond(nua_server_request_t *sr,
tag_type_t tag, tag_value_t value, ...);
int nua_base_server_respond(nua_server_request_t *sr,
tagi_t const *tags);
int nua_server_report(nua_server_request_t *sr);
int nua_base_server_treport(nua_server_request_t *sr,
tag_type_t tag, tag_value_t value, ...);
int nua_base_server_report(nua_server_request_t *sr, tagi_t const *tags);
/* ---------------------------------------------------------------------- */
#endif /* NUA_DIALOG_H */
@@ -45,9 +45,6 @@
#include <sofia-sip/sip_status.h>
#include <sofia-sip/su_tagarg.h>
#define NTA_LEG_MAGIC_T struct nua_handle_s
#define NTA_OUTGOING_MAGIC_T struct nua_handle_s
#define NEA_SMAGIC_T struct nua_handle_s
#define NEA_EMAGIC_T struct nua_handle_s
@@ -121,13 +118,13 @@ nua_stack_notifier(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *ta
status = 900, phrase = "Error when notifying watchers";
else
nua_stack_event(nua, nh, NULL, e, status = SIP_200_OK,
SIPTAG_EVENT(event),
SIPTAG_CONTENT_TYPE(ct),
TAG_END());
nua_stack_tevent(nua, nh, NULL, e, status = SIP_200_OK,
SIPTAG_EVENT(event),
SIPTAG_CONTENT_TYPE(ct),
TAG_END());
if (status != 200)
nua_stack_event(nua, nh, NULL, e, status, phrase, TAG_END());
nua_stack_event(nua, nh, NULL, e, status, phrase, NULL);
su_home_deinit(home);
}
@@ -223,7 +220,7 @@ void authorize_watcher(nea_server_t *nes,
what = "active";
}
SU_DEBUG_7(("nua(%p): authorize_watcher: %s\n", nh, what));
SU_DEBUG_7(("nua(%p): authorize_watcher: %s\n", (void *)nh, what));
nea_sub_auth(sn->sn_subscriber, substate,
TAG_IF(substate == nua_substate_pending,
NEATAG_FAKE(1)),
@@ -235,13 +232,13 @@ void authorize_watcher(nea_server_t *nes,
substate = nua_substate_terminated;
nea_server_flush(nes, NULL);
SU_DEBUG_7(("nua(%p): authorize_watcher: %s\n",
nh, "watcher is removed"));
(void *)nh, "watcher is removed"));
}
nua_stack_event(nua, nh, msg, nua_i_subscription, status, phrase,
NUTAG_SUBSTATE(substate),
NEATAG_SUB(sn->sn_subscriber),
TAG_END());
nua_stack_tevent(nua, nh, msg, nua_i_subscription, status, phrase,
NUTAG_SUBSTATE(substate),
NEATAG_SUB(sn->sn_subscriber),
TAG_END());
}
/* ---------------------------------------------------------------------- */
@@ -262,12 +259,11 @@ void nua_stack_authorize(nua_t *nua,
if (sub && state > 0) {
nea_sub_auth(sub, state, TAG_NEXT(tags));
nua_stack_event(nua, nh, NULL, e, SIP_200_OK, TAG_END());
nua_stack_event(nua, nh, NULL, e, SIP_200_OK, NULL);
}
else {
nua_stack_event(nua, nh, NULL, e, NUA_INTERNAL_ERROR, TAG_END());
nua_stack_event(nua, nh, NULL, e, NUA_INTERNAL_ERROR, NULL);
}
return;
}
/** @internal Shutdown notifier object */
@@ -347,5 +343,5 @@ void nua_stack_terminate(nua_t *nua,
NEATAG_REASON("noresource"),
TAG_NEXT(tags));
nua_stack_event(nua, nh, NULL, e, SIP_200_OK, TAG_END());
nua_stack_event(nua, nh, NULL, e, SIP_200_OK, NULL);
}
@@ -43,17 +43,8 @@
#include <sofia-sip/sip_protos.h>
#include <sofia-sip/sip_status.h>
#define NTA_LEG_MAGIC_T struct nua_handle_s
#define NTA_OUTGOING_MAGIC_T struct nua_handle_s
#include "nua_stack.h"
static int process_response_to_method(nua_handle_t *nh,
nta_outgoing_t *orq,
sip_t const *sip);
static void restart_method(nua_handle_t *nh, tagi_t *tags);
static int respond_to_method(nua_server_request_t *sr, tagi_t const *tags);
/** Send an extension request.
*
* Send an entension request message.
@@ -78,32 +69,25 @@ static int respond_to_method(nua_server_request_t *sr, tagi_t const *tags);
* @since New in @VERSION_1_12_4.
*/
static nua_client_methods_t const nua_method_client_methods = {
SIP_METHOD_UNKNOWN,
0,
{
/* create_dialog */ 0,
/* in_dialog */ 0,
/* target_refresh */ 1,
},
/* nua_method_client_template */ NULL,
/* nua_method_client_init */ NULL,
/* nua_method_client_request */ NULL,
/* nua_method_client_check_restart */ NULL,
/* nua_method_client_response */ NULL
};
int
nua_stack_method(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags)
{
nua_client_request_t *cr = nh->nh_ds->ds_cr;
msg_t *msg;
if (cr->cr_orq)
return UA_EVENT2(e, 900, "Request already in progress");
nua_stack_init_handle(nua, nh, TAG_NEXT(tags));
msg = nua_creq_msg(nua, nh, cr, cr->cr_retry_count,
SIP_METHOD_UNKNOWN,
TAG_NEXT(tags));
if (msg)
cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,
process_response_to_method, nh, NULL,
msg,
SIPTAG_END(),
TAG_NEXT(tags));
if (!cr->cr_orq) {
msg_destroy(msg);
return UA_EVENT1(e, NUA_INTERNAL_ERROR);
}
return cr->cr_event = e;
return nua_client_create(nh, e, &nua_method_client_methods, tags);
}
/** @NUA_EVENT nua_r_method
@@ -127,20 +111,6 @@ nua_stack_method(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags
* @END_NUA_EVENT
*/
static int process_response_to_method(nua_handle_t *nh,
nta_outgoing_t *orq,
sip_t const *sip)
{
if (nua_creq_check_restart(nh, nh->nh_ds->ds_cr, orq, sip, restart_method))
return 0;
return nua_stack_process_response(nh, nh->nh_ds->ds_cr, orq, sip, TAG_END());
}
void restart_method(nua_handle_t *nh, tagi_t *tags)
{
nua_creq_restart(nh, nh->nh_ds->ds_cr, process_response_to_method, tags);
}
/** @NUA_EVENT nua_i_method
*
* @brief Incoming extension request.
@@ -155,50 +125,35 @@ void restart_method(nua_handle_t *nh, tagi_t *tags)
* @param nh operation handle associated with the method
* @param hmagic application context associated with the handle
* (maybe NULL if outside session)
* @param sip incoming request
* @param sip headers in incoming request (see also nua_current_request())
* @param tags NUTAG_METHOD()
*
* The extension name is in sip->sip_request->rq_method_name, too.
* The extension method name is in sip->sip_request->rq_method_name, too.
*
* @sa nua_method(), #nua_r_method
* @note If the @a status is < 200, it is up to application to respond to
* the request with nua_respond(). If the handle is destroyed, the stack
* returns a <i>500 Internal Server Error</i> response to any unresponded
* request.
*
* @sa nua_method(), #nua_r_method, NUTAG_ALLOW(), NUTAG_APPL_METHOD(),
* nua_respond(), NUTAG_WITH(), NUTAG_WITH_THIS(), NUTAG_
*
* @END_NUA_EVENT
*/
int nua_stack_process_method(nua_t *nua,
nua_handle_t *nh,
nta_incoming_t *irq,
sip_t const *sip)
{
nua_server_request_t *sr, sr0[1];
sr = SR_INIT(sr0);
sr = nua_server_request(nua, nh, irq, sip, sr, sizeof *sr,
respond_to_method, 0);
return nua_stack_server_event(nua, sr, nua_i_method, TAG_END());
}
static
int respond_to_method(nua_server_request_t *sr, tagi_t const *tags)
{
nua_handle_t *nh = sr->sr_owner;
nua_t *nua = nh->nh_nua;
msg_t *msg;
msg = nua_server_response(sr, sr->sr_status, sr->sr_phrase, TAG_NEXT(tags));
if (msg) {
nta_incoming_mreply(sr->sr_irq, msg);
}
else {
SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR);
nta_incoming_treply(sr->sr_irq, sr->sr_status, sr->sr_phrase, TAG_END());
nua_stack_event(nua, nh, NULL,
nua_i_error, 900, "Response to Extension Method Fails",
TAG_END());
}
return sr->sr_status >= 200 ? sr->sr_status : 0;
}
nua_server_methods_t const nua_extension_server_methods =
{
SIP_METHOD_UNKNOWN,
nua_i_method, /* Event */
{
1, /* Do create dialog */
0, /* Can be an initial request */
1, /* Perhaps a target refresh request? */
1, /* Add a contact? */
},
nua_base_server_init,
nua_base_server_preprocess,
nua_base_server_params,
nua_base_server_respond,
nua_base_server_report,
};
@@ -43,9 +43,6 @@
#include <sofia-sip/sip_protos.h>
#include <sofia-sip/sip_status.h>
#define NTA_LEG_MAGIC_T struct nua_handle_s
#define NTA_OUTGOING_MAGIC_T struct nua_handle_s
#include "nua_stack.h"
/* ======================================================================== */
@@ -72,48 +69,41 @@
* @sa #nua_i_message, @RFC3428
*/
static int process_response_to_message(nua_handle_t *nh,
nta_outgoing_t *orq,
sip_t const *sip);
static int nua_message_client_init(nua_client_request_t *cr,
msg_t *, sip_t *,
tagi_t const *tags);
static nua_client_methods_t const nua_message_client_methods = {
SIP_METHOD_MESSAGE,
0,
{
/* create_dialog */ 0,
/* in_dialog */ 0,
/* target refresh */ 0
},
/* nua_message_client_template */ NULL,
nua_message_client_init,
/*nua_message_client_request*/ NULL,
/* nua_message_client_check_restart */ NULL,
/*nua_message_client_response*/ NULL
};
int
nua_stack_message(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags)
nua_stack_message(nua_t *nua,
nua_handle_t *nh,
nua_event_t e,
tagi_t const *tags)
{
nua_client_request_t *cr = nh->nh_ds->ds_cr;
msg_t *msg;
sip_t *sip;
if (nh_is_special(nh)) {
return UA_EVENT2(e, 900, "Invalid handle for MESSAGE");
}
else if (cr->cr_orq) {
return UA_EVENT2(e, 900, "Request already in progress");
}
nua_stack_init_handle(nua, nh, TAG_NEXT(tags));
msg = nua_creq_msg(nua, nh, cr, cr->cr_retry_count,
SIP_METHOD_MESSAGE,
NUTAG_ADD_CONTACT(NH_PGET(nh, win_messenger_enable)),
TAG_NEXT(tags));
sip = sip_object(msg);
if (sip)
cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,
process_response_to_message, nh, NULL,
msg,
SIPTAG_END(), TAG_NEXT(tags));
if (!cr->cr_orq) {
msg_destroy(msg);
return UA_EVENT1(e, NUA_INTERNAL_ERROR);
}
return cr->cr_event = e;
return nua_client_create(nh, e, &nua_message_client_methods, tags);
}
void restart_message(nua_handle_t *nh, tagi_t *tags)
static int nua_message_client_init(nua_client_request_t *cr,
msg_t *msg, sip_t *sip,
tagi_t const *tags)
{
nua_creq_restart(nh, nh->nh_ds->ds_cr, process_response_to_message, tags);
if (NH_PGET(cr->cr_owner, win_messenger_enable))
cr->cr_contactize = 1;
return 0;
}
/** @NUA_EVENT nua_r_message
@@ -137,15 +127,6 @@ void restart_message(nua_handle_t *nh, tagi_t *tags)
* @END_NUA_EVENT
*/
static int process_response_to_message(nua_handle_t *nh,
nta_outgoing_t *orq,
sip_t const *sip)
{
if (nua_creq_check_restart(nh, nh->nh_ds->ds_cr, orq, sip, restart_message))
return 0;
return nua_stack_process_response(nh, nh->nh_ds->ds_cr, orq, sip, TAG_END());
}
/** @NUA_EVENT nua_i_message
*
* @brief Incoming @b MESSAGE request.
@@ -168,32 +149,39 @@ static int process_response_to_message(nua_handle_t *nh,
* @END_NUA_EVENT
*/
int nua_stack_process_message(nua_t *nua,
nua_handle_t *nh,
nta_incoming_t *irq,
sip_t const *sip)
int nua_message_server_init(nua_server_request_t *sr);
int nua_message_server_params(nua_server_request_t *, tagi_t const *);
nua_server_methods_t const nua_message_server_methods =
{
SIP_METHOD_MESSAGE,
nua_i_message, /* Event */
{
0, /* Do not create dialog */
0, /* Can be initial request */
0, /* Perhaps a target refresh request? */
0, /* Do not add contact by default */
},
nua_message_server_init,
nua_base_server_preprocess,
nua_message_server_params,
nua_base_server_respond,
nua_base_server_report,
};
int nua_message_server_init(nua_server_request_t *sr)
{
msg_t *msg;
if (!NH_PGET(sr->sr_owner, message_enable))
return SR_STATUS1(sr, SIP_403_FORBIDDEN);
if (nh
? !NH_PGET(nh, message_enable)
: !DNH_PGET(nua->nua_dhandle, message_enable))
return 403;
return 0;
}
if (nh == NULL)
if (!(nh = nua_stack_incoming_handle(nua, irq, sip, 0)))
return 500; /* respond with 500 Internal Server Error */
int nua_message_server_params(nua_server_request_t *sr,
tagi_t const *tags)
{
if (NH_PGET(sr->sr_owner, win_messenger_enable))
sr->sr_add_contact = 1;
msg = nta_incoming_getrequest(irq);
nua_stack_event(nh->nh_nua, nh, msg, nua_i_message, SIP_200_OK, TAG_END());
#if 0 /* XXX */
if (nh->nh_nua->nua_messageRespond) {
nh->nh_irq = irq;
return 0;
}
#endif
return 200;
return 0;
}
File diff suppressed because it is too large. Load diff
@@ -45,9 +45,6 @@
#include <sofia-sip/sip_protos.h>
#include <sofia-sip/sip_status.h>
#define NTA_LEG_MAGIC_T struct nua_handle_s
#define NTA_OUTGOING_MAGIC_T struct nua_handle_s
#include "nua_stack.h"
/**@fn void nua_options(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
@@ -69,46 +66,6 @@
* @sa #nua_i_options, @RFC3261 section 10
*/
static int process_response_to_options(nua_handle_t *nh,
nta_outgoing_t *orq,
sip_t const *sip);
int
nua_stack_options(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags)
{
nua_client_request_t *cr = nh->nh_ds->ds_cr;
msg_t *msg;
if (nh_is_special(nh)) {
return UA_EVENT2(e, 900, "Invalid handle for OPTIONS");
}
else if (cr->cr_orq) {
return UA_EVENT2(e, 900, "Request already in progress");
}
nua_stack_init_handle(nua, nh, TAG_NEXT(tags));
msg = nua_creq_msg(nua, nh, cr, cr->cr_retry_count,
SIP_METHOD_OPTIONS,
TAG_NEXT(tags));
cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,
process_response_to_options, nh, NULL,
msg,
SIPTAG_END(), TAG_NEXT(tags));
if (!cr->cr_orq) {
msg_destroy(msg);
return UA_EVENT1(e, NUA_INTERNAL_ERROR);
}
return cr->cr_event = e;
}
void restart_options(nua_handle_t *nh, tagi_t *tags)
{
nua_creq_restart(nh, nh->nh_ds->ds_cr, process_response_to_options, tags);
}
/** @NUA_EVENT nua_r_options
*
* Answer to outgoing OPTIONS.
@@ -130,11 +87,25 @@ void restart_options(nua_handle_t *nh, tagi_t *tags)
* @END_NUA_EVENT
*/
static int process_response_to_options(nua_handle_t *nh,
nta_outgoing_t *orq,
sip_t const *sip)
{
if (nua_creq_check_restart(nh, nh->nh_ds->ds_cr, orq, sip, restart_options))
return 0;
return nua_stack_process_response(nh, nh->nh_ds->ds_cr, orq, sip, TAG_END());
static nua_client_methods_t const nua_options_client_methods = {
SIP_METHOD_OPTIONS,
0,
{
/* create_dialog */ 0,
/* in_dialog */ 0,
/* target refresh */ 0
},
/*nua_options_client_template*/ NULL,
/*nua_options_client_init*/ NULL,
/*nua_options_client_request*/ NULL,
/* nua_options_client_check_restart */ NULL,
/*nua_options_client_response*/ NULL
};
int nua_stack_options(nua_t *nua,
nua_handle_t *nh,
nua_event_t e,
tagi_t const *tags)
{
return nua_client_create(nh, e, &nua_options_client_methods, tags);
}
+28 -17
View File
@@ -149,9 +149,10 @@ int nua_stack_set_defaults(nua_handle_t *nh,
NHP_SET(nhp, auto_ack, 1);
NHP_SET(nhp, invite_timeout, 120);
NHP_SET(nhp, session_timer, 1800);
nhp->nhp_session_timer = 1800;
nhp->nhp_refresher = nua_no_refresher;
NHP_SET(nhp, min_se, 120);
NHP_SET(nhp, refresher, nua_no_refresher);
NHP_SET(nhp, update_refresh, 0);
NHP_SET(nhp, message_enable, 1);
@@ -393,6 +394,7 @@ int nua_stack_init_instance(nua_handle_t *nh, tagi_t const *tags)
* NUTAG_ALLOW(), SIPTAG_ALLOW(), and SIPTAG_ALLOW_STR() \n
* NUTAG_ALLOW_EVENTS(), SIPTAG_ALLOW_EVENTS(), and
* SIPTAG_ALLOW_EVENTS_STR() \n
* NUTAG_AUTH_CACHE() \n
* NUTAG_AUTOACK() \n
* NUTAG_AUTOALERT() \n
* NUTAG_AUTOANSWER() \n
@@ -762,12 +764,6 @@ static int nhp_set_tags(su_home_t *home,
else if (tag == nutag_enablemessenger) {
NHP_SET(nhp, win_messenger_enable, value != 0);
}
#if 0
/* NUTAG_AUTORESPOND(autorespond) */
else if (tag == nutag_autorespond) {
NHP_SET(nhp, autorespond, value);
}
#endif
/* NUTAG_CALLEE_CAPS(callee_caps) */
else if (tag == nutag_callee_caps) {
NHP_SET(nhp, callee_caps, value != 0);
@@ -784,6 +780,11 @@ static int nhp_set_tags(su_home_t *home,
else if (tag == nutag_path_enable) {
NHP_SET(nhp, path_enable, value != 0);
}
/* NUTAG_AUTH_CACHE(auth_cache) */
else if (tag == nutag_auth_cache) {
if (value >= 0 && value < (tag_value_t)_nua_auth_cache_invalid)
NHP_SET(nhp, auth_cache, (int)value);
}
/* NUTAG_REFER_EXPIRES(refer_expires) */
else if (tag == nutag_refer_expires) {
NHP_SET(nhp, refer_expires, value);
@@ -882,7 +883,8 @@ static int nhp_set_tags(su_home_t *home,
sip_allow_class,
&appl_method,
(msg_list_t const *)nhp->nhp_appl_method,
NHP_ISSET(nhp, allow), /* already set by tags */
/* already set by tags? */
NHP_ISSET(nhp, appl_method),
0, /* dup it, don't make */
1, /* merge with old value */
t->t_value);
@@ -1171,10 +1173,10 @@ int nua_handle_save_tags(nua_handle_t *nh, tagi_t *tags)
nh->nh_tags =
tl_filtered_tlist(nh->nh_home, tagfilter,
SIPTAG_FROM(p_from),
TAG_FILTER(nua_handle_tags_filter),
SIPTAG_TO(p_to),
TAG_FILTER(nua_handle_tags_filter),
TAG_IF(p_from != SIP_NONE, SIPTAG_FROM(p_from)),
TAG_IF(p_from != SIP_NONE, TAG_FILTER(nua_handle_tags_filter)),
TAG_IF(p_to != SIP_NONE, SIPTAG_TO(p_to)),
TAG_IF(p_to != SIP_NONE, TAG_FILTER(nua_handle_tags_filter)),
TAG_NEXT(tags));
nh->nh_ptags =
@@ -1366,7 +1368,9 @@ int nua_stack_set_smime_params(nua_t *nua, tagi_t const *tags)
* application contact associated with the operation handle
* when responding to nua_get_hparams()
* @param sip NULL
* @param tags
* @param tags
* NUTAG_APPL_METHOD() \n
* NUTAG_AUTH_CACHE() \n
* NUTAG_AUTOACK() \n
* NUTAG_AUTOALERT() \n
* NUTAG_AUTOANSWER() \n
@@ -1500,6 +1504,11 @@ int nua_stack_get_params(nua_t *nua, nua_handle_t *nh, nua_event_t e,
#define TIF(TAG, pref) \
TAG_IF(nhp->nhp_set.nhb_##pref, TAG(nhp->nhp_##pref))
/* Include tag in the list returned to user
* if it has been earlier set (by user) returning default parameters */
#define TIFD(TAG, pref) \
TAG_IF(nh == dnh || nhp->nhp_set.nhb_##pref, TAG(nhp->nhp_##pref))
/* Include string tag made out of SIP header
* if it has been earlier set (by user) */
#define TIF_STR(TAG, pref) \
@@ -1537,9 +1546,9 @@ int nua_stack_get_params(nua_t *nua, nua_handle_t *nh, nua_event_t e,
TIF(NUTAG_AUTOACK, auto_ack),
TIF(NUTAG_INVITE_TIMER, invite_timeout),
TIF(NUTAG_SESSION_TIMER, session_timer),
TIFD(NUTAG_SESSION_TIMER, session_timer),
TIF(NUTAG_MIN_SE, min_se),
TIF(NUTAG_SESSION_REFRESHER, refresher),
TIFD(NUTAG_SESSION_REFRESHER, refresher),
TIF(NUTAG_UPDATE_REFRESH, update_refresh),
TIF(NUTAG_ENABLEMESSAGE, message_enable),
@@ -1550,6 +1559,7 @@ int nua_stack_get_params(nua_t *nua, nua_handle_t *nh, nua_event_t e,
TIF(NUTAG_MEDIA_FEATURES, media_features),
TIF(NUTAG_SERVICE_ROUTE_ENABLE, service_route_enable),
TIF(NUTAG_PATH_ENABLE, path_enable),
TIF(NUTAG_AUTH_CACHE, auth_cache),
TIF(NUTAG_REFER_EXPIRES, refer_expires),
TIF(NUTAG_REFER_WITH_ID, refer_with_id),
@@ -1559,6 +1569,7 @@ int nua_stack_get_params(nua_t *nua, nua_handle_t *nh, nua_event_t e,
TIF_STR(SIPTAG_SUPPORTED_STR, supported),
TIF(SIPTAG_ALLOW, allow),
TIF_STR(SIPTAG_ALLOW_STR, allow),
TIF_STR(NUTAG_APPL_METHOD, appl_method),
TIF(SIPTAG_ALLOW_EVENTS, allow_events),
TIF_STR(SIPTAG_ALLOW_EVENTS_STR, allow_events),
TIF_SIP(SIPTAG_USER_AGENT, user_agent),
@@ -1607,7 +1618,7 @@ int nua_stack_get_params(nua_t *nua, nua_handle_t *nh, nua_event_t e,
TAG_NEXT(media_params));
nua_stack_event(nua, nh, NULL, nua_r_get_params, SIP_200_OK, TAG_NEXT(lst));
nua_stack_event(nua, nh, NULL, nua_r_get_params, SIP_200_OK, lst);
su_home_deinit(tmphome);
@@ -95,9 +95,11 @@ typedef struct nua_handle_preferences
unsigned nhp_service_route_enable:1;
/** Enable Path */
unsigned nhp_path_enable:1;
/** Authentication cache policy */
unsigned nhp_auth_cache:1;
/** Always include id with Event: refer */
unsigned nhp_refer_with_id:1;
unsigned:0;
/* Default lifetime for implicit subscriptions created by REFER */
@@ -157,6 +159,7 @@ typedef struct nua_handle_preferences
unsigned nhb_media_features:1;
unsigned nhb_service_route_enable:1;
unsigned nhb_path_enable:1;
unsigned nhb_auth_cache:1;
unsigned nhb_refer_with_id:1;
unsigned nhb_refer_expires:1;
unsigned nhb_substate:1;
@@ -166,8 +169,8 @@ typedef struct nua_handle_preferences
unsigned nhb_allow:1;
unsigned nhb_supported:1;
unsigned nhb_allow_events:1;
unsigned :0; /* at most 32 bits ... */
unsigned nhb_allow_events:1;
unsigned nhb_user_agent:1;
unsigned nhb_organization:1;
@@ -223,4 +226,9 @@ typedef struct nua_handle_preferences
(NHP_ISSET((nh)->nh_prefs, pref) && \
(nh)->nh_nua->nua_dhandle->nh_prefs != (nh)->nh_prefs)
/* Check if preference has been set by applicationx */
#define NUA_PISSET(nua, nh, pref) \
(NHP_ISSET((nua)->nua_dhandle->nh_prefs, pref) || \
((nh) && NHP_ISSET((nh)->nh_prefs, pref)))
#endif /* NUA_PARAMS_H */
+184 -207
View File
@@ -45,9 +45,6 @@
#include <sofia-sip/sip_protos.h>
#include <sofia-sip/sip_status.h>
#define NTA_LEG_MAGIC_T struct nua_handle_s
#define NTA_OUTGOING_MAGIC_T struct nua_handle_s
#include "nua_stack.h"
/* ====================================================================== */
@@ -55,6 +52,7 @@
struct publish_usage {
sip_etag_t *pu_etag;
int pu_published;
};
static char const *nua_publish_usage_name(nua_dialog_usage_t const *du);
@@ -116,14 +114,6 @@ void nua_publish_usage_remove(nua_handle_t *nh,
/* ======================================================================== */
/* PUBLISH */
static int nua_stack_publish2(nua_t *nua, nua_handle_t *nh, nua_event_t e,
int refresh, tagi_t const *tags);
static int process_response_to_publish(nua_handle_t *nh,
nta_outgoing_t *orq,
sip_t const *sip);
/**@fn \
* void nua_publish(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
*
@@ -237,213 +227,213 @@ void nua_unpublish(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
* @END_NUA_EVENT
*/
int nua_stack_publish(nua_t *nua, nua_handle_t *nh, nua_event_t e,
tagi_t const *tags)
static int nua_publish_client_template(nua_client_request_t *cr,
msg_t **return_msg,
tagi_t const *tags);
static int nua_publish_client_init(nua_client_request_t *cr,
msg_t *, sip_t *,
tagi_t const *tags);
static int nua_publish_client_request(nua_client_request_t *cr,
msg_t *, sip_t *,
tagi_t const *tags);
static int nua_publish_client_response(nua_client_request_t *cr,
int status, char const *phrase,
sip_t const *sip);
static nua_client_methods_t const nua_publish_client_methods = {
SIP_METHOD_PUBLISH,
0,
{
/* create_dialog */ 0,
/* in_dialog */ 0,
/* target refresh */ 0
},
nua_publish_client_template,
nua_publish_client_init,
nua_publish_client_request,
/* nua_publish_client_check_restart */ NULL,
nua_publish_client_response,
/* nua_publish_client_preliminary */ NULL
};
/**@internal Send PUBLISH. */
int nua_stack_publish(nua_t *nua,
nua_handle_t *nh,
nua_event_t e,
tagi_t const *tags)
{
return nua_stack_publish2(nua, nh, e, 0, tags);
return nua_client_create(nh, e, &nua_publish_client_methods, tags);
}
static
int nua_stack_publish2(nua_t *nua, nua_handle_t *nh, nua_event_t e,
int refresh,
tagi_t const *tags)
static int nua_publish_client_template(nua_client_request_t *cr,
msg_t **return_msg,
tagi_t const *tags)
{
nua_dialog_usage_t *du;
if (cr->cr_event == nua_r_publish)
return 0;
du = nua_dialog_usage_get(cr->cr_owner->nh_ds, nua_publish_usage, NULL);
if (du && du->du_cr) {
if (nua_client_set_target(cr, du->du_cr->cr_target) < 0)
return -1;
*return_msg = msg_copy(du->du_cr->cr_msg);
return 1;
}
return 0;
}
static int nua_publish_client_init(nua_client_request_t *cr,
msg_t *msg, sip_t *sip,
tagi_t const *tags)
{
nua_handle_t *nh = cr->cr_owner;
nua_dialog_usage_t *du;
struct publish_usage *pu;
nua_client_request_t *cr = nh->nh_ds->ds_cr;
msg_t *msg = NULL;
sip_t *sip;
int remove_body = 0;
if (nua_stack_set_handle_special(nh, nh_has_nothing, nua_r_publish) < 0)
return UA_EVENT2(e, 900, "Invalid handle for PUBLISH");
if (cr->cr_orq) {
return UA_EVENT2(e, 900, "Request already in progress");
}
nua_stack_init_handle(nua, nh, TAG_NEXT(tags));
if (e == nua_r_unpublish) {
du = nua_dialog_usage_get(nh->nh_ds, nua_publish_usage, NULL);
if (du)
refresh = 1;
else
du = nua_dialog_usage_add(nh, nh->nh_ds, nua_publish_usage, NULL);
}
else if (!refresh)
if (cr->cr_event == nua_r_publish) {
du = nua_dialog_usage_add(nh, nh->nh_ds, nua_publish_usage, NULL);
if (!du)
return -1;
pu = nua_dialog_usage_private(du);
pu->pu_published = 0;
if (sip->sip_if_match) {
pu->pu_etag = sip_etag_dup(nh->nh_home, sip->sip_if_match);
if (!pu->pu_etag)
return -1;
sip_header_remove(msg, sip, (sip_header_t *)sip->sip_if_match);
}
}
else
du = nua_dialog_usage_get(nh->nh_ds, nua_publish_usage, NULL);
if (!du)
return UA_EVENT1(e, NUA_INTERNAL_ERROR);
nua_dialog_usage_reset_refresh(du);
pu = nua_dialog_usage_private(du); assert(pu);
if (refresh) {
if (cr->cr_msg)
msg_destroy(cr->cr_msg);
cr->cr_msg = msg_copy(du->du_msg);
remove_body = pu->pu_etag != NULL;
}
msg = nua_creq_msg(nua, nh, cr, cr->cr_retry_count || refresh,
SIP_METHOD_PUBLISH,
NUTAG_ADD_CONTACT(0),
TAG_NEXT(tags));
sip = sip_object(msg);
if (!msg || !sip)
goto error;
du->du_terminating =
e != nua_r_publish ||
(sip->sip_expires && sip->sip_expires->ex_delta == 0);
if (!du->du_terminating && !refresh) {
/* Save template */
if (du->du_msg)
msg_destroy(du->du_msg);
du->du_msg = msg_ref_create(cr->cr_msg);
}
cr->cr_orq =
nta_outgoing_mcreate(nua->nua_nta,
process_response_to_publish, nh, NULL,
msg,
SIPTAG_IF_MATCH(pu->pu_etag),
TAG_IF(remove_body, SIPTAG_PAYLOAD(NONE)),
TAG_IF(remove_body, SIPTAG_CONTENT_TYPE(NONE)),
TAG_IF(e != nua_r_publish,
SIPTAG_EXPIRES_STR("0")),
SIPTAG_END(), TAG_NEXT(tags));
if (!cr->cr_orq)
goto error;
cr->cr_usage = du;
return cr->cr_event = e;
error:
msg_destroy(msg);
if (!du->du_ready == 0)
nua_dialog_usage_remove(nh, nh->nh_ds, du);
return UA_EVENT1(e, NUA_INTERNAL_ERROR);
return 0;
}
static void
restart_publish(nua_handle_t *nh, tagi_t *tags)
{
nua_creq_restart(nh, nh->nh_ds->ds_cr, process_response_to_publish, tags);
}
static
int process_response_to_publish(nua_handle_t *nh,
nta_outgoing_t *orq,
sip_t const *sip)
int nua_publish_client_request(nua_client_request_t *cr,
msg_t *msg, sip_t *sip,
tagi_t const *tags)
{
int status = sip->sip_status->st_status;
nua_client_request_t *cr = nh->nh_ds->ds_cr;
nua_dialog_usage_t *du = cr->cr_usage;
struct publish_usage *pu = nua_dialog_usage_private(du);
unsigned saved_retry_count = cr->cr_retry_count + 1;
int un, done;
sip_etag_t const *etag = NULL;
if (nua_creq_check_restart(nh, cr, orq, sip, restart_publish))
return 0;
un = cr->cr_terminating ||
cr->cr_event != nua_r_publish ||
(du && du->du_shutdown) ||
(sip->sip_expires && sip->sip_expires->ex_delta == 0);
cr->cr_terminating = un;
done = un;
if (status < 200 || pu == NULL)
return nua_stack_process_response(nh, cr, orq, sip, TAG_END());
if (du) {
struct publish_usage *pu = nua_dialog_usage_private(du);
if (pu->pu_etag)
su_free(nh->nh_home, pu->pu_etag), pu->pu_etag = NULL;
if (nua_client_bind(cr, du) < 0)
return -1;
if (pu->pu_published)
done = 1;
etag = pu->pu_etag;
}
if (!du->du_terminating) {
int retry = 0, invalid_expiration = 0;
return nua_base_client_trequest(cr, msg, sip,
SIPTAG_IF_MATCH(etag),
TAG_IF(done, SIPTAG_PAYLOAD(NONE)),
TAG_IF(done, SIPTAG_CONTENT_TYPE(NONE)),
TAG_IF(un, SIPTAG_EXPIRES_STR("0")),
TAG_NEXT(tags));
}
if (status < 300) {
if (!sip->sip_expires)
invalid_expiration = 1;
else if (sip->sip_expires->ex_delta == 0)
retry = 1, invalid_expiration = 1;
static int nua_publish_client_response(nua_client_request_t *cr,
int status, char const *phrase,
sip_t const *sip)
{
nua_handle_t *nh = cr->cr_owner;
nua_dialog_usage_t *du = cr->cr_usage;
if (!cr->cr_terminated && du && sip) {
struct publish_usage *pu = nua_dialog_usage_private(du);
sip_expires_t const *ex = sip->sip_expires;
/* Reset state */
pu->pu_published = 0;
if (pu->pu_etag)
su_free(nh->nh_home, pu->pu_etag), pu->pu_etag = NULL;
if (status == 412) {
if (nua_client_restart(cr, 100, phrase))
return 0;
}
else if (status == 412)
retry = 1;
else if (status < 300) {
if (ex && ex->ex_delta == 0 &&
nua_client_restart(cr, 100, "Trying re-PUBLISH"))
return 0;
if (status < 300 && !invalid_expiration && !retry) {
pu->pu_published = 1;
pu->pu_etag = sip_etag_dup(nh->nh_home, sip->sip_etag);
du->du_ready = 1;
nua_dialog_usage_set_expires(du, sip->sip_expires->ex_delta);
}
else if (retry && saved_retry_count < NH_PGET(nh, retry_count)) {
msg_t *response = nta_outgoing_getresponse(orq);
nua_stack_event(nh->nh_nua, nh, response, cr->cr_event,
100, "Trying re-PUBLISH",
TAG_END());
nua_creq_deinit(cr, orq);
nua_stack_publish2(nh->nh_nua, nh, cr->cr_event, 1, NULL);
cr->cr_retry_count = saved_retry_count;
return 0;
}
else if (invalid_expiration) {
msg_t *response = nta_outgoing_getresponse(orq);
nua_stack_event(nh->nh_nua, nh, response, cr->cr_event,
900, "Received Invalid Expiration Time",
TAG_END());
nua_dialog_usage_remove(nh, nh->nh_ds, cr->cr_usage);
nua_creq_deinit(cr, orq);
cr->cr_usage = NULL;
return 0;
if (!ex || ex->ex_delta == 0 || !pu->pu_etag) {
cr->cr_terminated = 1;
if (!ex || ex->ex_delta == 0)
SET_STATUS(900, "Received Invalid Expiration Time");
else
SET_STATUS1(NUA_INTERNAL_ERROR);
}
}
}
return nua_stack_process_response(nh, cr, orq, sip, TAG_END());
return nua_base_client_response(cr, status, phrase, sip, NULL);
}
static void nua_publish_usage_refresh(nua_handle_t *nh,
nua_dialog_state_t *ds,
nua_dialog_usage_t *du,
sip_time_t now)
nua_dialog_state_t *ds,
nua_dialog_usage_t *du,
sip_time_t now)
{
if (ds->ds_cr->cr_usage == du) /* Already publishing. */
return;
nua_stack_publish2(nh->nh_nua, nh, nua_r_publish, 1, NULL);
nua_client_request_t *cr = du->du_cr;
if (cr) {
if (nua_client_resend_request(cr, 0) >= 0)
return;
}
nua_stack_event(nh->nh_nua, nh, NULL,
nua_r_publish, NUA_INTERNAL_ERROR,
NULL);
nua_dialog_usage_remove(nh, ds, du);
}
/** @interal Shut down PUBLISH usage.
/** @interal Shut down PUBLISH usage.
*
* @retval >0 shutdown done
* @retval 0 shutdown in progress
* @retval <0 try again later
*/
static int nua_publish_usage_shutdown(nua_handle_t *nh,
nua_dialog_state_t *ds,
nua_dialog_usage_t *du)
nua_dialog_state_t *ds,
nua_dialog_usage_t *du)
{
nua_client_request_t *cr = ds->ds_cr;
nua_client_request_t *cr = du->du_cr;
if (!cr->cr_usage) {
/* Unpublish */
nua_stack_publish2(nh->nh_nua, nh, nua_r_destroy, 1, NULL);
return cr->cr_usage != du;
if (cr) {
if (nua_client_resend_request(cr, 1) >= 0)
return 0;
}
if (!du->du_ready && !cr->cr_orq)
return 1; /* had unauthenticated initial request */
return -1; /* Request in progress */
/* XXX - report to user */
nua_dialog_usage_remove(nh, ds, du);
return 200;
}
/* ---------------------------------------------------------------------- */
/* Server side */
static
int respond_to_publish(nua_server_request_t *sr, tagi_t const *tags);
/** @NUA_EVENT nua_i_publish
*
* Incoming PUBLISH request.
@@ -453,7 +443,7 @@ int respond_to_publish(nua_server_request_t *sr, tagi_t const *tags);
* events with nua_set_params() tag NUTAG_ALLOW_EVENTS().
*
* The nua_response() call responding to a PUBLISH request must have
* NUTAG_WITH() (or NUTAG_WITH_CURRENT()/NUTAG_WITH_SAVED()) tag. Note that
* NUTAG_WITH() (or NUTAG_WITH_THIS()/NUTAG_WITH_SAVED()) tag. Note that
* a successful response to PUBLISH @b MUST include @Expires and @SIPETag
* headers.
*
@@ -481,48 +471,35 @@ int respond_to_publish(nua_server_request_t *sr, tagi_t const *tags);
* @END_NUA_EVENT
*/
int nua_stack_process_publish(nua_t *nua,
nua_handle_t *nh,
nta_incoming_t *irq,
sip_t const *sip)
int nua_publish_server_init(nua_server_request_t *sr);
nua_server_methods_t const nua_publish_server_methods =
{
SIP_METHOD_PUBLISH,
nua_i_publish, /* Event */
{
0, /* Do not create dialog */
0, /* Initial request */
0, /* Not a target refresh request */
1, /* Add Contact */
},
nua_publish_server_init,
nua_base_server_preprocess,
nua_base_server_params,
nua_base_server_respond,
nua_base_server_report,
};
int nua_publish_server_init(nua_server_request_t *sr)
{
nua_server_request_t *sr, sr0[1];
sip_allow_events_t *allow_events = NUA_PGET(nua, nh, allow_events);
sip_event_t *o = sip->sip_event;
sip_allow_events_t *allow_events = NH_PGET(sr->sr_owner, allow_events);
sip_event_t *o = sr->sr_request.sip->sip_event;
char const *event = o ? o->o_type : NULL;
sr = SR_INIT(sr0);
if (!allow_events)
SR_STATUS1(sr, SIP_501_NOT_IMPLEMENTED);
return SR_STATUS1(sr, SIP_501_NOT_IMPLEMENTED);
else if (!event || !msg_header_find_param(allow_events->k_common, event))
SR_STATUS1(sr, SIP_489_BAD_EVENT);
return SR_STATUS1(sr, SIP_489_BAD_EVENT);
sr = nua_server_request(nua, nh, irq, sip, sr, sizeof *sr,
respond_to_publish, 0);
return nua_stack_server_event(nua, sr, nua_i_publish, TAG_END());
}
static
int respond_to_publish(nua_server_request_t *sr, tagi_t const *tags)
{
nua_handle_t *nh = sr->sr_owner;
nua_t *nua = nh->nh_nua;
msg_t *msg;
msg = nua_server_response(sr, sr->sr_status, sr->sr_phrase, TAG_NEXT(tags));
if (msg) {
nta_incoming_mreply(sr->sr_irq, msg);
}
else {
SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR);
nta_incoming_treply(sr->sr_irq, sr->sr_status, sr->sr_phrase, TAG_END());
nua_stack_event(nua, nh, NULL,
nua_i_error, 900, "PUBLISH Response Fails",
TAG_END());
}
return sr->sr_status >= 200 ? sr->sr_status : 0;
return 0;
}
File diff suppressed because it is too large. Load diff
@@ -44,8 +44,6 @@
#include <sofia-sip/sip_status.h>
#include <sofia-sip/sip_util.h>
#define NTA_LEG_MAGIC_T struct nua_handle_s
#define NTA_OUTGOING_MAGIC_T struct nua_handle_s
#define NTA_INCOMING_MAGIC_T struct nua_handle_s
#define NTA_RELIABLE_MAGIC_T struct nua_handle_s
@@ -62,7 +60,7 @@
* the REGISTER method with NUTAG_ALLOW() tag.
*
* The nua_response() call responding to a REGISTER request must have
* NUTAG_WITH() (or NUTAG_WITH_CURRENT()/NUTAG_WITH_SAVED()) tag. Note that
* NUTAG_WITH() (or NUTAG_WITH_THIS()/NUTAG_WITH_SAVED()) tag. Note that
* a successful response to REGISTER @b MUST include the @Contact header
* bound to the the AoR URI (in @To header).
*
@@ -89,15 +87,19 @@
* @END_NUA_EVENT
*/
int nua_stack_process_register(nua_t *nua,
nua_handle_t *nh,
nta_incoming_t *irq,
sip_t const *sip)
{
nua_server_request_t *sr, sr0[1];
sr = nua_server_request(nua, nh, irq, sip, SR_INIT(sr0), sizeof *sr,
nua_default_respond, 0);
return nua_stack_server_event(nua, sr, nua_i_register, TAG_END());
}
nua_server_methods_t const nua_register_server_methods =
{
SIP_METHOD_REGISTER,
nua_i_register, /* Event */
{
0, /* Do not create dialog */
0, /* Initial request */
0, /* Not a target refresh request */
0, /* Do not add Contact */
},
nua_base_server_init,
nua_base_server_preprocess,
nua_base_server_params,
nua_base_server_respond,
nua_base_server_report,
};
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+39 -104
View File
@@ -103,6 +103,32 @@ typedef struct register_usage nua_registration_t;
TAG_IF((include) && (soa) && soa_is_remote_chat_active(soa) >= 0, \
SOATAG_ACTIVE_CHAT(soa_is_remote_chat_active(soa)))
#if HAVE_NUA_HANDLE_DEBUG
#define nua_handle_ref(nh) nua_handle_ref_by((nh), __func__)
#define nua_handle_unref(nh) nua_handle_unref_by((nh), __func__)
static inline nua_handle_t *nua_handle_ref_by(nua_handle_t *nh,
char const *by)
{
if (nh)
SU_DEBUG_0(("nua_handle_ref(%p) => "MOD_ZU" by %s\n", nh,
su_home_refcount((su_home_t *)nh) + 1,
by));
return (nua_handle_t *)su_home_ref((su_home_t *)nh);
}
static inline int nua_handle_unref_by(nua_handle_t *nh, char const *by)
{
if (nh)
SU_DEBUG_0(("nua_handle_unref(%p) => "MOD_ZU" by %s\n", nh,
su_home_refcount((su_home_t *)nh) - 1,
by));
return su_home_unref((su_home_t *)nh);
}
#endif
/** NUA handle.
*
*/
@@ -113,7 +139,8 @@ struct nua_handle_s
nua_handle_t **nh_prev;
nua_t *nh_nua; /**< Pointer to NUA object */
void *nh_valid;
void *nh_valid; /**< Cookie */
#define nua_valid_handle_cookie ((void *)(intptr_t)nua_handle)
nua_hmagic_t *nh_magic; /**< Application context */
tagi_t *nh_tags; /**< Initial tags */
@@ -154,7 +181,8 @@ struct nua_handle_s
nea_server_t *nh_notifier; /**< SIP notifier */
};
#define NH_IS_VALID(nh) ((nh) && (nh)->nh_valid)
#define NH_IS_VALID(nh) \
((nh) && (nh)->nh_valid == nua_valid_handle_cookie)
#define NH_STATUS(nh) \
(nh)->nh_status, \
@@ -285,28 +313,29 @@ nua_stack_signal_handler
nua_stack_method;
#define UA_EVENT1(e, statusphrase) \
nua_stack_event(nua, nh, NULL, e, statusphrase, TAG_END())
nua_stack_event(nua, nh, NULL, e, statusphrase, NULL)
#define UA_EVENT2(e, status, phrase) \
nua_stack_event(nua, nh, NULL, e, status, phrase, TAG_END())
nua_stack_event(nua, nh, NULL, e, status, phrase, NULL)
#define UA_EVENT3(e, status, phrase, tag) \
nua_stack_event(nua, nh, NULL, e, status, phrase, tag, TAG_END())
nua_stack_event(nua, nh, NULL, e, status, phrase, tag, NULL)
int nua_stack_tevent(nua_t *nua, nua_handle_t *nh, msg_t *msg,
nua_event_t event, int status, char const *phrase,
tag_type_t tag, tag_value_t value, ...);
int nua_stack_event(nua_t *nua, nua_handle_t *nh, msg_t *msg,
nua_event_t event, int status, char const *phrase,
tag_type_t tag, tag_value_t value, ...);
tagi_t const *tags);
nua_handle_t *nh_create_handle(nua_t *nua, nua_hmagic_t *hmagic,
tagi_t *tags);
nua_handle_t *nh_create_handle(nua_t *nua, nua_hmagic_t *hmagic, tagi_t *tags);
nua_handle_t *nua_stack_incoming_handle(nua_t *nua,
nta_incoming_t *irq,
sip_t const *sip,
int create_dialog);
enum { create_dialog = 1 };
int nua_stack_init_handle(nua_t *nua, nua_handle_t *nh,
tag_type_t tag, tag_value_t value, ...);
@@ -349,48 +378,8 @@ int nua_stack_process_request(nua_handle_t *nh,
nta_incoming_t *irq,
sip_t const *sip);
int nua_stack_process_response(nua_handle_t *nh,
nua_client_request_t *cr,
nta_outgoing_t *orq,
sip_t const *sip,
tag_type_t tag, tag_value_t value, ...);
int nua_stack_launch_network_change_detector(nua_t *nua);
msg_t *nua_creq_msg(nua_t *nua, nua_handle_t *nh,
nua_client_request_t *cr,
int restart,
sip_method_t method, char const *name,
tag_type_t tag, tag_value_t value, ...);
int nua_tagis_have_contact_tag(tagi_t const *t);
int nua_creq_check_restart(nua_handle_t *nh,
nua_client_request_t *cr,
nta_outgoing_t *orq,
sip_t const *sip,
nua_creq_restart_f *f);
int nua_creq_restart_with(nua_handle_t *nh,
nua_client_request_t *cr,
nta_outgoing_t *orq,
int status, char const *phrase,
nua_creq_restart_f *f,
tag_type_t tag, tag_value_t value, ...);
int nua_creq_save_restart(nua_handle_t *nh,
nua_client_request_t *cr,
nta_outgoing_t *orq,
int status, char const *phrase,
nua_creq_restart_f *f);
int nua_creq_restart(nua_handle_t *nh,
nua_client_request_t *cr,
nta_response_f *cb,
tagi_t *tags);
void nua_creq_deinit(nua_client_request_t *cr, nta_outgoing_t *orq);
sip_contact_t const *nua_stack_get_contact(nua_registration_t const *nr);
int nua_registration_add_contact_to_request(nua_handle_t *nh,
@@ -405,51 +394,6 @@ int nua_registration_add_contact_to_response(nua_handle_t *nh,
sip_record_route_t const *,
sip_contact_t const *remote);
msg_t *nh_make_response(nua_t *nua, nua_handle_t *nh,
nta_incoming_t *irq,
int status, char const *phrase,
tag_type_t tag, tag_value_t value, ...);
typedef int nua_stack_process_request_t(nua_t *nua,
nua_handle_t *nh,
nta_incoming_t *irq,
sip_t const *sip);
nua_stack_process_request_t nua_stack_process_invite;
nua_stack_process_request_t nua_stack_process_info;
nua_stack_process_request_t nua_stack_process_update;
nua_stack_process_request_t nua_stack_process_bye;
nua_stack_process_request_t nua_stack_process_message;
nua_stack_process_request_t nua_stack_process_options;
nua_stack_process_request_t nua_stack_process_publish;
nua_stack_process_request_t nua_stack_process_subscribe;
nua_stack_process_request_t nua_stack_process_notify;
nua_stack_process_request_t nua_stack_process_refer;
nua_stack_process_request_t nua_stack_process_unknown;
nua_stack_process_request_t nua_stack_process_register;
nua_stack_process_request_t nua_stack_process_method;
nua_client_request_t
*nua_client_request_pending(nua_client_request_t const *),
*nua_client_request_restarting(nua_client_request_t const *),
*nua_client_request_by_orq(nua_client_request_t const *cr,
nta_outgoing_t const *orq);
nua_server_request_t *nua_server_request(nua_t *nua,
nua_handle_t *nh,
nta_incoming_t *irq,
sip_t const *sip,
nua_server_request_t *sr,
size_t size,
nua_server_respond_f *respond,
int create_dialog);
int nua_stack_server_event(nua_t *nua,
nua_server_request_t *sr,
nua_event_t event,
tag_type_t tag, tag_value_t value, ...);
/* ---------------------------------------------------------------------- */
#ifndef SDP_MIME_TYPE
@@ -466,15 +410,6 @@ extern char const nua_application_sdp[];
#define NUTAG_ADD_CONTACT(v) _nutag_add_contact, tag_bool_v(v)
extern tag_typedef_t _nutag_add_contact;
#define NUTAG_ADD_CONTACT_REF(v) _nutag_add_contact_ref, tag_bool_vr(&v)
extern tag_typedef_t _nutag_add_contact_ref;
#define NUTAG_COPY(v) _nutag_copy, tag_bool_v(v)
extern tag_typedef_t _nutag_copy;
#define NUTAG_COPY_REF(v) _nutag_copy_ref, tag_bool_vr(&v)
extern tag_typedef_t _nutag_copy_ref;
/* ---------------------------------------------------------------------- */
typedef unsigned longlong ull;
File diff suppressed because it is too large. Load diff
+3 -3
View File
@@ -68,6 +68,7 @@ tag_typedef_t nutag_answer_recv = BOOLTAG_TYPEDEF(answer_recv);
tag_typedef_t nutag_offer_sent = BOOLTAG_TYPEDEF(offer_sent);
tag_typedef_t nutag_answer_sent = BOOLTAG_TYPEDEF(answer_sent);
tag_typedef_t nutag_substate = INTTAG_TYPEDEF(substate);
tag_typedef_t nutag_newsub = BOOLTAG_TYPEDEF(newsub);
tag_typedef_t nutag_invite_timer = UINTTAG_TYPEDEF(invite_timer);
tag_typedef_t nutag_session_timer = UINTTAG_TYPEDEF(session_timer);
tag_typedef_t nutag_min_se = UINTTAG_TYPEDEF(min_se);
@@ -143,10 +144,9 @@ tag_typedef_t nutag_supported = STRTAG_TYPEDEF(supported);
tag_typedef_t nutag_path_enable = BOOLTAG_TYPEDEF(path_enable);
tag_typedef_t nutag_service_route_enable =
BOOLTAG_TYPEDEF(service_route_enable);
tag_typedef_t nutag_auth_cache = INTTAG_TYPEDEF(auth_cache);
tag_typedef_t nutag_detect_network_updates = UINTTAG_TYPEDEF(detect_network_updates);
tag_typedef_t nutag_with = PTRTAG_TYPEDEF(with);
tag_typedef_t _nutag_add_contact = BOOLTAG_TYPEDEF(add_contact);
tag_typedef_t _nutag_copy = BOOLTAG_TYPEDEF(copy);
tag_typedef_t nutag_dialog = UINTTAG_TYPEDEF(dialog);
+84 -118
View File
@@ -117,7 +117,6 @@ struct outbound {
char const *ob_instance; /**< Our instance ID */
int32_t ob_reg_id; /**< Flow-id */
char const *ob_features; /**< Feature parameters for rcontact */
sip_contact_t *ob_rcontact; /**< Our contact */
sip_contact_t *ob_dcontact; /**< Contact for dialogs */
sip_contact_t *ob_previous; /**< Stale contact */
@@ -294,7 +293,8 @@ int outbound_set_options(outbound_t *ob,
else if (MATCH(use-upnp) || MATCH(use_upnp)) prefs->use_upnp = value;
else if (MATCH(use-stun) || MATCH(use_stun)) prefs->use_stun = value;
else
SU_DEBUG_1(("outbound_t: unknown option \"%.*s\"\n", (int)len, s));
SU_DEBUG_1(("outbound(%p): unknown option \"%.*s\"\n",
(void *)ob->ob_owner, (int)len, s));
s += len;
len = strspn(s, " \t\n\r,;");
@@ -304,7 +304,8 @@ int outbound_set_options(outbound_t *ob,
}
if (s && s[0]) {
SU_DEBUG_1(("outbound_t: invalid options \"%s\"\n", options));
SU_DEBUG_1(("outbound(%p): invalid options \"%s\"\n",
(void *)ob->ob_owner, options));
return -1;
}
@@ -315,7 +316,8 @@ int outbound_set_options(outbound_t *ob,
prefs->use_socks ||
prefs->use_upnp ||
prefs->use_stun)) {
SU_DEBUG_1(("outbound(%p): no nat traversal method given\n", ob->ob_owner));
SU_DEBUG_1(("outbound(%p): no nat traversal method given\n",
(void *)ob->ob_owner));
}
ob->ob_prefs = *prefs;
@@ -324,60 +326,27 @@ int outbound_set_options(outbound_t *ob,
return 0;
}
/** Set the feature string (added to the Contact header when registering). */
int outbound_set_features(outbound_t *ob, char *features)
/* ---------------------------------------------------------------------- */
/** Obtain contacts for REGISTER */
int outbound_get_contacts(outbound_t *ob,
sip_contact_t **return_current_contact,
sip_contact_t **return_previous_contact)
{
char *old_features = (char *)ob->ob_features;
char *new_features = su_strdup(ob->ob_home, features);
if (features && !new_features)
return -1;
ob->ob_features = new_features;
su_free(ob->ob_home, old_features);
if (ob) {
if (ob->ob_contacts)
*return_current_contact = ob->ob_rcontact;
*return_previous_contact = ob->ob_previous;
}
return 0;
}
/* ---------------------------------------------------------------------- */
/** Hook for sending register request with extra outbound-ish headers. */
nta_outgoing_t *outbound_register_request(outbound_t *ob, int terminating,
sip_contact_t *stack_contact,
nta_agent_t *nta,
nta_response_f *callback,
nta_outgoing_magic_t *magic,
url_string_t *next_hop,
msg_t *msg,
tag_type_t tag, tag_value_t value,
...)
/** REGISTER request has been sent */
int outbound_start_registering(outbound_t *ob)
{
sip_contact_t *previous_contact = NULL;
ta_list ta;
nta_outgoing_t *orq;
if (stack_contact) {
if (ob) {
if (ob->ob_contacts)
stack_contact = ob->ob_rcontact;
previous_contact = ob->ob_previous;
}
}
ta_start(ta, tag, value);
orq = nta_outgoing_mcreate(nta, callback, magic, next_hop, msg,
TAG_IF(previous_contact,
SIPTAG_CONTACT(previous_contact)),
TAG_IF(stack_contact,
SIPTAG_CONTACT(stack_contact)),
ta_tags(ta));
ta_end(ta);
if (orq && ob)
if (ob)
ob->ob_registering = 1;
return orq;
return 0;
}
/** Process response to REGISTER request */
@@ -391,17 +360,16 @@ int outbound_register_response(outbound_t *ob,
if (!ob)
return 0;
assert(!request || request->sip_request);
assert(!response || response->sip_status);
if (!response || !request)
return 0;
if (terminating) {
ob->ob_registered = ob->ob_registering = 0;
ob->ob_registering = ob->ob_registered = 0;
return 0; /* Cleanup is done separately */
}
if (!response || !request)
return 0;
assert(request->sip_request); assert(response->sip_status);
reregister = outbound_check_for_nat(ob, request, response);
if (reregister)
return reregister;
@@ -423,7 +391,13 @@ int outbound_register_response(outbound_t *ob,
}
/** @internal Check if there is a NAT between us and registrar */
/** @internal Check if there is a NAT between us and registrar.
*
* @retval -1 upon an error
* @retval #ob_register_ok (0) if the registration was OK
* @retval #ob_reregister (1) if client needs to re-register
* @retval #ob_reregister_now (2) if client needs to re-register immediately
*/
static
int outbound_check_for_nat(outbound_t *ob,
sip_t const *request,
@@ -457,18 +431,18 @@ int outbound_check_for_nat(outbound_t *ob,
if (!m || binding_changed >= ob_nat_changed) {
if (ob->ob_stun) {
/* Use STUN? */
return 1;
return ob_reregister;
}
else if (ob->ob_upnp) {
/* Use UPnP */
return 1;
return ob_reregister;
}
else {
if (outbound_contacts_from_via(ob, response->sip_via) < 0)
return -1;
}
return 2;
return ob_reregister_now;
}
return 0;
@@ -512,7 +486,7 @@ int outbound_nat_detect(outbound_t *ob,
if (!host_is_ip_address(received)) {
if (received[0])
SU_DEBUG_3(("outbound(%p): Via with invalid received=%s\n",
ob->ob_owner, received));
(void *)ob->ob_owner, received));
return 0;
}
@@ -530,14 +504,14 @@ int outbound_nat_detect(outbound_t *ob,
if (!nat_detected) {
SU_DEBUG_1(("outbound(%p): detected NAT: %s != %s\n",
ob->ob_owner, v->v_host, received));
(void *)ob->ob_owner, v->v_host, received));
if (ob->ob_oo && ob->ob_oo->oo_status)
ob->ob_oo->oo_status(ob->ob_owner, ob, 101, "NAT detected", TAG_END());
}
else {
SU_DEBUG_1(("outbound(%p): NAT binding changed: "
"[%s]:%s != [%s]:%s\n",
ob->ob_owner, nat_detected, nat_port, received, rport));
(void *)ob->ob_owner, nat_detected, nat_port, received, rport));
if (ob->ob_oo && ob->ob_oo->oo_status)
ob->ob_oo->oo_status(ob->ob_owner, ob, 102, "NAT binding changed", TAG_END());
}
@@ -709,21 +683,32 @@ static int create_keepalive_message(outbound_t *ob, sip_t const *regsip)
{
msg_t *msg = nta_msg_create(ob->ob_nta, MSG_FLG_COMPACT), *previous;
sip_t *osip = sip_object(msg);
sip_accept_contact_t *ac;
char const *p1 = ob->ob_instance;
char const *p2 = ob->ob_features;
sip_contact_t *m = ob->ob_rcontact;
unsigned d = ob->ob_keepalive.interval;
assert(regsip); assert(regsip->sip_request);
if (p1 || p2) {
ac = sip_accept_contact_format(msg_home(msg), "*;require;explicit;%s%s%s",
p1 ? p1 : "",
p2 && p2 ? ";" : "",
p2 ? p2 : "");
msg_header_insert(msg, NULL, (void *)ac);
if (m && m->m_params) {
sip_accept_contact_t *ac;
size_t i;
int features = 0;
ac = sip_accept_contact_make(msg_home(msg), "*;require;explicit");
for (i = 0; m->m_params[i]; i++) {
char const *s = m->m_params[i];
if (!sip_is_callerpref(s))
continue;
features++;
s = su_strdup(msg_home(msg), s);
msg_header_add_param(msg_home(msg), ac->cp_common, s);
}
if (features)
msg_header_insert(msg, NULL, (void *)ac);
else
msg_header_free(msg_home(msg), (void *)ac);
}
if (0 >
@@ -877,18 +862,19 @@ static int response_to_keepalive_options(outbound_t *ob,
if (loglevel >= SU_LOG->log_level) {
su_llog(SU_LOG, loglevel,
"outbound(%p): %s <" URL_PRINT_FORMAT ">\n",
ob->ob_owner, failed ? "FAILED to validate" : "validated",
(void *)ob->ob_owner,
failed ? "FAILED to validate" : "validated",
URL_PRINT_ARGS(ob->ob_rcontact->m_url));
if (failed)
su_llog(SU_LOG, loglevel, "outbound(%p): FAILED with %u %s\n",
ob->ob_owner, status, phrase);
(void *)ob->ob_owner, status, phrase);
}
if (failed)
ob->ob_oo->oo_probe_error(ob->ob_owner, ob, status, phrase, TAG_END());
}
else if (status == 408) {
SU_DEBUG_1(("outbound(%p): keepalive timeout\n", ob->ob_owner));
SU_DEBUG_1(("outbound(%p): keepalive timeout\n", (void *)ob->ob_owner));
ob->ob_oo->oo_keepalive_error(ob->ob_owner, ob, status, phrase, TAG_END());
return 0;
}
@@ -982,7 +968,7 @@ int outbound_process_request(outbound_t *ob,
if (ob->ob_keepalive.validating) {
SU_DEBUG_1(("outbound(%p): registration check OPTIONS received\n",
ob->ob_owner));
(void *)ob->ob_owner));
ob->ob_keepalive.validated = 1;
}
@@ -1018,48 +1004,16 @@ int outbound_contacts_from_via(outbound_t *ob, sip_via_t const *via)
v = v0; *v0 = *via; v0->v_next = NULL;
dcontact = ob->ob_oo->oo_contact(ob->ob_owner, home,
dcontact = ob->ob_oo->oo_contact(ob->ob_owner, home, 1,
NULL, v, v->v_protocol, NULL);
if (ob->ob_instance && ob->ob_reg_id != 0)
snprintf(reg_id_param, sizeof reg_id_param, ";reg-id=%u", ob->ob_reg_id);
rcontact = ob->ob_oo->oo_contact(ob->ob_owner, home,
rcontact = ob->ob_oo->oo_contact(ob->ob_owner, home, 0,
NULL, v, v->v_protocol,
ob->ob_features ? ob->ob_features : "",
ob->ob_instance, reg_id_param, NULL);
#if 0
char *uri;
/* uri contains < > */
uri = sip_contact_string_from_via(NULL, via, NULL, v->v_protocol);
dcontact = sip_contact_make(home, uri);
if (ob->ob_instance) {
char reg_id[20];
if (ob->ob_instance && ob->ob_reg_id)
snprintf(reg_id, sizeof reg_id, ";reg-id=%u", ob->ob_reg_id);
else
strcpy(reg_id, "");
rcontact = sip_contact_format(home, "%s;%s%s%s%s",
uri, ob->ob_instance, reg_id,
ob->ob_features ? ";" : "",
ob->ob_features ? ob->ob_features : "");
}
else if (ob->ob_features)
rcontact = sip_contact_format(home, "%s;%s", uri, ob->ob_features);
else
rcontact = dcontact;
free(uri);
#endif
v = sip_via_dup(home, v);
if (!rcontact || !dcontact || !v) {
@@ -1137,6 +1091,9 @@ int outbound_set_contact(outbound_t *ob,
m3 = ob->ob_previous;
if (terminating) {
if (ob->ob_by_stack && application_contact == NULL)
return 0;
if (ob->ob_contacts)
previous = ob->ob_rcontact;
}
@@ -1147,11 +1104,14 @@ int outbound_set_contact(outbound_t *ob,
previous = ob->ob_contacts ? ob->ob_rcontact : NULL;
}
}
else if (ob->ob_by_stack) {
return 0; /* Xyzzy - nothing happens */
}
else if (v) {
char const *tport = !v->v_next ? v->v_protocol : NULL;
char reg_id_param[20];
dcontact = ob->ob_oo->oo_contact(ob->ob_owner, home,
dcontact = ob->ob_oo->oo_contact(ob->ob_owner, home, 1,
NULL, v, tport, NULL);
if (!dcontact)
return -1;
@@ -1159,9 +1119,8 @@ int outbound_set_contact(outbound_t *ob,
if (ob->ob_instance && ob->ob_reg_id != 0)
snprintf(reg_id_param, sizeof reg_id_param, ";reg-id=%u", ob->ob_reg_id);
rcontact = ob->ob_oo->oo_contact(ob->ob_owner, home,
rcontact = ob->ob_oo->oo_contact(ob->ob_owner, home, 0,
NULL, v, v->v_protocol,
ob->ob_features ? ob->ob_features : "",
ob->ob_instance, reg_id_param, NULL);
if (!rcontact)
return -1;
@@ -1172,9 +1131,11 @@ int outbound_set_contact(outbound_t *ob,
previous = ob->ob_contacts ? ob->ob_rcontact : NULL;
}
}
ob->ob_by_stack = application_contact == NULL;
ob->ob_contacts = rcontact != NULL;
ob->ob_rcontact = rcontact;
ob->ob_dcontact = dcontact;
ob->ob_previous = previous;
@@ -1205,6 +1166,11 @@ sip_contact_t const *outbound_dialog_contact(outbound_t const *ob)
return ob->ob_dcontact;
}
sip_contact_t const *outbound_dialog_gruu(outbound_t const *ob)
{
return ob ? ob->ob_gruu : NULL;
}
/* ---------------------------------------------------------------------- */
+7 -10
View File
@@ -70,17 +70,11 @@ int outbound_set_options(outbound_t *ob,
unsigned dgram_interval,
unsigned stream_interval);
int outbound_set_features(outbound_t *ob, char *features);
int outbound_get_contacts(outbound_t *ob,
sip_contact_t **return_current_contact,
sip_contact_t **return_previous_contact);
nta_outgoing_t *outbound_register_request(outbound_t *ob, int terminating,
sip_contact_t *stack_contact,
nta_agent_t *nta,
nta_response_f *callback,
nta_outgoing_magic_t *magic,
url_string_t *next_hop,
msg_t *msg,
tag_type_t tag, tag_value_t value,
...);
int outbound_start_registering(outbound_t *ob);
int outbound_register_response(outbound_t *ob,
int terminating,
@@ -102,6 +96,8 @@ int outbound_set_contact(outbound_t *ob,
sip_contact_t const *outbound_dialog_contact(outbound_t const *ob);
sip_contact_t const *outbound_dialog_gruu(outbound_t const *ob);
int outbound_gruuize(outbound_t *ob, sip_t const *sip);
void outbound_start_keepalive(outbound_t *ob,
@@ -122,6 +118,7 @@ struct outbound_owner_vtable
int oo_size;
sip_contact_t *(*oo_contact)(outbound_owner_t *,
su_home_t *home,
int used_in_dialog,
char const *extra_username,
sip_via_t const *v,
char const *transport,
@@ -262,6 +262,12 @@ SOFIAPUBFUN char const *nua_event_name(nua_event_t event);
/** Get name for NUA callstate. */
SOFIAPUBFUN char const *nua_callstate_name(enum nua_callstate state);
/** Return name of subscription state. @NEW_1_12_5. */
SOFIAPUBFUN char const *nua_substate_name(enum nua_substate substate);
/** Convert string to enum nua_substate. @NEW_1_12_5. */
SOFIAPUBFUN enum nua_substate nua_substate_make(char const *sip_substate);
/** Send SIP REGISTER request to the registrar. */
SOFIAPUBFUN void nua_register(nua_handle_t *nh, tag_type_t, tag_value_t, ...);
@@ -340,6 +346,9 @@ SOFIAPUBFUN void nua_respond(nua_handle_t *nh,
tag_type_t, tag_value_t,
...);
/** Check if event can be responded with nua_respond() */
SOFIAPUBFUN int nua_event_is_incoming_request(nua_event_t e);
#define nua_handle_home(nh) ((su_home_t *)(nh))
/** Generate an instance identifier */
@@ -157,6 +157,9 @@ SOFIAPUBVAR tag_typedef_t nutag_with;
*/
#define NUTAG_WITH_THIS(nua) nutag_with, tag_ptr_v(nua_current_request((nua)))
#define NUTAG_WITH_CURRENT(nua) \
nutag_with, tag_ptr_v(nua_current_request((nua)))
/**Specify request to respond to.
*
* @par Used with
@@ -174,6 +177,26 @@ SOFIAPUBVAR tag_typedef_t nutag_with;
*/
#define NUTAG_WITH_SAVED(e) nutag_with, tag_ptr_v(nua_saved_event_request((e)))
/**An (extension) method is used to create dialog or refresh target.
*
* @par Used with
* nua_method()
*
* @par Parameter type
* unsigned int (0, 1, 2)
*
* @par Values
* - 0 if dialog target is not refreshed
* - 1 if dialog target is refreshed
* - > 1 if dialog is to be created
*
* @NEW_1_12_6.
*
* @sa nua_method(), #nua_i_method
*/
#define NUTAG_DIALOG(b) nutag_dialog, tag_uint_v((b))
SOFIAPUBVAR tag_typedef_t nutag_dialog;
/**Set request retry count.
*
* Retry count determines how many times stack will automatically retry
@@ -451,8 +474,8 @@ SOFIAPUBVAR tag_typedef_t nutag_include_extra_sdp_ref;
*
* @par Used with
* nua_invite() \n
* nua_set_params() \n
* nua_get_params()
* nua_set_params(), nua_set_hparams(),
* nua_get_params(), nua_get_hparams()
*
* @par Parameter type
* int (enum nua_af)
@@ -471,40 +494,48 @@ SOFIAPUBVAR tag_typedef_t nutag_invite_timer_ref;
/**Default session timer in seconds.
*
* Set default session timer in seconds when using session timer extension.
* The value given here is the proposed session expiration time in seconds.
* Note that the session timer extension is ponly used
* Set default value for session timer in seconds when the session timer
* extension is used. The tag value is the proposed session expiration time
* in seconds, the session is refreshed twice during the expiration time.
*
* @par Sending INVITE and UPDATE Requests
*
* If NUTAG_SESSION_TIMER() is used with non-zero value, the value is
* used in the @SessionExpires header included in the INVITE or UPDATE
* requests. The intermediate proxies or the ultimate destination can lower
* the interval in @SessionExpires header. If the value is too low, they can
* If NUTAG_SESSION_TIMER() is used with non-zero value, the value is used
* in the @SessionExpires header included in the INVITE or UPDATE requests.
* The intermediate proxies or the ultimate destination can lower the
* interval in @SessionExpires header. If the value is too low, they can
* reject the request with the status code <i>422 Session Timer Too
* Small</i>. When Re-INVITE will be sent in given intervals. In that case,
* @b nua retries the request automatically.
*
* @par Returning Response to the INVITE and UPDATE Requests
* Small</i>. In that case, @b nua increases the value of @SessionExpires
* header and retries the request automatically.
*
* @par Returning a Response to the INVITE and UPDATE Requests
*
* The NUTAG_SESSION_TIMER() value is also used when sending the final
* response to the INVITE or UPDATE requests. If the NUTAG_SESSION_TIMER()
* value is 0 or the value in the @SessionExpires header of the requeast is
* value is 0 or the value in the @SessionExpires header of the request is
* lower than the value in NUTAG_SESSION_TIMER(), the value from the
* incoming @SessionExpires header is used. However, if the value in
* @SessionExpires is lower than the minimal acceptable session expiration
* interval specified with the tag NUTAG_MIN_SE() the request is
* automatically rejected with <i>422 Session Timer Too Small</i>.
*
* @par Refreshes
*
* After the initial INVITE request, the SIP session is refreshed at the
* intervals indicated by the @SessionExpires header returned in the 2XX
* response. The party indicated with the "refresher" parameter of the
* @SessionExpires header sends a re-INVITE requests (or an UPDATE
* request if NUTAG_UPDATE_REFRESH(1) parameter tag has been set).
*
* @par When to Use NUTAG_SESSION_TIMER()?
*
* The session time extension is enabled ("timer" feature tag is included in
* @Supported header) but not activated by default (no @SessionExpires
* header is included in the requests or responses by default). Using
* non-zero value with NUTAG_SESSION_TIMER() activates it. When the
* extension is activated, @nua refreshes the call state by sending periodic
* re-INVITE or UPDATE requests unless the remote end indicated that it will
* take care of refreshes.
* non-zero value with NUTAG_SESSION_TIMER() or NUTAG_SESSION_REFRESHER()
* activates it. When the extension is activated, @nua refreshes the call
* state by sending periodic re-INVITE or UPDATE requests unless the remote
* end indicated that it will take care of refreshes.
*
* The session timer extension is mainly useful for proxies or back-to-back
* user agents that keep call state. The call state is "soft" meaning that
@@ -512,6 +543,10 @@ SOFIAPUBVAR tag_typedef_t nutag_invite_timer_ref;
* will be destroyed. An ordinary user-agent can also make use of session
* timer if it cannot get any activity feedback from RTP or other media.
*
* @note The session timer extension is used only if the feature
* tag "timer" is listed in the @Supported header, set by NUTAG_SUPPORTED(),
* SIPTAG_SUPPORTED(), or SIPTAG_SUPPORTED_STR() tags.
*
* @par Used with
* nua_invite(), nua_update(), nua_respond() \n
* nua_set_params() or nua_set_hparams() \n
@@ -530,8 +565,8 @@ SOFIAPUBVAR tag_typedef_t nutag_invite_timer_ref;
* Corresponding tag taking reference parameter is NUTAG_SESSION_TIMER_REF()
*
* @sa NUTAG_SUPPORTED(), NUTAG_MIN_SE(), NUTAG_SESSION_REFRESHER(),
* nua_invite(), #nua_r_invite, #nua_i_invite, nua_update(), #nua_r_update,
* #nua_i_update,
* nua_invite(), #nua_r_invite, #nua_i_invite, nua_respond(),
* nua_update(), #nua_r_update, #nua_i_update,
* NUTAG_UPDATE_REFRESH(), @RFC4028, @SessionExpires, @MinSE
*/
#define NUTAG_SESSION_TIMER(x) nutag_session_timer, tag_uint_v((x))
@@ -571,6 +606,7 @@ SOFIAPUBVAR tag_typedef_t nutag_min_se;
#define NUTAG_MIN_SE_REF(x) nutag_min_se_ref, tag_uint_vr((&(x)))
SOFIAPUBVAR tag_typedef_t nutag_min_se_ref;
/** Enumeration type of NUTAG_SESSION_REFRESHER(). */
enum nua_session_refresher {
nua_no_refresher, /**< Disable session timer. */
nua_local_refresher, /**< Session refresh by local end. */
@@ -1074,7 +1110,7 @@ SOFIAPUBVAR tag_typedef_t nutag_registrar_ref;
*
* The outbound option string can specify how the NAT traversal is handled.
* The option tokens are as follows:
* - "gruuize": try to generate a GRUU
* - "gruuize": try to generate a GRUU contact from REGISTER response
* - "outbound": use SIP outbound extension (off by default)
* - "validate": validate registration behind a NAT by sending OPTIONS to self
* - "natify": try to traverse NAT
@@ -1084,6 +1120,10 @@ SOFIAPUBVAR tag_typedef_t nutag_registrar_ref;
* An option token with "no-" or "not-" prefix turns the option off. For
* example, if you want to try to traverse NATs but not to use OPTIONS
* keepalive, use NUTAG_OUTBOUND("natify no-options-keepalive").
*
* An empty string can be passed to let the stack choose the
* default values for outbound usage (in the 1.12.5 release, the
* defaults are: "gruuize no-outbound validate use-port options-keepalive").
*
* @note
* Options string is used so that no new tags need to be added when the
@@ -1207,7 +1247,7 @@ SOFIAPUBVAR tag_typedef_t nutag_outbound_set4_ref;
* nua_create()
*
* @par Parameter type
* msg_mclass_t *
* msg_mclass_t const *
*
* @par Values
* Pointer to an extended SIP parser.
@@ -1242,7 +1282,44 @@ SOFIAPUBVAR tag_typedef_t nutag_auth;
#define NUTAG_AUTH_REF(x) nutag_auth_ref, tag_str_vr(&(x))
SOFIAPUBVAR tag_typedef_t nutag_auth_ref;
/** Authentication caching policy
*
* @par Used with
* nua_set_params(), nua_set_hparams() \n
* nua_get_params(), nua_get_hparams() \n
* @NUA_HPARAM_CALLS
*
* @par Parameter type
* enum nua_auth_cache
*
* @par Values
* - nua_auth_cache_dialog (0) - include credentials within dialog
* - nua_auth_cache_challenged (1) - include credentials only when
* challenged
*
* Corresponding tag taking reference parameter is NUTAG_AUTH_CACHE_REF().
*
* @NEW_1_12_6
*/
#define NUTAG_AUTH_CACHE(x) nutag_auth_cache, tag_int_v(x)
SOFIAPUBVAR tag_typedef_t nutag_auth_cache;
#define NUTAG_AUTH_CACHE_REF(x) nutag_auth_cache_ref, tag_int_vr(&(x))
SOFIAPUBVAR tag_typedef_t nutag_auth_cache_ref;
/** Authentication caching policy. @NEW_1_12_6 */
enum nua_auth_cache {
/** Include credentials within dialog (default) */
nua_auth_cache_dialog = 0,
/** Include credentials only when challenged */
nua_auth_cache_challenged = 1,
_nua_auth_cache_invalid
};
/** Keepalive interval in milliseconds.
*
* This setting applies to OPTIONS/STUN keepalives. See documentation
* for nua_register() for more detailed information.
*
* @par Used with
* nua_register() \n
@@ -1268,6 +1345,8 @@ SOFIAPUBVAR tag_typedef_t nutag_keepalive;
SOFIAPUBVAR tag_typedef_t nutag_keepalive_ref;
/** Transport-level keepalive interval for streams.
*
* See documentation for nua_register() for more detailed information.
*
* @par Used with
* nua_register() \n
@@ -1327,6 +1406,7 @@ SOFIAPUBVAR tag_typedef_t nutag_authtime_ref;
*
* @par Used with
* nua_register(), nua_set_hparams(), nua_set_params().
* nua_invite(), nua_respond(), nua_subscribe(), nua_notify()
*
* @par Parameter type
* string (char *)
@@ -1358,6 +1438,7 @@ SOFIAPUBVAR tag_typedef_t nutag_m_display_ref;
*
* @par Used with
* nua_register(), nua_set_hparams(), nua_set_params().
* nua_invite(), nua_respond(), nua_subscribe(), nua_notify()
*
* @par Parameter type
* string (char *)
@@ -1388,7 +1469,8 @@ SOFIAPUBVAR tag_typedef_t nutag_m_username_ref;
* user-agent.
*
* @par Used with
* nua_register(), nua_set_hparams(), nua_set_params().
* nua_register(), nua_set_hparams(), nua_set_params(),
* nua_invite(), nua_respond(), nua_subscribe(), nua_notify()
*
* @par Parameter type
* string (char *)
@@ -1735,7 +1817,8 @@ SOFIAPUBVAR tag_typedef_t nutag_allow_ref;
*
* Corresponding tag taking reference parameter is NUTAG_APPL_METHOD_REF()
*
* @since Working since @VERSION_1_12_5.
* @since Working since @VERSION_1_12_5. Handling of client-side PRACK and
* UPDATE was fixed in @VERSION_1_12_6.
*/
#define NUTAG_APPL_METHOD(x) nutag_appl_method, tag_str_v(x)
SOFIAPUBVAR tag_typedef_t nutag_appl_method;
@@ -1859,26 +1942,39 @@ enum nua_callstate {
/** Get name for NUA call state */
SOFIAPUBFUN char const *nua_callstate_name(enum nua_callstate state);
/** Subscription state
/**Subscription state.
*
* @par Used with
* #nua_notify() \n
* #nua_r_subscribe \n
* #nua_i_notify
* #nua_i_notify \n
* #nua_i_subscribe \n
* #nua_r_notify \n
* nua_notify() \n
* nua_respond() to SUBSCRIBE
*
* @par Parameter type
* int
*
* @par Values
* @c nua_substate_embryonic (0) \n
* @c nua_substate_pending (1) \n
* @c nua_substate_active (2) \n
* @c nua_substate_terminated (3) \n
* - #nua_substate_embryonic (0)
* - #nua_substate_pending (1)
* - #nua_substate_active (2)
* - #nua_substate_terminated (3)
*
* see
* <a href="http://www.ietf.org/rfc/rfc3265.txt">RFC 3265</a>
* Note that the @SubscriptionState or @Expires headers specified by
* application overrides the subscription state specified by
* NUTAG_SUBSTATE(). Application can terminate subscription by including
* NUTAG_SUBSTATE(nua_substate_terminated), @SubscriptionState with value
* "terminated" or @Expires header with value 0 in the NOTIFY request sent
* by nua_notify().
*
* @sa @RFC3265, @SubscriptionState, SIPTAG_SUBSCRIPTION_STATE(),
* SIPTAG_SUBSCRIPTION_STATE_STR(), #nua_r_subscribe, #nua_i_subscribe,
* #nua_i_refer, #nua_r_notify, #nua_i_notify.
*
* Corresponding tag taking reference parameter is NUTAG_SUBSTATE_REF()
*/
*/
#define NUTAG_SUBSTATE(x) nutag_substate, tag_int_v(x)
SOFIAPUBVAR tag_typedef_t nutag_substate;
@@ -1896,6 +1992,46 @@ enum nua_substate {
nua_substate_terminated = nea_terminated /**< Terminated subscription */
};
/** Return name of subscription state. @NEW_1_12_5. */
SOFIAPUBFUN char const *nua_substate_name(enum nua_substate substate);
/** Convert string to enum nua_substate. @NEW_1_12_5. */
SOFIAPUBFUN enum nua_substate nua_substate_make(char const *sip_substate);
/**Send unsolicited NOTIFY request.
*
* Some applications may require sending unsolicited NOTIFY requests, that
* is, NOTIFY without SUBSCRIBE or REFER request sent by event watcher.
* However, sending NOTIFY request requires an existing dialog usage by
* default. If NUTAG_NEWSUB(1) is included in the nua_notify() the usage
* is create the usage by itself.
*
* If you want to create a subscription that does not terminate immediately
* include SIPTAG_SUBSCRIPTION_STATE_STR() with an "expires" parameter in
* the argument list, too.
*
* @par Used with
* nua_notify()
*
* @par Parameter type
* int (boolean)
*
* @par Values
* - 0 - false (default) - do not create new subscription
* but reject NOTIFY with 481 locally \n
* - 1 - true - create a subscription if it does not exist \n
*
* Corresponding tag taking reference parameter is NUTAG_NEWSUB().
*
* @since @NEW_1_12_5.
*/
#define NUTAG_NEWSUB(x) nutag_newsub, tag_bool_v(x)
SOFIAPUBVAR tag_typedef_t nutag_newsub;
#define NUTAG_NEWSUB_REF(x) nutag_newsub_ref, tag_bool_vr(&(x))
SOFIAPUBVAR tag_typedef_t nutag_newsub_ref;
/**Default lifetime for implicit subscriptions created by REFER.
*
* Default expiration time in seconds for implicit subscriptions created by
+474 -33
View File
@@ -101,24 +101,17 @@ int accept_pracked2(CONDITION_PARAMS)
save_event_in_list(ctx, event, ep, call);
switch (event) {
case nua_i_prack:
if (200 <= status && status < 300) {
RESPOND(ep, call, nh, SIP_200_OK,
NUTAG_INCLUDE_EXTRA_SDP(1),
TAG_END());
ep->next_condition = until_ready;
}
default:
break;
}
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());
RESPOND(ep, call, nh, SIP_200_OK,
NUTAG_INCLUDE_EXTRA_SDP(1),
TAG_END());
return 0;
case nua_callstate_ready:
return 1;
case nua_callstate_terminated:
if (call)
nua_handle_destroy(call->nh), call->nh = NULL;
@@ -170,6 +163,7 @@ int test_180rel(struct context *ctx)
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);
@@ -411,17 +405,21 @@ int test_prack_auth(struct context *ctx)
TEST_1(is_answer_recv(e->data->e_tags));
TEST_1(!is_offer_sent(e->data->e_tags));
if (md5 && !md5sess) {
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
TEST(e->data->e_status, 407);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
if (e->data->e_status != 200 && md5 && !md5sess) {
if (e->data->e_status != 100) {
TEST(e->data->e_status, 407);
}
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));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
}
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_r_invite);
@@ -552,6 +550,8 @@ int ringing_pracked(CONDITION_PARAMS)
}
}
int respond_483_to_prack(CONDITION_PARAMS);
int test_183rel(struct context *ctx)
{
BEGIN();
@@ -661,30 +661,110 @@ int test_183rel(struct context *ctx)
if (print_headings)
printf("TEST NUA-10.2.1: PASSED\n");
/* Test for graceful termination by client because 483 sent to PRACK */
if (print_headings)
printf("TEST NUA-10.2.2: terminate call\n");
printf("TEST NUA-10.2.2: graceful termination because PRACK fails\n");
BYE(b, b_call, b_call->nh, TAG_END());
run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
nua_set_hparams(b_call->nh, NUTAG_APPL_METHOD("PRACK"),
NUTAG_AUTOANSWER(0), TAG_END());
run_b_until(ctx, nua_r_set_params, NULL);
/* B transitions:
READY --(T2)--> TERMINATING: nua_bye()
TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
INVITE(a, a_call, a_call->nh, TAG_END());
run_ab_until(ctx, -1, until_terminated, -1, respond_483_to_prack);
/* Client transitions:
INIT -(C1)-> CALLING: nua_invite(), nua_i_state
CALLING -(C2)-> TERMINATING: nua_r_invite, nua_i_state,
nua_r_prack, nua_i_state
TERMINATING -(T1)-> TERMINATED: nua_r_invite, 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);
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);
/* 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(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));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
TEST(e->data->e_status, 483);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminating);
{
int bye = 1, cancel = 1, invite = 1;
while (bye || cancel || invite) {
TEST_1(e = e->next);
if (e->data->e_event == nua_r_bye) {
TEST_E(e->data->e_event, nua_r_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);
bye = 0;
}
else if (e->data->e_event == nua_r_invite) {
TEST_E(e->data->e_event, nua_r_invite);
TEST(e->data->e_status, 487);
invite = 0;
}
else if (e->data->e_event == nua_r_cancel) {
TEST_E(e->data->e_event, nua_r_cancel);
TEST_1(e->data->e_status == 200 || e->data->e_status == 481);
cancel = 0;
}
}
}
TEST_1(!e->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, nua_respond(to PRACK)
EARLY -(S3b)-> TERMINATED: nua_i_bye, 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 183 Session Progress */
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(e->data->e_status, 183);
TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
TEST_1(is_answer_sent(e->data->e_tags));
/* 183 is PRACKed, PRACK is responded with 483 */
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_prack);
/* Client terminates the call
- we may (it is received before BYE) or may not (received after BYE)
get CANCEL request
*/
TEST_1(e = e->next);
if (e->data->e_event == nua_i_cancel) {
TEST_E(e->data->e_event, nua_i_cancel);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_ready);
TEST_1(e = e->next);
}
TEST_E(e->data->e_event, nua_i_bye);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminated);
TEST_1(!e->next);
free_events_in_list(ctx, b->events);
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
@@ -694,6 +774,39 @@ int test_183rel(struct context *ctx)
END();
}
int respond_483_to_prack(CONDITION_PARAMS)
{
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
return 0;
switch (event) {
case nua_i_prack:
if (status <= 200) {
RESPOND(ep, call, nh, 483, "Foo",
NUTAG_WITH_THIS(nua),
TAG_END());
}
default:
break;
}
save_event_in_list(ctx, event, ep, call);
switch (callstate(tags)) {
case nua_callstate_received:
RESPOND(ep, call, nh, SIP_183_SESSION_PROGRESS,
TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
TAG_END());
return 0;
case nua_callstate_terminated:
if (call)
nua_handle_destroy(call->nh), call->nh = NULL;
return 1;
default:
return 0;
}
}
/*
X ringing_updated ep
|-------INVITE------>|
@@ -858,6 +971,8 @@ int test_preconditions(struct context *ctx)
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_update);
TEST(e->data->e_status, 200);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_session_expires);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
@@ -1085,14 +1200,14 @@ int test_preconditions2(struct context *ctx)
nua_set_params(ctx->a.nua,
NUTAG_EARLY_MEDIA(1),
SIPTAG_SUPPORTED_STR("100rel, precondition"),
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"),
SIPTAG_SUPPORTED_STR("100rel, precondition, timer"),
TAG_END());
run_b_until(ctx, nua_r_set_params, until_final_response);
@@ -1578,6 +1693,310 @@ int test_update_by_uas(struct context *ctx)
END();
}
int cancel_when_pracked(CONDITION_PARAMS);
int alert_call(CONDITION_PARAMS);
int test_180rel_cancel1(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;
if (print_headings)
printf("TEST NUA-10.6: CANCEL after PRACK\n");
/* Test for 100rel:
A B
|-------INVITE------>|
|<----100 Trying-----|
| |
|<-------180---------|
|-------PRACK------->|
|<-------200---------|
| |
|------CANCEL------->|
|<------200 OK-------|
| |
|<-------487---------|
|--------ACK-------->|
| |
*/
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),
NUTAG_ONLY183_100REL(0),
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(0),
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, cancel_when_pracked, -1, alert_call);
/* Client transitions:
INIT -(C1)-> CALLING: nua_invite(), nua_i_state
CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state, nua_r_prack
PROCEEDING -(C3+C4)-> TERMINATED: 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));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_cancel);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
TEST(e->data->e_status, 487);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminated);
TEST_1(!e->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
Option A:
EARLY -(S10)-> TERMINATED: nua_i_cancel, nua_i_state
Option B:
EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
READY -(T1)-> TERMINATED: nua_i_bye, 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);
/* Does not have effect on call state */
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_cancel);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
free_events_in_list(ctx, b->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.6: PASSED\n");
END();
}
int cancel_when_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_r_prack)
CANCEL(ep, call, nh, TAG_END());
switch (callstate(tags)) {
case nua_callstate_proceeding:
return 0;
case nua_callstate_ready:
return 1;
case nua_callstate_terminated:
return 1;
default:
return 0;
}
}
int test_180rel_cancel2(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;
if (print_headings)
printf("TEST NUA-10.7: CANCEL after 100rel 180\n");
/* Test for 100rel:
A B
|-------INVITE------>|
|<----100 Trying-----|
| |
|<-------180---------|
|-------PRACK------->|
|<-------200---------|
| |
|------CANCEL------->|
|<------200 OK-------|
| |
|<-------487---------|
|--------ACK-------->|
| |
*/
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),
NUTAG_ONLY183_100REL(0),
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(0),
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, cancel_when_ringing, -1, accept_pracked2);
/* Client transitions:
INIT -(C1)-> CALLING: nua_invite(), nua_i_state
CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state, nua_r_prack
PROCEEDING -(C3+C4)-> TERMINATED: 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));
#define NEXT_SKIP_PRACK_CANCEL() \
do { TEST_1(e = e->next); } \
while (e->data->e_event == nua_r_prack || e->data->e_event == nua_r_cancel)
NEXT_SKIP_PRACK_CANCEL();
TEST_E(e->data->e_event, nua_r_invite);
if (e->data->e_status == 487) {
TEST(e->data->e_status, 487);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminated);
TEST_1(!e->next);
}
else {
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);
BYE(a, a_call, a_call->nh, TAG_END());
run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
NEXT_SKIP_PRACK_CANCEL(); TEST_E(e->data->e_event, nua_r_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);
/*
Server transitions:
INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
Option A:
EARLY -(S10)-> TERMINATED: nua_i_cancel, nua_i_state
Option B:
EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
READY -(T1)-> TERMINATED: nua_i_bye, 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);
/* Does not have effect on call state */
if (e->next->data->e_event == nua_i_cancel) {
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_cancel);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
}
else {
/* 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 = e->next); TEST_E(e->data->e_event, nua_i_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 */
}
free_events_in_list(ctx, b->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.7: PASSED\n");
END();
}
int test_100rel(struct context *ctx)
{
@@ -1589,6 +2008,28 @@ int test_100rel(struct context *ctx)
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_180rel_cancel1(ctx); RETURN_ON_SINGLE_FAILURE(retval);
retval = test_180rel_cancel2(ctx); RETURN_ON_SINGLE_FAILURE(retval);
nua_set_params(ctx->a.nua,
NUTAG_EARLY_MEDIA(0),
SIPTAG_SUPPORTED(ctx->a.supported),
TAG_END());
run_a_until(ctx, nua_r_set_params, until_final_response);
nua_set_params(ctx->b.nua,
NUTAG_EARLY_MEDIA(0),
NUTAG_ONLY183_100REL(0),
SIPTAG_SUPPORTED(ctx->b.supported),
TAG_END());
run_b_until(ctx, nua_r_set_params, until_final_response);
nua_set_params(ctx->c.nua,
NUTAG_EARLY_MEDIA(0),
NUTAG_ONLY183_100REL(0),
SIPTAG_SUPPORTED(ctx->c.supported),
TAG_END());
run_c_until(ctx, nua_r_set_params, until_final_response);
return retval;
}
@@ -117,6 +117,8 @@ int accept_call_with_early_sdp(CONDITION_PARAMS)
case nua_callstate_received:
RESPOND(ep, call, nh, SIP_180_RINGING,
TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
NUTAG_M_DISPLAY("Bob"),
NUTAG_M_USERNAME("b+b"),
TAG_END());
return 0;
case nua_callstate_early:
@@ -203,9 +205,16 @@ int test_basic_call_1(struct context *ctx)
sip_replaces_t *repa, *repb;
nua_handle_t *nh;
static int once = 0;
sip_time_t se, min_se;
if (print_headings)
printf("TEST NUA-3.1: Basic call\n");
/* Disable session timer from proxy */
test_proxy_get_session_timer(ctx->p, &se, &min_se);
test_proxy_set_session_timer(ctx->p, 0, 0);
a_call->sdp = "m=audio 5008 RTP/AVP 8";
b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
@@ -217,6 +226,8 @@ int test_basic_call_1(struct context *ctx)
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),
NUTAG_M_USERNAME("a+a"),
NUTAG_M_DISPLAY("Alice"),
TAG_END());
run_ab_until(ctx, -1, until_ready, -1, accept_call_with_early_sdp);
@@ -263,8 +274,15 @@ int test_basic_call_1(struct context *ctx)
TEST_1(is_answer_recv(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
TEST(e->data->e_status, 200);
TEST_1(sip->sip_payload);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_payload);
TEST_1(sip->sip_contact);
TEST_S(sip->sip_contact->m_display, "Bob");
TEST_S(sip->sip_contact->m_url->url_user, "b+b");
if (!once) {
/* The session expiration is not used by default. */
TEST_1(sip->sip_session_expires == NULL);
}
/* Test that B uses application-specific contact */
if (ctx->proxy_tests)
TEST_1(sip->sip_contact->m_url->url_user);
@@ -282,6 +300,14 @@ int test_basic_call_1(struct context *ctx)
*/
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
TEST(e->data->e_status, 100);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_contact);
TEST_S(sip->sip_contact->m_display, "Alice");
TEST_S(sip->sip_contact->m_url->url_user, "a+a");
if (!once++) {
/* The Session-Expires header is not used by default. */
TEST_1(sip->sip_session_expires == NULL);
}
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));
@@ -331,6 +357,8 @@ int test_basic_call_1(struct context *ctx)
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
test_proxy_set_session_timer(ctx->p, se, min_se);
if (print_headings)
printf("TEST NUA-3.1: PASSED\n");
@@ -404,6 +432,7 @@ int test_basic_call_2(struct context *ctx)
INVITE(a, a_call, a_call->nh,
NUTAG_URL(b->contact->m_url),
SOATAG_USER_SDP_STR(a_call->sdp),
NUTAG_ALLOW("INFO"),
TAG_END());
run_ab_until(ctx, -1, until_ready, -1, accept_early_answer);
@@ -466,32 +495,96 @@ int test_basic_call_2(struct context *ctx)
TEST_1(nua_handle_has_active_call(b_call->nh));
TEST_1(!nua_handle_has_call_on_hold(b_call->nh));
/* Send a NOTIFY from B to A */
if (print_headings)
printf("TEST NUA-3.2.2: send a NOTIFY within a dialog\n");
/* Make A to accept NOTIFY */
nua_set_params(a->nua, NUTAG_APPL_METHOD("NOTIFY"), TAG_END());
run_a_until(ctx, nua_r_set_params, until_final_response);
NOTIFY(b, b_call, b_call->nh,
NUTAG_NEWSUB(1),
SIPTAG_SUBJECT_STR("NUA-3.2.2"),
SIPTAG_EVENT_STR("message-summary"),
SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"),
SIPTAG_PAYLOAD_STR("Messages-Waiting: no"),
TAG_END());
run_ab_until(ctx, -1, accept_notify, -1, save_until_final_response);
/* Notifier events: nua_r_notify */
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_notify);
TEST(e->data->e_status, 200);
TEST_1(tl_find(e->data->e_tags, nutag_substate));
TEST(tl_find(e->data->e_tags, nutag_substate)->t_value,
nua_substate_terminated);
/* watcher events: nua_i_notify */
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_notify);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_subscription_state);
TEST_S(sip->sip_subscription_state->ss_substate, "terminated");
TEST_1(tl_find(e->data->e_tags, nutag_substate));
TEST(tl_find(e->data->e_tags, nutag_substate)->t_value,
nua_substate_terminated);
TEST_1(!e->next);
free_events_in_list(ctx, a->events);
free_events_in_list(ctx, b->events);
if (print_headings)
printf("TEST NUA-3.2.2: PASSED\n");
INFO(b, b_call, b_call->nh, TAG_END());
BYE(b, b_call, b_call->nh, TAG_END());
INFO(b, b_call, b_call->nh, TAG_END());
run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
while (!b->events->head || /* r_info */
!b->events->head->next || /* r_bye */
!b->events->head->next->next || /* i_state */
!b->events->head->next->next->next) /* r_info */
run_ab_until(ctx, -1, save_events, -1, save_until_final_response);
/* B transitions:
nua_info()
READY --(T2)--> TERMINATING: nua_bye()
nua_r_info with 200
TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
nua_r_info with 481/900
*/
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_bye);
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_info);
TEST_1(e = e->next); 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 = e->next); TEST_E(e->data->e_event, nua_r_info);
TEST_1(e->data->e_status >= 900 || e->data->e_status == 481);
TEST_1(!e->next);
free_events_in_list(ctx, b->events);
TEST_1(!nua_handle_has_active_call(b_call->nh));
/* A transitions:
nua_i_info
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_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_info);
TEST_1(e = e->next); 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);
TEST_1(!nua_handle_has_active_call(a_call->nh));
BYE(a, a_call, a_call->nh, TAG_END());
run_a_until(ctx, -1, save_until_final_response);
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_bye);
TEST_1(e->data->e_status >= 900);
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;
@@ -502,8 +595,376 @@ int test_basic_call_2(struct context *ctx)
END();
}
/* ====================================================================== */
/* Basic calls with soa disabled */
int accept_call_no_media(CONDITION_PARAMS)
{
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
return 0;
save_event_in_list(ctx, event, ep, call);
switch (callstate(tags)) {
case nua_callstate_received:
RESPOND(ep, call, nh, SIP_180_RINGING,
NUTAG_MEDIA_ENABLE(0),
TAG_END());
return 0;
case nua_callstate_early:
RESPOND(ep, call, nh, SIP_200_OK,
TAG_IF(call->sdp, SIPTAG_CONTENT_TYPE_STR("application/sdp")),
TAG_IF(call->sdp, SIPTAG_PAYLOAD_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 1;
default:
return 0;
}
}
int test_basic_call_3(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;
sip_t const *sip;
if (print_headings)
printf("TEST NUA-3.3: Basic call with media disabled\n");
a_call->sdp = "v=0\r\n"
"o=- 1 1 IN IP4 127.0.0.1\r\n"
"s=-\r\n"
"c=IN IP4 127.0.0.1\r\n"
"t=0 0\r\n"
"m=audio 5008 RTP/AVP 8\r\n";
b_call->sdp =
"v=0\r\n"
"o=- 2 1 IN IP4 127.0.0.1\r\n"
"s=-\r\n"
"c=IN IP4 127.0.0.1\r\n"
"t=0 0\r\n"
"m=audio 5010 RTP/AVP 0 8\r\n";
TEST_1(a_call->nh = nua_handle(a->nua, a_call,
SIPTAG_TO_STR("<sip:b@x.org>"),
TAG_END()));
TEST_1(!nua_handle_has_active_call(a_call->nh));
TEST_1(!nua_handle_has_call_on_hold(a_call->nh));
INVITE(a, a_call, a_call->nh,
NUTAG_MEDIA_ENABLE(0),
NUTAG_URL(b->contact->m_url),
SIPTAG_CONTENT_TYPE_STR("application/sdp"),
SIPTAG_PAYLOAD_STR(a_call->sdp),
TAG_END());
run_ab_until(ctx, -1, until_ready, -1, accept_call_no_media);
/* 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, 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_answer_recv(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
TEST(e->data->e_status, 200);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_content_type);
TEST_S(sip->sip_content_type->c_type, "application/sdp");
TEST_1(sip->sip_payload); /* there is sdp in 200 OK */
TEST_1(sip->sip_contact);
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_answer_recv(e->data->e_tags));
TEST_1(!e->next);
free_events_in_list(ctx, a->events);
TEST_1(nua_handle_has_active_call(a_call->nh));
TEST_1(!nua_handle_has_call_on_hold(a_call->nh));
/*
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));
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_state);
TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
TEST_1(is_answer_sent(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(!e->next);
free_events_in_list(ctx, b->events);
TEST_1(nua_handle_has_active_call(b_call->nh));
TEST_1(!nua_handle_has_call_on_hold(b_call->nh));
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);
TEST_1(!nua_handle_has_active_call(b_call->nh));
/* A transitions:
nua_i_info
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-3.3: PASSED\n");
END();
}
int ack_when_completing_no_media(CONDITION_PARAMS)
{
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
return 0;
save_event_in_list(ctx, event, ep, call);
switch (callstate(tags)) {
case nua_callstate_completing:
ACK(ep, call, nh,
TAG_IF(call->sdp, SIPTAG_CONTENT_TYPE_STR("application/sdp")),
TAG_IF(call->sdp, SIPTAG_PAYLOAD_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 1;
default:
return 0;
}
}
int accept_call_no_media2(CONDITION_PARAMS)
{
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
return 0;
save_event_in_list(ctx, event, ep, call);
switch (callstate(tags)) {
case nua_callstate_received:
RESPOND(ep, call, nh, SIP_180_RINGING,
NUTAG_MEDIA_ENABLE(0),
TAG_IF(call->sdp, SIPTAG_CONTENT_TYPE_STR("application/sdp")),
TAG_IF(call->sdp, SIPTAG_PAYLOAD_STR(call->sdp)),
TAG_END());
return 0;
case nua_callstate_early:
RESPOND(ep, call, nh, SIP_200_OK,
TAG_IF(call->sdp, SIPTAG_CONTENT_TYPE_STR("application/sdp")),
TAG_IF(call->sdp, SIPTAG_PAYLOAD_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 1;
default:
return 0;
}
}
/* Media disabled, offer/answer in 200 OK/ACK */
int test_basic_call_4(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;
sip_t const *sip;
if (print_headings)
printf("TEST NUA-3.4: 3pcc call with media disabled\n");
a_call->sdp = "v=0\r\n"
"o=- 1 1 IN IP4 127.0.0.1\r\n"
"s=-\r\n"
"c=IN IP4 127.0.0.1\r\n"
"t=0 0\r\n"
"m=audio 5008 RTP/AVP 8\r\n";
b_call->sdp =
"v=0\r\n"
"o=- 2 1 IN IP4 127.0.0.1\r\n"
"s=-\r\n"
"c=IN IP4 127.0.0.1\r\n"
"t=0 0\r\n"
"m=audio 5010 RTP/AVP 0 8\r\n";
TEST_1(a_call->nh = nua_handle(a->nua, a_call,
SIPTAG_TO_STR("<sip:b@x.org>"),
TAG_END()));
TEST_1(!nua_handle_has_active_call(a_call->nh));
TEST_1(!nua_handle_has_call_on_hold(a_call->nh));
INVITE(a, a_call, a_call->nh,
NUTAG_MEDIA_ENABLE(0),
NUTAG_URL(b->contact->m_url),
NUTAG_AUTOACK(0),
TAG_END());
run_ab_until(ctx, -1, ack_when_completing_no_media,
-1, accept_call_no_media2);
/* 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, 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_answer_recv(e->data->e_tags));
TEST_1(is_offer_recv(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
TEST(e->data->e_status, 200);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_content_type);
TEST_S(sip->sip_content_type->c_type, "application/sdp");
TEST_1(sip->sip_payload); /* there is sdp in 200 OK */
TEST_1(sip->sip_contact);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_completing); /* COMPLETING */
TEST_1(is_offer_recv(e->data->e_tags));
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_answer_sent(e->data->e_tags));
TEST_1(!e->next);
free_events_in_list(ctx, a->events);
TEST_1(nua_handle_has_active_call(a_call->nh));
TEST_1(!nua_handle_has_call_on_hold(a_call->nh));
/*
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));
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(is_offer_sent(e->data->e_tags));
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_sent(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_answer_recv(e->data->e_tags));
TEST_1(!e->next);
free_events_in_list(ctx, b->events);
TEST_1(nua_handle_has_active_call(b_call->nh));
TEST_1(!nua_handle_has_call_on_hold(b_call->nh));
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);
TEST_1(!nua_handle_has_active_call(b_call->nh));
/* A transitions:
nua_i_info
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-3.4: PASSED\n");
END();
}
int test_basic_call(struct context *ctx)
{
return test_basic_call_1(ctx) || test_basic_call_2(ctx);
return test_basic_call_1(ctx) || test_basic_call_2(ctx) ||
test_basic_call_3(ctx) || test_basic_call_4(ctx);
}
@@ -467,7 +467,7 @@ int test_call_hold(struct context *ctx)
*/
if (print_headings)
printf("TEST NUA-7.6: re-INVITE without auto-ack\n");
printf("TEST NUA-7.6.1: re-INVITE without auto-ack\n");
/* Turn off auto-ack */
nua_set_hparams(b_call->nh, NUTAG_AUTOACK(0), TAG_END());
@@ -517,7 +517,7 @@ int test_call_hold(struct context *ctx)
free_events_in_list(ctx, a->events);
if (print_headings)
printf("TEST NUA-7.6: PASSED\n");
printf("TEST NUA-7.6.1: PASSED\n");
/* ---------------------------------------------------------------------- */
@@ -528,7 +528,7 @@ int test_call_hold(struct context *ctx)
*/
if (print_headings)
printf("TEST NUA-7.6: terminate call\n");
printf("TEST NUA-7.6.2: terminate call\n");
BYE(a, a_call, a_call->nh, TAG_END());
run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
@@ -555,7 +555,7 @@ int test_call_hold(struct context *ctx)
free_events_in_list(ctx, b->events);
if (print_headings)
printf("TEST NUA-7.6: PASSED\n");
printf("TEST NUA-7.6.2: PASSED\n");
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
@@ -725,9 +725,6 @@ int test_reinvite(struct context *ctx)
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-7.8: PASSED\n");
END();
}
@@ -784,6 +781,211 @@ int ringing_until_terminated(CONDITION_PARAMS)
}
}
/* ======================================================================== */
int accept_and_attempt_reinvite(CONDITION_PARAMS);
int until_ready2(CONDITION_PARAMS);
/* test_reinvite2 message sequence looks like this:
A B
| |
|-------INVITE------>|
|<----100 Trying-----|
| |
|<----180 Ringing----|
| |
| /-INVITE-|
| \---900->|
| |
|<--------200--------|
|---------ACK------->|
: :
: queue INVITE :
: :
|-----re-INVITE----->|
|<--------200--------|
|---------ACK------->|
|-----re-INVITE----->|
|<--------200--------|
|---------ACK------->|
: :
: glare :
: :
|-----re-INVITE----->|
|<----re-INVITE------|
|<--------491--------|
|---------491------->|
|---------ACK------->|
|<--------ACK--------|
: :
|---------BYE------->|
|<--------200--------|
*/
int test_reinvite2(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;
if (print_headings)
printf("TEST NUA-7.8.1: Test re-INVITE glare\n");
a_call->sdp = "m=audio 5008 RTP/AVP 0 8\n";
b_call->sdp = "m=audio 5010 RTP/AVP 8\n";
TEST_1(a_call->nh =
nua_handle(a->nua, a_call,
SIPTAG_FROM_STR("Alice <sip:alice@example.com>"),
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, accept_and_attempt_reinvite);
TEST_1(nua_handle_has_active_call(a_call->nh));
TEST_1(nua_handle_has_active_call(b_call->nh));
free_events_in_list(ctx, a->events);
free_events_in_list(ctx, b->events);
/* Check that we can queue INVITEs */
INVITE(a, a_call, a_call->nh, TAG_END());
INVITE(a, a_call, a_call->nh, TAG_END());
run_ab_until(ctx, -1, until_ready2, -1, until_ready2);
free_events_in_list(ctx, a->events);
free_events_in_list(ctx, b->events);
/* Check that INVITE glare works */
INVITE(a, a_call, a_call->nh, TAG_END());
INVITE(b, b_call, b_call->nh, TAG_END());
a->flags.n = 0, b->flags.n = 0;
run_ab_until(ctx, -1, until_ready2, -1, until_ready2);
free_events_in_list(ctx, a->events);
free_events_in_list(ctx, b->events);
if (print_headings)
printf("TEST NUA-7.8.1: PASSED\n");
/* ---------------------------------------------------------------------- */
/*
A B
|---------BYE------->|
|<--------200--------|
*/
if (print_headings)
printf("TEST NUA-7.8.2: terminate call\n");
BYE(a, a_call, a_call->nh, TAG_END());
run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
/*
Transitions of A:
READY --(T2)--> TERMINATING: nua_bye()
TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
*/
TEST_1(e = a->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, a->events);
/* Transitions of B:
READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state
*/
TEST_1(e = b->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, b->events);
if (print_headings)
printf("TEST NUA-7.8.2: PASSED\n");
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
END();
}
int accept_and_attempt_reinvite(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) {
INVITE(ep, call, nh, TAG_END());
RESPOND(ep, call, nh, SIP_200_OK,
TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
TAG_END());
}
else switch (callstate(tags)) {
case nua_callstate_received:
RESPOND(ep, call, nh, SIP_180_RINGING,
SIPTAG_REQUIRE_STR("100rel"),
TAG_END());
return 0;
case nua_callstate_early:
return 0;
case nua_callstate_ready:
return 1;
case nua_callstate_terminated:
if (call)
nua_handle_destroy(call->nh), call->nh = NULL;
return 1;
default:
return 0;
}
return 0;
}
/*
X INVITE
| |
|-------INVITE------>|
|<--------200--------|
|---------ACK------->|
*/
int until_ready2(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_r_invite && status == 491) {
if (ep == &ctx->a && ++ctx->b.flags.n >= 2) ctx->b.running = 0;
if (ep == &ctx->b && ++ctx->a.flags.n >= 2) ctx->a.running = 0;
}
switch (callstate(tags)) {
case nua_callstate_ready:
return ++ep->flags.n >= 2;
case nua_callstate_terminated:
if (call)
nua_handle_destroy(call->nh), call->nh = NULL;
return 1;
default:
return 0;
}
}
int test_reinvites(struct context *ctx)
{
int retval = 0;
@@ -794,7 +996,10 @@ int test_reinvites(struct context *ctx)
retval = test_call_hold(ctx);
if (retval == 0)
retval |= test_reinvite(ctx);
retval = test_reinvite(ctx);
if (retval == 0)
retval = test_reinvite2(ctx);
if (print_headings && retval == 0)
printf("TEST NUA-7: PASSED\n");
@@ -261,7 +261,8 @@ int test_reject_b(struct context *ctx)
/* ------------------------------------------------------------------------ */
int reject_302(CONDITION_PARAMS);
int reject_302(CONDITION_PARAMS), reject_305(CONDITION_PARAMS);
int redirect_always(CONDITION_PARAMS);
int reject_604(CONDITION_PARAMS);
/*
@@ -281,6 +282,7 @@ int reject_604(CONDITION_PARAMS);
|<---604 Nowhere-----|
|--------ACK-------->|
*/
int reject_302(CONDITION_PARAMS)
{
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
@@ -298,6 +300,33 @@ int reject_302(CONDITION_PARAMS)
SIPTAG_CONTACT(m), TAG_END());
}
return 0;
case nua_callstate_terminated:
if (call)
nua_handle_destroy(call->nh), call->nh = NULL;
ep->next_condition = reject_305;
return 0;
default:
return 0;
}
}
int reject_305(CONDITION_PARAMS)
{
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
return 0;
save_event_in_list(ctx, event, ep, call);
switch (callstate(tags)) {
case nua_callstate_received:
{
sip_contact_t m[1];
*m = *ep->contact;
m->m_url->url_user = "305";
m->m_url->url_params = "lr=1";
RESPOND(ep, call, nh, SIP_305_USE_PROXY, SIPTAG_CONTACT(m), TAG_END());
}
return 0;
case nua_callstate_terminated:
if (call)
nua_handle_destroy(call->nh), call->nh = NULL;
@@ -308,6 +337,27 @@ int reject_302(CONDITION_PARAMS)
}
}
int redirect_always(CONDITION_PARAMS)
{
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
return 0;
if (event == nua_i_invite) {
char user[30];
sip_contact_t m[1];
*m = *ep->contact;
snprintf(user, sizeof user, "user-%u", ep->flags.n++);
m->m_url->url_user = user;
RESPOND(ep, call, nh, SIP_302_MOVED_TEMPORARILY,
SIPTAG_CONTACT(m), TAG_END());
nua_handle_destroy(nh);
call->nh = NULL;
return 1;
}
return 0;
}
int reject_604(CONDITION_PARAMS)
{
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
@@ -338,6 +388,7 @@ int test_reject_302(struct context *ctx)
struct endpoint *a = &ctx->a, *b = &ctx->b;
struct call *a_call = a->call, *b_call = b->call;
struct event *e;
sip_t const *sip;
/* Make call reject-3 */
if (print_headings)
@@ -388,6 +439,12 @@ int test_reject_302(struct context *ctx)
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, 100);
TEST(sip_object(e->data->e_msg)->sip_status->st_status, 305);
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(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); /* PROCEEDING */
@@ -415,6 +472,18 @@ int test_reject_302(struct context *ctx)
TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
TEST_1(is_offer_recv(e->data->e_tags));
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(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_request);
TEST_S(sip->sip_request->rq_url->url_user, "302");
TEST_1(sip->sip_route);
TEST_S(sip->sip_route->r_url->url_user, "305");
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));
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(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
@@ -425,6 +494,25 @@ int test_reject_302(struct context *ctx)
free_events_in_list(ctx, b->events);
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
if (print_headings)
printf("TEST NUA-4.3: PASSED\n");
if (print_headings)
printf("TEST NUA-4.3.1: redirect until retry count is exceeded\n");
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)),
SIPTAG_SUBJECT_STR("redirect always"),
SOATAG_USER_SDP_STR(a_call->sdp),
TAG_END());
run_ab_until(ctx, -1, until_terminated, -1, redirect_always);
free_events_in_list(ctx, a->events);
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
free_events_in_list(ctx, b->events);
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
if (print_headings)
printf("TEST NUA-4.3: PASSED\n");
@@ -638,11 +726,12 @@ int test_reject_401(struct context *ctx)
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(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_proxy_authorization);
/* Ensure that nua_authenticate() tags get added to the request */
TEST_1(sip->sip_subject);
TEST_S(sip->sip_subject->g_value, "Got 407");
TEST_1(sip->sip_proxy_authorization);
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));
@@ -723,7 +812,7 @@ int test_reject_401_aka(struct context *ctx)
sip_t const *sip;
if (print_headings)
printf("TEST NUA-4.6: invalid challenge \n");
printf("TEST NUA-4.6.1: invalid challenge \n");
a_call->sdp = "m=audio 5008 RTP/AVP 8";
b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
@@ -772,7 +861,161 @@ int test_reject_401_aka(struct context *ctx)
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
if (print_headings)
printf("TEST NUA-4.6: PASSED\n");
printf("TEST NUA-4.6.1: PASSED\n");
END();
}
/* ------------------------------------------------------------------------ */
/* Reject call with 401, twice */
/*
A reject-401-bad B
| |
|-------INVITE------>|
|<----100 Trying-----|
|<--------401--------|
|---------ACK------->|
| |
|-------INVITE------>|
|<----100 Trying-----|
|<--------401--------|
|---------ACK------->|
*/
int reject_401_bad(CONDITION_PARAMS)
{
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
return 0;
save_event_in_list(ctx, event, ep, call);
switch (callstate(tags)) {
case nua_callstate_received:
RESPOND(ep, call, nh, SIP_401_UNAUTHORIZED,
/* Send a challenge that we do not grok */
SIPTAG_WWW_AUTHENTICATE_STR("Digest realm=\"No hope\", "
"nonce=\"goO541ftNrw327aWpu2\", "
"algorithm=MD5, "
"qop=\"auth\""),
TAG_END());
return 0;
case nua_callstate_terminated:
if (call)
nua_handle_destroy(call->nh), call->nh = NULL;
if (ep->flags.bit0) /* Terminate 2 calls */
return 1;
ep->flags.bit0 = 1;
return 0;
default:
return 0;
}
}
int authenticate_bad(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_r_invite && status == 401) {
AUTHENTICATE(ep, call, nh, NUTAG_AUTH("Digest:\"No hope\":jaska:secret"),
SIPTAG_SUBJECT_STR("Bad password"),
TAG_END());
return 0;
}
switch (callstate(tags)) {
case nua_callstate_terminated:
if (call)
nua_handle_destroy(call->nh), call->nh = NULL;
return 1;
default:
return 0;
}
}
int test_reject_401_bad(struct context *ctx)
{
BEGIN();
struct endpoint *a = &ctx->a, *b = &ctx->b;
struct call *a_call = a->call, *b_call = b->call;
struct event const *e;
sip_t const *sip;
if (print_headings)
printf("TEST NUA-4.6.2: bad username/password\n");
a_call->sdp = "m=audio 5008 RTP/AVP 8";
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)),
SIPTAG_SUBJECT_STR("reject-401-bad"),
SOATAG_USER_SDP_STR(a_call->sdp),
TAG_END());
run_ab_until(ctx, -1, authenticate_bad, -1, reject_401_bad);
/*
Client transitions
INIT -(C1)-> CALLING -(C6a)-> TERMINATED/INIT
*/
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(sip_object(e->data->e_msg)->sip_status->st_status, 401);
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(is_offer_sent(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
TEST(sip_object(e->data->e_msg)->sip_status->st_status, 401);
/* nua_authenticate() fails and INVITE returns an internal error response */
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
TEST(e->data->e_status, 904);
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);
/*
Server transitions:
INIT -(S1)-> RECEIVED -(S6a)-> TERMINATED
*/
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
TEST_1(sip = sip_object(e->data->e_msg));
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));
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_1(sip = sip_object(e->data->e_msg));
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));
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);
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-4.6.2: PASSED\n");
END();
}
@@ -911,7 +1154,7 @@ int test_mime_negotiation(struct context *ctx)
/*
Client transitions in reject-3:
INIT -(C1)-> PROCEEDING -(C6a)-> TERMINATED
INIT -(C1)-> CALLING -(C6a)-> TERMINATED
*/
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
@@ -927,7 +1170,7 @@ int test_mime_negotiation(struct context *ctx)
/* No content-encoding is supported */
TEST_S(sip->sip_accept_encoding->aa_value, "");
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* CALLING */
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
TEST_1(!e->next);
free_events_in_list(ctx, a->events);
@@ -944,3 +1187,340 @@ int test_mime_negotiation(struct context *ctx)
END();
}
/* ---------------------------------------------------------------------- */
size_t filter_200_OK(void *arg, void *message, size_t len)
{
(void)arg;
if (len >= 11 && strncasecmp(message, "SIP/2.0 200", 11) == 0)
return 0;
return len;
}
size_t filter_ACK(void *arg, void *message, size_t len)
{
(void)arg;
if (len >= 7 && strncasecmp(message, "ACK sip", 7) == 0)
return 0;
return len;
}
int call_with_bad_ack(CONDITION_PARAMS);
int accept_call_with_bad_contact(CONDITION_PARAMS);
int test_call_timeouts(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;
struct nat_filter *f, *f2;
if (print_headings)
printf("TEST NUA-4.7: check for error and timeout handling\n");
a_call->sdp = "m=audio 5008 RTP/AVP 8";
b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
if (!ctx->nat)
goto completed_4_7_1;
if (print_headings)
printf("TEST NUA-4.7.1: ACK timeout (200 OK filtered)\n");
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
TEST_1(f = test_nat_add_filter(ctx->nat, filter_200_OK, NULL, nat_inbound));
TEST_1(f2 = test_nat_add_filter(ctx->nat, filter_200_OK,
NULL, nat_outbound));
INVITE(a, a_call, a_call->nh,
TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
SIPTAG_SUBJECT_STR("NUA-4.7.1"),
SOATAG_USER_SDP_STR(a_call->sdp),
TAG_END());
run_ab_until(ctx, -1, until_terminated, -1, accept_call);
/*
A accept_call B
| |
|-------INVITE------>|
|<----100 Trying-----|
| |
|<----180 Ringing----|
| |
| X-----200--------|
| X-----200--------|
| X-----200--------|
| |
|<--------BYE--------|
|--------200 OK---X |
*/
/*
Client transitions:
*/
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(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); /* PROCEEDING */
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_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);
/*
Server transitions:
-(S1)-> RECEIVED -(S2a)-> EARLY -(S3b)-> COMPLETED -(S5)-> TERMINATING
-(S10)-> TERMINATED -X
*/
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));
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(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_answer_sent(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_error);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminating); /* TERMINATING */
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_bye);
TEST(e->data->e_status, 408);
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;
free_events_in_list(ctx, b->events);
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
TEST_1(test_nat_remove_filter(ctx->nat, f) == 0);
TEST_1(test_nat_remove_filter(ctx->nat, f2) == 0);
if (print_headings)
printf("TEST NUA-4.7.1: PASSED\n");
completed_4_7_1:
if (!ctx->nat)
goto completed_4_7_2;
if (print_headings)
printf("TEST NUA-4.7.2: ACK timeout (ACK filtered)\n");
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
TEST_1(f = test_nat_add_filter(ctx->nat, filter_ACK, NULL, nat_outbound));
INVITE(a, a_call, a_call->nh,
TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
SIPTAG_SUBJECT_STR("NUA-4.7.2"),
SOATAG_USER_SDP_STR(a_call->sdp),
TAG_END());
run_ab_until(ctx, -1, until_terminated, -1, accept_call);
/*
A accept_call B
| |
|-------INVITE------>|
|<----100 Trying-----|
| |
|<----180 Ringing----|
| |
|<--------200--------|
|--------ACK-----X |
| |
|<--------200--------|
|--------ACK-----X |
| |
|<--------200--------|
|--------ACK-----X |
| |
|<--------BYE--------|
|--------200 OK----->|
*/
/*
*/
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(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(e = e->next); 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(e = e->next); TEST_E(e->data->e_event, nua_i_bye);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminated);
TEST_1(!e->next);
/*
Server transitions:
-(S1)-> RECEIVED -(S2a)-> EARLY -(S3b)-> COMPLETED -(S5)-> TERMINATING
-(S10)-> TERMINATED -X
*/
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));
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(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_answer_sent(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_error);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminating); /* TERMINATING */
TEST_1(e = e->next); 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, a->events);
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
free_events_in_list(ctx, b->events);
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
TEST_1(test_nat_remove_filter(ctx->nat, f) == 0);
if (print_headings)
printf("TEST NUA-4.7.2: PASSED\n");
completed_4_7_2:
if (print_headings)
printf("TEST NUA-4.7.3: sending ACK fails\n");
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)),
SIPTAG_SUBJECT_STR("NUA-4.7.3"),
SOATAG_USER_SDP_STR(a_call->sdp),
NUTAG_AUTOACK(0),
TAG_END());
run_ab_until(ctx, -1, call_with_bad_ack, -1, accept_call);
/*
A accept_call B
| |
|-------INVITE------>|
|<----100 Trying-----|
| |
|<----180 Ringing----|
| |
|<--------200--------|
|--ACK-X |
| |
|---------BYE------->|
|<-------200 OK------|
*/
/*
*/
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(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(e = e->next); 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_completing); /* COMPLETING */
/* try to send ACK */
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminating);
TEST_1(e = e->next); 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);
TEST_1(!e->next);
/*
Server transitions:
-(S1)-> RECEIVED -(S2a)-> EARLY -(S3b)-> COMPLETED -(S5)-> TERMINATING
-(S10)-> TERMINATED -X
*/
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));
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(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_answer_sent(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_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, a->events);
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
free_events_in_list(ctx, b->events);
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
if (print_headings)
printf("TEST NUA-4.7.3: PASSED\n");
/* XXX - PRACK timeout, PRACK failing, media failing, re-INVITEs */
if (print_headings)
printf("TEST NUA-4.7: PASSED\n");
END();
}
int call_with_bad_ack(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_r_invite && 200 <= status && status < 300) {
ACK(ep, call, nh,
/* Syntax error - sending ACK fails, we send BYE */
SIPTAG_MAX_FORWARDS_STR("blue"),
TAG_END());
}
return event == nua_i_state && callstate(tags) == nua_callstate_terminated;
}
/* ---------------------------------------------------------------------- */
int test_rejects(struct context *ctx)
{
return
test_reject_401_bad(ctx) ||
test_reject_a(ctx) ||
test_reject_b(ctx) ||
test_reject_302(ctx) ||
test_reject_401(ctx) ||
test_mime_negotiation(ctx) ||
test_call_timeouts(ctx) ||
test_reject_401_aka(ctx) ||
0;
}
@@ -118,6 +118,8 @@ int cancel_when_ringing(CONDITION_PARAMS)
case nua_callstate_proceeding:
CANCEL(ep, call, nh, TAG_END());
return 0;
case nua_callstate_ready:
return 1;
case nua_callstate_terminated:
return 1;
default:
@@ -144,6 +146,7 @@ int alert_call(CONDITION_PARAMS)
}
}
int accept_after_183(CONDITION_PARAMS);
int test_call_cancel(struct context *ctx)
{
@@ -211,7 +214,7 @@ int test_call_cancel(struct context *ctx)
/* ------------------------------------------------------------------------ */
if (print_headings)
printf("TEST NUA-5.2: cancel call when ringing\n");
printf("TEST NUA-5.2.1: cancel call when ringing\n");
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
@@ -278,11 +281,56 @@ int test_call_cancel(struct context *ctx)
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
if (print_headings)
printf("TEST NUA-5.2: PASSED\n");
printf("TEST NUA-5.2.1: PASSED\n");
/* ------------------------------------------------------------------------ */
if (print_headings)
printf("TEST NUA-5.2.2: CANCEL call when server waits for PRACK\n");
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),
NUTAG_APPL_METHOD("PRACK"),
/*SIPTAG_REJECT_CONTACT_STR("*;audio=FALSE"),*/
TAG_END());
run_ab_until(ctx, -1, cancel_when_ringing, -1, accept_after_183);
free_events_in_list(ctx, a->events);
free_events_in_list(ctx, b->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-5.2.2: PASSED\n");
END();
}
int accept_after_183(CONDITION_PARAMS)
{
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
return 0;
save_event_in_list(ctx, event, ep, call);
switch (callstate(tags)) {
case nua_callstate_received:
RESPOND(ep, call, nh, SIP_183_SESSION_PROGRESS, TAG_END());
RESPOND(ep, call, nh, SIP_200_OK, TAG_END());
return 0;
case nua_callstate_terminated:
return 1;
default:
return 0;
}
}
/* ======================================================================== */
/* Destroy call handle */
@@ -496,13 +544,13 @@ int destroy_when_early(CONDITION_PARAMS)
return 0;
case nua_callstate_early:
if (call)
nua_handle_destroy(call->nh), call->nh = NULL;
DESTROY(ep, call, nh), call->nh = NULL;
return 1;
case nua_callstate_completed:
case nua_callstate_ready:
case nua_callstate_terminated:
if (call)
nua_handle_destroy(call->nh), call->nh = NULL;
DESTROY(ep, call, nh), call->nh = NULL;
return 1;
default:
return 0;
@@ -594,7 +642,7 @@ int destroy_when_completed(CONDITION_PARAMS)
case nua_callstate_ready:
case nua_callstate_terminated:
if (call)
nua_handle_destroy(call->nh), call->nh = NULL;
DESTROY(ep, call, nh), call->nh = NULL;
return 1;
default:
return 0;
@@ -673,6 +721,82 @@ int test_call_destroy_4(struct context *ctx)
END();
}
/* Destroy when one INVITE is queued. */
int test_call_destroy_5(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;
if (print_headings)
printf("TEST NUA-5.7: destroy when re-INVITE is queued\n");
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)),
NUTAG_AUTOACK(0),
SOATAG_USER_SDP_STR(a_call->sdp),
TAG_END());
INVITE(a, a_call, a_call->nh, TAG_END());
run_ab_until(ctx, -1, until_terminated, -1, destroy_when_completed);
/* Client transitions:
INIT -(C1)-> CALLING: nua_invite(), ...
*/
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); /* PROCEEDING */
TEST_1(e = e->next); 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_completing); /* COMPLETING */
TEST_1(is_answer_recv(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_bye);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
TEST(e->data->e_status, 481);
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;
/*
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 ... DESTROY
*/
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));
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(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_answer_sent(e->data->e_tags));
TEST_1(!e->next);
free_events_in_list(ctx, b->events);
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
if (print_headings)
printf("TEST NUA-5.7: PASSED\n");
END();
}
int test_call_destroy(struct context *ctx)
{
struct endpoint *a = &ctx->a, *b = &ctx->b;
@@ -685,10 +809,12 @@ int test_call_destroy(struct context *ctx)
test_call_destroy_1(ctx) ||
test_call_destroy_2(ctx) ||
test_call_destroy_3(ctx) ||
test_call_destroy_4(ctx);
test_call_destroy_4(ctx) ||
test_call_destroy_5(ctx);
}
/* ======================================================================== */
/* Early BYE
A B
@@ -731,13 +857,30 @@ int bye_when_ringing(CONDITION_PARAMS)
}
}
int test_early_bye(struct context *ctx)
int bye_when_completing(CONDITION_PARAMS);
static int ack_sent = 0;
size_t count_acks(void *arg, void *message, size_t len)
{
(void)arg;
if (strncasecmp(message, "ACK sip:", 8) == 0)
ack_sent++;
return len;
}
int test_bye_before_200(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;
a_call->sdp = "m=audio 5008 RTP/AVP 8";
b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
if (print_headings)
printf("TEST NUA-6.1: BYE call when ringing\n");
@@ -809,3 +952,513 @@ int test_early_bye(struct context *ctx)
END();
}
int bye_when_completing(CONDITION_PARAMS)
{
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
return 0;
save_event_in_list(ctx, event, ep, call);
switch (callstate(tags)) {
case nua_callstate_completing:
ack_sent = 0;
BYE(ep, call, nh, TAG_END());
return 0;
case nua_callstate_terminated:
return 1;
default:
return 0;
}
}
int test_bye_before_ack(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;
struct nat_filter *f = NULL;
a_call->sdp = "m=audio 5008 RTP/AVP 8";
b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
/* Early BYE 2
A B
|-------INVITE------>|
|<----100 Trying-----|
| |
|<----180 Ringing----|
|<-------200---------|
| |
|--------BYE-------->|
|<------200 OK-------|
|--------ACK-------->|
| |
| |
*/
if (print_headings)
printf("TEST NUA-6.2: BYE call when completing\n");
if (ctx->nat)
TEST_1(f = test_nat_add_filter(ctx->nat, count_acks, NULL, nat_outbound));
ack_sent = 0;
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),
NUTAG_AUTOACK(0),
TAG_END());
run_ab_until(ctx, -1, bye_when_completing, -1, accept_until_terminated);
/* Client transitions:
INIT -(C1)-> CALLING: nua_invite(), nua_i_state
CALLING -(C2)-> PROCEEDING: nua_r_invite(180, nua_i_state, nua_cancel()
PROCEEDING -(C6b)-> TERMINATED: nua_r_invite(487), 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);
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(e = e->next); 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_completing);
TEST_1(e = e->next);
TEST_E(e->data->e_event, nua_r_bye); TEST(e->data->e_status, 200);
TEST_1(e->data->e_msg);
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);
if (ctx->nat) {
while (ack_sent == 0)
su_root_step(ctx->root, 100);
TEST_1(ack_sent > 0);
TEST_1(test_nat_remove_filter(ctx->nat, f) == 0);
}
/*
Server transitions:
INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
RECEIVED -(S2a)-> EARLY: nua_respond(180), nua_i_state
EARLY -(S6b)--> TERMINATED: nua_i_cancel, 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));
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(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
TEST_1(e = e->next); 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;
free_events_in_list(ctx, b->events);
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
if (print_headings)
printf("TEST NUA-6.2: PASSED\n");
END();
}
int reject_reinvite_401(CONDITION_PARAMS);
int test_bye_after_receiving_401(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;
a_call->sdp = "m=audio 5008 RTP/AVP 8";
b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
/* BYE after receiving 401
A B
|-------INVITE------>|
|<----100 Trying-----|
| |
|<----180 Ringing----|
|<-------200---------|
|--------ACK-------->|
| |
|<------INVITE-------|
|--------401-------->|
|<--------ACK--------|
| |
|<--------BYE--------|
|------200 OK------->|
| |
*/
if (print_headings)
printf("TEST NUA-6.3: BYE after receiving 401\n");
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)),
SIPTAG_SUBJECT_STR("NUA-6.3"),
SOATAG_USER_SDP_STR(a_call->sdp),
NUTAG_AUTOANSWER(0),
TAG_END());
run_ab_until(ctx, -1, until_ready, -1, accept_call);
free_events_in_list(ctx, a->events);
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
free_events_in_list(ctx, b->events);
/* re-INVITE A. */
INVITE(b, b_call, b_call->nh,
SIPTAG_SUBJECT_STR("NUA-6.3 re-INVITE"),
TAG_END());
run_ab_until(ctx, -1, reject_reinvite_401, -1, until_final_response);
TEST_1(nua_handle_has_active_call(a_call->nh));
TEST_1(nua_handle_has_active_call(b_call->nh));
free_events_in_list(ctx, a->events);
free_events_in_list(ctx, b->events);
BYE(b, b_call, b_call->nh, TAG_END());
run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
free_events_in_list(ctx, a->events);
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
free_events_in_list(ctx, b->events);
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
if (print_headings)
printf("TEST NUA-6.3: PASSED\n");
END();
}
int test_bye_after_sending_401(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;
a_call->sdp = "m=audio 5008 RTP/AVP 8";
b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
/* BYE after sending 401
A B
|-------INVITE------>|
|<----100 Trying-----|
| |
|<----180 Ringing----|
|<-------200---------|
|--------ACK-------->|
| |
|<------INVITE-------|
|--------401-------->|
|<--------ACK--------|
| |
|--------BYE-------->|
|<------200 OK-------|
| |
*/
if (print_headings)
printf("TEST NUA-6.4.1: BYE after sending 401\n");
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)),
SIPTAG_SUBJECT_STR("NUA-6.4.1"),
SOATAG_USER_SDP_STR(a_call->sdp),
NUTAG_AUTOANSWER(0),
TAG_END());
run_ab_until(ctx, -1, until_ready, -1, accept_call);
free_events_in_list(ctx, a->events);
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
free_events_in_list(ctx, b->events);
/* re-INVITE A. */
INVITE(b, b_call, b_call->nh,
SIPTAG_SUBJECT_STR("NUA-6.4.1 re-INVITE"),
TAG_END());
run_ab_until(ctx, -1, reject_reinvite_401, -1, until_final_response);
TEST_1(nua_handle_has_active_call(a_call->nh));
TEST_1(nua_handle_has_active_call(b_call->nh));
free_events_in_list(ctx, a->events);
free_events_in_list(ctx, b->events);
BYE(a, a_call, a_call->nh, TAG_END());
run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
free_events_in_list(ctx, a->events);
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
free_events_in_list(ctx, b->events);
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
if (print_headings)
printf("TEST NUA-6.4.1: PASSED\n");
END();
}
int test_bye_after_receiving_401_to_update(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;
a_call->sdp = "m=audio 5008 RTP/AVP 8";
b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
/* BYE after receiving 401
A B
|-------INVITE------>|
|<----100 Trying-----|
| |
|<----180 Ringing----|
|<-------200---------|
|--------ACK-------->|
| |
|<------UPDATE-------|
|--------401-------->|
| |
|<--------BYE--------|
|------200 OK------->|
| |
*/
if (print_headings)
printf("TEST NUA-6.4.2: BYE after receiving 401 to UPDATE\n");
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)),
SIPTAG_SUBJECT_STR("NUA-6.4.2"),
SOATAG_USER_SDP_STR(a_call->sdp),
NUTAG_AUTOANSWER(0),
NUTAG_APPL_METHOD("UPDATE"),
TAG_END());
run_ab_until(ctx, -1, until_ready, -1, accept_call);
free_events_in_list(ctx, a->events);
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
free_events_in_list(ctx, b->events);
/* UPDATE A. */
UPDATE(b, b_call, b_call->nh,
SIPTAG_SUBJECT_STR("NUA-6.4.2 UPDATE"),
TAG_END());
BYE(b, b_call, b_call->nh, TAG_END()); /* Queued until nua_authenticate */
run_ab_until(ctx, -1, reject_reinvite_401, -1, until_final_response);
TEST_1(nua_handle_has_active_call(a_call->nh));
TEST_1(nua_handle_has_active_call(b_call->nh));
free_events_in_list(ctx, a->events);
free_events_in_list(ctx, b->events);
AUTHENTICATE(b, b_call, b_call->nh, TAG_END());
run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
free_events_in_list(ctx, a->events);
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
free_events_in_list(ctx, b->events);
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
if (print_headings)
printf("TEST NUA-6.4.2: PASSED\n");
END();
}
int reject_reinvite_401(CONDITION_PARAMS)
{
void *request = nua_current_request(nua);
save_event_in_list(ctx, event, ep, call);
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
return 0;
if (status < 200 && (event == nua_i_invite || event == nua_i_update)) {
RESPOND(ep, call, nh, SIP_401_UNAUTHORIZED,
NUTAG_WITH(request),
SIPTAG_WWW_AUTHENTICATE_STR("Digest realm=\"test_nua\", "
"nonce=\"nsdhfuds\", algorithm=MD5, "
"qop=\"auth\""),
TAG_END());
return 0;
}
if (event == nua_i_state) switch (callstate(tags)) {
case nua_callstate_ready:
return 1;
case nua_callstate_terminated:
if (call)
nua_handle_destroy(call->nh), call->nh = NULL;
return 1;
default:
return 0;
}
return 0;
}
int test_bye_to_invalid_contact(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;
a_call->sdp = "m=audio 5008 RTP/AVP 8";
b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
/* Early BYE 2
A B
|-------INVITE------>|
|<----100 Trying-----|
| |
|<----180 Ringing----|
|<-------200---------|
| |
|--------BYE-------->|
|<------200 OK-------|
|--------ACK-------->|
| |
| |
*/
if (print_headings)
printf("TEST NUA-6.4.3: BYE call when completing\n");
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_CONTACT(NULL),
SIPTAG_HEADER_STR("Contact: <<sip:xyzzy@com.invalid>"),
TAG_END());
run_ab_until(ctx, -1, until_ready, -1, accept_call);
/* Client transitions:
INIT -(C1)-> CALLING: nua_invite(), nua_i_state
CALLING -(C2)-> PROCEEDING: nua_r_invite(180, nua_i_state, nua_cancel()
PROCEEDING -(C6b)-> TERMINATED: nua_r_invite(487), 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);
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(e = e->next); 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);
TEST_1(!e->next);
/*
Server transitions:
INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
RECEIVED -(S2a)-> EARLY: nua_respond(180), nua_i_state
EARLY -(S6b)--> TERMINATED: nua_i_cancel, 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));
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(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
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(!e->next);
free_events_in_list(ctx, a->events);
free_events_in_list(ctx, b->events);
BYE(b, b_call, b_call->nh, TAG_END());
run_b_until(ctx, -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);
TEST_1(!nua_handle_has_active_call(b_call->nh));
TEST_1(nua_handle_has_active_call(a_call->nh));
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-6.4.3: PASSED\n");
END();
}
int test_early_bye(struct context *ctx)
{
return
test_bye_before_200(ctx) ||
test_bye_before_ack(ctx) ||
test_bye_after_receiving_401(ctx) ||
test_bye_after_sending_401(ctx) ||
test_bye_after_receiving_401_to_update(ctx) ||
test_bye_to_invalid_contact(ctx) ||
0;
}
@@ -167,6 +167,13 @@ int test_extension(struct context *ctx)
free_events_in_list(ctx, b->events);
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
nua_set_params(b->nua,
SIPTAG_ALLOW(b->allow),
NUTAG_APPL_METHOD(NULL),
NUTAG_APPL_METHOD(b->appl_method),
TAG_END());
run_b_until(ctx, nua_r_set_params, until_final_response);
if (print_headings)
printf("TEST NUA-13.1: PASSED\n");
END();
+43 -11
View File
@@ -35,6 +35,8 @@
#include "test_nua.h"
#include <sofia-sip/tport_tag.h>
#if HAVE_FUNC
#elif HAVE_FUNCTION
#define __func__ __FUNCTION__
@@ -65,6 +67,9 @@ int test_nua_init(struct context *ctx,
struct event *e;
sip_contact_t const *m = NULL;
sip_from_t const *sipaddress = NULL;
sip_allow_t const *allow = NULL;
sip_supported_t const *supported = NULL;
char const *appl_method = NULL;
url_t const *p_uri, *a_uri; /* Proxy URI */
char const *a_bind, *a_bind2;
@@ -105,7 +110,9 @@ int test_nua_init(struct context *ctx,
AUTHTAG_OPAQUE("kuik"),
AUTHTAG_DB(passwd_name),
AUTHTAG_QOP("auth-int"),
AUTHTAG_ALGORITHM("md5-sess"),
AUTHTAG_ALGORITHM("md5"),
AUTHTAG_NEXT_EXPIRES(60),
TAG_IF(ctx->proxy_logging, TPTAG_LOG(1)),
TAG_END());
ctx->proxy_tests = ctx->p != NULL;
@@ -218,22 +225,29 @@ int test_nua_init(struct context *ctx,
NUTAG_URL(a_bind),
TAG_IF(a_bind != a_bind2, NUTAG_SIPS_URL(a_bind2)),
SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8"),
NTATAG_SIP_T1X64(4000),
NTATAG_SIP_T1X64(2000),
NUTAG_INSTANCE(ctx->a.instance),
TAG_IF(ctx->a.logging, TPTAG_LOG(1)),
TAG_END());
TEST_1(ctx->a.nua);
nua_get_params(ctx->a.nua, TAG_ANY(), TAG_END());
run_a_until(ctx, nua_r_get_params, save_until_final_response);
TEST_1(e = ctx->a.events->head);
TEST_1(e = ctx->a.specials->head);
TEST(tl_gets(e->data->e_tags,
NTATAG_CONTACT_REF(m),
SIPTAG_FROM_REF(sipaddress),
TAG_END()), 2); TEST_1(m);
SIPTAG_ALLOW_REF(allow),
NUTAG_APPL_METHOD_REF(appl_method),
SIPTAG_SUPPORTED_REF(supported),
TAG_END()), 5); TEST_1(m);
TEST_1(ctx->a.contact = sip_contact_dup(ctx->home, m));
TEST_1(ctx->a.to = sip_to_dup(ctx->home, sipaddress));
TEST_1(ctx->a.allow = sip_allow_dup(ctx->home, allow));
TEST_1(ctx->a.appl_method = su_strdup(ctx->home, appl_method));
TEST_1(ctx->a.supported = sip_supported_dup(ctx->home, supported));
free_events_in_list(ctx, ctx->a.events);
free_events_in_list(ctx, ctx->a.specials);
if (print_headings)
printf("TEST NUA-2.2.1: PASSED\n");
@@ -249,19 +263,30 @@ int test_nua_init(struct context *ctx,
NUTAG_URL("sip:0.0.0.0:*"),
SOATAG_USER_SDP_STR("m=audio 5006 RTP/AVP 8 0"),
NUTAG_INSTANCE(ctx->b.instance),
/* Quicker timeout */
NTATAG_SIP_T1X64(2000),
TAG_IF(ctx->b.logging, TPTAG_LOG(1)),
TAG_END());
TEST_1(ctx->b.nua);
nua_get_params(ctx->b.nua, TAG_ANY(), TAG_END());
run_b_until(ctx, nua_r_get_params, save_until_final_response);
TEST_1(e = ctx->b.events->head);
TEST_1(e = ctx->b.specials->head);
TEST(tl_gets(e->data->e_tags,
NTATAG_CONTACT_REF(m),
SIPTAG_FROM_REF(sipaddress),
TAG_END()), 2); TEST_1(m);
SIPTAG_ALLOW_REF(allow),
NUTAG_APPL_METHOD_REF(appl_method),
SIPTAG_SUPPORTED_REF(supported),
TAG_END()), 5); TEST_1(m);
TEST_1(ctx->b.contact = sip_contact_dup(ctx->home, m));
TEST_1(ctx->b.to = sip_to_dup(ctx->home, sipaddress));
free_events_in_list(ctx, ctx->b.events);
TEST_1(ctx->b.allow = sip_allow_dup(ctx->home, allow));
TEST_1(ctx->b.appl_method = su_strdup(ctx->home, appl_method));
TEST_1(ctx->b.supported = sip_supported_dup(ctx->home, supported));
free_events_in_list(ctx, ctx->b.specials);
if (print_headings)
printf("TEST NUA-2.2.2: PASSED\n");
@@ -277,19 +302,26 @@ int test_nua_init(struct context *ctx,
NUTAG_URL("sip:0.0.0.0:*"),
SOATAG_USER_SDP_STR("m=audio 5400 RTP/AVP 8 0"),
NUTAG_INSTANCE(ctx->c.instance),
TAG_IF(ctx->c.logging, TPTAG_LOG(1)),
TAG_END());
TEST_1(ctx->c.nua);
nua_get_params(ctx->c.nua, TAG_ANY(), TAG_END());
run_c_until(ctx, nua_r_get_params, save_until_final_response);
TEST_1(e = ctx->c.events->head);
TEST_1(e = ctx->c.specials->head);
TEST(tl_gets(e->data->e_tags,
NTATAG_CONTACT_REF(m),
SIPTAG_FROM_REF(sipaddress),
TAG_END()), 2); TEST_1(m);
SIPTAG_ALLOW_REF(allow),
NUTAG_APPL_METHOD_REF(appl_method),
SIPTAG_SUPPORTED_REF(supported),
TAG_END()), 5); TEST_1(m);
TEST_1(ctx->c.contact = sip_contact_dup(ctx->home, m));
TEST_1(ctx->c.to = sip_to_dup(ctx->home, sipaddress));
free_events_in_list(ctx, ctx->c.events);
TEST_1(ctx->c.allow = sip_allow_dup(ctx->home, allow));
TEST_1(ctx->c.appl_method = su_strdup(ctx->home, appl_method));
TEST_1(ctx->c.supported = sip_supported_dup(ctx->home, supported));
free_events_in_list(ctx, ctx->c.specials);
if (print_headings)
printf("TEST NUA-2.2.3: PASSED\n");
+118 -3
View File
@@ -91,6 +91,8 @@ struct nat {
struct binding *bindings;
struct nat_filter *in_filters, *out_filters;
/* True if we act in symmetric way */
int symmetric;
/* True if we do logging */
@@ -153,6 +155,15 @@ static int tcp_out_to_in(struct nat *, su_wait_t *wait, struct binding *);
static int invalidate_binding(struct binding *b);
LIST_PROTOS(static, nat_filter, struct nat_filter);
struct nat_filter
{
struct nat_filter *next, **prev;
size_t (*condition)(void *arg, void *message, size_t len);
void *arg;
};
/* nat entry point */
static int
test_nat_init(su_root_t *root, struct nat *nat)
@@ -670,19 +681,35 @@ static int udp_in_to_out(struct nat *nat, su_wait_t *wait, struct binding *b)
{
int events;
ssize_t n, m;
size_t len, filtered;
struct nat_filter *f;
events = su_wait_events(wait, b->in_socket);
n = su_recv(b->in_socket, nat->buffer, sizeof nat->buffer, 0);
if (n < 0) {
if (n == -1) {
su_perror("udp_in_to_out: recv");
return 0;
}
len = (size_t)n;
for (f = nat->out_filters; f; f = f->next) {
filtered = f->condition(f->arg, nat->buffer, len);
if (filtered != len) {
if (nat->logging)
printf("nat: udp filtered "MOD_ZU" from %s => "MOD_ZU" to %s\n",
len, b->in_name, filtered, b->out_name);
if (filtered == 0)
return 0;
len = filtered;
}
}
if (nat->symmetric)
m = su_send(b->out_socket, nat->buffer, n, 0);
m = su_send(b->out_socket, nat->buffer, len, 0);
else
m = su_sendto(b->out_socket, nat->buffer, n, 0,
m = su_sendto(b->out_socket, nat->buffer, len, 0,
nat->out_address, nat->out_addrlen);
if (nat->logging)
@@ -696,6 +723,8 @@ static int udp_out_to_in(struct nat *nat, su_wait_t *wait, struct binding *b)
{
int events;
ssize_t n, m;
size_t len, filtered;
struct nat_filter *f;
events = su_wait_events(wait, b->out_socket);
@@ -705,6 +734,20 @@ static int udp_out_to_in(struct nat *nat, su_wait_t *wait, struct binding *b)
return 0;
}
len = (size_t)n;
for (f = nat->in_filters; f; f = f->next) {
filtered = f->condition(f->arg, nat->buffer, len);
if (filtered != len) {
if (nat->logging)
printf("nat: udp filtered "MOD_ZU" from %s => "MOD_ZU" to %s\n",
len, b->out_name, filtered, b->in_name);
if (filtered == 0)
return 0;
len = filtered;
}
}
m = su_send(b->in_socket, nat->buffer, n, 0);
if (nat->logging)
@@ -882,3 +925,75 @@ static int invalidate_binding(struct binding *b)
return 0;
}
LIST_BODIES(static, nat_filter, struct nat_filter, next, prev);
struct args {
struct nat *nat;
struct nat_filter *f;
int outbound;
};
int execute_nat_filter_insert(void *_args)
{
struct args *a = (struct args *)_args;
if (a->outbound)
nat_filter_insert(&a->nat->out_filters, a->f);
else
nat_filter_insert(&a->nat->in_filters, a->f);
return 0;
}
int execute_nat_filter_remove(void *_args)
{
struct args *a = (struct args *)_args;
nat_filter_remove(a->f);
return 0;
}
struct nat_filter *test_nat_add_filter(struct nat *nat,
size_t (*condition)(void *arg,
void *message,
size_t len),
void *arg,
int outbound)
{
struct args a[1];
if (nat == NULL)
return su_seterrno(EFAULT), NULL;
a->nat = nat;
a->f = su_zalloc(nat->home, sizeof *a->f);
a->outbound = outbound;
if (a->f) {
a->f->condition = condition;
a->f->arg = arg;
if (su_task_execute(su_clone_task(nat->clone),
execute_nat_filter_insert, a, NULL) < 0)
su_free(nat->home, a->f), a->f = NULL;
}
return a->f;
}
int test_nat_remove_filter(struct nat *nat,
struct nat_filter *filter)
{
struct args a[1];
if (nat == NULL)
return su_seterrno(EFAULT);
a->nat = nat;
a->f = filter;
if (su_task_execute(su_clone_task(nat->clone),
execute_nat_filter_remove, a, NULL) < 0)
return -1;
su_free(nat->home, filter);
return 0;
}
@@ -31,6 +31,7 @@
SOFIA_BEGIN_DECLS
struct nat;
struct nat_filter;
struct nat *test_nat_create(su_root_t *, int family,
tag_type_t, tag_value_t, ...);
@@ -42,6 +43,18 @@ int test_nat_public(struct nat *nat, void const *address, int addrlen);
int test_nat_flush(struct nat *nat);
struct nat_filter *test_nat_add_filter(struct nat *nat,
size_t (*condition)(void *arg,
void *message,
size_t len),
void *arg,
int outbound);
enum { nat_inbound, nat_outbound };
int test_nat_remove_filter(struct nat *nat,
struct nat_filter *filter);
/* Tags */
/** If true, act as symmetric nat. */
+42 -11
View File
@@ -72,20 +72,29 @@ static RETSIGTYPE sig_alarm(int s)
static char const options_usage[] =
" -v | --verbose be verbose\n"
" -q | --quiet be quiet\n"
" -a | --abort abort on error\n"
" -s use only single thread\n"
" -l level set logging level (0 by default)\n"
" -e | --events print nua events\n"
" -A print nua events for A\n"
" -B print nua events for B\n"
" -C print nua events for C\n"
" --log=a log messages for A\n"
" --log=b log messages for B\n"
" --log=c log messages for C\n"
" --log=proxy log messages for proxy\n"
" --attach print pid, wait for a debugger to be attached\n"
" --no-proxy do not use internal proxy\n"
" --no-nat do not use internal \"nat\"\n"
" --symmetric run internal \"nat\" in symmetric mode\n"
" -N print events from internal \"nat\"\n"
" --loop loop main tests for ever\n"
" --no-alarm don't ask for guard ALARM\n"
" -p uri specify uri of outbound proxy (implies --no-proxy)\n"
" --proxy-tests run tests involving proxy, too\n"
#if SU_HAVE_OSX_CF_API /* If compiled with CoreFoundation events */
" --osx-runloop use OSX CoreFoundation runloop instead of poll() loop\n"
#endif
" -k do not exit after first error\n"
;
@@ -99,7 +108,7 @@ void usage(int exitcode)
int main(int argc, char *argv[])
{
int retval = 0;
int i, o_quiet = 0, o_attach = 0, o_alarm = 1;
int i, o_quiet = 0, o_attach = 0, o_alarm = 1, o_loop = 0;
int o_events_init = 0, o_events_a = 0, o_events_b = 0, o_events_c = 0;
int o_iproxy = 1, o_inat = 1;
int o_inat_symmetric = 0, o_inat_logging = 0, o_expensive = 0;
@@ -199,6 +208,21 @@ int main(int argc, char *argv[])
else if (strcmp(argv[i], "--no-alarm") == 0) {
o_alarm = 0;
}
else if (strcmp(argv[i], "--loop") == 0) {
o_alarm = 0, o_loop = 1;
}
else if (strcmp(argv[i], "--log=a") == 0) {
ctx->a.logging = 1;
}
else if (strcmp(argv[i], "--log=b") == 0) {
ctx->b.logging = 1;
}
else if (strcmp(argv[i], "--log=c") == 0) {
ctx->c.logging = 1;
}
else if (strcmp(argv[i], "--log=proxy") == 0) {
ctx->proxy_logging = 1;
}
#if SU_HAVE_OSX_CF_API /* If compiled with CoreFoundation events */
else if (strcmp(argv[i], "--osx-runloop") == 0) {
ctx->osx_runloop = 1;
@@ -210,8 +234,10 @@ int main(int argc, char *argv[])
else if (argv[i][0] != '-') {
break;
}
else
else {
fprintf(stderr, "test_nua: unknown argument \"%s\"\n\n", argv[i]);
usage(1);
}
}
if (o_attach) {
@@ -222,8 +248,15 @@ int main(int argc, char *argv[])
}
#if HAVE_ALARM
else if (o_alarm) {
alarm(o_expensive ? 60 : 120);
signal(SIGALRM, sig_alarm);
if (o_expensive) {
printf("%s: extending timeout to %u because expensive tests\n",
name, 240);
alarm(240);
}
else {
alarm(120);
}
}
#endif
@@ -279,17 +312,12 @@ int main(int argc, char *argv[])
if (retval == 0 && o_inat)
retval |= test_nat_timeout(ctx);
if (retval == 0) {
retval |= test_extension(ctx); SINGLE_FAILURE_CHECK();
while (retval == 0) {
retval |= test_basic_call(ctx); SINGLE_FAILURE_CHECK();
retval |= test_reject_a(ctx); SINGLE_FAILURE_CHECK();
retval |= test_reject_b(ctx); SINGLE_FAILURE_CHECK();
retval |= test_reject_302(ctx); SINGLE_FAILURE_CHECK();
retval |= test_reject_401(ctx); SINGLE_FAILURE_CHECK();
retval |= test_mime_negotiation(ctx); SINGLE_FAILURE_CHECK();
retval |= test_reject_401_aka(ctx); SINGLE_FAILURE_CHECK();
retval |= test_rejects(ctx); SINGLE_FAILURE_CHECK();
retval |= test_call_cancel(ctx); SINGLE_FAILURE_CHECK();
retval |= test_call_destroy(ctx); SINGLE_FAILURE_CHECK();
retval |= test_offer_answer(ctx); SINGLE_FAILURE_CHECK();
retval |= test_early_bye(ctx); SINGLE_FAILURE_CHECK();
retval |= test_reinvites(ctx); SINGLE_FAILURE_CHECK();
retval |= test_session_timer(ctx); SINGLE_FAILURE_CHECK();
@@ -297,6 +325,9 @@ int main(int argc, char *argv[])
retval |= test_100rel(ctx); SINGLE_FAILURE_CHECK();
retval |= test_simple(ctx); SINGLE_FAILURE_CHECK();
retval |= test_events(ctx); SINGLE_FAILURE_CHECK();
retval |= test_extension(ctx); SINGLE_FAILURE_CHECK();
if (!o_loop)
break;
}
if (ctx->proxy_tests && (retval == 0 || !ctx->p))
+21 -9
View File
@@ -126,10 +126,14 @@ struct context
int threading, proxy_tests, expensive, quit_on_single_failure, osx_runloop;
char const *external_proxy;
int proxy_logging;
struct endpoint {
char name[4];
struct context *ctx; /* Backpointer */
int logging;
int running;
condition_function *next_condition;
@@ -138,6 +142,10 @@ struct context
sip_contact_t *contact;
sip_from_t *to;
sip_allow_t *allow;
char const *appl_method;
sip_supported_t *supported;
printer_function *printer;
char const *instance;
@@ -158,12 +166,11 @@ struct context
struct eventlist specials[1];
/* State flags for complex scenarios */
union {
struct {
unsigned bit0:1, bit1:1, bit2:1, bit3:1;
unsigned bit4:1, bit5:1, bit6:1, bit7:1;
} b;
struct {
unsigned n;
unsigned bit0:1, bit1:1, bit2:1, bit3:1;
unsigned bit4:1, bit5:1, bit6:1, bit7:1;
unsigned :0;
} flags;
} a, b, c;
@@ -185,6 +192,9 @@ int save_event_in_list(struct context *,
struct call *);
void free_events_in_list(struct context *,
struct eventlist *);
void free_event_in_list(struct context *ctx,
struct eventlist *list,
struct event *e);
#define CONDITION_PARAMS \
nua_event_t event, \
@@ -204,6 +214,9 @@ int save_until_special(CONDITION_PARAMS);
int until_terminated(CONDITION_PARAMS);
int until_ready(CONDITION_PARAMS);
int accept_call(CONDITION_PARAMS);
int cancel_when_ringing(CONDITION_PARAMS);
int accept_notify(CONDITION_PARAMS);
void a_callback(nua_event_t event,
int status, char const *phrase,
@@ -316,11 +329,10 @@ int test_nat_timeout(struct context *ctx);
int test_unregister(struct context *ctx);
int test_basic_call(struct context *ctx);
int test_reject_a(struct context *ctx);
int test_reject_b(struct context *ctx);
int test_reject_302(struct context *ctx);
int test_reject_401(struct context *ctx);
int test_offer_answer(struct context *ctx);
int test_rejects(struct context *ctx);
int test_mime_negotiation(struct context *ctx);
int test_call_timeouts(struct context *ctx);
int test_reject_401_aka(struct context *ctx);
int test_call_cancel(struct context *ctx);
int test_call_destroy(struct context *ctx);
@@ -210,7 +210,10 @@ int test_stack_errors(struct context *ctx)
run_a_until(ctx, -1, save_until_final_response);
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_unregister);
TEST(e->data->e_status, 401);
if (e->data->e_status == 401)
TEST(e->data->e_status, 401);
else
TEST(e->data->e_status, 406);
TEST_1(!e->next);
free_events_in_list(ctx, a->events);
@@ -117,12 +117,12 @@ int test_nua_params(struct context *ctx)
nua_get_params(ctx->a.nua, TAG_ANY(), TAG_END());
run_a_until(ctx, nua_r_get_params, save_until_final_response);
TEST_1(e = ctx->a.events->head);
TEST_1(e = ctx->a.specials->head);
TEST_E(e->data->e_event, nua_r_get_params);
for (n = 0, t = e->data->e_tags; t; n++, t = tl_next(t))
;
TEST_1(n > 32);
free_events_in_list(ctx, ctx->a.events);
free_events_in_list(ctx, ctx->a.specials);
nh = nua_handle(ctx->a.nua, NULL, TAG_END()); TEST_1(nh);
nua_handle_unref(nh);
@@ -148,9 +148,12 @@ int test_nua_params(struct context *ctx)
SIPTAG_SUPPORTED_STR("test"),
SIPTAG_ALLOW_STR("DWIM, OPTIONS, INFO"),
NUTAG_APPL_METHOD(NULL),
NUTAG_APPL_METHOD("INVITE, REGISTER, PUBLISH, SUBSCRIBE"),
SIPTAG_ALLOW_EVENTS_STR("reg"),
SIPTAG_USER_AGENT_STR("test_nua/1.0"),
SIPTAG_ORGANIZATION_STR("Open Laboratory"),
NUTAG_M_DISPLAY("XXX"),
@@ -190,6 +193,7 @@ int test_nua_params(struct context *ctx)
NUTAG_MEDIA_FEATURES(1),
NUTAG_SERVICE_ROUTE_ENABLE(0),
NUTAG_PATH_ENABLE(0),
NUTAG_AUTH_CACHE(nua_auth_cache_challenged),
NUTAG_REFER_EXPIRES(333),
NUTAG_REFER_WITH_ID(0),
NUTAG_SUBSTATE(nua_substate_pending),
@@ -211,10 +215,13 @@ int test_nua_params(struct context *ctx)
SIPTAG_ALLOW(sip_allow_make(tmphome, "INFO")),
NUTAG_ALLOW("ACK, INFO"),
NUTAG_APPL_METHOD("NOTIFY"),
SIPTAG_ALLOW_EVENTS_STR("reg"),
SIPTAG_ALLOW_EVENTS(sip_allow_events_make(tmphome, "presence")),
NUTAG_ALLOW_EVENTS("presence.winfo"),
SIPTAG_USER_AGENT(sip_user_agent_make(tmphome, "test_nua")),
SIPTAG_ORGANIZATION(sip_organization_make(tmphome, "Pussy Galore's Flying Circus")),
@@ -262,12 +269,14 @@ int test_nua_params(struct context *ctx)
int media_features = -1;
int service_route_enable = -1;
int path_enable = -1;
int auth_cache = -1;
unsigned refer_expires = (unsigned)-1;
int refer_with_id = -1;
int substate = -1;
sip_allow_t const *allow = NONE;
char const *allow_str = "NONE";
char const *appl_method = "NONE";
sip_allow_events_t const *allow_events = NONE;
char const *allow_events_str = "NONE";
sip_supported_t const *supported = NONE;
@@ -291,7 +300,7 @@ int test_nua_params(struct context *ctx)
nua_get_params(ctx->a.nua, TAG_ANY(), TAG_END());
run_a_until(ctx, nua_r_get_params, save_until_final_response);
TEST_1(e = ctx->a.events->head);
TEST_1(e = ctx->a.specials->head);
TEST_E(e->data->e_event, nua_r_get_params);
n = tl_gets(e->data->e_tags,
@@ -324,6 +333,7 @@ int test_nua_params(struct context *ctx)
NUTAG_MEDIA_FEATURES_REF(media_features),
NUTAG_SERVICE_ROUTE_ENABLE_REF(service_route_enable),
NUTAG_PATH_ENABLE_REF(path_enable),
NUTAG_AUTH_CACHE_REF(auth_cache),
NUTAG_REFER_EXPIRES_REF(refer_expires),
NUTAG_REFER_WITH_ID_REF(refer_with_id),
NUTAG_SUBSTATE_REF(substate),
@@ -332,6 +342,7 @@ int test_nua_params(struct context *ctx)
SIPTAG_SUPPORTED_STR_REF(supported_str),
SIPTAG_ALLOW_REF(allow),
SIPTAG_ALLOW_STR_REF(allow_str),
NUTAG_APPL_METHOD_REF(appl_method),
SIPTAG_ALLOW_EVENTS_REF(allow_events),
SIPTAG_ALLOW_EVENTS_STR_REF(allow_events_str),
SIPTAG_USER_AGENT_REF(user_agent),
@@ -353,7 +364,7 @@ int test_nua_params(struct context *ctx)
NUTAG_INSTANCE_REF(instance),
TAG_END());
TEST(n, 46);
TEST(n, 48);
TEST_S(sip_header_as_string(tmphome, (void *)from), Alice);
TEST_S(from_str, Alice);
@@ -383,12 +394,14 @@ int test_nua_params(struct context *ctx)
TEST(media_features, 1);
TEST(service_route_enable, 0);
TEST(path_enable, 0);
TEST(auth_cache, nua_auth_cache_challenged);
TEST(refer_expires, 333);
TEST(refer_with_id, 0);
TEST(substate, nua_substate_pending);
TEST_S(sip_header_as_string(tmphome, (void *)allow), "OPTIONS, INFO, ACK");
TEST_S(allow_str, "OPTIONS, INFO, ACK");
TEST_S(appl_method, "INVITE, REGISTER, PUBLISH, SUBSCRIBE, NOTIFY");
TEST_S(sip_header_as_string(tmphome, (void *)allow_events),
"reg, presence, presence.winfo");
TEST_S(allow_events_str, "reg, presence, presence.winfo");
@@ -414,7 +427,7 @@ int test_nua_params(struct context *ctx)
TEST_S(m_features, expect_m_features); }
TEST_S(outbound, "foo");
free_events_in_list(ctx, ctx->a.events);
free_events_in_list(ctx, ctx->a.specials);
}
/* Test that only those tags that have been set per handle are returned by nua_get_hparams() */
@@ -446,6 +459,7 @@ int test_nua_params(struct context *ctx)
int media_features = -1;
int service_route_enable = -1;
int path_enable = -1;
int auth_cache = -1;
unsigned refer_expires = (unsigned)-1;
int refer_with_id = -1;
int substate = -1;
@@ -504,6 +518,7 @@ int test_nua_params(struct context *ctx)
NUTAG_MEDIA_FEATURES_REF(media_features),
NUTAG_SERVICE_ROUTE_ENABLE_REF(service_route_enable),
NUTAG_PATH_ENABLE_REF(path_enable),
NUTAG_AUTH_CACHE_REF(auth_cache),
NUTAG_SUBSTATE_REF(substate),
SIPTAG_SUPPORTED_REF(supported),
@@ -556,6 +571,7 @@ int test_nua_params(struct context *ctx)
TEST(media_features, -1);
TEST(service_route_enable, -1);
TEST(path_enable, -1);
TEST(auth_cache, -1);
TEST(refer_expires, (unsigned)-1);
TEST(refer_with_id, -1);
TEST(substate, -1);
@@ -0,0 +1,479 @@
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@nokia.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
/**@CFILE test_offer_answer.c
* @brief Test offer/answer failures.
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
*
* @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
*/
#include "config.h"
#include "test_nua.h"
#include <sofia-sip/su_tag_class.h>
#if HAVE_FUNC
#elif HAVE_FUNCTION
#define __func__ __FUNCTION__
#else
#define __func__ "test_offer_answer"
#endif
/* ======================================================================== */
/* Send offer in INVITE, no answer:
A B
--nua_invite()-->| |
|-------INVITE------>|
<--nua_i_state---| |
|<----100 Trying-----|
| |
|<--------180--------|
<--nua_r_invite--| |
<--nua_i_state---| |
|<------200 OK-------|
<--nua_r_invite--| |
|--------ACK-------->|
|--------BYE-------->|
<--nua_i_state---| |
|<-------200 OK------|
<--nua_r_bye-----| |
<--nua_i_state---| |
Client transitions:
INIT -(C1)-> CALLING -(C2a)-> PROCEEDING -(C3+C4)->
TERMINATING -> TERMINATED
Server transitions:
INIT -(S1)-> RECEIVED -(S2a)-> EARLY -(S3b)-> COMPLETED -(S4)-> READY
-> TERMINATED
*/
int no_media_terminated(CONDITION_PARAMS);
int test_no_answer_1(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;
sip_t *sip;
if (print_headings)
printf("TEST NUA-6.5: No SDP answer from callee\n");
a_call->sdp = "m=audio 5008 RTP/AVP 8";
b_call->sdp = NULL;
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
TEST_1(!nua_handle_has_active_call(a_call->nh));
TEST_1(!nua_handle_has_call_on_hold(a_call->nh));
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),
NUTAG_M_USERNAME("a+a"),
NUTAG_M_DISPLAY("Alice"),
TAG_END());
run_ab_until(ctx, -1, until_terminated, -1, no_media_terminated);
TEST_1(!nua_handle_has_active_call(a_call->nh));
TEST_1(!nua_handle_has_call_on_hold(a_call->nh));
TEST_1(!nua_handle_has_active_call(b_call->nh));
TEST_1(!nua_handle_has_call_on_hold(b_call->nh));
/* Client transitions:
INIT -(C1)-> CALLING: nua_invite(), nua_i_state
CALLING -(C3)-> PROCEEDING: nua_r_invite, nua_i_state
PROCEEDING -(C3a+C5)-> TERMINATING: nua_r_invite, nua_i_state
TERMINATING -(C12)-> TERMINATED: nua_r_bye, 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(sip = sip_object(e->data->e_msg));
TEST_1(!sip->sip_payload);
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_answer_recv(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
TEST(e->data->e_status, 200);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(!sip->sip_payload);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_media_error);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminating); /* TERMINATING */
TEST_1(e = e->next); 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, 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
READY -(T1)-> TERMINATED: nua_i_bye, 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(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_contact);
TEST_S(sip->sip_contact->m_display, "Alice");
TEST_S(sip->sip_contact->m_url->url_user, "a+a");
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));
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_state);
TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
TEST_1(!is_answer_sent(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
TEST_1(sip = sip_object(e->data->e_msg));
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_answer_recv(e->data->e_tags));
TEST_1(!is_offer_recv(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_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, a->events);
free_events_in_list(ctx, b->events);
TEST_1(!nua_handle_has_active_call(a_call->nh));
TEST_1(!nua_handle_has_active_call(b_call->nh));
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-6.5: PASSED\n");
END();
}
int no_media_terminated(CONDITION_PARAMS)
{
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
return 0;
save_event_in_list(ctx, event, ep, call);
switch (callstate(tags)) {
case nua_callstate_received:
RESPOND(ep, call, nh, SIP_180_RINGING,
NUTAG_MEDIA_ENABLE(0),
TAG_END());
return 0;
case nua_callstate_early:
RESPOND(ep, call, nh, SIP_200_OK,
NUTAG_MEDIA_ENABLE(0),
TAG_END());
return 0;
case nua_callstate_terminated:
if (call)
nua_handle_destroy(call->nh), call->nh = NULL;
return 1;
default:
return 0;
}
}
int accept_call_until_terminated(CONDITION_PARAMS);
/* No offer in INVITE, offer in 200 OK, no answer in ACK */
int test_no_answer_2(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;
sip_t const *sip;
if (print_headings)
printf("TEST NUA-6.6: No SDP offer from caller\n");
a_call->sdp = "v=0\r\n"
"o=- 1 1 IN IP4 127.0.0.1\r\n"
"s=-\r\n"
"c=IN IP4 127.0.0.1\r\n"
"t=0 0\r\n"
"m=audio 5008 RTP/AVP 8\r\n";
b_call->sdp =
"v=0\r\n"
"o=- 2 1 IN IP4 127.0.0.1\r\n"
"s=-\r\n"
"c=IN IP4 127.0.0.1\r\n"
"t=0 0\r\n"
"m=audio 5010 RTP/AVP 0 8\r\n";
TEST_1(a_call->nh = nua_handle(a->nua, a_call,
SIPTAG_TO_STR("<sip:b@x.org>"),
TAG_END()));
TEST_1(!nua_handle_has_active_call(a_call->nh));
TEST_1(!nua_handle_has_call_on_hold(a_call->nh));
INVITE(a, a_call, a_call->nh,
NUTAG_MEDIA_ENABLE(0),
NUTAG_URL(b->contact->m_url),
NUTAG_AUTOACK(1),
TAG_END());
run_ab_until(ctx, -1, until_terminated,
-1, accept_call_until_terminated);
/* 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, 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_answer_recv(e->data->e_tags));
TEST_1(!is_offer_recv(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
TEST(e->data->e_status, 200);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_content_type);
TEST_S(sip->sip_content_type->c_type, "application/sdp");
TEST_1(sip->sip_payload); /* there is sdp in 200 OK */
TEST_1(sip->sip_contact);
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_answer_sent(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_bye);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* READY */
TEST_1(!e->next);
free_events_in_list(ctx, a->events);
TEST_1(!nua_handle_has_active_call(a_call->nh));
TEST_1(!nua_handle_has_call_on_hold(a_call->nh));
/*
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));
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_state);
TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
TEST_1(is_offer_sent(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_media_error);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminating); /* TERMINATING */
TEST_1(e = e->next); 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);
TEST_1(!nua_handle_has_active_call(b_call->nh));
TEST_1(!nua_handle_has_call_on_hold(b_call->nh));
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-6.6: PASSED\n");
END();
}
int accept_call_until_terminated(CONDITION_PARAMS)
{
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
return 0;
save_event_in_list(ctx, event, ep, call);
switch (callstate(tags)) {
case nua_callstate_received:
RESPOND(ep, call, nh, SIP_180_RINGING,
TAG_END());
return 0;
case nua_callstate_early:
RESPOND(ep, call, nh, SIP_200_OK,
NUTAG_MEDIA_ENABLE(1),
TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
TAG_END());
return 0;
case nua_callstate_terminated:
if (call)
nua_handle_destroy(call->nh), call->nh = NULL;
return 1;
default:
return 0;
}
}
/* No offer in INVITE, no user SDP in 200 OK */
int test_missing_user_sdp(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;
if (print_headings)
printf("TEST NUA-6.6.2: No SDP offer from caller\n");
a_call->sdp = "v=0\r\n"
"o=- 1 1 IN IP4 127.0.0.1\r\n"
"s=-\r\n"
"c=IN IP4 127.0.0.1\r\n"
"t=0 0\r\n"
"m=audio 5008 RTP/AVP 8\r\n";
b_call->sdp = NULL;
nua_set_params(b->nua, NUTAG_MEDIA_ENABLE(0), 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_STR("<sip:b@x.org>"),
TAG_END()));
TEST_1(!nua_handle_has_active_call(a_call->nh));
TEST_1(!nua_handle_has_call_on_hold(a_call->nh));
INVITE(a, a_call, a_call->nh,
NUTAG_MEDIA_ENABLE(0),
NUTAG_URL(b->contact->m_url),
NUTAG_AUTOACK(1),
TAG_END());
run_ab_until(ctx, -1, until_terminated,
-1, accept_call_until_terminated);
/* 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, 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_answer_recv(e->data->e_tags));
TEST_1(!is_offer_recv(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
TEST(e->data->e_status, 500);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* READY */
TEST_1(!e->next);
free_events_in_list(ctx, a->events);
TEST_1(!nua_handle_has_active_call(a_call->nh));
TEST_1(!nua_handle_has_call_on_hold(a_call->nh));
/*
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));
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_error);
TEST(e->data->e_status, 500);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* COMPLETED */
TEST_1(!e->next);
free_events_in_list(ctx, b->events);
TEST_1(!nua_handle_has_active_call(b_call->nh));
TEST_1(!nua_handle_has_call_on_hold(b_call->nh));
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
nua_set_params(b->nua,
NUTAG_MEDIA_ENABLE(1),
SOATAG_USER_SDP_STR("m=audio 5006 RTP/AVP 8 0"),
TAG_END());
run_b_until(ctx, nua_r_set_params, until_final_response);
if (print_headings)
printf("TEST NUA-6.6.2: PASSED\n");
END();
}
int test_offer_answer(struct context *ctx)
{
return
test_no_answer_1(ctx) ||
test_no_answer_2(ctx) ||
test_missing_user_sdp(ctx) ||
0;
}
+51 -20
View File
@@ -44,7 +44,7 @@
int save_events(CONDITION_PARAMS)
{
return save_event_in_list(ctx, event, ep, ep->call) == event_is_normal;
return save_event_in_list(ctx, event, ep, call) == event_is_normal;
}
int until_final_response(CONDITION_PARAMS)
@@ -54,7 +54,7 @@ int until_final_response(CONDITION_PARAMS)
int save_until_final_response(CONDITION_PARAMS)
{
save_event_in_list(ctx, event, ep, ep->call);
save_event_in_list(ctx, event, ep, call);
return event >= nua_r_set_params && status >= 200;
}
@@ -64,13 +64,13 @@ int save_until_final_response(CONDITION_PARAMS)
*/
int save_until_received(CONDITION_PARAMS)
{
return save_event_in_list(ctx, event, ep, ep->call) == event_is_normal;
return save_event_in_list(ctx, event, ep, call) == event_is_normal;
}
/** Save events until nua_i_outbound is received. */
int save_until_special(CONDITION_PARAMS)
{
return save_event_in_list(ctx, event, ep, ep->call) == event_is_special;
return save_event_in_list(ctx, event, ep, call) == event_is_special;
}
/* Return call state from event tag list */
@@ -143,34 +143,49 @@ void print_event(nua_event_t event,
sip_t const *sip,
tagi_t tags[])
{
tagi_t const *t;
if (event == nua_i_state) {
fprintf(stderr, "%s.nua(%p): event %s %s\n",
ep->name, nh, nua_event_name(event),
ep->name, (void *)nh, nua_event_name(event),
nua_callstate_name(callstate(tags)));
}
else if ((int)event >= nua_r_set_params) {
fprintf(stderr, "%s.nua(%p): event %s status %u %s\n",
ep->name, nh, nua_event_name(event), status, phrase);
t = tl_find(tags, nutag_substate);
if (t) {
fprintf(stderr, "%s.nua(%p): event %s status %u %s (%s)\n",
ep->name, (void*)nh, nua_event_name(event), status, phrase,
nua_substate_name(t->t_value));
}
else {
fprintf(stderr, "%s.nua(%p): event %s status %u %s\n",
ep->name, (void *)nh, nua_event_name(event), status, phrase);
}
}
else if (event == nua_i_notify) {
t = tl_find(tags, nutag_substate);
fprintf(stderr, "%s.nua(%p): event %s %s (%s)\n",
ep->name, (void *)nh, nua_event_name(event), phrase,
nua_substate_name(t ? t->t_value : 0));
}
else if ((int)event >= 0) {
fprintf(stderr, "%s.nua(%p): event %s %s\n",
ep->name, nh, nua_event_name(event), phrase);
ep->name, (void *)nh, nua_event_name(event), phrase);
}
else if (status > 0) {
fprintf(stderr, "%s.nua(%p): call %s() with status %u %s\n",
ep->name, nh, operation, status, phrase);
ep->name, (void *)nh, operation, status, phrase);
}
else {
tagi_t const *t;
t = tl_find(tags, siptag_subject_str);
if (t && t->t_value) {
char const *subject = (char const *)t->t_value;
fprintf(stderr, "%s.nua(%p): call %s() \"%s\"\n",
ep->name, nh, operation, subject);
ep->name, (void *)nh, operation, subject);
}
else
fprintf(stderr, "%s.nua(%p): call %s()\n",
ep->name, nh, operation);
ep->name, (void *)nh, operation);
}
if ((tstflags & tst_verbatim) && tags)
@@ -202,10 +217,11 @@ void ep_callback(nua_event_t event,
}
}
if ((ep->next_event == -1 || ep->next_event == event) &&
(ep->next_condition == NULL ||
if ((ep->next_condition == NULL ||
ep->next_condition(event, status, phrase,
nua, ctx, ep, nh, call, sip, tags)))
nua, ctx, ep, nh, call, sip, tags))
&&
(ep->next_event == -1 || ep->next_event == event))
ep->running = 0;
ep->last_event = event;
@@ -256,21 +272,21 @@ void run_abc_until(struct context *ctx,
a->last_event = -1;
a->running = a_condition != NULL && a_condition != save_events;
a->running |= a_event != -1;
a->flags.n = 0;
memset(&a->flags, 0, sizeof a->flags);
b->next_event = b_event;
b->next_condition = b_condition;
b->last_event = -1;
b->running = b_condition != NULL && b_condition != save_events;
b->running |= b_event != -1;
b->flags.n = 0;
memset(&b->flags, 0, sizeof b->flags);
c->next_event = c_event;
c->next_condition = c_condition;
c->last_event = -1;
c->running = c_condition != NULL && c_condition != save_events;
c->running |= c_event != -1;
c->flags.n = 0;
memset(&c->flags, 0, sizeof c->flags);
for (; a->running || b->running || c->running;) {
su_root_step(ctx->root, 1000);
@@ -379,7 +395,7 @@ int RESPOND(struct endpoint *ep,
return 0;
}
/* Destroy an handle */
/* Destroy a handle */
int DESTROY(struct endpoint *ep,
struct call *call,
nua_handle_t *nh)
@@ -450,7 +466,7 @@ int save_event_in_list(struct context *ctx,
return action;
}
/* Save nua event in endpoint list */
/* Free nua events from endpoint list */
void free_events_in_list(struct context *ctx,
struct eventlist *list)
{
@@ -466,6 +482,21 @@ void free_events_in_list(struct context *ctx,
list->tail = &list->head;
}
void free_event_in_list(struct context *ctx,
struct eventlist *list,
struct event *e)
{
if (e) {
if ((*e->prev = e->next))
e->next->prev = e->prev;
nua_destroy_event(e->saved_event);
su_free(ctx->home, e);
if (list->head == NULL)
list->tail = &list->head;
}
}
int is_special(nua_event_t e)
{
if (e == nua_i_active || e == nua_i_terminated)
+61 -20
View File
@@ -52,6 +52,7 @@ struct binding;
#include <sofia-sip/auth_module.h>
#include <sofia-sip/su_tagarg.h>
#include <sofia-sip/msg_addr.h>
#include <sofia-sip/hostdomain.h>
#include <stdlib.h>
#include <assert.h>
@@ -228,9 +229,10 @@ test_proxy_init(su_root_t *root, struct proxy *proxy)
URL_STRING_MAKE("sip:0.0.0.0:*"),
NULL, NULL,
NTATAG_UA(0),
NTATAG_CANCEL_487(0),
NTATAG_SERVER_RPORT(1),
NTATAG_CLIENT_RPORT(1),
TAG_END());
TAG_NEXT(proxy->tags));
proxy->transport_contacts = create_transport_contacts(proxy);
@@ -308,7 +310,7 @@ test_proxy_deinit(su_root_t *root, struct proxy *proxy)
free(proxy->tags);
}
/* Create tst proxy object */
/* Create test proxy object */
struct proxy *test_proxy_create(su_root_t *root,
tag_type_t tag, tag_value_t value, ...)
{
@@ -373,6 +375,27 @@ void test_proxy_get_expiration(struct proxy *p,
}
}
void test_proxy_set_session_timer(struct proxy *p,
sip_time_t session_expires,
sip_time_t min_se)
{
if (p) {
p->prefs.session_expires = session_expires;
p->prefs.min_se = min_se;
}
}
void test_proxy_get_session_timer(struct proxy *p,
sip_time_t *return_session_expires,
sip_time_t *return_min_se)
{
if (p) {
if (return_session_expires)
*return_session_expires = p->prefs.session_expires;
if (return_min_se) *return_min_se = p->prefs.min_se;
}
}
/* ---------------------------------------------------------------------- */
static sip_contact_t *create_transport_contacts(struct proxy *p)
@@ -425,6 +448,7 @@ int proxy_request(struct proxy *proxy,
sip_session_expires_t *x = NULL, x0[1];
sip_min_se_t *min_se = NULL, min_se0[1];
char const *require = NULL;
mf = sip->sip_max_forwards;
@@ -445,24 +469,33 @@ int proxy_request(struct proxy *proxy,
}
if (method == sip_method_invite) {
if (!sip->sip_min_se ||
sip->sip_min_se->min_delta < proxy->prefs.min_se) {
min_se = sip_min_se_init(min_se0);
min_se->min_delta = proxy->prefs.min_se;
if (proxy->prefs.min_se) {
if (!sip->sip_min_se ||
sip->sip_min_se->min_delta < proxy->prefs.min_se) {
min_se = sip_min_se_init(min_se0);
min_se->min_delta = proxy->prefs.min_se;
}
if (sip->sip_session_expires
&& sip->sip_session_expires->x_delta < proxy->prefs.min_se
&& sip_has_supported(sip->sip_supported, "timer")) {
if (min_se == NULL)
min_se = sip->sip_min_se; assert(min_se);
nta_incoming_treply(irq, SIP_422_SESSION_TIMER_TOO_SMALL,
SIPTAG_MIN_SE(min_se),
TAG_END());
return 422;
}
}
if (!sip->sip_session_expires) {
x = sip_session_expires_init(x0);
x->x_delta = proxy->prefs.session_expires;
}
else if (sip->sip_session_expires->x_delta < proxy->prefs.min_se
&& sip_has_supported(sip->sip_supported, "timer")) {
if (min_se == NULL)
min_se = sip->sip_min_se; assert(min_se);
nta_incoming_treply(irq, SIP_422_SESSION_TIMER_TOO_SMALL,
SIPTAG_MIN_SE(min_se),
TAG_END());
return 422;
if (proxy->prefs.session_expires) {
if (!sip->sip_session_expires ||
sip->sip_session_expires->x_delta > proxy->prefs.session_expires) {
x = sip_session_expires_init(x0);
x->x_delta = proxy->prefs.session_expires;
if (!sip_has_supported(sip->sip_supported, "timer"))
require = "timer";
}
}
}
@@ -526,6 +559,7 @@ int proxy_request(struct proxy *proxy,
SIPTAG_REQUEST(rq),
SIPTAG_SESSION_EXPIRES(x),
SIPTAG_MIN_SE(min_se),
SIPTAG_REQUIRE_STR(require),
TAG_END());
if (t->client == NULL) {
proxy_transaction_destroy(t);
@@ -707,8 +741,8 @@ static int binding_update(struct proxy *p,
sip_contact_t *binding_contacts(su_home_t *home, struct binding *bindings);
int process_register(struct proxy *proxy,
nta_incoming_t *irq,
sip_t const *sip)
nta_incoming_t *irq,
sip_t const *sip)
{
auth_status_t *as;
msg_t *msg;
@@ -751,6 +785,13 @@ static int process_register2(struct proxy *p,
sip_t const *sip)
{
struct registration_entry *e = NULL;
sip_contact_t *m = sip->sip_contact;
sip_via_t *v = sip->sip_via;
if (m && v && v->v_received && m->m_url->url_host
&& strcasecmp(v->v_received, m->m_url->url_host)
&& host_is_ip_address(m->m_url->url_host))
return set_status(as, 406, "Unacceptable Contact");
auth_mod_check_client(p->auth, as, sip->sip_authorization,
registrar_challenger);
@@ -48,6 +48,14 @@ void test_proxy_get_expiration(struct proxy *,
sip_time_t *return_expires,
sip_time_t *return_max_expires);
void test_proxy_set_session_timer(struct proxy *p,
sip_time_t session_expires,
sip_time_t min_se);
void test_proxy_get_session_timer(struct proxy *p,
sip_time_t *return_session_expires,
sip_time_t *return_min_se);
SOFIA_END_DECLS
#endif
+170 -499
View File
@@ -43,21 +43,22 @@
#define __func__ "test_call_hold"
#endif
int accept_call_immediately(CONDITION_PARAMS);
/* ======================================================================== */
/* NUA-9 tests: REFER */
int test_refer0(struct context *ctx, int refer_with_id, char const *tests);
int test_refer1(struct context *ctx, int refer_with_id, char const *tests);
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_refer(struct context *ctx)
{
/* test twice, once without id and once with id */
return
test_refer0(ctx, 0, "NUA-9.1") ||
test_refer0(ctx, 1, "NUA-9.2") ||
test_refer1(ctx, 0, "NUA-9.3");
test_refer0(ctx, "NUA-9.1", 0, 0) ||
test_refer0(ctx, "NUA-9.2", 1, 0) ||
test_refer0(ctx, "NUA-9.3", 0, 1) ||
test_refer0(ctx, "NUA-9.4", 1, 1);
}
/* Referred call:
@@ -103,13 +104,15 @@ int test_refer(struct context *ctx)
*/
int test_refer0(struct context *ctx, int refer_with_id, char const *tests)
int test_refer0(struct context *ctx, char const *tests,
int refer_with_id, int notify_by_appl)
{
BEGIN();
struct endpoint *a = &ctx->a, *b = &ctx->b, *c = &ctx->c;
struct call *a_call = a->call, *b_call = b->call, *c_call = c->call;
struct call *a_c2;
struct call *a_refer, *a_c2, *b_refer;
struct eventlist *a_revents, *b_revents;
struct event *e;
sip_t const *sip;
sip_event_t const *a_event, *b_event;
@@ -124,7 +127,10 @@ int test_refer0(struct context *ctx, int refer_with_id, char const *tests)
su_home_auto(tmphome, sizeof(tmphome));
if (print_headings)
printf("TEST %s: REFER: refer A to C\n", tests);
printf("TEST %s: REFER: refer A to C%s%s%s\n", tests,
refer_with_id ? " with Event id" : "",
refer_with_id && !notify_by_appl ? " and" : "",
!notify_by_appl ? " nua generating the NOTIFYs" : "");
if (print_headings)
printf("TEST %s.1: REFER: make a call between A and B\n", tests);
@@ -133,6 +139,28 @@ int test_refer0(struct context *ctx, int refer_with_id, char const *tests)
nua_set_params(ctx->a.nua, NUTAG_REFER_WITH_ID(refer_with_id), TAG_END());
run_a_until(ctx, nua_r_set_params, until_final_response);
if (refer_with_id) {
TEST_1(a_refer = calloc(1, (sizeof *a_refer) + (sizeof *a_refer->events)));
call_init(a_refer);
a_refer->events = (void *)(a_refer + 1);
eventlist_init(a_refer->events);
a_call->next = a_refer;
a_revents = a_refer->events;
TEST_1(b_refer = calloc(1, (sizeof *b_refer) + (sizeof *b_refer->events)));
call_init(b_refer);
b_refer->events = (void *)(b_refer + 1);
eventlist_init(b_refer->events);
b_call->next = b_refer;
b_revents = b_refer->events;
}
else {
a_refer = a_call, b_refer = b_call;
a_revents = a->events, b_revents = b->events;
}
TEST_1(a_c2 = calloc(1, (sizeof *a_c2) + (sizeof *a_c2->events)));
call_init(a_c2);
a_c2->events = (void *)(a_c2 + 1);
@@ -198,7 +226,7 @@ int test_refer0(struct context *ctx, int refer_with_id, char const *tests)
printf("TEST %s.1: PASSED\n", tests);
/* ---------------------------------------------------------------------- */
/* REFER (initial NOTIFY is no more sent)
/* REFER (initial NOTIFY is no more sent unless REFER creates a new dialog)
A B
|<------REFER--------|
|-------200 OK------>|
@@ -207,13 +235,20 @@ int test_refer0(struct context *ctx, int refer_with_id, char const *tests)
*/
if (print_headings)
printf("TEST %s.2: refer A to C\n", tests);
printf("TEST %s.2: B refers A to C\n", tests);
if (b_refer != b_call)
TEST_1(b_refer->nh =
nua_handle(b->nua, b_refer, SIPTAG_TO(a->to), TAG_END()));
*sip_refer_to_init(r0)->r_url = *c->contact->m_url;
r0->r_url->url_headers = "subject=referred";
r0->r_display = "C";
REFER(b, b_call, b_call->nh, SIPTAG_REFER_TO(r0), TAG_END());
REFER(b, b_refer, b_refer->nh, SIPTAG_REFER_TO(r0),
TAG_IF(!ctx->proxy_tests && b_refer != b_call,
NUTAG_URL(a->contact->m_url)),
TAG_END());
run_ab_until(ctx, -1, save_until_received,
-1, save_until_final_response);
@@ -221,7 +256,7 @@ int test_refer0(struct context *ctx, int refer_with_id, char const *tests)
Events in A:
nua_i_refer
*/
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_refer);
TEST_1(e = a_revents->head); TEST_E(e->data->e_event, nua_i_refer);
TEST(e->data->e_status, 202);
a_event = NULL;
TEST(tl_gets(e->data->e_tags,
@@ -233,17 +268,12 @@ int test_refer0(struct context *ctx, int refer_with_id, char const *tests)
TEST_1(refer_to = sip_refer_to_dup(tmphome, sip->sip_refer_to));
TEST_1(sip->sip_referred_by);
TEST_1(referred_by = sip_referred_by_dup(tmphome, sip->sip_referred_by));
if (e->next) {
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_notify);
TEST_1(!e->next);
}
free_events_in_list(ctx, a->events);
/*
Events in B after nua_refer():
nua_r_refer
*/
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_refer);
TEST_1(e = b_revents->head); TEST_E(e->data->e_event, nua_r_refer);
TEST(e->data->e_status, 100);
TEST(tl_gets(e->data->e_tags,
NUTAG_REFER_EVENT_REF(b_event),
@@ -254,22 +284,32 @@ int test_refer0(struct context *ctx, int refer_with_id, char const *tests)
TEST(e->data->e_status, 202);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_SIZE(strtoul(b_event->o_id, NULL, 10), sip->sip_cseq->cs_seq);
#if 0
if (!e->next)
run_b_until(ctx, -1, save_until_received);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
TEST(e->data->e_status, 200);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_event);
if (refer_with_id)
TEST_S(sip->sip_event->o_id, b_event->o_id);
TEST_1(sip->sip_subscription_state);
TEST_S(sip->sip_subscription_state->ss_substate, "pending");
TEST_1(sip->sip_payload && sip->sip_payload->pl_data);
TEST_S(sip->sip_payload->pl_data, "SIP/2.0 100 Trying\r\n");
TEST_1(!e->next);
#endif
free_events_in_list(ctx, b->events);
if (a_refer != a_call) {
if (b_revents->head->next->next == NULL)
run_ab_until(ctx, -1, save_until_received, nua_i_notify, save_events);
else if (a_revents->head->next == NULL)
run_a_until(ctx, -1, save_until_received);
TEST_1(e = a_revents->head->next); TEST_E(e->data->e_event, nua_r_notify);
TEST_1(!e->next);
TEST_1(e = b_revents->head->next->next);
TEST_E(e->data->e_event, nua_i_notify);
TEST(e->data->e_status, 200);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_event);
if (refer_with_id)
TEST_S(sip->sip_event->o_id, b_event->o_id);
TEST_1(sip->sip_subscription_state);
TEST_S(sip->sip_subscription_state->ss_substate, "pending");
TEST_1(sip->sip_payload && sip->sip_payload->pl_data);
TEST_S(sip->sip_payload->pl_data, "SIP/2.0 100 Trying\r\n");
TEST_1(!e->next);
}
free_events_in_list(ctx, a_revents);
free_events_in_list(ctx, b_revents);
if (print_headings)
printf("TEST %s.2: PASSED\n", tests);
@@ -371,42 +411,43 @@ int test_refer0(struct context *ctx, int refer_with_id, char const *tests)
*sip_to_init(to)->a_url = *refer_to->r_url;
to->a_display = refer_to->r_display;
a->call->next = a_c2;
a_refer->next = a_c2;
TEST_1(a_c2->nh = nua_handle(a->nua, a_c2, SIPTAG_TO(to), TAG_END()));
INVITE(a, a_c2, a_c2->nh, /* NUTAG_URL(refer_to->r_url), */
NUTAG_REFER_EVENT(a_event),
NUTAG_NOTIFY_REFER(a_call->nh),
TAG_IF(!notify_by_appl, NUTAG_REFER_EVENT(a_event)),
TAG_IF(!notify_by_appl, NUTAG_NOTIFY_REFER(a_refer->nh)),
SOATAG_USER_SDP_STR(a_c2->sdp),
SIPTAG_REFERRED_BY(referred_by),
TAG_END());
run_abc_until(ctx,
-1, until_ready,
-1, notify_by_appl ? notify_until_terminated : until_ready,
-1, save_until_received,
-1, accept_call_immediately);
/* XXX - we should use accept_call instead of accept_call_immediately but
nua has a problem with automatically generated NOTIFYs:
3rd NOTIFY is not sent because 2nd is still in progress
*/
-1, accept_call);
/* Wait until both NOTIFY has been responded */
while (a_revents->head == NULL || a_revents->head->next == NULL)
run_ab_until(ctx, -1, save_until_received, -1, save_events);
while (b_revents->head == NULL || b_revents->head->next == NULL)
run_ab_until(ctx, -1, save_events, -1, save_until_received);
/* Client A transitions:
INIT -(C1)-> CALLING: nua_invite(), nua_i_state
CALLING -(C2a+C4)-> READY: nua_r_invite, nua_i_state
nua_i_notify
XXX should be:
CALLING -(C2+C4)-> PROCEEDING: nua_r_invite, nua_i_state
optional: nua_i_notify
nua_r_notify
PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
nua_i_notify
optional: nua_i_notify
nua_r_notify
*/
TEST_1(e = a_c2->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); /* PROCEEDING */
TEST_1(e = e->next); 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 */
@@ -414,19 +455,32 @@ int test_refer0(struct context *ctx, int refer_with_id, char const *tests)
TEST_1(!e->next);
free_events_in_list(ctx, a_c2->events);
if (a->events->head == NULL)
run_a_until(ctx, -1, save_until_received);
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_notify);
TEST_1(!e->next);
free_events_in_list(ctx, a->events);
TEST_1(e = a_revents->head); TEST_E(e->data->e_event, nua_r_notify);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_notify);
if (a_refer == a_call && notify_by_appl) {
free_event_in_list(ctx, a_revents, a_revents->head);
free_event_in_list(ctx, a_revents, a_revents->head);
}
else {
TEST_1(!e->next);
free_events_in_list(ctx, a_revents);
}
/*
Events in B after nua_refer():
nua_i_notify
*/
if (b->events->head == NULL)
run_b_until(ctx, -1, save_until_received);
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_notify);
TEST_1(e = b_revents->head); TEST_E(e->data->e_event, nua_i_notify);
TEST(e->data->e_status, 200);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_subscription_state);
TEST_S(sip->sip_subscription_state->ss_substate, "active");
TEST_1(sip->sip_payload && sip->sip_payload->pl_data);
TEST_S(sip->sip_payload->pl_data, "SIP/2.0 180 Ringing\r\n");
TEST_1(sip->sip_event);
if (refer_with_id)
TEST_S(sip->sip_event->o_id, b_event->o_id);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
TEST(e->data->e_status, 200);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_subscription_state);
@@ -436,13 +490,20 @@ int test_refer0(struct context *ctx, int refer_with_id, char const *tests)
TEST_1(sip->sip_event);
if (refer_with_id)
TEST_S(sip->sip_event->o_id, b_event->o_id);
TEST_1(!e->next);
free_events_in_list(ctx, b->events);
if (b_refer == b_call && notify_by_appl) {
free_event_in_list(ctx, b_revents, b_revents->head);
free_event_in_list(ctx, b_revents, b_revents->head);
}
else {
TEST_1(!e->next);
free_events_in_list(ctx, b_revents);
}
/*
C transitions:
INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
RECEIVED -(S3b)-> COMPLETED: nua_respond(), 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 = c->events->head); TEST_E(e->data->e_event, nua_i_invite);
@@ -451,6 +512,8 @@ int test_refer0(struct context *ctx, int refer_with_id, char const *tests)
TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
TEST_1(is_offer_recv(e->data->e_tags));
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(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_answer_sent(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
@@ -472,20 +535,28 @@ int test_refer0(struct context *ctx, int refer_with_id, char const *tests)
if (print_headings)
printf("TEST %s.5.1: terminate call between A and B\n", tests);
BYE(a, a_call, a_call->nh, TAG_END());
run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
if (notify_by_appl) {
if (!a->events->head || !a->events->head->next)
run_ab_until(ctx, -1, until_terminated, -1, save_events);
if (!b->events->head || !b->events->head->next)
run_ab_until(ctx, -1, save_events, -1, until_terminated);
}
else {
BYE(a, a_call, a_call->nh, TAG_END());
run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
}
/*
Transitions of A:
READY --(T2)--> TERMINATING: nua_bye()
TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
Transitions of A:
READY --(T2)--> TERMINATING: nua_bye()
TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
*/
TEST_1(e = a->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, a->events);
/* Transitions of B:
READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state
*/
@@ -540,11 +611,21 @@ int test_refer0(struct context *ctx, int refer_with_id, char const *tests)
if (print_headings)
printf("TEST %s.5.2: PASSED\n", tests);
nua_handle_destroy(a_c2->nh), a_c2->nh = NULL;
a->call->next = NULL; free(a_c2);
nua_handle_destroy(c_call->nh), c_call->nh = NULL;
nua_handle_destroy(a_c2->nh), a_c2->nh = NULL;
a_refer->next = NULL; free(a_c2);
if (a_refer != a_call) {
nua_handle_destroy(a_refer->nh), a_refer->nh = NULL;
a_call->next = NULL; free(a_refer);
}
if (b_refer != b_call) {
nua_handle_destroy(b_refer->nh), b_refer->nh = NULL;
b_call->next = NULL; free(b_refer);
}
if (print_headings)
printf("TEST %s: PASSED\n", tests);
@@ -554,40 +635,6 @@ int test_refer0(struct context *ctx, int refer_with_id, char const *tests)
}
/*
accept_call_immediately
X
| |
|-------INVITE------>|
|<----100 Trying-----|
| |
|<--------200--------|
|---------ACK------->|
*/
int accept_call_immediately(CONDITION_PARAMS)
{
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
return 0;
save_event_in_list(ctx, event, ep, call);
switch (callstate(tags)) {
case nua_callstate_received:
RESPOND(ep, call, nh, SIP_200_OK,
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 1;
default:
return 0;
}
}
/*
X INVITE
| |
@@ -610,18 +657,31 @@ int notify_until_terminated(CONDITION_PARAMS)
if (event == nua_r_invite) {
sip_status_t *st = sip->sip_status;
sip_payload_t *pl;
struct call *r_call;
if (!nua_handle_has_events(ep->call->nh))
r_call = ep->call->next;
else
r_call = ep->call;
assert(nua_handle_has_events(r_call->nh));
pl = sip_payload_format(NULL, "SIP/2.0 %u %s\r\n",
st->st_status, st->st_phrase);
NOTIFY(ep, ep->call, ep->call->nh,
NOTIFY(ep, r_call, r_call->nh,
SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
SIPTAG_PAYLOAD(pl),
TAG_IF(st->st_status >= 200,
NUTAG_SUBSTATE(nua_substate_terminated)),
NUTAG_SUBSTATE(st->st_status >= 200
? nua_substate_terminated
: nua_substate_active),
TAG_END());
BYE(ep, ep->call, ep->call->nh, TAG_END());
su_free(NULL, pl);
if (st->st_status >= 200)
BYE(ep, ep->call, ep->call->nh, TAG_END());
return 0;
}
@@ -635,392 +695,3 @@ int notify_until_terminated(CONDITION_PARAMS)
return 0;
}
}
/* Referred call - NOTIFY and BYE are overlapped
A B
| |
|-------INVITE------>|
|<----100 Trying-----|
| |
|<----180 Ringing----|
| |
|<------200 OK-------|
|--------ACK-------->|
| |
|<------REFER--------|
|-------200 OK------>| C
[|-------NOTIFY------>|] |
[|<------200 OK-------|] |
| | |
| | |
|<-----SUBSCRIBE-----| |
|-------200 OK------>| |
| | |
| | |
|-----------------INVITE-------------------->|
| | |
| | |
|<------------------200----------------------|
|-------NOTIFY------>| |
|--------BYE-------->| |
|-------------------ACK--------------------->|
|<------200 OK-------| |
|<------200 OK-------| |
| X |
| |
|-------------------BYE--------------------->|
|<------------------200----------------------|
| |
*/
int test_refer1(struct context *ctx, int refer_with_id, char const *tests)
{
BEGIN();
struct endpoint *a = &ctx->a, *b = &ctx->b, *c = &ctx->c;
struct call *a_call = a->call, *b_call = b->call, *c_call = c->call;
struct call *a_c2;
struct event *e;
sip_t const *sip;
sip_event_t const *a_event, *b_event;
sip_refer_to_t const *refer_to;
sip_referred_by_t const *referred_by;
sip_refer_to_t r0[1];
sip_to_t to[1];
su_home_t tmphome[SU_HOME_AUTO_SIZE(16384)];
su_home_auto(tmphome, sizeof(tmphome));
if (print_headings)
printf("TEST %s: REFER: refer A to C\n", tests);
if (print_headings)
printf("TEST %s.1: REFER: make a call between A and B\n", tests);
/* Do (not) include id with first implicit Event: refer */
nua_set_params(ctx->a.nua, NUTAG_REFER_WITH_ID(refer_with_id), TAG_END());
run_a_until(ctx, nua_r_set_params, until_final_response);
TEST_1(a_c2 = calloc(1, (sizeof *a_c2) + (sizeof *a_c2->events)));
call_init(a_c2);
a_c2->events = (void *)(a_c2 + 1);
eventlist_init(a_c2->events);
a_call->sdp = "m=audio 5008 RTP/AVP 8";
b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
a_c2->sdp = "m=audio 5012 RTP/AVP 8";
c_call->sdp = "m=audio 5014 RTP/AVP 0 8";
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, accept_call);
/* 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, 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(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
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_answer_recv(e->data->e_tags));
TEST_1(!e->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));
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(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_answer_sent(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(!e->next);
free_events_in_list(ctx, b->events);
if (print_headings)
printf("TEST %s.1: PASSED\n", tests);
/* ---------------------------------------------------------------------- */
/* REFER (initial NOTIFY is no more sent)
A B
|<------REFER--------|
|-------200 OK------>|
[|-------NOTIFY------>|] |
[|<------200 OK-------|] |
*/
if (print_headings)
printf("TEST %s.2: refer A to C\n", tests);
*sip_refer_to_init(r0)->r_url = *c->contact->m_url;
r0->r_url->url_headers = "subject=referred";
r0->r_display = "C";
REFER(b, b_call, b_call->nh, SIPTAG_REFER_TO(r0), TAG_END());
run_ab_until(ctx, -1, save_until_received,
-1, save_until_final_response);
/*
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, 202);
a_event = NULL;
TEST(tl_gets(e->data->e_tags,
NUTAG_REFER_EVENT_REF(a_event),
TAG_END()), 1);
TEST_1(a_event); TEST_1(a_event = sip_event_dup(tmphome, a_event));
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_refer_to);
TEST_1(refer_to = sip_refer_to_dup(tmphome, sip->sip_refer_to));
TEST_1(sip->sip_referred_by);
TEST_1(referred_by = sip_referred_by_dup(tmphome, sip->sip_referred_by));
if (e->next) {
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_notify);
TEST_1(!e->next);
}
free_events_in_list(ctx, a->events);
/*
Events in B after nua_refer():
nua_r_refer
*/
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_refer);
TEST(e->data->e_status, 100);
TEST(tl_gets(e->data->e_tags,
NUTAG_REFER_EVENT_REF(b_event),
TAG_END()), 1);
TEST_1(b_event); TEST_1(b_event->o_id);
TEST_1(b_event = sip_event_dup(tmphome, b_event));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_refer);
TEST(e->data->e_status, 202);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_SIZE(strtoul(b_event->o_id, NULL, 10), sip->sip_cseq->cs_seq);
#if 0
if (!e->next)
run_b_until(ctx, -1, save_until_received);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
TEST(e->data->e_status, 200);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_event);
if (refer_with_id)
TEST_S(sip->sip_event->o_id, b_event->o_id);
TEST_1(sip->sip_subscription_state);
TEST_S(sip->sip_subscription_state->ss_substate, "pending");
TEST_1(sip->sip_payload && sip->sip_payload->pl_data);
TEST_S(sip->sip_payload->pl_data, "SIP/2.0 100 Trying\r\n");
TEST_1(!e->next);
#endif
free_events_in_list(ctx, b->events);
if (print_headings)
printf("TEST %s.2: PASSED\n", tests);
/* ---------------------------------------------------------------------- */
/*
A B C
| | |
|-----------------INVITE-------------------->|
| | |
XXX | |
| | |
|<------------------200----------------------|
|-------NOTIFY------>| |
|---------BYE------->| |
|-------------------ACK--------------------->|
|<--------200--------| |
|<------200 OK-------| |
| X
*/
if (print_headings)
printf("TEST %s.4: A invites C\n", tests);
*sip_to_init(to)->a_url = *refer_to->r_url;
to->a_display = refer_to->r_display;
a->call->next = a_c2;
TEST_1(a_c2->nh = nua_handle(a->nua, a_c2, SIPTAG_TO(to), TAG_END()));
INVITE(a, a_c2, a_c2->nh, /* NUTAG_URL(refer_to->r_url), */
NUTAG_REFER_EVENT(a_event),
/* NUTAG_NOTIFY_REFER(a_call->nh), */
SOATAG_USER_SDP_STR(a_c2->sdp),
SIPTAG_REFERRED_BY(referred_by),
TAG_END());
run_abc_until(ctx,
-1, notify_until_terminated,
-1, until_terminated,
-1, accept_call_immediately);
/* XXX - we should use accept_call instead of accept_call_immediately but
nua has a problem with automatically generated NOTIFYs:
3rd NOTIFY is not sent because 2nd is still in progress
*/
/* Client A transitions:
INIT -(C1)-> CALLING: nua_invite(), nua_i_state
CALLING -(C2a+C4)-> READY: nua_r_invite, nua_i_state
nua_r_notify
Transitions of first call:
READY --(T2)--> TERMINATING: nua_bye()
TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
XXX should be:
CALLING -(C2+C4)-> PROCEEDING: nua_r_invite, nua_i_state
optional: nua_i_notify
PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
nua_i_notify
optional: nua_i_notify
*/
TEST_1(e = a_c2->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, 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_answer_recv(e->data->e_tags));
TEST_1(!e->next);
free_events_in_list(ctx, a_c2->events);
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_notify);
TEST_1(e = e->next); 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 */
free_events_in_list(ctx, a->events);
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
/*
Events in B after nua_refer():
nua_i_notify
READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state
*/
if (b->events->head == NULL)
run_b_until(ctx, -1, save_until_received);
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_notify);
TEST(e->data->e_status, 200);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_subscription_state);
TEST_S(sip->sip_subscription_state->ss_substate, "terminated");
TEST_1(sip->sip_payload && sip->sip_payload->pl_data);
TEST_S(sip->sip_payload->pl_data, "SIP/2.0 200 OK\r\n");
TEST_1(sip->sip_event);
if (refer_with_id)
TEST_S(sip->sip_event->o_id, b_event->o_id);
TEST_1(e = e->next); 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, b->events);
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
/*
C transitions:
INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
RECEIVED -(S3b)-> COMPLETED: nua_respond(), nua_i_state
COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
*/
TEST_1(e = c->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));
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_answer_sent(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(!e->next);
free_events_in_list(ctx, c->events);
if (print_headings)
printf("TEST %s.4: PASSED\n", tests);
/* ---------------------------------------------------------------------- */
/*
A C
|-------------------BYE--------------------->|
|<------------------200----------------------|
*/
if (print_headings)
printf("TEST %s.5.2: terminate call between A and C\n", tests);
BYE(a, a_c2, a_c2->nh, TAG_END());
run_abc_until(ctx, -1, until_terminated, -1, NULL, -1, until_terminated);
/*
Transitions of A:
READY --(T2)--> TERMINATING: nua_bye()
TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
*/
TEST_1(e = a_c2->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, a_c2->events);
/* Transitions of B:
READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state
*/
TEST_1(e = c->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, c->events);
if (print_headings)
printf("TEST %s.5.2: PASSED\n", tests);
nua_handle_destroy(a_c2->nh), a_c2->nh = NULL;
a->call->next = NULL; free(a_c2);
nua_handle_destroy(c_call->nh), c_call->nh = NULL;
if (print_headings)
printf("TEST %s: PASSED\n", tests);
su_home_deinit(tmphome);
END();
}
@@ -55,6 +55,7 @@ int test_register_to_proxy(struct context *ctx)
struct event *e;
sip_t const *sip;
sip_cseq_t cseq[1];
int seen_401;
if (ctx->p)
test_proxy_set_expiration(ctx->p, 5, 5, 10);
@@ -133,16 +134,32 @@ int test_register_to_proxy(struct context *ctx)
NUTAG_KEEPALIVE(1000),
NUTAG_M_DISPLAY("A&A"),
NUTAG_M_USERNAME("a"),
NUTAG_M_PARAMS("foo=bar"),
NUTAG_M_FEATURES("q=0.9"),
SIPTAG_CSEQ(cseq),
TAG_END());
run_a_until(ctx, -1, save_until_final_response);
TEST_1(e = a->events->head);
TEST_E(e->data->e_event, nua_r_register);
TEST_1(sip = sip_object(e->data->e_msg));
if (ctx->nat) {
TEST_E(e->data->e_event, nua_r_register);
TEST(e->data->e_status, 100);
TEST(sip->sip_status->st_status, 406);
/* Check that CSeq included in tags is actually used in the request */
TEST(sip->sip_cseq->cs_seq, 13);
TEST_1(!sip->sip_contact);
TEST_1(e = e->next);
TEST_1(sip = sip_object(e->data->e_msg));
TEST(sip->sip_cseq->cs_seq, 14);
}
else {
/* Check that CSeq included in tags is actually used in the request */
TEST(sip->sip_cseq->cs_seq, 13);
}
TEST_E(e->data->e_event, nua_r_register);
TEST(e->data->e_status, 401);
TEST(sip->sip_status->st_status, 401);
TEST(sip->sip_cseq->cs_seq, 13);
TEST_1(!sip->sip_contact);
TEST_1(!e->next);
free_events_in_list(ctx, a->events);
@@ -160,7 +177,8 @@ int test_register_to_proxy(struct context *ctx)
/* VC does not dig \" with TEST_S() */
TEST_S(sip->sip_contact->m_display, expect_m_display); }
TEST_S(sip->sip_contact->m_url->url_user, "a");
TEST(sip->sip_cseq->cs_seq, 14);
TEST_1(strstr(sip->sip_contact->m_url->url_params, "foo=bar"));
TEST_S(sip->sip_contact->m_q, "0.9");
if (ctx->nat) {
TEST_1(e = a->specials->head);
@@ -184,6 +202,8 @@ int test_register_to_proxy(struct context *ctx)
REGISTER(b, b_reg, b_reg->nh, SIPTAG_TO(b->to),
SIPTAG_CONTACT(m),
/* Do not include credentials unless challenged */
NUTAG_AUTH_CACHE(nua_auth_cache_challenged),
TAG_END());
}
run_ab_until(ctx, -1, save_events, -1, save_until_final_response);
@@ -208,7 +228,7 @@ int test_register_to_proxy(struct context *ctx)
TEST_1(sip->sip_contact);
TEST_S(sip->sip_contact->m_display, "B");
TEST_S(sip->sip_contact->m_url->url_user, "b");
free_events_in_list(ctx, b->events);
if (print_headings)
printf("TEST NUA-2.3.2: PASSED\n");
@@ -221,8 +241,12 @@ int test_register_to_proxy(struct context *ctx)
TEST_1(c_reg->nh = nua_handle(c->nua, c_reg, TAG_END()));
REGISTER(c, c_reg, c_reg->nh, SIPTAG_TO(c->to),
NUTAG_OUTBOUND(NULL),
NUTAG_M_DISPLAY("C"),
NUTAG_M_USERNAME("c"),
NUTAG_M_PARAMS("c=1"),
NUTAG_M_FEATURES("q=0.987;expires=5"),
NUTAG_CALLEE_CAPS(1),
SIPTAG_EXPIRES_STR("5"), /* Test 423 negotiation */
TAG_END());
run_abc_until(ctx, -1, save_events, -1, save_events,
@@ -253,6 +277,9 @@ int test_register_to_proxy(struct context *ctx)
TEST_1(sip->sip_contact);
TEST_S(sip->sip_contact->m_display, "C");
TEST_S(sip->sip_contact->m_url->url_user, "c");
TEST_1(strstr(sip->sip_contact->m_url->url_params, "c=1"));
TEST_S(sip->sip_contact->m_q, "0.987");
TEST_1(msg_header_find_param(sip->sip_contact->m_common, "methods="));
TEST_1(!e->next);
free_events_in_list(ctx, c->events);
@@ -306,11 +333,21 @@ int test_register_to_proxy(struct context *ctx)
TEST_1(!e->next);
free_events_in_list(ctx, a->events);
seen_401 = 0;
for (e = b->events->head; e; e = e->next) {
TEST_E(e->data->e_event, nua_r_register);
TEST(e->data->e_status, 200);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_contact);
if (e->data->e_status == 200) {
TEST(e->data->e_status, 200);
TEST_1(seen_401);
TEST_1(sip->sip_contact);
}
else if (sip->sip_status && sip->sip_status->st_status == 401) {
seen_401 = 1;
}
if (!e->next)
break;
}
@@ -349,7 +386,7 @@ int test_register_to_c(struct context *ctx)
sip_t const *sip;
if (print_headings)
printf("TEST NUA-2.3.2: REGISTER b to c\n");
printf("TEST NUA-2.6.1: REGISTER b to c\n");
nua_set_params(ctx->c.nua,
NUTAG_ALLOW("REGISTER"),
@@ -372,9 +409,6 @@ int test_register_to_c(struct context *ctx)
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(!sip->sip_contact);
if (print_headings)
printf("TEST NUA-2.6.1: PASSED\n");
free_events_in_list(ctx, b->events);
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
@@ -388,7 +422,7 @@ int test_register_to_c(struct context *ctx)
nua_handle_destroy(c_call->nh), c_call->nh = NULL;
if (print_headings)
printf("TEST NUA-2.3.4: PASSED\n");
printf("TEST NUA-2.6.1: PASSED\n");
END();
}
@@ -552,7 +586,8 @@ int test_nat_timeout(struct context *ctx)
BEGIN();
struct endpoint *a = &ctx->a, *b = &ctx->b, *c = &ctx->c;
struct endpoint *a = &ctx->a, *b = &ctx->b;
struct call *a_call = a->call, *b_call = b->call;
struct event *e;
sip_t const *sip;
@@ -586,7 +621,38 @@ int test_nat_timeout(struct context *ctx)
if (print_headings)
printf("TEST NUA-2.5.1: PASSED\n");
(void)b; (void)c; (void)sip;
if (print_headings)
printf("TEST NUA-2.5.2: OPTIONS from B to A\n");
TEST_1(b_call->nh = nua_handle(b->nua, b_call, SIPTAG_TO(a->to), TAG_END()));
OPTIONS(b, b_call, b_call->nh, TAG_END());
run_ab_until(ctx, -1, save_until_received,
-1, save_until_final_response);
/* Client events: nua_options(), nua_r_options */
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_options);
TEST(e->data->e_status, 200);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_allow); TEST_1(sip->sip_accept); TEST_1(sip->sip_supported);
/* TEST_1(sip->sip_content_type); */
/* TEST_1(sip->sip_payload); */
TEST_1(!e->next);
free_events_in_list(ctx, b->events);
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
/* Server events: nua_i_options */
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_options);
TEST(e->data->e_status, 200);
TEST_1(!e->next);
free_events_in_list(ctx, a->events);
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
if (print_headings)
printf("TEST NUA-2.5.2: PASSED\n");
END();
}
@@ -619,6 +685,10 @@ int test_unregister(struct context *ctx)
run_a_until(ctx, -1, save_until_final_response);
TEST_1(e = a->events->head);
TEST_E(e->data->e_event, nua_r_unregister);
if (e->data->e_status == 100) {
TEST_1(e = e->next);
TEST_E(e->data->e_event, nua_r_unregister);
}
TEST(e->data->e_status, 200);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(!sip->sip_contact);
@@ -639,6 +709,10 @@ int test_unregister(struct context *ctx)
run_b_until(ctx, -1, save_until_final_response);
TEST_1(e = b->events->head);
TEST_E(e->data->e_event, nua_r_unregister);
if (e->data->e_status == 100) {
TEST_1(e = e->next);
TEST_E(e->data->e_event, nua_r_unregister);
}
TEST(e->data->e_status, 200);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(!sip->sip_contact);
@@ -658,6 +732,7 @@ int test_unregister(struct context *ctx)
UNREGISTER(c, c->call, c->call->nh, SIPTAG_TO(c->to),
NUTAG_M_DISPLAY("C"),
NUTAG_M_USERNAME("c"),
NUTAG_M_PARAMS("c=1"),
TAG_END());
run_c_until(ctx, -1, save_until_final_response);
@@ -22,7 +22,7 @@
*
*/
/**@CFILE test_nua_re_invite.c
/**@CFILE test_session_timer.c
* @brief NUA-8 tests: Session timer, UPDATE
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
@@ -40,11 +40,13 @@
#elif HAVE_FUNCTION
#define __func__ __FUNCTION__
#else
#define __func__ "test_call_hold"
#define __func__ "test_session_timer"
#endif
/* ======================================================================== */
static size_t remove_update(void *a, void *message, size_t len);
int test_session_timer(struct context *ctx)
{
BEGIN();
@@ -69,22 +71,6 @@ int test_session_timer(struct context *ctx)
|--INVITE->| |
|<--422----| |
|---ACK--->| |
| |
|-------INVITE------>|
|<-------422---------|
|--------ACK-------->|
| |
|-------INVITE------>|
|<----100 Trying-----|
| |
|<----180 Ringing----|
| |
|<------200 OK-------|
|--------ACK-------->|
| |
|<-------BYE---------|
|-------200 OK-------|
| |
*/
@@ -94,8 +80,15 @@ int test_session_timer(struct context *ctx)
a_call->sdp = "m=audio 5008 RTP/AVP 8";
b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
/* We negotiate session timer of 6 second */
/* Disable session timer from proxy */
test_proxy_set_session_timer(ctx->p, 0, 0);
nua_set_params(ctx->b.nua,
NUTAG_SESSION_REFRESHER(nua_any_refresher),
NUTAG_MIN_SE(1),
NUTAG_SESSION_TIMER(6),
NTATAG_SIP_T1X64(8000),
TAG_END());
run_b_until(ctx, nua_r_set_params, until_final_response);
@@ -159,23 +152,132 @@ int test_session_timer(struct context *ctx)
if (print_headings)
printf("TEST NUA-8.1.1: PASSED\n");
if (print_headings)
printf("TEST NUA-8.1.2: Session timers negotiation\n");
if (ctx->expensive) {
nua_set_hparams(a_call->nh,
NUTAG_SUPPORTED("timer"),
NUTAG_MIN_SE(1),
NUTAG_SESSION_TIMER(5),
TAG_END());
run_a_until(ctx, nua_r_set_params, until_final_response);
nua_set_hparams(b_call->nh,
NUTAG_AUTOANSWER(0),
NUTAG_MIN_SE(120),
TAG_END());
if (print_headings)
printf("TEST NUA-8.1.2: Wait for refresh using INVITE\n");
run_ab_until(ctx, -1, until_ready, -1, until_ready);
free_events_in_list(ctx, a->events);
free_events_in_list(ctx, b->events);
if (print_headings)
printf("TEST NUA-8.1.2: PASSED\n");
nua_set_hparams(b_call->nh,
NUTAG_UPDATE_REFRESH(1),
TAG_END());
run_b_until(ctx, nua_r_set_params, until_final_response);
if (print_headings)
printf("TEST NUA-8.1.3: Wait for refresh using UPDATE\n");
run_ab_until(ctx, -1, until_ready, -1, until_ready);
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_update);
free_events_in_list(ctx, a->events);
free_events_in_list(ctx, b->events);
if (print_headings)
printf("TEST NUA-8.1.3: PASSED\n");
if (ctx->nat) {
struct nat_filter *f;
if (print_headings)
printf("TEST NUA-8.1.4: filter UPDATE, wait until session expires\n");
f = test_nat_add_filter(ctx->nat, remove_update, NULL, nat_inbound);
TEST_1(f);
run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_bye);
free_events_in_list(ctx, a->events);
free_events_in_list(ctx, b->events);
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
test_nat_remove_filter(ctx->nat, f);
if (print_headings)
printf("TEST NUA-8.1.4: PASSED\n");
}
}
if (b_call->nh) {
if (print_headings)
printf("TEST NUA-8.1.9: Terminate first session timer call\n");
BYE(b, b_call, b_call->nh, TAG_END());
run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
free_events_in_list(ctx, a->events);
free_events_in_list(ctx, b->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-8.1.9: PASSED\n");
}
/*
| |
|-------INVITE------>|
|<-------422---------|
|--------ACK-------->|
| |
|-------INVITE------>|
|<----100 Trying-----|
| |
|<----180 Ringing----|
| |
|<------200 OK-------|
|--------ACK-------->|
| |
|<-------BYE---------|
|-------200 OK-------|
| |
*/
if (print_headings)
printf("TEST NUA-8.2: Session timers negotiation\n");
test_proxy_set_session_timer(ctx->p, 180, 90);
nua_set_params(a->nua,
NUTAG_SUPPORTED("timer"),
TAG_END());
run_a_until(ctx, nua_r_set_params, until_final_response);
nua_set_params(b->nua,
NUTAG_AUTOANSWER(0),
NUTAG_MIN_SE(120),
NTATAG_SIP_T1X64(2000),
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, timer"),
NUTAG_SESSION_TIMER(15),
NUTAG_MIN_SE(5),
NUTAG_SESSION_TIMER(4),
NUTAG_MIN_SE(3),
TAG_END());
run_ab_until(ctx, -1, until_ready, -1, accept_call);
@@ -252,17 +354,17 @@ int test_session_timer(struct context *ctx)
free_events_in_list(ctx, b->events);
if (print_headings)
printf("TEST NUA-8.1: PASSED\n");
printf("TEST NUA-8.2: PASSED\n");
if (print_headings)
printf("TEST NUA-8.2: use UPDATE\n");
printf("TEST NUA-8.3: UPDATE with session timer headers\n");
UPDATE(b, b_call, b_call->nh, TAG_END());
run_ab_until(ctx, -1, until_ready, -1, until_ready);
/* Events from B (who sent UPDATE) */
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
TEST_1(is_offer_sent(e->data->e_tags));
if (!e->next)
run_b_until(ctx, -1, until_ready);
@@ -313,7 +415,20 @@ int test_session_timer(struct context *ctx)
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
if (print_headings)
printf("TEST NUA-8.2: PASSED\n");
printf("TEST NUA-8.3: PASSED\n");
END();
}
static
size_t remove_update(void *a, void *message, size_t len)
{
(void)a;
if (strncmp("UPDATE ", message, 7) == 0) {
return 0;
}
return len;
}
+692 -15
View File
@@ -43,6 +43,8 @@
#define __func__ "test_simple"
#endif
extern int accept_request(CONDITION_PARAMS);
int test_message(struct context *ctx)
{
BEGIN();
@@ -62,7 +64,7 @@ int test_message(struct context *ctx)
*/
if (print_headings)
printf("TEST NUA-11.1: MESSAGE\n");
printf("TEST NUA-11.1.1: MESSAGE\n");
if (ctx->proxy_tests)
*url = *b->to->a_url;
@@ -76,7 +78,7 @@ int test_message(struct context *ctx)
MESSAGE(a, a_call, a_call->nh,
NUTAG_URL(url),
SIPTAG_SUBJECT_STR("NUA-11.1"),
SIPTAG_SUBJECT_STR("NUA-11.1.1"),
SIPTAG_CONTENT_TYPE_STR("text/plain"),
SIPTAG_PAYLOAD_STR("Hello hellO!\n"),
TAG_END());
@@ -98,7 +100,7 @@ int test_message(struct context *ctx)
TEST(e->data->e_status, 200);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_subject && sip->sip_subject->g_string);
TEST_S(sip->sip_subject->g_string, "NUA-11.1");
TEST_S(sip->sip_subject->g_string, "NUA-11.1.1");
TEST_1(sip->sip_organization);
TEST_S(sip->sip_organization->g_string, "United Testers");
TEST_1(!e->next);
@@ -110,7 +112,64 @@ int test_message(struct context *ctx)
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
if (print_headings)
printf("TEST NUA-11.1: PASSED\n");
printf("TEST NUA-11.1.1: PASSED\n");
/* MESSAGE as application method
A B
|-------MESSAGE----->|
|<-------202---------|
| |
*/
if (print_headings)
printf("TEST NUA-11.1.2: MESSAGE\n");
nua_set_params(b->nua, NUTAG_APPL_METHOD("MESSAGE"), TAG_END());
run_b_until(ctx, nua_r_set_params, until_final_response);
TEST_1(a_call->nh = nua_handle(a->nua, a_call, TAG_END()));
MESSAGE(a, a_call, a_call->nh,
NUTAG_URL(url),
SIPTAG_SUBJECT_STR("NUA-11.1.2"),
SIPTAG_CONTENT_TYPE_STR("text/plain"),
SIPTAG_PAYLOAD_STR("Hello hellO!\n"),
TAG_END());
run_ab_until(ctx, -1, save_until_final_response, -1, accept_request);
/* Client events:
nua_message(), nua_r_message
*/
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_message);
TEST(e->data->e_status, 202);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip_user_agent(sip));
TEST_S(sip_user_agent(sip)->g_value, "007");
TEST_1(!e->next);
/*
Server events:
nua_i_message
*/
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_message);
TEST(e->data->e_status, 100);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_subject && sip->sip_subject->g_string);
TEST_S(sip->sip_subject->g_string, "NUA-11.1.2");
TEST_1(sip->sip_organization);
TEST_S(sip->sip_organization->g_string, "United Testers");
TEST_1(!e->next);
free_events_in_list(ctx, a->events);
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
free_events_in_list(ctx, b->events);
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
if (print_headings)
printf("TEST NUA-11.1.2: PASSED\n");
/* Message test
@@ -131,7 +190,7 @@ int test_message(struct context *ctx)
MESSAGE(a, a_call, a_call->nh,
/* We cannot reach us by using our contact! */
NUTAG_URL(!ctx->p && !ctx->proxy_tests ? a->contact->m_url : NULL),
SIPTAG_SUBJECT_STR("NUA-11.1b"),
SIPTAG_SUBJECT_STR("NUA-11.2"),
SIPTAG_CONTENT_TYPE_STR("text/plain"),
SIPTAG_PAYLOAD_STR("Hello hellO!\n"),
TAG_END());
@@ -141,16 +200,21 @@ int test_message(struct context *ctx)
/* Events:
nua_message(), nua_i_message, nua_r_message
*/
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_message);
TEST_1(e = a->specials->head);
while (e->data->e_event == nua_i_outbound)
e = e->next;
TEST_E(e->data->e_event, nua_i_message);
TEST(e->data->e_status, 200);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_subject && sip->sip_subject->g_string);
TEST_S(sip->sip_subject->g_string, "NUA-11.1b");
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_message);
TEST_S(sip->sip_subject->g_string, "NUA-11.2");
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_message);
TEST(e->data->e_status, 200);
TEST_1(!e->next);
free_events_in_list(ctx, a->events);
free_events_in_list(ctx, a->specials);
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
if (print_headings)
@@ -159,12 +223,32 @@ int test_message(struct context *ctx)
END();
}
int accept_request(CONDITION_PARAMS)
{
msg_t *with = nua_current_request(nua);
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
return 0;
save_event_in_list(ctx, event, ep, call);
if (status < 200) {
RESPOND(ep, call, nh, SIP_202_ACCEPTED,
NUTAG_WITH(with),
SIPTAG_USER_AGENT_STR("007"),
TAG_END());
return 1;
}
return 0;
}
int respond_with_etag(CONDITION_PARAMS)
{
msg_t *with = nua_current_request(nua);
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
return 0;
return 1;
save_event_in_list(ctx, event, ep, call);
@@ -191,6 +275,14 @@ int respond_with_etag(CONDITION_PARAMS)
}
}
static int close_handle(CONDITION_PARAMS)
{
if (call->nh == nh)
call->nh = NULL;
nua_handle_destroy(nh);
return 1;
}
int test_publish(struct context *ctx)
{
BEGIN();
@@ -357,8 +449,60 @@ int test_publish(struct context *ctx)
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
/* Let server close handle without responding to PUBLISH */
PUBLISH(a, a_call, a_call->nh,
TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
SIPTAG_EVENT_STR("presence"),
SIPTAG_CONTENT_TYPE_STR("text/urllist"),
SIPTAG_PAYLOAD_STR("sip:example.com\n"),
TAG_END());
run_ab_until(ctx, -1, save_until_final_response, -1, close_handle);
/* Client events:
nua_publish(), nua_r_publish
*/
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_publish);
TEST(e->data->e_status, 500);
TEST_1(!e->next);
free_events_in_list(ctx, a->events);
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
/* No Event header */
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
PUBLISH(a, a_call, a_call->nh,
TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
SIPTAG_CONTENT_TYPE_STR("text/urllist"),
SIPTAG_PAYLOAD_STR("sip:example.com\n"),
TAG_END());
run_ab_until(ctx, -1, save_until_final_response, -1, save_events);
/* Client events:
nua_publish(), nua_r_publish
*/
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_publish);
TEST(e->data->e_status, 489);
TEST_1(!e->next);
free_events_in_list(ctx, a->events);
/*
Server events: nothing
*/
TEST_1(!b->events->head);
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
if (print_headings)
printf("TEST NUA-11.3: PASSED\n");
END();
}
@@ -429,7 +573,10 @@ int test_subscribe_notify(struct context *ctx)
tagi_t const *n_tags, *r_tags;
if (print_headings)
printf("TEST NUA-11.4: establishing subscription without notifier\n");
printf("TEST NUA-11.4: notifier server using nua_notify()\n");
if (print_headings)
printf("TEST NUA-11.4.1: establishing subscription\n");
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
@@ -489,7 +636,7 @@ int test_subscribe_notify(struct context *ctx)
free_events_in_list(ctx, b->events);
if (print_headings)
printf("TEST NUA-11.4: PASSED\n");
printf("TEST NUA-11.4.1: PASSED\n");
/* ---------------------------------------------------------------------- */
@@ -502,7 +649,7 @@ int test_subscribe_notify(struct context *ctx)
| |
*/
if (print_headings)
printf("TEST NUA-11.5: send NOTIFY\n");
printf("TEST NUA-11.4.2: send NOTIFY\n");
/* Update presence data */
@@ -542,7 +689,7 @@ int test_subscribe_notify(struct context *ctx)
free_events_in_list(ctx, b->events);
if (print_headings)
printf("TEST NUA-11.5: PASSED\n");
printf("TEST NUA-11.4.2: PASSED\n");
/* ---------------------------------------------------------------------- */
@@ -557,7 +704,7 @@ int test_subscribe_notify(struct context *ctx)
| |
*/
if (print_headings)
printf("TEST NUA-11.6: un-SUBSCRIBE\n");
printf("TEST NUA-11.4.3: un-SUBSCRIBE\n");
UNSUBSCRIBE(a, a_call, a_call->nh, TAG_END());
@@ -614,11 +761,538 @@ int test_subscribe_notify(struct context *ctx)
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
if (print_headings)
printf("TEST NUA-11.6: PASSED\n");
printf("TEST NUA-11.4.3: PASSED\n");
if (print_headings)
printf("TEST NUA-11.4: PASSED\n");
END();
}
/* ---------------------------------------------------------------------- */
/* Subscriber gracefully terminates dialog upon 483 */
static
size_t change_status_to_483(void *a, void *message, size_t len);
int save_until_notified_and_responded_twice(CONDITION_PARAMS);
int save_until_notify_responded_twice(CONDITION_PARAMS);
int test_subscribe_notify_graceful(struct context *ctx)
{
if (!ctx->nat)
return 0;
BEGIN();
struct endpoint *a = &ctx->a, *b = &ctx->b;
struct call *a_call = a->call, *b_call = b->call;
struct event *e;
sip_t const *sip;
tagi_t const *n_tags, *r_tags;
struct nat_filter *f;
if (print_headings)
printf("TEST NUA-11.5.1: establishing subscription\n");
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
SUBSCRIBE(a, a_call, a_call->nh, NUTAG_URL(b->contact->m_url),
SIPTAG_EVENT_STR("presence"),
SIPTAG_ACCEPT_STR("application/xpidf, application/pidf+xml"),
TAG_END());
run_ab_until(ctx, -1, save_until_notified_and_responded,
-1, accept_and_notify);
/* Client events:
nua_subscribe(), nua_i_notify/nua_r_subscribe
*/
TEST_1(e = a->events->head);
if (e->data->e_event == nua_i_notify) {
TEST_E(e->data->e_event, nua_i_notify);
TEST_1(sip = sip_object(e->data->e_msg));
n_tags = e->data->e_tags;
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_subscribe);
r_tags = e->data->e_tags;
TEST_1(tl_find(r_tags, nutag_substate));
TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_pending);
}
else {
TEST_E(e->data->e_event, nua_r_subscribe);
TEST(e->data->e_status, 202);
r_tags = e->data->e_tags;
TEST_1(tl_find(r_tags, nutag_substate));
TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_embryonic);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
TEST_1(sip = sip_object(e->data->e_msg));
n_tags = e->data->e_tags;
}
TEST_1(sip->sip_event); TEST_S(sip->sip_event->o_type, "presence");
TEST_1(sip->sip_content_type);
TEST_S(sip->sip_content_type->c_type, "application/pidf+xml");
TEST_1(sip->sip_subscription_state);
TEST_S(sip->sip_subscription_state->ss_substate, "pending");
TEST_1(sip->sip_subscription_state->ss_expires);
TEST_1(tl_find(n_tags, nutag_substate));
TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_pending);
TEST_1(!e->next);
free_events_in_list(ctx, a->events);
/* Server events: nua_i_subscribe, nua_r_notify */
TEST_1(e = b->events->head);
TEST_E(e->data->e_event, nua_i_subscribe);
TEST_E(e->data->e_status, 100);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_notify);
r_tags = e->data->e_tags;
TEST_1(tl_find(r_tags, nutag_substate));
TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_pending);
free_events_in_list(ctx, b->events);
if (print_headings)
printf("TEST NUA-11.5.1: PASSED\n");
if (print_headings)
printf("TEST NUA-11.5.2: terminate gracefully upon 483\n");
TEST_1(f = test_nat_add_filter(ctx->nat,
change_status_to_483, NULL,
nat_inbound));
SUBSCRIBE(a, a_call, a_call->nh, TAG_END());
run_ab_until(ctx, -1, save_until_notified_and_responded_twice,
-1, save_until_notify_responded_twice);
#if 0
/* Client events:
nua_unsubscribe(), nua_i_notify/nua_r_unsubscribe
*/
TEST_1(e = a->events->head);
if (e->data->e_event == nua_i_notify) {
TEST_E(e->data->e_event, nua_i_notify);
n_tags = e->data->e_tags;
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_event);
TEST_1(sip->sip_subscription_state);
TEST_S(sip->sip_subscription_state->ss_substate, "terminated");
TEST_1(!sip->sip_subscription_state->ss_expires);
TEST_1(tl_find(n_tags, nutag_substate));
TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_terminated);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_unsubscribe);
TEST(e->data->e_status, 200);
r_tags = e->data->e_tags;
TEST_1(tl_find(r_tags, nutag_substate));
TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_terminated);
}
else {
TEST_E(e->data->e_event, nua_r_unsubscribe);
TEST(e->data->e_status, 200);
r_tags = e->data->e_tags;
TEST_1(tl_find(r_tags, nutag_substate));
TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_terminated);
}
TEST_1(!e->next);
/* Notifier events: nua_r_notify */
TEST_1(e = b->events->head);
TEST_E(e->data->e_event, nua_i_subscribe);
TEST(e->data->e_status, 200);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(tl_find(e->data->e_tags, nutag_substate));
TEST(tl_find(e->data->e_tags, nutag_substate)->t_value,
nua_substate_terminated);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_notify);
TEST_1(e->data->e_status >= 200);
r_tags = e->data->e_tags;
TEST_1(tl_find(r_tags, nutag_substate));
TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_terminated);
#endif
free_events_in_list(ctx, a->events);
free_events_in_list(ctx, b->events);
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
test_nat_remove_filter(ctx->nat, f);
if (print_headings)
printf("TEST NUA-11.5.2: PASSED\n");
END();
}
static
size_t change_status_to_483(void *a, void *message, size_t len)
{
(void)a;
if (strncmp("SIP/2.0 2", message, 9) == 0) {
memcpy(message, "SIP/2.0 483", 11);
}
return len;
}
int save_until_notified_and_responded_twice(CONDITION_PARAMS)
{
save_event_in_list(ctx, event, ep, call);
if (event == nua_i_notify) {
if (ep->flags.bit0)
ep->flags.bit1 = 1;
ep->flags.bit0 = 1;
}
if (event == nua_r_subscribe || event == nua_r_unsubscribe) {
if (status >= 300)
return 1;
else if (status >= 200) {
if (ep->flags.bit2)
ep->flags.bit3 = 1;
ep->flags.bit2 = 1;
}
}
return ep->flags.bit0 && ep->flags.bit1 && ep->flags.bit2 && ep->flags.bit3;
}
int save_until_notify_responded_twice(CONDITION_PARAMS)
{
save_event_in_list(ctx, event, ep, call);
if (event == nua_r_notify) {
if (ep->flags.bit0)
ep->flags.bit1 = 1;
ep->flags.bit0 = 1;
}
return ep->flags.bit0 && ep->flags.bit1;
}
/* ---------------------------------------------------------------------- */
/* Unsolicited NOTIFY */
int accept_notify(CONDITION_PARAMS);
int test_newsub_notify(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;
sip_t const *sip;
sip_call_id_t *i;
tagi_t const *n_tags, *r_tags;
if (print_headings)
printf("TEST NUA-11.7.1: rejecting NOTIFY without subscription locally\n");
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
NOTIFY(a, a_call, a_call->nh, NUTAG_URL(b->contact->m_url),
SIPTAG_SUBJECT_STR("NUA-11.7.1"),
SIPTAG_EVENT_STR("message-summary"),
SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"),
SIPTAG_PAYLOAD_STR("Messages-Waiting: yes"),
TAG_END());
run_a_until(ctx, -1, save_until_final_response);
/* Client events:
nua_notify(), nua_r_notify
*/
TEST_1(e = a->events->head);
TEST_E(e->data->e_event, nua_r_notify);
TEST(e->data->e_status, 481);
TEST_1(!e->data->e_msg);
TEST_1(!e->next);
free_events_in_list(ctx, a->events);
if (print_headings)
printf("TEST NUA-11.7.1: PASSED\n");
if (print_headings)
printf("TEST NUA-11.7.2: rejecting NOTIFY without subscription\n");
TEST_1(i = sip_call_id_create(nua_handle_home(a_call->nh), NULL));
NOTIFY(a, a_call, a_call->nh, NUTAG_URL(b->contact->m_url),
NUTAG_NEWSUB(1),
SIPTAG_SUBJECT_STR("NUA-11.7.2 first"),
SIPTAG_FROM_STR("<sip:alice@example.com>;tag=nua-11.7.2"),
SIPTAG_CALL_ID(i),
SIPTAG_CSEQ_STR("1 NOTIFY"),
SIPTAG_EVENT_STR("message-summary"),
SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"),
SIPTAG_PAYLOAD_STR("Messages-Waiting: yes"),
TAG_END());
run_a_until(ctx, -1, save_until_final_response);
/* Client events:
nua_notify(), nua_r_notify
*/
TEST_1(e = a->events->head);
TEST_E(e->data->e_event, nua_r_notify);
TEST(e->data->e_status, 481);
TEST_1(e->data->e_msg);
TEST_1(!e->next);
free_events_in_list(ctx, a->events);
/* 2nd NOTIFY using same dialog */
/* Check that server really discards the dialog */
NOTIFY(a, a_call, a_call->nh, NUTAG_URL(b->contact->m_url),
NUTAG_NEWSUB(1),
SIPTAG_SUBJECT_STR("NUA-11.7.2 second"),
SIPTAG_FROM_STR("<sip:alice@example.com>;tag=nua-11.7.2"),
SIPTAG_CALL_ID(i),
SIPTAG_CSEQ_STR("2 NOTIFY"),
SIPTAG_EVENT_STR("message-summary"),
SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"),
SIPTAG_PAYLOAD_STR("Messages-Waiting: yes"),
TAG_END());
run_a_until(ctx, -1, save_until_final_response);
/* Client events:
nua_notify(), nua_r_notify
*/
TEST_1(e = a->events->head);
TEST_E(e->data->e_event, nua_r_notify);
TEST(e->data->e_status, 481);
TEST_1(e->data->e_msg);
TEST_1(!e->next);
free_events_in_list(ctx, a->events);
if (print_headings)
printf("TEST NUA-11.7.2: PASSED\n");
/* ---------------------------------------------------------------------- */
if (print_headings)
printf("TEST NUA-11.7.3: accept NOTIFY\n");
nua_set_params(b->nua, NUTAG_APPL_METHOD("NOTIFY"), TAG_END());
run_b_until(ctx, nua_r_set_params, until_final_response);
NOTIFY(a, a_call, a_call->nh,
NUTAG_URL(b->contact->m_url),
NUTAG_NEWSUB(1),
SIPTAG_SUBJECT_STR("NUA-11.7.3"),
SIPTAG_EVENT_STR("message-summary"),
SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"),
SIPTAG_PAYLOAD_STR("Messages-Waiting: yes"),
TAG_END());
run_ab_until(ctx, -1, save_until_final_response, -1, accept_notify);
/* Notifier events: nua_r_notify */
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_notify);
TEST(e->data->e_status, 200);
r_tags = e->data->e_tags;
TEST_1(tl_find(r_tags, nutag_substate));
TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_terminated);
/* subscriber events:
nua_i_notify
*/
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_notify);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_subscription_state);
TEST_S(sip->sip_subscription_state->ss_substate, "terminated");
n_tags = e->data->e_tags;
TEST_1(tl_find(n_tags, nutag_substate));
TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_terminated);
TEST_1(!e->next);
free_events_in_list(ctx, a->events);
free_events_in_list(ctx, b->events);
if (print_headings)
printf("TEST NUA-11.7.3: PASSED\n");
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-11.7: PASSED\n");
END();
}
/**Terminate when received notify.
* Respond to NOTIFY with 200 OK if it has not been responded.
* Save events (except nua_i_active or terminated).
*/
int accept_notify(CONDITION_PARAMS)
{
if (event == nua_i_notify && status < 200)
RESPOND(ep, call, nh, SIP_200_OK,
NUTAG_WITH_THIS(ep->nua),
TAG_END());
save_event_in_list(ctx, event, ep, call);
return event == nua_i_notify;
}
/* ======================================================================== */
int save_until_subscription_terminated(CONDITION_PARAMS);
int accept_subscription_until_terminated(CONDITION_PARAMS);
/* Timeout subscription */
int test_subscription_timeout(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;
sip_t const *sip;
tagi_t const *n_tags, *r_tags;
if (print_headings)
printf("TEST NUA-11.8: subscribe and wait until subscription times out\n");
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
METHOD(a, a_call, a_call->nh,
NUTAG_METHOD("SUBSCRIBE"),
NUTAG_URL(b->contact->m_url),
SIPTAG_EVENT_STR("presence"),
SIPTAG_ACCEPT_STR("application/xpidf, application/pidf+xml"),
SIPTAG_EXPIRES_STR("2"),
NUTAG_APPL_METHOD("NOTIFY"),
NUTAG_DIALOG(2),
TAG_END());
run_ab_until(ctx,
-1, save_until_subscription_terminated,
-1, accept_subscription_until_terminated);
/* Client events:
nua_method(), nua_i_notify/nua_r_method, nua_i_notify
*/
TEST_1(e = a->events->head);
if (e->data->e_event == nua_i_notify) {
TEST_E(e->data->e_event, nua_i_notify);
TEST_1(sip = sip_object(e->data->e_msg));
n_tags = e->data->e_tags;
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_subscribe);
r_tags = e->data->e_tags;
}
else {
TEST_E(e->data->e_event, nua_r_method);
TEST(e->data->e_status, 202);
r_tags = e->data->e_tags;
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
TEST_1(sip = sip_object(e->data->e_msg));
n_tags = e->data->e_tags;
}
TEST_1(sip->sip_event); TEST_S(sip->sip_event->o_type, "presence");
TEST_1(sip->sip_content_type);
TEST_S(sip->sip_content_type->c_type, "application/pidf+xml");
TEST_1(sip->sip_subscription_state);
TEST_S(sip->sip_subscription_state->ss_substate, "pending");
TEST_1(sip->sip_subscription_state->ss_expires);
TEST_1(tl_find(n_tags, nutag_substate));
TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_pending);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
n_tags = e->data->e_tags;
TEST_1(tl_find(n_tags, nutag_substate));
TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_terminated);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_event);
TEST_1(sip->sip_subscription_state);
TEST_S(sip->sip_subscription_state->ss_substate, "terminated");
TEST_1(!sip->sip_subscription_state->ss_expires);
TEST_1(!e->next);
free_events_in_list(ctx, a->events);
/* Server events: nua_i_subscribe, nua_r_notify */
TEST_1(e = b->events->head);
TEST_E(e->data->e_event, nua_i_subscribe);
TEST_E(e->data->e_status, 100);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_notify);
r_tags = e->data->e_tags;
TEST_1(tl_find(r_tags, nutag_substate));
TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_pending);
/* Notifier events: 2nd nua_r_notify */
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_notify);
TEST_1(e->data->e_status >= 200);
r_tags = e->data->e_tags;
TEST_1(tl_find(r_tags, nutag_substate));
TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_terminated);
free_events_in_list(ctx, b->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-11.8: PASSED\n");
END();
}
int save_until_subscription_terminated(CONDITION_PARAMS)
{
void *with = nua_current_request(nua);
save_event_in_list(ctx, event, ep, call);
if (event == nua_i_notify) {
if (status < 200)
RESPOND(ep, call, nh, SIP_200_OK, NUTAG_WITH(with), TAG_END());
tags = tl_find(tags, nutag_substate);
return tags && tags->t_value == nua_substate_terminated;
}
return 0;
}
int accept_subscription_until_terminated(CONDITION_PARAMS)
{
void *with = nua_current_request(nua);
save_event_in_list(ctx, event, ep, call);
if (event == nua_i_subscribe && status < 200) {
RESPOND(ep, call, nh, SIP_202_ACCEPTED,
NUTAG_WITH(with),
SIPTAG_EXPIRES_STR("360"),
TAG_END());
NOTIFY(ep, call, nh,
SIPTAG_EVENT(sip->sip_event),
SIPTAG_CONTENT_TYPE_STR("application/pidf+xml"),
SIPTAG_PAYLOAD_STR(presence_closed),
NUTAG_SUBSTATE(nua_substate_pending),
TAG_END());
}
else if (event == nua_r_notify) {
tags = tl_find(tags, nutag_substate);
return tags && tags->t_value == nua_substate_terminated;
}
return 0;
}
/* ======================================================================== */
/* Test simple methods: MESSAGE, PUBLISH, SUBSCRIBE/NOTIFY */
@@ -628,5 +1302,8 @@ int test_simple(struct context *ctx)
test_message(ctx)
|| test_publish(ctx)
|| test_subscribe_notify(ctx)
|| test_subscribe_notify_graceful(ctx)
|| test_newsub_notify(ctx)
|| test_subscription_timeout(ctx)
;
}
@@ -64,15 +64,15 @@ int save_until_notified(CONDITION_PARAMS)
int save_until_notified_and_responded(CONDITION_PARAMS)
{
save_event_in_list(ctx, event, ep, call);
if (event == nua_i_notify) ep->flags.b.bit0 = 1;
if (event == nua_i_notify) ep->flags.bit0 = 1;
if (event == nua_r_subscribe || event == nua_r_unsubscribe) {
if (status >= 300)
return 1;
else if (status >= 200)
ep->flags.b.bit1 = 1;
ep->flags.bit1 = 1;
}
return ep->flags.b.bit0 && ep->flags.b.bit1;
return ep->flags.bit0 && ep->flags.bit1;
}
@@ -58,4 +58,5 @@ EXTRA_DIST = Doxyfile sdp.docs $(BUILT_SOURCES) \
# ----------------------------------------------------------------------
# Sofia specific rules
include ../sofia.am
include $(top_srcdir)/rules/sofia.am
Loaded 100 of 270 files, more files were not shown because too many files have changed in this diff. Show more