mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-03-12 12:18:18 +00:00
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:
parent
fabed21ea8
commit
853936abd3
@ -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/
|
||||
|
||||
|
||||
|
@ -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.
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
----------
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
/>
|
||||
|
||||
|
@ -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
|
||||
### ---------------------
|
||||
|
@ -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
|
||||
================
|
||||
|
||||
|
@ -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
|
||||
--------
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
@ -58,4 +58,4 @@ AUTOMAKE_OPTIONS = foreign
|
||||
# ----------------------------------------------------------------------
|
||||
# Sofia specific rules
|
||||
|
||||
include ../../libsofia-sip-ua/sofia.am
|
||||
include $(top_srcdir)/rules/sofia.am
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
||||
|
@ -9,12 +9,25 @@
|
||||
|
||||
AUTOMAKE_OPTIONS = foreign
|
||||
|
||||
# select whicn optional sofia-sip modules have been enabled
|
||||
# in the build
|
||||
OPT_LIBADD =
|
||||
OPT_SUBDIRS_STUN =
|
||||
OPT_SUBDIRS_NTH =
|
||||
if HAVE_STUN
|
||||
OPT_LIBADD += stun/libstun.la
|
||||
OPT_SUBDIRS_STUN += stun
|
||||
endif
|
||||
if HAVE_NTH
|
||||
OPT_LIBADD += nth/libnth.la http/libhttp.la
|
||||
OPT_SUBDIRS_NTH += nth http
|
||||
endif
|
||||
|
||||
# note: order does matter in the subdir list
|
||||
SUBDIRS = su features bnf sresolv sdp url msg sip stun ipt soa \
|
||||
tport http nta nea iptsec nth nua
|
||||
SUBDIRS = su features bnf sresolv sdp url msg sip $(OPT_SUBDIRS_STUN) ipt soa \
|
||||
tport nta nea iptsec $(OPT_SUBDIRS_NTH) nua
|
||||
DIST_SUBDIRS = $(SUBDIRS) docs
|
||||
|
||||
EXTRA_DIST = sofia.am
|
||||
DOXYGEN = doxygen
|
||||
|
||||
lib_LTLIBRARIES = libsofia-sip-ua.la
|
||||
@ -27,37 +40,22 @@ libsofia_sip_ua_la_LIBADD = bnf/libbnf.la \
|
||||
msg/libmsg.la \
|
||||
nea/libnea.la \
|
||||
nta/libnta.la \
|
||||
nth/libnth.la \
|
||||
nua/libnua.la \
|
||||
http/libhttp.la \
|
||||
sdp/libsdp.la \
|
||||
sip/libsip.la \
|
||||
soa/libsoa.la \
|
||||
sresolv/libsresolv.la \
|
||||
su/libsu.la \
|
||||
stun/libstun.la \
|
||||
tport/libtport.la \
|
||||
url/liburl.la
|
||||
url/liburl.la \
|
||||
$(OPT_LIBADD)
|
||||
|
||||
# set the libtool version info version:revision:age for libsofia-sip-ua
|
||||
# - soname to 'libsofia-sip-ua.so.(CUR-AGE)'
|
||||
libsofia_sip_ua_la_LDFLAGS = \
|
||||
-version-info $(LIBVER_SOFIA_SIP_UA_CUR):$(LIBVER_SOFIA_SIP_UA_REV):$(LIBVER_SOFIA_SIP_UA_AGE)
|
||||
|
||||
if ENABLE_COVERAGE
|
||||
COVERAGE_RECURSIVE = coverage-recursive
|
||||
coverage: $(COVERAGE_RECURSIVE)
|
||||
endif
|
||||
|
||||
all-recursive: built-sources-recursive
|
||||
built-sources: built-sources-recursive
|
||||
clean-built-sources: clean-built-sources-recursive
|
||||
|
||||
built-sources-recursive clean-built-sources-recursive $(COVERAGE_RECURSIVE):
|
||||
target=`echo $@ | sed s/-recursive//`; \
|
||||
list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
|
||||
echo "Making $@ in $$subdir"; \
|
||||
(cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$target) \
|
||||
done;
|
||||
include $(top_srcdir)/rules/recursive.am
|
||||
|
||||
doxygen: built-sources
|
||||
@echo Generating empty doxytags
|
||||
|
@ -43,4 +43,5 @@ TESTS = torture_bnf
|
||||
# ----------------------------------------------------------------------
|
||||
# Sofia specific rules
|
||||
|
||||
include ../sofia.am
|
||||
include $(top_srcdir)/rules/sofia.am
|
||||
|
||||
|
@ -377,7 +377,7 @@ int canonize_ip6_address(char *host, char *hexparts[9])
|
||||
|
||||
if (i == maxparts + 1) {
|
||||
/* There is an extra doublecolon */
|
||||
for (j = doublecolon; j <= i; j++)
|
||||
for (j = doublecolon; j + 1 < i; j++)
|
||||
hexparts[j] = hexparts[j + 1];
|
||||
i--;
|
||||
}
|
||||
@ -825,9 +825,9 @@ static size_t convert_ip_address(char const *s,
|
||||
{
|
||||
size_t len;
|
||||
int canonize = 0;
|
||||
char buf[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
|
||||
|
||||
#if SU_HAVE_IN6
|
||||
char buf[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
|
||||
|
||||
len = span_ip6_reference(s);
|
||||
if (len) {
|
||||
|
@ -340,9 +340,10 @@ int host_test(void)
|
||||
END();
|
||||
}
|
||||
|
||||
void usage(void)
|
||||
void usage(int exitcode)
|
||||
{
|
||||
fprintf(stderr, "usage: %s [-v]\n", name);
|
||||
fprintf(stderr, "usage: %s [-v] [-a]\n", name);
|
||||
exit(exitcode);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
@ -353,8 +354,10 @@ int main(int argc, char *argv[])
|
||||
for (i = 1; argv[i]; i++) {
|
||||
if (strcmp(argv[i], "-v") == 0)
|
||||
test_flags |= tst_verbatim;
|
||||
else if (strcmp(argv[i], "-a") == 0)
|
||||
test_flags |= tst_abort;
|
||||
else
|
||||
usage();
|
||||
usage(1);
|
||||
}
|
||||
|
||||
retval |= bnf_test(); fflush(stdout);
|
||||
|
@ -45,4 +45,8 @@ ALIASES = \
|
||||
"VERSION_1_12_4=<a href=\"http://sofia-sip.sf.net/relnotes/relnotes-sofia-sip-1.12.4.txt\">1.12.4</a>" \
|
||||
"VERSION_1_12_5=<a href=\"http://sofia-sip.sf.net/relnotes/relnotes-sofia-sip-1.12.5.txt\">1.12.5</a>" \
|
||||
"NEW_1_12_5=@since New in <a href=\"http://sofia-sip.sf.net/relnotes/relnotes-sofia-sip-1.12.5.txt\">1.12.5</a>" \
|
||||
"EXP_1_12_5=@since Experimental in <a href=\"http://sofia-sip.sf.net/relnotes/relnotes-sofia-sip-1.12.5.txt\">1.12.5</a>, available if --enable-experimental configuration option is given" \
|
||||
"VERSION_1_12_6=<a href=\"http://sofia-sip.sf.net/relnotes/relnotes-sofia-sip-1.12.6.txt\">1.12.6</a>" \
|
||||
"NEW_1_12_6=@since New in <a href=\"http://sofia-sip.sf.net/relnotes/relnotes-sofia-sip-1.12.6.txt\">1.12.6</a>" \
|
||||
"EXP_1_12_6=@since Experimental in <a href=\"http://sofia-sip.sf.net/relnotes/relnotes-sofia-sip-1.12.6.txt\">1.12.6</a>, available if --enable-experimental configuration option is given" \
|
||||
|
||||
|
@ -47,4 +47,4 @@ CLEANFILES = Doxyfile.rfc
|
||||
# ----------------------------------------------------------------------
|
||||
# Sofia specific rules
|
||||
|
||||
include ../sofia.am
|
||||
include $(top_srcdir)/rules/sofia.am
|
||||
|
@ -31,4 +31,5 @@ EXTRA_DIST = Doxyfile features.docs
|
||||
# ----------------------------------------------------------------------
|
||||
# Sofia specific rules
|
||||
|
||||
include ../sofia.am
|
||||
include $(top_srcdir)/rules/sofia.am
|
||||
|
||||
|
@ -30,17 +30,17 @@ PUBLIC_H = sofia-sip/http.h sofia-sip/http_header.h \
|
||||
sofia-sip/http_status.h sofia-sip/http_hclasses.h
|
||||
|
||||
BUILT_H = sofia-sip/http_protos.h sofia-sip/http_tag.h
|
||||
BUILT_C = http_tag.c http_tag_ref.c http_parser_table.c
|
||||
BUILT_C = http_tag.c http_parser_table.c
|
||||
|
||||
BUILT_SOURCES = $(BUILT_H) $(BUILT_C)
|
||||
BUILT_SOURCES = $(BUILT_H) $(BUILT_C) http_tag_ref.c
|
||||
|
||||
nobase_include_sofia_HEADERS = $(BUILT_H) $(PUBLIC_H)
|
||||
|
||||
libhttp_la_SOURCES = $(INTERNAL_H) \
|
||||
http_parser.c http_header.c \
|
||||
http_basic.c http_extra.c \
|
||||
http_basic.c http_extra.c http_inlined.c \
|
||||
http_status.c http_tag_class.c \
|
||||
$(BUILT_C)
|
||||
$(BUILT_SOURCES)
|
||||
|
||||
COVERAGE_INPUT = $(libhttp_la_SOURCES) $(include_sofia_HEADERS)
|
||||
|
||||
@ -48,6 +48,7 @@ LDADD = libhttp.la \
|
||||
../bnf/libbnf.la \
|
||||
../msg/libmsg.la \
|
||||
../url/liburl.la \
|
||||
../ipt/libipt.la \
|
||||
../su/libsu.la
|
||||
|
||||
test_http_LDFLAGS = -static
|
||||
@ -64,30 +65,29 @@ EXTRA_DIST = Doxyfile http.docs \
|
||||
# ----------------------------------------------------------------------
|
||||
# Sofia specific rules
|
||||
|
||||
include ../sofia.am
|
||||
include $(top_srcdir)/rules/sofia.am
|
||||
|
||||
TAG_DLL_FLAGS = DLLREF=1
|
||||
|
||||
MSG_PARSER_AWK = $(srcdir)/../msg/msg_parser.awk
|
||||
MSG_PARSER_AWK = ${srcdir}/../msg/msg_parser.awk
|
||||
|
||||
AWK_HTTP_AWK = $(AWK) -f $(MSG_PARSER_AWK) module=http
|
||||
AWK_HTTP_AWK = ${AWK} -f ${MSG_PARSER_AWK} module=http
|
||||
|
||||
sofia-sip/http_tag.h: sofia-sip/http_tag.h.in $(MSG_PARSER_AWK)
|
||||
sofia-sip/http_protos.h: sofia-sip/http_protos.h.in $(MSG_PARSER_AWK)
|
||||
http_tag.c: http_tag.c.in $(MSG_PARSER_AWK)
|
||||
http_parser_table.c: http_parser_table.c.in $(MSG_PARSER_AWK)
|
||||
SS_HTTP_H = ${srcdir}/sofia-sip/http.h
|
||||
|
||||
sofia-sip/http_protos.h: sofia-sip/http.h
|
||||
${BUILT_H} ${BUILT_C}: ${srcdir}/sofia-sip/http.h ${MSG_PARSER_AWK}
|
||||
|
||||
sofia-sip/http_protos.h: ${srcdir}/sofia-sip/http_protos.h.in
|
||||
@-mkdir sofia-sip 2>/dev/null || true
|
||||
$(AWK_HTTP_AWK) PR=$@ TEMPLATE=$(srcdir)/sofia-sip/http_protos.h.in $<
|
||||
${AWK_HTTP_AWK} PR=$@ TEMPLATE=${srcdir}/$@.in ${SS_HTTP_H}
|
||||
|
||||
sofia-sip/http_tag.h: sofia-sip/http.h
|
||||
sofia-sip/http_tag.h: ${srcdir}/sofia-sip/http_tag.h.in
|
||||
@-mkdir sofia-sip 2>/dev/null || true
|
||||
$(AWK_HTTP_AWK) PR=$@ TEMPLATE=$(srcdir)/sofia-sip/http_tag.h.in $<
|
||||
${AWK_HTTP_AWK} PR=$@ TEMPLATE=${srcdir}/$@.in ${SS_HTTP_H}
|
||||
|
||||
http_tag.c: sofia-sip/http.h
|
||||
$(AWK_HTTP_AWK) PR=$@ TEMPLATE=$(srcdir)/http_tag.c.in $<
|
||||
http_tag.c: ${srcdir}/http_tag.c.in
|
||||
${AWK_HTTP_AWK} PR=$@ TEMPLATE=${srcdir}/$@.in ${SS_HTTP_H}
|
||||
|
||||
http_parser_table.c: sofia-sip/http.h
|
||||
$(AWK_HTTP_AWK) PT=$@ TEMPLATE=$(srcdir)/http_parser_table.c.in \
|
||||
MC_HASH_SIZE=127 $<
|
||||
http_parser_table.c: ${srcdir}/http_parser_table.c.in
|
||||
${AWK_HTTP_AWK} PT=$@ TEMPLATE=${srcdir}/$@.in \
|
||||
MC_HASH_SIZE=127 ${SS_HTTP_H}
|
||||
|
@ -55,6 +55,7 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
|
||||
/* ====================================================================== */
|
||||
|
||||
@ -1196,7 +1197,7 @@ char *http_range_dup_one(msg_header_t *dst, msg_header_t const *src,
|
||||
http_range_t const *o = (http_range_t const *)src;
|
||||
char *end = b + xtra;
|
||||
|
||||
b = msg_params_dup((char const * const **)&rng->rng_specs,
|
||||
b = msg_params_dup((msg_param_t const **)&rng->rng_specs,
|
||||
o->rng_specs, b, xtra);
|
||||
MSG_STRING_DUP(b, rng->rng_unit, o->rng_unit);
|
||||
|
||||
|
52
libs/sofia-sip/libsofia-sip-ua/http/http_inlined.c
Normal file
52
libs/sofia-sip/libsofia-sip-ua/http/http_inlined.c
Normal 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
|
@ -61,9 +61,9 @@ char const http_version_1_0[] = "HTTP/1.0";
|
||||
/** HTTP version 0.9 is an empty string. */
|
||||
char const http_version_0_9[] = "";
|
||||
|
||||
msg_mclass_t *http_default_mclass(void)
|
||||
msg_mclass_t const *http_default_mclass(void)
|
||||
{
|
||||
extern msg_mclass_t http_mclass[];
|
||||
extern msg_mclass_t const http_mclass[];
|
||||
|
||||
return http_mclass;
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ SOFIAPUBVAR char const http_version_1_1[];
|
||||
*/
|
||||
|
||||
/** HTTP parser description. */
|
||||
SOFIAPUBFUN msg_mclass_t *http_default_mclass(void);
|
||||
SOFIAPUBFUN msg_mclass_t const *http_default_mclass(void);
|
||||
|
||||
/** Complete a HTTP request. */
|
||||
SOFIAPUBFUN int http_request_complete(msg_t *msg);
|
||||
|
@ -76,14 +76,7 @@ static int http_tag_test(void);
|
||||
static int test_query_parser(void);
|
||||
|
||||
static msg_t *read_message(char const string[]);
|
||||
msg_mclass_t *test_mclass = NULL;
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"usage: %s [-v]\n",
|
||||
name);
|
||||
}
|
||||
msg_mclass_t const *test_mclass = NULL;
|
||||
|
||||
char *lastpart(char *path)
|
||||
{
|
||||
@ -95,6 +88,14 @@ char *lastpart(char *path)
|
||||
|
||||
int tstflags;
|
||||
|
||||
void usage(int exitcode)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"usage: %s [-v] [-a]\n",
|
||||
name);
|
||||
exit(exitcode);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int retval = 0;
|
||||
@ -105,8 +106,10 @@ int main(int argc, char *argv[])
|
||||
for (i = 1; argv[i]; i++) {
|
||||
if (strcmp(argv[i], "-v") == 0)
|
||||
tstflags |= tst_verbatim;
|
||||
else if (strcmp(argv[i], "-a") == 0)
|
||||
tstflags |= tst_abort;
|
||||
else
|
||||
usage();
|
||||
usage(1);
|
||||
}
|
||||
|
||||
if (!test_mclass)
|
||||
|
@ -51,4 +51,5 @@ EXTRA_DIST += Doxyfile ipt.docs
|
||||
# ----------------------------------------------------------------------
|
||||
# Sofia specific rules
|
||||
|
||||
include ../sofia.am
|
||||
include $(top_srcdir)/rules/sofia.am
|
||||
|
||||
|
@ -57,6 +57,9 @@ SOFIAPUBFUN isize_t base64_e(char buf[], isize_t bsiz, void *data, isize_t dsiz)
|
||||
/** Calculate size of n bytes encoded in base64 */
|
||||
#define BASE64_SIZE(n) ((((n) + 2) / 3) * 4)
|
||||
|
||||
/** Calculate size of n bytes encoded in base64 sans trailing =. @NEW_1_12_5 */
|
||||
#define BASE64_MINSIZE(n) ((n * 4 + 2) / 3)
|
||||
|
||||
SOFIA_END_DECLS
|
||||
|
||||
#endif /* !BASE_64 */
|
||||
|
@ -43,56 +43,39 @@
|
||||
|
||||
SOFIA_BEGIN_DECLS
|
||||
|
||||
#if SU_HAVE_INLINE
|
||||
su_inline
|
||||
#else
|
||||
SOFIAPUBFUN
|
||||
#endif
|
||||
int
|
||||
str0cmp(char const *a, char const *b),
|
||||
str0ncmp(char const *a, char const *b, size_t n),
|
||||
str0casecmp(char const *a, char const *b),
|
||||
str0ncasecmp(char const *a, char const *b, size_t n);
|
||||
|
||||
#if SU_HAVE_INLINE
|
||||
su_inline
|
||||
#else
|
||||
SOFIAPUBFUN
|
||||
#endif
|
||||
size_t
|
||||
strnspn(char const *s, size_t size, char const *term),
|
||||
strncspn(char const *s, size_t ssize, char const *reject);
|
||||
|
||||
#if SU_HAVE_INLINE
|
||||
int str0cmp(char const *a, char const *b)
|
||||
su_inline int str0cmp(char const *a, char const *b)
|
||||
{
|
||||
if (a == NULL) a = "";
|
||||
if (b == NULL) b = "";
|
||||
return strcmp(a, b);
|
||||
}
|
||||
|
||||
int str0ncmp(char const *a, char const *b, size_t n)
|
||||
su_inline int str0ncmp(char const *a, char const *b, size_t n)
|
||||
{
|
||||
if (a == NULL) a = "";
|
||||
if (b == NULL) b = "";
|
||||
return strncmp(a, b, n);
|
||||
}
|
||||
|
||||
int str0casecmp(char const *a, char const *b)
|
||||
su_inline int str0casecmp(char const *a, char const *b)
|
||||
{
|
||||
if (a == NULL) a = "";
|
||||
if (b == NULL) b = "";
|
||||
return strcasecmp(a, b);
|
||||
}
|
||||
|
||||
int str0ncasecmp(char const *a, char const *b, size_t n)
|
||||
su_inline int str0ncasecmp(char const *a, char const *b, size_t n)
|
||||
{
|
||||
if (a == NULL) a = "";
|
||||
if (b == NULL) b = "";
|
||||
return strncasecmp(a, b, n);
|
||||
}
|
||||
|
||||
size_t strnspn(char const *s, size_t ssize, char const *term)
|
||||
#if !SU_HAVE_INLINE
|
||||
SOFIAPUBFUN size_t strnspn(char const *s, size_t size, char const *term);
|
||||
SOFIAPUBFUN size_t strncspn(char const *s, size_t ssize, char const *reject);
|
||||
#else
|
||||
su_inline size_t strnspn(char const *s, size_t ssize, char const *term)
|
||||
{
|
||||
size_t n;
|
||||
size_t tsize = strlen(term);
|
||||
@ -123,7 +106,7 @@ size_t strnspn(char const *s, size_t ssize, char const *term)
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t strncspn(char const *s, size_t ssize, char const *reject)
|
||||
su_inline size_t strncspn(char const *s, size_t ssize, char const *reject)
|
||||
{
|
||||
size_t n;
|
||||
size_t rsize = strlen(reject);
|
||||
|
@ -161,11 +161,12 @@ int test_decoding(void)
|
||||
}
|
||||
|
||||
|
||||
void usage(void)
|
||||
void usage(int exitcode)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"usage: %s [-v]\n",
|
||||
"usage: %s [-v] [-a]\n",
|
||||
name);
|
||||
exit(exitcode);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
@ -176,8 +177,10 @@ int main(int argc, char *argv[])
|
||||
for (i = 1; argv[i]; i++) {
|
||||
if (strcmp(argv[i], "-v") == 0)
|
||||
tstflags |= tst_verbatim;
|
||||
else if (strcmp(argv[i], "-a") == 0)
|
||||
tstflags |= tst_abort;
|
||||
else
|
||||
usage();
|
||||
usage(1);
|
||||
}
|
||||
|
||||
retval |= test_encoding(); fflush(stdout);
|
||||
|
@ -11,6 +11,7 @@ TAGFILES += ../docs/bnf.doxytags=../bnf
|
||||
TAGFILES += ../docs/url.doxytags=../url
|
||||
TAGFILES += ../docs/msg.doxytags=../msg
|
||||
TAGFILES += ../docs/sip.doxytags=../sip
|
||||
TAGFILES += ../docs/http.doxytags=../http
|
||||
TAGFILES += ../docs/sresolv.doxytags=../sresolv
|
||||
TAGFILES += ../docs/tport.doxytags=../tport
|
||||
TAGFILES += ../docs/nta.doxytags=../nta
|
||||
@ -18,3 +19,6 @@ TAGFILES += ../docs/nta.doxytags=../nta
|
||||
GENERATE_TAGFILE = ../docs/iptsec.doxytags
|
||||
|
||||
ALIASES +=
|
||||
|
||||
PREDEFINED += SOFIA_EXTEND_AUTH_CLIENT=1
|
||||
|
||||
|
@ -35,29 +35,18 @@ nobase_include_sofia_HEADERS = \
|
||||
sofia-sip/auth_common.h \
|
||||
sofia-sip/auth_client.h sofia-sip/auth_digest.h \
|
||||
sofia-sip/auth_module.h sofia-sip/auth_plugin.h \
|
||||
sofia-sip/auth_client_plugin.h \
|
||||
$(NTLM_HEADER)
|
||||
sofia-sip/auth_client_plugin.h
|
||||
|
||||
libiptsec_la_SOURCES = iptsec_debug.h \
|
||||
auth_client.c auth_common.c auth_digest.c \
|
||||
auth_module.c auth_tag.c auth_tag_ref.c \
|
||||
auth_plugin.c auth_plugin_delayed.c \
|
||||
auth_module_http.c auth_module_sip.c \
|
||||
$(NTLM_SOURCE) \
|
||||
auth_module_sip.c \
|
||||
iptsec_debug.c
|
||||
|
||||
NTLM_HEADER = sofia-sip/auth_ntlm.h
|
||||
if HAVE_NTLM
|
||||
NTLM_SOURCE = auth_ntlm.c auth_client_ntlm.c auth_plugin_ntlm.c
|
||||
endif
|
||||
|
||||
EXTRA_libiptsec_la_SOURCES = \
|
||||
auth_ntlm.c auth_client_ntlm.c auth_plugin_ntlm.c
|
||||
|
||||
COVERAGE_INPUT = $(libiptsec_la_SOURCES) $(include_sofia_HEADERS)
|
||||
|
||||
LDADD = libiptsec.la \
|
||||
../http/libhttp.la \
|
||||
../nta/libnta.la \
|
||||
../sip/libsip.la \
|
||||
../msg/libmsg.la \
|
||||
@ -68,13 +57,31 @@ LDADD = libiptsec.la \
|
||||
|
||||
test_auth_digest_LDFLAGS = -static
|
||||
|
||||
if HAVE_NTLM
|
||||
nobase_include_sofia_HEADERS += $(NTLM_HEADER)
|
||||
libiptsec_la_SOURCES += $(NTLM_SOURCE)
|
||||
endif
|
||||
|
||||
if HAVE_NTH
|
||||
libiptsec_la_SOURCES += $(HTTP_SOURCE)
|
||||
LDADD += ../http/libhttp.la
|
||||
endif
|
||||
|
||||
HTTP_SOURCE = auth_module_http.c
|
||||
|
||||
NTLM_HEADER = sofia-sip/auth_ntlm.h
|
||||
NTLM_SOURCE = auth_ntlm.c auth_client_ntlm.c auth_plugin_ntlm.c
|
||||
|
||||
EXTRA_libiptsec_la_SOURCES = \
|
||||
$(NTLM_HEADER) $(NTLM_SOURCE) $(HTTP_SOURCE)
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Install and distribution rules
|
||||
|
||||
EXTRA_DIST = Doxyfile iptsec.docs testpasswd \
|
||||
auth_module_sip.c auth_module_http.c $(BUILT_SOURCES)
|
||||
EXTRA_DIST = Doxyfile iptsec.docs testpasswd $(BUILT_SOURCES)
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Sofia specific rules
|
||||
|
||||
include ../sofia.am
|
||||
include $(top_srcdir)/rules/sofia.am
|
||||
|
||||
|
@ -31,6 +31,8 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#define SOFIA_EXTEND_AUTH_CLIENT 1
|
||||
|
||||
#include <sofia-sip/su.h>
|
||||
#include <sofia-sip/su_md5.h>
|
||||
|
||||
@ -77,9 +79,7 @@ static int ca_credentials(auth_client_t *ca,
|
||||
char const *user,
|
||||
char const *pass);
|
||||
|
||||
static int ca_clear_credentials(auth_client_t *ca,
|
||||
char const *scheme,
|
||||
char const *realm);
|
||||
static int ca_clear_credentials(auth_client_t *ca);
|
||||
|
||||
|
||||
/** Initialize authenticators.
|
||||
@ -178,29 +178,31 @@ int ca_challenge(auth_client_t *ca,
|
||||
return -1;
|
||||
|
||||
if (!ca->ca_credential_class)
|
||||
stale = 1, ca->ca_credential_class = credential_class;
|
||||
stale = 2, ca->ca_credential_class = credential_class;
|
||||
|
||||
return stale ? 2 : 1;
|
||||
return stale > 1 ? 2 : 1;
|
||||
}
|
||||
|
||||
/** Store authentication info to authenticators.
|
||||
*
|
||||
* The function auc_info() feeds the authentication data from the
|
||||
* authentication info @a info to the list of authenticators @a auc_list.
|
||||
* The function auc_info() feeds the authentication data from the @b
|
||||
* Authentication-Info header @a info to the list of authenticators @a
|
||||
* auc_list.
|
||||
*
|
||||
* @param[in,out] auc_list list of authenticators to be updated
|
||||
* @param[in] info info to be processed
|
||||
* @param[in] crcl corresponding credential class
|
||||
* @param[in] info info header to be processed
|
||||
* @param[in] credential_class corresponding credential class
|
||||
*
|
||||
* The authentication info can be in either Authentication-Info or in
|
||||
* Proxy-Authentication-Info headers.
|
||||
* If the header is Authentication-Info, the @a crcl should be
|
||||
* #sip_authorization_class or #http_authorization_class.
|
||||
* Likewise, If the header is Proxy-Authentication-Info, the @a crcl should
|
||||
* be #sip_proxy_authorization_class or #http_proxy_authorization_class.
|
||||
* The authentication info can be in either @AuthenticationInfo or in
|
||||
* @ProxyAuthenticationInfo headers. If the header is @AuthenticationInfo,
|
||||
* the @a credential_class should be #sip_authorization_class or
|
||||
* #http_authorization_class. Likewise, If the header is
|
||||
* @ProxyAuthenticationInfo, the @a credential_class should be
|
||||
* #sip_proxy_authorization_class or #http_proxy_authorization_class.
|
||||
|
||||
* The authentication into usually contains next nonce or mutual
|
||||
* authentication information. We handle only nextnonce parameter.
|
||||
* The authentication into header usually contains next nonce or mutual
|
||||
* authentication information. Currently, only the nextnonce parameter is
|
||||
* processed.
|
||||
*
|
||||
* @bug
|
||||
* The result can be quite unexpected if there are more than one
|
||||
@ -210,9 +212,11 @@ int ca_challenge(auth_client_t *ca,
|
||||
* @retval number of challenges to updated
|
||||
* @retval 0 when there was no challenge to update
|
||||
* @retval -1 upon an error
|
||||
*
|
||||
* @NEW_1_12_5
|
||||
*/
|
||||
int auc_info(auth_client_t **auc_list,
|
||||
msg_auth_info_t const *ai,
|
||||
msg_auth_info_t const *info,
|
||||
msg_hclass_t *credential_class)
|
||||
{
|
||||
auth_client_t *ca;
|
||||
@ -222,7 +226,7 @@ int auc_info(auth_client_t **auc_list,
|
||||
|
||||
/* Update matching authenticator */
|
||||
for (ca = *auc_list; ca; ca = ca->ca_next) {
|
||||
int updated = ca_info(ca, ai, credential_class);
|
||||
int updated = ca_info(ca, info, credential_class);
|
||||
if (updated < 0)
|
||||
return -1;
|
||||
if (updated >= 1)
|
||||
@ -241,12 +245,12 @@ int auc_info(auth_client_t **auc_list,
|
||||
*/
|
||||
static
|
||||
int ca_info(auth_client_t *ca,
|
||||
msg_auth_info_t const *ai,
|
||||
msg_auth_info_t const *info,
|
||||
msg_hclass_t *credential_class)
|
||||
{
|
||||
assert(ca); assert(ai);
|
||||
assert(ca); assert(info);
|
||||
|
||||
if (!ca || !ai)
|
||||
if (!ca || !info)
|
||||
return -1;
|
||||
|
||||
if (!ca->ca_credential_class)
|
||||
@ -261,7 +265,7 @@ int ca_info(auth_client_t *ca,
|
||||
|| !ca->ca_auc->auc_info)
|
||||
return 0;
|
||||
|
||||
return ca->ca_auc->auc_info(ca, ai);
|
||||
return ca->ca_auc->auc_info(ca, info);
|
||||
}
|
||||
|
||||
|
||||
@ -336,8 +340,8 @@ int auc_credentials(auth_client_t **auc_list, su_home_t *home,
|
||||
* @param[in] user username
|
||||
* @param[in] pass password
|
||||
*
|
||||
* @retval number of matching clients
|
||||
* @retval 0 when no matching client was found
|
||||
* @retval number of updated clients
|
||||
* @retval 0 when no client was updated
|
||||
* @retval -1 upon an error
|
||||
*/
|
||||
int auc_all_credentials(auth_client_t **auc_list,
|
||||
@ -371,6 +375,9 @@ int ca_credentials(auth_client_t *ca,
|
||||
char const *user,
|
||||
char const *pass)
|
||||
{
|
||||
char *new_user, *new_pass;
|
||||
char *old_user, *old_pass;
|
||||
|
||||
assert(ca);
|
||||
|
||||
if (!ca || !ca->ca_scheme || !ca->ca_realm)
|
||||
@ -380,12 +387,24 @@ int ca_credentials(auth_client_t *ca,
|
||||
(realm != NULL && strcmp(realm, ca->ca_realm)))
|
||||
return -1;
|
||||
|
||||
ca->ca_user = su_strdup(ca->ca_home, user);
|
||||
ca->ca_pass = su_strdup(ca->ca_home, pass);
|
||||
old_user = ca->ca_user, old_pass = ca->ca_pass;
|
||||
|
||||
if (!ca->ca_user || !ca->ca_pass)
|
||||
if (str0cmp(user, old_user) == 0 && str0cmp(pass, old_pass) == 0)
|
||||
return 0;
|
||||
|
||||
new_user = su_strdup(ca->ca_home, user);
|
||||
new_pass = su_strdup(ca->ca_home, pass);
|
||||
|
||||
if (!new_user || !new_pass)
|
||||
return -1;
|
||||
|
||||
ca->ca_user = new_user, ca->ca_pass = new_pass;
|
||||
if (AUTH_CLIENT_IS_EXTENDED(ca))
|
||||
ca->ca_clear = 0;
|
||||
|
||||
su_free(ca->ca_home, old_user);
|
||||
su_free(ca->ca_home, old_pass);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -412,12 +431,15 @@ int auc_copy_credentials(auth_client_t **dst,
|
||||
char *u, *p;
|
||||
if (!ca->ca_user || !ca->ca_pass)
|
||||
continue;
|
||||
if (AUTH_CLIENT_IS_EXTENDED(ca) && ca->ca_clear)
|
||||
continue;
|
||||
if (!ca->ca_scheme[0] || strcmp(ca->ca_scheme, d->ca_scheme))
|
||||
continue;
|
||||
if (!ca->ca_realm[0] || strcmp(ca->ca_realm, d->ca_realm))
|
||||
continue;
|
||||
|
||||
if (d->ca_user && strcmp(d->ca_user, ca->ca_user) == 0 &&
|
||||
if (!(AUTH_CLIENT_IS_EXTENDED(d) && d->ca_clear) &&
|
||||
d->ca_user && strcmp(d->ca_user, ca->ca_user) == 0 &&
|
||||
d->ca_pass && strcmp(d->ca_pass, ca->ca_pass) == 0) {
|
||||
retval++;
|
||||
break;
|
||||
@ -431,6 +453,9 @@ int auc_copy_credentials(auth_client_t **dst,
|
||||
if (d->ca_user) su_free(d->ca_home, (void *)d->ca_user);
|
||||
if (d->ca_pass) su_free(d->ca_home, (void *)d->ca_pass);
|
||||
d->ca_user = u, d->ca_pass = p;
|
||||
if (AUTH_CLIENT_IS_EXTENDED(d))
|
||||
d->ca_clear = 0;
|
||||
|
||||
retval++;
|
||||
break;
|
||||
}
|
||||
@ -453,13 +478,24 @@ int auc_copy_credentials(auth_client_t **dst,
|
||||
* @retval -1 upon an error
|
||||
*/
|
||||
int auc_clear_credentials(auth_client_t **auc_list,
|
||||
char const *scheme,
|
||||
char const *realm)
|
||||
char const *scheme,
|
||||
char const *realm)
|
||||
{
|
||||
int retval = 0;
|
||||
int match;
|
||||
|
||||
for (; *auc_list; auc_list = &(*auc_list)->ca_next) {
|
||||
int match = ca_clear_credentials(*auc_list, scheme, realm);
|
||||
auth_client_t *ca = *auc_list;
|
||||
|
||||
if (!AUTH_CLIENT_IS_EXTENDED(ca))
|
||||
continue;
|
||||
|
||||
if ((scheme != NULL && strcasecmp(scheme, ca->ca_scheme)) ||
|
||||
(realm != NULL && strcmp(realm, ca->ca_realm)))
|
||||
continue;
|
||||
|
||||
match = ca->ca_auc->auc_clear(*auc_list);
|
||||
|
||||
if (match < 0) {
|
||||
retval = -1;
|
||||
break;
|
||||
@ -472,21 +508,14 @@ int auc_clear_credentials(auth_client_t **auc_list,
|
||||
}
|
||||
|
||||
static
|
||||
int ca_clear_credentials(auth_client_t *ca,
|
||||
char const *scheme,
|
||||
char const *realm)
|
||||
int ca_clear_credentials(auth_client_t *ca)
|
||||
{
|
||||
assert(ca);
|
||||
assert(ca); assert(ca->ca_home->suh_size >= (int)(sizeof *ca));
|
||||
|
||||
if (!ca || !ca->ca_scheme || !ca->ca_realm)
|
||||
if (!ca)
|
||||
return -1;
|
||||
|
||||
if ((scheme != NULL && strcasecmp(scheme, ca->ca_scheme)) ||
|
||||
(realm != NULL && strcmp(realm, ca->ca_realm)))
|
||||
return -1;
|
||||
|
||||
su_free(ca->ca_home, (void *)ca->ca_user), ca->ca_user = NULL;
|
||||
su_free(ca->ca_home, (void *)ca->ca_pass), ca->ca_pass = NULL;
|
||||
ca->ca_clear = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -495,6 +524,8 @@ int ca_clear_credentials(auth_client_t *ca,
|
||||
*
|
||||
* @retval 1 when authorization can proceed
|
||||
* @retval 0 when there is not enough credentials
|
||||
*
|
||||
* @NEW_1_12_5
|
||||
*/
|
||||
int auc_has_authorization(auth_client_t **auc_list)
|
||||
{
|
||||
@ -507,6 +538,8 @@ int auc_has_authorization(auth_client_t **auc_list)
|
||||
for (ca = *auc_list; ca; ca = ca->ca_next) {
|
||||
if (!ca->ca_user || !ca->ca_pass || !ca->ca_credential_class)
|
||||
return 0;
|
||||
if (AUTH_CLIENT_IS_EXTENDED(ca) && ca->ca_clear)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -564,8 +597,11 @@ int auc_authorization(auth_client_t **auc_list, msg_t *msg, msg_pub_t *pub,
|
||||
if (!ca->ca_auc)
|
||||
continue;
|
||||
|
||||
if (ca->ca_auc->auc_authorize(ca, home, method, url, body, &h) < 0
|
||||
|| msg_header_insert(msg, pub, h) < 0)
|
||||
if (ca->ca_auc->auc_authorize(ca, home, method, url, body, &h) < 0)
|
||||
return -1;
|
||||
if (h == NULL)
|
||||
continue;
|
||||
if (msg_header_insert(msg, pub, h) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -633,14 +669,15 @@ static int auc_basic_authorization(auth_client_t *ca,
|
||||
msg_payload_t const *body,
|
||||
msg_header_t **);
|
||||
|
||||
const auth_client_plugin_t ca_basic_plugin =
|
||||
static const auth_client_plugin_t ca_basic_plugin =
|
||||
{
|
||||
/* auc_plugin_size: */ sizeof ca_basic_plugin,
|
||||
/* auc_size: */ sizeof (auth_client_t),
|
||||
/* auc_name: */ "Basic",
|
||||
/* auc_challenge: */ NULL,
|
||||
/* auc_authorize: */ auc_basic_authorization,
|
||||
/* auc_info: */ NULL
|
||||
/* auc_info: */ NULL,
|
||||
/* auc_clear: */ ca_clear_credentials
|
||||
};
|
||||
|
||||
/**Create a basic authorization header.
|
||||
@ -677,6 +714,9 @@ int auc_basic_authorization(auth_client_t *ca,
|
||||
if (user == NULL || pass == NULL)
|
||||
return -1;
|
||||
|
||||
if (AUTH_CLIENT_IS_EXTENDED(ca) && ca->ca_clear)
|
||||
return 0;
|
||||
|
||||
ulen = strlen(user), plen = strlen(pass), uplen = ulen + 1 + plen;
|
||||
b64len = BASE64_SIZE(uplen);
|
||||
basiclen = strlen("Basic ") + b64len;
|
||||
@ -731,7 +771,7 @@ static int auc_digest_authorization(auth_client_t *ca,
|
||||
msg_payload_t const *body,
|
||||
msg_header_t **);
|
||||
static int auc_digest_info(auth_client_t *ca,
|
||||
msg_auth_info_t const *ai);
|
||||
msg_auth_info_t const *info);
|
||||
|
||||
static const auth_client_plugin_t ca_digest_plugin =
|
||||
{
|
||||
@ -740,10 +780,15 @@ static const auth_client_plugin_t ca_digest_plugin =
|
||||
/* auc_name: */ "Digest",
|
||||
/* auc_challenge: */ auc_digest_challenge,
|
||||
/* auc_authorize: */ auc_digest_authorization,
|
||||
/* auc_info: */ auc_digest_info
|
||||
/* auc_info: */ auc_digest_info,
|
||||
/* auc_clear: */ ca_clear_credentials
|
||||
};
|
||||
|
||||
/** Store a digest authorization challenge.
|
||||
*
|
||||
* @retval 2 if credentials need to be (re)sent
|
||||
* @retval 1 if challenge was updated
|
||||
* @retval -1 upon an error
|
||||
*/
|
||||
static int auc_digest_challenge(auth_client_t *ca, msg_auth_t const *ch)
|
||||
{
|
||||
@ -761,27 +806,18 @@ static int auc_digest_challenge(auth_client_t *ca, msg_auth_t const *ch)
|
||||
if (ac->ac_qop && !ac->ac_auth && !ac->ac_auth_int)
|
||||
goto error;
|
||||
|
||||
stale = ac->ac_stale || str0cmp(ac->ac_nonce, cda->cda_ac->ac_nonce);
|
||||
stale = ac->ac_stale || cda->cda_ac->ac_nonce == NULL;
|
||||
|
||||
if (ac->ac_qop && (cda->cda_cnonce == NULL || ac->ac_stale)) {
|
||||
su_guid_t guid[1];
|
||||
char *cnonce;
|
||||
char *e;
|
||||
|
||||
size_t b64len = BASE64_MINSIZE(sizeof(guid)) + 1;
|
||||
if (cda->cda_cnonce != NULL)
|
||||
/* Free the old one if we are updating after stale=true */
|
||||
su_free(home, (void *)cda->cda_cnonce);
|
||||
su_guid_generate(guid);
|
||||
cda->cda_cnonce = cnonce = su_alloc(home, BASE64_SIZE(sizeof(guid)) + 1);
|
||||
base64_e(cnonce, BASE64_SIZE(sizeof(guid)) + 1, guid, sizeof(guid));
|
||||
/* somewhere else in the code the '=' chars are stripped in the header
|
||||
we need to strip it now before the digest is created or we're in trouble
|
||||
cos they won't match.....
|
||||
*/
|
||||
e = cnonce + strlen(cnonce) - 1;
|
||||
while(*e == '=') {
|
||||
*e-- = '\0';
|
||||
}
|
||||
cda->cda_cnonce = cnonce = su_alloc(home, b64len);
|
||||
base64_e(cnonce, b64len, guid, sizeof(guid));
|
||||
cda->cda_ncount = 0;
|
||||
}
|
||||
|
||||
@ -797,14 +833,14 @@ static int auc_digest_challenge(auth_client_t *ca, msg_auth_t const *ch)
|
||||
}
|
||||
|
||||
static int auc_digest_info(auth_client_t *ca,
|
||||
msg_auth_info_t const *ai)
|
||||
msg_auth_info_t const *info)
|
||||
{
|
||||
auth_digest_client_t *cda = (auth_digest_client_t *)ca;
|
||||
su_home_t *home = ca->ca_home;
|
||||
char const *nextnonce = NULL;
|
||||
issize_t n;
|
||||
|
||||
n = auth_get_params(home, ai->ai_params,
|
||||
n = auth_get_params(home, info->ai_params,
|
||||
"nextnonce=", &nextnonce,
|
||||
NULL);
|
||||
|
||||
@ -825,9 +861,9 @@ static int auc_digest_info(auth_client_t *ca,
|
||||
* sip_authorization_class or sip_proxy_authorization_class, as well as
|
||||
* http_authorization_class or http_proxy_authorization_class.
|
||||
*
|
||||
* @return
|
||||
* Returns a pointer to newly created authorization header, or NULL upon an
|
||||
* error.
|
||||
* @retval 1 when authorization headers has been created
|
||||
* @retval 0 when there is no credentials
|
||||
* @retval -1 upon an error
|
||||
*/
|
||||
static
|
||||
int auc_digest_authorization(auth_client_t *ca,
|
||||
@ -853,6 +889,9 @@ int auc_digest_authorization(auth_client_t *ca,
|
||||
auth_response_t ar[1] = {{ 0 }};
|
||||
char ncount[17];
|
||||
|
||||
if (!user || !pass || (AUTH_CLIENT_IS_EXTENDED(ca) && ca->ca_clear))
|
||||
return 0;
|
||||
|
||||
ar->ar_size = sizeof(ar);
|
||||
ar->ar_username = user;
|
||||
ar->ar_realm = ac->ac_realm;
|
||||
|
@ -76,6 +76,7 @@ static char const __func__[] = "auth_mod";
|
||||
|
||||
char const auth_internal_server_error[] = "Internal server error";
|
||||
|
||||
static void auth_call_scheme_destructor(void *);
|
||||
static void auth_md5_hmac_key(auth_mod_t *am);
|
||||
|
||||
HTABLE_PROTOS_WITH(auth_htable, aht, auth_passwd_t, usize_t, unsigned);
|
||||
@ -94,7 +95,7 @@ auth_mod_t *auth_mod_alloc(auth_scheme_t *scheme,
|
||||
|
||||
if ((am = su_home_new(scheme->asch_size))) {
|
||||
am->am_scheme = scheme;
|
||||
am->am_refcount = 1;
|
||||
su_home_destructor(am->am_home, auth_call_scheme_destructor);
|
||||
}
|
||||
|
||||
return am;
|
||||
@ -246,10 +247,14 @@ int auth_init_default(auth_mod_t *am,
|
||||
/** Destroy (a reference to) an authentication module. */
|
||||
void auth_mod_destroy(auth_mod_t *am)
|
||||
{
|
||||
if (am && am->am_refcount != 0 && --am->am_refcount == 0) {
|
||||
am->am_scheme->asch_destroy(am);
|
||||
su_home_zap(am->am_home);
|
||||
}
|
||||
su_home_unref(am->am_home);
|
||||
}
|
||||
|
||||
/** Call scheme-specific destructor function. */
|
||||
static void auth_call_scheme_destructor(void *arg)
|
||||
{
|
||||
auth_mod_t *am = arg;
|
||||
am->am_scheme->asch_destroy(am);
|
||||
}
|
||||
|
||||
/** Do-nothing destroy function.
|
||||
@ -264,18 +269,13 @@ void auth_destroy_default(auth_mod_t *am)
|
||||
/** Create a new reference to authentication module. */
|
||||
auth_mod_t *auth_mod_ref(auth_mod_t *am)
|
||||
{
|
||||
if (!am || am->am_refcount == 0)
|
||||
return NULL;
|
||||
|
||||
am->am_refcount++;
|
||||
|
||||
return am;
|
||||
return (auth_mod_t *)su_home_ref(am->am_home);
|
||||
}
|
||||
|
||||
/** Destroy a reference to an authentication module. */
|
||||
void auth_mod_unref(auth_mod_t *am)
|
||||
{
|
||||
auth_mod_destroy(am);
|
||||
su_home_unref(am->am_home);
|
||||
}
|
||||
|
||||
/** Get authenticatin module name. @NEW_1_12_4. */
|
||||
@ -608,7 +608,7 @@ struct nonce {
|
||||
uint8_t digest[6];
|
||||
};
|
||||
|
||||
#define AUTH_DIGEST_NONCE_LEN (BASE64_SIZE(sizeof (struct nonce)) + 1)
|
||||
#define AUTH_DIGEST_NONCE_LEN (BASE64_MINSIZE(sizeof (struct nonce)) + 1)
|
||||
|
||||
/** Authenticate a request with @b Digest authentication scheme.
|
||||
*
|
||||
@ -950,7 +950,8 @@ int auth_readdb_if_needed(auth_mod_t *am)
|
||||
#include <sys/file.h>
|
||||
#endif
|
||||
|
||||
#define auth_apw_local auth_readdb_internal
|
||||
/* This is just a magic value */
|
||||
#define auth_apw_local ((void *)(intptr_t)auth_readdb_internal)
|
||||
|
||||
/** Read authentication database */
|
||||
static
|
||||
|
@ -126,7 +126,7 @@ static int delayed_auth_init(auth_mod_t *am,
|
||||
|
||||
struct auth_splugin_t
|
||||
{
|
||||
void const *asp_tag;
|
||||
void const *asp_cookie;
|
||||
auth_splugin_t *asp_next;
|
||||
auth_splugin_t **asp_prev;
|
||||
auth_mod_t *asp_am;
|
||||
@ -136,6 +136,8 @@ struct auth_splugin_t
|
||||
int asp_canceled;
|
||||
};
|
||||
|
||||
/* This is unique identifier */
|
||||
#define delayed_asp_cookie ((void const *)(intptr_t)delayed_auth_cancel)
|
||||
|
||||
static void delayed_auth_method_recv(su_root_magic_t *rm,
|
||||
su_msg_r msg,
|
||||
@ -162,7 +164,7 @@ static void delayed_auth_method(auth_mod_t *am,
|
||||
|
||||
asp = su_msg_data(mamc); assert(asp);
|
||||
|
||||
asp->asp_tag = delayed_auth_cancel;
|
||||
asp->asp_cookie = delayed_asp_cookie;
|
||||
asp->asp_am = am;
|
||||
asp->asp_as = as;
|
||||
asp->asp_header = auth;
|
||||
@ -216,7 +218,7 @@ static void delayed_auth_cancel(auth_mod_t *am, auth_status_t *as)
|
||||
|
||||
(void)ap; /* xyzzy */
|
||||
|
||||
if (as->as_plugin && as->as_plugin->asp_tag == delayed_auth_cancel)
|
||||
if (as->as_plugin && as->as_plugin->asp_cookie == delayed_asp_cookie)
|
||||
as->as_plugin->asp_canceled = 1;
|
||||
|
||||
as->as_status = 500, as->as_phrase = "Authentication canceled";
|
||||
|
@ -29,6 +29,9 @@
|
||||
/**@file sofia-sip/auth_client_plugin.h
|
||||
* @brief Client-side plugin interface for authentication
|
||||
*
|
||||
* @note For extensions in 1.12.6 or later,
|
||||
* you have to #define SOFIA_EXTEND_AUTH_CLIENT to 1.
|
||||
*
|
||||
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
|
||||
*
|
||||
* @date Created: Fri May 19 16:18:21 EEST 2006
|
||||
@ -58,6 +61,10 @@ struct auth_client_s {
|
||||
char *ca_pass;
|
||||
|
||||
msg_hclass_t *ca_credential_class;
|
||||
|
||||
#if SOFIA_EXTEND_AUTH_CLIENT
|
||||
int ca_clear;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct auth_client_plugin
|
||||
@ -81,8 +88,19 @@ struct auth_client_plugin
|
||||
|
||||
/** Store nextnonce from Authentication-Info or Proxy-Authentication-Info. */
|
||||
int (*auc_info)(auth_client_t *ca, msg_auth_info_t const *ai);
|
||||
|
||||
#if SOFIA_EXTEND_AUTH_CLIENT
|
||||
/** Clear credentials (user/pass). @NEW_1_12_6 */
|
||||
int (*auc_clear)(auth_client_t *ca);
|
||||
#endif
|
||||
};
|
||||
|
||||
/** Check if authentication client has been extended. @NEW_1_12_6 */
|
||||
#define AUTH_CLIENT_IS_EXTENDED(ca) \
|
||||
((ca)->ca_auc->auc_plugin_size > \
|
||||
(int)offsetof(auth_client_plugin_t, auc_clear) \
|
||||
&& (ca)->ca_auc->auc_clear != NULL)
|
||||
|
||||
SOFIA_END_DECLS
|
||||
|
||||
#endif /* !defined AUTH_CLIENT_PLUGIN_H */
|
||||
|
@ -105,7 +105,7 @@ struct auth_scheme
|
||||
typedef struct
|
||||
{
|
||||
unsigned apw_index; /**< Key to hash table */
|
||||
void const *apw_type; /**< Magic pointer */
|
||||
void const *apw_type; /**< Magic identifier */
|
||||
|
||||
char const *apw_user; /**< Username */
|
||||
char const *apw_realm; /**< Realm */
|
||||
@ -124,7 +124,7 @@ struct stat;
|
||||
struct auth_mod_t
|
||||
{
|
||||
su_home_t am_home[1];
|
||||
unsigned am_refcount; /**< Number of references to this module */
|
||||
unsigned _am_refcount; /**< Not used */
|
||||
|
||||
/* User database / cache */
|
||||
char const *am_db; /**< User database file name */
|
||||
|
@ -769,8 +769,6 @@ int test_digest_client()
|
||||
{
|
||||
char const *nonce1, *nextnonce, *nonce2;
|
||||
|
||||
reinit_as(as); auth_mod_destroy(am); aucs = NULL;
|
||||
|
||||
TEST_1(am = auth_mod_create(NULL,
|
||||
AUTHTAG_METHOD("Digest"),
|
||||
AUTHTAG_REALM("ims3.so.noklab.net"),
|
||||
@ -1164,9 +1162,10 @@ int test_module_io()
|
||||
extern su_log_t iptsec_log[];
|
||||
|
||||
static
|
||||
void usage(void)
|
||||
void usage(int exitcode)
|
||||
{
|
||||
fprintf(stderr, "usage: %s [-v] [-l n]\n", name);
|
||||
fprintf(stderr, "usage: %s [-v] [-a] [-l n]\n", name);
|
||||
exit(exitcode);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
@ -1179,8 +1178,10 @@ int main(int argc, char *argv[])
|
||||
su_init();
|
||||
|
||||
for (i = 1; argv[i]; i++) {
|
||||
if (argv[i] && strcmp(argv[i], "-v") == 0)
|
||||
if (strcmp(argv[i], "-v") == 0)
|
||||
tstflags |= tst_verbatim;
|
||||
else if (strcmp(argv[i], "-a") == 0)
|
||||
tstflags |= tst_abort;
|
||||
else if (strncmp(argv[i], "-l", 2) == 0) {
|
||||
int level = 3;
|
||||
char *rest = NULL;
|
||||
@ -1193,11 +1194,11 @@ int main(int argc, char *argv[])
|
||||
level = 3, rest = "";
|
||||
|
||||
if (rest == NULL || *rest)
|
||||
usage();
|
||||
usage(1);
|
||||
|
||||
su_log_set_level(iptsec_log, level);
|
||||
} else {
|
||||
usage();
|
||||
usage(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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}
|
||||
|
47
libs/sofia-sip/libsofia-sip-ua/msg/msg_inlined.c
Normal file
47
libs/sofia-sip/libsofia-sip-ua/msg/msg_inlined.c
Normal 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
|
@ -54,11 +54,13 @@ BEGIN {
|
||||
split("", NAMES);
|
||||
split("", Comments);
|
||||
split("", COMMENTS);
|
||||
split("", experimental);
|
||||
|
||||
# indexed by the C name of the header
|
||||
split("", Since); # Non-NUL if extra
|
||||
split("", Extra); # Offset in extra headers
|
||||
|
||||
without_experimental = 0;
|
||||
template="";
|
||||
template1="";
|
||||
template2="";
|
||||
@ -78,13 +80,18 @@ function name_hash (name)
|
||||
{
|
||||
hash = 0;
|
||||
|
||||
len = split(name, chars, "");
|
||||
len = length(name);
|
||||
|
||||
for (i = 1; i <= len; i++) {
|
||||
c = tolower(chars[i]);
|
||||
c = tolower(substr(name, i, 1));
|
||||
hash = (38501 * (hash + index(ascii, c))) % 65536;
|
||||
}
|
||||
|
||||
if (hash == 0) {
|
||||
print "*** msg_parser.awk: calculating hash failed\n";
|
||||
exit(5);
|
||||
}
|
||||
|
||||
if (0) {
|
||||
# Test that hash algorithm above agrees with the C version
|
||||
pipe = ("../msg/msg_name_hash " name);
|
||||
@ -155,11 +162,24 @@ function protos (name, comment, hash, since)
|
||||
Extra[name] = extra++;
|
||||
}
|
||||
|
||||
expr = (without_experimental > 0 && do_hash);
|
||||
if (expr) {
|
||||
printf "%s is experimental\n", Comment;
|
||||
}
|
||||
|
||||
experimental[N] = expr;
|
||||
|
||||
if (PR) {
|
||||
if (expr) {
|
||||
print "#if SU_HAVE_EXPERIMENTAL" > PR;
|
||||
}
|
||||
replace(template, hash, name, NAME, comment, Comment, COMMENT, since);
|
||||
replace(template1, hash, name, NAME, comment, Comment, COMMENT, since);
|
||||
replace(template2, hash, name, NAME, comment, Comment, COMMENT, since);
|
||||
replace(template3, hash, name, NAME, comment, Comment, COMMENT, since);
|
||||
if (expr) {
|
||||
print "#endif /* SU_HAVE_EXPERIMENTAL */" > PR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -210,8 +230,19 @@ function process_footer (text)
|
||||
for (i = 1; i <= n; i++) {
|
||||
l = lines[i];
|
||||
if (match(tolower(l), /#(xxxxxx(x_xxxxxxx)?|hash)#/)) {
|
||||
expr = 0;
|
||||
|
||||
for (j = 1; j <= N; j++) {
|
||||
l = lines[i];
|
||||
if (expr != experimental[j]) {
|
||||
expr = experimental[j];
|
||||
if (expr) {
|
||||
print "#if SU_HAVE_EXPERIMENTAL" > PR;
|
||||
}
|
||||
else {
|
||||
print "#endif /* SU_HAVE_EXPERIMENTAL */" > PR;
|
||||
}
|
||||
}
|
||||
gsub(/#hash#/, hashes[j], l);
|
||||
gsub(/#xxxxxxx_xxxxxxx#/, comments[j], l);
|
||||
gsub(/#Xxxxxxx_Xxxxxxx#/, Comments[j], l);
|
||||
@ -220,6 +251,10 @@ function process_footer (text)
|
||||
gsub(/#XXXXXX#/, NAMES[j], l);
|
||||
print l > PR;
|
||||
}
|
||||
|
||||
if (expr) {
|
||||
print "#endif /* SU_HAVE_EXPERIMENTAL */" > PR;
|
||||
}
|
||||
} else {
|
||||
print l > PR;
|
||||
}
|
||||
@ -333,10 +368,11 @@ function templates ()
|
||||
}
|
||||
|
||||
/^#### EXTRA HEADER LIST STARTS HERE ####$/ { HLIST=1; templates(); }
|
||||
HLIST && /^#### EXPERIMENTAL HEADER LIST STARTS HERE ####$/ {
|
||||
without_experimental=total; }
|
||||
HLIST && /^[a-z]/ { protos($1, $0, 0, $2); headers[total++] = $1; }
|
||||
/^#### EXTRA HEADER LIST ENDS HERE ####$/ { HLIST=0; }
|
||||
|
||||
|
||||
/^ *\/\* === Headers start here \*\// { in_header_list=1; templates(); }
|
||||
/^ *\/\* === Headers end here \*\// { in_header_list=0; }
|
||||
|
||||
@ -366,10 +402,13 @@ in_header_list && /^ (sip|rtsp|http|msg|mp)_[a-z_0-9]+_t/ {
|
||||
END {
|
||||
if (failed) { exit };
|
||||
|
||||
if (without_experimental == 0)
|
||||
without_experimental = total;
|
||||
|
||||
if (!NO_LAST) {
|
||||
protos("unknown", "/**< Unknown headers */", -3);
|
||||
protos("error", "/**< Erroneous headers */", -4);
|
||||
protos("separator", "/**< Separator line between headers and payload */", -5);
|
||||
protos("separator", "/**< Separator line between headers and body */", -5);
|
||||
protos("payload", "/**< Message payload */", -6);
|
||||
if (multipart)
|
||||
protos("multipart", "/**< Multipart payload */", -7);
|
||||
@ -397,6 +436,10 @@ END {
|
||||
gsub(/#DATE#/, "@date Generated: " date, header);
|
||||
print header > PT;
|
||||
|
||||
print "" > PT;
|
||||
print "#define msg_offsetof(s, f) ((unsigned short)offsetof(s ,f))" > PT;
|
||||
print "" > PT;
|
||||
|
||||
if (MC_SHORT_SIZE) {
|
||||
printf("static msg_href_t const " \
|
||||
"%s_short_forms[MC_SHORT_SIZE] = \n{\n",
|
||||
@ -408,7 +451,7 @@ END {
|
||||
n = shorts[i];
|
||||
flags = header_flags[n]; if (flags) flags = ",\n " flags;
|
||||
|
||||
printf(" { /* %s */ %s_%s_class, offsetof(%s_t, %s_%s)%s }%s\n",
|
||||
printf(" { /* %s */ %s_%s_class, msg_offsetof(%s_t, %s_%s)%s }%s\n",
|
||||
substr(lower_case, i, 1),
|
||||
tprefix, n, module, prefix, n, flags, c) \
|
||||
> PT;
|
||||
@ -426,7 +469,16 @@ END {
|
||||
if (extra > 0) {
|
||||
printf("struct %s {\n", extra_struct) > PT;
|
||||
printf(" %s base;\n", module_struct) > PT;
|
||||
printf(" msg_header_t *extra[%u];\n", extra) > PT;
|
||||
if (total - without_experimental < extra) {
|
||||
printf(" msg_header_t *extra[%u];\n",
|
||||
extra - (total - without_experimental)) > PT;
|
||||
}
|
||||
if (total - without_experimental > 0) {
|
||||
print "#if SU_HAVE_EXPERIMENTAL" > PT;
|
||||
printf(" msg_header_t *experimental[%u];\n",
|
||||
total - without_experimental) > PT;
|
||||
print "#endif" > PT;
|
||||
}
|
||||
printf("};\n\n") > PT;
|
||||
module_struct = "struct " extra_struct;
|
||||
}
|
||||
@ -450,11 +502,11 @@ END {
|
||||
len = split("request status separator payload unknown error", unnamed, " ");
|
||||
|
||||
for (i = 1; i <= len; i++) {
|
||||
printf(" {{ %s_%s_class, offsetof(%s_t, %s_%s) }},\n",
|
||||
printf(" {{ %s_%s_class, msg_offsetof(%s_t, %s_%s) }},\n",
|
||||
tprefix, unnamed[i], module, prefix, unnamed[i]) > PT;
|
||||
}
|
||||
if (multipart) {
|
||||
printf(" {{ %s_class, offsetof(%s_t, %s_multipart) }},\n",
|
||||
printf(" {{ %s_class, msg_offsetof(%s_t, %s_multipart) }},\n",
|
||||
multipart, module, prefix) > PT;
|
||||
} else {
|
||||
printf(" {{ NULL, 0 }},\n") > PT;
|
||||
@ -465,7 +517,13 @@ END {
|
||||
else {
|
||||
printf(" NULL, \n") > PT;
|
||||
}
|
||||
printf(" %d, %d, \n", MC_HASH_SIZE, total) > PT;
|
||||
printf(" %d, \n", MC_HASH_SIZE) > PT;
|
||||
printf ("#if SU_HAVE_EXPERIMENTAL\n" \
|
||||
" %d,\n" \
|
||||
"#else\n" \
|
||||
" %d,\n" \
|
||||
"#endif\n", \
|
||||
total, without_experimental) > PT;
|
||||
printf(" {\n") > PT;
|
||||
|
||||
for (i = 0; i < total; i++) {
|
||||
@ -484,6 +542,7 @@ END {
|
||||
}
|
||||
|
||||
header_hash[j] = n;
|
||||
experimental2[j] = (i >= without_experimental);
|
||||
}
|
||||
|
||||
for (i = 0; i < MC_HASH_SIZE; i++) {
|
||||
@ -492,14 +551,23 @@ END {
|
||||
n = header_hash[i];
|
||||
flags = header_flags[n]; if (flags) flags = ",\n " flags;
|
||||
|
||||
if (experimental2[i]) {
|
||||
print "#if SU_HAVE_EXPERIMENTAL" > PT;
|
||||
}
|
||||
|
||||
if (Since[n]) {
|
||||
printf(" { %s_%s_class, offsetof(struct %s, extra[%u])%s }%s\n",
|
||||
printf(" { %s_%s_class,\n" \
|
||||
" msg_offsetof(struct %s, extra[%u])%s }%s\n",
|
||||
tprefix, n, extra_struct, Extra[n], flags, c) > PT;
|
||||
}
|
||||
else {
|
||||
printf(" { %s_%s_class, offsetof(%s_t, %s_%s)%s }%s\n",
|
||||
printf(" { %s_%s_class, msg_offsetof(%s_t, %s_%s)%s }%s\n",
|
||||
tprefix, n, module, prefix, n, flags, c) > PT;
|
||||
}
|
||||
|
||||
if (experimental2[i]) {
|
||||
printf("#else\n { NULL, 0 }%s\n#endif\n", c) > PT;
|
||||
}
|
||||
}
|
||||
else {
|
||||
printf(" { NULL, 0 }%s\n", c) > PT;
|
||||
|
@ -1974,6 +1974,8 @@ msg_t *msg_make(msg_mclass_t const *mc, int flags,
|
||||
return NULL;
|
||||
|
||||
msg = msg_create(mc, flags);
|
||||
if (msg == NULL)
|
||||
return NULL;
|
||||
|
||||
su_home_preload(msg_home(msg), 1, len + 1024);
|
||||
|
||||
|
@ -56,7 +56,8 @@ SOFIA_BEGIN_DECLS
|
||||
* 1) Header class definitions.
|
||||
*/
|
||||
|
||||
#if HAVE_STRUCT_KEYWORDS
|
||||
/* Do not use keywords until you fix msg_kind_foo_critical thing! */ \
|
||||
#if HAVE_STRUCT_KEYWORDS && 0
|
||||
/** Define a header class */
|
||||
#define MSG_HEADER_CLASS(pr, c, l, s, params, kind, dup, upd) \
|
||||
{{ \
|
||||
@ -74,6 +75,7 @@ SOFIA_BEGIN_DECLS
|
||||
hc_kind: msg_kind_##kind, \
|
||||
}}
|
||||
#else
|
||||
/** Define a header class */
|
||||
#define MSG_HEADER_CLASS(pr, c, l, s, params, kind, dup, upd) \
|
||||
{{ \
|
||||
pr##c##_hash, \
|
||||
@ -198,9 +200,11 @@ SOFIAPUBFUN issize_t msg_parse_next_field(su_home_t *home, msg_header_t *prev,
|
||||
|
||||
/** Duplicate string. @HI */
|
||||
#define MSG_STRING_DUP(p, d, s) \
|
||||
(void)((s)?((p)=(char*)memccpy((void *)((d)=(char*)p),(s),0,SIZE_MAX))\
|
||||
(void)((s)?((p)=(char*)memccpy((void *)((d)=(char*)p),(s),0,INT_MAX))\
|
||||
:((d)=NULL))
|
||||
|
||||
/* Solaris has broken memccpy - it considers last argument as signed */
|
||||
|
||||
/** Calculate string size. @HI */
|
||||
#define MSG_STRING_SIZE(s) ((s) ? (strlen(s) + 1) : 0)
|
||||
|
||||
|
46
libs/sofia-sip/libsofia-sip-ua/msg/test_inlined.c
Normal file
46
libs/sofia-sip/libsofia-sip-ua/msg/test_inlined.c
Normal 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
|
@ -59,11 +59,6 @@ static int test_flags = 0;
|
||||
|
||||
char const name[] = "test_msg";
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
fprintf(stderr, "usage: %s [-v]\n", name);
|
||||
}
|
||||
|
||||
static int msg_time_test(void)
|
||||
{
|
||||
char buf[32];
|
||||
@ -138,7 +133,6 @@ static int msg_time_test(void)
|
||||
}
|
||||
|
||||
END();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int addr_test(void)
|
||||
@ -1688,6 +1682,12 @@ static int random_test(void)
|
||||
END();
|
||||
}
|
||||
|
||||
void usage(int exitcode)
|
||||
{
|
||||
fprintf(stderr, "usage: %s [-v] [-a]\n", name);
|
||||
exit(exitcode);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int retval = 0;
|
||||
@ -1696,8 +1696,10 @@ int main(int argc, char *argv[])
|
||||
for (i = 1; argv[i]; i++) {
|
||||
if (strcmp(argv[i], "-v") == 0)
|
||||
test_flags |= tst_verbatim;
|
||||
else if (strcmp(argv[i], "-a") == 0)
|
||||
test_flags |= tst_abort;
|
||||
else
|
||||
usage();
|
||||
usage(1);
|
||||
}
|
||||
|
||||
retval |= msg_time_test(); fflush(stdout);
|
||||
|
@ -59,4 +59,5 @@ EXTRA_DIST = Doxyfile nea.docs $(BUILT_SOURCES)
|
||||
# ----------------------------------------------------------------------
|
||||
# Sofia specific rules
|
||||
|
||||
include ../sofia.am
|
||||
include $(top_srcdir)/rules/sofia.am
|
||||
|
||||
|
@ -496,14 +496,14 @@ nea_server_t *nea_server_create(nta_agent_t *agent,
|
||||
nes->nes_eventity_uri &&
|
||||
(nes->nes_leg || leg == NULL) &&
|
||||
nes->nes_timer) {
|
||||
SU_DEBUG_5(("nea_server_create(%p): success\n", nes));
|
||||
SU_DEBUG_5(("nea_server_create(%p): success\n", (void *)nes));
|
||||
su_timer_set(nes->nes_timer, nes_event_timer, nes);
|
||||
|
||||
nes->nes_callback = callback;
|
||||
nes->nes_context = context;
|
||||
}
|
||||
else {
|
||||
SU_DEBUG_5(("nea_server_create(%p): failed\n", nes));
|
||||
SU_DEBUG_5(("nea_server_create(%p): failed\n", (void *)nes));
|
||||
nea_server_destroy(nes), nes = NULL;
|
||||
}
|
||||
}
|
||||
@ -551,11 +551,11 @@ int nea_server_shutdown(nea_server_t *nes,
|
||||
return 500;
|
||||
|
||||
if (nes->nes_in_callback) {
|
||||
SU_DEBUG_5(("nea_server_shutdown(%p) while in callback\n", nes));
|
||||
SU_DEBUG_5(("nea_server_shutdown(%p) while in callback\n", (void *)nes));
|
||||
return 100;
|
||||
}
|
||||
|
||||
SU_DEBUG_5(("nea_server_shutdown(%p)\n", nes));
|
||||
SU_DEBUG_5(("nea_server_shutdown(%p)\n", (void *)nes));
|
||||
|
||||
in_callback = nes->nes_in_callback; nes->nes_in_callback = 1;
|
||||
|
||||
@ -585,12 +585,12 @@ void nea_server_destroy(nea_server_t *nes)
|
||||
return;
|
||||
|
||||
if (nes->nes_in_callback) {
|
||||
SU_DEBUG_5(("nea_server_destroy(%p) while in callback\n", nes));
|
||||
SU_DEBUG_5(("nea_server_destroy(%p) while in callback\n", (void *)nes));
|
||||
nes->nes_pending_destroy = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
SU_DEBUG_5(("nea_server_destroy(%p)\n", nes));
|
||||
SU_DEBUG_5(("nea_server_destroy(%p)\n", (void *)nes));
|
||||
|
||||
nta_leg_destroy(nes->nes_leg), nes->nes_leg = NULL;
|
||||
|
||||
@ -837,8 +837,8 @@ int nea_view_update(nea_server_t *nes,
|
||||
if (evq->evq_content_type)
|
||||
nea_view_queue(nes, evv, evq);
|
||||
|
||||
SU_DEBUG_7(("nea_server_update(%p): %s (%s)\n",
|
||||
nes, ev->ev_event->o_type, evv->evv_content_type->c_type));
|
||||
SU_DEBUG_7(("nea_server_update(%p): %s (%s)\n", (void *)nes,
|
||||
ev->ev_event->o_type, evv->evv_content_type->c_type));
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -1019,7 +1019,8 @@ int nea_server_notify(nea_server_t *nes, nea_event_t *ev)
|
||||
nea_sub_t *s;
|
||||
int notified = 0, throttled = nes->nes_throttled;
|
||||
|
||||
SU_DEBUG_7(("nea_server_notify(%p): %s\n", nes, ev ? ev->ev_event->o_type: ""));
|
||||
SU_DEBUG_7(("nea_server_notify(%p): %s\n", (void *)nes,
|
||||
ev ? ev->ev_event->o_type: ""));
|
||||
|
||||
++nes->nes_in_list;
|
||||
|
||||
|
@ -73,7 +73,7 @@ EXTRA_DIST = Doxyfile nta.docs sl_utils.docs \
|
||||
# ----------------------------------------------------------------------
|
||||
# Sofia specific rules
|
||||
|
||||
include ../sofia.am
|
||||
include $(top_srcdir)/rules/sofia.am
|
||||
|
||||
# Generate list of nta tags
|
||||
TAG_DLL_FLAGS = LIST=nta_tag_list
|
File diff suppressed because it is too large
Load Diff
@ -343,8 +343,8 @@ int nta_check_accept(nta_incoming_t *irq,
|
||||
/**Check @SessionExpires header.
|
||||
*
|
||||
* If the proposed session-expiration time is smaller than @MinSE or our
|
||||
* minimal session expiration time, respond with 422 containing our minimal
|
||||
* session expiration time in @MinSE header.
|
||||
* minimal session expiration time, respond with 422 containing shortest
|
||||
* acceptable session expiration time in @MinSE header.
|
||||
*
|
||||
* @param irq incoming transaction object (may be NULL).
|
||||
* @param sip contents of the SIP message
|
||||
@ -359,26 +359,28 @@ int nta_check_session_expires(nta_incoming_t *irq,
|
||||
sip_time_t my_min_se,
|
||||
tag_type_t tag, tag_value_t value, ...)
|
||||
{
|
||||
if ((sip->sip_min_se &&
|
||||
sip->sip_session_expires->x_delta < sip->sip_min_se->min_delta)
|
||||
|| sip->sip_session_expires->x_delta < my_min_se) {
|
||||
unsigned long min_se = my_min_se;
|
||||
|
||||
if (sip->sip_min_se && min_se < sip->sip_min_se->min_delta)
|
||||
min_se = sip->sip_min_se->min_delta;
|
||||
|
||||
if (sip->sip_session_expires->x_delta >= min_se)
|
||||
return 0;
|
||||
|
||||
if (irq) {
|
||||
ta_list ta;
|
||||
sip_min_se_t min_se0[1];
|
||||
|
||||
sip_min_se_t min_se[1];
|
||||
ta_start(ta, tag, value);
|
||||
|
||||
sip_min_se_init(min_se)->min_delta = my_min_se;
|
||||
sip_min_se_init(min_se0)->min_delta = min_se;
|
||||
|
||||
if (irq) {
|
||||
ta_start(ta, tag, value);
|
||||
nta_incoming_treply(irq,
|
||||
SIP_422_SESSION_TIMER_TOO_SMALL,
|
||||
SIPTAG_MIN_SE(min_se),
|
||||
ta_tags(ta));
|
||||
ta_end(ta);
|
||||
}
|
||||
|
||||
return 422;
|
||||
nta_incoming_treply(irq,
|
||||
SIP_422_SESSION_TIMER_TOO_SMALL,
|
||||
SIPTAG_MIN_SE(min_se0),
|
||||
ta_tags(ta));
|
||||
ta_end(ta);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 422;
|
||||
}
|
||||
|
@ -98,16 +98,17 @@ struct nta_agent_s
|
||||
nta_agent_magic_t *sa_magic;
|
||||
nta_message_f *sa_callback;
|
||||
|
||||
uint32_t sa_nw_updates; /* Shall we enable network detector? */
|
||||
|
||||
nta_update_magic_t *sa_update_magic;
|
||||
nta_update_tport_f *sa_update_tport;
|
||||
|
||||
su_time_t sa_now; /**< Timestamp in microsecond resolution. */
|
||||
su_duration_t sa_next; /**< Timestamp for next agent_timer. */
|
||||
su_time_t sa_now; /**< Timestamp in microsecond resolution. */
|
||||
uint32_t sa_millisec; /**< Timestamp in milliseconds resolution. */
|
||||
|
||||
uint32_t sa_nw_updates; /* Shall we enable network detector? */
|
||||
|
||||
uint32_t sa_flags; /**< Message flags */
|
||||
msg_mclass_t *sa_mclass;
|
||||
msg_mclass_t const *sa_mclass;
|
||||
|
||||
sip_contact_t *sa_contact;
|
||||
sip_via_t *sa_vias; /**< @Via headers for all transports */
|
||||
@ -223,6 +224,9 @@ struct nta_agent_s
|
||||
/** If true, automatically create compartments */
|
||||
unsigned sa_auto_comp:1;
|
||||
|
||||
/** Set when executing timer */
|
||||
unsigned sa_in_timer:1;
|
||||
|
||||
unsigned :0;
|
||||
|
||||
/** Messages memory preload. */
|
||||
@ -342,6 +346,11 @@ struct nta_leg_s
|
||||
unsigned leg_loose_route : 1; /**< Topmost route in set is LR */
|
||||
#endif
|
||||
unsigned leg_local_is_to : 1; /**< Backwards-compatibility. */
|
||||
unsigned leg_tagged : 1; /**< Tagged after creation.
|
||||
*
|
||||
* Request missing To tag matches it
|
||||
* even after tagging.
|
||||
*/
|
||||
unsigned:0;
|
||||
nta_request_f *leg_callback;
|
||||
nta_leg_magic_t *leg_magic;
|
||||
@ -463,12 +472,17 @@ struct nta_outgoing_s
|
||||
|
||||
sip_method_t orq_method;
|
||||
char const *orq_method_name;
|
||||
url_t const *orq_url; /**< Original RequestURI */
|
||||
|
||||
sip_from_t const *orq_from;
|
||||
sip_to_t const *orq_to;
|
||||
char const *orq_tag; /**< Tag from final response. */
|
||||
|
||||
sip_cseq_t const *orq_cseq;
|
||||
sip_call_id_t const *orq_call_id;
|
||||
|
||||
char const *orq_tag; /**< Tag from final response. */
|
||||
msg_t *orq_request;
|
||||
msg_t *orq_response;
|
||||
|
||||
su_time_t orq_sent; /**< When request was sent? */
|
||||
unsigned orq_delay; /**< RTT estimate */
|
||||
@ -501,11 +515,9 @@ struct nta_outgoing_s
|
||||
unsigned orq_sigcomp_new:1; /**< Create compartment if needed */
|
||||
unsigned orq_sigcomp_zap:1; /**< Reset SigComp after completing */
|
||||
unsigned orq_must_100rel : 1;
|
||||
unsigned orq_timestamp : 1; /**< insert @Timestamp header. */
|
||||
unsigned orq_timestamp : 1; /**< Insert @Timestamp header. */
|
||||
unsigned : 0; /* pad */
|
||||
|
||||
uint32_t orq_rseq; /**< Latest incoming rseq */
|
||||
|
||||
#if HAVE_SOFIA_SRESOLV
|
||||
sipdns_resolver_t *orq_resolver;
|
||||
#endif
|
||||
@ -522,12 +534,10 @@ struct nta_outgoing_s
|
||||
|
||||
char const *orq_branch; /**< Transaction branch */
|
||||
char const *orq_via_branch; /**< @Via branch */
|
||||
url_t const *orq_url; /**< Original RequestURI */
|
||||
|
||||
msg_t *orq_request;
|
||||
msg_t *orq_response;
|
||||
|
||||
nta_outgoing_t *orq_cancel; /**< CANCEL transaction */
|
||||
|
||||
uint32_t orq_rseq; /**< Latest incoming rseq */
|
||||
};
|
||||
|
||||
/* Virtual function table for plugging in SigComp */
|
||||
|
@ -110,38 +110,38 @@ tag_typedef_t ntatag_rseq = UINTTAG_TYPEDEF(rseq);
|
||||
|
||||
/* Status */
|
||||
|
||||
tag_typedef_t ntatag_s_irq_hash = UINTTAG_TYPEDEF(s_irq_hash);
|
||||
tag_typedef_t ntatag_s_orq_hash = UINTTAG_TYPEDEF(s_orq_hash);
|
||||
tag_typedef_t ntatag_s_leg_hash = UINTTAG_TYPEDEF(s_leg_hash);
|
||||
tag_typedef_t ntatag_s_irq_hash_used = UINTTAG_TYPEDEF(s_irq_hash_used);
|
||||
tag_typedef_t ntatag_s_orq_hash_used = UINTTAG_TYPEDEF(s_orq_hash_used);
|
||||
tag_typedef_t ntatag_s_leg_hash_used = UINTTAG_TYPEDEF(s_leg_hash_used);
|
||||
tag_typedef_t ntatag_s_recv_msg = UINTTAG_TYPEDEF(s_recv_msg);
|
||||
tag_typedef_t ntatag_s_recv_request = UINTTAG_TYPEDEF(s_recv_request);
|
||||
tag_typedef_t ntatag_s_recv_response = UINTTAG_TYPEDEF(s_recv_response);
|
||||
tag_typedef_t ntatag_s_bad_message = UINTTAG_TYPEDEF(s_bad_message);
|
||||
tag_typedef_t ntatag_s_bad_request = UINTTAG_TYPEDEF(s_bad_request);
|
||||
tag_typedef_t ntatag_s_bad_response = UINTTAG_TYPEDEF(s_bad_response);
|
||||
tag_typedef_t ntatag_s_drop_request = UINTTAG_TYPEDEF(s_drop_request);
|
||||
tag_typedef_t ntatag_s_drop_response = UINTTAG_TYPEDEF(s_drop_response);
|
||||
tag_typedef_t ntatag_s_client_tr = UINTTAG_TYPEDEF(s_client_tr);
|
||||
tag_typedef_t ntatag_s_server_tr = UINTTAG_TYPEDEF(s_server_tr);
|
||||
tag_typedef_t ntatag_s_dialog_tr = UINTTAG_TYPEDEF(s_dialog_tr);
|
||||
tag_typedef_t ntatag_s_acked_tr = UINTTAG_TYPEDEF(s_acked_tr);
|
||||
tag_typedef_t ntatag_s_canceled_tr = UINTTAG_TYPEDEF(s_canceled_tr);
|
||||
tag_typedef_t ntatag_s_trless_request = UINTTAG_TYPEDEF(s_trless_request);
|
||||
tag_typedef_t ntatag_s_trless_to_tr = UINTTAG_TYPEDEF(s_trless_to_tr);
|
||||
tag_typedef_t ntatag_s_trless_response = UINTTAG_TYPEDEF(s_trless_response);
|
||||
tag_typedef_t ntatag_s_trless_200 = UINTTAG_TYPEDEF(s_trless_200);
|
||||
tag_typedef_t ntatag_s_merged_request = UINTTAG_TYPEDEF(s_merged_request);
|
||||
tag_typedef_t ntatag_s_sent_msg = UINTTAG_TYPEDEF(s_sent_msg);
|
||||
tag_typedef_t ntatag_s_sent_request = UINTTAG_TYPEDEF(s_sent_request);
|
||||
tag_typedef_t ntatag_s_sent_response = UINTTAG_TYPEDEF(s_sent_response);
|
||||
tag_typedef_t ntatag_s_retry_request = UINTTAG_TYPEDEF(s_retry_request);
|
||||
tag_typedef_t ntatag_s_retry_response = UINTTAG_TYPEDEF(s_retry_response);
|
||||
tag_typedef_t ntatag_s_recv_retry = UINTTAG_TYPEDEF(s_recv_retry);
|
||||
tag_typedef_t ntatag_s_tout_request = UINTTAG_TYPEDEF(s_tout_request);
|
||||
tag_typedef_t ntatag_s_tout_response = UINTTAG_TYPEDEF(s_tout_response);
|
||||
tag_typedef_t ntatag_s_irq_hash = USIZETAG_TYPEDEF(s_irq_hash);
|
||||
tag_typedef_t ntatag_s_orq_hash = USIZETAG_TYPEDEF(s_orq_hash);
|
||||
tag_typedef_t ntatag_s_leg_hash = USIZETAG_TYPEDEF(s_leg_hash);
|
||||
tag_typedef_t ntatag_s_irq_hash_used = USIZETAG_TYPEDEF(s_irq_hash_used);
|
||||
tag_typedef_t ntatag_s_orq_hash_used = USIZETAG_TYPEDEF(s_orq_hash_used);
|
||||
tag_typedef_t ntatag_s_leg_hash_used = USIZETAG_TYPEDEF(s_leg_hash_used);
|
||||
tag_typedef_t ntatag_s_recv_msg = USIZETAG_TYPEDEF(s_recv_msg);
|
||||
tag_typedef_t ntatag_s_recv_request = USIZETAG_TYPEDEF(s_recv_request);
|
||||
tag_typedef_t ntatag_s_recv_response = USIZETAG_TYPEDEF(s_recv_response);
|
||||
tag_typedef_t ntatag_s_bad_message = USIZETAG_TYPEDEF(s_bad_message);
|
||||
tag_typedef_t ntatag_s_bad_request = USIZETAG_TYPEDEF(s_bad_request);
|
||||
tag_typedef_t ntatag_s_bad_response = USIZETAG_TYPEDEF(s_bad_response);
|
||||
tag_typedef_t ntatag_s_drop_request = USIZETAG_TYPEDEF(s_drop_request);
|
||||
tag_typedef_t ntatag_s_drop_response = USIZETAG_TYPEDEF(s_drop_response);
|
||||
tag_typedef_t ntatag_s_client_tr = USIZETAG_TYPEDEF(s_client_tr);
|
||||
tag_typedef_t ntatag_s_server_tr = USIZETAG_TYPEDEF(s_server_tr);
|
||||
tag_typedef_t ntatag_s_dialog_tr = USIZETAG_TYPEDEF(s_dialog_tr);
|
||||
tag_typedef_t ntatag_s_acked_tr = USIZETAG_TYPEDEF(s_acked_tr);
|
||||
tag_typedef_t ntatag_s_canceled_tr = USIZETAG_TYPEDEF(s_canceled_tr);
|
||||
tag_typedef_t ntatag_s_trless_request = USIZETAG_TYPEDEF(s_trless_request);
|
||||
tag_typedef_t ntatag_s_trless_to_tr = USIZETAG_TYPEDEF(s_trless_to_tr);
|
||||
tag_typedef_t ntatag_s_trless_response = USIZETAG_TYPEDEF(s_trless_response);
|
||||
tag_typedef_t ntatag_s_trless_200 = USIZETAG_TYPEDEF(s_trless_200);
|
||||
tag_typedef_t ntatag_s_merged_request = USIZETAG_TYPEDEF(s_merged_request);
|
||||
tag_typedef_t ntatag_s_sent_msg = USIZETAG_TYPEDEF(s_sent_msg);
|
||||
tag_typedef_t ntatag_s_sent_request = USIZETAG_TYPEDEF(s_sent_request);
|
||||
tag_typedef_t ntatag_s_sent_response = USIZETAG_TYPEDEF(s_sent_response);
|
||||
tag_typedef_t ntatag_s_retry_request = USIZETAG_TYPEDEF(s_retry_request);
|
||||
tag_typedef_t ntatag_s_retry_response = USIZETAG_TYPEDEF(s_retry_response);
|
||||
tag_typedef_t ntatag_s_recv_retry = USIZETAG_TYPEDEF(s_recv_retry);
|
||||
tag_typedef_t ntatag_s_tout_request = USIZETAG_TYPEDEF(s_tout_request);
|
||||
tag_typedef_t ntatag_s_tout_response = USIZETAG_TYPEDEF(s_tout_response);
|
||||
|
||||
/* Internal */
|
||||
tag_typedef_t ntatag_delay_sending = BOOLTAG_TYPEDEF(delay_sending);
|
||||
|
@ -1,4 +1,4 @@
|
||||
#! /bin/bash
|
||||
#! /bin/sh
|
||||
#
|
||||
# Run nta_test with our own name server
|
||||
#
|
||||
@ -50,11 +50,11 @@ export PATH
|
||||
|
||||
me6="::1"
|
||||
|
||||
if ../su/localinfo -6 -n -g -s >& /dev/null ; then
|
||||
if ../su/localinfo -6 -n -g -s > /dev/null 2>&1 ; then
|
||||
ipv6=true aaaa=aaaa v6flag=-6
|
||||
me6=$(../su/localinfo -6 -n -s -g | awk '{print $1; exit(0); }')
|
||||
else
|
||||
if ! ../su/localinfo '--help' >& /dev/null ; then
|
||||
if ! ../su/localinfo '--help' > /dev/null 2>&1 ; then
|
||||
echo "warning: $0: missing 'localinfo', cannot test IPv6"
|
||||
else
|
||||
echo "warning: $0: no valid IPv6 addresses available"
|
||||
@ -62,7 +62,7 @@ else
|
||||
ipv6=false aaaa=a
|
||||
fi
|
||||
|
||||
if type named >& /dev/null && ./portbind --help >& /dev/null
|
||||
if type named > /dev/null 2>&1 && ./portbind --help > /dev/null 2>&1
|
||||
then
|
||||
|
||||
port=$(./portbind $v6flag) sink=$port
|
||||
|
@ -299,6 +299,9 @@ int nta_incoming_complete_response(nta_incoming_t *irq,
|
||||
char const *phrase,
|
||||
tag_type_t tag, tag_value_t value, ...);
|
||||
|
||||
SOFIAPUBFUN
|
||||
msg_t *nta_incoming_create_response(nta_incoming_t *irq, int status, char const *phrase);
|
||||
|
||||
SOFIAPUBFUN
|
||||
int nta_incoming_treply(nta_incoming_t *ireq,
|
||||
int status, char const *phrase,
|
||||
|
@ -59,10 +59,10 @@ NTA_DLL extern tag_typedef_t ntatag_any;
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_mclass;
|
||||
/** Message class used by NTA. @HI */
|
||||
#define NTATAG_MCLASS(x) ntatag_mclass, tag_ptr_v((x))
|
||||
#define NTATAG_MCLASS(x) ntatag_mclass, tag_cptr_v((x))
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_mclass_ref;
|
||||
#define NTATAG_MCLASS_REF(x) ntatag_mclass_ref, tag_ptr_vr(&(x), (x))
|
||||
#define NTATAG_MCLASS_REF(x) ntatag_mclass_ref, tag_cptr_vr(&(x), (x))
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_bad_req_mask;
|
||||
/** Mask for bad request messages.
|
||||
@ -464,223 +464,223 @@ NTA_DLL extern tag_typedef_t ntatag_rseq_ref;
|
||||
/* Tags for statistics. */
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_irq_hash;
|
||||
#define NTATAG_S_IRQ_HASH(x) ntatag_s_irq_hash, tag_uint_v(x)
|
||||
#define NTATAG_S_IRQ_HASH(x) ntatag_s_irq_hash, tag_usize_v(x)
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_irq_hash_ref;
|
||||
#define NTATAG_S_IRQ_HASH_REF(x) ntatag_s_irq_hash_ref, tag_uint_vr(&(x))
|
||||
#define NTATAG_S_IRQ_HASH_REF(x) ntatag_s_irq_hash_ref, tag_usize_vr(&(x))
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_orq_hash;
|
||||
#define NTATAG_S_ORQ_HASH(x) ntatag_s_orq_hash, tag_uint_v(x)
|
||||
#define NTATAG_S_ORQ_HASH(x) ntatag_s_orq_hash, tag_usize_v(x)
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_orq_hash_ref;
|
||||
#define NTATAG_S_ORQ_HASH_REF(x) ntatag_s_orq_hash_ref, tag_uint_vr(&(x))
|
||||
#define NTATAG_S_ORQ_HASH_REF(x) ntatag_s_orq_hash_ref, tag_usize_vr(&(x))
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_leg_hash;
|
||||
#define NTATAG_S_LEG_HASH(x) ntatag_s_leg_hash, tag_uint_v(x)
|
||||
#define NTATAG_S_LEG_HASH(x) ntatag_s_leg_hash, tag_usize_v(x)
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_leg_hash_ref;
|
||||
#define NTATAG_S_LEG_HASH_REF(x) ntatag_s_leg_hash_ref, tag_uint_vr(&(x))
|
||||
#define NTATAG_S_LEG_HASH_REF(x) ntatag_s_leg_hash_ref, tag_usize_vr(&(x))
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_irq_hash_used;
|
||||
#define NTATAG_S_IRQ_HASH_USED(x) ntatag_s_irq_hash_used, tag_uint_v(x)
|
||||
#define NTATAG_S_IRQ_HASH_USED(x) ntatag_s_irq_hash_used, tag_usize_v(x)
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_irq_hash_used_ref;
|
||||
#define NTATAG_S_IRQ_HASH_USED_REF(x) \
|
||||
ntatag_s_irq_hash_used_ref, tag_uint_vr(&(x))
|
||||
ntatag_s_irq_hash_used_ref, tag_usize_vr(&(x))
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_orq_hash_used;
|
||||
#define NTATAG_S_ORQ_HASH_USED(x) ntatag_s_orq_hash_used, tag_uint_v(x)
|
||||
#define NTATAG_S_ORQ_HASH_USED(x) ntatag_s_orq_hash_used, tag_usize_v(x)
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_orq_hash_used_ref;
|
||||
#define NTATAG_S_ORQ_HASH_USED_REF(x) \
|
||||
ntatag_s_orq_hash_used_ref, tag_uint_vr(&(x))
|
||||
ntatag_s_orq_hash_used_ref, tag_usize_vr(&(x))
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_leg_hash_used;
|
||||
#define NTATAG_S_LEG_HASH_USED(x) ntatag_s_leg_hash_used, tag_uint_v(x)
|
||||
#define NTATAG_S_LEG_HASH_USED(x) ntatag_s_leg_hash_used, tag_usize_v(x)
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_leg_hash_used_ref;
|
||||
#define NTATAG_S_LEG_HASH_USED_REF(x) \
|
||||
ntatag_s_leg_hash_used_ref, tag_uint_vr(&(x))
|
||||
ntatag_s_leg_hash_used_ref, tag_usize_vr(&(x))
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_recv_msg;
|
||||
#define NTATAG_S_RECV_MSG(x) ntatag_s_recv_msg, tag_uint_v(x)
|
||||
#define NTATAG_S_RECV_MSG(x) ntatag_s_recv_msg, tag_usize_v(x)
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_recv_msg_ref;
|
||||
#define NTATAG_S_RECV_MSG_REF(x) ntatag_s_recv_msg_ref, tag_uint_vr(&(x))
|
||||
#define NTATAG_S_RECV_MSG_REF(x) ntatag_s_recv_msg_ref, tag_usize_vr(&(x))
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_recv_request;
|
||||
#define NTATAG_S_RECV_REQUEST(x) ntatag_s_recv_request, tag_uint_v(x)
|
||||
#define NTATAG_S_RECV_REQUEST(x) ntatag_s_recv_request, tag_usize_v(x)
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_recv_request_ref;
|
||||
#define NTATAG_S_RECV_REQUEST_REF(x)\
|
||||
ntatag_s_recv_request_ref, tag_uint_vr(&(x))
|
||||
ntatag_s_recv_request_ref, tag_usize_vr(&(x))
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_recv_response;
|
||||
#define NTATAG_S_RECV_RESPONSE(x) ntatag_s_recv_response, tag_uint_v(x)
|
||||
#define NTATAG_S_RECV_RESPONSE(x) ntatag_s_recv_response, tag_usize_v(x)
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_recv_response_ref;
|
||||
#define NTATAG_S_RECV_RESPONSE_REF(x)\
|
||||
ntatag_s_recv_response_ref, tag_uint_vr(&(x))
|
||||
ntatag_s_recv_response_ref, tag_usize_vr(&(x))
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_bad_message;
|
||||
#define NTATAG_S_BAD_MESSAGE(x) ntatag_s_bad_message, tag_uint_v(x)
|
||||
#define NTATAG_S_BAD_MESSAGE(x) ntatag_s_bad_message, tag_usize_v(x)
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_bad_message_ref;
|
||||
#define NTATAG_S_BAD_MESSAGE_REF(x)\
|
||||
ntatag_s_bad_message_ref, tag_uint_vr(&(x))
|
||||
ntatag_s_bad_message_ref, tag_usize_vr(&(x))
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_bad_request;
|
||||
#define NTATAG_S_BAD_REQUEST(x) ntatag_s_bad_request, tag_uint_v(x)
|
||||
#define NTATAG_S_BAD_REQUEST(x) ntatag_s_bad_request, tag_usize_v(x)
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_bad_request_ref;
|
||||
#define NTATAG_S_BAD_REQUEST_REF(x)\
|
||||
ntatag_s_bad_request_ref, tag_uint_vr(&(x))
|
||||
ntatag_s_bad_request_ref, tag_usize_vr(&(x))
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_bad_response;
|
||||
#define NTATAG_S_BAD_RESPONSE(x) ntatag_s_bad_response, tag_uint_v(x)
|
||||
#define NTATAG_S_BAD_RESPONSE(x) ntatag_s_bad_response, tag_usize_v(x)
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_bad_response_ref;
|
||||
#define NTATAG_S_BAD_RESPONSE_REF(x)\
|
||||
ntatag_s_bad_response_ref, tag_uint_vr(&(x))
|
||||
ntatag_s_bad_response_ref, tag_usize_vr(&(x))
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_drop_request;
|
||||
#define NTATAG_S_DROP_REQUEST(x) ntatag_s_drop_request, tag_uint_v(x)
|
||||
#define NTATAG_S_DROP_REQUEST(x) ntatag_s_drop_request, tag_usize_v(x)
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_drop_request_ref;
|
||||
#define NTATAG_S_DROP_REQUEST_REF(x)\
|
||||
ntatag_s_drop_request_ref, tag_uint_vr(&(x))
|
||||
ntatag_s_drop_request_ref, tag_usize_vr(&(x))
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_drop_response;
|
||||
#define NTATAG_S_DROP_RESPONSE(x) ntatag_s_drop_response, tag_uint_v(x)
|
||||
#define NTATAG_S_DROP_RESPONSE(x) ntatag_s_drop_response, tag_usize_v(x)
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_drop_response_ref;
|
||||
#define NTATAG_S_DROP_RESPONSE_REF(x)\
|
||||
ntatag_s_drop_response_ref, tag_uint_vr(&(x))
|
||||
ntatag_s_drop_response_ref, tag_usize_vr(&(x))
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_client_tr;
|
||||
#define NTATAG_S_CLIENT_TR(x) ntatag_s_client_tr, tag_uint_v(x)
|
||||
#define NTATAG_S_CLIENT_TR(x) ntatag_s_client_tr, tag_usize_v(x)
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_client_tr_ref;
|
||||
#define NTATAG_S_CLIENT_TR_REF(x)\
|
||||
ntatag_s_client_tr_ref, tag_uint_vr(&(x))
|
||||
ntatag_s_client_tr_ref, tag_usize_vr(&(x))
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_server_tr;
|
||||
#define NTATAG_S_SERVER_TR(x) ntatag_s_server_tr, tag_uint_v(x)
|
||||
#define NTATAG_S_SERVER_TR(x) ntatag_s_server_tr, tag_usize_v(x)
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_server_tr_ref;
|
||||
#define NTATAG_S_SERVER_TR_REF(x)\
|
||||
ntatag_s_server_tr_ref, tag_uint_vr(&(x))
|
||||
ntatag_s_server_tr_ref, tag_usize_vr(&(x))
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_dialog_tr;
|
||||
#define NTATAG_S_DIALOG_TR(x) ntatag_s_dialog_tr, tag_uint_v(x)
|
||||
#define NTATAG_S_DIALOG_TR(x) ntatag_s_dialog_tr, tag_usize_v(x)
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_dialog_tr_ref;
|
||||
#define NTATAG_S_DIALOG_TR_REF(x)\
|
||||
ntatag_s_dialog_tr_ref, tag_uint_vr(&(x))
|
||||
ntatag_s_dialog_tr_ref, tag_usize_vr(&(x))
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_acked_tr;
|
||||
#define NTATAG_S_ACKED_TR(x) ntatag_s_acked_tr, tag_uint_v(x)
|
||||
#define NTATAG_S_ACKED_TR(x) ntatag_s_acked_tr, tag_usize_v(x)
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_acked_tr_ref;
|
||||
#define NTATAG_S_ACKED_TR_REF(x) ntatag_s_acked_tr_ref, tag_uint_vr(&(x))
|
||||
#define NTATAG_S_ACKED_TR_REF(x) ntatag_s_acked_tr_ref, tag_usize_vr(&(x))
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_canceled_tr;
|
||||
#define NTATAG_S_CANCELED_TR(x) ntatag_s_canceled_tr, tag_uint_v(x)
|
||||
#define NTATAG_S_CANCELED_TR(x) ntatag_s_canceled_tr, tag_usize_v(x)
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_canceled_tr_ref;
|
||||
#define NTATAG_S_CANCELED_TR_REF(x) \
|
||||
ntatag_s_canceled_tr_ref, tag_uint_vr(&(x))
|
||||
ntatag_s_canceled_tr_ref, tag_usize_vr(&(x))
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_trless_request;
|
||||
#define NTATAG_S_TRLESS_REQUEST(x) ntatag_s_trless_request, tag_uint_v(x)
|
||||
#define NTATAG_S_TRLESS_REQUEST(x) ntatag_s_trless_request, tag_usize_v(x)
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_trless_request_ref;
|
||||
#define NTATAG_S_TRLESS_REQUEST_REF(x)\
|
||||
ntatag_s_trless_request_ref, tag_uint_vr(&(x))
|
||||
ntatag_s_trless_request_ref, tag_usize_vr(&(x))
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_trless_to_tr;
|
||||
#define NTATAG_S_TRLESS_TO_TR(x) ntatag_s_trless_to_tr, tag_uint_v(x)
|
||||
#define NTATAG_S_TRLESS_TO_TR(x) ntatag_s_trless_to_tr, tag_usize_v(x)
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_trless_to_tr_ref;
|
||||
#define NTATAG_S_TRLESS_TO_TR_REF(x)\
|
||||
ntatag_s_trless_to_tr_ref, tag_uint_vr(&(x))
|
||||
ntatag_s_trless_to_tr_ref, tag_usize_vr(&(x))
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_trless_response;
|
||||
#define NTATAG_S_TRLESS_RESPONSE(x) ntatag_s_trless_response, tag_uint_v(x)
|
||||
#define NTATAG_S_TRLESS_RESPONSE(x) ntatag_s_trless_response, tag_usize_v(x)
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_trless_response_ref;
|
||||
#define NTATAG_S_TRLESS_RESPONSE_REF(x)\
|
||||
ntatag_s_trless_response_ref, tag_uint_vr(&(x))
|
||||
ntatag_s_trless_response_ref, tag_usize_vr(&(x))
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_trless_200;
|
||||
#define NTATAG_S_TRLESS_200(x) ntatag_s_trless_200, tag_uint_v(x)
|
||||
#define NTATAG_S_TRLESS_200(x) ntatag_s_trless_200, tag_usize_v(x)
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_trless_200_ref;
|
||||
#define NTATAG_S_TRLESS_200_REF(x)\
|
||||
ntatag_s_trless_200_ref, tag_uint_vr(&(x))
|
||||
ntatag_s_trless_200_ref, tag_usize_vr(&(x))
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_merged_request;
|
||||
#define NTATAG_S_MERGED_REQUEST(x) ntatag_s_merged_request, tag_uint_v(x)
|
||||
#define NTATAG_S_MERGED_REQUEST(x) ntatag_s_merged_request, tag_usize_v(x)
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_merged_request_ref;
|
||||
#define NTATAG_S_MERGED_REQUEST_REF(x)\
|
||||
ntatag_s_merged_request_ref, tag_uint_vr(&(x))
|
||||
ntatag_s_merged_request_ref, tag_usize_vr(&(x))
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_sent_msg;
|
||||
#define NTATAG_S_SENT_MSG(x) ntatag_s_sent_msg, tag_uint_v(x)
|
||||
#define NTATAG_S_SENT_MSG(x) ntatag_s_sent_msg, tag_usize_v(x)
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_sent_msg_ref;
|
||||
#define NTATAG_S_SENT_MSG_REF(x)\
|
||||
ntatag_s_sent_msg_ref, tag_uint_vr(&(x))
|
||||
ntatag_s_sent_msg_ref, tag_usize_vr(&(x))
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_sent_request;
|
||||
#define NTATAG_S_SENT_REQUEST(x) ntatag_s_sent_request, tag_uint_v(x)
|
||||
#define NTATAG_S_SENT_REQUEST(x) ntatag_s_sent_request, tag_usize_v(x)
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_sent_request_ref;
|
||||
#define NTATAG_S_SENT_REQUEST_REF(x)\
|
||||
ntatag_s_sent_request_ref, tag_uint_vr(&(x))
|
||||
ntatag_s_sent_request_ref, tag_usize_vr(&(x))
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_sent_response;
|
||||
#define NTATAG_S_SENT_RESPONSE(x) ntatag_s_sent_response, tag_uint_v(x)
|
||||
#define NTATAG_S_SENT_RESPONSE(x) ntatag_s_sent_response, tag_usize_v(x)
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_sent_response_ref;
|
||||
#define NTATAG_S_SENT_RESPONSE_REF(x)\
|
||||
ntatag_s_sent_response_ref, tag_uint_vr(&(x))
|
||||
ntatag_s_sent_response_ref, tag_usize_vr(&(x))
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_retry_request;
|
||||
#define NTATAG_S_RETRY_REQUEST(x) ntatag_s_retry_request, tag_uint_v(x)
|
||||
#define NTATAG_S_RETRY_REQUEST(x) ntatag_s_retry_request, tag_usize_v(x)
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_retry_request_ref;
|
||||
#define NTATAG_S_RETRY_REQUEST_REF(x)\
|
||||
ntatag_s_retry_request_ref, tag_uint_vr(&(x))
|
||||
ntatag_s_retry_request_ref, tag_usize_vr(&(x))
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_retry_response;
|
||||
#define NTATAG_S_RETRY_RESPONSE(x) ntatag_s_retry_response, tag_uint_v(x)
|
||||
#define NTATAG_S_RETRY_RESPONSE(x) ntatag_s_retry_response, tag_usize_v(x)
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_retry_response_ref;
|
||||
#define NTATAG_S_RETRY_RESPONSE_REF(x)\
|
||||
ntatag_s_retry_response_ref, tag_uint_vr(&(x))
|
||||
ntatag_s_retry_response_ref, tag_usize_vr(&(x))
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_recv_retry;
|
||||
#define NTATAG_S_RECV_RETRY(x) ntatag_s_recv_retry, tag_uint_v(x)
|
||||
#define NTATAG_S_RECV_RETRY(x) ntatag_s_recv_retry, tag_usize_v(x)
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_recv_retry_ref;
|
||||
#define NTATAG_S_RECV_RETRY_REF(x)\
|
||||
ntatag_s_recv_retry_ref, tag_uint_vr(&(x))
|
||||
ntatag_s_recv_retry_ref, tag_usize_vr(&(x))
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_tout_request;
|
||||
#define NTATAG_S_TOUT_REQUEST(x) ntatag_s_tout_request, tag_uint_v(x)
|
||||
#define NTATAG_S_TOUT_REQUEST(x) ntatag_s_tout_request, tag_usize_v(x)
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_tout_request_ref;
|
||||
#define NTATAG_S_TOUT_REQUEST_REF(x)\
|
||||
ntatag_s_tout_request_ref, tag_uint_vr(&(x))
|
||||
ntatag_s_tout_request_ref, tag_usize_vr(&(x))
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_tout_response;
|
||||
#define NTATAG_S_TOUT_RESPONSE(x) ntatag_s_tout_response, tag_uint_v(x)
|
||||
#define NTATAG_S_TOUT_RESPONSE(x) ntatag_s_tout_response, tag_usize_v(x)
|
||||
|
||||
NTA_DLL extern tag_typedef_t ntatag_s_tout_response_ref;
|
||||
#define NTATAG_S_TOUT_RESPONSE_REF(x)\
|
||||
ntatag_s_tout_response_ref, tag_uint_vr(&(x))
|
||||
ntatag_s_tout_response_ref, tag_usize_vr(&(x))
|
||||
|
||||
SOFIA_END_DECLS
|
||||
|
||||
|
@ -654,7 +654,7 @@ int readfile(FILE *f, void **contents)
|
||||
|
||||
*contents = buffer;
|
||||
|
||||
return len;
|
||||
return (int)len;
|
||||
}
|
||||
|
||||
#if HAVE_DIRENT_H
|
||||
@ -663,6 +663,8 @@ int readfile(FILE *f, void **contents)
|
||||
|
||||
static int test_bad_messages(agent_t *ag)
|
||||
{
|
||||
BEGIN();
|
||||
|
||||
#if HAVE_DIRENT_H
|
||||
DIR *dir;
|
||||
struct dirent *d;
|
||||
@ -687,13 +689,10 @@ static int test_bad_messages(agent_t *ag)
|
||||
if (dir == NULL) {
|
||||
fprintf(stderr, "test_nta: cannot find sip torture messages\n");
|
||||
fprintf(stderr, "test_nta: tried %s\n", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
offset = strlen(name);
|
||||
|
||||
BEGIN();
|
||||
|
||||
TEST_1(ag->ag_default_leg = nta_leg_tcreate(ag->ag_agent,
|
||||
leg_callback_500,
|
||||
ag,
|
||||
@ -713,14 +712,14 @@ static int test_bad_messages(agent_t *ag)
|
||||
|
||||
TEST(su_getaddrinfo(host, port, hints, &ai), 0); TEST_1(ai);
|
||||
s = su_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); TEST_1(s != -1);
|
||||
memset(su, 0, sulen = sizeof su);
|
||||
memset(su, 0, sulen = ai->ai_addrlen);
|
||||
su->su_len = sizeof su; su->su_family = ai->ai_family;
|
||||
TEST_1(bind(s, &su->su_sa, sulen) == 0);
|
||||
TEST_1(getsockname(s, &su->su_sa, &sulen) == 0);
|
||||
sprintf(via, "v: SIP/2.0/UDP is.invalid:%u\r\n", ntohs(su->su_port));
|
||||
vlen = strlen(via);
|
||||
|
||||
for (d = readdir(dir); d; d = readdir(dir)) {
|
||||
for (d = dir ? readdir(dir) : NULL; d; d = readdir(dir)) {
|
||||
size_t len = strlen(d->d_name);
|
||||
FILE *f;
|
||||
int blen, n;
|
||||
@ -733,6 +732,7 @@ static int test_bad_messages(agent_t *ag)
|
||||
strncpy(name + offset, d->d_name, PATH_MAX - offset);
|
||||
TEST_1(f = fopen(name, "rb"));
|
||||
TEST_1((blen = readfile(f, &buffer)) > 0);
|
||||
fclose(f);
|
||||
r = buffer;
|
||||
|
||||
if (strncmp(r, "JUNK ", 5) == 0) {
|
||||
@ -751,6 +751,12 @@ static int test_bad_messages(agent_t *ag)
|
||||
su_root_step(ag->ag_root, 1);
|
||||
}
|
||||
|
||||
TEST_SIZE(su_sendto(s, "\r\n\r\n", 4, 0, (void *)ai->ai_addr, ai->ai_addrlen), 4);
|
||||
|
||||
su_root_step(ag->ag_root, 1);
|
||||
|
||||
TEST_SIZE(su_sendto(s, "", 0, 0, ai->ai_addr, ai->ai_addrlen), 0);
|
||||
|
||||
su_close(s);
|
||||
|
||||
for (i = 0; i < 20; i++)
|
||||
@ -758,12 +764,12 @@ static int test_bad_messages(agent_t *ag)
|
||||
|
||||
nta_leg_destroy(ag->ag_default_leg), ag->ag_default_leg = NULL;
|
||||
|
||||
closedir(dir);
|
||||
if (dir)
|
||||
closedir(dir);
|
||||
|
||||
#endif /* HAVE_DIRENT_H */
|
||||
|
||||
END();
|
||||
#else
|
||||
return 0;
|
||||
#endif /* HAVE_DIRENT_H */
|
||||
}
|
||||
|
||||
static unsigned char const code[] =
|
||||
@ -3357,6 +3363,7 @@ char const nta_test_usage[] =
|
||||
"usage: %s OPTIONS\n"
|
||||
"where OPTIONS are\n"
|
||||
" -v | --verbose be verbose\n"
|
||||
" -a | --abort abort() on error\n"
|
||||
" -q | --quiet be quiet\n"
|
||||
" -1 quit on first error\n"
|
||||
" -l level set logging level (0 by default)\n"
|
||||
@ -3368,10 +3375,10 @@ char const nta_test_usage[] =
|
||||
#endif
|
||||
;
|
||||
|
||||
void usage(void)
|
||||
void usage(int exitcode)
|
||||
{
|
||||
fprintf(stderr, nta_test_usage, name);
|
||||
exit(1);
|
||||
exit(exitcode);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
@ -3384,6 +3391,8 @@ int main(int argc, char *argv[])
|
||||
for (i = 1; argv[i]; i++) {
|
||||
if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0)
|
||||
tstflags |= tst_verbatim;
|
||||
else if (strcmp(argv[i], "-a") == 0 || strcmp(argv[i], "--abort") == 0)
|
||||
tstflags |= tst_abort;
|
||||
else if (strcmp(argv[i], "-q") == 0 || strcmp(argv[i], "--quiet") == 0)
|
||||
tstflags &= ~tst_verbatim;
|
||||
else if (strcmp(argv[i], "-1") == 0)
|
||||
@ -3400,7 +3409,7 @@ int main(int argc, char *argv[])
|
||||
level = 3, rest = "";
|
||||
|
||||
if (rest == NULL || *rest)
|
||||
usage();
|
||||
usage(1);
|
||||
|
||||
su_log_set_level(nta_log, level);
|
||||
su_log_set_level(tport_log, level);
|
||||
@ -3411,7 +3420,7 @@ int main(int argc, char *argv[])
|
||||
else if (argv[i + 1])
|
||||
ag->ag_obp = (url_string_t *)(argv[++i]);
|
||||
else
|
||||
usage();
|
||||
usage(1);
|
||||
}
|
||||
else if (strncmp(argv[i], "-m", 2) == 0) {
|
||||
if (argv[i][2])
|
||||
@ -3419,7 +3428,7 @@ int main(int argc, char *argv[])
|
||||
else if (argv[i + 1])
|
||||
ag->ag_m = argv[++i];
|
||||
else
|
||||
usage();
|
||||
usage(1);
|
||||
}
|
||||
else if (strcmp(argv[i], "--attach") == 0) {
|
||||
o_attach = 1;
|
||||
@ -3434,7 +3443,7 @@ int main(int argc, char *argv[])
|
||||
break;
|
||||
}
|
||||
else
|
||||
usage();
|
||||
usage(1);
|
||||
}
|
||||
|
||||
if (o_attach) {
|
||||
|
@ -559,18 +559,18 @@ int api_test_stats(agent_t *ag)
|
||||
|
||||
nta_agent_t *nta;
|
||||
|
||||
uint32_t irq_hash = -1, orq_hash = -1, leg_hash = -1;
|
||||
uint32_t recv_msg = -1, sent_msg = -1;
|
||||
uint32_t recv_request = -1, recv_response = -1;
|
||||
uint32_t bad_message = -1, bad_request = -1, bad_response = -1;
|
||||
uint32_t drop_request = -1, drop_response = -1;
|
||||
uint32_t client_tr = -1, server_tr = -1, dialog_tr = -1;
|
||||
uint32_t acked_tr = -1, canceled_tr = -1;
|
||||
uint32_t trless_request = -1, trless_to_tr = -1, trless_response = -1;
|
||||
uint32_t trless_200 = -1, merged_request = -1;
|
||||
uint32_t sent_request = -1, sent_response = -1;
|
||||
uint32_t retry_request = -1, retry_response = -1, recv_retry = -1;
|
||||
uint32_t tout_request = -1, tout_response = -1;
|
||||
usize_t irq_hash = -1, orq_hash = -1, leg_hash = -1;
|
||||
usize_t recv_msg = -1, sent_msg = -1;
|
||||
usize_t recv_request = -1, recv_response = -1;
|
||||
usize_t bad_message = -1, bad_request = -1, bad_response = -1;
|
||||
usize_t drop_request = -1, drop_response = -1;
|
||||
usize_t client_tr = -1, server_tr = -1, dialog_tr = -1;
|
||||
usize_t acked_tr = -1, canceled_tr = -1;
|
||||
usize_t trless_request = -1, trless_to_tr = -1, trless_response = -1;
|
||||
usize_t trless_200 = -1, merged_request = -1;
|
||||
usize_t sent_request = -1, sent_response = -1;
|
||||
usize_t retry_request = -1, retry_response = -1, recv_retry = -1;
|
||||
usize_t tout_request = -1, tout_response = -1;
|
||||
|
||||
TEST_1(nta = nta_agent_create(ag->ag_root, (url_string_t *)"sip:*:*",
|
||||
NULL, NULL, TAG_END()));
|
||||
@ -1238,6 +1238,7 @@ char const nta_test_api_usage[] =
|
||||
"usage: %s OPTIONS\n"
|
||||
"where OPTIONS are\n"
|
||||
" -v | --verbose be verbose\n"
|
||||
" -a | --abort abort() on error\n"
|
||||
" -q | --quiet be quiet\n"
|
||||
" -1 quit on first error\n"
|
||||
" -l level set logging level (0 by default)\n"
|
||||
@ -1247,10 +1248,10 @@ char const nta_test_api_usage[] =
|
||||
#endif
|
||||
;
|
||||
|
||||
void usage(void)
|
||||
void usage(int exitcode)
|
||||
{
|
||||
fprintf(stderr, nta_test_api_usage, name);
|
||||
exit(1);
|
||||
exit(exitcode);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
@ -1261,9 +1262,11 @@ int main(int argc, char *argv[])
|
||||
agent_t ag[1] = {{ { SU_HOME_INIT(ag) }, 0, NULL }};
|
||||
|
||||
for (i = 1; argv[i]; i++) {
|
||||
if (strcmp(argv[i], "-v") == 0)
|
||||
if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0)
|
||||
tstflags |= tst_verbatim;
|
||||
else if (strcmp(argv[i], "-q") == 0)
|
||||
else if (strcmp(argv[i], "-a") == 0 || strcmp(argv[i], "--abort") == 0)
|
||||
tstflags |= tst_abort;
|
||||
else if (strcmp(argv[i], "-q") == 0 || strcmp(argv[i], "--quiet") == 0)
|
||||
tstflags &= ~tst_verbatim;
|
||||
else if (strcmp(argv[i], "-1") == 0)
|
||||
quit_on_single_failure = 1;
|
||||
@ -1279,7 +1282,7 @@ int main(int argc, char *argv[])
|
||||
level = 3, rest = "";
|
||||
|
||||
if (rest == NULL || *rest)
|
||||
usage();
|
||||
usage(1);
|
||||
|
||||
su_log_set_level(nta_log, level);
|
||||
su_log_set_level(tport_log, level);
|
||||
@ -1297,14 +1300,14 @@ int main(int argc, char *argv[])
|
||||
break;
|
||||
}
|
||||
else
|
||||
usage();
|
||||
usage(1);
|
||||
}
|
||||
|
||||
if (o_attach) {
|
||||
char line[10];
|
||||
char *response, line[10];
|
||||
printf("nua_test: pid %lu\n", (unsigned long)getpid());
|
||||
printf("<Press RETURN to continue>\n");
|
||||
fgets(line, sizeof line, stdin);
|
||||
response = fgets(line, sizeof line, stdin);
|
||||
}
|
||||
#if HAVE_ALARM
|
||||
else if (o_alarm) {
|
||||
|
@ -63,4 +63,4 @@ EXTRA_DIST = Doxyfile nth.docs $(BUILT_SOURCES) \
|
||||
# ----------------------------------------------------------------------
|
||||
# Sofia specific rules
|
||||
|
||||
include ../sofia.am
|
||||
include $(top_srcdir)/rules/sofia.am
|
||||
|
@ -38,7 +38,10 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#if HAVE_SIGNAL
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
typedef struct context_s context_t;
|
||||
#define NTH_SITE_MAGIC_T context_t
|
||||
@ -77,7 +80,10 @@ static int request(context_t *context,
|
||||
http_t const *http,
|
||||
char const *path);
|
||||
su_msg_r server_intr_msg = SU_MSG_R_INIT;
|
||||
|
||||
#if HAVE_SIGNAL
|
||||
static RETSIGTYPE server_intr_handler(int signum);
|
||||
#endif
|
||||
static void server_break(context_t *c, su_msg_r msg, su_msg_arg_t *arg);
|
||||
|
||||
static msg_payload_t *read_payload(su_home_t *home, char const *fname);
|
||||
@ -140,12 +146,12 @@ int main(int argc, char *argv[])
|
||||
su_root_task(context->c_root),
|
||||
server_break, 0);
|
||||
|
||||
#if HAVE_SIGNAL
|
||||
signal(SIGINT, server_intr_handler);
|
||||
|
||||
#ifndef _WIN32
|
||||
signal(SIGPIPE, server_intr_handler);
|
||||
#if HAVE_SIGQUIT
|
||||
signal(SIGQUIT, server_intr_handler);
|
||||
signal(SIGHUP, server_intr_handler);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (context->c_root) {
|
||||
|
@ -1094,7 +1094,7 @@ int hc_reply(nth_client_t * hc, int status, char const *phrase)
|
||||
|
||||
assert(status >= 400);
|
||||
|
||||
SU_DEBUG_5(("nth: hc_reply(%p, %u, %s)\n", hc, status, phrase));
|
||||
SU_DEBUG_5(("nth: hc_reply(%p, %u, %s)\n", (void *)hc, status, phrase));
|
||||
|
||||
if (hc->hc_pending) {
|
||||
tport_release(hc->hc_tport, hc->hc_pending, hc->hc_request, NULL, hc,
|
||||
|
@ -704,7 +704,7 @@ server_t *server_create(url_t const *url,
|
||||
tag_type_t tag, tag_value_t value, ...)
|
||||
{
|
||||
server_t *srv;
|
||||
msg_mclass_t *mclass = NULL;
|
||||
msg_mclass_t const *mclass = NULL;
|
||||
tp_name_t tpn[1] = {{ NULL }};
|
||||
su_root_t *root = NULL;
|
||||
http_server_t const *server = NULL;
|
||||
|
@ -109,7 +109,7 @@ su_inline tag_value_t nthtag_template_vr(struct nth_client_s const **vp)
|
||||
{return(tag_value_t)vp;}
|
||||
#else
|
||||
#define nthtag_template_v(v) ((tag_value_t)(v))
|
||||
#define nthtag_template_vr(vp) ((tag_value_t)&(vp))
|
||||
#define nthtag_template_vr(vp) ((tag_value_t)(vp))
|
||||
#endif
|
||||
|
||||
NTH_DLL extern tag_typedef_t nthtag_template;
|
||||
@ -126,7 +126,7 @@ su_inline tag_value_t nthtag_message_vr(struct msg_s **vp)
|
||||
{ return(tag_value_t)vp; }
|
||||
#else
|
||||
#define nthtag_message_v(v) ((tag_value_t)(v))
|
||||
#define nthtag_message_vr(vp) ((tag_value_t)&(vp))
|
||||
#define nthtag_message_vr(vp) ((tag_value_t)(vp))
|
||||
#endif
|
||||
|
||||
NTH_DLL extern tag_typedef_t nthtag_message;
|
||||
@ -142,7 +142,7 @@ su_inline tag_value_t nthtag_authentication_v(struct auth_client_s **v) { return
|
||||
su_inline tag_value_t nthtag_authentication_vr(struct auth_client_s ***vp) {return(tag_value_t)vp;}
|
||||
#else
|
||||
#define nthtag_authentication_v(v) ((tag_value_t)(v))
|
||||
#define nthtag_authentication_vr(vp) ((tag_value_t)&(vp))
|
||||
#define nthtag_authentication_vr(vp) ((tag_value_t)(vp))
|
||||
#endif
|
||||
|
||||
NTH_DLL extern tag_typedef_t nthtag_authentication;
|
||||
|
@ -893,10 +893,10 @@ static RETSIGTYPE sig_alarm(int s)
|
||||
}
|
||||
#endif
|
||||
|
||||
void usage(void)
|
||||
void usage(int exitcode)
|
||||
{
|
||||
fprintf(stderr, "usage: %s [-v|-q] [-p proxy-uri]\n", name);
|
||||
exit(1);
|
||||
fprintf(stderr, "usage: %s [-v|-q] [-a] [-p proxy-uri]\n", name);
|
||||
exit(exitcode);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
@ -915,6 +915,8 @@ int main(int argc, char **argv)
|
||||
for (i = 1; argv[i]; i++) {
|
||||
if (strcmp(argv[i], "-v") == 0)
|
||||
tstflags |= tst_verbatim;
|
||||
else if (strcmp(argv[i], "-a") == 0)
|
||||
tstflags |= tst_abort;
|
||||
else if (strcmp(argv[i], "-q") == 0)
|
||||
tstflags &= ~tst_verbatim;
|
||||
else if (strcmp(argv[i], "-p") == 0 && argv[i + 1])
|
||||
@ -931,7 +933,7 @@ int main(int argc, char **argv)
|
||||
break;
|
||||
}
|
||||
else
|
||||
usage();
|
||||
usage(1);
|
||||
}
|
||||
|
||||
t->t_srcdir = srcdir;
|
||||
|
@ -30,6 +30,9 @@ ALIASES += nua="@ref index \"nua\""
|
||||
ALIASES += NUA_EVENT="@var nua_event_e::"
|
||||
ALIASES += END_NUA_EVENT="@par "
|
||||
|
||||
ALIASES += \
|
||||
NUA_HPARAM_CALLS="nua_invite(), nua_respond(), nua_ack(), nua_prack(), nua_update(), nua_info(), nua_bye(), nua_options(), nua_message(), nua_register(), nua_publish(), nua_refer(),nua_subscribe(), nua_notify(), nua_refer(), nua_notifier()"
|
||||
|
||||
VERBATIM_HEADERS = NO
|
||||
|
||||
@INCLUDE = ../sip/sip.doxyaliases
|
||||
|
@ -80,6 +80,7 @@ test_nua_SOURCES = test_nua.c test_nua.h test_ops.c \
|
||||
test_init.c \
|
||||
test_nua_api.c test_nua_params.c \
|
||||
test_register.c test_basic_call.c \
|
||||
test_offer_answer.c \
|
||||
test_call_reject.c test_cancel_bye.c \
|
||||
test_call_hold.c test_session_timer.c \
|
||||
test_refer.c test_100rel.c \
|
||||
@ -96,6 +97,6 @@ EXTRA_DIST = Doxyfile nua.docs $(BUILT_SOURCES)
|
||||
# ----------------------------------------------------------------------
|
||||
# Sofia specific rules
|
||||
|
||||
include ../sofia.am
|
||||
include $(top_srcdir)/rules/sofia.am
|
||||
|
||||
TAG_DLL_FLAGS = LIST=nua_tag_list
|
||||
|
@ -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;
|
||||
|
||||
|
@ -1124,7 +1124,7 @@ follows:
|
||||
<td>terminating</td>
|
||||
<td>Process answer</td>
|
||||
<td>
|
||||
If there was an failure in SDP negotiation or other failure with media,
|
||||
If there was a failure in SDP negotiation or other failure with media,
|
||||
the stack will automatically terminate the call. The BYE follows
|
||||
immediatelhy after the ACK.
|
||||
</td></tr>
|
||||
@ -1262,7 +1262,7 @@ does not include the extensions like @b 100rel or @b UPDATE.
|
||||
| +---------------| | : | :
|
||||
| | +------------+ : | :
|
||||
| | | : | :
|
||||
| | nua_respond/18X (2) : | :
|
||||
| | nua_respond/18X (2a) : | :
|
||||
| | | : | :
|
||||
| | V V | :
|
||||
| | +------------+ | :
|
||||
@ -2029,7 +2029,8 @@ NUTAG_AUTOANSWER(0) on B side, NUTAG_AUTOACK(0) on A side.
|
||||
* Always present
|
||||
* @param nh Pointer to operation handle.
|
||||
* @param hmagic Pointer to callback context from nua_handle().
|
||||
* @param sip Parsed incoming message. May be NULL.
|
||||
* @param sip Headers in parsed incoming message. May be NULL.
|
||||
* See also nua_current_request().
|
||||
* @param tags Tag list containing more information about the state of NUA.
|
||||
* May be empty.
|
||||
*
|
||||
@ -2038,17 +2039,22 @@ NUTAG_AUTOANSWER(0) on B side, NUTAG_AUTOACK(0) on A side.
|
||||
* individual event.
|
||||
*
|
||||
* The events can be divided into the following categories: \n
|
||||
* @par Indications:
|
||||
* @par Status or Error Indications:
|
||||
* #nua_i_active \n
|
||||
* #nua_i_error \n
|
||||
* #nua_i_fork \n
|
||||
* #nua_i_media_error \n
|
||||
* #nua_i_subscription \n
|
||||
* #nua_i_state \n
|
||||
* #nua_i_terminated
|
||||
*
|
||||
* @par SIP requests:
|
||||
* #nua_i_ack \n
|
||||
* #nua_i_bye \n
|
||||
* #nua_i_cancel \n
|
||||
* #nua_i_chat \n
|
||||
* #nua_i_error \n
|
||||
* #nua_i_fork \n
|
||||
* #nua_i_info \n
|
||||
* #nua_i_invite \n
|
||||
* #nua_i_media_error \n
|
||||
* #nua_i_message \n
|
||||
* #nua_i_method \n
|
||||
* #nua_i_notify \n
|
||||
@ -2058,9 +2064,6 @@ NUTAG_AUTOANSWER(0) on B side, NUTAG_AUTOACK(0) on A side.
|
||||
* #nua_i_refer \n
|
||||
* #nua_i_register \n
|
||||
* #nua_i_subscribe \n
|
||||
* #nua_i_subscription \n
|
||||
* #nua_i_state \n
|
||||
* #nua_i_terminated \n
|
||||
* #nua_i_update
|
||||
*
|
||||
* @par Responses:
|
||||
@ -2122,7 +2125,8 @@ NUTAG_AUTOANSWER(0) on B side, NUTAG_AUTOACK(0) on A side.
|
||||
*
|
||||
* Outgoing call has been forked.
|
||||
*
|
||||
* This is sent when an INVITE request is answered with multiple 200 responses.
|
||||
* This is sent when an INVITE request is answered with multiple 2XX series
|
||||
* responses.
|
||||
*
|
||||
* @param status response status code
|
||||
* @param phrase a short textual description of @a status code
|
||||
@ -2219,7 +2223,7 @@ NUTAG_AUTOANSWER(0) on B side, NUTAG_AUTOACK(0) on A side.
|
||||
* @param nh operation handle associated with the notifier
|
||||
* @param hmagic operation magic associated with the notifier
|
||||
* @param sip response to MESSAGE request or NULL upon an error
|
||||
* (error code and message are in status an phrase parameters)
|
||||
* (error code and message are in status and phrase parameters)
|
||||
* @param tags empty
|
||||
*
|
||||
* @sa nua_chat(), #nua_r_message
|
||||
|
@ -110,13 +110,14 @@ nua_handle_t *nh_create_handle(nua_t *nua,
|
||||
assert(nua->nua_home);
|
||||
|
||||
if ((nh = su_home_clone(nua->nua_home, sizeof(*nh)))) {
|
||||
nh->nh_valid = nua_handle;
|
||||
nh->nh_valid = nua_valid_handle_cookie;
|
||||
nh->nh_nua = nua;
|
||||
nh->nh_magic = hmagic;
|
||||
nh->nh_prefs = nua->nua_dhandle->nh_prefs;
|
||||
|
||||
if (nua_handle_save_tags(nh, tags) < 0) {
|
||||
SU_DEBUG_5(("nua(%p): creating handle %p failed\n", nua, nh));
|
||||
SU_DEBUG_5(("nua(%p): creating handle %p failed\n",
|
||||
(void *)nua, (void *)nh));
|
||||
su_home_unref(nh->nh_home), nh = NULL;
|
||||
}
|
||||
|
||||
@ -136,7 +137,7 @@ nua_handle_t *nh_create_handle(nua_t *nua,
|
||||
}
|
||||
else {
|
||||
_handle_lifetime = 2;
|
||||
SU_DEBUG_0(("nh_handle_create(%p)\n", nh));
|
||||
SU_DEBUG_0(("nh_handle_create(%p)\n", (void *)nh));
|
||||
su_home_destructor(nh->nh_home, nh_destructor);
|
||||
}
|
||||
}
|
||||
@ -159,10 +160,12 @@ extern char const _NUA_HANDLE_DEBUG[];
|
||||
static void nh_destructor(void *arg)
|
||||
{
|
||||
nua_handle_t *nh = arg;
|
||||
|
||||
SU_DEBUG_0(("nh_destructor(%p)\n", nh));
|
||||
SU_DEBUG_0(("nh_destructor(%p)\n", (void *)nh));
|
||||
}
|
||||
|
||||
#undef nua_handle_ref
|
||||
#undef nua_handle_unref
|
||||
|
||||
/** Make a new reference to handle.
|
||||
*
|
||||
* The handles use reference counting for memory management. In addition to
|
||||
@ -180,7 +183,6 @@ nua_handle_t *nua_handle_ref(nua_handle_t *nh)
|
||||
return (nua_handle_t *)su_home_ref(nh->nh_home);
|
||||
}
|
||||
|
||||
|
||||
/** Destroy reference to handle.
|
||||
*
|
||||
* The handles use reference counting for memory management. In addition to
|
||||
@ -214,6 +216,50 @@ char const *nua_generate_instance_identifier(su_home_t *home)
|
||||
return su_strdup(home, str);
|
||||
}
|
||||
|
||||
/** Check if event is a request that can be responded with nua_respond().
|
||||
*
|
||||
* Note that if event status is 200 or greater, it already has been
|
||||
* responded. This function is provided for compatibility with future
|
||||
* versions of nua. An unknown event can always be handled in the event
|
||||
* callback like this:
|
||||
* @code
|
||||
* switch (event) {
|
||||
* ...
|
||||
* default:
|
||||
* if (status < 200 && nua_event_is_incoming_request(event))
|
||||
* nua_respond(nh, SIP_501_NOT_IMPLEMENTED,
|
||||
* NUTAG_WITH_THIS(nua), TAG_END());
|
||||
* if (hmagic == NULL)
|
||||
* nua_handle_destroy(nh);
|
||||
* return;
|
||||
* ...
|
||||
* @endcode
|
||||
*
|
||||
* @sa #nua_event_t, nua_respond()
|
||||
*
|
||||
* @NEW_1_12_6
|
||||
*/
|
||||
int nua_event_is_incoming_request(nua_event_t event)
|
||||
{
|
||||
switch (event) {
|
||||
case nua_i_invite: return 1;
|
||||
case nua_i_cancel: return 1;
|
||||
case nua_i_register: return 1;
|
||||
case nua_i_bye: return 1;
|
||||
case nua_i_options: return 1;
|
||||
case nua_i_refer: return 1;
|
||||
case nua_i_publish: return 1;
|
||||
case nua_i_prack: return 1;
|
||||
case nua_i_info: return 1;
|
||||
case nua_i_update: return 1;
|
||||
case nua_i_message: return 1;
|
||||
case nua_i_subscribe: return 1;
|
||||
case nua_i_notify: return 1;
|
||||
case nua_i_method: return 1;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** Get name for a NUA event. */
|
||||
char const *nua_event_name(nua_event_t event)
|
||||
{
|
||||
@ -301,3 +347,34 @@ char const *nua_callstate_name(enum nua_callstate state)
|
||||
default: return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
/** Return name of subscription state. @NEW_1_12_5. */
|
||||
char const *nua_substate_name(enum nua_substate substate)
|
||||
{
|
||||
switch (substate) {
|
||||
case nua_substate_embryonic:
|
||||
/*FALLTHROUGH*/
|
||||
case nua_substate_pending:
|
||||
return "pending";
|
||||
case nua_substate_terminated:
|
||||
return "terminated";
|
||||
case nua_substate_active:
|
||||
/*FALLTHROUGH*/
|
||||
default:
|
||||
return "active";
|
||||
}
|
||||
}
|
||||
|
||||
/** Convert string to enum nua_substate. @NEW_1_12_5. */
|
||||
enum nua_substate nua_substate_make(char const *sip_substate)
|
||||
{
|
||||
if (sip_substate == NULL)
|
||||
return nua_substate_active;
|
||||
else if (strcasecmp(sip_substate, "terminated") == 0)
|
||||
return nua_substate_terminated;
|
||||
else if (strcasecmp(sip_substate, "pending") == 0)
|
||||
return nua_substate_pending;
|
||||
else /* if (strcasecmp(sip_substate, "active") == 0) */
|
||||
return nua_substate_active;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -48,49 +48,93 @@ typedef NUA_OWNER_T nua_owner_t;
|
||||
#include <sofia-sip/nta.h>
|
||||
#endif
|
||||
|
||||
typedef su_msg_r nua_saved_signal_t;
|
||||
|
||||
typedef struct nua_server_request nua_server_request_t;
|
||||
typedef struct nua_client_request nua_client_request_t;
|
||||
|
||||
/** Respond to an incoming request. */
|
||||
typedef int nua_server_respond_f(nua_server_request_t *, tagi_t const *);
|
||||
typedef struct {
|
||||
sip_method_t sm_method;
|
||||
char const *sm_method_name;
|
||||
|
||||
/** Restart an outgoing request. */
|
||||
typedef void nua_creq_restart_f(nua_owner_t *, tagi_t *tags);
|
||||
int sm_event;
|
||||
|
||||
struct {
|
||||
unsigned create_dialog:1, in_dialog:1, target_refresh:1, add_contact:1;
|
||||
unsigned :0;
|
||||
} sm_flags;
|
||||
|
||||
/** Initialize server-side request. */
|
||||
int (*sm_init)(nua_server_request_t *sr);
|
||||
|
||||
/** Preprocess server-side request (after handle has been created). */
|
||||
int (*sm_preprocess)(nua_server_request_t *sr);
|
||||
|
||||
/** Update server-side request parameters */
|
||||
int (*sm_params)(nua_server_request_t *sr, tagi_t const *tags);
|
||||
|
||||
/** Respond to server-side request. */
|
||||
int (*sm_respond)(nua_server_request_t *sr, tagi_t const *tags);
|
||||
|
||||
/** Report server-side request to application. */
|
||||
int (*sm_report)(nua_server_request_t *sr, tagi_t const *tags);
|
||||
|
||||
} nua_server_methods_t;
|
||||
|
||||
/** Server side transaction */
|
||||
struct nua_server_request {
|
||||
struct nua_server_request *sr_next, **sr_prev;
|
||||
|
||||
nua_server_methods_t const *sr_methods;
|
||||
|
||||
nua_owner_t *sr_owner; /**< Backpointer to handle */
|
||||
nua_dialog_usage_t *sr_usage; /**< Backpointer to usage */
|
||||
|
||||
/** When the application responds to an request with
|
||||
* nua_respond(), the sr_respond() is called
|
||||
*/
|
||||
nua_server_respond_f *sr_respond;
|
||||
|
||||
nta_incoming_t *sr_irq; /**< Server transaction object */
|
||||
msg_t *sr_msg; /**< Request message */
|
||||
|
||||
struct {
|
||||
msg_t *msg; /**< Request message */
|
||||
sip_t const *sip; /**< Headers in request message */
|
||||
} sr_request;
|
||||
|
||||
struct {
|
||||
msg_t *msg; /**< Response message */
|
||||
sip_t *sip; /**< Headers in response message */
|
||||
} sr_response;
|
||||
|
||||
sip_method_t sr_method; /**< Request method */
|
||||
|
||||
int sr_application; /**< Status by application */
|
||||
|
||||
int sr_status; /**< Status code */
|
||||
char const *sr_phrase; /**< Status phrase */
|
||||
|
||||
unsigned sr_auto:1; /**< Autoresponse - no event has been sent */
|
||||
unsigned sr_event:1; /**< Reported to application */
|
||||
unsigned sr_initial:1; /**< Handle was created by this request */
|
||||
unsigned sr_add_contact:1; /**< Add Contact header to the response */
|
||||
unsigned sr_target_refresh:1; /**< Refresh target */
|
||||
unsigned sr_terminating:1; /**< Terminate usage after final response */
|
||||
unsigned sr_gracefully:1; /**< Terminate usage gracefully */
|
||||
|
||||
unsigned sr_neutral:1; /**< No effect on session or other usage */
|
||||
|
||||
/* Flags used with 100rel */
|
||||
unsigned sr_100rel:1, sr_pracked:1;
|
||||
|
||||
/* Flags used with offer-answer */
|
||||
unsigned sr_offer_recv:1; /**< We have received an offer */
|
||||
unsigned sr_answer_sent:2; /**< We have answered (reliably, if >1) */
|
||||
|
||||
unsigned sr_offer_sent:1; /**< We have offered SDP */
|
||||
unsigned sr_offer_sent:2; /**< We have offered SDP (reliably, if >1) */
|
||||
unsigned sr_answer_recv:1; /**< We have received SDP answer */
|
||||
};
|
||||
unsigned :0;
|
||||
|
||||
#define SR_INIT(sr) \
|
||||
((void)memset((sr), 0, sizeof (sr)[0]), \
|
||||
(void)(SR_STATUS1((sr), SIP_100_TRYING)), \
|
||||
sr)
|
||||
char const *sr_sdp; /**< SDP received from client */
|
||||
size_t sr_sdp_len; /**< SDP length */
|
||||
|
||||
/**< Save 200 OK nua_respond() signal until PRACK has been received */
|
||||
nua_saved_signal_t sr_signal;
|
||||
};
|
||||
|
||||
#define SR_STATUS(sr, status, phrase) \
|
||||
((sr)->sr_phrase = (phrase), (sr)->sr_status = (status))
|
||||
@ -104,46 +148,194 @@ int sr_status(nua_server_request_t *sr, int status, char const *phrase)
|
||||
return (void)(sr->sr_phrase = phrase), (sr->sr_status = status);
|
||||
}
|
||||
|
||||
/** Methods for client request */
|
||||
typedef struct {
|
||||
sip_method_t crm_method;
|
||||
char const *crm_method_name;
|
||||
size_t crm_extra; /**< Size of private data */
|
||||
|
||||
struct {
|
||||
unsigned create_dialog:1, in_dialog:1, target_refresh:1;
|
||||
unsigned:0;
|
||||
} crm_flags;
|
||||
|
||||
/** Generate a request message.
|
||||
*
|
||||
* @retval 1 when request message has been created
|
||||
* @retval 0 when request message should be created in normal fashion
|
||||
* @retval -1 upon an error
|
||||
*/
|
||||
int (*crm_template)(nua_client_request_t *cr,
|
||||
msg_t **return_msg,
|
||||
tagi_t const *tags);
|
||||
|
||||
/**@a crm_init is called when a client request is sent first time.
|
||||
*
|
||||
* @retval 1 when request has been responded
|
||||
* @retval 0 when request should be sent in normal fashion
|
||||
* @retval -1 upon an error
|
||||
*/
|
||||
int (*crm_init)(nua_client_request_t *, msg_t *msg, sip_t *sip,
|
||||
tagi_t const *tags);
|
||||
|
||||
/** @a crm_send is called each time when a client request is sent.
|
||||
*
|
||||
* @retval 1 when request has been responded
|
||||
* @retval 0 when request has been sent
|
||||
* @retval -1 upon an error (request message has not been destroyed)
|
||||
* @retval -2 upon an error (request message has been destroyed)
|
||||
*/
|
||||
int (*crm_send)(nua_client_request_t *,
|
||||
msg_t *msg, sip_t *sip,
|
||||
tagi_t const *tags);
|
||||
|
||||
/** @a crm_check_restart is called each time when a response is received.
|
||||
*
|
||||
* It is used to restart reqquest after responses with method-specific
|
||||
* status code or method-specific way of restarting the request.
|
||||
*
|
||||
* @retval 1 when request has been restarted
|
||||
* @retval 0 when response should be processed normally
|
||||
*/
|
||||
int (*crm_check_restart)(nua_client_request_t *,
|
||||
int status, char const *phrase,
|
||||
sip_t const *sip);
|
||||
|
||||
/** @a crm_recv is called each time a final response is received.
|
||||
*
|
||||
* A final response is in range 200 .. 699 (or internal response) and it
|
||||
* cannot be restarted.
|
||||
*
|
||||
* crm_recv() should call nua_base_client_response() or
|
||||
* nua_base_client_tresponse(). The return values below are documented with
|
||||
* nua_base_client_response(), too.
|
||||
*
|
||||
* @retval 0 if response was preliminary
|
||||
* @retval 1 if response was final
|
||||
* @retval 2 if response destroyed the handle, too.
|
||||
*/
|
||||
int (*crm_recv)(nua_client_request_t *,
|
||||
int status, char const *phrase,
|
||||
sip_t const *sip);
|
||||
|
||||
/** @a crm_preliminary is called each time a preliminary response is received.
|
||||
*
|
||||
* A preliminary response is in range 101 .. 199.
|
||||
*
|
||||
* crm_preliminary() should call nua_base_client_response() or
|
||||
* nua_base_client_tresponse().
|
||||
*
|
||||
* @retval 0 if response was preliminary
|
||||
* @retval 1 if response was final
|
||||
* @retval 2 if response destroyed the handle, too.
|
||||
*/
|
||||
int (*crm_preliminary)(nua_client_request_t *,
|
||||
int status, char const *phrase,
|
||||
sip_t const *sip);
|
||||
|
||||
/** @a crm_report is called each time a response is received and it is
|
||||
* reported to the application.
|
||||
*
|
||||
* The status and phrase may be different from the status and phrase
|
||||
* received from the network, e.g., when the request is restarted.
|
||||
*
|
||||
* @return The return value should be 0. It is currently ignored.
|
||||
*/
|
||||
int (*crm_report)(nua_client_request_t *,
|
||||
int status, char const *phrase,
|
||||
sip_t const *sip,
|
||||
nta_outgoing_t *orq,
|
||||
tagi_t const *tags);
|
||||
|
||||
/** @a crm_deinit is called when a client-side request is destroyed.
|
||||
*
|
||||
* @return The return value should be 0. It is currently ignored.
|
||||
*/
|
||||
int (*crm_deinit)(nua_client_request_t *);
|
||||
|
||||
} nua_client_methods_t;
|
||||
|
||||
/* Client-side request. Documented by nua_client_create() */
|
||||
struct nua_client_request
|
||||
{
|
||||
nua_client_request_t *cr_next; /**< Linked list of requests */
|
||||
/*nua_event_t*/ int cr_event; /**< Request event */
|
||||
nua_creq_restart_f *cr_restart;
|
||||
nta_outgoing_t *cr_orq;
|
||||
msg_t *cr_msg;
|
||||
nua_client_request_t *cr_next, **cr_prev; /**< Linked list of requests */
|
||||
nua_owner_t *cr_owner;
|
||||
nua_dialog_usage_t *cr_usage;
|
||||
|
||||
nua_saved_signal_t cr_signal;
|
||||
tagi_t const *cr_tags;
|
||||
|
||||
nua_client_methods_t const *cr_methods;
|
||||
|
||||
msg_t *cr_msg;
|
||||
sip_t *cr_sip;
|
||||
|
||||
nta_outgoing_t *cr_orq;
|
||||
|
||||
/*nua_event_t*/ int cr_event; /**< Request event */
|
||||
sip_method_t cr_method;
|
||||
char const *cr_method_name;
|
||||
|
||||
url_t *cr_target;
|
||||
|
||||
uint32_t cr_seq;
|
||||
|
||||
unsigned short cr_status; /**< Latest status */
|
||||
|
||||
unsigned short cr_retry_count; /**< Retry count for this request */
|
||||
|
||||
/* Flags used with offer-answer */
|
||||
unsigned short cr_answer_recv; /**< Recv answer in response
|
||||
* with this status.
|
||||
*/
|
||||
unsigned cr_offer_sent:1; /**< Sent offer in this request */
|
||||
unsigned cr_offer_sent:1; /**< Sent offer in this request */
|
||||
|
||||
unsigned cr_offer_recv:1; /**< Recv offer in a response */
|
||||
unsigned cr_answer_sent:1; /**< Sent answer in (PR)ACK */
|
||||
unsigned cr_offer_recv:1; /**< Recv offer in a response */
|
||||
unsigned cr_answer_sent:1; /**< Sent answer in (PR)ACK */
|
||||
|
||||
unsigned cr_has_contact:1; /**< Request has application contact */
|
||||
/* Flags with usage */
|
||||
unsigned cr_neutral:1; /**< No effect on session or other usage */
|
||||
|
||||
/* Lifelong flags? */
|
||||
unsigned cr_auto:1; /**< Request was generated by stack */
|
||||
unsigned cr_has_contact:1; /**< Request has user Contact */
|
||||
unsigned cr_contactize:1; /**< Request needs Contact */
|
||||
unsigned cr_dialog:1; /**< Request can initiate dialog */
|
||||
|
||||
/* Current state */
|
||||
unsigned cr_challenged:1; /**< Request was challenged */
|
||||
unsigned cr_wait_for_cred:1; /**< Request is pending authentication */
|
||||
unsigned cr_restarting:1; /**< Request is being restarted */
|
||||
unsigned cr_reporting:1; /**< Reporting in progress */
|
||||
unsigned cr_terminating:1; /**< Request terminates the usage */
|
||||
signed int cr_terminated:2; /**< Response terminated usage (1) or
|
||||
whole dialog (-1) */
|
||||
unsigned cr_graceful:1; /**< Graceful termination required */
|
||||
};
|
||||
|
||||
|
||||
struct nua_dialog_state
|
||||
{
|
||||
nua_client_request_t ds_cr[1];
|
||||
nua_server_request_t *ds_sr;
|
||||
|
||||
/** Dialog usages. */
|
||||
nua_dialog_usage_t *ds_usage;
|
||||
|
||||
/** Client requests */
|
||||
nua_client_request_t *ds_cr;
|
||||
/** Server requests */
|
||||
nua_server_request_t *ds_sr;
|
||||
|
||||
/* Dialog and subscription state */
|
||||
unsigned ds_reporting:1; /**< We are reporting */
|
||||
|
||||
unsigned ds_route:1; /**< We have route */
|
||||
unsigned ds_terminated:1; /**< Being terminated */
|
||||
unsigned ds_terminating:1; /**< Being terminated */
|
||||
|
||||
unsigned ds_has_session:1; /**< We have session */
|
||||
unsigned ds_has_register:1; /**< We have registration */
|
||||
unsigned ds_has_publish:1; /**< We have publish */
|
||||
|
||||
unsigned ds_has_referrals:1; /**< We have (or have had) referrals */
|
||||
unsigned ds_got_session:1; /**< We have (or have had) session */
|
||||
unsigned ds_got_referrals:1; /**< We have (or have had) referrals */
|
||||
|
||||
unsigned :0;
|
||||
|
||||
@ -196,8 +388,8 @@ typedef struct {
|
||||
struct nua_dialog_usage {
|
||||
nua_dialog_usage_t *du_next;
|
||||
nua_usage_class const *du_class;
|
||||
nua_client_request_t *du_cr; /**< Client request bound with usage */
|
||||
|
||||
unsigned du_terminating:1; /**< Now trying to terminate usage */
|
||||
unsigned du_ready:1; /**< Established usage */
|
||||
unsigned du_shutdown:1; /**< Shutdown in progress */
|
||||
unsigned:0;
|
||||
@ -206,13 +398,11 @@ struct nua_dialog_usage {
|
||||
* Non-zero if the usage is established, SIP_TIME_MAX if there no
|
||||
* expiration time.
|
||||
*/
|
||||
sip_time_t du_expires;
|
||||
|
||||
sip_time_t du_refresh; /**< When to refresh */
|
||||
|
||||
sip_event_t const *du_event; /**< Event of usage */
|
||||
|
||||
msg_t *du_msg; /**< Template message */
|
||||
};
|
||||
|
||||
void nua_dialog_uac_route(nua_owner_t *, nua_dialog_state_t *ds,
|
||||
@ -225,6 +415,11 @@ int nua_dialog_remove(nua_owner_t *own,
|
||||
nua_dialog_state_t *ds,
|
||||
nua_dialog_usage_t *usage);
|
||||
|
||||
static inline int nua_dialog_is_reporting(nua_dialog_state_t const *ds)
|
||||
{
|
||||
return ds && ds->ds_reporting;
|
||||
}
|
||||
|
||||
char const *nua_dialog_usage_name(nua_dialog_usage_t const *du);
|
||||
|
||||
nua_dialog_usage_t *nua_dialog_usage_add(nua_owner_t *,
|
||||
@ -243,18 +438,16 @@ void nua_dialog_usage_remove(nua_owner_t *,
|
||||
void nua_dialog_deinit(nua_owner_t *own,
|
||||
nua_dialog_state_t *ds);
|
||||
|
||||
void nua_dialog_terminated(nua_owner_t *,
|
||||
struct nua_dialog_state *ds,
|
||||
int status,
|
||||
char const *phrase);
|
||||
|
||||
void nua_dialog_usage_set_expires(nua_dialog_usage_t *du, unsigned delta);
|
||||
int nua_dialog_shutdown(nua_owner_t *owner, nua_dialog_state_t *ds);
|
||||
|
||||
void nua_dialog_usage_set_refresh(nua_dialog_usage_t *du, unsigned delta);
|
||||
|
||||
void nua_dialog_usage_refresh_range(nua_dialog_usage_t *du,
|
||||
unsigned min, unsigned max);
|
||||
|
||||
void nua_dialog_usage_refresh_at(nua_dialog_usage_t *du,
|
||||
sip_time_t target);
|
||||
|
||||
void nua_dialog_usage_reset_refresh(nua_dialog_usage_t *du);
|
||||
|
||||
void nua_dialog_usage_refresh(nua_owner_t *owner,
|
||||
@ -262,6 +455,10 @@ void nua_dialog_usage_refresh(nua_owner_t *owner,
|
||||
nua_dialog_usage_t *du,
|
||||
sip_time_t now);
|
||||
|
||||
int nua_dialog_usage_shutdown(nua_owner_t *owner,
|
||||
nua_dialog_state_t *ds,
|
||||
nua_dialog_usage_t *du);
|
||||
|
||||
static inline
|
||||
int nua_dialog_is_established(nua_dialog_state_t const *ds)
|
||||
{
|
||||
@ -287,18 +484,178 @@ nua_dialog_usage_t *nua_dialog_usage_public(void const *p)
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
void nua_server_request_destroy(nua_server_request_t *sr);
|
||||
int nua_client_create(nua_owner_t *owner,
|
||||
int event,
|
||||
nua_client_methods_t const *methods,
|
||||
tagi_t const *tags);
|
||||
|
||||
int nua_server_respond(nua_server_request_t *sr,
|
||||
int status, char const *phrase,
|
||||
int nua_client_tcreate(nua_owner_t *nh,
|
||||
int event,
|
||||
nua_client_methods_t const *methods,
|
||||
tag_type_t tag, tag_value_t value, ...);
|
||||
|
||||
msg_t *nua_server_response(nua_server_request_t *sr,
|
||||
int status, char const *phrase,
|
||||
tag_type_t tag, tag_value_t value, ...);
|
||||
static inline
|
||||
void *nua_private_client_request(nua_client_request_t const *cr)
|
||||
{
|
||||
return (void *)(cr + 1);
|
||||
}
|
||||
|
||||
int nua_default_respond(nua_server_request_t *sr,
|
||||
tagi_t const *tags);
|
||||
void nua_client_request_destroy(nua_client_request_t *);
|
||||
|
||||
int nua_client_request_queue(nua_client_request_t *cr);
|
||||
|
||||
static inline int nua_client_is_queued(nua_client_request_t const *cr)
|
||||
{
|
||||
return cr && cr->cr_prev;
|
||||
}
|
||||
|
||||
nua_client_request_t *nua_client_request_remove(nua_client_request_t *cr);
|
||||
|
||||
int nua_client_bind(nua_client_request_t *cr, nua_dialog_usage_t *du);
|
||||
|
||||
static inline int nua_client_is_bound(nua_client_request_t const *cr)
|
||||
{
|
||||
return cr && cr->cr_usage && cr->cr_usage->du_cr == cr;
|
||||
}
|
||||
|
||||
static inline int nua_client_is_reporting(nua_client_request_t const *cr)
|
||||
{
|
||||
return cr && cr->cr_reporting;
|
||||
}
|
||||
|
||||
/** Mark client request as a terminating one */
|
||||
static inline void nua_client_terminating(nua_client_request_t *cr)
|
||||
{
|
||||
cr->cr_terminating = 1;
|
||||
}
|
||||
|
||||
int nua_client_init_request(nua_client_request_t *cr);
|
||||
|
||||
int nua_client_restart_request(nua_client_request_t *cr,
|
||||
int terminating,
|
||||
tagi_t const *tags);
|
||||
|
||||
int nua_client_resend_request(nua_client_request_t *cr,
|
||||
int terminating);
|
||||
|
||||
int nua_base_client_request(nua_client_request_t *cr,
|
||||
msg_t *msg,
|
||||
sip_t *sip,
|
||||
tagi_t const *tags);
|
||||
|
||||
int nua_base_client_trequest(nua_client_request_t *cr,
|
||||
msg_t *msg,
|
||||
sip_t *sip,
|
||||
tag_type_t tag, tag_value_t value, ...);
|
||||
|
||||
extern nta_response_f nua_client_orq_response;
|
||||
|
||||
int nua_client_return(nua_client_request_t *cr,
|
||||
int status,
|
||||
char const *phrase,
|
||||
msg_t *to_be_destroyed);
|
||||
|
||||
int nua_client_response(nua_client_request_t *cr,
|
||||
int status,
|
||||
char const *phrase,
|
||||
sip_t const *sip);
|
||||
|
||||
int nua_client_check_restart(nua_client_request_t *cr,
|
||||
int status,
|
||||
char const *phrase,
|
||||
sip_t const *sip);
|
||||
|
||||
int nua_base_client_check_restart(nua_client_request_t *cr,
|
||||
int status,
|
||||
char const *phrase,
|
||||
sip_t const *sip);
|
||||
|
||||
int nua_client_restart(nua_client_request_t *cr,
|
||||
int status, char const *phrase);
|
||||
|
||||
int nua_base_client_response(nua_client_request_t *cr,
|
||||
int status, char const *phrase,
|
||||
sip_t const *sip,
|
||||
tagi_t const *tags);
|
||||
|
||||
int nua_base_client_tresponse(nua_client_request_t *cr,
|
||||
int status, char const *phrase,
|
||||
sip_t const *sip,
|
||||
tag_type_t tag, tag_value_t value, ...);
|
||||
|
||||
int nua_client_set_target(nua_client_request_t *cr, url_t const *target);
|
||||
|
||||
int nua_client_report(nua_client_request_t *cr,
|
||||
int status, char const *phrase,
|
||||
sip_t const *sip,
|
||||
nta_outgoing_t *orq,
|
||||
tagi_t const *tags);
|
||||
|
||||
nua_client_request_t *nua_client_request_pending(nua_client_request_t const *);
|
||||
|
||||
int nua_client_next_request(nua_client_request_t *cr, int invite);
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
extern nua_server_methods_t const
|
||||
nua_extension_server_methods,
|
||||
nua_invite_server_methods, /**< INVITE */
|
||||
nua_bye_server_methods, /**< BYE */
|
||||
nua_options_server_methods, /**< OPTIONS */
|
||||
nua_register_server_methods, /**< REGISTER */
|
||||
nua_info_server_methods, /**< INFO */
|
||||
nua_prack_server_methods, /**< PRACK */
|
||||
nua_update_server_methods, /**< UPDATE */
|
||||
nua_message_server_methods, /**< MESSAGE */
|
||||
nua_subscribe_server_methods, /**< SUBSCRIBE */
|
||||
nua_notify_server_methods, /**< NOTIFY */
|
||||
nua_refer_server_methods, /**< REFER */
|
||||
nua_publish_server_methods; /**< PUBLISH */
|
||||
|
||||
/** Return true if we have not sent final response to request */
|
||||
static inline
|
||||
int nua_server_request_is_pending(nua_server_request_t const *sr)
|
||||
{
|
||||
return sr && sr->sr_response.msg;
|
||||
}
|
||||
|
||||
static inline
|
||||
int nua_server_request_status(nua_server_request_t const *sr)
|
||||
{
|
||||
return sr ? nta_incoming_status(sr->sr_irq) : 500;
|
||||
}
|
||||
|
||||
void nua_server_request_destroy(nua_server_request_t *sr);
|
||||
|
||||
int nua_base_server_init(nua_server_request_t *sr);
|
||||
|
||||
#define nua_base_server_init NULL
|
||||
|
||||
int nua_base_server_preprocess(nua_server_request_t *sr);
|
||||
|
||||
#define nua_base_server_preprocess NULL
|
||||
|
||||
int nua_server_params(nua_server_request_t *sr, tagi_t const *tags);
|
||||
|
||||
int nua_base_server_params(nua_server_request_t *sr, tagi_t const *tags);
|
||||
|
||||
#define nua_base_server_params NULL
|
||||
|
||||
int nua_server_trespond(nua_server_request_t *sr,
|
||||
tag_type_t tag, tag_value_t value, ...);
|
||||
int nua_server_respond(nua_server_request_t *sr, tagi_t const *tags);
|
||||
|
||||
int nua_base_server_trespond(nua_server_request_t *sr,
|
||||
tag_type_t tag, tag_value_t value, ...);
|
||||
int nua_base_server_respond(nua_server_request_t *sr,
|
||||
tagi_t const *tags);
|
||||
|
||||
int nua_server_report(nua_server_request_t *sr);
|
||||
|
||||
int nua_base_server_treport(nua_server_request_t *sr,
|
||||
tag_type_t tag, tag_value_t value, ...);
|
||||
int nua_base_server_report(nua_server_request_t *sr, tagi_t const *tags);
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
#endif /* NUA_DIALOG_H */
|
||||
|
@ -45,9 +45,6 @@
|
||||
#include <sofia-sip/sip_status.h>
|
||||
#include <sofia-sip/su_tagarg.h>
|
||||
|
||||
#define NTA_LEG_MAGIC_T struct nua_handle_s
|
||||
#define NTA_OUTGOING_MAGIC_T struct nua_handle_s
|
||||
|
||||
#define NEA_SMAGIC_T struct nua_handle_s
|
||||
#define NEA_EMAGIC_T struct nua_handle_s
|
||||
|
||||
@ -121,13 +118,13 @@ nua_stack_notifier(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *ta
|
||||
status = 900, phrase = "Error when notifying watchers";
|
||||
|
||||
else
|
||||
nua_stack_event(nua, nh, NULL, e, status = SIP_200_OK,
|
||||
SIPTAG_EVENT(event),
|
||||
SIPTAG_CONTENT_TYPE(ct),
|
||||
TAG_END());
|
||||
nua_stack_tevent(nua, nh, NULL, e, status = SIP_200_OK,
|
||||
SIPTAG_EVENT(event),
|
||||
SIPTAG_CONTENT_TYPE(ct),
|
||||
TAG_END());
|
||||
|
||||
if (status != 200)
|
||||
nua_stack_event(nua, nh, NULL, e, status, phrase, TAG_END());
|
||||
nua_stack_event(nua, nh, NULL, e, status, phrase, NULL);
|
||||
|
||||
su_home_deinit(home);
|
||||
}
|
||||
@ -223,7 +220,7 @@ void authorize_watcher(nea_server_t *nes,
|
||||
what = "active";
|
||||
}
|
||||
|
||||
SU_DEBUG_7(("nua(%p): authorize_watcher: %s\n", nh, what));
|
||||
SU_DEBUG_7(("nua(%p): authorize_watcher: %s\n", (void *)nh, what));
|
||||
nea_sub_auth(sn->sn_subscriber, substate,
|
||||
TAG_IF(substate == nua_substate_pending,
|
||||
NEATAG_FAKE(1)),
|
||||
@ -235,13 +232,13 @@ void authorize_watcher(nea_server_t *nes,
|
||||
substate = nua_substate_terminated;
|
||||
nea_server_flush(nes, NULL);
|
||||
SU_DEBUG_7(("nua(%p): authorize_watcher: %s\n",
|
||||
nh, "watcher is removed"));
|
||||
(void *)nh, "watcher is removed"));
|
||||
}
|
||||
|
||||
nua_stack_event(nua, nh, msg, nua_i_subscription, status, phrase,
|
||||
NUTAG_SUBSTATE(substate),
|
||||
NEATAG_SUB(sn->sn_subscriber),
|
||||
TAG_END());
|
||||
nua_stack_tevent(nua, nh, msg, nua_i_subscription, status, phrase,
|
||||
NUTAG_SUBSTATE(substate),
|
||||
NEATAG_SUB(sn->sn_subscriber),
|
||||
TAG_END());
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
@ -262,12 +259,11 @@ void nua_stack_authorize(nua_t *nua,
|
||||
|
||||
if (sub && state > 0) {
|
||||
nea_sub_auth(sub, state, TAG_NEXT(tags));
|
||||
nua_stack_event(nua, nh, NULL, e, SIP_200_OK, TAG_END());
|
||||
nua_stack_event(nua, nh, NULL, e, SIP_200_OK, NULL);
|
||||
}
|
||||
else {
|
||||
nua_stack_event(nua, nh, NULL, e, NUA_INTERNAL_ERROR, TAG_END());
|
||||
nua_stack_event(nua, nh, NULL, e, NUA_INTERNAL_ERROR, NULL);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/** @internal Shutdown notifier object */
|
||||
@ -347,5 +343,5 @@ void nua_stack_terminate(nua_t *nua,
|
||||
NEATAG_REASON("noresource"),
|
||||
TAG_NEXT(tags));
|
||||
|
||||
nua_stack_event(nua, nh, NULL, e, SIP_200_OK, TAG_END());
|
||||
nua_stack_event(nua, nh, NULL, e, SIP_200_OK, NULL);
|
||||
}
|
||||
|
@ -43,17 +43,8 @@
|
||||
#include <sofia-sip/sip_protos.h>
|
||||
#include <sofia-sip/sip_status.h>
|
||||
|
||||
#define NTA_LEG_MAGIC_T struct nua_handle_s
|
||||
#define NTA_OUTGOING_MAGIC_T struct nua_handle_s
|
||||
|
||||
#include "nua_stack.h"
|
||||
|
||||
static int process_response_to_method(nua_handle_t *nh,
|
||||
nta_outgoing_t *orq,
|
||||
sip_t const *sip);
|
||||
static void restart_method(nua_handle_t *nh, tagi_t *tags);
|
||||
static int respond_to_method(nua_server_request_t *sr, tagi_t const *tags);
|
||||
|
||||
/** Send an extension request.
|
||||
*
|
||||
* Send an entension request message.
|
||||
@ -78,32 +69,25 @@ static int respond_to_method(nua_server_request_t *sr, tagi_t const *tags);
|
||||
* @since New in @VERSION_1_12_4.
|
||||
*/
|
||||
|
||||
static nua_client_methods_t const nua_method_client_methods = {
|
||||
SIP_METHOD_UNKNOWN,
|
||||
0,
|
||||
{
|
||||
/* create_dialog */ 0,
|
||||
/* in_dialog */ 0,
|
||||
/* target_refresh */ 1,
|
||||
},
|
||||
/* nua_method_client_template */ NULL,
|
||||
/* nua_method_client_init */ NULL,
|
||||
/* nua_method_client_request */ NULL,
|
||||
/* nua_method_client_check_restart */ NULL,
|
||||
/* nua_method_client_response */ NULL
|
||||
};
|
||||
|
||||
int
|
||||
nua_stack_method(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags)
|
||||
{
|
||||
nua_client_request_t *cr = nh->nh_ds->ds_cr;
|
||||
msg_t *msg;
|
||||
|
||||
if (cr->cr_orq)
|
||||
return UA_EVENT2(e, 900, "Request already in progress");
|
||||
|
||||
nua_stack_init_handle(nua, nh, TAG_NEXT(tags));
|
||||
|
||||
msg = nua_creq_msg(nua, nh, cr, cr->cr_retry_count,
|
||||
SIP_METHOD_UNKNOWN,
|
||||
TAG_NEXT(tags));
|
||||
if (msg)
|
||||
cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,
|
||||
process_response_to_method, nh, NULL,
|
||||
msg,
|
||||
SIPTAG_END(),
|
||||
TAG_NEXT(tags));
|
||||
if (!cr->cr_orq) {
|
||||
msg_destroy(msg);
|
||||
return UA_EVENT1(e, NUA_INTERNAL_ERROR);
|
||||
}
|
||||
|
||||
return cr->cr_event = e;
|
||||
return nua_client_create(nh, e, &nua_method_client_methods, tags);
|
||||
}
|
||||
|
||||
/** @NUA_EVENT nua_r_method
|
||||
@ -127,20 +111,6 @@ nua_stack_method(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags
|
||||
* @END_NUA_EVENT
|
||||
*/
|
||||
|
||||
static int process_response_to_method(nua_handle_t *nh,
|
||||
nta_outgoing_t *orq,
|
||||
sip_t const *sip)
|
||||
{
|
||||
if (nua_creq_check_restart(nh, nh->nh_ds->ds_cr, orq, sip, restart_method))
|
||||
return 0;
|
||||
return nua_stack_process_response(nh, nh->nh_ds->ds_cr, orq, sip, TAG_END());
|
||||
}
|
||||
|
||||
void restart_method(nua_handle_t *nh, tagi_t *tags)
|
||||
{
|
||||
nua_creq_restart(nh, nh->nh_ds->ds_cr, process_response_to_method, tags);
|
||||
}
|
||||
|
||||
/** @NUA_EVENT nua_i_method
|
||||
*
|
||||
* @brief Incoming extension request.
|
||||
@ -155,50 +125,35 @@ void restart_method(nua_handle_t *nh, tagi_t *tags)
|
||||
* @param nh operation handle associated with the method
|
||||
* @param hmagic application context associated with the handle
|
||||
* (maybe NULL if outside session)
|
||||
* @param sip incoming request
|
||||
* @param sip headers in incoming request (see also nua_current_request())
|
||||
* @param tags NUTAG_METHOD()
|
||||
*
|
||||
* The extension name is in sip->sip_request->rq_method_name, too.
|
||||
* The extension method name is in sip->sip_request->rq_method_name, too.
|
||||
*
|
||||
* @sa nua_method(), #nua_r_method
|
||||
* @note If the @a status is < 200, it is up to application to respond to
|
||||
* the request with nua_respond(). If the handle is destroyed, the stack
|
||||
* returns a <i>500 Internal Server Error</i> response to any unresponded
|
||||
* request.
|
||||
*
|
||||
* @sa nua_method(), #nua_r_method, NUTAG_ALLOW(), NUTAG_APPL_METHOD(),
|
||||
* nua_respond(), NUTAG_WITH(), NUTAG_WITH_THIS(), NUTAG_
|
||||
*
|
||||
* @END_NUA_EVENT
|
||||
*/
|
||||
|
||||
int nua_stack_process_method(nua_t *nua,
|
||||
nua_handle_t *nh,
|
||||
nta_incoming_t *irq,
|
||||
sip_t const *sip)
|
||||
{
|
||||
nua_server_request_t *sr, sr0[1];
|
||||
|
||||
sr = SR_INIT(sr0);
|
||||
|
||||
sr = nua_server_request(nua, nh, irq, sip, sr, sizeof *sr,
|
||||
respond_to_method, 0);
|
||||
|
||||
return nua_stack_server_event(nua, sr, nua_i_method, TAG_END());
|
||||
}
|
||||
|
||||
static
|
||||
int respond_to_method(nua_server_request_t *sr, tagi_t const *tags)
|
||||
{
|
||||
nua_handle_t *nh = sr->sr_owner;
|
||||
nua_t *nua = nh->nh_nua;
|
||||
msg_t *msg;
|
||||
|
||||
msg = nua_server_response(sr, sr->sr_status, sr->sr_phrase, TAG_NEXT(tags));
|
||||
|
||||
if (msg) {
|
||||
nta_incoming_mreply(sr->sr_irq, msg);
|
||||
}
|
||||
else {
|
||||
SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR);
|
||||
nta_incoming_treply(sr->sr_irq, sr->sr_status, sr->sr_phrase, TAG_END());
|
||||
nua_stack_event(nua, nh, NULL,
|
||||
nua_i_error, 900, "Response to Extension Method Fails",
|
||||
TAG_END());
|
||||
}
|
||||
|
||||
return sr->sr_status >= 200 ? sr->sr_status : 0;
|
||||
}
|
||||
nua_server_methods_t const nua_extension_server_methods =
|
||||
{
|
||||
SIP_METHOD_UNKNOWN,
|
||||
nua_i_method, /* Event */
|
||||
{
|
||||
1, /* Do create dialog */
|
||||
0, /* Can be an initial request */
|
||||
1, /* Perhaps a target refresh request? */
|
||||
1, /* Add a contact? */
|
||||
},
|
||||
nua_base_server_init,
|
||||
nua_base_server_preprocess,
|
||||
nua_base_server_params,
|
||||
nua_base_server_respond,
|
||||
nua_base_server_report,
|
||||
};
|
||||
|
@ -43,9 +43,6 @@
|
||||
#include <sofia-sip/sip_protos.h>
|
||||
#include <sofia-sip/sip_status.h>
|
||||
|
||||
#define NTA_LEG_MAGIC_T struct nua_handle_s
|
||||
#define NTA_OUTGOING_MAGIC_T struct nua_handle_s
|
||||
|
||||
#include "nua_stack.h"
|
||||
|
||||
/* ======================================================================== */
|
||||
@ -72,48 +69,41 @@
|
||||
* @sa #nua_i_message, @RFC3428
|
||||
*/
|
||||
|
||||
static int process_response_to_message(nua_handle_t *nh,
|
||||
nta_outgoing_t *orq,
|
||||
sip_t const *sip);
|
||||
static int nua_message_client_init(nua_client_request_t *cr,
|
||||
msg_t *, sip_t *,
|
||||
tagi_t const *tags);
|
||||
|
||||
static nua_client_methods_t const nua_message_client_methods = {
|
||||
SIP_METHOD_MESSAGE,
|
||||
0,
|
||||
{
|
||||
/* create_dialog */ 0,
|
||||
/* in_dialog */ 0,
|
||||
/* target refresh */ 0
|
||||
},
|
||||
/* nua_message_client_template */ NULL,
|
||||
nua_message_client_init,
|
||||
/*nua_message_client_request*/ NULL,
|
||||
/* nua_message_client_check_restart */ NULL,
|
||||
/*nua_message_client_response*/ NULL
|
||||
};
|
||||
|
||||
int
|
||||
nua_stack_message(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags)
|
||||
nua_stack_message(nua_t *nua,
|
||||
nua_handle_t *nh,
|
||||
nua_event_t e,
|
||||
tagi_t const *tags)
|
||||
{
|
||||
nua_client_request_t *cr = nh->nh_ds->ds_cr;
|
||||
msg_t *msg;
|
||||
sip_t *sip;
|
||||
|
||||
if (nh_is_special(nh)) {
|
||||
return UA_EVENT2(e, 900, "Invalid handle for MESSAGE");
|
||||
}
|
||||
else if (cr->cr_orq) {
|
||||
return UA_EVENT2(e, 900, "Request already in progress");
|
||||
}
|
||||
|
||||
nua_stack_init_handle(nua, nh, TAG_NEXT(tags));
|
||||
|
||||
msg = nua_creq_msg(nua, nh, cr, cr->cr_retry_count,
|
||||
SIP_METHOD_MESSAGE,
|
||||
NUTAG_ADD_CONTACT(NH_PGET(nh, win_messenger_enable)),
|
||||
TAG_NEXT(tags));
|
||||
sip = sip_object(msg);
|
||||
|
||||
if (sip)
|
||||
cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,
|
||||
process_response_to_message, nh, NULL,
|
||||
msg,
|
||||
SIPTAG_END(), TAG_NEXT(tags));
|
||||
if (!cr->cr_orq) {
|
||||
msg_destroy(msg);
|
||||
return UA_EVENT1(e, NUA_INTERNAL_ERROR);
|
||||
}
|
||||
|
||||
return cr->cr_event = e;
|
||||
return nua_client_create(nh, e, &nua_message_client_methods, tags);
|
||||
}
|
||||
|
||||
void restart_message(nua_handle_t *nh, tagi_t *tags)
|
||||
static int nua_message_client_init(nua_client_request_t *cr,
|
||||
msg_t *msg, sip_t *sip,
|
||||
tagi_t const *tags)
|
||||
{
|
||||
nua_creq_restart(nh, nh->nh_ds->ds_cr, process_response_to_message, tags);
|
||||
if (NH_PGET(cr->cr_owner, win_messenger_enable))
|
||||
cr->cr_contactize = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @NUA_EVENT nua_r_message
|
||||
@ -137,15 +127,6 @@ void restart_message(nua_handle_t *nh, tagi_t *tags)
|
||||
* @END_NUA_EVENT
|
||||
*/
|
||||
|
||||
static int process_response_to_message(nua_handle_t *nh,
|
||||
nta_outgoing_t *orq,
|
||||
sip_t const *sip)
|
||||
{
|
||||
if (nua_creq_check_restart(nh, nh->nh_ds->ds_cr, orq, sip, restart_message))
|
||||
return 0;
|
||||
return nua_stack_process_response(nh, nh->nh_ds->ds_cr, orq, sip, TAG_END());
|
||||
}
|
||||
|
||||
/** @NUA_EVENT nua_i_message
|
||||
*
|
||||
* @brief Incoming @b MESSAGE request.
|
||||
@ -168,32 +149,39 @@ static int process_response_to_message(nua_handle_t *nh,
|
||||
* @END_NUA_EVENT
|
||||
*/
|
||||
|
||||
int nua_stack_process_message(nua_t *nua,
|
||||
nua_handle_t *nh,
|
||||
nta_incoming_t *irq,
|
||||
sip_t const *sip)
|
||||
int nua_message_server_init(nua_server_request_t *sr);
|
||||
int nua_message_server_params(nua_server_request_t *, tagi_t const *);
|
||||
|
||||
nua_server_methods_t const nua_message_server_methods =
|
||||
{
|
||||
SIP_METHOD_MESSAGE,
|
||||
nua_i_message, /* Event */
|
||||
{
|
||||
0, /* Do not create dialog */
|
||||
0, /* Can be initial request */
|
||||
0, /* Perhaps a target refresh request? */
|
||||
0, /* Do not add contact by default */
|
||||
},
|
||||
nua_message_server_init,
|
||||
nua_base_server_preprocess,
|
||||
nua_message_server_params,
|
||||
nua_base_server_respond,
|
||||
nua_base_server_report,
|
||||
};
|
||||
|
||||
int nua_message_server_init(nua_server_request_t *sr)
|
||||
{
|
||||
msg_t *msg;
|
||||
if (!NH_PGET(sr->sr_owner, message_enable))
|
||||
return SR_STATUS1(sr, SIP_403_FORBIDDEN);
|
||||
|
||||
if (nh
|
||||
? !NH_PGET(nh, message_enable)
|
||||
: !DNH_PGET(nua->nua_dhandle, message_enable))
|
||||
return 403;
|
||||
|
||||
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
@ -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);
|
||||
}
|
||||
|
@ -149,9 +149,10 @@ int nua_stack_set_defaults(nua_handle_t *nh,
|
||||
NHP_SET(nhp, auto_ack, 1);
|
||||
NHP_SET(nhp, invite_timeout, 120);
|
||||
|
||||
NHP_SET(nhp, session_timer, 1800);
|
||||
nhp->nhp_session_timer = 1800;
|
||||
nhp->nhp_refresher = nua_no_refresher;
|
||||
|
||||
NHP_SET(nhp, min_se, 120);
|
||||
NHP_SET(nhp, refresher, nua_no_refresher);
|
||||
NHP_SET(nhp, update_refresh, 0);
|
||||
|
||||
NHP_SET(nhp, message_enable, 1);
|
||||
@ -393,6 +394,7 @@ int nua_stack_init_instance(nua_handle_t *nh, tagi_t const *tags)
|
||||
* NUTAG_ALLOW(), SIPTAG_ALLOW(), and SIPTAG_ALLOW_STR() \n
|
||||
* NUTAG_ALLOW_EVENTS(), SIPTAG_ALLOW_EVENTS(), and
|
||||
* SIPTAG_ALLOW_EVENTS_STR() \n
|
||||
* NUTAG_AUTH_CACHE() \n
|
||||
* NUTAG_AUTOACK() \n
|
||||
* NUTAG_AUTOALERT() \n
|
||||
* NUTAG_AUTOANSWER() \n
|
||||
@ -762,12 +764,6 @@ static int nhp_set_tags(su_home_t *home,
|
||||
else if (tag == nutag_enablemessenger) {
|
||||
NHP_SET(nhp, win_messenger_enable, value != 0);
|
||||
}
|
||||
#if 0
|
||||
/* NUTAG_AUTORESPOND(autorespond) */
|
||||
else if (tag == nutag_autorespond) {
|
||||
NHP_SET(nhp, autorespond, value);
|
||||
}
|
||||
#endif
|
||||
/* NUTAG_CALLEE_CAPS(callee_caps) */
|
||||
else if (tag == nutag_callee_caps) {
|
||||
NHP_SET(nhp, callee_caps, value != 0);
|
||||
@ -784,6 +780,11 @@ static int nhp_set_tags(su_home_t *home,
|
||||
else if (tag == nutag_path_enable) {
|
||||
NHP_SET(nhp, path_enable, value != 0);
|
||||
}
|
||||
/* NUTAG_AUTH_CACHE(auth_cache) */
|
||||
else if (tag == nutag_auth_cache) {
|
||||
if (value >= 0 && value < (tag_value_t)_nua_auth_cache_invalid)
|
||||
NHP_SET(nhp, auth_cache, (int)value);
|
||||
}
|
||||
/* NUTAG_REFER_EXPIRES(refer_expires) */
|
||||
else if (tag == nutag_refer_expires) {
|
||||
NHP_SET(nhp, refer_expires, value);
|
||||
@ -882,7 +883,8 @@ static int nhp_set_tags(su_home_t *home,
|
||||
sip_allow_class,
|
||||
&appl_method,
|
||||
(msg_list_t const *)nhp->nhp_appl_method,
|
||||
NHP_ISSET(nhp, allow), /* already set by tags */
|
||||
/* already set by tags? */
|
||||
NHP_ISSET(nhp, appl_method),
|
||||
0, /* dup it, don't make */
|
||||
1, /* merge with old value */
|
||||
t->t_value);
|
||||
@ -1171,10 +1173,10 @@ int nua_handle_save_tags(nua_handle_t *nh, tagi_t *tags)
|
||||
|
||||
nh->nh_tags =
|
||||
tl_filtered_tlist(nh->nh_home, tagfilter,
|
||||
SIPTAG_FROM(p_from),
|
||||
TAG_FILTER(nua_handle_tags_filter),
|
||||
SIPTAG_TO(p_to),
|
||||
TAG_FILTER(nua_handle_tags_filter),
|
||||
TAG_IF(p_from != SIP_NONE, SIPTAG_FROM(p_from)),
|
||||
TAG_IF(p_from != SIP_NONE, TAG_FILTER(nua_handle_tags_filter)),
|
||||
TAG_IF(p_to != SIP_NONE, SIPTAG_TO(p_to)),
|
||||
TAG_IF(p_to != SIP_NONE, TAG_FILTER(nua_handle_tags_filter)),
|
||||
TAG_NEXT(tags));
|
||||
|
||||
nh->nh_ptags =
|
||||
@ -1366,7 +1368,9 @@ int nua_stack_set_smime_params(nua_t *nua, tagi_t const *tags)
|
||||
* application contact associated with the operation handle
|
||||
* when responding to nua_get_hparams()
|
||||
* @param sip NULL
|
||||
* @param tags
|
||||
* @param tags
|
||||
* NUTAG_APPL_METHOD() \n
|
||||
* NUTAG_AUTH_CACHE() \n
|
||||
* NUTAG_AUTOACK() \n
|
||||
* NUTAG_AUTOALERT() \n
|
||||
* NUTAG_AUTOANSWER() \n
|
||||
@ -1500,6 +1504,11 @@ int nua_stack_get_params(nua_t *nua, nua_handle_t *nh, nua_event_t e,
|
||||
#define TIF(TAG, pref) \
|
||||
TAG_IF(nhp->nhp_set.nhb_##pref, TAG(nhp->nhp_##pref))
|
||||
|
||||
/* Include tag in the list returned to user
|
||||
* if it has been earlier set (by user) returning default parameters */
|
||||
#define TIFD(TAG, pref) \
|
||||
TAG_IF(nh == dnh || nhp->nhp_set.nhb_##pref, TAG(nhp->nhp_##pref))
|
||||
|
||||
/* Include string tag made out of SIP header
|
||||
* if it has been earlier set (by user) */
|
||||
#define TIF_STR(TAG, pref) \
|
||||
@ -1537,9 +1546,9 @@ int nua_stack_get_params(nua_t *nua, nua_handle_t *nh, nua_event_t e,
|
||||
TIF(NUTAG_AUTOACK, auto_ack),
|
||||
TIF(NUTAG_INVITE_TIMER, invite_timeout),
|
||||
|
||||
TIF(NUTAG_SESSION_TIMER, session_timer),
|
||||
TIFD(NUTAG_SESSION_TIMER, session_timer),
|
||||
TIF(NUTAG_MIN_SE, min_se),
|
||||
TIF(NUTAG_SESSION_REFRESHER, refresher),
|
||||
TIFD(NUTAG_SESSION_REFRESHER, refresher),
|
||||
TIF(NUTAG_UPDATE_REFRESH, update_refresh),
|
||||
|
||||
TIF(NUTAG_ENABLEMESSAGE, message_enable),
|
||||
@ -1550,6 +1559,7 @@ int nua_stack_get_params(nua_t *nua, nua_handle_t *nh, nua_event_t e,
|
||||
TIF(NUTAG_MEDIA_FEATURES, media_features),
|
||||
TIF(NUTAG_SERVICE_ROUTE_ENABLE, service_route_enable),
|
||||
TIF(NUTAG_PATH_ENABLE, path_enable),
|
||||
TIF(NUTAG_AUTH_CACHE, auth_cache),
|
||||
TIF(NUTAG_REFER_EXPIRES, refer_expires),
|
||||
TIF(NUTAG_REFER_WITH_ID, refer_with_id),
|
||||
|
||||
@ -1559,6 +1569,7 @@ int nua_stack_get_params(nua_t *nua, nua_handle_t *nh, nua_event_t e,
|
||||
TIF_STR(SIPTAG_SUPPORTED_STR, supported),
|
||||
TIF(SIPTAG_ALLOW, allow),
|
||||
TIF_STR(SIPTAG_ALLOW_STR, allow),
|
||||
TIF_STR(NUTAG_APPL_METHOD, appl_method),
|
||||
TIF(SIPTAG_ALLOW_EVENTS, allow_events),
|
||||
TIF_STR(SIPTAG_ALLOW_EVENTS_STR, allow_events),
|
||||
TIF_SIP(SIPTAG_USER_AGENT, user_agent),
|
||||
@ -1607,7 +1618,7 @@ int nua_stack_get_params(nua_t *nua, nua_handle_t *nh, nua_event_t e,
|
||||
|
||||
TAG_NEXT(media_params));
|
||||
|
||||
nua_stack_event(nua, nh, NULL, nua_r_get_params, SIP_200_OK, TAG_NEXT(lst));
|
||||
nua_stack_event(nua, nh, NULL, nua_r_get_params, SIP_200_OK, lst);
|
||||
|
||||
su_home_deinit(tmphome);
|
||||
|
||||
|
@ -95,9 +95,11 @@ typedef struct nua_handle_preferences
|
||||
unsigned nhp_service_route_enable:1;
|
||||
/** Enable Path */
|
||||
unsigned nhp_path_enable:1;
|
||||
/** Authentication cache policy */
|
||||
unsigned nhp_auth_cache:1;
|
||||
|
||||
/** Always include id with Event: refer */
|
||||
unsigned nhp_refer_with_id:1;
|
||||
|
||||
unsigned:0;
|
||||
|
||||
/* Default lifetime for implicit subscriptions created by REFER */
|
||||
@ -157,6 +159,7 @@ typedef struct nua_handle_preferences
|
||||
unsigned nhb_media_features:1;
|
||||
unsigned nhb_service_route_enable:1;
|
||||
unsigned nhb_path_enable:1;
|
||||
unsigned nhb_auth_cache:1;
|
||||
unsigned nhb_refer_with_id:1;
|
||||
unsigned nhb_refer_expires:1;
|
||||
unsigned nhb_substate:1;
|
||||
@ -166,8 +169,8 @@ typedef struct nua_handle_preferences
|
||||
|
||||
unsigned nhb_allow:1;
|
||||
unsigned nhb_supported:1;
|
||||
unsigned nhb_allow_events:1;
|
||||
unsigned :0; /* at most 32 bits ... */
|
||||
unsigned nhb_allow_events:1;
|
||||
unsigned nhb_user_agent:1;
|
||||
unsigned nhb_organization:1;
|
||||
|
||||
@ -223,4 +226,9 @@ typedef struct nua_handle_preferences
|
||||
(NHP_ISSET((nh)->nh_prefs, pref) && \
|
||||
(nh)->nh_nua->nua_dhandle->nh_prefs != (nh)->nh_prefs)
|
||||
|
||||
/* Check if preference has been set by applicationx */
|
||||
#define NUA_PISSET(nua, nh, pref) \
|
||||
(NHP_ISSET((nua)->nua_dhandle->nh_prefs, pref) || \
|
||||
((nh) && NHP_ISSET((nh)->nh_prefs, pref)))
|
||||
|
||||
#endif /* NUA_PARAMS_H */
|
||||
|
@ -45,9 +45,6 @@
|
||||
#include <sofia-sip/sip_protos.h>
|
||||
#include <sofia-sip/sip_status.h>
|
||||
|
||||
#define NTA_LEG_MAGIC_T struct nua_handle_s
|
||||
#define NTA_OUTGOING_MAGIC_T struct nua_handle_s
|
||||
|
||||
#include "nua_stack.h"
|
||||
|
||||
/* ====================================================================== */
|
||||
@ -55,6 +52,7 @@
|
||||
|
||||
struct publish_usage {
|
||||
sip_etag_t *pu_etag;
|
||||
int pu_published;
|
||||
};
|
||||
|
||||
static char const *nua_publish_usage_name(nua_dialog_usage_t const *du);
|
||||
@ -116,14 +114,6 @@ void nua_publish_usage_remove(nua_handle_t *nh,
|
||||
/* ======================================================================== */
|
||||
/* PUBLISH */
|
||||
|
||||
static int nua_stack_publish2(nua_t *nua, nua_handle_t *nh, nua_event_t e,
|
||||
int refresh, tagi_t const *tags);
|
||||
|
||||
static int process_response_to_publish(nua_handle_t *nh,
|
||||
nta_outgoing_t *orq,
|
||||
sip_t const *sip);
|
||||
|
||||
|
||||
/**@fn \
|
||||
* void nua_publish(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
|
||||
*
|
||||
@ -237,213 +227,213 @@ void nua_unpublish(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
|
||||
* @END_NUA_EVENT
|
||||
*/
|
||||
|
||||
int nua_stack_publish(nua_t *nua, nua_handle_t *nh, nua_event_t e,
|
||||
tagi_t const *tags)
|
||||
static int nua_publish_client_template(nua_client_request_t *cr,
|
||||
msg_t **return_msg,
|
||||
tagi_t const *tags);
|
||||
static int nua_publish_client_init(nua_client_request_t *cr,
|
||||
msg_t *, sip_t *,
|
||||
tagi_t const *tags);
|
||||
static int nua_publish_client_request(nua_client_request_t *cr,
|
||||
msg_t *, sip_t *,
|
||||
tagi_t const *tags);
|
||||
static int nua_publish_client_response(nua_client_request_t *cr,
|
||||
int status, char const *phrase,
|
||||
sip_t const *sip);
|
||||
|
||||
static nua_client_methods_t const nua_publish_client_methods = {
|
||||
SIP_METHOD_PUBLISH,
|
||||
0,
|
||||
{
|
||||
/* create_dialog */ 0,
|
||||
/* in_dialog */ 0,
|
||||
/* target refresh */ 0
|
||||
},
|
||||
nua_publish_client_template,
|
||||
nua_publish_client_init,
|
||||
nua_publish_client_request,
|
||||
/* nua_publish_client_check_restart */ NULL,
|
||||
nua_publish_client_response,
|
||||
/* nua_publish_client_preliminary */ NULL
|
||||
};
|
||||
|
||||
/**@internal Send PUBLISH. */
|
||||
int nua_stack_publish(nua_t *nua,
|
||||
nua_handle_t *nh,
|
||||
nua_event_t e,
|
||||
tagi_t const *tags)
|
||||
{
|
||||
return nua_stack_publish2(nua, nh, e, 0, tags);
|
||||
return nua_client_create(nh, e, &nua_publish_client_methods, tags);
|
||||
}
|
||||
|
||||
static
|
||||
int nua_stack_publish2(nua_t *nua, nua_handle_t *nh, nua_event_t e,
|
||||
int refresh,
|
||||
tagi_t const *tags)
|
||||
static int nua_publish_client_template(nua_client_request_t *cr,
|
||||
msg_t **return_msg,
|
||||
tagi_t const *tags)
|
||||
{
|
||||
nua_dialog_usage_t *du;
|
||||
|
||||
if (cr->cr_event == nua_r_publish)
|
||||
return 0;
|
||||
|
||||
du = nua_dialog_usage_get(cr->cr_owner->nh_ds, nua_publish_usage, NULL);
|
||||
if (du && du->du_cr) {
|
||||
if (nua_client_set_target(cr, du->du_cr->cr_target) < 0)
|
||||
return -1;
|
||||
*return_msg = msg_copy(du->du_cr->cr_msg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nua_publish_client_init(nua_client_request_t *cr,
|
||||
msg_t *msg, sip_t *sip,
|
||||
tagi_t const *tags)
|
||||
{
|
||||
nua_handle_t *nh = cr->cr_owner;
|
||||
nua_dialog_usage_t *du;
|
||||
struct publish_usage *pu;
|
||||
nua_client_request_t *cr = nh->nh_ds->ds_cr;
|
||||
msg_t *msg = NULL;
|
||||
sip_t *sip;
|
||||
int remove_body = 0;
|
||||
|
||||
if (nua_stack_set_handle_special(nh, nh_has_nothing, nua_r_publish) < 0)
|
||||
return UA_EVENT2(e, 900, "Invalid handle for PUBLISH");
|
||||
|
||||
if (cr->cr_orq) {
|
||||
return UA_EVENT2(e, 900, "Request already in progress");
|
||||
}
|
||||
|
||||
nua_stack_init_handle(nua, nh, TAG_NEXT(tags));
|
||||
|
||||
if (e == nua_r_unpublish) {
|
||||
du = nua_dialog_usage_get(nh->nh_ds, nua_publish_usage, NULL);
|
||||
if (du)
|
||||
refresh = 1;
|
||||
else
|
||||
du = nua_dialog_usage_add(nh, nh->nh_ds, nua_publish_usage, NULL);
|
||||
}
|
||||
else if (!refresh)
|
||||
if (cr->cr_event == nua_r_publish) {
|
||||
du = nua_dialog_usage_add(nh, nh->nh_ds, nua_publish_usage, NULL);
|
||||
if (!du)
|
||||
return -1;
|
||||
pu = nua_dialog_usage_private(du);
|
||||
pu->pu_published = 0;
|
||||
if (sip->sip_if_match) {
|
||||
pu->pu_etag = sip_etag_dup(nh->nh_home, sip->sip_if_match);
|
||||
if (!pu->pu_etag)
|
||||
return -1;
|
||||
sip_header_remove(msg, sip, (sip_header_t *)sip->sip_if_match);
|
||||
}
|
||||
}
|
||||
else
|
||||
du = nua_dialog_usage_get(nh->nh_ds, nua_publish_usage, NULL);
|
||||
|
||||
if (!du)
|
||||
return UA_EVENT1(e, NUA_INTERNAL_ERROR);
|
||||
|
||||
nua_dialog_usage_reset_refresh(du);
|
||||
pu = nua_dialog_usage_private(du); assert(pu);
|
||||
|
||||
if (refresh) {
|
||||
if (cr->cr_msg)
|
||||
msg_destroy(cr->cr_msg);
|
||||
cr->cr_msg = msg_copy(du->du_msg);
|
||||
remove_body = pu->pu_etag != NULL;
|
||||
}
|
||||
|
||||
msg = nua_creq_msg(nua, nh, cr, cr->cr_retry_count || refresh,
|
||||
SIP_METHOD_PUBLISH,
|
||||
NUTAG_ADD_CONTACT(0),
|
||||
TAG_NEXT(tags));
|
||||
sip = sip_object(msg);
|
||||
|
||||
if (!msg || !sip)
|
||||
goto error;
|
||||
|
||||
du->du_terminating =
|
||||
e != nua_r_publish ||
|
||||
(sip->sip_expires && sip->sip_expires->ex_delta == 0);
|
||||
|
||||
if (!du->du_terminating && !refresh) {
|
||||
/* Save template */
|
||||
if (du->du_msg)
|
||||
msg_destroy(du->du_msg);
|
||||
du->du_msg = msg_ref_create(cr->cr_msg);
|
||||
}
|
||||
|
||||
cr->cr_orq =
|
||||
nta_outgoing_mcreate(nua->nua_nta,
|
||||
process_response_to_publish, nh, NULL,
|
||||
msg,
|
||||
SIPTAG_IF_MATCH(pu->pu_etag),
|
||||
TAG_IF(remove_body, SIPTAG_PAYLOAD(NONE)),
|
||||
TAG_IF(remove_body, SIPTAG_CONTENT_TYPE(NONE)),
|
||||
TAG_IF(e != nua_r_publish,
|
||||
SIPTAG_EXPIRES_STR("0")),
|
||||
SIPTAG_END(), TAG_NEXT(tags));
|
||||
if (!cr->cr_orq)
|
||||
goto error;
|
||||
|
||||
cr->cr_usage = du;
|
||||
|
||||
return cr->cr_event = e;
|
||||
|
||||
error:
|
||||
msg_destroy(msg);
|
||||
if (!du->du_ready == 0)
|
||||
nua_dialog_usage_remove(nh, nh->nh_ds, du);
|
||||
return UA_EVENT1(e, NUA_INTERNAL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
restart_publish(nua_handle_t *nh, tagi_t *tags)
|
||||
{
|
||||
nua_creq_restart(nh, nh->nh_ds->ds_cr, process_response_to_publish, tags);
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int process_response_to_publish(nua_handle_t *nh,
|
||||
nta_outgoing_t *orq,
|
||||
sip_t const *sip)
|
||||
int nua_publish_client_request(nua_client_request_t *cr,
|
||||
msg_t *msg, sip_t *sip,
|
||||
tagi_t const *tags)
|
||||
{
|
||||
int status = sip->sip_status->st_status;
|
||||
nua_client_request_t *cr = nh->nh_ds->ds_cr;
|
||||
nua_dialog_usage_t *du = cr->cr_usage;
|
||||
struct publish_usage *pu = nua_dialog_usage_private(du);
|
||||
unsigned saved_retry_count = cr->cr_retry_count + 1;
|
||||
int un, done;
|
||||
sip_etag_t const *etag = NULL;
|
||||
|
||||
if (nua_creq_check_restart(nh, cr, orq, sip, restart_publish))
|
||||
return 0;
|
||||
un = cr->cr_terminating ||
|
||||
cr->cr_event != nua_r_publish ||
|
||||
(du && du->du_shutdown) ||
|
||||
(sip->sip_expires && sip->sip_expires->ex_delta == 0);
|
||||
cr->cr_terminating = un;
|
||||
done = un;
|
||||
|
||||
if (status < 200 || pu == NULL)
|
||||
return nua_stack_process_response(nh, cr, orq, sip, TAG_END());
|
||||
if (du) {
|
||||
struct publish_usage *pu = nua_dialog_usage_private(du);
|
||||
|
||||
if (pu->pu_etag)
|
||||
su_free(nh->nh_home, pu->pu_etag), pu->pu_etag = NULL;
|
||||
if (nua_client_bind(cr, du) < 0)
|
||||
return -1;
|
||||
if (pu->pu_published)
|
||||
done = 1;
|
||||
etag = pu->pu_etag;
|
||||
}
|
||||
|
||||
if (!du->du_terminating) {
|
||||
int retry = 0, invalid_expiration = 0;
|
||||
return nua_base_client_trequest(cr, msg, sip,
|
||||
SIPTAG_IF_MATCH(etag),
|
||||
TAG_IF(done, SIPTAG_PAYLOAD(NONE)),
|
||||
TAG_IF(done, SIPTAG_CONTENT_TYPE(NONE)),
|
||||
TAG_IF(un, SIPTAG_EXPIRES_STR("0")),
|
||||
TAG_NEXT(tags));
|
||||
}
|
||||
|
||||
if (status < 300) {
|
||||
if (!sip->sip_expires)
|
||||
invalid_expiration = 1;
|
||||
else if (sip->sip_expires->ex_delta == 0)
|
||||
retry = 1, invalid_expiration = 1;
|
||||
static int nua_publish_client_response(nua_client_request_t *cr,
|
||||
int status, char const *phrase,
|
||||
sip_t const *sip)
|
||||
{
|
||||
nua_handle_t *nh = cr->cr_owner;
|
||||
nua_dialog_usage_t *du = cr->cr_usage;
|
||||
|
||||
if (!cr->cr_terminated && du && sip) {
|
||||
struct publish_usage *pu = nua_dialog_usage_private(du);
|
||||
sip_expires_t const *ex = sip->sip_expires;
|
||||
|
||||
/* Reset state */
|
||||
pu->pu_published = 0;
|
||||
if (pu->pu_etag)
|
||||
su_free(nh->nh_home, pu->pu_etag), pu->pu_etag = NULL;
|
||||
|
||||
if (status == 412) {
|
||||
if (nua_client_restart(cr, 100, phrase))
|
||||
return 0;
|
||||
}
|
||||
else if (status == 412)
|
||||
retry = 1;
|
||||
else if (status < 300) {
|
||||
if (ex && ex->ex_delta == 0 &&
|
||||
nua_client_restart(cr, 100, "Trying re-PUBLISH"))
|
||||
return 0;
|
||||
|
||||
if (status < 300 && !invalid_expiration && !retry) {
|
||||
pu->pu_published = 1;
|
||||
pu->pu_etag = sip_etag_dup(nh->nh_home, sip->sip_etag);
|
||||
du->du_ready = 1;
|
||||
nua_dialog_usage_set_expires(du, sip->sip_expires->ex_delta);
|
||||
}
|
||||
else if (retry && saved_retry_count < NH_PGET(nh, retry_count)) {
|
||||
msg_t *response = nta_outgoing_getresponse(orq);
|
||||
nua_stack_event(nh->nh_nua, nh, response, cr->cr_event,
|
||||
100, "Trying re-PUBLISH",
|
||||
TAG_END());
|
||||
nua_creq_deinit(cr, orq);
|
||||
nua_stack_publish2(nh->nh_nua, nh, cr->cr_event, 1, NULL);
|
||||
cr->cr_retry_count = saved_retry_count;
|
||||
return 0;
|
||||
}
|
||||
else if (invalid_expiration) {
|
||||
msg_t *response = nta_outgoing_getresponse(orq);
|
||||
nua_stack_event(nh->nh_nua, nh, response, cr->cr_event,
|
||||
900, "Received Invalid Expiration Time",
|
||||
TAG_END());
|
||||
nua_dialog_usage_remove(nh, nh->nh_ds, cr->cr_usage);
|
||||
nua_creq_deinit(cr, orq);
|
||||
cr->cr_usage = NULL;
|
||||
return 0;
|
||||
|
||||
if (!ex || ex->ex_delta == 0 || !pu->pu_etag) {
|
||||
cr->cr_terminated = 1;
|
||||
|
||||
if (!ex || ex->ex_delta == 0)
|
||||
SET_STATUS(900, "Received Invalid Expiration Time");
|
||||
else
|
||||
SET_STATUS1(NUA_INTERNAL_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nua_stack_process_response(nh, cr, orq, sip, TAG_END());
|
||||
return nua_base_client_response(cr, status, phrase, sip, NULL);
|
||||
}
|
||||
|
||||
|
||||
static void nua_publish_usage_refresh(nua_handle_t *nh,
|
||||
nua_dialog_state_t *ds,
|
||||
nua_dialog_usage_t *du,
|
||||
sip_time_t now)
|
||||
nua_dialog_state_t *ds,
|
||||
nua_dialog_usage_t *du,
|
||||
sip_time_t now)
|
||||
{
|
||||
if (ds->ds_cr->cr_usage == du) /* Already publishing. */
|
||||
return;
|
||||
nua_stack_publish2(nh->nh_nua, nh, nua_r_publish, 1, NULL);
|
||||
nua_client_request_t *cr = du->du_cr;
|
||||
|
||||
if (cr) {
|
||||
if (nua_client_resend_request(cr, 0) >= 0)
|
||||
return;
|
||||
}
|
||||
|
||||
nua_stack_event(nh->nh_nua, nh, NULL,
|
||||
nua_r_publish, NUA_INTERNAL_ERROR,
|
||||
NULL);
|
||||
|
||||
nua_dialog_usage_remove(nh, ds, du);
|
||||
}
|
||||
|
||||
/** @interal Shut down PUBLISH usage.
|
||||
/** @interal Shut down PUBLISH usage.
|
||||
*
|
||||
* @retval >0 shutdown done
|
||||
* @retval 0 shutdown in progress
|
||||
* @retval <0 try again later
|
||||
*/
|
||||
static int nua_publish_usage_shutdown(nua_handle_t *nh,
|
||||
nua_dialog_state_t *ds,
|
||||
nua_dialog_usage_t *du)
|
||||
nua_dialog_state_t *ds,
|
||||
nua_dialog_usage_t *du)
|
||||
{
|
||||
nua_client_request_t *cr = ds->ds_cr;
|
||||
nua_client_request_t *cr = du->du_cr;
|
||||
|
||||
if (!cr->cr_usage) {
|
||||
/* Unpublish */
|
||||
nua_stack_publish2(nh->nh_nua, nh, nua_r_destroy, 1, NULL);
|
||||
return cr->cr_usage != du;
|
||||
if (cr) {
|
||||
if (nua_client_resend_request(cr, 1) >= 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!du->du_ready && !cr->cr_orq)
|
||||
return 1; /* had unauthenticated initial request */
|
||||
|
||||
return -1; /* Request in progress */
|
||||
/* XXX - report to user */
|
||||
nua_dialog_usage_remove(nh, ds, du);
|
||||
return 200;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* Server side */
|
||||
|
||||
static
|
||||
int respond_to_publish(nua_server_request_t *sr, tagi_t const *tags);
|
||||
|
||||
/** @NUA_EVENT nua_i_publish
|
||||
*
|
||||
* Incoming PUBLISH request.
|
||||
@ -453,7 +443,7 @@ int respond_to_publish(nua_server_request_t *sr, tagi_t const *tags);
|
||||
* events with nua_set_params() tag NUTAG_ALLOW_EVENTS().
|
||||
*
|
||||
* The nua_response() call responding to a PUBLISH request must have
|
||||
* NUTAG_WITH() (or NUTAG_WITH_CURRENT()/NUTAG_WITH_SAVED()) tag. Note that
|
||||
* NUTAG_WITH() (or NUTAG_WITH_THIS()/NUTAG_WITH_SAVED()) tag. Note that
|
||||
* a successful response to PUBLISH @b MUST include @Expires and @SIPETag
|
||||
* headers.
|
||||
*
|
||||
@ -481,48 +471,35 @@ int respond_to_publish(nua_server_request_t *sr, tagi_t const *tags);
|
||||
* @END_NUA_EVENT
|
||||
*/
|
||||
|
||||
int nua_stack_process_publish(nua_t *nua,
|
||||
nua_handle_t *nh,
|
||||
nta_incoming_t *irq,
|
||||
sip_t const *sip)
|
||||
int nua_publish_server_init(nua_server_request_t *sr);
|
||||
|
||||
nua_server_methods_t const nua_publish_server_methods =
|
||||
{
|
||||
SIP_METHOD_PUBLISH,
|
||||
nua_i_publish, /* Event */
|
||||
{
|
||||
0, /* Do not create dialog */
|
||||
0, /* Initial request */
|
||||
0, /* Not a target refresh request */
|
||||
1, /* Add Contact */
|
||||
},
|
||||
nua_publish_server_init,
|
||||
nua_base_server_preprocess,
|
||||
nua_base_server_params,
|
||||
nua_base_server_respond,
|
||||
nua_base_server_report,
|
||||
};
|
||||
|
||||
int nua_publish_server_init(nua_server_request_t *sr)
|
||||
{
|
||||
nua_server_request_t *sr, sr0[1];
|
||||
sip_allow_events_t *allow_events = NUA_PGET(nua, nh, allow_events);
|
||||
sip_event_t *o = sip->sip_event;
|
||||
sip_allow_events_t *allow_events = NH_PGET(sr->sr_owner, allow_events);
|
||||
sip_event_t *o = sr->sr_request.sip->sip_event;
|
||||
char const *event = o ? o->o_type : NULL;
|
||||
|
||||
sr = SR_INIT(sr0);
|
||||
|
||||
if (!allow_events)
|
||||
SR_STATUS1(sr, SIP_501_NOT_IMPLEMENTED);
|
||||
return SR_STATUS1(sr, SIP_501_NOT_IMPLEMENTED);
|
||||
else if (!event || !msg_header_find_param(allow_events->k_common, event))
|
||||
SR_STATUS1(sr, SIP_489_BAD_EVENT);
|
||||
return SR_STATUS1(sr, SIP_489_BAD_EVENT);
|
||||
|
||||
sr = nua_server_request(nua, nh, irq, sip, sr, sizeof *sr,
|
||||
respond_to_publish, 0);
|
||||
|
||||
return nua_stack_server_event(nua, sr, nua_i_publish, TAG_END());
|
||||
}
|
||||
|
||||
static
|
||||
int respond_to_publish(nua_server_request_t *sr, tagi_t const *tags)
|
||||
{
|
||||
nua_handle_t *nh = sr->sr_owner;
|
||||
nua_t *nua = nh->nh_nua;
|
||||
msg_t *msg;
|
||||
|
||||
msg = nua_server_response(sr, sr->sr_status, sr->sr_phrase, TAG_NEXT(tags));
|
||||
|
||||
if (msg) {
|
||||
nta_incoming_mreply(sr->sr_irq, msg);
|
||||
}
|
||||
else {
|
||||
SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR);
|
||||
nta_incoming_treply(sr->sr_irq, sr->sr_status, sr->sr_phrase, TAG_END());
|
||||
nua_stack_event(nua, nh, NULL,
|
||||
nua_i_error, 900, "PUBLISH Response Fails",
|
||||
TAG_END());
|
||||
}
|
||||
|
||||
return sr->sr_status >= 200 ? sr->sr_status : 0;
|
||||
return 0;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -44,8 +44,6 @@
|
||||
#include <sofia-sip/sip_status.h>
|
||||
#include <sofia-sip/sip_util.h>
|
||||
|
||||
#define NTA_LEG_MAGIC_T struct nua_handle_s
|
||||
#define NTA_OUTGOING_MAGIC_T struct nua_handle_s
|
||||
#define NTA_INCOMING_MAGIC_T struct nua_handle_s
|
||||
#define NTA_RELIABLE_MAGIC_T struct nua_handle_s
|
||||
|
||||
@ -62,7 +60,7 @@
|
||||
* the REGISTER method with NUTAG_ALLOW() tag.
|
||||
*
|
||||
* The nua_response() call responding to a REGISTER request must have
|
||||
* NUTAG_WITH() (or NUTAG_WITH_CURRENT()/NUTAG_WITH_SAVED()) tag. Note that
|
||||
* NUTAG_WITH() (or NUTAG_WITH_THIS()/NUTAG_WITH_SAVED()) tag. Note that
|
||||
* a successful response to REGISTER @b MUST include the @Contact header
|
||||
* bound to the the AoR URI (in @To header).
|
||||
*
|
||||
@ -89,15 +87,19 @@
|
||||
* @END_NUA_EVENT
|
||||
*/
|
||||
|
||||
int nua_stack_process_register(nua_t *nua,
|
||||
nua_handle_t *nh,
|
||||
nta_incoming_t *irq,
|
||||
sip_t const *sip)
|
||||
{
|
||||
nua_server_request_t *sr, sr0[1];
|
||||
|
||||
sr = nua_server_request(nua, nh, irq, sip, SR_INIT(sr0), sizeof *sr,
|
||||
nua_default_respond, 0);
|
||||
|
||||
return nua_stack_server_event(nua, sr, nua_i_register, TAG_END());
|
||||
}
|
||||
nua_server_methods_t const nua_register_server_methods =
|
||||
{
|
||||
SIP_METHOD_REGISTER,
|
||||
nua_i_register, /* Event */
|
||||
{
|
||||
0, /* Do not create dialog */
|
||||
0, /* Initial request */
|
||||
0, /* Not a target refresh request */
|
||||
0, /* Do not add Contact */
|
||||
},
|
||||
nua_base_server_init,
|
||||
nua_base_server_preprocess,
|
||||
nua_base_server_params,
|
||||
nua_base_server_respond,
|
||||
nua_base_server_report,
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -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
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
|
||||
|
@ -70,17 +70,11 @@ int outbound_set_options(outbound_t *ob,
|
||||
unsigned dgram_interval,
|
||||
unsigned stream_interval);
|
||||
|
||||
int outbound_set_features(outbound_t *ob, char *features);
|
||||
int outbound_get_contacts(outbound_t *ob,
|
||||
sip_contact_t **return_current_contact,
|
||||
sip_contact_t **return_previous_contact);
|
||||
|
||||
nta_outgoing_t *outbound_register_request(outbound_t *ob, int terminating,
|
||||
sip_contact_t *stack_contact,
|
||||
nta_agent_t *nta,
|
||||
nta_response_f *callback,
|
||||
nta_outgoing_magic_t *magic,
|
||||
url_string_t *next_hop,
|
||||
msg_t *msg,
|
||||
tag_type_t tag, tag_value_t value,
|
||||
...);
|
||||
int outbound_start_registering(outbound_t *ob);
|
||||
|
||||
int outbound_register_response(outbound_t *ob,
|
||||
int terminating,
|
||||
@ -102,6 +96,8 @@ int outbound_set_contact(outbound_t *ob,
|
||||
|
||||
sip_contact_t const *outbound_dialog_contact(outbound_t const *ob);
|
||||
|
||||
sip_contact_t const *outbound_dialog_gruu(outbound_t const *ob);
|
||||
|
||||
int outbound_gruuize(outbound_t *ob, sip_t const *sip);
|
||||
|
||||
void outbound_start_keepalive(outbound_t *ob,
|
||||
@ -122,6 +118,7 @@ struct outbound_owner_vtable
|
||||
int oo_size;
|
||||
sip_contact_t *(*oo_contact)(outbound_owner_t *,
|
||||
su_home_t *home,
|
||||
int used_in_dialog,
|
||||
char const *extra_username,
|
||||
sip_via_t const *v,
|
||||
char const *transport,
|
||||
|
@ -262,6 +262,12 @@ SOFIAPUBFUN char const *nua_event_name(nua_event_t event);
|
||||
/** Get name for NUA callstate. */
|
||||
SOFIAPUBFUN char const *nua_callstate_name(enum nua_callstate state);
|
||||
|
||||
/** Return name of subscription state. @NEW_1_12_5. */
|
||||
SOFIAPUBFUN char const *nua_substate_name(enum nua_substate substate);
|
||||
|
||||
/** Convert string to enum nua_substate. @NEW_1_12_5. */
|
||||
SOFIAPUBFUN enum nua_substate nua_substate_make(char const *sip_substate);
|
||||
|
||||
/** Send SIP REGISTER request to the registrar. */
|
||||
SOFIAPUBFUN void nua_register(nua_handle_t *nh, tag_type_t, tag_value_t, ...);
|
||||
|
||||
@ -340,6 +346,9 @@ SOFIAPUBFUN void nua_respond(nua_handle_t *nh,
|
||||
tag_type_t, tag_value_t,
|
||||
...);
|
||||
|
||||
/** Check if event can be responded with nua_respond() */
|
||||
SOFIAPUBFUN int nua_event_is_incoming_request(nua_event_t e);
|
||||
|
||||
#define nua_handle_home(nh) ((su_home_t *)(nh))
|
||||
|
||||
/** Generate an instance identifier */
|
||||
|
@ -157,6 +157,9 @@ SOFIAPUBVAR tag_typedef_t nutag_with;
|
||||
*/
|
||||
#define NUTAG_WITH_THIS(nua) nutag_with, tag_ptr_v(nua_current_request((nua)))
|
||||
|
||||
#define NUTAG_WITH_CURRENT(nua) \
|
||||
nutag_with, tag_ptr_v(nua_current_request((nua)))
|
||||
|
||||
/**Specify request to respond to.
|
||||
*
|
||||
* @par Used with
|
||||
@ -174,6 +177,26 @@ SOFIAPUBVAR tag_typedef_t nutag_with;
|
||||
*/
|
||||
#define NUTAG_WITH_SAVED(e) nutag_with, tag_ptr_v(nua_saved_event_request((e)))
|
||||
|
||||
/**An (extension) method is used to create dialog or refresh target.
|
||||
*
|
||||
* @par Used with
|
||||
* nua_method()
|
||||
*
|
||||
* @par Parameter type
|
||||
* unsigned int (0, 1, 2)
|
||||
*
|
||||
* @par Values
|
||||
* - 0 if dialog target is not refreshed
|
||||
* - 1 if dialog target is refreshed
|
||||
* - > 1 if dialog is to be created
|
||||
*
|
||||
* @NEW_1_12_6.
|
||||
*
|
||||
* @sa nua_method(), #nua_i_method
|
||||
*/
|
||||
#define NUTAG_DIALOG(b) nutag_dialog, tag_uint_v((b))
|
||||
SOFIAPUBVAR tag_typedef_t nutag_dialog;
|
||||
|
||||
/**Set request retry count.
|
||||
*
|
||||
* Retry count determines how many times stack will automatically retry
|
||||
@ -451,8 +474,8 @@ SOFIAPUBVAR tag_typedef_t nutag_include_extra_sdp_ref;
|
||||
*
|
||||
* @par Used with
|
||||
* nua_invite() \n
|
||||
* nua_set_params() \n
|
||||
* nua_get_params()
|
||||
* nua_set_params(), nua_set_hparams(),
|
||||
* nua_get_params(), nua_get_hparams()
|
||||
*
|
||||
* @par Parameter type
|
||||
* int (enum nua_af)
|
||||
@ -471,40 +494,48 @@ SOFIAPUBVAR tag_typedef_t nutag_invite_timer_ref;
|
||||
|
||||
/**Default session timer in seconds.
|
||||
*
|
||||
* Set default session timer in seconds when using session timer extension.
|
||||
* The value given here is the proposed session expiration time in seconds.
|
||||
* Note that the session timer extension is ponly used
|
||||
* Set default value for session timer in seconds when the session timer
|
||||
* extension is used. The tag value is the proposed session expiration time
|
||||
* in seconds, the session is refreshed twice during the expiration time.
|
||||
*
|
||||
* @par Sending INVITE and UPDATE Requests
|
||||
*
|
||||
* If NUTAG_SESSION_TIMER() is used with non-zero value, the value is
|
||||
* used in the @SessionExpires header included in the INVITE or UPDATE
|
||||
* requests. The intermediate proxies or the ultimate destination can lower
|
||||
* the interval in @SessionExpires header. If the value is too low, they can
|
||||
* If NUTAG_SESSION_TIMER() is used with non-zero value, the value is used
|
||||
* in the @SessionExpires header included in the INVITE or UPDATE requests.
|
||||
* The intermediate proxies or the ultimate destination can lower the
|
||||
* interval in @SessionExpires header. If the value is too low, they can
|
||||
* reject the request with the status code <i>422 Session Timer Too
|
||||
* Small</i>. When Re-INVITE will be sent in given intervals. In that case,
|
||||
* @b nua retries the request automatically.
|
||||
*
|
||||
* @par Returning Response to the INVITE and UPDATE Requests
|
||||
* Small</i>. In that case, @b nua increases the value of @SessionExpires
|
||||
* header and retries the request automatically.
|
||||
*
|
||||
* @par Returning a Response to the INVITE and UPDATE Requests
|
||||
*
|
||||
* The NUTAG_SESSION_TIMER() value is also used when sending the final
|
||||
* response to the INVITE or UPDATE requests. If the NUTAG_SESSION_TIMER()
|
||||
* value is 0 or the value in the @SessionExpires header of the requeast is
|
||||
* value is 0 or the value in the @SessionExpires header of the request is
|
||||
* lower than the value in NUTAG_SESSION_TIMER(), the value from the
|
||||
* incoming @SessionExpires header is used. However, if the value in
|
||||
* @SessionExpires is lower than the minimal acceptable session expiration
|
||||
* interval specified with the tag NUTAG_MIN_SE() the request is
|
||||
* automatically rejected with <i>422 Session Timer Too Small</i>.
|
||||
*
|
||||
* @par Refreshes
|
||||
*
|
||||
* After the initial INVITE request, the SIP session is refreshed at the
|
||||
* intervals indicated by the @SessionExpires header returned in the 2XX
|
||||
* response. The party indicated with the "refresher" parameter of the
|
||||
* @SessionExpires header sends a re-INVITE requests (or an UPDATE
|
||||
* request if NUTAG_UPDATE_REFRESH(1) parameter tag has been set).
|
||||
*
|
||||
* @par When to Use NUTAG_SESSION_TIMER()?
|
||||
*
|
||||
* The session time extension is enabled ("timer" feature tag is included in
|
||||
* @Supported header) but not activated by default (no @SessionExpires
|
||||
* header is included in the requests or responses by default). Using
|
||||
* non-zero value with NUTAG_SESSION_TIMER() activates it. When the
|
||||
* extension is activated, @nua refreshes the call state by sending periodic
|
||||
* re-INVITE or UPDATE requests unless the remote end indicated that it will
|
||||
* take care of refreshes.
|
||||
* non-zero value with NUTAG_SESSION_TIMER() or NUTAG_SESSION_REFRESHER()
|
||||
* activates it. When the extension is activated, @nua refreshes the call
|
||||
* state by sending periodic re-INVITE or UPDATE requests unless the remote
|
||||
* end indicated that it will take care of refreshes.
|
||||
*
|
||||
* The session timer extension is mainly useful for proxies or back-to-back
|
||||
* user agents that keep call state. The call state is "soft" meaning that
|
||||
@ -512,6 +543,10 @@ SOFIAPUBVAR tag_typedef_t nutag_invite_timer_ref;
|
||||
* will be destroyed. An ordinary user-agent can also make use of session
|
||||
* timer if it cannot get any activity feedback from RTP or other media.
|
||||
*
|
||||
* @note The session timer extension is used only if the feature
|
||||
* tag "timer" is listed in the @Supported header, set by NUTAG_SUPPORTED(),
|
||||
* SIPTAG_SUPPORTED(), or SIPTAG_SUPPORTED_STR() tags.
|
||||
*
|
||||
* @par Used with
|
||||
* nua_invite(), nua_update(), nua_respond() \n
|
||||
* nua_set_params() or nua_set_hparams() \n
|
||||
@ -530,8 +565,8 @@ SOFIAPUBVAR tag_typedef_t nutag_invite_timer_ref;
|
||||
* Corresponding tag taking reference parameter is NUTAG_SESSION_TIMER_REF()
|
||||
*
|
||||
* @sa NUTAG_SUPPORTED(), NUTAG_MIN_SE(), NUTAG_SESSION_REFRESHER(),
|
||||
* nua_invite(), #nua_r_invite, #nua_i_invite, nua_update(), #nua_r_update,
|
||||
* #nua_i_update,
|
||||
* nua_invite(), #nua_r_invite, #nua_i_invite, nua_respond(),
|
||||
* nua_update(), #nua_r_update, #nua_i_update,
|
||||
* NUTAG_UPDATE_REFRESH(), @RFC4028, @SessionExpires, @MinSE
|
||||
*/
|
||||
#define NUTAG_SESSION_TIMER(x) nutag_session_timer, tag_uint_v((x))
|
||||
@ -571,6 +606,7 @@ SOFIAPUBVAR tag_typedef_t nutag_min_se;
|
||||
#define NUTAG_MIN_SE_REF(x) nutag_min_se_ref, tag_uint_vr((&(x)))
|
||||
SOFIAPUBVAR tag_typedef_t nutag_min_se_ref;
|
||||
|
||||
/** Enumeration type of NUTAG_SESSION_REFRESHER(). */
|
||||
enum nua_session_refresher {
|
||||
nua_no_refresher, /**< Disable session timer. */
|
||||
nua_local_refresher, /**< Session refresh by local end. */
|
||||
@ -1074,7 +1110,7 @@ SOFIAPUBVAR tag_typedef_t nutag_registrar_ref;
|
||||
*
|
||||
* The outbound option string can specify how the NAT traversal is handled.
|
||||
* The option tokens are as follows:
|
||||
* - "gruuize": try to generate a GRUU
|
||||
* - "gruuize": try to generate a GRUU contact from REGISTER response
|
||||
* - "outbound": use SIP outbound extension (off by default)
|
||||
* - "validate": validate registration behind a NAT by sending OPTIONS to self
|
||||
* - "natify": try to traverse NAT
|
||||
@ -1084,6 +1120,10 @@ SOFIAPUBVAR tag_typedef_t nutag_registrar_ref;
|
||||
* An option token with "no-" or "not-" prefix turns the option off. For
|
||||
* example, if you want to try to traverse NATs but not to use OPTIONS
|
||||
* keepalive, use NUTAG_OUTBOUND("natify no-options-keepalive").
|
||||
*
|
||||
* An empty string can be passed to let the stack choose the
|
||||
* default values for outbound usage (in the 1.12.5 release, the
|
||||
* defaults are: "gruuize no-outbound validate use-port options-keepalive").
|
||||
*
|
||||
* @note
|
||||
* Options string is used so that no new tags need to be added when the
|
||||
@ -1207,7 +1247,7 @@ SOFIAPUBVAR tag_typedef_t nutag_outbound_set4_ref;
|
||||
* nua_create()
|
||||
*
|
||||
* @par Parameter type
|
||||
* msg_mclass_t *
|
||||
* msg_mclass_t const *
|
||||
*
|
||||
* @par Values
|
||||
* Pointer to an extended SIP parser.
|
||||
@ -1242,7 +1282,44 @@ SOFIAPUBVAR tag_typedef_t nutag_auth;
|
||||
#define NUTAG_AUTH_REF(x) nutag_auth_ref, tag_str_vr(&(x))
|
||||
SOFIAPUBVAR tag_typedef_t nutag_auth_ref;
|
||||
|
||||
/** Authentication caching policy
|
||||
*
|
||||
* @par Used with
|
||||
* nua_set_params(), nua_set_hparams() \n
|
||||
* nua_get_params(), nua_get_hparams() \n
|
||||
* @NUA_HPARAM_CALLS
|
||||
*
|
||||
* @par Parameter type
|
||||
* enum nua_auth_cache
|
||||
*
|
||||
* @par Values
|
||||
* - nua_auth_cache_dialog (0) - include credentials within dialog
|
||||
* - nua_auth_cache_challenged (1) - include credentials only when
|
||||
* challenged
|
||||
*
|
||||
* Corresponding tag taking reference parameter is NUTAG_AUTH_CACHE_REF().
|
||||
*
|
||||
* @NEW_1_12_6
|
||||
*/
|
||||
#define NUTAG_AUTH_CACHE(x) nutag_auth_cache, tag_int_v(x)
|
||||
SOFIAPUBVAR tag_typedef_t nutag_auth_cache;
|
||||
|
||||
#define NUTAG_AUTH_CACHE_REF(x) nutag_auth_cache_ref, tag_int_vr(&(x))
|
||||
SOFIAPUBVAR tag_typedef_t nutag_auth_cache_ref;
|
||||
|
||||
/** Authentication caching policy. @NEW_1_12_6 */
|
||||
enum nua_auth_cache {
|
||||
/** Include credentials within dialog (default) */
|
||||
nua_auth_cache_dialog = 0,
|
||||
/** Include credentials only when challenged */
|
||||
nua_auth_cache_challenged = 1,
|
||||
_nua_auth_cache_invalid
|
||||
};
|
||||
|
||||
/** Keepalive interval in milliseconds.
|
||||
*
|
||||
* This setting applies to OPTIONS/STUN keepalives. See documentation
|
||||
* for nua_register() for more detailed information.
|
||||
*
|
||||
* @par Used with
|
||||
* nua_register() \n
|
||||
@ -1268,6 +1345,8 @@ SOFIAPUBVAR tag_typedef_t nutag_keepalive;
|
||||
SOFIAPUBVAR tag_typedef_t nutag_keepalive_ref;
|
||||
|
||||
/** Transport-level keepalive interval for streams.
|
||||
*
|
||||
* See documentation for nua_register() for more detailed information.
|
||||
*
|
||||
* @par Used with
|
||||
* nua_register() \n
|
||||
@ -1327,6 +1406,7 @@ SOFIAPUBVAR tag_typedef_t nutag_authtime_ref;
|
||||
*
|
||||
* @par Used with
|
||||
* nua_register(), nua_set_hparams(), nua_set_params().
|
||||
* nua_invite(), nua_respond(), nua_subscribe(), nua_notify()
|
||||
*
|
||||
* @par Parameter type
|
||||
* string (char *)
|
||||
@ -1358,6 +1438,7 @@ SOFIAPUBVAR tag_typedef_t nutag_m_display_ref;
|
||||
*
|
||||
* @par Used with
|
||||
* nua_register(), nua_set_hparams(), nua_set_params().
|
||||
* nua_invite(), nua_respond(), nua_subscribe(), nua_notify()
|
||||
*
|
||||
* @par Parameter type
|
||||
* string (char *)
|
||||
@ -1388,7 +1469,8 @@ SOFIAPUBVAR tag_typedef_t nutag_m_username_ref;
|
||||
* user-agent.
|
||||
*
|
||||
* @par Used with
|
||||
* nua_register(), nua_set_hparams(), nua_set_params().
|
||||
* nua_register(), nua_set_hparams(), nua_set_params(),
|
||||
* nua_invite(), nua_respond(), nua_subscribe(), nua_notify()
|
||||
*
|
||||
* @par Parameter type
|
||||
* string (char *)
|
||||
@ -1735,7 +1817,8 @@ SOFIAPUBVAR tag_typedef_t nutag_allow_ref;
|
||||
*
|
||||
* Corresponding tag taking reference parameter is NUTAG_APPL_METHOD_REF()
|
||||
*
|
||||
* @since Working since @VERSION_1_12_5.
|
||||
* @since Working since @VERSION_1_12_5. Handling of client-side PRACK and
|
||||
* UPDATE was fixed in @VERSION_1_12_6.
|
||||
*/
|
||||
#define NUTAG_APPL_METHOD(x) nutag_appl_method, tag_str_v(x)
|
||||
SOFIAPUBVAR tag_typedef_t nutag_appl_method;
|
||||
@ -1859,26 +1942,39 @@ enum nua_callstate {
|
||||
/** Get name for NUA call state */
|
||||
SOFIAPUBFUN char const *nua_callstate_name(enum nua_callstate state);
|
||||
|
||||
/** Subscription state
|
||||
/**Subscription state.
|
||||
*
|
||||
* @par Used with
|
||||
* #nua_notify() \n
|
||||
* #nua_r_subscribe \n
|
||||
* #nua_i_notify
|
||||
* #nua_i_notify \n
|
||||
* #nua_i_subscribe \n
|
||||
* #nua_r_notify \n
|
||||
* nua_notify() \n
|
||||
* nua_respond() to SUBSCRIBE
|
||||
*
|
||||
* @par Parameter type
|
||||
* int
|
||||
*
|
||||
* @par Values
|
||||
* @c nua_substate_embryonic (0) \n
|
||||
* @c nua_substate_pending (1) \n
|
||||
* @c nua_substate_active (2) \n
|
||||
* @c nua_substate_terminated (3) \n
|
||||
* - #nua_substate_embryonic (0)
|
||||
* - #nua_substate_pending (1)
|
||||
* - #nua_substate_active (2)
|
||||
* - #nua_substate_terminated (3)
|
||||
*
|
||||
* see
|
||||
* <a href="http://www.ietf.org/rfc/rfc3265.txt">RFC 3265</a>
|
||||
* Note that the @SubscriptionState or @Expires headers specified by
|
||||
* application overrides the subscription state specified by
|
||||
* NUTAG_SUBSTATE(). Application can terminate subscription by including
|
||||
* NUTAG_SUBSTATE(nua_substate_terminated), @SubscriptionState with value
|
||||
* "terminated" or @Expires header with value 0 in the NOTIFY request sent
|
||||
* by nua_notify().
|
||||
*
|
||||
* @sa @RFC3265, @SubscriptionState, SIPTAG_SUBSCRIPTION_STATE(),
|
||||
* SIPTAG_SUBSCRIPTION_STATE_STR(), #nua_r_subscribe, #nua_i_subscribe,
|
||||
* #nua_i_refer, #nua_r_notify, #nua_i_notify.
|
||||
*
|
||||
* Corresponding tag taking reference parameter is NUTAG_SUBSTATE_REF()
|
||||
*/
|
||||
*/
|
||||
#define NUTAG_SUBSTATE(x) nutag_substate, tag_int_v(x)
|
||||
SOFIAPUBVAR tag_typedef_t nutag_substate;
|
||||
|
||||
@ -1896,6 +1992,46 @@ enum nua_substate {
|
||||
nua_substate_terminated = nea_terminated /**< Terminated subscription */
|
||||
};
|
||||
|
||||
/** Return name of subscription state. @NEW_1_12_5. */
|
||||
SOFIAPUBFUN char const *nua_substate_name(enum nua_substate substate);
|
||||
|
||||
/** Convert string to enum nua_substate. @NEW_1_12_5. */
|
||||
SOFIAPUBFUN enum nua_substate nua_substate_make(char const *sip_substate);
|
||||
|
||||
/**Send unsolicited NOTIFY request.
|
||||
*
|
||||
* Some applications may require sending unsolicited NOTIFY requests, that
|
||||
* is, NOTIFY without SUBSCRIBE or REFER request sent by event watcher.
|
||||
* However, sending NOTIFY request requires an existing dialog usage by
|
||||
* default. If NUTAG_NEWSUB(1) is included in the nua_notify() the usage
|
||||
* is create the usage by itself.
|
||||
*
|
||||
* If you want to create a subscription that does not terminate immediately
|
||||
* include SIPTAG_SUBSCRIPTION_STATE_STR() with an "expires" parameter in
|
||||
* the argument list, too.
|
||||
*
|
||||
* @par Used with
|
||||
* nua_notify()
|
||||
*
|
||||
* @par Parameter type
|
||||
* int (boolean)
|
||||
*
|
||||
* @par Values
|
||||
* - 0 - false (default) - do not create new subscription
|
||||
* but reject NOTIFY with 481 locally \n
|
||||
* - 1 - true - create a subscription if it does not exist \n
|
||||
*
|
||||
* Corresponding tag taking reference parameter is NUTAG_NEWSUB().
|
||||
*
|
||||
* @since @NEW_1_12_5.
|
||||
*/
|
||||
#define NUTAG_NEWSUB(x) nutag_newsub, tag_bool_v(x)
|
||||
SOFIAPUBVAR tag_typedef_t nutag_newsub;
|
||||
|
||||
#define NUTAG_NEWSUB_REF(x) nutag_newsub_ref, tag_bool_vr(&(x))
|
||||
SOFIAPUBVAR tag_typedef_t nutag_newsub_ref;
|
||||
|
||||
|
||||
/**Default lifetime for implicit subscriptions created by REFER.
|
||||
*
|
||||
* Default expiration time in seconds for implicit subscriptions created by
|
||||
|
@ -101,24 +101,17 @@ int accept_pracked2(CONDITION_PARAMS)
|
||||
|
||||
save_event_in_list(ctx, event, ep, call);
|
||||
|
||||
switch (event) {
|
||||
case nua_i_prack:
|
||||
if (200 <= status && status < 300) {
|
||||
RESPOND(ep, call, nh, SIP_200_OK,
|
||||
NUTAG_INCLUDE_EXTRA_SDP(1),
|
||||
TAG_END());
|
||||
ep->next_condition = until_ready;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (callstate(tags)) {
|
||||
case nua_callstate_received:
|
||||
RESPOND(ep, call, nh, SIP_180_RINGING,
|
||||
TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
|
||||
TAG_END());
|
||||
RESPOND(ep, call, nh, SIP_200_OK,
|
||||
NUTAG_INCLUDE_EXTRA_SDP(1),
|
||||
TAG_END());
|
||||
return 0;
|
||||
case nua_callstate_ready:
|
||||
return 1;
|
||||
case nua_callstate_terminated:
|
||||
if (call)
|
||||
nua_handle_destroy(call->nh), call->nh = NULL;
|
||||
@ -170,6 +163,7 @@ int test_180rel(struct context *ctx)
|
||||
|
||||
nua_set_params(ctx->b.nua,
|
||||
NUTAG_EARLY_MEDIA(1),
|
||||
NUTAG_SESSION_TIMER(180),
|
||||
TAG_END());
|
||||
run_b_until(ctx, nua_r_set_params, until_final_response);
|
||||
|
||||
@ -411,17 +405,21 @@ int test_prack_auth(struct context *ctx)
|
||||
TEST_1(is_answer_recv(e->data->e_tags));
|
||||
TEST_1(!is_offer_sent(e->data->e_tags));
|
||||
|
||||
if (md5 && !md5sess) {
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
|
||||
TEST(e->data->e_status, 407);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
|
||||
|
||||
if (e->data->e_status != 200 && md5 && !md5sess) {
|
||||
if (e->data->e_status != 100) {
|
||||
TEST(e->data->e_status, 407);
|
||||
}
|
||||
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
|
||||
TEST_1(!is_answer_recv(e->data->e_tags));
|
||||
TEST_1(!is_offer_sent(e->data->e_tags));
|
||||
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
|
||||
}
|
||||
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
|
||||
TEST(e->data->e_status, 200);
|
||||
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
|
||||
@ -552,6 +550,8 @@ int ringing_pracked(CONDITION_PARAMS)
|
||||
}
|
||||
}
|
||||
|
||||
int respond_483_to_prack(CONDITION_PARAMS);
|
||||
|
||||
int test_183rel(struct context *ctx)
|
||||
{
|
||||
BEGIN();
|
||||
@ -661,30 +661,110 @@ int test_183rel(struct context *ctx)
|
||||
if (print_headings)
|
||||
printf("TEST NUA-10.2.1: PASSED\n");
|
||||
|
||||
/* Test for graceful termination by client because 483 sent to PRACK */
|
||||
if (print_headings)
|
||||
printf("TEST NUA-10.2.2: terminate call\n");
|
||||
printf("TEST NUA-10.2.2: graceful termination because PRACK fails\n");
|
||||
|
||||
BYE(b, b_call, b_call->nh, TAG_END());
|
||||
run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
|
||||
nua_set_hparams(b_call->nh, NUTAG_APPL_METHOD("PRACK"),
|
||||
NUTAG_AUTOANSWER(0), TAG_END());
|
||||
run_b_until(ctx, nua_r_set_params, NULL);
|
||||
|
||||
/* B transitions:
|
||||
READY --(T2)--> TERMINATING: nua_bye()
|
||||
TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
|
||||
INVITE(a, a_call, a_call->nh, TAG_END());
|
||||
|
||||
run_ab_until(ctx, -1, until_terminated, -1, respond_483_to_prack);
|
||||
|
||||
/* Client transitions:
|
||||
INIT -(C1)-> CALLING: nua_invite(), nua_i_state
|
||||
CALLING -(C2)-> TERMINATING: nua_r_invite, nua_i_state,
|
||||
nua_r_prack, nua_i_state
|
||||
TERMINATING -(T1)-> TERMINATED: nua_r_invite, nua_i_state
|
||||
*/
|
||||
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_bye);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
|
||||
TEST_1(!e->next);
|
||||
free_events_in_list(ctx, b->events);
|
||||
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
|
||||
TEST_1(is_offer_sent(e->data->e_tags));
|
||||
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST(e->data->e_status, 183);
|
||||
|
||||
/* A: READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state */
|
||||
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_bye);
|
||||
TEST(e->data->e_status, 200);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
|
||||
TEST_1(is_answer_recv(e->data->e_tags));
|
||||
TEST_1(!is_offer_sent(e->data->e_tags));
|
||||
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
|
||||
TEST(e->data->e_status, 483);
|
||||
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminating);
|
||||
|
||||
{
|
||||
int bye = 1, cancel = 1, invite = 1;
|
||||
|
||||
while (bye || cancel || invite) {
|
||||
TEST_1(e = e->next);
|
||||
if (e->data->e_event == nua_r_bye) {
|
||||
TEST_E(e->data->e_event, nua_r_bye);
|
||||
TEST(e->data->e_status, 200);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminated);
|
||||
bye = 0;
|
||||
}
|
||||
else if (e->data->e_event == nua_r_invite) {
|
||||
TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST(e->data->e_status, 487);
|
||||
invite = 0;
|
||||
}
|
||||
else if (e->data->e_event == nua_r_cancel) {
|
||||
TEST_E(e->data->e_event, nua_r_cancel);
|
||||
TEST_1(e->data->e_status == 200 || e->data->e_status == 481);
|
||||
cancel = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
TEST_1(!e->next);
|
||||
|
||||
free_events_in_list(ctx, a->events);
|
||||
|
||||
/*
|
||||
Server transitions:
|
||||
INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
|
||||
RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state, nua_respond(to PRACK)
|
||||
EARLY -(S3b)-> TERMINATED: nua_i_bye, nua_i_state
|
||||
*/
|
||||
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
|
||||
TEST(e->data->e_status, 100);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
|
||||
TEST_1(is_offer_recv(e->data->e_tags));
|
||||
|
||||
/* Responded with 183 Session Progress */
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(e->data->e_status, 183);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
|
||||
TEST_1(is_answer_sent(e->data->e_tags));
|
||||
|
||||
/* 183 is PRACKed, PRACK is responded with 483 */
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_prack);
|
||||
|
||||
/* Client terminates the call
|
||||
- we may (it is received before BYE) or may not (received after BYE)
|
||||
get CANCEL request
|
||||
*/
|
||||
TEST_1(e = e->next);
|
||||
if (e->data->e_event == nua_i_cancel) {
|
||||
TEST_E(e->data->e_event, nua_i_cancel);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_ready);
|
||||
TEST_1(e = e->next);
|
||||
}
|
||||
|
||||
TEST_E(e->data->e_event, nua_i_bye);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminated);
|
||||
TEST_1(!e->next);
|
||||
|
||||
free_events_in_list(ctx, b->events);
|
||||
|
||||
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
|
||||
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
|
||||
|
||||
@ -694,6 +774,39 @@ int test_183rel(struct context *ctx)
|
||||
END();
|
||||
}
|
||||
|
||||
int respond_483_to_prack(CONDITION_PARAMS)
|
||||
{
|
||||
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
|
||||
return 0;
|
||||
|
||||
switch (event) {
|
||||
case nua_i_prack:
|
||||
if (status <= 200) {
|
||||
RESPOND(ep, call, nh, 483, "Foo",
|
||||
NUTAG_WITH_THIS(nua),
|
||||
TAG_END());
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
save_event_in_list(ctx, event, ep, call);
|
||||
|
||||
switch (callstate(tags)) {
|
||||
case nua_callstate_received:
|
||||
RESPOND(ep, call, nh, SIP_183_SESSION_PROGRESS,
|
||||
TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
|
||||
TAG_END());
|
||||
return 0;
|
||||
case nua_callstate_terminated:
|
||||
if (call)
|
||||
nua_handle_destroy(call->nh), call->nh = NULL;
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
X ringing_updated ep
|
||||
|-------INVITE------>|
|
||||
@ -858,6 +971,8 @@ int test_preconditions(struct context *ctx)
|
||||
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_update);
|
||||
TEST(e->data->e_status, 200);
|
||||
TEST_1(sip = sip_object(e->data->e_msg));
|
||||
TEST_1(sip->sip_session_expires);
|
||||
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
|
||||
@ -1085,14 +1200,14 @@ int test_preconditions2(struct context *ctx)
|
||||
|
||||
nua_set_params(ctx->a.nua,
|
||||
NUTAG_EARLY_MEDIA(1),
|
||||
SIPTAG_SUPPORTED_STR("100rel, precondition"),
|
||||
SIPTAG_SUPPORTED_STR("100rel, precondition, timer"),
|
||||
TAG_END());
|
||||
run_a_until(ctx, nua_r_set_params, until_final_response);
|
||||
|
||||
nua_set_params(ctx->b.nua,
|
||||
NUTAG_EARLY_MEDIA(1),
|
||||
NUTAG_ONLY183_100REL(1),
|
||||
SIPTAG_SUPPORTED_STR("100rel, precondition"),
|
||||
SIPTAG_SUPPORTED_STR("100rel, precondition, timer"),
|
||||
TAG_END());
|
||||
run_b_until(ctx, nua_r_set_params, until_final_response);
|
||||
|
||||
@ -1578,6 +1693,310 @@ int test_update_by_uas(struct context *ctx)
|
||||
END();
|
||||
}
|
||||
|
||||
int cancel_when_pracked(CONDITION_PARAMS);
|
||||
int alert_call(CONDITION_PARAMS);
|
||||
|
||||
int test_180rel_cancel1(struct context *ctx)
|
||||
{
|
||||
BEGIN();
|
||||
|
||||
struct endpoint *a = &ctx->a, *b = &ctx->b;
|
||||
struct call *a_call = a->call, *b_call = b->call;
|
||||
struct event *e;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-10.6: CANCEL after PRACK\n");
|
||||
|
||||
/* Test for 100rel:
|
||||
|
||||
A B
|
||||
|-------INVITE------>|
|
||||
|<----100 Trying-----|
|
||||
| |
|
||||
|<-------180---------|
|
||||
|-------PRACK------->|
|
||||
|<-------200---------|
|
||||
| |
|
||||
|------CANCEL------->|
|
||||
|<------200 OK-------|
|
||||
| |
|
||||
|<-------487---------|
|
||||
|--------ACK-------->|
|
||||
| |
|
||||
|
||||
*/
|
||||
|
||||
a_call->sdp = "m=audio 5008 RTP/AVP 8";
|
||||
b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
|
||||
|
||||
nua_set_params(ctx->a.nua,
|
||||
NUTAG_EARLY_MEDIA(1),
|
||||
NUTAG_ONLY183_100REL(0),
|
||||
TAG_END());
|
||||
run_a_until(ctx, nua_r_set_params, until_final_response);
|
||||
|
||||
nua_set_params(ctx->b.nua,
|
||||
NUTAG_EARLY_MEDIA(1),
|
||||
NUTAG_ONLY183_100REL(0),
|
||||
TAG_END());
|
||||
run_b_until(ctx, nua_r_set_params, until_final_response);
|
||||
|
||||
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
|
||||
|
||||
INVITE(a, a_call, a_call->nh,
|
||||
TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
|
||||
SOATAG_USER_SDP_STR(a_call->sdp),
|
||||
TAG_END());
|
||||
|
||||
run_ab_until(ctx, -1, cancel_when_pracked, -1, alert_call);
|
||||
|
||||
/* Client transitions:
|
||||
INIT -(C1)-> CALLING: nua_invite(), nua_i_state
|
||||
CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state, nua_r_prack
|
||||
PROCEEDING -(C3+C4)-> TERMINATED: nua_r_invite, nua_i_state
|
||||
*/
|
||||
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
|
||||
TEST_1(is_offer_sent(e->data->e_tags));
|
||||
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST(e->data->e_status, 180);
|
||||
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
|
||||
TEST_1(is_answer_recv(e->data->e_tags));
|
||||
TEST_1(!is_offer_sent(e->data->e_tags));
|
||||
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_cancel);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST(e->data->e_status, 487);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminated);
|
||||
TEST_1(!e->next);
|
||||
|
||||
free_events_in_list(ctx, a->events);
|
||||
|
||||
/*
|
||||
Server transitions:
|
||||
INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
|
||||
RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
|
||||
Option A:
|
||||
EARLY -(S10)-> TERMINATED: nua_i_cancel, nua_i_state
|
||||
Option B:
|
||||
EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
|
||||
COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
|
||||
READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state
|
||||
*/
|
||||
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
|
||||
TEST(e->data->e_status, 100);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
|
||||
TEST_1(is_offer_recv(e->data->e_tags));
|
||||
|
||||
/* Responded with 180 Ringing */
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
|
||||
TEST_1(is_answer_sent(e->data->e_tags));
|
||||
|
||||
/* 180 is PRACKed */
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_prack);
|
||||
/* Does not have effect on call state */
|
||||
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_cancel);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
|
||||
|
||||
free_events_in_list(ctx, b->events);
|
||||
|
||||
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
|
||||
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-10.6: PASSED\n");
|
||||
|
||||
END();
|
||||
}
|
||||
|
||||
int cancel_when_pracked(CONDITION_PARAMS)
|
||||
{
|
||||
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
|
||||
return 0;
|
||||
|
||||
save_event_in_list(ctx, event, ep, call);
|
||||
|
||||
if (event == nua_r_prack)
|
||||
CANCEL(ep, call, nh, TAG_END());
|
||||
|
||||
switch (callstate(tags)) {
|
||||
case nua_callstate_proceeding:
|
||||
return 0;
|
||||
case nua_callstate_ready:
|
||||
return 1;
|
||||
case nua_callstate_terminated:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int test_180rel_cancel2(struct context *ctx)
|
||||
{
|
||||
BEGIN();
|
||||
|
||||
struct endpoint *a = &ctx->a, *b = &ctx->b;
|
||||
struct call *a_call = a->call, *b_call = b->call;
|
||||
struct event *e;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-10.7: CANCEL after 100rel 180\n");
|
||||
|
||||
/* Test for 100rel:
|
||||
|
||||
A B
|
||||
|-------INVITE------>|
|
||||
|<----100 Trying-----|
|
||||
| |
|
||||
|<-------180---------|
|
||||
|-------PRACK------->|
|
||||
|<-------200---------|
|
||||
| |
|
||||
|------CANCEL------->|
|
||||
|<------200 OK-------|
|
||||
| |
|
||||
|<-------487---------|
|
||||
|--------ACK-------->|
|
||||
| |
|
||||
|
||||
*/
|
||||
|
||||
a_call->sdp = "m=audio 5008 RTP/AVP 8";
|
||||
b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
|
||||
|
||||
nua_set_params(ctx->a.nua,
|
||||
NUTAG_EARLY_MEDIA(1),
|
||||
NUTAG_ONLY183_100REL(0),
|
||||
TAG_END());
|
||||
run_a_until(ctx, nua_r_set_params, until_final_response);
|
||||
|
||||
nua_set_params(ctx->b.nua,
|
||||
NUTAG_EARLY_MEDIA(1),
|
||||
NUTAG_ONLY183_100REL(0),
|
||||
TAG_END());
|
||||
run_b_until(ctx, nua_r_set_params, until_final_response);
|
||||
|
||||
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
|
||||
|
||||
INVITE(a, a_call, a_call->nh,
|
||||
TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
|
||||
SOATAG_USER_SDP_STR(a_call->sdp),
|
||||
TAG_END());
|
||||
|
||||
run_ab_until(ctx, -1, cancel_when_ringing, -1, accept_pracked2);
|
||||
|
||||
/* Client transitions:
|
||||
INIT -(C1)-> CALLING: nua_invite(), nua_i_state
|
||||
CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state, nua_r_prack
|
||||
PROCEEDING -(C3+C4)-> TERMINATED: nua_r_invite, nua_i_state
|
||||
*/
|
||||
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
|
||||
TEST_1(is_offer_sent(e->data->e_tags));
|
||||
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST(e->data->e_status, 180);
|
||||
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
|
||||
TEST_1(is_answer_recv(e->data->e_tags));
|
||||
TEST_1(!is_offer_sent(e->data->e_tags));
|
||||
|
||||
#define NEXT_SKIP_PRACK_CANCEL() \
|
||||
do { TEST_1(e = e->next); } \
|
||||
while (e->data->e_event == nua_r_prack || e->data->e_event == nua_r_cancel)
|
||||
|
||||
NEXT_SKIP_PRACK_CANCEL();
|
||||
|
||||
TEST_E(e->data->e_event, nua_r_invite);
|
||||
if (e->data->e_status == 487) {
|
||||
TEST(e->data->e_status, 487);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminated);
|
||||
TEST_1(!e->next);
|
||||
}
|
||||
else {
|
||||
TEST(e->data->e_status, 200);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_ready);
|
||||
|
||||
BYE(a, a_call, a_call->nh, TAG_END());
|
||||
run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
|
||||
|
||||
NEXT_SKIP_PRACK_CANCEL(); TEST_E(e->data->e_event, nua_r_bye);
|
||||
TEST(e->data->e_status, 200);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
|
||||
TEST_1(!e->next);
|
||||
}
|
||||
|
||||
free_events_in_list(ctx, a->events);
|
||||
|
||||
/*
|
||||
Server transitions:
|
||||
INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
|
||||
RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
|
||||
Option A:
|
||||
EARLY -(S10)-> TERMINATED: nua_i_cancel, nua_i_state
|
||||
Option B:
|
||||
EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
|
||||
COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
|
||||
READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state
|
||||
*/
|
||||
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
|
||||
TEST(e->data->e_status, 100);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
|
||||
TEST_1(is_offer_recv(e->data->e_tags));
|
||||
|
||||
/* Responded with 180 Ringing */
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
|
||||
TEST_1(is_answer_sent(e->data->e_tags));
|
||||
|
||||
/* 180 is PRACKed */
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_prack);
|
||||
/* Does not have effect on call state */
|
||||
|
||||
if (e->next->data->e_event == nua_i_cancel) {
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_cancel);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
|
||||
}
|
||||
else {
|
||||
/* Respond with 200 OK */
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
|
||||
TEST_1(!is_offer_answer_done(e->data->e_tags));
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
|
||||
TEST_1(!is_offer_answer_done(e->data->e_tags));
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_bye);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
|
||||
}
|
||||
|
||||
free_events_in_list(ctx, b->events);
|
||||
|
||||
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
|
||||
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-10.7: PASSED\n");
|
||||
|
||||
END();
|
||||
}
|
||||
|
||||
|
||||
int test_100rel(struct context *ctx)
|
||||
{
|
||||
@ -1589,6 +2008,28 @@ int test_100rel(struct context *ctx)
|
||||
retval = test_preconditions(ctx); RETURN_ON_SINGLE_FAILURE(retval);
|
||||
retval = test_preconditions2(ctx); RETURN_ON_SINGLE_FAILURE(retval);
|
||||
retval = test_update_by_uas(ctx); RETURN_ON_SINGLE_FAILURE(retval);
|
||||
retval = test_180rel_cancel1(ctx); RETURN_ON_SINGLE_FAILURE(retval);
|
||||
retval = test_180rel_cancel2(ctx); RETURN_ON_SINGLE_FAILURE(retval);
|
||||
|
||||
nua_set_params(ctx->a.nua,
|
||||
NUTAG_EARLY_MEDIA(0),
|
||||
SIPTAG_SUPPORTED(ctx->a.supported),
|
||||
TAG_END());
|
||||
run_a_until(ctx, nua_r_set_params, until_final_response);
|
||||
|
||||
nua_set_params(ctx->b.nua,
|
||||
NUTAG_EARLY_MEDIA(0),
|
||||
NUTAG_ONLY183_100REL(0),
|
||||
SIPTAG_SUPPORTED(ctx->b.supported),
|
||||
TAG_END());
|
||||
run_b_until(ctx, nua_r_set_params, until_final_response);
|
||||
|
||||
nua_set_params(ctx->c.nua,
|
||||
NUTAG_EARLY_MEDIA(0),
|
||||
NUTAG_ONLY183_100REL(0),
|
||||
SIPTAG_SUPPORTED(ctx->c.supported),
|
||||
TAG_END());
|
||||
run_c_until(ctx, nua_r_set_params, until_final_response);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
@ -117,6 +117,8 @@ int accept_call_with_early_sdp(CONDITION_PARAMS)
|
||||
case nua_callstate_received:
|
||||
RESPOND(ep, call, nh, SIP_180_RINGING,
|
||||
TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
|
||||
NUTAG_M_DISPLAY("Bob"),
|
||||
NUTAG_M_USERNAME("b+b"),
|
||||
TAG_END());
|
||||
return 0;
|
||||
case nua_callstate_early:
|
||||
@ -203,9 +205,16 @@ int test_basic_call_1(struct context *ctx)
|
||||
sip_replaces_t *repa, *repb;
|
||||
nua_handle_t *nh;
|
||||
|
||||
static int once = 0;
|
||||
sip_time_t se, min_se;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-3.1: Basic call\n");
|
||||
|
||||
/* Disable session timer from proxy */
|
||||
test_proxy_get_session_timer(ctx->p, &se, &min_se);
|
||||
test_proxy_set_session_timer(ctx->p, 0, 0);
|
||||
|
||||
a_call->sdp = "m=audio 5008 RTP/AVP 8";
|
||||
b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
|
||||
|
||||
@ -217,6 +226,8 @@ int test_basic_call_1(struct context *ctx)
|
||||
INVITE(a, a_call, a_call->nh,
|
||||
TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
|
||||
SOATAG_USER_SDP_STR(a_call->sdp),
|
||||
NUTAG_M_USERNAME("a+a"),
|
||||
NUTAG_M_DISPLAY("Alice"),
|
||||
TAG_END());
|
||||
|
||||
run_ab_until(ctx, -1, until_ready, -1, accept_call_with_early_sdp);
|
||||
@ -263,8 +274,15 @@ int test_basic_call_1(struct context *ctx)
|
||||
TEST_1(is_answer_recv(e->data->e_tags));
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST(e->data->e_status, 200);
|
||||
TEST_1(sip->sip_payload);
|
||||
TEST_1(sip = sip_object(e->data->e_msg));
|
||||
TEST_1(sip->sip_payload);
|
||||
TEST_1(sip->sip_contact);
|
||||
TEST_S(sip->sip_contact->m_display, "Bob");
|
||||
TEST_S(sip->sip_contact->m_url->url_user, "b+b");
|
||||
if (!once) {
|
||||
/* The session expiration is not used by default. */
|
||||
TEST_1(sip->sip_session_expires == NULL);
|
||||
}
|
||||
/* Test that B uses application-specific contact */
|
||||
if (ctx->proxy_tests)
|
||||
TEST_1(sip->sip_contact->m_url->url_user);
|
||||
@ -282,6 +300,14 @@ int test_basic_call_1(struct context *ctx)
|
||||
*/
|
||||
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
|
||||
TEST(e->data->e_status, 100);
|
||||
TEST_1(sip = sip_object(e->data->e_msg));
|
||||
TEST_1(sip->sip_contact);
|
||||
TEST_S(sip->sip_contact->m_display, "Alice");
|
||||
TEST_S(sip->sip_contact->m_url->url_user, "a+a");
|
||||
if (!once++) {
|
||||
/* The Session-Expires header is not used by default. */
|
||||
TEST_1(sip->sip_session_expires == NULL);
|
||||
}
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
|
||||
TEST_1(is_offer_recv(e->data->e_tags));
|
||||
@ -331,6 +357,8 @@ int test_basic_call_1(struct context *ctx)
|
||||
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
|
||||
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
|
||||
|
||||
test_proxy_set_session_timer(ctx->p, se, min_se);
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-3.1: PASSED\n");
|
||||
|
||||
@ -404,6 +432,7 @@ int test_basic_call_2(struct context *ctx)
|
||||
INVITE(a, a_call, a_call->nh,
|
||||
NUTAG_URL(b->contact->m_url),
|
||||
SOATAG_USER_SDP_STR(a_call->sdp),
|
||||
NUTAG_ALLOW("INFO"),
|
||||
TAG_END());
|
||||
|
||||
run_ab_until(ctx, -1, until_ready, -1, accept_early_answer);
|
||||
@ -466,32 +495,96 @@ int test_basic_call_2(struct context *ctx)
|
||||
TEST_1(nua_handle_has_active_call(b_call->nh));
|
||||
TEST_1(!nua_handle_has_call_on_hold(b_call->nh));
|
||||
|
||||
/* Send a NOTIFY from B to A */
|
||||
if (print_headings)
|
||||
printf("TEST NUA-3.2.2: send a NOTIFY within a dialog\n");
|
||||
|
||||
/* Make A to accept NOTIFY */
|
||||
nua_set_params(a->nua, NUTAG_APPL_METHOD("NOTIFY"), TAG_END());
|
||||
run_a_until(ctx, nua_r_set_params, until_final_response);
|
||||
|
||||
NOTIFY(b, b_call, b_call->nh,
|
||||
NUTAG_NEWSUB(1),
|
||||
SIPTAG_SUBJECT_STR("NUA-3.2.2"),
|
||||
SIPTAG_EVENT_STR("message-summary"),
|
||||
SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"),
|
||||
SIPTAG_PAYLOAD_STR("Messages-Waiting: no"),
|
||||
TAG_END());
|
||||
|
||||
run_ab_until(ctx, -1, accept_notify, -1, save_until_final_response);
|
||||
|
||||
/* Notifier events: nua_r_notify */
|
||||
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_notify);
|
||||
TEST(e->data->e_status, 200);
|
||||
TEST_1(tl_find(e->data->e_tags, nutag_substate));
|
||||
TEST(tl_find(e->data->e_tags, nutag_substate)->t_value,
|
||||
nua_substate_terminated);
|
||||
|
||||
/* watcher events: nua_i_notify */
|
||||
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_notify);
|
||||
TEST_1(sip = sip_object(e->data->e_msg));
|
||||
TEST_1(sip->sip_subscription_state);
|
||||
TEST_S(sip->sip_subscription_state->ss_substate, "terminated");
|
||||
TEST_1(tl_find(e->data->e_tags, nutag_substate));
|
||||
TEST(tl_find(e->data->e_tags, nutag_substate)->t_value,
|
||||
nua_substate_terminated);
|
||||
TEST_1(!e->next);
|
||||
|
||||
free_events_in_list(ctx, a->events);
|
||||
free_events_in_list(ctx, b->events);
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-3.2.2: PASSED\n");
|
||||
|
||||
INFO(b, b_call, b_call->nh, TAG_END());
|
||||
BYE(b, b_call, b_call->nh, TAG_END());
|
||||
INFO(b, b_call, b_call->nh, TAG_END());
|
||||
|
||||
run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
|
||||
|
||||
while (!b->events->head || /* r_info */
|
||||
!b->events->head->next || /* r_bye */
|
||||
!b->events->head->next->next || /* i_state */
|
||||
!b->events->head->next->next->next) /* r_info */
|
||||
run_ab_until(ctx, -1, save_events, -1, save_until_final_response);
|
||||
|
||||
/* B transitions:
|
||||
nua_info()
|
||||
READY --(T2)--> TERMINATING: nua_bye()
|
||||
nua_r_info with 200
|
||||
TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
|
||||
nua_r_info with 481/900
|
||||
*/
|
||||
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_bye);
|
||||
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_info);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_bye);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_info);
|
||||
TEST_1(e->data->e_status >= 900 || e->data->e_status == 481);
|
||||
TEST_1(!e->next);
|
||||
free_events_in_list(ctx, b->events);
|
||||
|
||||
TEST_1(!nua_handle_has_active_call(b_call->nh));
|
||||
|
||||
/* A transitions:
|
||||
nua_i_info
|
||||
READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state
|
||||
*/
|
||||
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_bye);
|
||||
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_info);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_bye);
|
||||
TEST(e->data->e_status, 200);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
|
||||
TEST_1(!e->next);
|
||||
free_events_in_list(ctx, a->events);
|
||||
|
||||
TEST_1(!nua_handle_has_active_call(a_call->nh));
|
||||
BYE(a, a_call, a_call->nh, TAG_END());
|
||||
run_a_until(ctx, -1, save_until_final_response);
|
||||
|
||||
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_bye);
|
||||
TEST_1(e->data->e_status >= 900);
|
||||
TEST_1(!e->next);
|
||||
free_events_in_list(ctx, a->events);
|
||||
|
||||
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
|
||||
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
|
||||
@ -502,8 +595,376 @@ int test_basic_call_2(struct context *ctx)
|
||||
END();
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
|
||||
/* Basic calls with soa disabled */
|
||||
|
||||
int accept_call_no_media(CONDITION_PARAMS)
|
||||
{
|
||||
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
|
||||
return 0;
|
||||
|
||||
save_event_in_list(ctx, event, ep, call);
|
||||
|
||||
switch (callstate(tags)) {
|
||||
case nua_callstate_received:
|
||||
RESPOND(ep, call, nh, SIP_180_RINGING,
|
||||
NUTAG_MEDIA_ENABLE(0),
|
||||
TAG_END());
|
||||
return 0;
|
||||
case nua_callstate_early:
|
||||
RESPOND(ep, call, nh, SIP_200_OK,
|
||||
TAG_IF(call->sdp, SIPTAG_CONTENT_TYPE_STR("application/sdp")),
|
||||
TAG_IF(call->sdp, SIPTAG_PAYLOAD_STR(call->sdp)),
|
||||
TAG_END());
|
||||
return 0;
|
||||
case nua_callstate_ready:
|
||||
return 1;
|
||||
case nua_callstate_terminated:
|
||||
if (call)
|
||||
nua_handle_destroy(call->nh), call->nh = NULL;
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int test_basic_call_3(struct context *ctx)
|
||||
{
|
||||
BEGIN();
|
||||
|
||||
struct endpoint *a = &ctx->a, *b = &ctx->b;
|
||||
struct call *a_call = a->call, *b_call = b->call;
|
||||
struct event *e;
|
||||
sip_t const *sip;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-3.3: Basic call with media disabled\n");
|
||||
|
||||
a_call->sdp = "v=0\r\n"
|
||||
"o=- 1 1 IN IP4 127.0.0.1\r\n"
|
||||
"s=-\r\n"
|
||||
"c=IN IP4 127.0.0.1\r\n"
|
||||
"t=0 0\r\n"
|
||||
"m=audio 5008 RTP/AVP 8\r\n";
|
||||
|
||||
b_call->sdp =
|
||||
"v=0\r\n"
|
||||
"o=- 2 1 IN IP4 127.0.0.1\r\n"
|
||||
"s=-\r\n"
|
||||
"c=IN IP4 127.0.0.1\r\n"
|
||||
"t=0 0\r\n"
|
||||
"m=audio 5010 RTP/AVP 0 8\r\n";
|
||||
|
||||
TEST_1(a_call->nh = nua_handle(a->nua, a_call,
|
||||
SIPTAG_TO_STR("<sip:b@x.org>"),
|
||||
TAG_END()));
|
||||
|
||||
TEST_1(!nua_handle_has_active_call(a_call->nh));
|
||||
TEST_1(!nua_handle_has_call_on_hold(a_call->nh));
|
||||
|
||||
INVITE(a, a_call, a_call->nh,
|
||||
NUTAG_MEDIA_ENABLE(0),
|
||||
NUTAG_URL(b->contact->m_url),
|
||||
SIPTAG_CONTENT_TYPE_STR("application/sdp"),
|
||||
SIPTAG_PAYLOAD_STR(a_call->sdp),
|
||||
TAG_END());
|
||||
|
||||
run_ab_until(ctx, -1, until_ready, -1, accept_call_no_media);
|
||||
|
||||
/* Client transitions:
|
||||
INIT -(C1)-> CALLING: nua_invite(), nua_i_state
|
||||
CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state
|
||||
PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
|
||||
*/
|
||||
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
|
||||
TEST_1(is_offer_sent(e->data->e_tags));
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST(e->data->e_status, 180);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
|
||||
TEST_1(!is_answer_recv(e->data->e_tags));
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST(e->data->e_status, 200);
|
||||
TEST_1(sip = sip_object(e->data->e_msg));
|
||||
TEST_1(sip->sip_content_type);
|
||||
TEST_S(sip->sip_content_type->c_type, "application/sdp");
|
||||
TEST_1(sip->sip_payload); /* there is sdp in 200 OK */
|
||||
TEST_1(sip->sip_contact);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
|
||||
TEST_1(is_answer_recv(e->data->e_tags));
|
||||
TEST_1(!e->next);
|
||||
free_events_in_list(ctx, a->events);
|
||||
|
||||
TEST_1(nua_handle_has_active_call(a_call->nh));
|
||||
TEST_1(!nua_handle_has_call_on_hold(a_call->nh));
|
||||
|
||||
/*
|
||||
Server transitions:
|
||||
INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
|
||||
RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
|
||||
EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
|
||||
COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
|
||||
*/
|
||||
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
|
||||
TEST(e->data->e_status, 100);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
|
||||
TEST_1(is_offer_recv(e->data->e_tags));
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
|
||||
TEST_1(!is_answer_sent(e->data->e_tags));
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
|
||||
TEST_1(is_answer_sent(e->data->e_tags));
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
|
||||
TEST_1(!e->next);
|
||||
free_events_in_list(ctx, b->events);
|
||||
|
||||
TEST_1(nua_handle_has_active_call(b_call->nh));
|
||||
TEST_1(!nua_handle_has_call_on_hold(b_call->nh));
|
||||
|
||||
BYE(b, b_call, b_call->nh, TAG_END());
|
||||
|
||||
run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
|
||||
|
||||
/* B transitions:
|
||||
READY --(T2)--> TERMINATING: nua_bye()
|
||||
TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
|
||||
*/
|
||||
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_bye);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
|
||||
TEST_1(!e->next);
|
||||
free_events_in_list(ctx, b->events);
|
||||
|
||||
TEST_1(!nua_handle_has_active_call(b_call->nh));
|
||||
|
||||
/* A transitions:
|
||||
nua_i_info
|
||||
READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state
|
||||
*/
|
||||
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_bye);
|
||||
TEST(e->data->e_status, 200);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
|
||||
TEST_1(!e->next);
|
||||
free_events_in_list(ctx, a->events);
|
||||
|
||||
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
|
||||
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-3.3: PASSED\n");
|
||||
|
||||
END();
|
||||
}
|
||||
|
||||
int ack_when_completing_no_media(CONDITION_PARAMS)
|
||||
{
|
||||
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
|
||||
return 0;
|
||||
|
||||
save_event_in_list(ctx, event, ep, call);
|
||||
|
||||
switch (callstate(tags)) {
|
||||
case nua_callstate_completing:
|
||||
ACK(ep, call, nh,
|
||||
TAG_IF(call->sdp, SIPTAG_CONTENT_TYPE_STR("application/sdp")),
|
||||
TAG_IF(call->sdp, SIPTAG_PAYLOAD_STR(call->sdp)),
|
||||
TAG_END());
|
||||
return 0;
|
||||
case nua_callstate_ready:
|
||||
return 1;
|
||||
case nua_callstate_terminated:
|
||||
if (call)
|
||||
nua_handle_destroy(call->nh), call->nh = NULL;
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int accept_call_no_media2(CONDITION_PARAMS)
|
||||
{
|
||||
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
|
||||
return 0;
|
||||
|
||||
save_event_in_list(ctx, event, ep, call);
|
||||
|
||||
switch (callstate(tags)) {
|
||||
case nua_callstate_received:
|
||||
RESPOND(ep, call, nh, SIP_180_RINGING,
|
||||
NUTAG_MEDIA_ENABLE(0),
|
||||
TAG_IF(call->sdp, SIPTAG_CONTENT_TYPE_STR("application/sdp")),
|
||||
TAG_IF(call->sdp, SIPTAG_PAYLOAD_STR(call->sdp)),
|
||||
TAG_END());
|
||||
return 0;
|
||||
case nua_callstate_early:
|
||||
RESPOND(ep, call, nh, SIP_200_OK,
|
||||
TAG_IF(call->sdp, SIPTAG_CONTENT_TYPE_STR("application/sdp")),
|
||||
TAG_IF(call->sdp, SIPTAG_PAYLOAD_STR(call->sdp)),
|
||||
TAG_END());
|
||||
return 0;
|
||||
case nua_callstate_ready:
|
||||
return 1;
|
||||
case nua_callstate_terminated:
|
||||
if (call)
|
||||
nua_handle_destroy(call->nh), call->nh = NULL;
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Media disabled, offer/answer in 200 OK/ACK */
|
||||
int test_basic_call_4(struct context *ctx)
|
||||
{
|
||||
BEGIN();
|
||||
|
||||
struct endpoint *a = &ctx->a, *b = &ctx->b;
|
||||
struct call *a_call = a->call, *b_call = b->call;
|
||||
struct event *e;
|
||||
sip_t const *sip;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-3.4: 3pcc call with media disabled\n");
|
||||
|
||||
a_call->sdp = "v=0\r\n"
|
||||
"o=- 1 1 IN IP4 127.0.0.1\r\n"
|
||||
"s=-\r\n"
|
||||
"c=IN IP4 127.0.0.1\r\n"
|
||||
"t=0 0\r\n"
|
||||
"m=audio 5008 RTP/AVP 8\r\n";
|
||||
|
||||
b_call->sdp =
|
||||
"v=0\r\n"
|
||||
"o=- 2 1 IN IP4 127.0.0.1\r\n"
|
||||
"s=-\r\n"
|
||||
"c=IN IP4 127.0.0.1\r\n"
|
||||
"t=0 0\r\n"
|
||||
"m=audio 5010 RTP/AVP 0 8\r\n";
|
||||
|
||||
TEST_1(a_call->nh = nua_handle(a->nua, a_call,
|
||||
SIPTAG_TO_STR("<sip:b@x.org>"),
|
||||
TAG_END()));
|
||||
|
||||
TEST_1(!nua_handle_has_active_call(a_call->nh));
|
||||
TEST_1(!nua_handle_has_call_on_hold(a_call->nh));
|
||||
|
||||
INVITE(a, a_call, a_call->nh,
|
||||
NUTAG_MEDIA_ENABLE(0),
|
||||
NUTAG_URL(b->contact->m_url),
|
||||
NUTAG_AUTOACK(0),
|
||||
TAG_END());
|
||||
|
||||
run_ab_until(ctx, -1, ack_when_completing_no_media,
|
||||
-1, accept_call_no_media2);
|
||||
|
||||
/* Client transitions:
|
||||
INIT -(C1)-> CALLING: nua_invite(), nua_i_state
|
||||
CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state
|
||||
PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
|
||||
*/
|
||||
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
|
||||
TEST_1(!is_offer_sent(e->data->e_tags));
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST(e->data->e_status, 180);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
|
||||
TEST_1(!is_answer_recv(e->data->e_tags));
|
||||
TEST_1(is_offer_recv(e->data->e_tags));
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST(e->data->e_status, 200);
|
||||
TEST_1(sip = sip_object(e->data->e_msg));
|
||||
TEST_1(sip->sip_content_type);
|
||||
TEST_S(sip->sip_content_type->c_type, "application/sdp");
|
||||
TEST_1(sip->sip_payload); /* there is sdp in 200 OK */
|
||||
TEST_1(sip->sip_contact);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_completing); /* COMPLETING */
|
||||
TEST_1(is_offer_recv(e->data->e_tags));
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
|
||||
TEST_1(is_answer_sent(e->data->e_tags));
|
||||
TEST_1(!e->next);
|
||||
free_events_in_list(ctx, a->events);
|
||||
|
||||
TEST_1(nua_handle_has_active_call(a_call->nh));
|
||||
TEST_1(!nua_handle_has_call_on_hold(a_call->nh));
|
||||
|
||||
/*
|
||||
Server transitions:
|
||||
INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
|
||||
RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
|
||||
EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
|
||||
COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
|
||||
*/
|
||||
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
|
||||
TEST(e->data->e_status, 100);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
|
||||
TEST_1(!is_offer_recv(e->data->e_tags));
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
|
||||
TEST_1(!is_answer_sent(e->data->e_tags));
|
||||
TEST_1(is_offer_sent(e->data->e_tags));
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
|
||||
TEST_1(is_offer_sent(e->data->e_tags));
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
|
||||
TEST_1(is_answer_recv(e->data->e_tags));
|
||||
TEST_1(!e->next);
|
||||
free_events_in_list(ctx, b->events);
|
||||
|
||||
TEST_1(nua_handle_has_active_call(b_call->nh));
|
||||
TEST_1(!nua_handle_has_call_on_hold(b_call->nh));
|
||||
|
||||
BYE(b, b_call, b_call->nh, TAG_END());
|
||||
|
||||
run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
|
||||
|
||||
/* B transitions:
|
||||
READY --(T2)--> TERMINATING: nua_bye()
|
||||
TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
|
||||
*/
|
||||
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_bye);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
|
||||
TEST_1(!e->next);
|
||||
free_events_in_list(ctx, b->events);
|
||||
|
||||
TEST_1(!nua_handle_has_active_call(b_call->nh));
|
||||
|
||||
/* A transitions:
|
||||
nua_i_info
|
||||
READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state
|
||||
*/
|
||||
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_bye);
|
||||
TEST(e->data->e_status, 200);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
|
||||
TEST_1(!e->next);
|
||||
free_events_in_list(ctx, a->events);
|
||||
|
||||
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
|
||||
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-3.4: PASSED\n");
|
||||
|
||||
END();
|
||||
}
|
||||
|
||||
int test_basic_call(struct context *ctx)
|
||||
{
|
||||
return test_basic_call_1(ctx) || test_basic_call_2(ctx);
|
||||
return test_basic_call_1(ctx) || test_basic_call_2(ctx) ||
|
||||
test_basic_call_3(ctx) || test_basic_call_4(ctx);
|
||||
}
|
||||
|
@ -467,7 +467,7 @@ int test_call_hold(struct context *ctx)
|
||||
*/
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-7.6: re-INVITE without auto-ack\n");
|
||||
printf("TEST NUA-7.6.1: re-INVITE without auto-ack\n");
|
||||
|
||||
/* Turn off auto-ack */
|
||||
nua_set_hparams(b_call->nh, NUTAG_AUTOACK(0), TAG_END());
|
||||
@ -517,7 +517,7 @@ int test_call_hold(struct context *ctx)
|
||||
free_events_in_list(ctx, a->events);
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-7.6: PASSED\n");
|
||||
printf("TEST NUA-7.6.1: PASSED\n");
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
@ -528,7 +528,7 @@ int test_call_hold(struct context *ctx)
|
||||
*/
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-7.6: terminate call\n");
|
||||
printf("TEST NUA-7.6.2: terminate call\n");
|
||||
|
||||
BYE(a, a_call, a_call->nh, TAG_END());
|
||||
run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
|
||||
@ -555,7 +555,7 @@ int test_call_hold(struct context *ctx)
|
||||
free_events_in_list(ctx, b->events);
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-7.6: PASSED\n");
|
||||
printf("TEST NUA-7.6.2: PASSED\n");
|
||||
|
||||
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
|
||||
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
|
||||
@ -725,9 +725,6 @@ int test_reinvite(struct context *ctx)
|
||||
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
|
||||
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-7.8: PASSED\n");
|
||||
|
||||
END();
|
||||
}
|
||||
|
||||
@ -784,6 +781,211 @@ int ringing_until_terminated(CONDITION_PARAMS)
|
||||
}
|
||||
}
|
||||
|
||||
/* ======================================================================== */
|
||||
|
||||
int accept_and_attempt_reinvite(CONDITION_PARAMS);
|
||||
int until_ready2(CONDITION_PARAMS);
|
||||
|
||||
/* test_reinvite2 message sequence looks like this:
|
||||
|
||||
A B
|
||||
| |
|
||||
|-------INVITE------>|
|
||||
|<----100 Trying-----|
|
||||
| |
|
||||
|<----180 Ringing----|
|
||||
| |
|
||||
| /-INVITE-|
|
||||
| \---900->|
|
||||
| |
|
||||
|<--------200--------|
|
||||
|---------ACK------->|
|
||||
: :
|
||||
: queue INVITE :
|
||||
: :
|
||||
|-----re-INVITE----->|
|
||||
|<--------200--------|
|
||||
|---------ACK------->|
|
||||
|-----re-INVITE----->|
|
||||
|<--------200--------|
|
||||
|---------ACK------->|
|
||||
: :
|
||||
: glare :
|
||||
: :
|
||||
|-----re-INVITE----->|
|
||||
|<----re-INVITE------|
|
||||
|<--------491--------|
|
||||
|---------491------->|
|
||||
|---------ACK------->|
|
||||
|<--------ACK--------|
|
||||
: :
|
||||
|---------BYE------->|
|
||||
|<--------200--------|
|
||||
*/
|
||||
|
||||
int test_reinvite2(struct context *ctx)
|
||||
{
|
||||
BEGIN();
|
||||
|
||||
struct endpoint *a = &ctx->a, *b = &ctx->b;
|
||||
struct call *a_call = a->call, *b_call = b->call;
|
||||
struct event *e;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-7.8.1: Test re-INVITE glare\n");
|
||||
|
||||
a_call->sdp = "m=audio 5008 RTP/AVP 0 8\n";
|
||||
b_call->sdp = "m=audio 5010 RTP/AVP 8\n";
|
||||
|
||||
TEST_1(a_call->nh =
|
||||
nua_handle(a->nua, a_call,
|
||||
SIPTAG_FROM_STR("Alice <sip:alice@example.com>"),
|
||||
SIPTAG_TO(b->to),
|
||||
TAG_END()));
|
||||
INVITE(a, a_call, a_call->nh,
|
||||
TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
|
||||
SOATAG_USER_SDP_STR(a_call->sdp),
|
||||
TAG_END());
|
||||
|
||||
run_ab_until(ctx, -1, until_ready, -1, accept_and_attempt_reinvite);
|
||||
|
||||
TEST_1(nua_handle_has_active_call(a_call->nh));
|
||||
TEST_1(nua_handle_has_active_call(b_call->nh));
|
||||
|
||||
free_events_in_list(ctx, a->events);
|
||||
free_events_in_list(ctx, b->events);
|
||||
|
||||
/* Check that we can queue INVITEs */
|
||||
INVITE(a, a_call, a_call->nh, TAG_END());
|
||||
INVITE(a, a_call, a_call->nh, TAG_END());
|
||||
|
||||
run_ab_until(ctx, -1, until_ready2, -1, until_ready2);
|
||||
|
||||
free_events_in_list(ctx, a->events);
|
||||
free_events_in_list(ctx, b->events);
|
||||
|
||||
/* Check that INVITE glare works */
|
||||
INVITE(a, a_call, a_call->nh, TAG_END());
|
||||
INVITE(b, b_call, b_call->nh, TAG_END());
|
||||
|
||||
a->flags.n = 0, b->flags.n = 0;
|
||||
run_ab_until(ctx, -1, until_ready2, -1, until_ready2);
|
||||
|
||||
free_events_in_list(ctx, a->events);
|
||||
free_events_in_list(ctx, b->events);
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-7.8.1: PASSED\n");
|
||||
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/*
|
||||
A B
|
||||
|---------BYE------->|
|
||||
|<--------200--------|
|
||||
*/
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-7.8.2: terminate call\n");
|
||||
|
||||
BYE(a, a_call, a_call->nh, TAG_END());
|
||||
run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
|
||||
|
||||
/*
|
||||
Transitions of A:
|
||||
READY --(T2)--> TERMINATING: nua_bye()
|
||||
TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
|
||||
*/
|
||||
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_bye);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
|
||||
TEST_1(!e->next);
|
||||
free_events_in_list(ctx, a->events);
|
||||
|
||||
/* Transitions of B:
|
||||
READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state
|
||||
*/
|
||||
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_bye);
|
||||
TEST(e->data->e_status, 200);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
|
||||
TEST_1(!e->next);
|
||||
free_events_in_list(ctx, b->events);
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-7.8.2: PASSED\n");
|
||||
|
||||
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
|
||||
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
|
||||
|
||||
END();
|
||||
}
|
||||
|
||||
int accept_and_attempt_reinvite(CONDITION_PARAMS)
|
||||
{
|
||||
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
|
||||
return 0;
|
||||
|
||||
save_event_in_list(ctx, event, ep, call);
|
||||
|
||||
if (event == nua_i_prack) {
|
||||
INVITE(ep, call, nh, TAG_END());
|
||||
RESPOND(ep, call, nh, SIP_200_OK,
|
||||
TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
|
||||
TAG_END());
|
||||
}
|
||||
else switch (callstate(tags)) {
|
||||
case nua_callstate_received:
|
||||
RESPOND(ep, call, nh, SIP_180_RINGING,
|
||||
SIPTAG_REQUIRE_STR("100rel"),
|
||||
TAG_END());
|
||||
return 0;
|
||||
case nua_callstate_early:
|
||||
return 0;
|
||||
case nua_callstate_ready:
|
||||
return 1;
|
||||
case nua_callstate_terminated:
|
||||
if (call)
|
||||
nua_handle_destroy(call->nh), call->nh = NULL;
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
X INVITE
|
||||
| |
|
||||
|-------INVITE------>|
|
||||
|<--------200--------|
|
||||
|---------ACK------->|
|
||||
*/
|
||||
int until_ready2(CONDITION_PARAMS)
|
||||
{
|
||||
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
|
||||
return 0;
|
||||
|
||||
save_event_in_list(ctx, event, ep, call);
|
||||
|
||||
if (event == nua_r_invite && status == 491) {
|
||||
if (ep == &ctx->a && ++ctx->b.flags.n >= 2) ctx->b.running = 0;
|
||||
if (ep == &ctx->b && ++ctx->a.flags.n >= 2) ctx->a.running = 0;
|
||||
}
|
||||
|
||||
switch (callstate(tags)) {
|
||||
case nua_callstate_ready:
|
||||
return ++ep->flags.n >= 2;
|
||||
case nua_callstate_terminated:
|
||||
if (call)
|
||||
nua_handle_destroy(call->nh), call->nh = NULL;
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int test_reinvites(struct context *ctx)
|
||||
{
|
||||
int retval = 0;
|
||||
@ -794,7 +996,10 @@ int test_reinvites(struct context *ctx)
|
||||
retval = test_call_hold(ctx);
|
||||
|
||||
if (retval == 0)
|
||||
retval |= test_reinvite(ctx);
|
||||
retval = test_reinvite(ctx);
|
||||
|
||||
if (retval == 0)
|
||||
retval = test_reinvite2(ctx);
|
||||
|
||||
if (print_headings && retval == 0)
|
||||
printf("TEST NUA-7: PASSED\n");
|
||||
|
@ -261,7 +261,8 @@ int test_reject_b(struct context *ctx)
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
int reject_302(CONDITION_PARAMS);
|
||||
int reject_302(CONDITION_PARAMS), reject_305(CONDITION_PARAMS);
|
||||
int redirect_always(CONDITION_PARAMS);
|
||||
int reject_604(CONDITION_PARAMS);
|
||||
|
||||
/*
|
||||
@ -281,6 +282,7 @@ int reject_604(CONDITION_PARAMS);
|
||||
|<---604 Nowhere-----|
|
||||
|--------ACK-------->|
|
||||
*/
|
||||
|
||||
int reject_302(CONDITION_PARAMS)
|
||||
{
|
||||
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
|
||||
@ -298,6 +300,33 @@ int reject_302(CONDITION_PARAMS)
|
||||
SIPTAG_CONTACT(m), TAG_END());
|
||||
}
|
||||
return 0;
|
||||
case nua_callstate_terminated:
|
||||
if (call)
|
||||
nua_handle_destroy(call->nh), call->nh = NULL;
|
||||
ep->next_condition = reject_305;
|
||||
return 0;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int reject_305(CONDITION_PARAMS)
|
||||
{
|
||||
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
|
||||
return 0;
|
||||
|
||||
save_event_in_list(ctx, event, ep, call);
|
||||
|
||||
switch (callstate(tags)) {
|
||||
case nua_callstate_received:
|
||||
{
|
||||
sip_contact_t m[1];
|
||||
*m = *ep->contact;
|
||||
m->m_url->url_user = "305";
|
||||
m->m_url->url_params = "lr=1";
|
||||
RESPOND(ep, call, nh, SIP_305_USE_PROXY, SIPTAG_CONTACT(m), TAG_END());
|
||||
}
|
||||
return 0;
|
||||
case nua_callstate_terminated:
|
||||
if (call)
|
||||
nua_handle_destroy(call->nh), call->nh = NULL;
|
||||
@ -308,6 +337,27 @@ int reject_302(CONDITION_PARAMS)
|
||||
}
|
||||
}
|
||||
|
||||
int redirect_always(CONDITION_PARAMS)
|
||||
{
|
||||
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
|
||||
return 0;
|
||||
|
||||
if (event == nua_i_invite) {
|
||||
char user[30];
|
||||
sip_contact_t m[1];
|
||||
*m = *ep->contact;
|
||||
snprintf(user, sizeof user, "user-%u", ep->flags.n++);
|
||||
m->m_url->url_user = user;
|
||||
RESPOND(ep, call, nh, SIP_302_MOVED_TEMPORARILY,
|
||||
SIPTAG_CONTACT(m), TAG_END());
|
||||
nua_handle_destroy(nh);
|
||||
call->nh = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int reject_604(CONDITION_PARAMS)
|
||||
{
|
||||
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
|
||||
@ -338,6 +388,7 @@ int test_reject_302(struct context *ctx)
|
||||
struct endpoint *a = &ctx->a, *b = &ctx->b;
|
||||
struct call *a_call = a->call, *b_call = b->call;
|
||||
struct event *e;
|
||||
sip_t const *sip;
|
||||
|
||||
/* Make call reject-3 */
|
||||
if (print_headings)
|
||||
@ -388,6 +439,12 @@ int test_reject_302(struct context *ctx)
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
|
||||
TEST_1(is_offer_sent(e->data->e_tags));
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST(e->data->e_status, 100);
|
||||
TEST(sip_object(e->data->e_msg)->sip_status->st_status, 305);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
|
||||
TEST_1(is_offer_sent(e->data->e_tags));
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST(e->data->e_status, 180);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
|
||||
@ -415,6 +472,18 @@ int test_reject_302(struct context *ctx)
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
|
||||
TEST_1(is_offer_recv(e->data->e_tags));
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_invite);
|
||||
TEST(e->data->e_status, 100);
|
||||
TEST_1(sip = sip_object(e->data->e_msg));
|
||||
TEST_1(sip->sip_request);
|
||||
TEST_S(sip->sip_request->rq_url->url_user, "302");
|
||||
TEST_1(sip->sip_route);
|
||||
TEST_S(sip->sip_route->r_url->url_user, "305");
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
|
||||
TEST_1(is_offer_recv(e->data->e_tags));
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
|
||||
@ -425,6 +494,25 @@ int test_reject_302(struct context *ctx)
|
||||
free_events_in_list(ctx, b->events);
|
||||
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-4.3: PASSED\n");
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-4.3.1: redirect until retry count is exceeded\n");
|
||||
|
||||
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
|
||||
INVITE(a, a_call, a_call->nh,
|
||||
TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
|
||||
SIPTAG_SUBJECT_STR("redirect always"),
|
||||
SOATAG_USER_SDP_STR(a_call->sdp),
|
||||
TAG_END());
|
||||
run_ab_until(ctx, -1, until_terminated, -1, redirect_always);
|
||||
|
||||
free_events_in_list(ctx, a->events);
|
||||
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
|
||||
free_events_in_list(ctx, b->events);
|
||||
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-4.3: PASSED\n");
|
||||
|
||||
@ -638,11 +726,12 @@ int test_reject_401(struct context *ctx)
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_invite);
|
||||
TEST(e->data->e_status, 100);
|
||||
TEST_1(sip = sip_object(e->data->e_msg));
|
||||
TEST_1(sip->sip_proxy_authorization);
|
||||
/* Ensure that nua_authenticate() tags get added to the request */
|
||||
TEST_1(sip->sip_subject);
|
||||
TEST_S(sip->sip_subject->g_value, "Got 407");
|
||||
TEST_1(sip->sip_proxy_authorization);
|
||||
TEST(e->data->e_status, 100);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
|
||||
TEST_1(is_offer_recv(e->data->e_tags));
|
||||
@ -723,7 +812,7 @@ int test_reject_401_aka(struct context *ctx)
|
||||
sip_t const *sip;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-4.6: invalid challenge \n");
|
||||
printf("TEST NUA-4.6.1: invalid challenge \n");
|
||||
|
||||
a_call->sdp = "m=audio 5008 RTP/AVP 8";
|
||||
b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
|
||||
@ -772,7 +861,161 @@ int test_reject_401_aka(struct context *ctx)
|
||||
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-4.6: PASSED\n");
|
||||
printf("TEST NUA-4.6.1: PASSED\n");
|
||||
|
||||
END();
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
/* Reject call with 401, twice */
|
||||
|
||||
/*
|
||||
A reject-401-bad B
|
||||
| |
|
||||
|-------INVITE------>|
|
||||
|<----100 Trying-----|
|
||||
|<--------401--------|
|
||||
|---------ACK------->|
|
||||
| |
|
||||
|-------INVITE------>|
|
||||
|<----100 Trying-----|
|
||||
|<--------401--------|
|
||||
|---------ACK------->|
|
||||
*/
|
||||
|
||||
int reject_401_bad(CONDITION_PARAMS)
|
||||
{
|
||||
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
|
||||
return 0;
|
||||
|
||||
save_event_in_list(ctx, event, ep, call);
|
||||
|
||||
switch (callstate(tags)) {
|
||||
case nua_callstate_received:
|
||||
RESPOND(ep, call, nh, SIP_401_UNAUTHORIZED,
|
||||
/* Send a challenge that we do not grok */
|
||||
SIPTAG_WWW_AUTHENTICATE_STR("Digest realm=\"No hope\", "
|
||||
"nonce=\"goO541ftNrw327aWpu2\", "
|
||||
"algorithm=MD5, "
|
||||
"qop=\"auth\""),
|
||||
TAG_END());
|
||||
return 0;
|
||||
case nua_callstate_terminated:
|
||||
if (call)
|
||||
nua_handle_destroy(call->nh), call->nh = NULL;
|
||||
if (ep->flags.bit0) /* Terminate 2 calls */
|
||||
return 1;
|
||||
ep->flags.bit0 = 1;
|
||||
return 0;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int authenticate_bad(CONDITION_PARAMS)
|
||||
{
|
||||
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
|
||||
return 0;
|
||||
|
||||
save_event_in_list(ctx, event, ep, call);
|
||||
|
||||
if (event == nua_r_invite && status == 401) {
|
||||
AUTHENTICATE(ep, call, nh, NUTAG_AUTH("Digest:\"No hope\":jaska:secret"),
|
||||
SIPTAG_SUBJECT_STR("Bad password"),
|
||||
TAG_END());
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (callstate(tags)) {
|
||||
case nua_callstate_terminated:
|
||||
if (call)
|
||||
nua_handle_destroy(call->nh), call->nh = NULL;
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int test_reject_401_bad(struct context *ctx)
|
||||
{
|
||||
BEGIN();
|
||||
|
||||
struct endpoint *a = &ctx->a, *b = &ctx->b;
|
||||
struct call *a_call = a->call, *b_call = b->call;
|
||||
struct event const *e;
|
||||
sip_t const *sip;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-4.6.2: bad username/password\n");
|
||||
|
||||
a_call->sdp = "m=audio 5008 RTP/AVP 8";
|
||||
|
||||
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
|
||||
INVITE(a, a_call, a_call->nh,
|
||||
TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
|
||||
SIPTAG_SUBJECT_STR("reject-401-bad"),
|
||||
SOATAG_USER_SDP_STR(a_call->sdp),
|
||||
TAG_END());
|
||||
|
||||
|
||||
run_ab_until(ctx, -1, authenticate_bad, -1, reject_401_bad);
|
||||
|
||||
/*
|
||||
Client transitions
|
||||
INIT -(C1)-> CALLING -(C6a)-> TERMINATED/INIT
|
||||
*/
|
||||
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
|
||||
TEST_1(is_offer_sent(e->data->e_tags));
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST(sip_object(e->data->e_msg)->sip_status->st_status, 401);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
|
||||
TEST_1(is_offer_sent(e->data->e_tags));
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST(sip_object(e->data->e_msg)->sip_status->st_status, 401);
|
||||
/* nua_authenticate() fails and INVITE returns an internal error response */
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST(e->data->e_status, 904);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
|
||||
TEST_1(!e->next);
|
||||
|
||||
free_events_in_list(ctx, a->events);
|
||||
|
||||
/*
|
||||
Server transitions:
|
||||
INIT -(S1)-> RECEIVED -(S6a)-> TERMINATED
|
||||
*/
|
||||
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
|
||||
TEST_1(sip = sip_object(e->data->e_msg));
|
||||
TEST(e->data->e_status, 100);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
|
||||
TEST_1(is_offer_recv(e->data->e_tags));
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
|
||||
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_invite);
|
||||
TEST_1(sip = sip_object(e->data->e_msg));
|
||||
TEST(e->data->e_status, 100);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
|
||||
TEST_1(is_offer_recv(e->data->e_tags));
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
|
||||
TEST_1(!e->next);
|
||||
|
||||
free_events_in_list(ctx, b->events);
|
||||
|
||||
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
|
||||
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-4.6.2: PASSED\n");
|
||||
|
||||
END();
|
||||
}
|
||||
@ -911,7 +1154,7 @@ int test_mime_negotiation(struct context *ctx)
|
||||
|
||||
/*
|
||||
Client transitions in reject-3:
|
||||
INIT -(C1)-> PROCEEDING -(C6a)-> TERMINATED
|
||||
INIT -(C1)-> CALLING -(C6a)-> TERMINATED
|
||||
*/
|
||||
|
||||
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
|
||||
@ -927,7 +1170,7 @@ int test_mime_negotiation(struct context *ctx)
|
||||
/* No content-encoding is supported */
|
||||
TEST_S(sip->sip_accept_encoding->aa_value, "");
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* CALLING */
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
|
||||
TEST_1(!e->next);
|
||||
|
||||
free_events_in_list(ctx, a->events);
|
||||
@ -944,3 +1187,340 @@ int test_mime_negotiation(struct context *ctx)
|
||||
|
||||
END();
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
size_t filter_200_OK(void *arg, void *message, size_t len)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
if (len >= 11 && strncasecmp(message, "SIP/2.0 200", 11) == 0)
|
||||
return 0;
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t filter_ACK(void *arg, void *message, size_t len)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
if (len >= 7 && strncasecmp(message, "ACK sip", 7) == 0)
|
||||
return 0;
|
||||
return len;
|
||||
}
|
||||
|
||||
int call_with_bad_ack(CONDITION_PARAMS);
|
||||
int accept_call_with_bad_contact(CONDITION_PARAMS);
|
||||
|
||||
int test_call_timeouts(struct context *ctx)
|
||||
{
|
||||
BEGIN();
|
||||
|
||||
struct endpoint *a = &ctx->a, *b = &ctx->b;
|
||||
struct call *a_call = a->call, *b_call = b->call;
|
||||
struct event *e;
|
||||
struct nat_filter *f, *f2;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-4.7: check for error and timeout handling\n");
|
||||
|
||||
a_call->sdp = "m=audio 5008 RTP/AVP 8";
|
||||
b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
|
||||
|
||||
if (!ctx->nat)
|
||||
goto completed_4_7_1;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-4.7.1: ACK timeout (200 OK filtered)\n");
|
||||
|
||||
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
|
||||
|
||||
TEST_1(f = test_nat_add_filter(ctx->nat, filter_200_OK, NULL, nat_inbound));
|
||||
TEST_1(f2 = test_nat_add_filter(ctx->nat, filter_200_OK,
|
||||
NULL, nat_outbound));
|
||||
|
||||
INVITE(a, a_call, a_call->nh,
|
||||
TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
|
||||
SIPTAG_SUBJECT_STR("NUA-4.7.1"),
|
||||
SOATAG_USER_SDP_STR(a_call->sdp),
|
||||
TAG_END());
|
||||
run_ab_until(ctx, -1, until_terminated, -1, accept_call);
|
||||
|
||||
/*
|
||||
A accept_call B
|
||||
| |
|
||||
|-------INVITE------>|
|
||||
|<----100 Trying-----|
|
||||
| |
|
||||
|<----180 Ringing----|
|
||||
| |
|
||||
| X-----200--------|
|
||||
| X-----200--------|
|
||||
| X-----200--------|
|
||||
| |
|
||||
|<--------BYE--------|
|
||||
|--------200 OK---X |
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
Client transitions:
|
||||
*/
|
||||
|
||||
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST(e->data->e_status, 180);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_bye);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
|
||||
TEST_1(!e->next);
|
||||
|
||||
/*
|
||||
Server transitions:
|
||||
-(S1)-> RECEIVED -(S2a)-> EARLY -(S3b)-> COMPLETED -(S5)-> TERMINATING
|
||||
-(S10)-> TERMINATED -X
|
||||
*/
|
||||
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
|
||||
TEST(e->data->e_status, 100);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
|
||||
TEST_1(is_offer_recv(e->data->e_tags));
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
|
||||
TEST_1(is_answer_sent(e->data->e_tags));
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_error);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminating); /* TERMINATING */
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_bye);
|
||||
TEST(e->data->e_status, 408);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
|
||||
TEST_1(!e->next);
|
||||
|
||||
free_events_in_list(ctx, a->events);
|
||||
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
|
||||
free_events_in_list(ctx, b->events);
|
||||
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
|
||||
|
||||
TEST_1(test_nat_remove_filter(ctx->nat, f) == 0);
|
||||
TEST_1(test_nat_remove_filter(ctx->nat, f2) == 0);
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-4.7.1: PASSED\n");
|
||||
|
||||
completed_4_7_1:
|
||||
|
||||
if (!ctx->nat)
|
||||
goto completed_4_7_2;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-4.7.2: ACK timeout (ACK filtered)\n");
|
||||
|
||||
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
|
||||
|
||||
TEST_1(f = test_nat_add_filter(ctx->nat, filter_ACK, NULL, nat_outbound));
|
||||
|
||||
INVITE(a, a_call, a_call->nh,
|
||||
TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
|
||||
SIPTAG_SUBJECT_STR("NUA-4.7.2"),
|
||||
SOATAG_USER_SDP_STR(a_call->sdp),
|
||||
TAG_END());
|
||||
run_ab_until(ctx, -1, until_terminated, -1, accept_call);
|
||||
|
||||
/*
|
||||
A accept_call B
|
||||
| |
|
||||
|-------INVITE------>|
|
||||
|<----100 Trying-----|
|
||||
| |
|
||||
|<----180 Ringing----|
|
||||
| |
|
||||
|<--------200--------|
|
||||
|--------ACK-----X |
|
||||
| |
|
||||
|<--------200--------|
|
||||
|--------ACK-----X |
|
||||
| |
|
||||
|<--------200--------|
|
||||
|--------ACK-----X |
|
||||
| |
|
||||
|<--------BYE--------|
|
||||
|--------200 OK----->|
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
*/
|
||||
|
||||
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST(e->data->e_status, 180);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST(e->data->e_status, 200);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_bye);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminated);
|
||||
TEST_1(!e->next);
|
||||
|
||||
/*
|
||||
Server transitions:
|
||||
-(S1)-> RECEIVED -(S2a)-> EARLY -(S3b)-> COMPLETED -(S5)-> TERMINATING
|
||||
-(S10)-> TERMINATED -X
|
||||
*/
|
||||
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
|
||||
TEST(e->data->e_status, 100);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
|
||||
TEST_1(is_offer_recv(e->data->e_tags));
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
|
||||
TEST_1(is_answer_sent(e->data->e_tags));
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_error);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminating); /* TERMINATING */
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_bye);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
|
||||
TEST_1(!e->next);
|
||||
|
||||
free_events_in_list(ctx, a->events);
|
||||
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
|
||||
free_events_in_list(ctx, b->events);
|
||||
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
|
||||
|
||||
TEST_1(test_nat_remove_filter(ctx->nat, f) == 0);
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-4.7.2: PASSED\n");
|
||||
|
||||
completed_4_7_2:
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-4.7.3: sending ACK fails\n");
|
||||
|
||||
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
|
||||
|
||||
INVITE(a, a_call, a_call->nh,
|
||||
TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
|
||||
SIPTAG_SUBJECT_STR("NUA-4.7.3"),
|
||||
SOATAG_USER_SDP_STR(a_call->sdp),
|
||||
NUTAG_AUTOACK(0),
|
||||
TAG_END());
|
||||
run_ab_until(ctx, -1, call_with_bad_ack, -1, accept_call);
|
||||
|
||||
/*
|
||||
A accept_call B
|
||||
| |
|
||||
|-------INVITE------>|
|
||||
|<----100 Trying-----|
|
||||
| |
|
||||
|<----180 Ringing----|
|
||||
| |
|
||||
|<--------200--------|
|
||||
|--ACK-X |
|
||||
| |
|
||||
|---------BYE------->|
|
||||
|<-------200 OK------|
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
*/
|
||||
|
||||
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST(e->data->e_status, 180);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST(e->data->e_status, 200);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_completing); /* COMPLETING */
|
||||
/* try to send ACK */
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminating);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_bye);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminated);
|
||||
TEST_1(!e->next);
|
||||
|
||||
/*
|
||||
Server transitions:
|
||||
-(S1)-> RECEIVED -(S2a)-> EARLY -(S3b)-> COMPLETED -(S5)-> TERMINATING
|
||||
-(S10)-> TERMINATED -X
|
||||
*/
|
||||
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
|
||||
TEST(e->data->e_status, 100);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
|
||||
TEST_1(is_offer_recv(e->data->e_tags));
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
|
||||
TEST_1(is_answer_sent(e->data->e_tags));
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_bye);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
|
||||
TEST_1(!e->next);
|
||||
|
||||
free_events_in_list(ctx, a->events);
|
||||
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
|
||||
free_events_in_list(ctx, b->events);
|
||||
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-4.7.3: PASSED\n");
|
||||
|
||||
/* XXX - PRACK timeout, PRACK failing, media failing, re-INVITEs */
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-4.7: PASSED\n");
|
||||
|
||||
END();
|
||||
}
|
||||
|
||||
int call_with_bad_ack(CONDITION_PARAMS)
|
||||
{
|
||||
if (!check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR))
|
||||
return 0;
|
||||
|
||||
save_event_in_list(ctx, event, ep, call);
|
||||
|
||||
if (event == nua_r_invite && 200 <= status && status < 300) {
|
||||
ACK(ep, call, nh,
|
||||
/* Syntax error - sending ACK fails, we send BYE */
|
||||
SIPTAG_MAX_FORWARDS_STR("blue"),
|
||||
TAG_END());
|
||||
}
|
||||
|
||||
return event == nua_i_state && callstate(tags) == nua_callstate_terminated;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
int test_rejects(struct context *ctx)
|
||||
{
|
||||
return
|
||||
test_reject_401_bad(ctx) ||
|
||||
test_reject_a(ctx) ||
|
||||
test_reject_b(ctx) ||
|
||||
test_reject_302(ctx) ||
|
||||
test_reject_401(ctx) ||
|
||||
test_mime_negotiation(ctx) ||
|
||||
test_call_timeouts(ctx) ||
|
||||
test_reject_401_aka(ctx) ||
|
||||
0;
|
||||
}
|
||||
|
@ -118,6 +118,8 @@ int cancel_when_ringing(CONDITION_PARAMS)
|
||||
case nua_callstate_proceeding:
|
||||
CANCEL(ep, call, nh, TAG_END());
|
||||
return 0;
|
||||
case nua_callstate_ready:
|
||||
return 1;
|
||||
case nua_callstate_terminated:
|
||||
return 1;
|
||||
default:
|
||||
@ -144,6 +146,7 @@ int alert_call(CONDITION_PARAMS)
|
||||
}
|
||||
}
|
||||
|
||||
int accept_after_183(CONDITION_PARAMS);
|
||||
|
||||
int test_call_cancel(struct context *ctx)
|
||||
{
|
||||
@ -211,7 +214,7 @@ int test_call_cancel(struct context *ctx)
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-5.2: cancel call when ringing\n");
|
||||
printf("TEST NUA-5.2.1: cancel call when ringing\n");
|
||||
|
||||
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
|
||||
|
||||
@ -278,11 +281,56 @@ int test_call_cancel(struct context *ctx)
|
||||
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-5.2: PASSED\n");
|
||||
printf("TEST NUA-5.2.1: PASSED\n");
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
if (print_headings)
|
||||
printf("TEST NUA-5.2.2: CANCEL call when server waits for PRACK\n");
|
||||
|
||||
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
|
||||
|
||||
INVITE(a, a_call, a_call->nh,
|
||||
TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
|
||||
SOATAG_USER_SDP_STR(a_call->sdp),
|
||||
NUTAG_APPL_METHOD("PRACK"),
|
||||
/*SIPTAG_REJECT_CONTACT_STR("*;audio=FALSE"),*/
|
||||
TAG_END());
|
||||
|
||||
run_ab_until(ctx, -1, cancel_when_ringing, -1, accept_after_183);
|
||||
|
||||
free_events_in_list(ctx, a->events);
|
||||
free_events_in_list(ctx, b->events);
|
||||
|
||||
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
|
||||
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-5.2.2: PASSED\n");
|
||||
|
||||
|
||||
END();
|
||||
}
|
||||
|
||||
int accept_after_183(CONDITION_PARAMS)
|
||||
{
|
||||
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
|
||||
return 0;
|
||||
|
||||
save_event_in_list(ctx, event, ep, call);
|
||||
|
||||
switch (callstate(tags)) {
|
||||
case nua_callstate_received:
|
||||
RESPOND(ep, call, nh, SIP_183_SESSION_PROGRESS, TAG_END());
|
||||
RESPOND(ep, call, nh, SIP_200_OK, TAG_END());
|
||||
return 0;
|
||||
case nua_callstate_terminated:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ======================================================================== */
|
||||
/* Destroy call handle */
|
||||
|
||||
@ -496,13 +544,13 @@ int destroy_when_early(CONDITION_PARAMS)
|
||||
return 0;
|
||||
case nua_callstate_early:
|
||||
if (call)
|
||||
nua_handle_destroy(call->nh), call->nh = NULL;
|
||||
DESTROY(ep, call, nh), call->nh = NULL;
|
||||
return 1;
|
||||
case nua_callstate_completed:
|
||||
case nua_callstate_ready:
|
||||
case nua_callstate_terminated:
|
||||
if (call)
|
||||
nua_handle_destroy(call->nh), call->nh = NULL;
|
||||
DESTROY(ep, call, nh), call->nh = NULL;
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
@ -594,7 +642,7 @@ int destroy_when_completed(CONDITION_PARAMS)
|
||||
case nua_callstate_ready:
|
||||
case nua_callstate_terminated:
|
||||
if (call)
|
||||
nua_handle_destroy(call->nh), call->nh = NULL;
|
||||
DESTROY(ep, call, nh), call->nh = NULL;
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
@ -673,6 +721,82 @@ int test_call_destroy_4(struct context *ctx)
|
||||
END();
|
||||
}
|
||||
|
||||
/* Destroy when one INVITE is queued. */
|
||||
int test_call_destroy_5(struct context *ctx)
|
||||
{
|
||||
BEGIN();
|
||||
|
||||
struct endpoint *a = &ctx->a, *b = &ctx->b;
|
||||
struct call *a_call = a->call, *b_call = b->call;
|
||||
struct event *e;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-5.7: destroy when re-INVITE is queued\n");
|
||||
|
||||
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
|
||||
|
||||
INVITE(a, a_call, a_call->nh,
|
||||
TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
|
||||
NUTAG_AUTOACK(0),
|
||||
SOATAG_USER_SDP_STR(a_call->sdp),
|
||||
TAG_END());
|
||||
|
||||
INVITE(a, a_call, a_call->nh, TAG_END());
|
||||
|
||||
run_ab_until(ctx, -1, until_terminated, -1, destroy_when_completed);
|
||||
|
||||
/* Client transitions:
|
||||
INIT -(C1)-> CALLING: nua_invite(), ...
|
||||
*/
|
||||
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
|
||||
TEST_1(is_offer_sent(e->data->e_tags));
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST(e->data->e_status, 180);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST(e->data->e_status, 200);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_completing); /* COMPLETING */
|
||||
TEST_1(is_answer_recv(e->data->e_tags));
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_bye);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST(e->data->e_status, 481);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
|
||||
TEST_1(!e->next);
|
||||
|
||||
free_events_in_list(ctx, a->events);
|
||||
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
|
||||
|
||||
/*
|
||||
Server transitions:
|
||||
INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
|
||||
RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
|
||||
EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state ... DESTROY
|
||||
*/
|
||||
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
|
||||
TEST(e->data->e_status, 100);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
|
||||
TEST_1(is_offer_recv(e->data->e_tags));
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
|
||||
TEST_1(is_answer_sent(e->data->e_tags));
|
||||
TEST_1(!e->next);
|
||||
|
||||
free_events_in_list(ctx, b->events);
|
||||
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-5.7: PASSED\n");
|
||||
|
||||
END();
|
||||
}
|
||||
|
||||
int test_call_destroy(struct context *ctx)
|
||||
{
|
||||
struct endpoint *a = &ctx->a, *b = &ctx->b;
|
||||
@ -685,10 +809,12 @@ int test_call_destroy(struct context *ctx)
|
||||
test_call_destroy_1(ctx) ||
|
||||
test_call_destroy_2(ctx) ||
|
||||
test_call_destroy_3(ctx) ||
|
||||
test_call_destroy_4(ctx);
|
||||
test_call_destroy_4(ctx) ||
|
||||
test_call_destroy_5(ctx);
|
||||
}
|
||||
|
||||
/* ======================================================================== */
|
||||
|
||||
/* Early BYE
|
||||
|
||||
A B
|
||||
@ -731,13 +857,30 @@ int bye_when_ringing(CONDITION_PARAMS)
|
||||
}
|
||||
}
|
||||
|
||||
int test_early_bye(struct context *ctx)
|
||||
int bye_when_completing(CONDITION_PARAMS);
|
||||
|
||||
static int ack_sent = 0;
|
||||
|
||||
size_t count_acks(void *arg, void *message, size_t len)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
if (strncasecmp(message, "ACK sip:", 8) == 0)
|
||||
ack_sent++;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int test_bye_before_200(struct context *ctx)
|
||||
{
|
||||
BEGIN();
|
||||
struct endpoint *a = &ctx->a, *b = &ctx->b;
|
||||
struct call *a_call = a->call, *b_call = b->call;
|
||||
struct event *e;
|
||||
|
||||
a_call->sdp = "m=audio 5008 RTP/AVP 8";
|
||||
b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-6.1: BYE call when ringing\n");
|
||||
|
||||
@ -809,3 +952,513 @@ int test_early_bye(struct context *ctx)
|
||||
END();
|
||||
}
|
||||
|
||||
|
||||
int bye_when_completing(CONDITION_PARAMS)
|
||||
{
|
||||
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
|
||||
return 0;
|
||||
|
||||
save_event_in_list(ctx, event, ep, call);
|
||||
|
||||
switch (callstate(tags)) {
|
||||
case nua_callstate_completing:
|
||||
ack_sent = 0;
|
||||
BYE(ep, call, nh, TAG_END());
|
||||
return 0;
|
||||
case nua_callstate_terminated:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int test_bye_before_ack(struct context *ctx)
|
||||
{
|
||||
BEGIN();
|
||||
struct endpoint *a = &ctx->a, *b = &ctx->b;
|
||||
struct call *a_call = a->call, *b_call = b->call;
|
||||
struct event *e;
|
||||
struct nat_filter *f = NULL;
|
||||
|
||||
a_call->sdp = "m=audio 5008 RTP/AVP 8";
|
||||
b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
|
||||
|
||||
/* Early BYE 2
|
||||
|
||||
A B
|
||||
|-------INVITE------>|
|
||||
|<----100 Trying-----|
|
||||
| |
|
||||
|<----180 Ringing----|
|
||||
|<-------200---------|
|
||||
| |
|
||||
|--------BYE-------->|
|
||||
|<------200 OK-------|
|
||||
|--------ACK-------->|
|
||||
| |
|
||||
| |
|
||||
*/
|
||||
if (print_headings)
|
||||
printf("TEST NUA-6.2: BYE call when completing\n");
|
||||
|
||||
if (ctx->nat)
|
||||
TEST_1(f = test_nat_add_filter(ctx->nat, count_acks, NULL, nat_outbound));
|
||||
ack_sent = 0;
|
||||
|
||||
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
|
||||
|
||||
INVITE(a, a_call, a_call->nh,
|
||||
TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
|
||||
SOATAG_USER_SDP_STR(a_call->sdp),
|
||||
NUTAG_AUTOACK(0),
|
||||
TAG_END());
|
||||
|
||||
run_ab_until(ctx, -1, bye_when_completing, -1, accept_until_terminated);
|
||||
|
||||
/* Client transitions:
|
||||
INIT -(C1)-> CALLING: nua_invite(), nua_i_state
|
||||
CALLING -(C2)-> PROCEEDING: nua_r_invite(180, nua_i_state, nua_cancel()
|
||||
PROCEEDING -(C6b)-> TERMINATED: nua_r_invite(487), nua_i_state
|
||||
*/
|
||||
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_calling);
|
||||
TEST_1(is_offer_sent(e->data->e_tags));
|
||||
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST(e->data->e_status, 180);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
|
||||
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST(e->data->e_status, 200);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_completing);
|
||||
TEST_1(e = e->next);
|
||||
|
||||
TEST_E(e->data->e_event, nua_r_bye); TEST(e->data->e_status, 200);
|
||||
TEST_1(e->data->e_msg);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
|
||||
TEST_1(!e->next);
|
||||
|
||||
if (ctx->nat) {
|
||||
while (ack_sent == 0)
|
||||
su_root_step(ctx->root, 100);
|
||||
TEST_1(ack_sent > 0);
|
||||
TEST_1(test_nat_remove_filter(ctx->nat, f) == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
Server transitions:
|
||||
INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
|
||||
RECEIVED -(S2a)-> EARLY: nua_respond(180), nua_i_state
|
||||
EARLY -(S6b)--> TERMINATED: nua_i_cancel, nua_i_state
|
||||
*/
|
||||
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
|
||||
TEST(e->data->e_status, 100);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
|
||||
TEST_1(is_offer_recv(e->data->e_tags));
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_bye);
|
||||
TEST(e->data->e_status, 200);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
|
||||
TEST_1(!e->next);
|
||||
|
||||
free_events_in_list(ctx, a->events);
|
||||
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
|
||||
|
||||
free_events_in_list(ctx, b->events);
|
||||
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-6.2: PASSED\n");
|
||||
|
||||
END();
|
||||
}
|
||||
|
||||
int reject_reinvite_401(CONDITION_PARAMS);
|
||||
|
||||
int test_bye_after_receiving_401(struct context *ctx)
|
||||
{
|
||||
BEGIN();
|
||||
struct endpoint *a = &ctx->a, *b = &ctx->b;
|
||||
struct call *a_call = a->call, *b_call = b->call;
|
||||
struct event *e;
|
||||
|
||||
a_call->sdp = "m=audio 5008 RTP/AVP 8";
|
||||
b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
|
||||
|
||||
/* BYE after receiving 401
|
||||
|
||||
A B
|
||||
|-------INVITE------>|
|
||||
|<----100 Trying-----|
|
||||
| |
|
||||
|<----180 Ringing----|
|
||||
|<-------200---------|
|
||||
|--------ACK-------->|
|
||||
| |
|
||||
|<------INVITE-------|
|
||||
|--------401-------->|
|
||||
|<--------ACK--------|
|
||||
| |
|
||||
|<--------BYE--------|
|
||||
|------200 OK------->|
|
||||
| |
|
||||
*/
|
||||
if (print_headings)
|
||||
printf("TEST NUA-6.3: BYE after receiving 401\n");
|
||||
|
||||
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
|
||||
|
||||
INVITE(a, a_call, a_call->nh,
|
||||
TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
|
||||
SIPTAG_SUBJECT_STR("NUA-6.3"),
|
||||
SOATAG_USER_SDP_STR(a_call->sdp),
|
||||
NUTAG_AUTOANSWER(0),
|
||||
TAG_END());
|
||||
|
||||
run_ab_until(ctx, -1, until_ready, -1, accept_call);
|
||||
|
||||
free_events_in_list(ctx, a->events);
|
||||
|
||||
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
|
||||
free_events_in_list(ctx, b->events);
|
||||
|
||||
/* re-INVITE A. */
|
||||
INVITE(b, b_call, b_call->nh,
|
||||
SIPTAG_SUBJECT_STR("NUA-6.3 re-INVITE"),
|
||||
TAG_END());
|
||||
run_ab_until(ctx, -1, reject_reinvite_401, -1, until_final_response);
|
||||
|
||||
TEST_1(nua_handle_has_active_call(a_call->nh));
|
||||
TEST_1(nua_handle_has_active_call(b_call->nh));
|
||||
|
||||
free_events_in_list(ctx, a->events);
|
||||
free_events_in_list(ctx, b->events);
|
||||
|
||||
BYE(b, b_call, b_call->nh, TAG_END());
|
||||
|
||||
run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
|
||||
|
||||
free_events_in_list(ctx, a->events);
|
||||
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
|
||||
|
||||
free_events_in_list(ctx, b->events);
|
||||
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-6.3: PASSED\n");
|
||||
|
||||
END();
|
||||
}
|
||||
|
||||
int test_bye_after_sending_401(struct context *ctx)
|
||||
{
|
||||
BEGIN();
|
||||
struct endpoint *a = &ctx->a, *b = &ctx->b;
|
||||
struct call *a_call = a->call, *b_call = b->call;
|
||||
struct event *e;
|
||||
|
||||
a_call->sdp = "m=audio 5008 RTP/AVP 8";
|
||||
b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
|
||||
|
||||
/* BYE after sending 401
|
||||
|
||||
A B
|
||||
|-------INVITE------>|
|
||||
|<----100 Trying-----|
|
||||
| |
|
||||
|<----180 Ringing----|
|
||||
|<-------200---------|
|
||||
|--------ACK-------->|
|
||||
| |
|
||||
|<------INVITE-------|
|
||||
|--------401-------->|
|
||||
|<--------ACK--------|
|
||||
| |
|
||||
|--------BYE-------->|
|
||||
|<------200 OK-------|
|
||||
| |
|
||||
*/
|
||||
if (print_headings)
|
||||
printf("TEST NUA-6.4.1: BYE after sending 401\n");
|
||||
|
||||
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
|
||||
|
||||
INVITE(a, a_call, a_call->nh,
|
||||
TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
|
||||
SIPTAG_SUBJECT_STR("NUA-6.4.1"),
|
||||
SOATAG_USER_SDP_STR(a_call->sdp),
|
||||
NUTAG_AUTOANSWER(0),
|
||||
TAG_END());
|
||||
|
||||
run_ab_until(ctx, -1, until_ready, -1, accept_call);
|
||||
|
||||
free_events_in_list(ctx, a->events);
|
||||
|
||||
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
|
||||
free_events_in_list(ctx, b->events);
|
||||
|
||||
/* re-INVITE A. */
|
||||
INVITE(b, b_call, b_call->nh,
|
||||
SIPTAG_SUBJECT_STR("NUA-6.4.1 re-INVITE"),
|
||||
TAG_END());
|
||||
run_ab_until(ctx, -1, reject_reinvite_401, -1, until_final_response);
|
||||
|
||||
TEST_1(nua_handle_has_active_call(a_call->nh));
|
||||
TEST_1(nua_handle_has_active_call(b_call->nh));
|
||||
|
||||
free_events_in_list(ctx, a->events);
|
||||
free_events_in_list(ctx, b->events);
|
||||
|
||||
BYE(a, a_call, a_call->nh, TAG_END());
|
||||
|
||||
run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
|
||||
|
||||
free_events_in_list(ctx, a->events);
|
||||
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
|
||||
|
||||
free_events_in_list(ctx, b->events);
|
||||
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-6.4.1: PASSED\n");
|
||||
|
||||
END();
|
||||
}
|
||||
|
||||
int test_bye_after_receiving_401_to_update(struct context *ctx)
|
||||
{
|
||||
BEGIN();
|
||||
struct endpoint *a = &ctx->a, *b = &ctx->b;
|
||||
struct call *a_call = a->call, *b_call = b->call;
|
||||
struct event *e;
|
||||
|
||||
a_call->sdp = "m=audio 5008 RTP/AVP 8";
|
||||
b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
|
||||
|
||||
/* BYE after receiving 401
|
||||
|
||||
A B
|
||||
|-------INVITE------>|
|
||||
|<----100 Trying-----|
|
||||
| |
|
||||
|<----180 Ringing----|
|
||||
|<-------200---------|
|
||||
|--------ACK-------->|
|
||||
| |
|
||||
|<------UPDATE-------|
|
||||
|--------401-------->|
|
||||
| |
|
||||
|<--------BYE--------|
|
||||
|------200 OK------->|
|
||||
| |
|
||||
*/
|
||||
if (print_headings)
|
||||
printf("TEST NUA-6.4.2: BYE after receiving 401 to UPDATE\n");
|
||||
|
||||
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
|
||||
|
||||
INVITE(a, a_call, a_call->nh,
|
||||
TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
|
||||
SIPTAG_SUBJECT_STR("NUA-6.4.2"),
|
||||
SOATAG_USER_SDP_STR(a_call->sdp),
|
||||
NUTAG_AUTOANSWER(0),
|
||||
NUTAG_APPL_METHOD("UPDATE"),
|
||||
TAG_END());
|
||||
|
||||
run_ab_until(ctx, -1, until_ready, -1, accept_call);
|
||||
|
||||
free_events_in_list(ctx, a->events);
|
||||
|
||||
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
|
||||
free_events_in_list(ctx, b->events);
|
||||
|
||||
/* UPDATE A. */
|
||||
UPDATE(b, b_call, b_call->nh,
|
||||
SIPTAG_SUBJECT_STR("NUA-6.4.2 UPDATE"),
|
||||
TAG_END());
|
||||
BYE(b, b_call, b_call->nh, TAG_END()); /* Queued until nua_authenticate */
|
||||
run_ab_until(ctx, -1, reject_reinvite_401, -1, until_final_response);
|
||||
|
||||
TEST_1(nua_handle_has_active_call(a_call->nh));
|
||||
TEST_1(nua_handle_has_active_call(b_call->nh));
|
||||
|
||||
free_events_in_list(ctx, a->events);
|
||||
free_events_in_list(ctx, b->events);
|
||||
|
||||
AUTHENTICATE(b, b_call, b_call->nh, TAG_END());
|
||||
|
||||
run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
|
||||
|
||||
free_events_in_list(ctx, a->events);
|
||||
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
|
||||
|
||||
free_events_in_list(ctx, b->events);
|
||||
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-6.4.2: PASSED\n");
|
||||
|
||||
END();
|
||||
}
|
||||
|
||||
int reject_reinvite_401(CONDITION_PARAMS)
|
||||
{
|
||||
void *request = nua_current_request(nua);
|
||||
|
||||
save_event_in_list(ctx, event, ep, call);
|
||||
|
||||
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
|
||||
return 0;
|
||||
|
||||
if (status < 200 && (event == nua_i_invite || event == nua_i_update)) {
|
||||
RESPOND(ep, call, nh, SIP_401_UNAUTHORIZED,
|
||||
NUTAG_WITH(request),
|
||||
SIPTAG_WWW_AUTHENTICATE_STR("Digest realm=\"test_nua\", "
|
||||
"nonce=\"nsdhfuds\", algorithm=MD5, "
|
||||
"qop=\"auth\""),
|
||||
TAG_END());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (event == nua_i_state) switch (callstate(tags)) {
|
||||
case nua_callstate_ready:
|
||||
return 1;
|
||||
case nua_callstate_terminated:
|
||||
if (call)
|
||||
nua_handle_destroy(call->nh), call->nh = NULL;
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_bye_to_invalid_contact(struct context *ctx)
|
||||
{
|
||||
BEGIN();
|
||||
struct endpoint *a = &ctx->a, *b = &ctx->b;
|
||||
struct call *a_call = a->call, *b_call = b->call;
|
||||
struct event *e;
|
||||
|
||||
a_call->sdp = "m=audio 5008 RTP/AVP 8";
|
||||
b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
|
||||
|
||||
/* Early BYE 2
|
||||
|
||||
A B
|
||||
|-------INVITE------>|
|
||||
|<----100 Trying-----|
|
||||
| |
|
||||
|<----180 Ringing----|
|
||||
|<-------200---------|
|
||||
| |
|
||||
|--------BYE-------->|
|
||||
|<------200 OK-------|
|
||||
|--------ACK-------->|
|
||||
| |
|
||||
| |
|
||||
*/
|
||||
if (print_headings)
|
||||
printf("TEST NUA-6.4.3: BYE call when completing\n");
|
||||
|
||||
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
|
||||
|
||||
INVITE(a, a_call, a_call->nh,
|
||||
TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
|
||||
SOATAG_USER_SDP_STR(a_call->sdp),
|
||||
SIPTAG_CONTACT(NULL),
|
||||
SIPTAG_HEADER_STR("Contact: <<sip:xyzzy@com.invalid>"),
|
||||
TAG_END());
|
||||
|
||||
run_ab_until(ctx, -1, until_ready, -1, accept_call);
|
||||
|
||||
/* Client transitions:
|
||||
INIT -(C1)-> CALLING: nua_invite(), nua_i_state
|
||||
CALLING -(C2)-> PROCEEDING: nua_r_invite(180, nua_i_state, nua_cancel()
|
||||
PROCEEDING -(C6b)-> TERMINATED: nua_r_invite(487), nua_i_state
|
||||
*/
|
||||
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_calling);
|
||||
TEST_1(is_offer_sent(e->data->e_tags));
|
||||
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST(e->data->e_status, 180);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_proceeding);
|
||||
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST(e->data->e_status, 200);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_ready);
|
||||
TEST_1(!e->next);
|
||||
|
||||
/*
|
||||
Server transitions:
|
||||
INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
|
||||
RECEIVED -(S2a)-> EARLY: nua_respond(180), nua_i_state
|
||||
EARLY -(S6b)--> TERMINATED: nua_i_cancel, nua_i_state
|
||||
*/
|
||||
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
|
||||
TEST(e->data->e_status, 100);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
|
||||
TEST_1(is_offer_recv(e->data->e_tags));
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
|
||||
TEST_1(!e->next);
|
||||
|
||||
free_events_in_list(ctx, a->events);
|
||||
free_events_in_list(ctx, b->events);
|
||||
|
||||
BYE(b, b_call, b_call->nh, TAG_END());
|
||||
|
||||
run_b_until(ctx, -1, until_terminated);
|
||||
|
||||
/* B transitions:
|
||||
READY --(T2)--> TERMINATING: nua_bye()
|
||||
TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
|
||||
*/
|
||||
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_bye);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
|
||||
TEST_1(!e->next);
|
||||
free_events_in_list(ctx, b->events);
|
||||
|
||||
TEST_1(!nua_handle_has_active_call(b_call->nh));
|
||||
TEST_1(nua_handle_has_active_call(a_call->nh));
|
||||
|
||||
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
|
||||
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-6.4.3: PASSED\n");
|
||||
|
||||
END();
|
||||
}
|
||||
|
||||
int test_early_bye(struct context *ctx)
|
||||
{
|
||||
return
|
||||
test_bye_before_200(ctx) ||
|
||||
test_bye_before_ack(ctx) ||
|
||||
test_bye_after_receiving_401(ctx) ||
|
||||
test_bye_after_sending_401(ctx) ||
|
||||
test_bye_after_receiving_401_to_update(ctx) ||
|
||||
test_bye_to_invalid_contact(ctx) ||
|
||||
0;
|
||||
}
|
||||
|
@ -167,6 +167,13 @@ int test_extension(struct context *ctx)
|
||||
free_events_in_list(ctx, b->events);
|
||||
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
|
||||
|
||||
nua_set_params(b->nua,
|
||||
SIPTAG_ALLOW(b->allow),
|
||||
NUTAG_APPL_METHOD(NULL),
|
||||
NUTAG_APPL_METHOD(b->appl_method),
|
||||
TAG_END());
|
||||
run_b_until(ctx, nua_r_set_params, until_final_response);
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-13.1: PASSED\n");
|
||||
END();
|
||||
|
@ -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");
|
||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user