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 2007-04-15 02:03:41 +00:00
parent fabed21ea8
commit 853936abd3
270 changed files with 37125 additions and 11406 deletions

View File

@ -10,6 +10,8 @@ Contributors (in alphabetical order, surname first)
Chan, Tat <first.surname@nokia.com>
Ciarkowski, Andrzej <wp-voigtkampff -at users -dot sourceforge -dot net>
Denis-Courmont, Remi <first.surname@nokia.com>
Filonenko Roman <shkoder -at ua -dot fm>
Haataja, Mikko <first.surname@nokia.com>
Jacobs, Remeres <first.surname@nokia.com>
Jalava, Teemu <first.surname@nokia.com>
@ -26,9 +28,7 @@ Urpalainen, Jari <first.surname@nokia.com>
Whittaker, Colin <colinw -at occamnetworks -dot com>
Zabaluev, Mikhail <first.surname@nokia.com>
Note: for details on who did what, see the version control
system change history, and release notes for past releases at
http://sofia-sip.sourceforge.net/relnotes/

View File

@ -221,3 +221,31 @@ other special, indirect and consequential damages, even if author has
been advised of the possibility of such damages.
----------------------------------------------------------------------------
libsofia-sip-ua/su/poll.c
The package also contains files from GNU C Library by Free Software
Foundation.
These files are distributed with the following copyright notice:
Copyright (C) 1994,1996,1997,1998,1999,2001,2002
Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C 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.
The GNU C 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 the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA.
----------------------------------------------------------------------------

View File

@ -27,6 +27,10 @@ ACLOCAL_AMFLAGS = -I m4
EXTRA_DIST += m4/sac-general.m4 m4/sac-su.m4 \
m4/sac-su2.m4 m4/sac-tport.m4 m4/sac-openssl.m4
EXTRA_DIST += docs/build_system.txt \
docs/devel_platform_notes.txt \
docs/release_management.txt
dist_man_MANS = man/man1/sip-date.1 man/man1/sip-options.1 \
man/man1/localinfo.1 man/man1/addrinfo.1 \
man/man1/stunc.1 man/man1/sip-dig.1
@ -44,7 +48,12 @@ endif
CLEANFILES = $(dist_man_MANS)
coverage built-sources clean-built-sources doxygen:
for i in libsofia-sip-ua $(GLIB_SUBDIRS) ; do $(MAKE) $(AM_MAKEFLAGS) -C $$i $@ ; done
coverage built-sources clean-built-sources valcheck doxygen:
@failcom='exit 1'; for f in x $$MAKEFLAGS; do \
case $$f in *=* | --[!k]*);; *k*) failcom='fail=yes';; esac; done; \
for i in libsofia-sip-ua $(GLIB_SUBDIRS) ; do \
(cd $$i && $(MAKE) $(AM_MAKEFLAGS) $@) || eval $$failcom; \
done ; \
test -z "$$fail"
.PHONY: coverage built-sources clean-built-sources doxygen manpages
.PHONY: coverage built-sources clean-built-sources valcheck doxygen manpages

View File

@ -46,7 +46,6 @@ The Sofia-SIP su submodule also provides some small utilities:
- localinfo (libsofia-sip-ua/su), prints information about
local network interfaces
References
----------

View File

@ -5,98 +5,108 @@ Release notes for current version of Sofia-SIP
Changes since last release
--------------------------
<changes since last written in freshmeat.net "Changes:" style;
and in less than 10 lines />
Bugs in blaa and foo have been fixed. The stack now supports
use of foobar...
Numerous nua bugs introduced in the release 1.12.5 have been fixed. Support
for nextnonce in Authentication-Info header has been added. The nua engine
now fully supports application-driven SDP.
API/ABI changes and versioning
------------------------------
<see previous release notes at
http://sofia-sip.sourceforge.net/relnotes/ for examples ;
- should include all changes to public headers, and
other important information to developers;
- and should be updated _continuously_! />
**template**: New features in API are marked with Doxytag macro @VERSION_1_XX_X.
libsofia-sip-ua:
- **template**: Added foobar() function (sofia-sip/foobar.h).
- Added sip_is_allowed() function and k_bitmap field to the
sip_allow_t structure
- Added SIP header Refer-Sub and related functions
- Added <sofia-sip/sip_extra.h> include file
- Added auc_info() function (sofia-sip/auth_client.h)
- Use calling/received callstate in nua_i_state event sent because of UPDATE
while call is ready
- Added tag define NUTAG_WITH_CURRENT() as an alias to NUTAG_WITH_THIS()
- Added tag NUTAG_DIALOG() controlling whether nua_method() creates a dialog.
- Added tag NUTAG_AUTH_CACHE() <sofia-sip/nua_tag.h> determining when to
include credentials in the request
- Added kqueue and /dev/poll interfaces (su_devpoll_port_create(),
su_devpoll_clone_start(), su_kqueue_port_create(), su_kqueue_clone_start()
in <sofia-sip/su_wait.h>)
- Added SIP_IS_ALLOWED() macro to <sofia-sip/sip_util.h>
- Fixed NUTAG_APPL_METHOD() implementation for UPDATE and PRACK as documented
("100rel" and "precondition" extensions now require explicit calls to
nua_update() and nua_prack() if those methods are included in
NUTAG_APPL_METHOD())
- Added auc_clear field and member to authentication client plugin interface
in <sofia-sip/auth_client_plugin.h>
- Added nua_event_is_incoming_request() to <sofia-sip/nua.h>
- This release is ABI/API compatible with applications linked against
any 1.12.x release. However, applications built against this release won't
work against an older library. The ABI has been tested with the nua module
unit test (test_nua) built against original 1.12.0 release.
libsofia-sip-ua-glib:
- The 'nua-glib' module has been removed from the library and moved
to a separate package 'sofia-nua-glib'. The remaining library (su-glib)
is now considered stable and will be API/ABI compatible with later
releases in the 1.12.x series.
- ABI has been modified and applications built against 1.12.4 and earlier
releases need to be rebuilt.
- No ABI/API changes, compatible with 1.12.0. Note, libsofia-sip-ua-glib
interface is not considered stable and may change in a future 1.12.x
release.
Contributors to this release
----------------------------
<list of people who contributed to _this_ release
- update as people's patches are added, or when you commit stuff
- current development team members (see AUTHORS) may be omitted
- name of the contributor should be enough (email addresses in AUTHORS),
plus a brief description of what was contributed
- roughly sorted by number of patches accepted
/>
- **template**: First Surname (patch to nua/soa/msg)
- Petteri Puolakka (patch to stun)
- Mikhail Zabluev (patch to su-glib mainloop integration)
- Pekka Pessi (/dev/poll interface to Solaris, kqueue)
- Martti Mela (kqueue interface to Max OS X and FreeBSD)
- Michael Jerris (Solaris patches)
- Colin Whittaker (sresolv patch)
See the AUTHORS file in the distribution package.
Notes on new features
---------------------
RFC 4488 defines the Refer-Sub header. Its datatypes, related functions and
methods declared in <sofia-sip/sip_extra.h> include file. The Refer-Sub
header structure can be accessed from sip_t structure with sip_refer_sub()
method, e.g.,
The Sofia-SIP has been compiled and tested on Solaris. The /dev/poll
interface (in su_devpoll_port.c) has been added for Solaris. Likewise, the
kqueue interface (in su_kqueue_port.c) has been added for FreeBSD and Mac OS
X. There is also select-based reactor for systems without poll().
if (sip_refer_sub(sip) &&
strcasecmp("false", sip_refer_sub(sip)->rs_value) == 0) {
/* Do not create implicit subscription */
}
The client authentication in nua has been updated. The nextnonce in
Authentication-Info or Proxy-Authentication-Info headers is now used during
the next . The NUTAG_AUTH_CACHE() policy determines how the cached
credentials are used. By default, the credentials are included in each
request within the dialog, however, with the
NUTAG_AUTH_CACHE(nua_auth_cache_challenged) the client authenticates
requests only after they have been challenged.
<information about major new features
- new/changed/removed functionality
- links to further documentation
- section may be omitted for minor releases
/>
The application can now fully control the SDP negotiation (when soa is
disabled with NUTAG_MEDIA_ENABLE(0)). The application can send UPDATE and
PRACK requests and respond to them. The callstate sent in nua_i_state after
UPDATE while the call has already been completed has been also changed.
Bugs fixed in this release
--------------------------
< notable bugs fixed in this release
- check the sf.net bug tracker; see closed bugs,
sorted by closing date
- other bugs as fixed in CVS/darcs
/>
- **template**: #9499652 sf.net bug item title
- Fixed crash when nua_bye() was called while a NOTIFY client transaction
was in progress. Problem reported by Anthony Minnessale.
- Not using close() with sockets in sres.c. Problem reported by
Roman Filonenko.
- Bug in zero-padding STUN messages with a message integrity
attribute. Patch by Petteri Puolakka.
- Fixed a severe problem with timer accuracy, when sofia-sip timers
where used under glib's mainloop.
- Improved glib mainloop integration to avoid warnings about already
active mainloop context, and potentially other issue. Patch by
Mikhail Zabaluev. Closes sf.net item #1606786.
- Fixed status code sent to network and returned to the client if there was
an internal error while responding to a request.
The problem was reported by Michael Jerris and Joshua Engelbrecht.
- Fixed #1685249, unclear termination of call in absense of credentials by
nua_authenticate(). Problem reported by Mikhail Zabaluev.
- Fixed status code reported to application when REGISTER transaction was
restarted by nua stack. Problem reported by Mikhail Zabaluev.
- An invalid Contact was used if STUN was disabled but there was no STUN
server. Problem reported by Miguel Freitas.
- Fixed problem logging long lines from with TPORT_LOG.
Problem reported by Mike Murdock and Michael Jerris.
- Nua now includes the SDP capabilities in the response to the OPTIONS
- Fixed assertion failure because BYE destroyed a session twice.
Problem reported by Michael Jerris.
- Fixed crash caused by a 0-length UDP datagram.
Problem reported by Michael Jerris.
- Fixed the 305 response handling by nua stack.
Bug #1676445 reported by Fabio Margarido.
- Fixed authentication-related bugs #1685245 and #1570746.
#1685245 reported by Mikhail Zabaluev.
- Fixed problems resuming DNS after server or link downtime.
Bug #1631198 reported and initial patch submitted by Colin Whittaker.
- Fixed NUTAG_APPL_METHOD() implementation for UPDATE and PRACK as documented
- Fixed crashes in nua state engines:
- when nua_invite() was called second time before receiving
final response to first INVITE
- when UAS expected PRACK but received CANCEL
- when UAC received error response to PRACK, it tried to send BYE and crashed
- when UAS rejected initial request, the subsequent request with same
dialog id (Call-ID, From-tag) crashed (dialog cleanup code left dialog
dangling)
Problems reported by Michael Jerris
- Fixed crash in nta state engine:
- DNS resolver failure in non-invite transctions crashed
- Fixed sdp handling when soa is disabled (NUTAG_MEDIA_ENABLE(0)).
Problem reported by Marcin Michalak

View File

@ -6,7 +6,8 @@ Changes since last release
--------------------------
<changes since last written in freshmeat.net "Changes:" style;
and in less than 10 lines />
and in less than 10 lines, written in 3rd person English, with
complete sentences />
Bugs in blaa and foo have been fixed. The stack now supports
use of foobar...
@ -39,9 +40,11 @@ Contributors to this release
<list of people who contributed to _this_ release
- update as people's patches are added, or when you commit stuff
- current development team members (see AUTHORS) may be omitted
- current development team members (see AUTHORS) may be omitted,
or listed at the end of the contribur list (depending on the scope
of the work done since the last release)
- name of the contributor should be enough (email addresses in AUTHORS),
plus a brief description of what was contributed
plus a _brief_ description of what was contributed
- roughly sorted by number of patches accepted
/>

View File

@ -11,14 +11,14 @@ dnl information on the package
dnl ---------------------------
dnl update both the version for AC_INIT and the LIBSOFIA_SIP_UA_MAJOR_MINOR
AC_INIT([sofia-sip], [1.12.4work])
AC_INIT([sofia-sip], [1.12.5work6])
AC_CONFIG_SRCDIR([libsofia-sip-ua/sip/sofia-sip/sip.h])
AC_SUBST(VER_LIBSOFIA_SIP_UA_MAJOR_MINOR, [1.12])
dnl Includedir specific to this sofia version
AC_SUBST(include_sofiadir, '${includedir}/sofia-sip-1.12')
AC_SUBST(LIBVER_SOFIA_SIP_UA_CUR, [3])
AC_SUBST(LIBVER_SOFIA_SIP_UA_CUR, [5])
AC_SUBST(LIBVER_SOFIA_SIP_UA_REV, [0])
AC_SUBST(LIBVER_SOFIA_SIP_UA_AGE, [3])
AC_SUBST(LIBVER_SOFIA_SIP_UA_AGE, [5])
AC_SUBST(LIBVER_SOFIA_SIP_UA_SOVER, [0]) # CUR-AGE
AC_SUBST(LIBVER_SOFIA_SIP_UA_GLIB_CUR, [3])
AC_SUBST(LIBVER_SOFIA_SIP_UA_GLIB_REV, [0])
@ -53,8 +53,15 @@ SAC_ENABLE_EXPENSIVE_CHECKS
dnl Add parameters for aclocal
AC_SUBST(ACLOCAL_AMFLAGS, "-I m4")
AC_CHECK_PROG([DOXYGEN], [doxygen], [doxygen], [echo])
AM_CONDITIONAL([HAVE_DOXYGEN], [test $DOXYGEN = doxygen])
AC_ARG_WITH(doxygen,
[ --with-doxygen[[=CMD]] use doxygen command CMD [[doxygen]]],[
case $enable_doxygen in
yes ) doxygen=doxygen ;;
no ) doxygen=echo ;;
esac], doxygen=doxygen)
AC_CHECK_PROG([DOXYGEN], [doxygen], [$doxygen], [echo])
AM_CONDITIONAL([HAVE_DOXYGEN], [test $DOXYGEN != echo])
### checks for libraries
### --------------------
@ -71,7 +78,7 @@ AC_DEFINE([HAVE_SOFIA_SRESOLV], 1, [Define to 1 if we use DNS library])
AC_DEFINE([HAVE_SOFIA_SMIME], 0, [Define to 1 if we use S/MIME library])
AC_ARG_ENABLE(stun,
[ --disable-stun disable stun module (enabled)],
[ --disable-stun disable stun module (enabled)],
, enable_stun=yes)
if test x$enable_stun = xno ; then
@ -83,10 +90,19 @@ elif test x${HAVE_OPENSSL} != x1 ; then
else
AC_DEFINE([HAVE_SOFIA_STUN], 1, [Define to 1 if we use STUN library])
fi
AM_CONDITIONAL([HAVE_STUN], [test "x$enable_stun" = xyes])
AC_ARG_ENABLE(nth,
[ --disable-nth disable nth and http modules (enabled)],
, enable_nth=yes)
AM_CONDITIONAL([HAVE_NTH], [test "x$enable_nth" = xyes])
if test x$enable_nth = xyes ; then
AC_DEFINE([HAVE_SOFIA_NTH], 1, [Define to 1 if we use NTH library])
fi
dnl Disable NTLM support by default
AC_ARG_ENABLE(ntlm,
[ --enable-ntlm enable NTLM support (disabled)],
[ --enable-ntlm enable NTLM support [[disabled]]],
, enable_ntlm=no)
if test x$enable_ntlm = xyes ; then
@ -104,22 +120,97 @@ AC_HEADER_STDC
### checks for declarations
### -----------------------
AC_CHECK_DECL([SIGPIPE], [
AC_DEFINE([HAVE_SIGPIPE], 1, [Define to 1 if you have SIGPIPE])],,[
#include <signal.h>
])
### checks for types
### ----------------
AC_TYPE_SIGNAL
AC_TYPE_LONGLONG([
AC_DEFINE([LLU], ["%llu"], [Define to format (%llu) for unsigned long long])dnl
AC_DEFINE([LLI], ["%lli"], [Define to format (%lli) for long long])dnl
AC_DEFINE([LLX], ["%llx"], [Define to format (%llx) for long long hex])dnl
AC_TYPE_LONGLONG
dnl
dnl Define HAVE_C99_FORMAT to 1 if the formatted IO functions (printf/scanf
dnl et.al.) support the C99 'size specifiers', namely ll, hh, j, z, t
dnl (representing long long int, char, intmax_t, size_t, ptrdiff_t). Some C
dnl compilers supported these specifiers prior to C99 as an extension.
dnl
AC_CACHE_CHECK([whether IO functions support C99 size specifiers],
[ac_cv_c_c99_format],[
ac_cv_c_c99_format=yes
AC_RUN_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT],
[[char buf[64];
if (sprintf(buf, "%lld%hhd%jd%zd%td", (long long int)1, (char)2, (intmax_t)3, (size_t)4, (ptrdiff_t)5) != 5)
exit(1);
else if (strcmp(buf, "12345"))
exit(2);]])],
[ac_cv_c_c99_format=yes],
[ac_cv_c_c99_format=no],
[ac_cv_c_c99_format=yes])
])
AC_DEFINE([MOD_ZD], ["%zd"], [Define printf() modifier for ssize_t])
AC_DEFINE([MOD_ZU], ["%zu"], [Define printf() modifier for size_t])
if test $ac_cv_c_c99_format = yes; then
AC_DEFINE([HAVE_C99_FORMAT], [1], [Define to 1 if printf supports C99 size specifiers])dnl
AC_DEFINE([LLU], ["%llu"], [Format (%llu) for unsigned long long])dnl
AC_DEFINE([LLI], ["%lli"], [Format (%lli) for long long])dnl
AC_DEFINE([LLX], ["%llx"], [Format (%llx) for long long hex])dnl
AC_DEFINE([MOD_ZD], ["%zd"], [Define printf() modifier for ssize_t])dnl
AC_DEFINE([MOD_ZU], ["%zu"], [Define printf() modifier for size_t])dnl
else
AC_CACHE_CHECK([whether IO functions support size specifier for long long],
[ac_cv_c_ll_format],[
ac_cv_c_ll_format=yes
AC_RUN_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT],
[[char buf[64];
if (sprintf(buf, "%lld", (long long int)1) != 1)
exit(1);
else if (strcmp(buf, "1"))
exit(2);]])],
[ac_cv_c_ll_format=yes],
[ac_cv_c_ll_format=no],
[ac_cv_c_ll_format=yes])
])
if test $ac_cv_c_ll_format = yes; then
AC_DEFINE([LLU], ["%llu"], [Format (%llu) for unsigned long long])dnl
AC_DEFINE([LLI], ["%lli"], [Format (%lli) for long long])dnl
AC_DEFINE([LLX], ["%llx"], [Format (%llx) for long long hex])dnl
else
AC_MSG_ERROR("printf cannot handle 64-bit integers")
fi
AC_CACHE_CHECK([whether IO functions support size specifier for size_t],
[ac_cv_c_z_format],[
ac_cv_c_z_format=yes
AC_RUN_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT],
[[char buf[64];
if (sprintf(buf, "%zd", (size_t)1) != 1)
exit(1);
else if (strcmp(buf, "1"))
exit(2);]])],
[ac_cv_c_z_format=yes],
[ac_cv_c_z_format=no],
[ac_cv_c_z_format=yes])
])
if test $ac_cv_c_z_format = yes; then
AC_DEFINE([MOD_ZD], ["%ld"], [Define printf() modifier for ssize_t])dnl
AC_DEFINE([MOD_ZU], ["%lu"], [Define printf() modifier for size_t])dnl
else
dnl Cross fingers
AC_MSG_WARN("printf cannot handle size_t, using long instead")
AC_DEFINE([MOD_ZD], ["%ld"], [Define printf() modifier for ssize_t])dnl
AC_DEFINE([MOD_ZU], ["%lu"], [Define printf() modifier for size_t])dnl
fi
fi
### checks for structures
### ---------------------

View File

@ -38,6 +38,11 @@ Makefile target notes
separately in ``DIST_SOURCES`` variable (otherwise ``make dist``
will fail)
Makefile fragments
------------------
Some common makefile rules are in 'rules' subdirectory.
Maintainer mode
---------------
@ -54,13 +59,16 @@ option '--enable-maintainer-mode'.
Running tests
=============
Sofia-SIP has quite complete suite of test cases. It is prudent to
run them while making changes and before committing them to revision
control system. However, running certain tests takes quite a long
time. Therefore, they are run only if the environment variable
Sofia-SIP has quite complete suite of test cases. It is prudent to run
them while making changes and before committing them to revision control
system. However, running certain tests takes quite a long time to
execture. Therefore, they are run only if the environment variable
EXPENSIVE_CHECKS has been set. EXPENSIVE_CHECKS is also set by the build
system if configure option '--enable-expensive-checks' has been used.
On hosts with i386 architecture, it is possible to run tests under
valgrind. Use the make target 'valcheck' for that purpose.
Code-tree layout
================

View File

@ -11,14 +11,30 @@ up-to-date autotools. Autoconf should be at least 2.57 and automake should
be at least 1.7. You can avoid running autoreconf explicitly if you use
./configure option --enable-maintainer-mode.
Notes to distributors
----------------------
Build options such as "--disable-stun" (HAVE_SOFIA_STUN) and
"--disable-nth" (HAVE_SOFIA_NTH) modify the public library API/ABI,
by omitting certain interfaces from the resulting library and installed
header files.
Options such as '--disable-size-compat' modify the library
ABI by changing the types used in public library function
signatures.
Generic POSIX (GNU/Linux, BSD, ...)
-----------------------------------
Sofia-SIP should compile out-of-the-box on generic POSIX
machines. Use the standard GNU autotool 'configure+make'
procedure to build the software. See top-level INSTALL
procedure to build the software. See top-level README file
for more information.
The configure script accepts various options. See "./configure --help"
for the full list.
Mac OS X
--------

View File

@ -61,7 +61,8 @@ Making the release tarball
sh> cvs tag rel-sofia-sip-x_y_z
- take a fresh checkout of the release using the release tag
sh> darcs get http://sofia-sip.org/repos/sofia-sip --tag=rel-sofia-sip-1_yy_z
- create the release tarball with "make distcheck"
- create the release tarball with "make distcheck" (make sure depcomp et
al libtool scripts are correctly created)
- calculate md5 and sha1 hashes using md5sum and sha1sum utilities,
and copy the values to the release-notes (see below)

View File

@ -31,16 +31,6 @@ EXTRA_DIST = docs/Doxyfile.aliases \
docs/Doxyfile.conf \
docs/Doxyfile.version
built-sources: built-sources-recursive
clean-built-sources: clean-built-sources-recursive
built-sources-recursive clean-built-sources-recursive:
target=`echo $@ | sed s/-recursive//`; \
list='$(SUBDIRS)'; for subdir in $$list; do \
echo "Making $@ in $$subdir"; \
(cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$target) \
done;
doxygen: built-sources
@cd ${srcdir} ;\
mkdir -p docs docs/html &&\
@ -53,4 +43,6 @@ doxygen: built-sources
done
cd ${srcdir}/docs/html && ../../${top_srcdir}/libsofia-sip-ua/docs/hide_emails.sh
include $(top_srcdir)/rules/recursive.am
.PHONY: built-sources built-sources-am doxygen

View File

@ -58,4 +58,4 @@ AUTOMAKE_OPTIONS = foreign
# ----------------------------------------------------------------------
# Sofia specific rules
include ../../libsofia-sip-ua/sofia.am
include $(top_srcdir)/rules/sofia.am

View File

@ -43,6 +43,7 @@ SOFIA_BEGIN_DECLS
SOFIAPUBFUN su_root_t *su_glib_root_create(su_root_magic_t *) __attribute__((__malloc__));
SOFIAPUBFUN GSource *su_glib_root_gsource(su_root_t *);
SOFIAPUBFUN void su_glib_prefer_gsource(void);
SOFIA_END_DECLS

View File

@ -25,7 +25,11 @@
/**
* @file su_source.c
* @brief Wrapper for glib GSource.
* *
*
* Refs:
* - http://sofia-sip.sourceforge.net/refdocs/su/group__su__wait.html
* - http://developer.gnome.org/doc/API/glib/glib-the-main-event-loop.html
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>.
*
* @date Created: Thu Mar 4 15:15:15 2004 ppessi
@ -36,12 +40,6 @@
#include "config.h"
#endif
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <glib.h>
#define SU_PORT_IMPLEMENTATION 1
@ -57,16 +55,26 @@
#include "su_port.h"
#include "sofia-sip/su_alloc.h"
static su_port_t *su_source_create(void) __attribute__((__malloc__));
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#if 1
#define PORT_LOCK_DEBUG(x) ((void)0)
#else
#define PORT_LOCK_DEBUG(x) printf x
#endif
static su_port_t *su_source_port_create(void) __attribute__((__malloc__));
static gboolean su_source_prepare(GSource *gs, gint *return_tout);
static gboolean su_source_check(GSource *gs);
static gboolean su_source_dispatch(GSource *gs,
GSourceFunc callback,
gpointer user_data);
GSourceFunc callback,
gpointer user_data);
static void su_source_finalize(GSource *source);
static int su_source_getmsgs(su_port_t *self);
static
GSourceFuncs su_source_funcs[1] = {{
su_source_prepare,
@ -106,21 +114,22 @@ static void su_source_break(su_port_t *self);
static su_duration_t su_source_step(su_port_t *self, su_duration_t tout);
static int su_source_own_thread(su_port_t const *port);
static int su_source_add_prepoll(su_port_t *port,
su_root_t *root,
su_prepoll_f *,
su_prepoll_magic_t *);
su_root_t *root,
su_prepoll_f *,
su_prepoll_magic_t *);
static int su_source_remove_prepoll(su_port_t *port,
su_root_t *root);
static su_timer_t **su_source_timers(su_port_t *port);
static int su_source_multishot(su_port_t *self, int multishot);
static int su_source_threadsafe(su_port_t *port);
static
su_port_vtable_t const su_source_vtable[1] =
static char const *su_source_name(su_port_t const *self);
static
su_port_vtable_t const su_source_port_vtable[1] =
{{
/* su_vtable_size: */ sizeof su_source_vtable,
/* su_vtable_size: */ sizeof su_source_port_vtable,
su_source_lock,
su_source_unlock,
su_source_incref,
su_source_decref,
@ -138,32 +147,38 @@ su_port_vtable_t const su_source_vtable[1] =
su_source_own_thread,
su_source_add_prepoll,
su_source_remove_prepoll,
su_source_timers,
su_base_port_timers,
su_source_multishot,
su_source_threadsafe
su_base_port_threadsafe,
/*su_source_yield*/ NULL,
/*su_source_wait_events*/ NULL,
su_base_port_getmsgs,
su_base_port_getmsgs_from,
su_source_name,
su_base_port_start_shared,
su_base_port_wait,
NULL,
}};
static char const *su_source_name(su_port_t const *self)
{
return "GSource";
}
/**
* Port is a per-thread reactor.
*
* Multiple root objects executed by single thread share a su_port_t object.
*/
struct su_source_s {
su_home_t sup_home[1];
su_port_vtable_t const *sup_vtable;
su_base_port_t sup_base[1];
GThread *sup_tid;
GStaticMutex sup_mutex[1];
GStaticRWLock sup_ref[1];
GSource *sup_source;
GMainLoop *sup_main_loop;
GSource *sup_source; /**< Backpointer to source */
GMainLoop *sup_main_loop; /**< Reference to mainloop while running */
/* Message list - this is protected by lock */
su_msg_t *sup_head;
su_msg_t **sup_tail;
/* Waits */
unsigned sup_registers; /** Counter incremented by
su_port_register() or
@ -177,9 +192,6 @@ struct su_source_s {
su_wakeup_f *sup_wait_cbs;
su_wakeup_arg_t**sup_wait_args;
su_root_t **sup_wait_roots;
/* Timer list */
su_timer_t *sup_timers;
};
typedef struct _SuSource
@ -194,10 +206,6 @@ typedef struct _SuSource
#define SU_SOURCE_INCREF(p, f) (g_source_ref(p->sup_source))
#define SU_SOURCE_DECREF(p, f) (g_source_unref(p->sup_source))
#define SU_SOURCE_INITLOCK(p) (g_static_mutex_init((p)->sup_mutex))
#define SU_SOURCE_LOCK(p, f) (g_static_mutex_lock((p)->sup_mutex))
#define SU_SOURCE_UNLOCK(p, f) (g_static_mutex_unlock((p)->sup_mutex))
#else
/* Debugging versions */
@ -205,15 +213,6 @@ typedef struct _SuSource
#define SU_SOURCE_DECREF(p, f) do { printf("decref(%p) by %s\n", (p), f), \
g_source_unref(p->sup_source); } while(0)
#define SU_SOURCE_INITLOCK(p) \
(g_static_mutex_init((p)->sup_mutex), printf("init_lock(%p)\n", p))
#define SU_SOURCE_LOCK(p, f) \
(printf("%ld at %s locking(%p)...", g_thread_self(), f, p), g_static_mutex_lock((p)->sup_mutex), printf(" ...%ld at %s locked(%p)...", g_thread_self(), f, p))
#define SU_SOURCE_UNLOCK(p, f) \
(g_static_mutex_unlock((p)->sup_mutex), printf(" ...%ld at %s unlocked(%p)\n", g_thread_self(), f, p))
#endif
#if HAVE_FUNC
@ -229,7 +228,7 @@ typedef struct _SuSource
/** Create a root that uses GSource as reactor */
su_root_t *su_glib_root_create(su_root_magic_t *magic)
{
return su_root_create_with_port(magic, su_source_create());
return su_root_create_with_port(magic, su_source_port_create());
}
/** Deprecated */
@ -238,6 +237,15 @@ su_root_t *su_root_source_create(su_root_magic_t *magic)
return su_glib_root_create(magic);
}
/**
* Returns a GSource object for the root
*
* Note that you need to unref the GSource with g_source_unref()
* before destroying the root object.
*
* @return NULL on error (for instance if root was not created with
* su_glib_root_create())
*/
GSource *su_glib_root_gsource(su_root_t *root)
{
g_assert(root);
@ -246,41 +254,20 @@ GSource *su_glib_root_gsource(su_root_t *root)
/*=============== Private function definitions ===============*/
/**@internal
*
* Allocates and initializes a reactor and message port object.
*
* @return
* If successful a pointer to the new message port is returned, otherwise
* NULL is returned.
*/
su_port_t *su_source_create(void)
/** Initialize source port */
int su_source_port_init(su_port_t *self,
GSource *gs,
su_port_vtable_t const *vtable)
{
SuSource *ss;
if (su_base_port_init(self, vtable) < 0)
return -1;
SU_DEBUG_9(("su_source_create() called\n"));
self->sup_source = gs;
self->sup_tid = g_thread_self();
ss = (SuSource *)g_source_new(su_source_funcs, (sizeof *ss));
if (ss) {
su_port_t *self = ss->ss_port;
self->sup_vtable = su_source_vtable;
self->sup_source = ss->ss_source;
SU_SOURCE_INITLOCK(self);
self->sup_tail = &self->sup_head;
self->sup_tid = g_thread_self();
SU_DEBUG_9(("su_source_with_main_context() returns %p\n", self));
return self;
} else {
su_perror("su_source_with_main_context(): su_home_clone");
SU_DEBUG_9(("su_source_with_main_context() fails\n"));
return NULL;
}
g_static_mutex_init(self->sup_mutex);
return 0;
}
/** @internal Destroy a port. */
@ -294,23 +281,70 @@ void su_source_finalize(GSource *gs)
SU_DEBUG_9(("su_source_finalize() called\n"));
if (self->sup_waits)
free(self->sup_waits), self->sup_waits = NULL;
if (self->sup_wait_cbs)
free(self->sup_wait_cbs), self->sup_wait_cbs = NULL;
if (self->sup_wait_args)
free(self->sup_wait_args), self->sup_wait_args = NULL;
if (self->sup_wait_roots)
free(self->sup_wait_roots), self->sup_wait_roots = NULL;
if (self->sup_indices)
free(self->sup_indices), self->sup_indices = NULL;
g_static_mutex_free(self->sup_mutex);
su_home_deinit(self->sup_home);
su_base_port_deinit(self);
su_home_deinit(self->sup_base->sup_home);
}
void su_source_port_lock(su_port_t *self, char const *who)
{
PORT_LOCK_DEBUG(("%p at %s locking(%p)...",
(void *)g_thread_self(), who, self));
g_static_mutex_lock(self->sup_mutex);
PORT_LOCK_DEBUG((" ...%p at %s locked(%p)...",
(void *)g_thread_self(), who, self));
}
void su_source_port_unlock(su_port_t *self, char const *who)
{
g_static_mutex_unlock(self->sup_mutex);
PORT_LOCK_DEBUG((" ...%p at %s unlocked(%p)\n",
(void *)g_thread_self(), who, self));
}
/** @internal Send a message to the port. */
int su_source_send(su_port_t *self, su_msg_r rmsg)
{
int wakeup = su_base_port_send(self, rmsg);
GMainContext *gmc;
if (wakeup < 0)
return -1;
if (wakeup == 0)
return 0;
gmc = g_source_get_context(self->sup_source);
if (gmc)
g_main_context_wakeup(gmc);
return 0;
}
/** @internal
* Checks if the calling thread owns the port object.
*
* @param self pointer to a port object
*
* @retval true (nonzero) if the calling thread owns the port,
* @retval false (zero) otherwise.
*/
int su_source_own_thread(su_port_t const *self)
{
return self == NULL || SU_SOURCE_OWN_THREAD(self);
}
/* -- Registering and unregistering ------------------------------------- */
/* Seconds from 1.1.1900 to 1.1.1970 */
#define NTP_EPOCH 2208988800UL
/** Prepare to wait - calculate time to next timer */
static
gboolean su_source_prepare(GSource *gs, gint *return_tout)
{
@ -319,12 +353,12 @@ gboolean su_source_prepare(GSource *gs, gint *return_tout)
enter;
if (self->sup_head) {
if (self->sup_base->sup_head) {
*return_tout = 0;
return TRUE;
}
if (self->sup_timers) {
if (self->sup_base->sup_timers) {
su_time_t now;
GTimeVal gtimeval;
su_duration_t tout;
@ -333,7 +367,7 @@ gboolean su_source_prepare(GSource *gs, gint *return_tout)
now.tv_sec = gtimeval.tv_sec + 2208988800UL;
now.tv_usec = gtimeval.tv_usec;
tout = su_timer_next_expires(self->sup_timers, now);
tout = su_timer_next_expires(self->sup_base->sup_timers, now);
*return_tout = (tout < 0 || tout > (su_duration_t)G_MAXINT)?
-1 : (gint)tout;
@ -376,10 +410,10 @@ gboolean su_source_dispatch(GSource *gs,
enter;
if (self->sup_head)
su_source_getmsgs(self);
if (self->sup_base->sup_head)
su_base_port_getmsgs(self);
if (self->sup_timers) {
if (self->sup_base->sup_timers) {
su_time_t now;
GTimeVal gtimeval;
su_duration_t tout;
@ -392,7 +426,7 @@ gboolean su_source_dispatch(GSource *gs,
now.tv_sec = gtimeval.tv_sec + 2208988800UL;
now.tv_usec = gtimeval.tv_usec;
timers = su_timer_expire(&self->sup_timers, &tout, now);
timers = su_timer_expire(&self->sup_base->sup_timers, &tout, now);
}
#if SU_HAVE_POLL
@ -424,12 +458,20 @@ gboolean su_source_dispatch(GSource *gs,
static void su_source_lock(su_port_t *self, char const *who)
{
SU_SOURCE_LOCK(self, who);
PORT_LOCK_DEBUG(("%p at %s locking(%p)...",
(void *)g_thread_self(), who, self));
g_static_mutex_lock(self->sup_mutex);
PORT_LOCK_DEBUG((" ...%p at %s locked(%p)...",
(void *)g_thread_self(), who, self));
}
static void su_source_unlock(su_port_t *self, char const *who)
{
SU_SOURCE_UNLOCK(self, who);
g_static_mutex_unlock(self->sup_mutex);
PORT_LOCK_DEBUG((" ...%p at %s unlocked(%p)\n",
(void *)g_thread_self(), who, self));
}
static void su_source_incref(su_port_t *self, char const *who)
@ -448,81 +490,6 @@ GSource *su_source_gsource(su_port_t *self)
return self->sup_source;
}
/** @internal Send a message to the port. */
int su_source_send(su_port_t *self, su_msg_r rmsg)
{
enter;
if (self) {
su_msg_t *msg;
GMainContext *gmc;
SU_SOURCE_LOCK(self, "su_source_send");
msg = rmsg[0]; rmsg[0] = NULL;
*self->sup_tail = msg;
self->sup_tail = &msg->sum_next;
SU_SOURCE_UNLOCK(self, "su_source_send");
gmc = g_source_get_context(self->sup_source);
if (gmc)
g_main_context_wakeup(gmc);
return 0;
}
else {
su_msg_destroy(rmsg);
return -1;
}
}
/** @internal
* Execute the messages in the incoming queue until the queue is empty..
*
* @param self - pointer to a port object
*
* @retval 0 if there was a signal to handle,
* @retval -1 otherwise.
*/
static
int su_source_getmsgs(su_port_t *self)
{
enter;
if (self && self->sup_head) {
su_root_t *root;
su_msg_f f;
SU_SOURCE_INCREF(self, "su_source_getmsgs");
SU_SOURCE_LOCK(self, "su_source_getmsgs");
while (self->sup_head) {
su_msg_t *msg = self->sup_head;
self->sup_head = msg->sum_next;
if (!self->sup_head) {
assert(self->sup_tail == &msg->sum_next);
self->sup_tail = &self->sup_head;
}
root = msg->sum_to->sut_root;
f = msg->sum_func;
SU_SOURCE_UNLOCK(self, "su_source_getmsgs");
if (f)
f(su_root_magic(root), &msg, msg->sum_data);
su_msg_delivery_report(&msg);
SU_SOURCE_LOCK(self, "su_source_getmsgs");
}
SU_SOURCE_UNLOCK(self, "su_source_getmsgs");
SU_SOURCE_DECREF(self, "su_source_getmsgs");
return 0;
}
else
return -1;
}
/** @internal
*
* Register a @c su_wait_t object. The wait object, a callback function and
@ -914,13 +881,6 @@ int su_source_multishot(su_port_t *self, int multishot)
return (errno = EINVAL), -1;
}
/** @internal Enable threadsafe operation. */
static
int su_source_threadsafe(su_port_t *port)
{
return su_home_threadsafe(port->sup_home);
}
/** @internal Main loop.
*
@ -1019,18 +979,19 @@ su_duration_t su_source_step(su_port_t *self, su_duration_t tout)
return 0;
}
/** @internal
* Checks if the calling thread owns the port object.
*
* @param self pointer to a port object
*
* @retval true (nonzero) if the calling thread owns the port,
* @retval false (zero) otherwise.
*/
int su_source_own_thread(su_port_t const *self)
static int su_source_add_prepoll(su_port_t *port,
su_root_t *root,
su_prepoll_f *prepoll,
su_prepoll_magic_t *magic)
{
return self == NULL || SU_SOURCE_OWN_THREAD(self);
/* We could call prepoll in su_source_prepare()?? */
return -1;
}
static int su_source_remove_prepoll(su_port_t *port,
su_root_t *root)
{
return -1;
}
#if 0
@ -1061,52 +1022,44 @@ void su_source_dump(su_port_t const *self, FILE *f)
#endif
/* =========================================================================
* Pre-poll() callback
/**@internal
*
* Allocates and initializes a reactor and message port object.
*
* @return
* If successful a pointer to the new message port is returned, otherwise
* NULL is returned.
*/
int su_source_add_prepoll(su_port_t *port,
su_root_t *root,
su_prepoll_f *callback,
su_prepoll_magic_t *magic)
static su_port_t *su_source_port_create(void)
{
#if 0
if (port->sup_prepoll)
return -1;
SuSource *ss;
su_port_t *self = NULL;
port->sup_prepoll = callback;
port->sup_pp_magic = magic;
port->sup_pp_root = root;
SU_DEBUG_9(("su_source_port_create() called\n"));
return 0;
#else
return -1;
#endif
ss = (SuSource *)g_source_new(su_source_funcs, (sizeof *ss));
if (ss) {
self = ss->ss_port;
if (su_source_port_init(self, ss->ss_source, su_source_port_vtable) < 0)
g_source_unref(ss->ss_source), self = NULL;
} else {
su_perror("su_source_port_create(): g_source_new");
}
SU_DEBUG_1(("su_source_port_create() returns %p\n", (void *)self));
return self;
}
int su_source_remove_prepoll(su_port_t *port,
su_root_t *root)
{
#if 0
if (port->sup_pp_root != root)
return -1;
/* No su_source_port_start */
port->sup_prepoll = NULL;
port->sup_pp_magic = NULL;
port->sup_pp_root = NULL;
return 0;
#else
return -1;
#endif
}
/* =========================================================================
* Timers
/** Use su_source implementation when su_root_create() is called.
*
* @NEW_1_12_5
*/
static
su_timer_t **su_source_timers(su_port_t *self)
void su_glib_prefer_gsource(void)
{
return &self->sup_timers;
su_port_prefer(su_source_port_create, NULL);
}

View File

@ -0,0 +1,269 @@
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005,2006 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
*
*/
/**
* @brief Test program for su-glib timers
*
* Based on torture_su_timer.c of libsofia-sip-ua.
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
* @author Kai Vehmanen <first.surname@nokia.com>
*
* @internal
*
* @date Created: Fri Oct 19 08:53:55 2001 pessi
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <signal.h>
#include <assert.h>
struct tester;
#define SU_ROOT_MAGIC_T struct tester
#define SU_INTERNAL_P su_root_t *
#define SU_TIMER_ARG_T struct timing
#include "sofia-sip/su.h"
#include "sofia-sip/su_wait.h"
#include "sofia-sip/su_log.h"
#include <sofia-sip/su_glib.h>
struct timing
{
int t_run;
int t_times;
su_time_t t_prev;
};
struct tester
{
su_root_t *root;
su_timer_t *t, *t1;
unsigned times;
void *sentinel;
};
void
print_stamp(struct tester *x, su_timer_t *t, struct timing *ti)
{
su_time_t now = su_now(), prev = ti->t_prev;
ti->t_prev = now;
printf("timer interval %f\n", 1000 * su_time_diff(now, prev));
if (!ti->t_run)
su_timer_set(t, print_stamp, ti);
if (++ti->t_times >= 10)
su_timer_reset(t);
}
void
print_X(struct tester *x, su_timer_t *t1, struct timing *ti)
{
su_timer_set(t1, print_X, ti);
putchar('X'); fflush(stdout);
}
su_msg_r intr_msg = SU_MSG_R_INIT;
static RETSIGTYPE intr_handler(int signum)
{
su_msg_send(intr_msg);
}
static void test_break(struct tester *tester, su_msg_r msg, su_msg_arg_t *arg)
{
su_root_break(tester->root);
}
void
end_test(struct tester *tester, su_timer_t *t, struct timing *ti)
{
printf("ending test\n");
su_timer_destroy(t);
su_timer_reset(tester->t);
su_timer_reset(tester->t1);
su_root_break(tester->root);
}
void
increment(struct tester *tester, su_timer_t *t, struct timing *ti)
{
tester->times++;
if ((void *)ti == (void*)tester->sentinel)
su_root_break(tester->root);
}
void
usage(char const *name)
{
fprintf(stderr, "usage: %s [-1r] [-Nnum] [interval]\n", name);
exit(1);
}
/*
* test su_timer functionality:
*
* Create a timer, executing print_stamp() in every 20 ms
*/
int main(int argc, char *argv[])
{
su_root_t *root;
su_timer_t *t, *t1, *t_end;
su_timer_t **timers;
su_duration_t interval = 60;
char *argv0 = argv[0];
char *s;
int use_t1 = 0;
su_time_t now, started;
intptr_t i, N = 500;
GSource *source;
struct timing timing[1] = {{ 0 }};
struct tester tester[1] = {{ 0 }};
while (argv[1] && argv[1][0] == '-') {
char *o = argv[1] + 1;
while (*o) {
if (*o == '1')
o++, use_t1 = 1;
else if (*o == 'r')
o++, timing->t_run = 1;
else if (*o == 'N') {
if (o[1])
N = strtoul(o + 1, &o, 0);
else if (argv[2])
N = strtoul(argv++[2], &o, 0);
break;
}
else
break;
}
if (*o)
usage(argv0);
argv++;
}
if (argv[1]) {
interval = strtoul(argv[1], &s, 10);
if (interval == 0 || s == argv[1])
usage(argv0);
}
su_init(); atexit(su_deinit);
tester->root = root = su_glib_root_create(tester);
source = su_root_gsource(tester->root);
g_source_attach(source, NULL /*g_main_context_default ()*/);
su_msg_create(intr_msg,
su_root_task(root),
su_root_task(root),
test_break, 0);
signal(SIGINT, intr_handler);
#if HAVE_SIGPIPE
signal(SIGPIPE, intr_handler);
signal(SIGQUIT, intr_handler);
signal(SIGHUP, intr_handler);
#endif
t = su_timer_create(su_root_task(root), interval);
t1 = su_timer_create(su_root_task(root), 1);
t_end = su_timer_create(su_root_task(root), 20 * interval);
if (t == NULL || t1 == NULL || t_end == NULL)
su_perror("su_timer_create"), exit(1);
tester->t = t, tester->t1 = t1;
timing->t_prev = su_now();
if (timing->t_run)
su_timer_run(t, print_stamp, timing);
else
su_timer_set(t, print_stamp, timing);
if (use_t1)
su_timer_set(t1, print_X, NULL);
su_timer_set(t_end, end_test, NULL);
su_root_run(root);
su_msg_destroy(intr_msg);
su_timer_destroy(t);
su_timer_destroy(t1);
if (timing->t_times != 10) {
fprintf(stderr, "%s: t expired %d times (expecting 10)\n",
argv0, timing->t_times);
return 1;
}
/* Insert timers in order */
timers = calloc(N, sizeof *timers);
if (!timers) { perror("calloc"); exit(1); }
now = started = su_now();
for (i = 0; i < N; i++) {
t = su_timer_create(su_root_task(root), 1000);
if (!t) { perror("su_timer_create"); exit(1); }
if (++now.tv_usec == 0) ++now.tv_sec;
su_timer_set_at(t, increment, (void *)i, now);
timers[i] = t;
}
tester->sentinel = (void*)(i - 1);
su_root_run(root);
printf("Processing %u timers took %f millisec (%f expected)\n",
(unsigned)i, su_time_diff(su_now(), started) * 1000, (double)i / 1000);
for (i = 0; i < N; i++) {
su_timer_destroy(timers[i]);
}
su_root_destroy(root);
su_deinit();
return 0;
}

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

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

View File

@ -43,4 +43,5 @@ TESTS = torture_bnf
# ----------------------------------------------------------------------
# Sofia specific rules
include ../sofia.am
include $(top_srcdir)/rules/sofia.am

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

View File

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

View File

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

View File

@ -47,4 +47,4 @@ CLEANFILES = Doxyfile.rfc
# ----------------------------------------------------------------------
# Sofia specific rules
include ../sofia.am
include $(top_srcdir)/rules/sofia.am

View File

@ -31,4 +31,5 @@ EXTRA_DIST = Doxyfile features.docs
# ----------------------------------------------------------------------
# Sofia specific rules
include ../sofia.am
include $(top_srcdir)/rules/sofia.am

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}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -51,4 +51,5 @@ EXTRA_DIST += Doxyfile ipt.docs
# ----------------------------------------------------------------------
# Sofia specific rules
include ../sofia.am
include $(top_srcdir)/rules/sofia.am

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -59,4 +59,5 @@ EXTRA_DIST = Doxyfile nea.docs $(BUILT_SOURCES)
# ----------------------------------------------------------------------
# Sofia specific rules
include ../sofia.am
include $(top_srcdir)/rules/sofia.am

View File

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

View File

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

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

View File

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

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

View File

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

View File

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

View File

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

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

View File

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

View File

@ -63,4 +63,4 @@ EXTRA_DIST = Doxyfile nth.docs $(BUILT_SOURCES) \
# ----------------------------------------------------------------------
# Sofia specific rules
include ../sofia.am
include $(top_srcdir)/rules/sofia.am

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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;

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

View File

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

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

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 */

View File

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

View File

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

View File

@ -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;
if (nh == NULL)
if (!(nh = nua_stack_incoming_handle(nua, irq, sip, 0)))
return 500; /* respond with 500 Internal Server Error */
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;
}
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;
return 0;
}

File diff suppressed because it is too large Load Diff

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"
/**@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);
}

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

View File

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

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

View File

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

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

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

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;
}
/* ---------------------------------------------------------------------- */

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,

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

Some files were not shown because too many files have changed in this diff Show More