mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-04-13 07:45:26 +00:00
Update sofia-sip from darcs:
Mon May 14 12:43:07 EDT 2007 martti.mela@nokia.com * su_base_port.c: fixed a double free in su_base_port_start_shared(). Fri May 25 13:56:23 EDT 2007 Pekka.Pessi@nokia.com * soa: added SOATAG_ORDERED_USER(), SOATAG_REUSE_REJECTED(). Allow replacing existing m=lines. Sun May 27 14:52:13 EDT 2007 Pekka.Pessi@nokia.com * msg_parser.c: fixed bug #1726034 Mon May 28 04:57:08 EDT 2007 Pekka.Pessi@nokia.com * test_nth.c: using non-blocking connect in test program, too. Mon May 28 04:58:05 EDT 2007 Pekka.Pessi@nokia.com * su.c: making all sockets non-blocking by default. Mon May 28 04:59:28 EDT 2007 Pekka.Pessi@nokia.com * m4/sac-su.m4: moved contents into sac-s2.m4 Mon May 28 05:32:26 EDT 2007 Pekka.Pessi@nokia.com * RELEASE: updated. Wed May 30 10:37:53 EDT 2007 Pekka.Pessi@nokia.com * m4/sac-su2.m4: added configure option --disable-tag-cast. Added SU_INLINE_TAG_CAST into sofia-sip/su_configure.h{,.in}. Using SU_INLINE_TAG_CAST in sofia-sip/sip_tag.h{,.in} sofia-sip/http_tag.h{,.in} sofia-sip/su_tag.h sofia-sip/su_tag_io.h sofia-sip/auth_module.h sofia-sip/nth_tag.h sofia-sip/nua_tag.h Fri Jun 1 15:11:52 EDT 2007 Pekka.Pessi@nokia.com * tport.c: fixed tport_set_params() with secondary transports Fri Jun 1 15:13:23 EDT 2007 Pekka.Pessi@nokia.com * tport_type_tcp.c: checking for end-of-stream even if su_getmsgsize() promised more data Fri Jun 1 15:15:34 EDT 2007 Pekka.Pessi@nokia.com * tport: added tport_is_clear_to_send(), allow use of tport_pending() without msg The error callback from tport can now be registered even if there is no request pending on transport (e.g., when keeping a transport connection open for inbound messages). Fri Jun 1 15:16:43 EDT 2007 Pekka.Pessi@nokia.com * nta: not retrying after an transport error if application provided the transport Fri Jun 1 15:17:23 EDT 2007 Pekka.Pessi@nokia.com * sip: do not accept empty URIs (<>) in From, To, and other headers expecting name-addr format Fri Jun 1 15:17:43 EDT 2007 Pekka.Pessi@nokia.com * torture_url.c: added test for parsing empty URLs. Fri Jun 1 15:19:27 EDT 2007 Pekka.Pessi@nokia.com * nua/test_proxy.[hc]: use registered connections for outbound with TCP. Added test_proxy_close_tports() used testing recovering from TCP failures. Fri Jun 1 15:20:33 EDT 2007 Pekka.Pessi@nokia.com * test_nua.c: added --print-tags and --tags-a, --tags=b and --tags=c options Added more functions for handling events Fri Jun 1 15:22:08 EDT 2007 Pekka.Pessi@nokia.com * test_nua: fixed some tests depending on delivery of responses in correct order Reordering might happen if some messages are sent over TCP, other over UDP. Fri Jun 1 15:27:55 EDT 2007 Pekka.Pessi@nokia.com * nua_register.c: re-registering in case the TCP connection towards proxy is closed In test_nua, Mr. B is now using TCP with the test proxy. Fri Jun 1 15:35:39 EDT 2007 Pekka.Pessi@nokia.com * nua/test_refer.c: fixed SIP payload checks Fri Jun 1 15:36:08 EDT 2007 Pekka.Pessi@nokia.com * nta_internal.h: added orq_user_tport field Tue Jun 5 06:16:43 EDT 2007 Pekka.Pessi@nokia.com * hide_email.sh: now fixing links, too. Fri Jun 15 05:34:29 EDT 2007 Pekka.Pessi@nokia.com * nua: fixed documentation entries for API functions left out from doxygen Thanks for Jerry Ricahrds for pointing this out. Wed May 23 10:26:26 EDT 2007 Mikhail Zabaluev <mikhail.zabaluev@nokia.com> * Correct documentation for parameter type of NUTAG_WITH_SAVED Mon Jun 18 12:34:58 EDT 2007 Mikhail Zabaluev <mikhail.zabaluev@nokia.com> * Make nua_saved_event_request() and hence NUTAG_WITH_SAVED resilient to a NULL event content git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@5413 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
parent
5b27ad1332
commit
8ff384d36f
@ -24,7 +24,7 @@ EXTRA_DIST = AUTHORS COPYING COPYRIGHTS ChangeLog.ext-trees \
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
EXTRA_DIST += m4/sac-general.m4 m4/sac-su.m4 m4/sac-coverage.m4 \
|
||||
EXTRA_DIST += m4/sac-general.m4 m4/sac-coverage.m4 \
|
||||
m4/sac-su2.m4 m4/sac-tport.m4 m4/sac-openssl.m4
|
||||
|
||||
EXTRA_DIST += docs/build_system.txt \
|
||||
|
@ -24,6 +24,9 @@ API/ABI changes and versioning
|
||||
New features in API are marked with Doxytag macro @VERSION_1_12_7.
|
||||
|
||||
libsofia-sip-ua:
|
||||
- Removed extra system headers from <sofia-sip/stun_common.h>
|
||||
- Added global variable su_socket_blocking. If it is set to true,
|
||||
sockets are created as blocking.
|
||||
- Added accessor function nta_outgoing_branch()
|
||||
- **template**: Added foobar() function (sofia-sip/foobar.h).
|
||||
- This release is ABI/API compatible with applications linked against
|
||||
|
@ -69,7 +69,6 @@ AM_CONDITIONAL([HAVE_DOXYGEN], [test $DOXYGEN != echo])
|
||||
SAC_SOFIA_SU
|
||||
SAC_OPENSSL
|
||||
SAC_TPORT
|
||||
SAC_SU
|
||||
|
||||
### internal modules
|
||||
### ----------------
|
||||
|
@ -29,9 +29,13 @@
|
||||
#
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
echo "Hiding email addresses in ${1:-.}"
|
||||
echo "Postprocessing HTML in ${1:-.}: hiding email addresses, fixing links"
|
||||
|
||||
find ${1:-.} -name '*.html' -print0 |
|
||||
xargs -0 \
|
||||
sed -r -i 's/([:>;][a-z][-a-z.]*)(@[a-z][a-z]*)\.[a-z][a-z]*(["<\&])/\1\2-email.address.hidden\3/gi'
|
||||
|
||||
sed -r -i '
|
||||
# Hide e-mail addresses
|
||||
s/([:>;][a-z][-a-z.]*)(@[a-z][a-z]*)\.[a-z][a-z]*(["<\&])/\1\2-email.address.hidden\3/gi;
|
||||
# Fix cross-module links
|
||||
s!doxygen="([a-z]*).doxytags:../\1/" href="../\1/\1_index.html"!doxygen="\1.doxytags:../\1/" href="../\1/index.html"!g;
|
||||
'
|
||||
|
@ -102,7 +102,7 @@ SOFIAPUBVAR tag_typedef_t httptag_http;
|
||||
#define HTTPTAG_HTTP_REF(x) httptag_http_ref, httptag_http_vr(&(x))
|
||||
SOFIAPUBVAR tag_typedef_t httptag_http_ref;
|
||||
|
||||
#if SU_HAVE_INLINE
|
||||
#if SU_INLINE_TAG_CAST
|
||||
su_inline
|
||||
tag_value_t httptag_http_v(http_t const *v) { return (tag_value_t)v; }
|
||||
su_inline
|
||||
@ -150,7 +150,7 @@ SOFIAPUBVAR tag_typedef_t httptag_header;
|
||||
#define HTTPTAG_HEADER_REF(x) httptag_header_ref, httptag_header_vr(&(x))
|
||||
SOFIAPUBVAR tag_typedef_t httptag_header_ref;
|
||||
|
||||
#if SU_HAVE_INLINE
|
||||
#if SU_INLINE_TAG_CAST
|
||||
su_inline tag_value_t
|
||||
httptag_header_v(http_header_t const *v)
|
||||
{ return (tag_value_t)v; }
|
||||
@ -220,7 +220,7 @@ SOFIAPUBVAR tag_typedef_t httptag_#xxxxxx#_ref;
|
||||
#define HTTPTAG_#XXXXXX#_STR_REF(x) HTTPTAG_STR_REF(#xxxxxx#, x)
|
||||
SOFIAPUBVAR tag_typedef_t httptag_#xxxxxx#_str_ref;
|
||||
|
||||
#if SU_HAVE_INLINE
|
||||
#if SU_INLINE_TAG_CAST
|
||||
su_inline tag_value_t
|
||||
httptag_#xxxxxx#_v(http_#xxxxxx#_t const *v)
|
||||
{ return (tag_value_t)v; }
|
||||
|
@ -253,7 +253,7 @@ SOFIAPUBVAR tag_typedef_t authtag_module;
|
||||
#define AUTHTAG_MODULE_REF(x) authtag_module_ref, authtag_module_vr((&x))
|
||||
SOFIAPUBVAR tag_typedef_t authtag_module_ref;
|
||||
|
||||
#if SU_HAVE_INLINE
|
||||
#if SU_INLINE_TAG_CAST
|
||||
su_inline tag_value_t authtag_module_v(auth_mod_t *v) {
|
||||
return (tag_value_t)v;
|
||||
}
|
||||
|
@ -1840,6 +1840,8 @@ char *msg_as_string(su_home_t *home, msg_t *msg, msg_pub_t *pub, int flags,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
b = b2;
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -797,7 +797,21 @@ int test_msg_parsing(void)
|
||||
|
||||
{
|
||||
size_t size = SIZE_MAX;
|
||||
char *s = msg_as_string(msg_home(msg), msg, NULL, 0, &size);
|
||||
char *s;
|
||||
char body[66 * 15 + 1];
|
||||
int i;
|
||||
msg_payload_t *pl;
|
||||
|
||||
/* Bug #1726034 */
|
||||
for (i = 0; i < 15; i++)
|
||||
strcpy(body + i * 66,
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n");
|
||||
pl = msg_payload_make(msg_home(msg), body);
|
||||
|
||||
TEST(msg_header_insert(msg, (msg_pub_t *)tst, (void *)pl), 0);
|
||||
|
||||
s = msg_as_string(msg_home(msg), msg, NULL, 0, &size);
|
||||
TEST_S(s,
|
||||
"GET a-wife HTTP/1.1" CRLF
|
||||
"Foo: bar" CRLF
|
||||
@ -806,7 +820,23 @@ int test_msg_parsing(void)
|
||||
"Content-Language: se-FI, fi-FI, sv-FI\r\n"
|
||||
"Accept-Language: se, fi, sv\r\n"
|
||||
CRLF
|
||||
"test" CRLF);
|
||||
"test" CRLF
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF
|
||||
);
|
||||
}
|
||||
|
||||
msg_destroy(msg);
|
||||
|
@ -2198,7 +2198,8 @@ void agent_recv_request(nta_agent_t *agent,
|
||||
TPTAG_SDWN_AFTER(stream),
|
||||
TAG_END());
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
msg_destroy(msg);
|
||||
if (stream) /* Send FIN */
|
||||
tport_shutdown(tport, 1);
|
||||
@ -6172,13 +6173,6 @@ size_t incoming_mass_destroy(nta_agent_t *sa, incoming_queue_t *q)
|
||||
HTABLE_BODIES_WITH(outgoing_htable, oht, nta_outgoing_t, HTABLE_HASH_ORQ,
|
||||
size_t, hash_value_t);
|
||||
|
||||
static nta_outgoing_t *outgoing_create(nta_agent_t *agent,
|
||||
nta_response_f *callback,
|
||||
nta_outgoing_magic_t *magic,
|
||||
url_string_t const *route_url,
|
||||
tp_name_t const *tpn,
|
||||
msg_t *msg,
|
||||
tag_type_t tag, tag_value_t value, ...);
|
||||
static int outgoing_features(nta_agent_t *agent, nta_outgoing_t *orq,
|
||||
msg_t *msg, sip_t *sip,
|
||||
tagi_t *tags);
|
||||
@ -6815,7 +6809,11 @@ nta_outgoing_t *outgoing_create(nta_agent_t *agent,
|
||||
/* select the tport to use for the outgoing message */
|
||||
if (override_tport) {
|
||||
/* note: no ref taken to the tport as its only used once here */
|
||||
tpn = tport_name(override_tport);
|
||||
if (tport_is_secondary(override_tport)) {
|
||||
tpn = tport_name(override_tport);
|
||||
orq->orq_user_tport = 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (route_url) {
|
||||
@ -7095,8 +7093,10 @@ outgoing_send(nta_outgoing_t *orq, int retransmit)
|
||||
if (cc)
|
||||
nta_compartment_decref(&cc);
|
||||
|
||||
if (orq->orq_user_tport)
|
||||
/* No retries */;
|
||||
/* RFC3261, 18.1.1 */
|
||||
if (err == EMSGSIZE && !orq->orq_try_tcp_instead) {
|
||||
else if (err == EMSGSIZE && !orq->orq_try_tcp_instead) {
|
||||
if (strcasecmp(tpn->tpn_proto, "udp") == 0 ||
|
||||
strcasecmp(tpn->tpn_proto, "*") == 0) {
|
||||
outgoing_try_tcp_instead(orq);
|
||||
@ -10217,6 +10217,10 @@ nta_transport_(nta_agent_t *agent,
|
||||
}
|
||||
|
||||
|
||||
/** Return a new reference to the transaction transport.
|
||||
*
|
||||
* @note The referenced transport must be unreferenced with tport_unref()
|
||||
*/
|
||||
tport_t *
|
||||
nta_incoming_transport(nta_agent_t *agent,
|
||||
nta_incoming_t *irq,
|
||||
|
@ -504,6 +504,7 @@ struct nta_outgoing_s
|
||||
unsigned orq_completed : 1;
|
||||
unsigned orq_delayed : 1;
|
||||
unsigned orq_stripped_uri : 1;
|
||||
unsigned orq_user_tport : 1; /**< Application provided tport - don't retry */
|
||||
unsigned orq_try_tcp_instead : 1;
|
||||
unsigned orq_try_udp_instead : 1;
|
||||
unsigned orq_reliable : 1; /**< Transport is reliable */
|
||||
|
@ -101,7 +101,7 @@ NTH_DLL extern tag_typedef_t nthtag_error_msg;
|
||||
NTH_DLL extern tag_typedef_t nthtag_error_msg_ref;
|
||||
#define NTHTAG_ERROR_MSG_REF(x) nthtag_error_msg_ref, tag_bool_vr(&(x))
|
||||
|
||||
#if SU_HAVE_INLINE
|
||||
#if SU_INLINE_TAG_CAST
|
||||
struct nth_client_s;
|
||||
su_inline tag_value_t nthtag_template_v(struct nth_client_s const *v)
|
||||
{ return (tag_value_t)v; }
|
||||
@ -119,7 +119,7 @@ NTH_DLL extern tag_typedef_t nthtag_template;
|
||||
NTH_DLL extern tag_typedef_t nthtag_template_ref;
|
||||
#define NTHTAG_TEMPLATE_REF(x) nthtag_template_ref, nthtag_template_vr(&(x))
|
||||
|
||||
#if SU_HAVE_INLINE
|
||||
#if SU_INLINE_TAG_CAST
|
||||
su_inline tag_value_t nthtag_message_v(struct msg_s *v)
|
||||
{ return (tag_value_t)v; }
|
||||
su_inline tag_value_t nthtag_message_vr(struct msg_s **vp)
|
||||
|
@ -570,6 +570,7 @@ static int send_request(tester_t *t, char const *req, size_t reqlen,
|
||||
|
||||
if (c == INVALID_SOCKET) {
|
||||
c = su_socket(t->t_addr->su_family, SOCK_STREAM, 0); TEST_1(c != SOCK_STREAM);
|
||||
TEST_1(su_setblocking(c, 1) != -1);
|
||||
TEST_1(connect(c, &t->t_addr->su_sa, t->t_addrlen) != -1);
|
||||
|
||||
while (su_root_step(t->t_root, 1) == 0);
|
||||
|
@ -1049,7 +1049,7 @@ msg_t *nua_current_request(nua_t const *nua)
|
||||
/** Get request message from saved nua event. @NEW_1_12_4. */
|
||||
msg_t *nua_saved_event_request(nua_saved_event_t const *saved)
|
||||
{
|
||||
return saved ? su_msg_data(saved)->e_msg : NULL;
|
||||
return saved && saved[0] ? su_msg_data(saved)->e_msg : NULL;
|
||||
}
|
||||
|
||||
/** Save nua event and its arguments */
|
||||
|
@ -48,7 +48,10 @@
|
||||
/* ======================================================================== */
|
||||
/* MESSAGE */
|
||||
|
||||
/** Send an instant message.
|
||||
/**@fn void nua_message( \
|
||||
* nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
|
||||
*
|
||||
* Send an instant message.
|
||||
*
|
||||
* Send an instant message using SIP MESSAGE method.
|
||||
*
|
||||
|
@ -37,6 +37,8 @@
|
||||
/** @internal SU network changed detector argument pointer type */
|
||||
#define SU_NETWORK_CHANGED_MAGIC_T struct nua_s
|
||||
|
||||
#define TP_CLIENT_T struct register_usage
|
||||
|
||||
#include <sofia-sip/string0.h>
|
||||
#include <sofia-sip/su_strlst.h>
|
||||
#include <sofia-sip/su_uniqueid.h>
|
||||
@ -46,7 +48,7 @@
|
||||
#include <sofia-sip/sip_util.h>
|
||||
#include <sofia-sip/sip_status.h>
|
||||
|
||||
#define NTA_UPDATE_MAGIC_T struct nua_s
|
||||
#define NTA_UPDATE_MAGIC_T struct nua_handle_s
|
||||
|
||||
#include "nua_stack.h"
|
||||
|
||||
@ -126,6 +128,7 @@ struct register_usage {
|
||||
|
||||
/** Status of registration */
|
||||
unsigned nr_ready:1;
|
||||
|
||||
/** Kind of registration.
|
||||
*
|
||||
* If nr_default is true, this is not a real registration but placeholder
|
||||
@ -138,7 +141,11 @@ struct register_usage {
|
||||
unsigned nr_default:1, nr_secure:1, nr_public:1, nr_ip4:1, nr_ip6:1;
|
||||
|
||||
/** Stack-generated contact */
|
||||
unsigned nr_by_stack:1, :0;
|
||||
unsigned nr_by_stack:1;
|
||||
|
||||
unsigned:0;
|
||||
|
||||
int nr_error_report_id; /**< ID used to ask for error reports from tport */
|
||||
|
||||
sip_route_t *nr_route; /**< Outgoing Service-Route */
|
||||
sip_path_t *nr_path; /**< Incoming Path */
|
||||
@ -205,6 +212,12 @@ static void nua_register_usage_remove(nua_handle_t *nh,
|
||||
nr->nr_compartment = NULL;
|
||||
#endif
|
||||
|
||||
if (nr->nr_error_report_id)
|
||||
tport_release(nr->nr_tport, nr->nr_error_report_id, NULL, NULL, nr, 0);
|
||||
|
||||
if (nr->nr_tport)
|
||||
tport_unref(nr->nr_tport), nr->nr_tport = NULL;
|
||||
|
||||
ds->ds_has_register = 0; /* There can be only one */
|
||||
}
|
||||
|
||||
@ -222,6 +235,12 @@ static void nua_register_usage_peer_info(nua_dialog_usage_t *du,
|
||||
/* ======================================================================== */
|
||||
/* REGISTER */
|
||||
|
||||
static void nua_register_connection_closed(tp_stack_t *sip_stack,
|
||||
nua_registration_t *nr,
|
||||
tport_t *tport,
|
||||
msg_t *msg,
|
||||
int error);
|
||||
|
||||
/* Interface towards outbound_t */
|
||||
sip_contact_t *nua_handle_contact_by_via(nua_handle_t *nh,
|
||||
su_home_t *home,
|
||||
@ -764,6 +783,7 @@ int nua_register_client_request(nua_client_request_t *cr,
|
||||
TAG_IF(unreg, NTATAG_SIGCOMP_CLOSE(1)),
|
||||
TAG_IF(!unreg, NTATAG_COMP("sigcomp")),
|
||||
#endif
|
||||
NTATAG_TPORT(nr->nr_tport),
|
||||
TAG_NEXT(tags));
|
||||
}
|
||||
|
||||
@ -827,6 +847,8 @@ static int nua_register_client_response(nua_client_request_t *cr,
|
||||
msg_t *_reqmsg = nta_outgoing_getrequest(cr->cr_orq);
|
||||
sip_t *req = sip_object(_reqmsg);
|
||||
|
||||
tport_t *tport;
|
||||
|
||||
msg_destroy(_reqmsg);
|
||||
|
||||
assert(nr); assert(sip); assert(req);
|
||||
@ -927,10 +949,26 @@ static int nua_register_client_response(nua_client_request_t *cr,
|
||||
outbound_start_keepalive(nr->nr_ob, cr->cr_orq);
|
||||
}
|
||||
|
||||
/* persistant connection for registration */
|
||||
if (!nr->nr_tport)
|
||||
/* note: nta_outgoing_transport() takes a ref */
|
||||
nr->nr_tport = nta_outgoing_transport (cr->cr_orq);
|
||||
tport = nta_outgoing_transport (cr->cr_orq);
|
||||
|
||||
/* cache persistant connection for registration */
|
||||
if (tport && tport != nr->nr_tport) {
|
||||
if (nr->nr_error_report_id) {
|
||||
if (tport_release(nr->nr_tport, nr->nr_error_report_id, NULL, NULL, nr, 0) < 0)
|
||||
SU_DEBUG_1(("nua_register: tport_release() failed\n"));
|
||||
nr->nr_error_report_id = 0;
|
||||
}
|
||||
tport_unref(nr->nr_tport);
|
||||
nr->nr_tport = tport;
|
||||
|
||||
if (tport_is_secondary(tport)) {
|
||||
tport_set_params(tport, TPTAG_SDWN_ERROR(1), TAG_END());
|
||||
nr->nr_error_report_id =
|
||||
tport_pend(tport, NULL, nua_register_connection_closed, nr);
|
||||
}
|
||||
}
|
||||
else
|
||||
tport_unref(tport); /* note: nta_outgoing_transport() makes a ref */
|
||||
|
||||
nua_registration_set_ready(nr, 1);
|
||||
}
|
||||
@ -943,9 +981,15 @@ static int nua_register_client_response(nua_client_request_t *cr,
|
||||
outbound_stop_keepalive(nr->nr_ob);
|
||||
|
||||
/* release the persistant transport for registration */
|
||||
if (nr->nr_tport)
|
||||
tport_decref(&nr->nr_tport), nr->nr_tport = NULL;
|
||||
if (nr->nr_tport) {
|
||||
if (nr->nr_error_report_id) {
|
||||
if (tport_release(nr->nr_tport, nr->nr_error_report_id, NULL, NULL, nr, 0) < 0)
|
||||
SU_DEBUG_1(("nua_register: tport_release() failed\n"));
|
||||
nr->nr_error_report_id = 0;
|
||||
}
|
||||
|
||||
tport_unref(nr->nr_tport), nr->nr_tport = NULL;
|
||||
}
|
||||
nua_registration_set_ready(nr, 0);
|
||||
}
|
||||
|
||||
@ -953,6 +997,24 @@ static int nua_register_client_response(nua_client_request_t *cr,
|
||||
return nua_base_client_response(cr, status, phrase, sip, NULL);
|
||||
}
|
||||
|
||||
static
|
||||
void nua_register_connection_closed(tp_stack_t *sip_stack,
|
||||
nua_registration_t *nr,
|
||||
tport_t *tport,
|
||||
msg_t *msg,
|
||||
int error)
|
||||
{
|
||||
if (tport_release(nr->nr_tport, nr->nr_error_report_id, NULL, NULL, nr, 0) < 0)
|
||||
SU_DEBUG_1(("nua_register: tport_release() failed\n"));
|
||||
|
||||
nr->nr_error_report_id = 0;
|
||||
tport_unref(nr->nr_tport), nr->nr_tport = NULL;
|
||||
|
||||
/* Schedule re-REGISTER immediately */
|
||||
nua_dialog_usage_refresh_at(nua_dialog_usage_public(nr), sip_now());
|
||||
}
|
||||
|
||||
|
||||
static void nua_register_usage_refresh(nua_handle_t *nh,
|
||||
nua_dialog_state_t *ds,
|
||||
nua_dialog_usage_t *du,
|
||||
@ -978,8 +1040,8 @@ static void nua_register_usage_refresh(nua_handle_t *nh,
|
||||
* @retval <0 try again later
|
||||
*/
|
||||
static int nua_register_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 = du->du_cr;
|
||||
nua_registration_t *nr = nua_dialog_usage_private(du);
|
||||
|
@ -1627,7 +1627,8 @@ static int nua_prack_client_report(nua_client_request_t *cr,
|
||||
* (maybe NULL if call handle was created for this call)
|
||||
* @param sip incoming INVITE request
|
||||
* @param tags SOATAG_ACTIVE_AUDIO(), SOATAG_ACTIVE_VIDEO()
|
||||
*
|
||||
*
|
||||
* @par
|
||||
* @par Responding to INVITE with nua_respond()
|
||||
*
|
||||
* If @a status in #nua_i_invite event is below 200, the application should
|
||||
@ -1700,6 +1701,7 @@ static int nua_prack_client_report(nua_client_request_t *cr,
|
||||
* #nua_i_prack, #nua_i_update, nua_update(),
|
||||
* nua_invite(), #nua_r_invite
|
||||
*
|
||||
* @par
|
||||
* @par Third Party Call Control
|
||||
*
|
||||
* When so called 2rd party call control is used, the initial @b INVITE may
|
||||
|
@ -121,7 +121,9 @@ void nua_subscribe_usage_remove(nua_handle_t *nh,
|
||||
/* ====================================================================== */
|
||||
/* SUBSCRIBE */
|
||||
|
||||
/** Subscribe to a SIP event.
|
||||
/**@fn void nua_subscribe(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
|
||||
*
|
||||
* Subscribe to a SIP event.
|
||||
*
|
||||
* Subscribe a SIP event using the SIP SUBSCRIBE request. If the
|
||||
* SUBSCRBE is successful a subscription state is established and
|
||||
@ -145,7 +147,9 @@ void nua_subscribe_usage_remove(nua_handle_t *nh,
|
||||
* @sa NUTAG_SUBSTATE(), @RFC3265
|
||||
*/
|
||||
|
||||
/** Unsubscribe an event.
|
||||
/**@fn void nua_unsubscribe(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
|
||||
*
|
||||
* Unsubscribe an event.
|
||||
*
|
||||
* Unsubscribe an active or pending subscription with SUBSCRIBE request
|
||||
* containing Expires: header with value 0. The dialog associated with
|
||||
@ -689,7 +693,9 @@ int nua_notify_server_report(nua_server_request_t *sr, tagi_t const *tags)
|
||||
/* ======================================================================== */
|
||||
/* REFER */
|
||||
|
||||
/** Transfer a call.
|
||||
/**@fn void nua_refer(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
|
||||
*
|
||||
* Transfer a call.
|
||||
*
|
||||
* Send a REFER request asking the recipient to transfer the call.
|
||||
*
|
||||
|
@ -166,7 +166,7 @@ SOFIAPUBVAR tag_typedef_t nutag_with;
|
||||
* nua_respond()
|
||||
*
|
||||
* @par Parameter type
|
||||
* msg_t *
|
||||
* nua_saved_event_t *
|
||||
*
|
||||
* @par Values
|
||||
* Pointer to a saved event.
|
||||
@ -2270,7 +2270,7 @@ SOFIAPUBVAR tag_typedef_t nutag_detect_network_updates;
|
||||
SOFIAPUBVAR tag_typedef_t nutag_detect_network_updates_ref;
|
||||
|
||||
/* Pass nua handle as tagged argument */
|
||||
#if SU_HAVE_INLINE
|
||||
#if SU_INLINE_TAG_CAST
|
||||
su_inline tag_value_t nutag_handle_v(nua_handle_t *v) { return (tag_value_t)v; }
|
||||
su_inline tag_value_t nutag_handle_vr(nua_handle_t **vp) {return(tag_value_t)vp;}
|
||||
#else
|
||||
|
@ -128,7 +128,7 @@ int test_180rel(struct context *ctx)
|
||||
|
||||
struct endpoint *a = &ctx->a, *b = &ctx->b;
|
||||
struct call *a_call = a->call, *b_call = b->call;
|
||||
struct event *e;
|
||||
struct event *e, *ep, *ei;
|
||||
sip_t *sip;
|
||||
|
||||
if (print_headings)
|
||||
@ -193,10 +193,17 @@ int test_180rel(struct context *ctx)
|
||||
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);
|
||||
ei = event_by_type(e->next, nua_r_invite);
|
||||
ep = event_by_type(e->next, nua_r_prack);
|
||||
if (!ep) {
|
||||
run_a_until(ctx, -1, until_final_response);
|
||||
ep = event_by_type(e->next, nua_r_prack);
|
||||
}
|
||||
|
||||
TEST_1(e = ep); TEST_E(e->data->e_event, nua_r_prack);
|
||||
TEST(e->data->e_status, 200);
|
||||
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST_1(e = ei); 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);
|
||||
@ -206,7 +213,8 @@ int test_180rel(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_ready); /* READY */
|
||||
TEST_1(!is_offer_answer_done(e->data->e_tags));
|
||||
TEST_1(!e->next);
|
||||
|
||||
TEST_1(!e->next || !ep->next);
|
||||
free_events_in_list(ctx, a->events);
|
||||
|
||||
/*
|
||||
@ -321,13 +329,13 @@ int test_prack_auth(struct context *ctx)
|
||||
|
||||
struct endpoint *c = &ctx->c, *b = &ctx->b;
|
||||
struct call *c_call = c->call, *b_call = b->call;
|
||||
struct event *e;
|
||||
struct event *e, *ep, *ei;
|
||||
sip_t *sip;
|
||||
sip_proxy_authenticate_t *au;
|
||||
char const *md5 = NULL, *md5sess = NULL;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-10.1.1: Call with 100rel and 180\n");
|
||||
printf("TEST NUA-10.1.3: Call with 100rel and 180\n");
|
||||
|
||||
/* Test for authentication during 100rel
|
||||
|
||||
@ -405,8 +413,14 @@ 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));
|
||||
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
|
||||
ei = event_by_type(e->next, nua_r_invite);
|
||||
ep = event_by_type(e->next, nua_r_prack);
|
||||
if (!ep) {
|
||||
run_a_until(ctx, -1, until_final_response);
|
||||
ep = event_by_type(e->next, nua_r_prack);
|
||||
}
|
||||
|
||||
TEST_1(e = ep); TEST_E(e->data->e_event, nua_r_prack);
|
||||
if (e->data->e_status != 200 && md5 && !md5sess) {
|
||||
if (e->data->e_status != 100) {
|
||||
TEST(e->data->e_status, 407);
|
||||
@ -419,16 +433,15 @@ int test_prack_auth(struct context *ctx)
|
||||
|
||||
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);
|
||||
TEST_1(e = ei); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST(e->data->e_status, 200);
|
||||
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
|
||||
TEST_1(!is_offer_answer_done(e->data->e_tags));
|
||||
TEST_1(!e->next);
|
||||
TEST_1(!e->next || !ep->next || (ep->data->e_status != 200 && !e->next->next->next));
|
||||
free_events_in_list(ctx, c->events);
|
||||
|
||||
/*
|
||||
@ -466,10 +479,10 @@ int test_prack_auth(struct context *ctx)
|
||||
free_events_in_list(ctx, b->events);
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-10.1.1: PASSED\n");
|
||||
printf("TEST NUA-10.1.3: PASSED\n");
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-10.1.2: terminate call\n");
|
||||
printf("TEST NUA-10.1.4: terminate call\n");
|
||||
|
||||
BYE(b, b_call, b_call->nh, TAG_END());
|
||||
run_bc_until(ctx, -1, until_terminated, -1, until_terminated);
|
||||
@ -496,7 +509,7 @@ int test_prack_auth(struct context *ctx)
|
||||
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-10.1.2: PASSED\n");
|
||||
printf("TEST NUA-10.1.4: PASSED\n");
|
||||
|
||||
END();
|
||||
}
|
||||
@ -558,7 +571,7 @@ int test_183rel(struct context *ctx)
|
||||
|
||||
struct endpoint *a = &ctx->a, *b = &ctx->b;
|
||||
struct call *a_call = a->call, *b_call = b->call;
|
||||
struct event *e;
|
||||
struct event *e, *ei, *ep;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-10.2.1: Call with 100rel, 183 and 180\n");
|
||||
@ -590,26 +603,43 @@ int test_183rel(struct context *ctx)
|
||||
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, 200);
|
||||
TEST_1(e = e->next);
|
||||
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
|
||||
ep = e->data->e_event == nua_r_prack ? e : NULL;
|
||||
|
||||
if (ep) {
|
||||
TEST(ep->data->e_status, 200); 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_offer_answer_done(e->data->e_tags));
|
||||
|
||||
if (!ep) {
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
|
||||
TEST(e->data->e_status, 200);
|
||||
}
|
||||
|
||||
ei = event_by_type(e->next, nua_r_invite);
|
||||
ep = event_by_type(e->next, nua_r_prack);
|
||||
if (!ep) {
|
||||
run_a_until(ctx, -1, until_final_response);
|
||||
ep = event_by_type(e->next, nua_r_prack);
|
||||
}
|
||||
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
|
||||
TEST_1(e = ep); TEST_E(e->data->e_event, nua_r_prack);
|
||||
TEST(e->data->e_status, 200);
|
||||
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST_1(e = ei); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST(e->data->e_status, 200);
|
||||
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
|
||||
TEST_1(!is_offer_answer_done(e->data->e_tags));
|
||||
TEST_1(!e->next);
|
||||
TEST_1(!e->next || !ep->next);
|
||||
free_events_in_list(ctx, a->events);
|
||||
|
||||
/*
|
||||
@ -879,7 +909,7 @@ int test_preconditions(struct context *ctx)
|
||||
|
||||
struct endpoint *a = &ctx->a, *b = &ctx->b;
|
||||
struct call *a_call = a->call, *b_call = b->call;
|
||||
struct event *e;
|
||||
struct event *e, *ep, *ei;
|
||||
sip_t *sip;
|
||||
|
||||
if (print_headings)
|
||||
@ -969,7 +999,10 @@ int test_preconditions(struct context *ctx)
|
||||
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_update);
|
||||
ei = event_by_type(e->next, nua_r_invite);
|
||||
ep = event_by_type(e->next, nua_r_update);
|
||||
|
||||
TEST_1(e = ep); 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);
|
||||
@ -979,17 +1012,27 @@ int test_preconditions(struct context *ctx)
|
||||
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_invite);
|
||||
TEST_1(e = ei); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST(e->data->e_status, 180);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
|
||||
TEST_1(!is_offer_answer_done(e->data->e_tags));
|
||||
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
|
||||
if (e == ep) /* invite was responded before update */
|
||||
e = ep->next->next;
|
||||
|
||||
ei = event_by_type(e->next, nua_r_invite);
|
||||
ep = event_by_type(e->next, nua_r_prack);
|
||||
if (!ep) {
|
||||
run_a_until(ctx, -1, until_final_response);
|
||||
ep = event_by_type(e->next, nua_r_prack);
|
||||
}
|
||||
|
||||
TEST_1(e = ep); TEST_E(e->data->e_event, nua_r_prack);
|
||||
TEST(e->data->e_status, 200);
|
||||
/* Does not have effect on call state */
|
||||
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST_1(e = ei); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST(e->data->e_status, 200);
|
||||
TEST_1(sip = sip_object(e->data->e_msg));
|
||||
if (ctx->proxy_tests) {
|
||||
@ -1001,7 +1044,7 @@ int test_preconditions(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_ready); /* READY */
|
||||
TEST_1(!is_offer_answer_done(e->data->e_tags));
|
||||
TEST_1(!e->next);
|
||||
TEST_1(!e->next || !ep->next);
|
||||
free_events_in_list(ctx, a->events);
|
||||
|
||||
/*
|
||||
@ -1169,7 +1212,7 @@ int test_preconditions2(struct context *ctx)
|
||||
|
||||
struct endpoint *a = &ctx->a, *b = &ctx->b;
|
||||
struct call *a_call = a->call, *b_call = b->call;
|
||||
struct event *e;
|
||||
struct event *e, *eu, *ei;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-10.4.1: Call with preconditions and non-100rel 180\n");
|
||||
@ -1253,22 +1296,25 @@ int test_preconditions2(struct context *ctx)
|
||||
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_update);
|
||||
TEST(e->data->e_status, 200);
|
||||
eu = event_by_type(e->next, nua_r_update);
|
||||
ei = event_by_type(e->next, nua_r_invite);
|
||||
|
||||
TEST_1(e = eu); TEST_E(e->data->e_event, nua_r_update);
|
||||
TEST(e->data->e_status, 200);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
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_invite);
|
||||
TEST_1(e = ei); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST(e->data->e_status, 180);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
|
||||
TEST_1(!is_offer_answer_done(e->data->e_tags));
|
||||
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST(e->data->e_status, 200);
|
||||
TEST_1(e = eu->next->next == ei ? ei->next->next : eu->next->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 */
|
||||
@ -1445,7 +1491,7 @@ int test_update_by_uas(struct context *ctx)
|
||||
|
||||
struct endpoint *a = &ctx->a, *b = &ctx->b;
|
||||
struct call *a_call = a->call, *b_call = b->call;
|
||||
struct event *e;
|
||||
struct event *e, *ep, *ei;
|
||||
sip_t *sip;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
@ -1563,11 +1609,18 @@ int test_update_by_uas(struct context *ctx)
|
||||
TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
|
||||
TEST_1(!is_offer_answer_done(e->data->e_tags));
|
||||
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack);
|
||||
ei = event_by_type(e->next, nua_r_invite);
|
||||
ep = event_by_type(e->next, nua_r_prack);
|
||||
if (!ep) {
|
||||
run_a_until(ctx, -1, until_final_response);
|
||||
ep = event_by_type(e->next, nua_r_prack);
|
||||
}
|
||||
|
||||
TEST_1(e = ep); TEST_E(e->data->e_event, nua_r_prack);
|
||||
TEST(e->data->e_status, 200);
|
||||
/* Does not have effect on call state */
|
||||
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST_1(e = ei); TEST_E(e->data->e_event, nua_r_invite);
|
||||
TEST(e->data->e_status, 200);
|
||||
if (ctx->proxy_tests) {
|
||||
TEST_1(sip = sip_object(e->data->e_msg));
|
||||
@ -1579,7 +1632,7 @@ int test_update_by_uas(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_ready); /* READY */
|
||||
TEST_1(!is_offer_answer_done(e->data->e_tags));
|
||||
TEST_1(!e->next);
|
||||
TEST_1(!e->next || !ep->next);
|
||||
free_events_in_list(ctx, a->events);
|
||||
|
||||
/*
|
||||
@ -1846,7 +1899,7 @@ int test_180rel_cancel2(struct context *ctx)
|
||||
|
||||
struct endpoint *a = &ctx->a, *b = &ctx->b;
|
||||
struct call *a_call = a->call, *b_call = b->call;
|
||||
struct event *e;
|
||||
struct event *e, *ep, *ec;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-10.7: CANCEL after 100rel 180\n");
|
||||
@ -1911,17 +1964,21 @@ int test_180rel_cancel2(struct context *ctx)
|
||||
TEST_1(is_answer_recv(e->data->e_tags));
|
||||
TEST_1(!is_offer_sent(e->data->e_tags));
|
||||
|
||||
#define NEXT_SKIP_PRACK_CANCEL() \
|
||||
#define NEXT_SKIP(x) \
|
||||
do { TEST_1(e = e->next); } \
|
||||
while (e->data->e_event == nua_r_prack || e->data->e_event == nua_r_cancel)
|
||||
while (x);
|
||||
|
||||
NEXT_SKIP_PRACK_CANCEL();
|
||||
NEXT_SKIP(e->data->e_event == nua_r_prack ||
|
||||
e->data->e_event == nua_r_cancel ||
|
||||
e->data->e_event == nua_i_state);
|
||||
|
||||
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);
|
||||
if (e->next)
|
||||
NEXT_SKIP(e->data->e_event == nua_r_prack || e->data->e_event == nua_r_cancel);
|
||||
TEST_1(!e->next);
|
||||
}
|
||||
else {
|
||||
@ -1932,7 +1989,8 @@ int test_180rel_cancel2(struct context *ctx)
|
||||
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);
|
||||
NEXT_SKIP(e->data->e_event == nua_r_prack || e->data->e_event == nua_r_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 */
|
||||
@ -1963,18 +2021,20 @@ int test_180rel_cancel2(struct context *ctx)
|
||||
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 */
|
||||
ec = event_by_type(e->next, nua_i_cancel);
|
||||
|
||||
if (e->next->data->e_event == nua_i_cancel) {
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_cancel);
|
||||
if (ec) {
|
||||
TEST_1(e = ec); 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);
|
||||
/* 180 is PRACKed, PRACK does not have effect on call state */
|
||||
ep = event_by_type(e->next, nua_i_prack);
|
||||
if (ep) e = ep;
|
||||
/* Responded with 200 OK */
|
||||
TEST_1(e = event_by_type(e->next, nua_i_state));
|
||||
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);
|
||||
|
@ -1100,7 +1100,7 @@ int test_basic_call_5(struct context *ctx)
|
||||
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-3.4: PASSED\n");
|
||||
printf("TEST NUA-3.5: PASSED\n");
|
||||
|
||||
END();
|
||||
}
|
||||
|
@ -1520,7 +1520,7 @@ int test_rejects(struct context *ctx)
|
||||
test_reject_302(ctx) ||
|
||||
test_reject_401(ctx) ||
|
||||
test_mime_negotiation(ctx) ||
|
||||
test_call_timeouts(ctx) ||
|
||||
test_reject_401_aka(ctx) ||
|
||||
test_call_timeouts(ctx) ||
|
||||
0;
|
||||
}
|
||||
|
@ -1349,11 +1349,14 @@ int test_bye_to_invalid_contact(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 *sip = NULL;
|
||||
|
||||
int seen_401;
|
||||
|
||||
a_call->sdp = "m=audio 5008 RTP/AVP 8";
|
||||
b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
|
||||
|
||||
/* Early BYE 2
|
||||
/* Bad Contact URI
|
||||
|
||||
A B
|
||||
|-------INVITE------>|
|
||||
@ -1362,14 +1365,17 @@ int test_bye_to_invalid_contact(struct context *ctx)
|
||||
|<----180 Ringing----|
|
||||
|<-------200---------|
|
||||
| |
|
||||
|--------BYE-------->|
|
||||
|<------200 OK-------|
|
||||
|--------ACK-------->|
|
||||
| |
|
||||
|<-------BYE---------|
|
||||
|--------400-------->|
|
||||
| |
|
||||
|--------BYE-------->|
|
||||
|<------200 OK-------|
|
||||
| |
|
||||
*/
|
||||
if (print_headings)
|
||||
printf("TEST NUA-6.4.3: BYE call when completing\n");
|
||||
printf("TEST NUA-6.4.3: Test dialog with bad Contact info\n");
|
||||
|
||||
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
|
||||
|
||||
@ -1448,6 +1454,42 @@ int test_bye_to_invalid_contact(struct context *ctx)
|
||||
if (print_headings)
|
||||
printf("TEST NUA-6.4.3: PASSED\n");
|
||||
|
||||
if (!ctx->p)
|
||||
return 0;
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-6.4.4: Wait for re-REGISTER after connection has been closed\n");
|
||||
|
||||
/* B is supposed to re-register pretty soon, wait for re-registration */
|
||||
|
||||
run_b_until(ctx, -1, save_until_final_response);
|
||||
|
||||
seen_401 = 0;
|
||||
|
||||
for (e = b->events->head; e; e = e->next) {
|
||||
TEST_E(e->data->e_event, nua_r_register);
|
||||
TEST_1(sip = sip_object(e->data->e_msg));
|
||||
|
||||
if (e->data->e_status == 200) {
|
||||
TEST(e->data->e_status, 200);
|
||||
TEST_1(seen_401);
|
||||
TEST_1(sip->sip_contact);
|
||||
}
|
||||
else if (sip->sip_status && sip->sip_status->st_status == 401) {
|
||||
seen_401 = 1;
|
||||
}
|
||||
|
||||
if (!e->next)
|
||||
break;
|
||||
}
|
||||
TEST_1(e);
|
||||
TEST_S(sip->sip_contact->m_expires, "3600");
|
||||
TEST_1(!e->next);
|
||||
free_events_in_list(ctx, b->events);
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-6.4.4: PASSED\n");
|
||||
|
||||
END();
|
||||
}
|
||||
|
||||
|
@ -70,8 +70,9 @@ int test_nua_init(struct context *ctx,
|
||||
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 */
|
||||
url_t const *p_uri, *a_uri, *b_uri; /* Proxy URI */
|
||||
char const *a_bind, *a_bind2;
|
||||
url_t b_proxy[1];
|
||||
|
||||
a_bind = a_bind2 = "sip:0.0.0.0:*";
|
||||
|
||||
@ -121,7 +122,7 @@ int test_nua_init(struct context *ctx,
|
||||
printf("TEST NUA-2.1.1: PASSED\n");
|
||||
}
|
||||
|
||||
p_uri = a_uri = test_proxy_uri(ctx->p);
|
||||
p_uri = a_uri = b_uri = test_proxy_uri(ctx->p);
|
||||
|
||||
if (start_nat && p_uri == NULL)
|
||||
p_uri = url_hdup(ctx->home, (void *)o_proxy);
|
||||
@ -257,8 +258,15 @@ int test_nua_init(struct context *ctx,
|
||||
|
||||
ctx->b.instance = nua_generate_instance_identifier(ctx->home);
|
||||
|
||||
if (ctx->p) {
|
||||
/* B uses TCP when talking with proxy */
|
||||
*b_proxy = *b_uri;
|
||||
b_uri = b_proxy;
|
||||
b_proxy->url_params = "transport=tcp";
|
||||
}
|
||||
|
||||
ctx->b.nua = nua_create(ctx->root, b_callback, ctx,
|
||||
NUTAG_PROXY(p_uri ? p_uri : o_proxy),
|
||||
NUTAG_PROXY(b_uri ? b_uri : o_proxy),
|
||||
SIPTAG_FROM_STR("sip:bob@example.org"),
|
||||
NUTAG_URL("sip:0.0.0.0:*"),
|
||||
SOATAG_USER_SDP_STR("m=audio 5006 RTP/AVP 8 0"),
|
||||
|
@ -211,6 +211,18 @@ int main(int argc, char *argv[])
|
||||
else if (strcmp(argv[i], "--loop") == 0) {
|
||||
o_alarm = 0, o_loop = 1;
|
||||
}
|
||||
else if (strcmp(argv[i], "--print-tags") == 0) {
|
||||
ctx->print_tags = 1;
|
||||
}
|
||||
else if (strcmp(argv[i], "--tags=a") == 0) {
|
||||
ctx->a.print_tags = 1;
|
||||
}
|
||||
else if (strcmp(argv[i], "--tags=b") == 0) {
|
||||
ctx->b.print_tags = 1;
|
||||
}
|
||||
else if (strcmp(argv[i], "--tags=c") == 0) {
|
||||
ctx->c.print_tags = 1;
|
||||
}
|
||||
else if (strcmp(argv[i], "--log=a") == 0) {
|
||||
ctx->a.logging = 1;
|
||||
}
|
||||
@ -317,8 +329,8 @@ int main(int argc, char *argv[])
|
||||
retval |= test_rejects(ctx); SINGLE_FAILURE_CHECK();
|
||||
retval |= test_call_cancel(ctx); SINGLE_FAILURE_CHECK();
|
||||
retval |= test_call_destroy(ctx); SINGLE_FAILURE_CHECK();
|
||||
retval |= test_offer_answer(ctx); SINGLE_FAILURE_CHECK();
|
||||
retval |= test_early_bye(ctx); SINGLE_FAILURE_CHECK();
|
||||
retval |= test_offer_answer(ctx); SINGLE_FAILURE_CHECK();
|
||||
retval |= test_reinvites(ctx); SINGLE_FAILURE_CHECK();
|
||||
retval |= test_session_timer(ctx); SINGLE_FAILURE_CHECK();
|
||||
retval |= test_refer(ctx); SINGLE_FAILURE_CHECK();
|
||||
|
@ -124,6 +124,7 @@ struct context
|
||||
su_root_t *root;
|
||||
|
||||
int threading, proxy_tests, expensive, quit_on_single_failure, osx_runloop;
|
||||
int print_tags;
|
||||
char const *external_proxy;
|
||||
|
||||
int proxy_logging;
|
||||
@ -133,6 +134,7 @@ struct context
|
||||
struct context *ctx; /* Backpointer */
|
||||
|
||||
int logging;
|
||||
int print_tags;
|
||||
|
||||
int running;
|
||||
|
||||
@ -196,6 +198,9 @@ void free_event_in_list(struct context *ctx,
|
||||
struct eventlist *list,
|
||||
struct event *e);
|
||||
|
||||
struct event *event_by_type(struct event *e, nua_event_t);
|
||||
size_t count_events(struct event const *e);
|
||||
|
||||
#define CONDITION_PARAMS \
|
||||
nua_event_t event, \
|
||||
int status, char const *phrase, \
|
||||
|
@ -190,7 +190,8 @@ void print_event(nua_event_t event,
|
||||
ep->name, (void *)nh, operation);
|
||||
}
|
||||
|
||||
if ((tstflags & tst_verbatim) && tags)
|
||||
if (tags &&
|
||||
((tstflags & tst_verbatim) || ctx->print_tags || ep->print_tags))
|
||||
tl_print(stderr, "", tags);
|
||||
}
|
||||
|
||||
@ -499,6 +500,27 @@ void free_event_in_list(struct context *ctx,
|
||||
}
|
||||
}
|
||||
|
||||
struct event *event_by_type(struct event *e, nua_event_t etype)
|
||||
{
|
||||
for (; e; e = e->next) {
|
||||
if (e->data->e_event == etype)
|
||||
break;
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
size_t count_events(struct event const *e)
|
||||
{
|
||||
size_t n;
|
||||
|
||||
for (n = 0; e; e = e->next)
|
||||
n++;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
int is_special(nua_event_t e)
|
||||
{
|
||||
if (e == nua_i_active || e == nua_i_terminated)
|
||||
|
@ -53,6 +53,8 @@ struct binding;
|
||||
#include <sofia-sip/su_tagarg.h>
|
||||
#include <sofia-sip/msg_addr.h>
|
||||
#include <sofia-sip/hostdomain.h>
|
||||
#include <sofia-sip/tport.h>
|
||||
#include <sofia-sip/nta_tport.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
@ -111,6 +113,8 @@ struct proxy {
|
||||
sip_time_t min_expires, expires, max_expires;
|
||||
|
||||
sip_time_t session_expires, min_se;
|
||||
|
||||
int outbound_tcp; /**< Use inbound TCP connection as outbound */
|
||||
} prefs;
|
||||
};
|
||||
|
||||
@ -119,7 +123,6 @@ static struct registration_entry *registration_entry_new(struct proxy *,
|
||||
url_t const *);
|
||||
static void registration_entry_destroy(struct registration_entry *e);
|
||||
|
||||
|
||||
struct registration_entry
|
||||
{
|
||||
struct registration_entry *next, **prev;
|
||||
@ -132,14 +135,16 @@ struct registration_entry
|
||||
struct binding
|
||||
{
|
||||
struct binding *next, **prev;
|
||||
sip_contact_t *contact; /* bindings */
|
||||
sip_contact_t *contact; /* binding */
|
||||
sip_time_t registered, expires; /* When registered and when expires */
|
||||
sip_call_id_t *call_id;
|
||||
sip_call_id_t *call_id;
|
||||
uint32_t cseq;
|
||||
tport_t *tport; /**< Reference to tport */
|
||||
};
|
||||
|
||||
static struct binding *binding_new(su_home_t *home,
|
||||
sip_contact_t *contact,
|
||||
tport_t *tport,
|
||||
sip_call_id_t *call_id,
|
||||
uint32_t cseq,
|
||||
sip_time_t registered,
|
||||
@ -147,7 +152,9 @@ static struct binding *binding_new(su_home_t *home,
|
||||
static void binding_destroy(su_home_t *home, struct binding *b);
|
||||
static int binding_is_active(struct binding const *b)
|
||||
{
|
||||
return b->expires > sip_now();
|
||||
return
|
||||
b->expires > sip_now() &&
|
||||
(b->tport == NULL || tport_is_clear_to_send(b->tport));
|
||||
}
|
||||
|
||||
LIST_PROTOS(static, proxy_transaction, struct proxy_transaction);
|
||||
@ -195,6 +202,8 @@ static int process_options(struct proxy *proxy,
|
||||
static struct registration_entry *
|
||||
registration_entry_find(struct proxy const *proxy, url_t const *uri);
|
||||
|
||||
static int close_tports(void *proxy);
|
||||
|
||||
static auth_challenger_t registrar_challenger[1];
|
||||
static auth_challenger_t proxy_challenger[1];
|
||||
|
||||
@ -268,6 +277,8 @@ test_proxy_init(su_root_t *root, struct proxy *proxy)
|
||||
proxy->prefs.session_expires = 180;
|
||||
proxy->prefs.min_se = 90;
|
||||
|
||||
proxy->prefs.outbound_tcp = 1;
|
||||
|
||||
if (!proxy->defleg ||
|
||||
!proxy->example_net || !proxy->example_org || !proxy->example_com)
|
||||
return -1;
|
||||
@ -302,11 +313,11 @@ test_proxy_deinit(su_root_t *root, struct proxy *proxy)
|
||||
nta_outgoing_destroy(t->client), t->client = NULL;
|
||||
}
|
||||
|
||||
nta_agent_destroy(proxy->agent);
|
||||
|
||||
while (proxy->entries)
|
||||
registration_entry_destroy(proxy->entries);
|
||||
|
||||
nta_agent_destroy(proxy->agent);
|
||||
|
||||
free(proxy->tags);
|
||||
}
|
||||
|
||||
@ -396,6 +407,38 @@ void test_proxy_get_session_timer(struct proxy *p,
|
||||
}
|
||||
}
|
||||
|
||||
void test_proxy_set_outbound(struct proxy *p,
|
||||
int use_outbound)
|
||||
{
|
||||
if (p) {
|
||||
p->prefs.outbound_tcp = use_outbound;
|
||||
}
|
||||
}
|
||||
|
||||
void test_proxy_get_outbound(struct proxy *p,
|
||||
int *return_use_outbound)
|
||||
{
|
||||
if (p) {
|
||||
if (return_use_outbound)
|
||||
*return_use_outbound = p->prefs.outbound_tcp;
|
||||
}
|
||||
}
|
||||
|
||||
int test_proxy_close_tports(struct proxy *p)
|
||||
{
|
||||
if (p) {
|
||||
int retval = -EPROTO;
|
||||
|
||||
su_task_execute(su_clone_task(p->clone), close_tports, p, &retval);
|
||||
|
||||
if (retval < 0)
|
||||
return errno = -retval, -1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
return errno = EFAULT, -1;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
static sip_contact_t *create_transport_contacts(struct proxy *p)
|
||||
@ -449,6 +492,7 @@ int proxy_request(struct proxy *proxy,
|
||||
sip_session_expires_t *x = NULL, x0[1];
|
||||
sip_min_se_t *min_se = NULL, min_se0[1];
|
||||
char const *require = NULL;
|
||||
tport_t *tport = NULL;
|
||||
|
||||
mf = sip->sip_max_forwards;
|
||||
|
||||
@ -529,8 +573,9 @@ int proxy_request(struct proxy *proxy,
|
||||
nta_incoming_treply(irq, SIP_480_TEMPORARILY_UNAVAILABLE, TAG_END());
|
||||
return 480;
|
||||
}
|
||||
|
||||
|
||||
target = b->contact->m_url;
|
||||
tport = b->tport;
|
||||
}
|
||||
|
||||
t = proxy_transaction_new(proxy);
|
||||
@ -560,6 +605,7 @@ int proxy_request(struct proxy *proxy,
|
||||
SIPTAG_SESSION_EXPIRES(x),
|
||||
SIPTAG_MIN_SE(min_se),
|
||||
SIPTAG_REQUIRE_STR(require),
|
||||
NTATAG_TPORT(tport),
|
||||
TAG_END());
|
||||
if (t->client == NULL) {
|
||||
proxy_transaction_destroy(t);
|
||||
@ -734,9 +780,10 @@ static int validate_contacts(struct proxy *p, auth_status_t *as,
|
||||
static int check_out_of_order(struct proxy *p, auth_status_t *as,
|
||||
struct registration_entry *e, sip_t const *);
|
||||
static int binding_update(struct proxy *p,
|
||||
auth_status_t *as,
|
||||
struct registration_entry *e,
|
||||
sip_t const *sip);
|
||||
auth_status_t *as,
|
||||
struct registration_entry *e,
|
||||
nta_incoming_t *irq,
|
||||
sip_t const *sip);
|
||||
|
||||
sip_contact_t *binding_contacts(su_home_t *home, struct binding *bindings);
|
||||
|
||||
@ -768,10 +815,11 @@ int process_register(struct proxy *proxy,
|
||||
assert(as->as_status >= 200);
|
||||
|
||||
nta_incoming_treply(irq,
|
||||
as->as_status, as->as_phrase,
|
||||
SIPTAG_HEADER((void *)as->as_info),
|
||||
SIPTAG_HEADER((void *)as->as_response),
|
||||
TAG_END());
|
||||
as->as_status, as->as_phrase,
|
||||
SIPTAG_HEADER((void *)as->as_info),
|
||||
SIPTAG_HEADER((void *)as->as_response),
|
||||
TAG_END());
|
||||
|
||||
status = as->as_status;
|
||||
|
||||
su_home_unref(as->as_home);
|
||||
@ -816,7 +864,7 @@ static int process_register2(struct proxy *p,
|
||||
if (!e)
|
||||
return set_status(as, SIP_500_INTERNAL_SERVER_ERROR);
|
||||
|
||||
if (binding_update(p, as, e, sip))
|
||||
if (binding_update(p, as, e, irq, sip))
|
||||
return as->as_status;
|
||||
|
||||
msg_header_free(p->home, (void *)e->contacts);
|
||||
@ -954,6 +1002,7 @@ LIST_BODIES(static, registration_entry, struct registration_entry, next, prev);
|
||||
static
|
||||
struct binding *binding_new(su_home_t *home,
|
||||
sip_contact_t *contact,
|
||||
tport_t *tport,
|
||||
sip_call_id_t *call_id,
|
||||
uint32_t cseq,
|
||||
sip_time_t registered,
|
||||
@ -968,6 +1017,7 @@ struct binding *binding_new(su_home_t *home,
|
||||
*m = *contact; m->m_next = NULL;
|
||||
|
||||
b->contact = sip_contact_dup(home, m);
|
||||
b->tport = tport_ref(tport);
|
||||
b->call_id = sip_call_id_dup(home, call_id);
|
||||
b->cseq = cseq;
|
||||
b->registered = registered;
|
||||
@ -992,6 +1042,7 @@ void binding_destroy(su_home_t *home, struct binding *b)
|
||||
}
|
||||
msg_header_free(home, (void *)b->contact);
|
||||
msg_header_free(home, (void *)b->call_id);
|
||||
tport_unref(b->tport);
|
||||
su_free(home, b);
|
||||
}
|
||||
|
||||
@ -999,16 +1050,21 @@ static
|
||||
int binding_update(struct proxy *p,
|
||||
auth_status_t *as,
|
||||
struct registration_entry *e,
|
||||
nta_incoming_t *irq,
|
||||
sip_t const *sip)
|
||||
{
|
||||
struct binding *b, *old, *next, *last, *bindings = NULL, **bb = &bindings;
|
||||
sip_contact_t *m;
|
||||
sip_time_t expires;
|
||||
|
||||
sip_time_t now = sip_now();
|
||||
tport_t *tport = NULL;
|
||||
|
||||
assert(sip->sip_contact);
|
||||
|
||||
if (p->prefs.outbound_tcp &&
|
||||
str0casecmp(sip->sip_via->v_protocol, sip_transport_tcp) == 0)
|
||||
tport = nta_incoming_transport(p->agent, irq, NULL);
|
||||
|
||||
/* Create new bindings */
|
||||
for (m = sip->sip_contact; m; m = m->m_next) {
|
||||
if (m->m_url->url_type == url_any)
|
||||
@ -1022,7 +1078,7 @@ int binding_update(struct proxy *p,
|
||||
|
||||
msg_header_remove_param(m->m_common, "expires");
|
||||
|
||||
b = binding_new(p->home, m, sip->sip_call_id, sip->sip_cseq->cs_seq,
|
||||
b = binding_new(p->home, m, tport, sip->sip_call_id, sip->sip_cseq->cs_seq,
|
||||
now, now + expires);
|
||||
if (!b)
|
||||
break;
|
||||
@ -1030,6 +1086,8 @@ int binding_update(struct proxy *p,
|
||||
*bb = b, b->prev = bb, bb = &b->next;
|
||||
}
|
||||
|
||||
tport_unref(tport);
|
||||
|
||||
last = NULL;
|
||||
|
||||
if (m == NULL) {
|
||||
@ -1095,3 +1153,25 @@ sip_contact_t *binding_contacts(su_home_t *home, struct binding *bindings)
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
static int close_tports(void *_proxy)
|
||||
{
|
||||
struct proxy *p = _proxy;
|
||||
struct registration_entry *e;
|
||||
struct binding *b;
|
||||
|
||||
/* Close all outbound transports */
|
||||
for (e = p->entries; e; e = e->next) {
|
||||
for (b = e->bindings; b; b = b->next) {
|
||||
if (b->tport) {
|
||||
tport_shutdown(b->tport, 2);
|
||||
tport_unref(b->tport);
|
||||
b->tport = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -56,6 +56,8 @@ void test_proxy_get_session_timer(struct proxy *p,
|
||||
sip_time_t *return_session_expires,
|
||||
sip_time_t *return_min_se);
|
||||
|
||||
int test_proxy_close_tports(struct proxy *p);
|
||||
|
||||
SOFIA_END_DECLS
|
||||
|
||||
#endif
|
||||
|
@ -113,7 +113,7 @@ int test_refer0(struct context *ctx, char const *tests,
|
||||
struct call *a_call = a->call, *b_call = b->call, *c_call = c->call;
|
||||
struct call *a_refer, *a_c2, *b_refer;
|
||||
struct eventlist *a_revents, *b_revents;
|
||||
struct event *e;
|
||||
struct event *e, *notify_e;
|
||||
sip_t const *sip;
|
||||
sip_event_t const *a_event, *b_event;
|
||||
sip_refer_to_t const *refer_to;
|
||||
@ -280,21 +280,38 @@ int test_refer0(struct context *ctx, char const *tests,
|
||||
TAG_END()), 1);
|
||||
TEST_1(b_event); TEST_1(b_event->o_id);
|
||||
TEST_1(b_event = sip_event_dup(tmphome, b_event));
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_refer);
|
||||
|
||||
notify_e = NULL;
|
||||
|
||||
TEST_1(e = e->next);
|
||||
if (e->data->e_event == nua_i_notify) {
|
||||
notify_e = e;
|
||||
TEST_1(e = e->next);
|
||||
}
|
||||
TEST_E(e->data->e_event, nua_r_refer);
|
||||
TEST(e->data->e_status, 202);
|
||||
TEST_1(sip = sip_object(e->data->e_msg));
|
||||
TEST_SIZE(strtoul(b_event->o_id, NULL, 10), sip->sip_cseq->cs_seq);
|
||||
|
||||
if (a_refer != a_call) {
|
||||
if (b_revents->head->next->next == NULL)
|
||||
run_ab_until(ctx, -1, save_until_received, nua_i_notify, save_events);
|
||||
else if (a_revents->head->next == NULL)
|
||||
while (!notify_e) {
|
||||
for (e = b_revents->head; e; e = e->next) {
|
||||
if (e->data->e_event == nua_i_notify) {
|
||||
notify_e = e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!notify_e)
|
||||
run_ab_until(ctx, -1, save_until_received, nua_i_notify, save_events);
|
||||
}
|
||||
|
||||
if (a_revents->head->next == NULL)
|
||||
run_a_until(ctx, -1, save_until_received);
|
||||
|
||||
TEST_1(e = a_revents->head->next); TEST_E(e->data->e_event, nua_r_notify);
|
||||
TEST_1(!e->next);
|
||||
|
||||
TEST_1(e = b_revents->head->next->next);
|
||||
TEST_1(e = notify_e);
|
||||
TEST_E(e->data->e_event, nua_i_notify);
|
||||
TEST(e->data->e_status, 200);
|
||||
TEST_1(sip = sip_object(e->data->e_msg));
|
||||
@ -304,8 +321,8 @@ int test_refer0(struct context *ctx, char const *tests,
|
||||
TEST_1(sip->sip_subscription_state);
|
||||
TEST_S(sip->sip_subscription_state->ss_substate, "pending");
|
||||
TEST_1(sip->sip_payload && sip->sip_payload->pl_data);
|
||||
TEST_S(sip->sip_payload->pl_data, "SIP/2.0 100 Trying\r\n");
|
||||
TEST_1(!e->next);
|
||||
TEST_M(sip->sip_payload->pl_data, "SIP/2.0 100 Trying\r\n",
|
||||
sip->sip_payload->pl_len);
|
||||
}
|
||||
|
||||
free_events_in_list(ctx, a_revents);
|
||||
@ -363,7 +380,8 @@ int test_refer0(struct context *ctx, char const *tests,
|
||||
TEST_1(sip->sip_subscription_state);
|
||||
TEST_S(sip->sip_subscription_state->ss_substate, "pending");
|
||||
TEST_1(sip->sip_payload && sip->sip_payload->pl_data);
|
||||
TEST_S(sip->sip_payload->pl_data, "SIP/2.0 100 Trying\r\n");
|
||||
TEST_M(sip->sip_payload->pl_data, "SIP/2.0 100 Trying\r\n",
|
||||
sip->sip_payload->pl_len);
|
||||
TEST_1(e = e->next);
|
||||
}
|
||||
TEST_E(e->data->e_event, nua_r_subscribe);
|
||||
@ -476,7 +494,7 @@ int test_refer0(struct context *ctx, char const *tests,
|
||||
TEST_1(sip->sip_subscription_state);
|
||||
TEST_S(sip->sip_subscription_state->ss_substate, "active");
|
||||
TEST_1(sip->sip_payload && sip->sip_payload->pl_data);
|
||||
TEST_S(sip->sip_payload->pl_data, "SIP/2.0 180 Ringing\r\n");
|
||||
TEST_M(sip->sip_payload->pl_data, "SIP/2.0 180 Ringing\r\n", sip->sip_payload->pl_len);
|
||||
TEST_1(sip->sip_event);
|
||||
if (refer_with_id)
|
||||
TEST_S(sip->sip_event->o_id, b_event->o_id);
|
||||
@ -486,7 +504,7 @@ int test_refer0(struct context *ctx, char const *tests,
|
||||
TEST_1(sip->sip_subscription_state);
|
||||
TEST_S(sip->sip_subscription_state->ss_substate, "terminated");
|
||||
TEST_1(sip->sip_payload && sip->sip_payload->pl_data);
|
||||
TEST_S(sip->sip_payload->pl_data, "SIP/2.0 200 OK\r\n");
|
||||
TEST_M(sip->sip_payload->pl_data, "SIP/2.0 200 OK\r\n", sip->sip_payload->pl_len);
|
||||
TEST_1(sip->sip_event);
|
||||
if (refer_with_id)
|
||||
TEST_S(sip->sip_event->o_id, b_event->o_id);
|
||||
|
@ -200,6 +200,10 @@ int test_register_to_proxy(struct context *ctx)
|
||||
m->m_display = "B";
|
||||
m->m_url->url_user = "b";
|
||||
|
||||
/* Include "tcp" transport parameter in Contact */
|
||||
if (ctx->p)
|
||||
m->m_url->url_params = "transport=tcp";
|
||||
|
||||
REGISTER(b, b_reg, b_reg->nh, SIPTAG_TO(b->to),
|
||||
SIPTAG_CONTACT(m),
|
||||
/* Do not include credentials unless challenged */
|
||||
@ -229,11 +233,14 @@ int test_register_to_proxy(struct context *ctx)
|
||||
TEST_S(sip->sip_contact->m_display, "B");
|
||||
TEST_S(sip->sip_contact->m_url->url_user, "b");
|
||||
free_events_in_list(ctx, b->events);
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-2.3.2: PASSED\n");
|
||||
|
||||
if (ctx->p)
|
||||
if (ctx->p) {
|
||||
test_proxy_close_tports(ctx->p);
|
||||
test_proxy_set_expiration(ctx->p, 600, 3600, 36000);
|
||||
}
|
||||
|
||||
if (print_headings)
|
||||
printf("TEST NUA-2.3.3: REGISTER c\n");
|
||||
|
@ -1194,7 +1194,7 @@ int test_subscription_timeout(struct context *ctx)
|
||||
|
||||
struct endpoint *a = &ctx->a, *b = &ctx->b;
|
||||
struct call *a_call = a->call, *b_call = b->call;
|
||||
struct event *e;
|
||||
struct event *e, *en, *es;
|
||||
sip_t const *sip;
|
||||
tagi_t const *n_tags, *r_tags;
|
||||
|
||||
@ -1220,22 +1220,16 @@ int test_subscription_timeout(struct context *ctx)
|
||||
/* Client events:
|
||||
nua_method(), nua_i_notify/nua_r_method, nua_i_notify
|
||||
*/
|
||||
TEST_1(e = a->events->head);
|
||||
if (e->data->e_event == nua_i_notify) {
|
||||
TEST_E(e->data->e_event, nua_i_notify);
|
||||
TEST_1(sip = sip_object(e->data->e_msg));
|
||||
n_tags = e->data->e_tags;
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_subscribe);
|
||||
r_tags = e->data->e_tags;
|
||||
}
|
||||
else {
|
||||
TEST_E(e->data->e_event, nua_r_method);
|
||||
TEST(e->data->e_status, 202);
|
||||
r_tags = e->data->e_tags;
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
|
||||
TEST_1(sip = sip_object(e->data->e_msg));
|
||||
n_tags = e->data->e_tags;
|
||||
}
|
||||
TEST_1(en = event_by_type(a->events->head, nua_i_notify));
|
||||
TEST_1(es = event_by_type(a->events->head, nua_r_method));
|
||||
|
||||
TEST_1(e = en); TEST_E(e->data->e_event, nua_i_notify);
|
||||
TEST_1(sip = sip_object(e->data->e_msg));
|
||||
n_tags = e->data->e_tags;
|
||||
|
||||
TEST_1(e = es); TEST_E(e->data->e_event, nua_r_method);
|
||||
r_tags = e->data->e_tags;
|
||||
|
||||
TEST_1(sip->sip_event); TEST_S(sip->sip_event->o_type, "presence");
|
||||
TEST_1(sip->sip_content_type);
|
||||
TEST_S(sip->sip_content_type->c_type, "application/pidf+xml");
|
||||
@ -1245,7 +1239,12 @@ int test_subscription_timeout(struct context *ctx)
|
||||
TEST_1(tl_find(n_tags, nutag_substate));
|
||||
TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_pending);
|
||||
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
|
||||
if (es->next == en)
|
||||
e = en->next;
|
||||
else
|
||||
e = es->next;
|
||||
|
||||
TEST_1(e); TEST_E(e->data->e_event, nua_i_notify);
|
||||
n_tags = e->data->e_tags;
|
||||
TEST_1(tl_find(n_tags, nutag_substate));
|
||||
TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_terminated);
|
||||
|
@ -89,9 +89,9 @@ int test_events(struct context *ctx)
|
||||
|
||||
struct endpoint *a = &ctx->a, *b = &ctx->b;
|
||||
struct call *a_call = a->call, *b_call = b->call;
|
||||
struct event *e;
|
||||
struct event *e, *en, *es;
|
||||
sip_t const *sip;
|
||||
tagi_t const *n_tags, *r_tags;
|
||||
tagi_t const *t, *n_tags, *r_tags;
|
||||
url_t b_url[1];
|
||||
nea_sub_t *sub = NULL;
|
||||
|
||||
@ -206,26 +206,25 @@ int test_events(struct context *ctx)
|
||||
/* Client events:
|
||||
nua_subscribe(), nua_i_notify/nua_r_subscribe
|
||||
*/
|
||||
TEST_1(e = a->events->head);
|
||||
if (e->data->e_event == nua_i_notify) {
|
||||
TEST_E(e->data->e_event, nua_i_notify);
|
||||
TEST_1(sip = sip_object(e->data->e_msg));
|
||||
n_tags = e->data->e_tags;
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_subscribe);
|
||||
r_tags = e->data->e_tags;
|
||||
TEST_1(tl_find(r_tags, nutag_substate));
|
||||
TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_active);
|
||||
TEST_1(en = event_by_type(a->events->head, nua_i_notify));
|
||||
TEST_1(es = event_by_type(a->events->head, nua_r_subscribe));
|
||||
|
||||
TEST_1(e = es); TEST_E(e->data->e_event, nua_r_subscribe);
|
||||
r_tags = e->data->e_tags;
|
||||
TEST_1(tl_find(r_tags, nutag_substate));
|
||||
if (es->next == en) {
|
||||
TEST_1(200 <= e->data->e_status && e->data->e_status < 300);
|
||||
TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_embryonic);
|
||||
}
|
||||
else {
|
||||
TEST_E(e->data->e_event, nua_r_subscribe);
|
||||
TEST(e->data->e_status, 202);
|
||||
r_tags = e->data->e_tags;
|
||||
TEST_1(tl_find(r_tags, nutag_substate));
|
||||
TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_embryonic);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
|
||||
TEST_1(sip = sip_object(e->data->e_msg));
|
||||
n_tags = e->data->e_tags;
|
||||
TEST_1(200 <= e->data->e_status && e->data->e_status < 300);
|
||||
TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_active);
|
||||
}
|
||||
|
||||
TEST_1(e = en); TEST_E(e->data->e_event, nua_i_notify);
|
||||
TEST_1(sip = sip_object(e->data->e_msg));
|
||||
n_tags = e->data->e_tags;
|
||||
|
||||
TEST_1(sip->sip_event); TEST_S(sip->sip_event->o_type, "presence");
|
||||
TEST_1(sip->sip_content_type);
|
||||
TEST_S(sip->sip_content_type->c_type, "application/pidf+xml");
|
||||
@ -234,7 +233,7 @@ int test_events(struct context *ctx)
|
||||
TEST_1(sip->sip_subscription_state->ss_expires);
|
||||
TEST_1(tl_find(n_tags, nutag_substate));
|
||||
TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_active);
|
||||
TEST_1(!e->next);
|
||||
TEST_1(!en->next || !es->next);
|
||||
free_events_in_list(ctx, a->events);
|
||||
|
||||
if (print_headings)
|
||||
@ -302,7 +301,7 @@ int test_events(struct context *ctx)
|
||||
|
||||
UNSUBSCRIBE(a, a_call, a_call->nh, TAG_END());
|
||||
|
||||
run_ab_until(ctx, -1, save_until_notified_and_responded,
|
||||
run_ab_until(ctx, -1, save_until_final_response,
|
||||
-1, NULL /* XXX save_until_received */);
|
||||
|
||||
/* Client events:
|
||||
@ -313,26 +312,21 @@ int test_events(struct context *ctx)
|
||||
TEST_E(e->data->e_event, nua_i_notify);
|
||||
TEST_1(sip = sip_object(e->data->e_msg));
|
||||
n_tags = e->data->e_tags;
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_unsubscribe);
|
||||
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(sip->sip_event);
|
||||
TEST_1(sip->sip_subscription_state);
|
||||
TEST_S(sip->sip_subscription_state->ss_substate, "terminated");
|
||||
TEST_1(!sip->sip_subscription_state->ss_expires);
|
||||
TEST_1(tl_find(n_tags, nutag_substate));
|
||||
TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_terminated);
|
||||
TEST_1(e = e->next);
|
||||
}
|
||||
else {
|
||||
TEST_E(e->data->e_event, nua_r_unsubscribe);
|
||||
TEST(e->data->e_status, 202);
|
||||
TEST_1(tl_find(e->data->e_tags, nutag_substate));
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
|
||||
TEST_1(sip = sip_object(e->data->e_msg));
|
||||
n_tags = e->data->e_tags;
|
||||
}
|
||||
TEST_1(sip->sip_event);
|
||||
TEST_1(sip->sip_subscription_state);
|
||||
TEST_S(sip->sip_subscription_state->ss_substate, "terminated");
|
||||
TEST_1(!sip->sip_subscription_state->ss_expires);
|
||||
TEST_1(tl_find(n_tags, nutag_substate));
|
||||
TEST(tl_find(n_tags, nutag_substate)->t_value, nua_substate_terminated);
|
||||
TEST_1(!e->next);
|
||||
TEST_E(e->data->e_event, nua_r_unsubscribe);
|
||||
TEST_1(tl_find(e->data->e_tags, nutag_substate));
|
||||
TEST(tl_find(e->data->e_tags, nutag_substate)->t_value,
|
||||
nua_substate_terminated);
|
||||
/* Currently, NOTIFY is dropped after successful response to unsubscribe */
|
||||
/* But we don't really care.. */
|
||||
/* TEST_1(!e->next); */
|
||||
free_events_in_list(ctx, a->events);
|
||||
|
||||
if (print_headings)
|
||||
@ -383,26 +377,18 @@ int test_events(struct context *ctx)
|
||||
/* Client events:
|
||||
nua_subscribe(), nua_i_notify/nua_r_subscribe
|
||||
*/
|
||||
TEST_1(e = a->events->head);
|
||||
if (e->data->e_event == nua_i_notify) {
|
||||
TEST_E(e->data->e_event, nua_i_notify);
|
||||
TEST_1(sip = sip_object(e->data->e_msg));
|
||||
n_tags = e->data->e_tags;
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_subscribe);
|
||||
TEST_1(tl_find(e->data->e_tags, nutag_substate));
|
||||
TEST(tl_find(e->data->e_tags, nutag_substate)->t_value,
|
||||
nua_substate_pending);
|
||||
}
|
||||
else {
|
||||
TEST_E(e->data->e_event, nua_r_subscribe);
|
||||
TEST(e->data->e_status, 202);
|
||||
TEST_1(tl_find(e->data->e_tags, nutag_substate));
|
||||
TEST(tl_find(e->data->e_tags, nutag_substate)->t_value,
|
||||
nua_substate_embryonic);
|
||||
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
|
||||
TEST_1(sip = sip_object(e->data->e_msg));
|
||||
n_tags = e->data->e_tags;
|
||||
}
|
||||
TEST_1(en = event_by_type(a->events->head, nua_i_notify));
|
||||
TEST_1(es = event_by_type(a->events->head, nua_r_subscribe));
|
||||
|
||||
e = es; TEST_E(e->data->e_event, nua_r_subscribe);
|
||||
TEST_1(t = tl_find(e->data->e_tags, nutag_substate));
|
||||
TEST_1(t->t_value == nua_substate_pending ||
|
||||
t->t_value == nua_substate_embryonic);
|
||||
|
||||
e = en; TEST_E(e->data->e_event, nua_i_notify);
|
||||
TEST_1(sip = sip_object(e->data->e_msg));
|
||||
n_tags = e->data->e_tags;
|
||||
|
||||
TEST_1(sip->sip_event); TEST_S(sip->sip_event->o_type, "presence");
|
||||
TEST_S(sip->sip_event->o_id, "1");
|
||||
TEST_1(sip->sip_content_type);
|
||||
@ -417,7 +403,7 @@ int test_events(struct context *ctx)
|
||||
TEST_1(tl_find(n_tags, nutag_substate));
|
||||
TEST(tl_find(n_tags, nutag_substate)->t_value,
|
||||
nua_substate_pending);
|
||||
TEST_1(!e->next);
|
||||
TEST_1(!en->next || !es->next);
|
||||
free_events_in_list(ctx, a->events);
|
||||
|
||||
/*
|
||||
|
@ -718,6 +718,9 @@ issize_t sip_name_addr_d(su_home_t *home,
|
||||
* it is like "Contact: url:foo,sip:bar,sip:zunk"
|
||||
*/
|
||||
c = *s; *s = '\0'; /* terminate temporarily */
|
||||
/* Do not accept an empty URL */
|
||||
if (addr_spec[0] == '\0')
|
||||
return -1;
|
||||
if (url_d(return_url, addr_spec) == -1)
|
||||
return -1;
|
||||
*s = c; /* return terminator */
|
||||
|
@ -104,7 +104,7 @@ SOFIAPUBVAR tag_typedef_t siptag_sip;
|
||||
#define SIPTAG_SIP_REF(x) siptag_sip_ref, siptag_sip_vr(&(x))
|
||||
SOFIAPUBVAR tag_typedef_t siptag_sip_ref;
|
||||
|
||||
#if SU_HAVE_INLINE
|
||||
#if SU_INLINE_TAG_CAST
|
||||
su_inline
|
||||
tag_value_t siptag_sip_v(sip_t const *v) { return (tag_value_t)v; }
|
||||
su_inline
|
||||
@ -136,7 +136,7 @@ SOFIAPUBVAR tag_typedef_t siptag_header;
|
||||
#define SIPTAG_HEADER_REF(x) siptag_header_ref, siptag_header_vr(&(x))
|
||||
SOFIAPUBVAR tag_typedef_t siptag_header_ref;
|
||||
|
||||
#if SU_HAVE_INLINE
|
||||
#if SU_INLINE_TAG_CAST
|
||||
su_inline tag_value_t
|
||||
siptag_header_v(sip_header_t const *v)
|
||||
{ return (tag_value_t)v; }
|
||||
@ -240,7 +240,7 @@ SOFIAPUBVAR tag_typedef_t siptag_#xxxxxx#_str;
|
||||
#define SIPTAG_#XXXXXX#_STR_REF(x) siptag_#xxxxxx#_str_ref, tag_str_vr(&(x))
|
||||
SOFIAPUBVAR tag_typedef_t siptag_#xxxxxx#_str_ref;
|
||||
|
||||
#if SU_HAVE_INLINE
|
||||
#if SU_INLINE_TAG_CAST
|
||||
su_inline tag_value_t
|
||||
siptag_#xxxxxx#_v(sip_#xxxxxx#_t const *v)
|
||||
{ return (tag_value_t)v; }
|
||||
|
@ -405,6 +405,8 @@ int test_basic(void)
|
||||
|
||||
TEST_1(!sip_from_create(home, (void *)"sip:joe@[baa"));
|
||||
|
||||
TEST_1(!sip_from_make(home, (void *)"tester <>;tag=fasjfuios"));
|
||||
|
||||
TEST_1(f = sip_from_make(home, (void *)"sip:joe@bar (foo)"));
|
||||
su_free(home, f);
|
||||
|
||||
|
@ -80,9 +80,19 @@ typedef struct soa_static_session
|
||||
{
|
||||
soa_session_t sss_session[1];
|
||||
char *sss_audio_aux;
|
||||
int sss_ordered_user; /**< User SDP is ordered */
|
||||
int sss_reuse_rejected; /**< Try to reuse rejected media line slots */
|
||||
|
||||
/** Mapping from user SDP m= lines to session SDP m= lines */
|
||||
int *sss_u2s;
|
||||
/** Mapping from session SDP m= lines to user SDP m= lines */
|
||||
int *sss_s2u;
|
||||
}
|
||||
soa_static_session_t;
|
||||
|
||||
#define U2S_NOT_USED (-1)
|
||||
#define U2S_SENTINEL (-2)
|
||||
|
||||
static int soa_static_init(char const *, soa_session_t *, soa_session_t *);
|
||||
static void soa_static_deinit(soa_session_t *);
|
||||
static int soa_static_set_params(soa_session_t *ss, tagi_t const *tags);
|
||||
@ -152,10 +162,14 @@ static int soa_static_set_params(soa_session_t *ss, tagi_t const *tags)
|
||||
{
|
||||
soa_static_session_t *sss = (soa_static_session_t *)ss;
|
||||
char const *audio_aux = sss->sss_audio_aux;
|
||||
int ordered_user = sss->sss_ordered_user;
|
||||
int reuse_rejected = sss->sss_reuse_rejected;
|
||||
int n, m;
|
||||
|
||||
n = tl_gets(tags,
|
||||
SOATAG_AUDIO_AUX_REF(audio_aux),
|
||||
SOATAG_ORDERED_USER_REF(ordered_user),
|
||||
SOATAG_REUSE_REJECTED_REF(reuse_rejected),
|
||||
TAG_END());
|
||||
|
||||
if (n > 0 && str0casecmp(audio_aux, sss->sss_audio_aux)) {
|
||||
@ -167,6 +181,9 @@ static int soa_static_set_params(soa_session_t *ss, tagi_t const *tags)
|
||||
su_free(ss->ss_home, tbf);
|
||||
}
|
||||
|
||||
sss->sss_ordered_user = ordered_user != 0;
|
||||
sss->sss_reuse_rejected = reuse_rejected != 0;
|
||||
|
||||
m = soa_base_set_params(ss, tags);
|
||||
if (m < 0)
|
||||
return m;
|
||||
@ -182,6 +199,8 @@ static int soa_static_get_params(soa_session_t const *ss, tagi_t *tags)
|
||||
|
||||
n = tl_tgets(tags,
|
||||
SOATAG_AUDIO_AUX(sss->sss_audio_aux),
|
||||
SOATAG_ORDERED_USER(sss->sss_ordered_user),
|
||||
SOATAG_REUSE_REJECTED(sss->sss_reuse_rejected),
|
||||
TAG_END());
|
||||
m = soa_base_get_params(ss, tags);
|
||||
if (m < 0)
|
||||
@ -204,6 +223,10 @@ static tagi_t *soa_static_get_paramlist(soa_session_t const *ss,
|
||||
tl = soa_base_get_paramlist(ss,
|
||||
TAG_IF(sss->sss_audio_aux,
|
||||
SOATAG_AUDIO_AUX(sss->sss_audio_aux)),
|
||||
TAG_IF(sss->sss_ordered_user,
|
||||
SOATAG_ORDERED_USER(1)),
|
||||
TAG_IF(sss->sss_reuse_rejected,
|
||||
SOATAG_REUSE_REJECTED(1)),
|
||||
TAG_NEXT(ta_args(ta)));
|
||||
|
||||
ta_end(ta);
|
||||
@ -239,6 +262,7 @@ static int soa_static_set_user_sdp(soa_session_t *ss,
|
||||
}
|
||||
|
||||
/** Generate a rejected m= line */
|
||||
static
|
||||
sdp_media_t *soa_sdp_make_rejected_media(su_home_t *home,
|
||||
sdp_media_t const *m,
|
||||
sdp_session_t *sdp,
|
||||
@ -263,6 +287,7 @@ sdp_media_t *soa_sdp_make_rejected_media(su_home_t *home,
|
||||
|
||||
/** Expand a @a truncated SDP.
|
||||
*/
|
||||
static
|
||||
sdp_session_t *soa_sdp_expand_media(su_home_t *home,
|
||||
sdp_session_t const *truncated,
|
||||
sdp_session_t const *complete)
|
||||
@ -312,6 +337,7 @@ int soa_sdp_upgrade_is_needed(sdp_session_t const *session,
|
||||
}
|
||||
|
||||
/** Check if codec is in auxiliary list */
|
||||
static
|
||||
int soa_sdp_is_auxiliary_codec(sdp_rtpmap_t const *rm, char const *auxiliary)
|
||||
{
|
||||
char const *codec;
|
||||
@ -342,68 +368,84 @@ int soa_sdp_is_auxiliary_codec(sdp_rtpmap_t const *rm, char const *auxiliary)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
sdp_rtpmap_t *soa_sdp_media_matching_rtpmap(sdp_rtpmap_t const *from,
|
||||
sdp_rtpmap_t const *anylist,
|
||||
char const *auxiliary)
|
||||
{
|
||||
sdp_rtpmap_t const *rm;
|
||||
|
||||
/** Find first matching media in table. */
|
||||
sdp_media_t *soa_sdp_matching(soa_session_t *ss,
|
||||
sdp_media_t *mm[],
|
||||
sdp_media_t const *with,
|
||||
int *return_common_codecs)
|
||||
for (rm = anylist; rm; rm = rm->rm_next) {
|
||||
/* Ignore auxiliary codecs */
|
||||
if (auxiliary && soa_sdp_is_auxiliary_codec(rm, auxiliary))
|
||||
continue;
|
||||
|
||||
if (sdp_rtpmap_find_matching(from, rm))
|
||||
return (sdp_rtpmap_t *)rm;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define SDP_MEDIA_NONE ((sdp_media_t *)-1)
|
||||
|
||||
/** Find first matching media in table @a mm.
|
||||
*
|
||||
* - if allow_rtp_mismatch == 0, search for a matching codec
|
||||
* - if allow_rtp_mismatch == 1, prefer m=line with matching codec
|
||||
* - if allow_rtp_mismatch > 1, ignore codecs
|
||||
*/
|
||||
static
|
||||
int soa_sdp_matching_mindex(soa_session_t *ss,
|
||||
sdp_media_t *mm[],
|
||||
sdp_media_t const *with,
|
||||
int *return_codec_mismatch)
|
||||
{
|
||||
int i, j = -1;
|
||||
sdp_media_t *m;
|
||||
sdp_rtpmap_t const *rm;
|
||||
soa_static_session_t *sss = (soa_static_session_t *)ss;
|
||||
char const *auxiliary;
|
||||
int rtp = sdp_media_uses_rtp(with), dummy;
|
||||
char const *auxiliary = NULL;
|
||||
|
||||
auxiliary = with->m_type == sdp_media_audio ? sss->sss_audio_aux : NULL;
|
||||
if (return_codec_mismatch == NULL)
|
||||
return_codec_mismatch = &dummy;
|
||||
|
||||
/* Looking for a single codec */
|
||||
if (with->m_rtpmaps && with->m_rtpmaps->rm_next == NULL)
|
||||
auxiliary = NULL;
|
||||
if (with->m_type == sdp_media_audio) {
|
||||
auxiliary = sss->sss_audio_aux;
|
||||
/* Looking for a single codec */
|
||||
if (with->m_rtpmaps && with->m_rtpmaps->rm_next == NULL)
|
||||
auxiliary = NULL;
|
||||
}
|
||||
|
||||
for (i = 0; mm[i]; i++) {
|
||||
if (mm[i] == SDP_MEDIA_NONE)
|
||||
continue;
|
||||
|
||||
if (!sdp_media_match_with(mm[i], with))
|
||||
continue;
|
||||
|
||||
if (!sdp_media_uses_rtp(with))
|
||||
if (!rtp)
|
||||
break;
|
||||
|
||||
if (!return_common_codecs)
|
||||
if (soa_sdp_media_matching_rtpmap(with->m_rtpmaps,
|
||||
mm[i]->m_rtpmaps,
|
||||
auxiliary))
|
||||
break;
|
||||
|
||||
/* Check also rtpmaps */
|
||||
for (rm = mm[i]->m_rtpmaps; rm; rm = rm->rm_next) {
|
||||
/* Ignore auxiliary codecs */
|
||||
if (auxiliary && soa_sdp_is_auxiliary_codec(rm, auxiliary))
|
||||
continue;
|
||||
|
||||
if (sdp_rtpmap_find_matching(with->m_rtpmaps, rm))
|
||||
break;
|
||||
}
|
||||
if (rm)
|
||||
break;
|
||||
if (j == -1)
|
||||
j = i;
|
||||
}
|
||||
|
||||
if (return_common_codecs)
|
||||
*return_common_codecs = mm[i] != NULL;
|
||||
|
||||
if (mm[i] == NULL && j != -1)
|
||||
i = j; /* return m= line without common codecs */
|
||||
|
||||
m = mm[i];
|
||||
|
||||
for (; mm[i]; i++)
|
||||
mm[i] = mm[i + 1];
|
||||
|
||||
return m;
|
||||
if (mm[i])
|
||||
return *return_codec_mismatch = 0, i;
|
||||
else
|
||||
return *return_codec_mismatch = 1, j;
|
||||
}
|
||||
|
||||
/** Set payload types in @a l_m according to the values in @a r_m.
|
||||
*
|
||||
* @retval number of common codecs
|
||||
*/
|
||||
static
|
||||
int soa_sdp_set_rtpmap_pt(sdp_media_t *l_m,
|
||||
sdp_media_t const *r_m)
|
||||
{
|
||||
@ -511,6 +553,7 @@ int soa_sdp_set_rtpmap_pt(sdp_media_t *l_m,
|
||||
*
|
||||
* @return Number of common codecs
|
||||
*/
|
||||
static
|
||||
int soa_sdp_sort_rtpmap(sdp_rtpmap_t **inout_list,
|
||||
sdp_rtpmap_t const *rrm,
|
||||
char const *auxiliary)
|
||||
@ -564,6 +607,7 @@ int soa_sdp_sort_rtpmap(sdp_rtpmap_t **inout_list,
|
||||
*
|
||||
* @return Number of common codecs
|
||||
*/
|
||||
static
|
||||
int soa_sdp_select_rtpmap(sdp_rtpmap_t **inout_list,
|
||||
sdp_rtpmap_t const *rrm,
|
||||
char const *auxiliary,
|
||||
@ -597,139 +641,220 @@ int soa_sdp_select_rtpmap(sdp_rtpmap_t **inout_list,
|
||||
return common_codecs;
|
||||
}
|
||||
|
||||
/** Sort and select rtpmaps within session */
|
||||
int soa_sdp_upgrade_rtpmaps(soa_session_t *ss,
|
||||
sdp_session_t *session,
|
||||
sdp_session_t const *remote)
|
||||
|
||||
/** Sort and select rtpmaps */
|
||||
static
|
||||
int soa_sdp_media_upgrade_rtpmaps(soa_session_t *ss,
|
||||
sdp_media_t *sm,
|
||||
sdp_media_t const *rm)
|
||||
{
|
||||
soa_static_session_t *sss = (soa_static_session_t *)ss;
|
||||
char const *auxiliary = NULL;
|
||||
int common_codecs;
|
||||
|
||||
common_codecs = soa_sdp_set_rtpmap_pt(sm, rm);
|
||||
|
||||
if (rm->m_type == sdp_media_audio)
|
||||
auxiliary = sss->sss_audio_aux;
|
||||
|
||||
if (ss->ss_rtp_sort == SOA_RTP_SORT_REMOTE ||
|
||||
(ss->ss_rtp_sort == SOA_RTP_SORT_DEFAULT &&
|
||||
rm->m_mode == sdp_recvonly)) {
|
||||
soa_sdp_sort_rtpmap(&sm->m_rtpmaps, rm->m_rtpmaps, auxiliary);
|
||||
}
|
||||
|
||||
if (common_codecs == 0)
|
||||
;
|
||||
else if (ss->ss_rtp_select == SOA_RTP_SELECT_SINGLE) {
|
||||
soa_sdp_select_rtpmap(&sm->m_rtpmaps, rm->m_rtpmaps, auxiliary, 1);
|
||||
}
|
||||
else if (ss->ss_rtp_select == SOA_RTP_SELECT_COMMON) {
|
||||
soa_sdp_select_rtpmap(&sm->m_rtpmaps, rm->m_rtpmaps, auxiliary, 0);
|
||||
}
|
||||
|
||||
return common_codecs;
|
||||
}
|
||||
|
||||
|
||||
/** Sort and select rtpmaps within session */
|
||||
static
|
||||
int soa_sdp_session_upgrade_rtpmaps(soa_session_t *ss,
|
||||
sdp_session_t *session,
|
||||
sdp_session_t const *remote)
|
||||
{
|
||||
sdp_media_t *sm;
|
||||
sdp_media_t const *rm;
|
||||
|
||||
for (sm = session->sdp_media, rm = remote->sdp_media;
|
||||
sm && rm;
|
||||
sm = sm->m_next, rm = rm->m_next) {
|
||||
if (sm->m_rejected)
|
||||
continue;
|
||||
if (sdp_media_uses_rtp(sm)) {
|
||||
int common_codecs = soa_sdp_set_rtpmap_pt(sm, rm);
|
||||
|
||||
char const *auxiliary =
|
||||
rm->m_type == sdp_media_audio ? sss->sss_audio_aux : NULL;
|
||||
|
||||
if (ss->ss_rtp_sort == SOA_RTP_SORT_REMOTE ||
|
||||
(ss->ss_rtp_sort == SOA_RTP_SORT_DEFAULT &&
|
||||
rm->m_mode == sdp_recvonly)) {
|
||||
soa_sdp_sort_rtpmap(&sm->m_rtpmaps, rm->m_rtpmaps, auxiliary);
|
||||
}
|
||||
|
||||
if (common_codecs == 0)
|
||||
;
|
||||
else if (ss->ss_rtp_select == SOA_RTP_SELECT_SINGLE) {
|
||||
soa_sdp_select_rtpmap(&sm->m_rtpmaps, rm->m_rtpmaps, auxiliary, 1);
|
||||
}
|
||||
else if (ss->ss_rtp_select == SOA_RTP_SELECT_COMMON) {
|
||||
soa_sdp_select_rtpmap(&sm->m_rtpmaps, rm->m_rtpmaps, auxiliary, 0);
|
||||
}
|
||||
}
|
||||
if (!sm->m_rejected && sdp_media_uses_rtp(sm))
|
||||
soa_sdp_media_upgrade_rtpmaps(ss, sm, rm);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/** Upgrade m= lines within session */
|
||||
static
|
||||
int soa_sdp_upgrade(soa_session_t *ss,
|
||||
su_home_t *home,
|
||||
sdp_session_t *session,
|
||||
sdp_session_t const *caps,
|
||||
sdp_session_t const *upgrader)
|
||||
sdp_session_t const *user,
|
||||
sdp_session_t const *remote,
|
||||
int **return_u2s,
|
||||
int **return_s2u)
|
||||
{
|
||||
soa_static_session_t *sss = (soa_static_session_t *)ss;
|
||||
|
||||
int Ns, Nc, Nu, size, i, j;
|
||||
sdp_media_t *m, **mm, *cm;
|
||||
sdp_media_t **s_media, **o_media, **c_media;
|
||||
sdp_media_t const **u_media;
|
||||
int Ns, Nu, Nr, size, i, j;
|
||||
sdp_media_t *m, **mm, *um;
|
||||
sdp_media_t **s_media, **o_media, **u_media;
|
||||
sdp_media_t const *rm, **r_media;
|
||||
int *u2s = NULL, *s2u = NULL;
|
||||
|
||||
if (session == NULL || user == NULL)
|
||||
return (errno = EFAULT), -1;
|
||||
|
||||
Ns = sdp_media_count(session, sdp_media_any, 0, 0, 0);
|
||||
Nc = sdp_media_count(caps, sdp_media_any, 0, 0, 0);
|
||||
Nu = sdp_media_count(upgrader, sdp_media_any, 0, 0, 0);
|
||||
Nu = sdp_media_count(user, sdp_media_any, 0, 0, 0);
|
||||
Nr = sdp_media_count(remote, sdp_media_any, 0, 0, 0);
|
||||
|
||||
if (caps == upgrader)
|
||||
size = Ns + Nc + 1;
|
||||
else if (Ns < Nu)
|
||||
size = Nu + 1;
|
||||
if (remote == NULL)
|
||||
size = Ns + Nu + 1;
|
||||
else if (Ns < Nr)
|
||||
size = Nr + 1;
|
||||
else
|
||||
size = Ns + 1;
|
||||
|
||||
s_media = su_zalloc(home, size * (sizeof *s_media));
|
||||
o_media = su_zalloc(home, (Ns + 1) * (sizeof *o_media));
|
||||
c_media = su_zalloc(home, (Nc + 1) * (sizeof *c_media));
|
||||
u_media = su_zalloc(home, (Nu + 1) * (sizeof *u_media));
|
||||
r_media = su_zalloc(home, (Nr + 1) * (sizeof *r_media));
|
||||
|
||||
cm = sdp_media_dup_all(home, caps->sdp_media, session);
|
||||
um = sdp_media_dup_all(home, user->sdp_media, session);
|
||||
|
||||
if (!s_media || !c_media || !u_media || !cm)
|
||||
if (!s_media || !u_media || !r_media || !um)
|
||||
return -1;
|
||||
|
||||
u2s = su_alloc(home, (Nu + 1) * sizeof(*u2s));
|
||||
s2u = su_alloc(home, size * sizeof(*s2u));
|
||||
if (!u2s || !s2u)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < Nu; i++)
|
||||
u2s[i] = U2S_NOT_USED;
|
||||
u2s[i] = U2S_SENTINEL;
|
||||
|
||||
for (i = 0; i <= size; i++)
|
||||
s2u[i] = U2S_NOT_USED;
|
||||
s2u[i] = U2S_SENTINEL;
|
||||
|
||||
for (i = 0, m = session->sdp_media; m && i < Ns; m = m->m_next)
|
||||
o_media[i++] = m;
|
||||
assert(i == Ns);
|
||||
for (i = 0, m = cm; m && i < Nc; m = m->m_next)
|
||||
c_media[i++] = m;
|
||||
assert(i == Nc);
|
||||
for (i = 0, m = upgrader->sdp_media; m && i < Nu; m = m->m_next)
|
||||
for (i = 0, m = um; m && i < Nu; m = m->m_next)
|
||||
u_media[i++] = m;
|
||||
assert(i == Nu);
|
||||
m = remote ? remote->sdp_media : NULL;
|
||||
for (i = 0; m && i < Nr; m = m->m_next)
|
||||
r_media[i++] = m;
|
||||
assert(i == Nr);
|
||||
|
||||
if (caps != upgrader) {
|
||||
if (sss->sss_ordered_user && sss->sss_u2s) { /* User SDP is ordered */
|
||||
for (j = 0; sss->sss_u2s[j] != U2S_SENTINEL; j++) {
|
||||
i = sss->sss_u2s[j];
|
||||
if (i == U2S_NOT_USED)
|
||||
continue;
|
||||
if (j >= Nu) /* lines removed from user SDP */
|
||||
continue;
|
||||
s_media[i] = u_media[j], u_media[j] = SDP_MEDIA_NONE;
|
||||
u2s[j] = i, s2u[i] = j;
|
||||
}
|
||||
}
|
||||
|
||||
if (remote) {
|
||||
/* Update session according to remote */
|
||||
for (i = 0; i < Nu; i++) {
|
||||
int common_codecs = 0;
|
||||
for (i = 0; i < Nr; i++) {
|
||||
rm = r_media[i];
|
||||
m = s_media[i];
|
||||
|
||||
m = soa_sdp_matching(ss, c_media, u_media[i], &common_codecs);
|
||||
if (!m) {
|
||||
int codec_mismatch = 0;
|
||||
|
||||
if (!m || u_media[i]->m_rejected) {
|
||||
m = soa_sdp_make_rejected_media(home, u_media[i], session, 0);
|
||||
}
|
||||
else if (sdp_media_uses_rtp(m)) {
|
||||
/* Process rtpmaps */
|
||||
char const *auxiliary =
|
||||
m->m_type == sdp_media_audio ? sss->sss_audio_aux : NULL;
|
||||
if (!rm->m_rejected)
|
||||
j = soa_sdp_matching_mindex(ss, u_media, rm, &codec_mismatch);
|
||||
else
|
||||
j = -1;
|
||||
|
||||
if (!common_codecs && !ss->ss_rtp_mismatch)
|
||||
m = soa_sdp_make_rejected_media(home, m, session, 1);
|
||||
soa_sdp_set_rtpmap_pt(m, u_media[i]);
|
||||
|
||||
if (ss->ss_rtp_sort == SOA_RTP_SORT_REMOTE ||
|
||||
(ss->ss_rtp_sort == SOA_RTP_SORT_DEFAULT &&
|
||||
u_media[i]->m_mode == sdp_recvonly)) {
|
||||
soa_sdp_sort_rtpmap(&m->m_rtpmaps, u_media[i]->m_rtpmaps, auxiliary);
|
||||
if (j == -1) {
|
||||
s_media[i] = soa_sdp_make_rejected_media(home, rm, session, 0);
|
||||
continue;
|
||||
}
|
||||
else if (codec_mismatch && !ss->ss_rtp_mismatch) {
|
||||
m = soa_sdp_make_rejected_media(home, u_media[j], session, 1);
|
||||
soa_sdp_set_rtpmap_pt(s_media[i] = m, rm);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (common_codecs &&
|
||||
(ss->ss_rtp_select == SOA_RTP_SELECT_SINGLE ||
|
||||
ss->ss_rtp_select == SOA_RTP_SELECT_COMMON)) {
|
||||
soa_sdp_select_rtpmap(&m->m_rtpmaps, u_media[i]->m_rtpmaps, auxiliary,
|
||||
ss->ss_rtp_select == SOA_RTP_SELECT_SINGLE);
|
||||
}
|
||||
s_media[i] = m = u_media[j]; u_media[j] = SDP_MEDIA_NONE;
|
||||
u2s[j] = i, s2u[i] = j;
|
||||
}
|
||||
|
||||
s_media[i] = m;
|
||||
if (sdp_media_uses_rtp(rm))
|
||||
soa_sdp_media_upgrade_rtpmaps(ss, m, rm);
|
||||
}
|
||||
}
|
||||
else if (sss->sss_ordered_user) {
|
||||
/* Update session with unused media in u_media */
|
||||
|
||||
if (!sss->sss_reuse_rejected) {
|
||||
/* Mark previously used slots */
|
||||
for (i = 0; i < Ns; i++) {
|
||||
if (s_media[i])
|
||||
continue;
|
||||
s_media[i] = soa_sdp_make_rejected_media(home, o_media[i], session, 0);
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 0; j < Nu; j++) {
|
||||
if (u_media[j] == SDP_MEDIA_NONE)
|
||||
continue;
|
||||
|
||||
for (i = 0; i < size - 1; i++) {
|
||||
if (s_media[i] != NULL)
|
||||
continue;
|
||||
s_media[i] = u_media[j], u_media[j] = SDP_MEDIA_NONE;
|
||||
u2s[j] = i, s2u[i] = j;
|
||||
}
|
||||
|
||||
assert(i != size);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Update session according to local */
|
||||
/* Match unused user media by media types with the existing session */
|
||||
for (i = 0; i < Ns; i++) {
|
||||
m = soa_sdp_matching(ss, c_media, o_media[i], NULL);
|
||||
if (!m)
|
||||
m = soa_sdp_make_rejected_media(home, o_media[i], session, 0);
|
||||
s_media[i] = m;
|
||||
if (s_media[i])
|
||||
continue;
|
||||
|
||||
j = soa_sdp_matching_mindex(ss, u_media, o_media[i], NULL);
|
||||
if (j == -1) {
|
||||
s_media[i] = soa_sdp_make_rejected_media(home, o_media[i], session, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
s_media[i] = u_media[j], u_media[j] = SDP_MEDIA_NONE;
|
||||
u2s[j] = i, s2u[i] = j;
|
||||
}
|
||||
|
||||
/* Here we just append new media at the end */
|
||||
for (j = 0; c_media[j]; j++)
|
||||
s_media[i++] = c_media[j];
|
||||
for (j = 0; j < Nu; j++) {
|
||||
if (u_media[j] != SDP_MEDIA_NONE) {
|
||||
s_media[i] = u_media[j], u_media[j] = SDP_MEDIA_NONE;
|
||||
u2s[j] = i, s2u[i] = j;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
assert(i <= size);
|
||||
}
|
||||
|
||||
@ -739,10 +864,46 @@ int soa_sdp_upgrade(soa_session_t *ss,
|
||||
}
|
||||
*mm = NULL;
|
||||
|
||||
#ifndef NDEBUG
|
||||
for (j = i; j < size; j++)
|
||||
assert(s2u[j] == U2S_NOT_USED);
|
||||
#endif
|
||||
|
||||
s2u[size = i] = U2S_SENTINEL;
|
||||
*return_u2s = u2s;
|
||||
*return_s2u = s2u;
|
||||
|
||||
#ifndef NDEBUG /* X check */
|
||||
for (j = 0; j < Nu; j++) {
|
||||
i = u2s[j];
|
||||
assert(i == U2S_NOT_USED || s2u[i] == j);
|
||||
}
|
||||
for (i = 0; i < size; i++) {
|
||||
j = s2u[i];
|
||||
assert(j == U2S_NOT_USED || u2s[j] == i);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int *u2s_alloc(su_home_t *home, int const *u2s)
|
||||
{
|
||||
if (u2s) {
|
||||
int i, *a;
|
||||
for (i = 0; u2s[i] != U2S_SENTINEL; i++)
|
||||
;
|
||||
a = su_alloc(home, (i + 1) * (sizeof *u2s));
|
||||
if (a)
|
||||
memcpy(a, u2s, (i + 1) * (sizeof *u2s));
|
||||
return a;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Check if @a session contains media that are rejected by @a remote. */
|
||||
static
|
||||
int soa_sdp_reject_is_needed(sdp_session_t const *session,
|
||||
sdp_session_t const *remote)
|
||||
{
|
||||
@ -774,6 +935,7 @@ int soa_sdp_reject_is_needed(sdp_session_t const *session,
|
||||
}
|
||||
|
||||
/** If m= line is rejected by remote mark m= line rejected within session */
|
||||
static
|
||||
int soa_sdp_reject(su_home_t *home,
|
||||
sdp_session_t *session,
|
||||
sdp_session_t const *remote)
|
||||
@ -813,6 +975,7 @@ int soa_sdp_reject(su_home_t *home,
|
||||
}
|
||||
|
||||
/** Check if @a session mode should be changed. */
|
||||
static
|
||||
int soa_sdp_mode_set_is_needed(sdp_session_t const *session,
|
||||
sdp_session_t const *remote,
|
||||
char const *hold)
|
||||
@ -855,6 +1018,7 @@ int soa_sdp_mode_set_is_needed(sdp_session_t const *session,
|
||||
|
||||
|
||||
/** Update mode within session */
|
||||
static
|
||||
int soa_sdp_mode_set(sdp_session_t *session,
|
||||
sdp_session_t const *remote,
|
||||
char const *hold)
|
||||
@ -908,6 +1072,8 @@ static int offer_answer_step(soa_session_t *ss,
|
||||
enum offer_answer_action action,
|
||||
char const *by)
|
||||
{
|
||||
soa_static_session_t *sss = (soa_static_session_t *)ss;
|
||||
|
||||
char c_address[64];
|
||||
sdp_session_t *local = ss->ss_local->ssd_sdp;
|
||||
sdp_session_t local0[1];
|
||||
@ -922,6 +1088,8 @@ static int offer_answer_step(soa_session_t *ss,
|
||||
sdp_connection_t *c, c0[1] = {{ sizeof(c0) }};
|
||||
sdp_time_t t[1] = {{ sizeof(t) }};
|
||||
|
||||
int *u2s = NULL, *s2u = NULL, *tbf;
|
||||
|
||||
char const *phrase = "Internal Media Error";
|
||||
|
||||
su_home_t tmphome[SU_HOME_AUTO_SIZE(8192)];
|
||||
@ -991,7 +1159,7 @@ static int offer_answer_step(soa_session_t *ss,
|
||||
*local0 = *local, local = local0;
|
||||
SU_DEBUG_7(("soa_static(%p, %s): %s\n", (void *)ss, by,
|
||||
"upgrade with local description"));
|
||||
soa_sdp_upgrade(ss, tmphome, local, user, user);
|
||||
soa_sdp_upgrade(ss, tmphome, local, user, NULL, &u2s, &s2u);
|
||||
break;
|
||||
case generate_answer:
|
||||
/* Upgrade local SDP based on remote SDP */
|
||||
@ -1003,7 +1171,7 @@ static int offer_answer_step(soa_session_t *ss,
|
||||
*local0 = *local, local = local0;
|
||||
SU_DEBUG_7(("soa_static(%p, %s): %s\n", (void *)ss, by,
|
||||
"upgrade with remote description"));
|
||||
soa_sdp_upgrade(ss, tmphome, local, user, remote);
|
||||
soa_sdp_upgrade(ss, tmphome, local, user, remote, &u2s, &s2u);
|
||||
}
|
||||
break;
|
||||
case process_answer:
|
||||
@ -1074,7 +1242,7 @@ static int offer_answer_step(soa_session_t *ss,
|
||||
*local0 = *local, local = local0;
|
||||
DUP_LOCAL(local);
|
||||
}
|
||||
soa_sdp_upgrade_rtpmaps(ss, local, remote);
|
||||
soa_sdp_session_upgrade_rtpmaps(ss, local, remote);
|
||||
}
|
||||
break;
|
||||
case generate_offer:
|
||||
@ -1125,9 +1293,16 @@ static int offer_answer_step(soa_session_t *ss,
|
||||
|
||||
soa_description_free(ss, ss->ss_previous);
|
||||
|
||||
if (u2s) {
|
||||
u2s = u2s_alloc(ss->ss_home, u2s);
|
||||
s2u = u2s_alloc(ss->ss_home, s2u);
|
||||
if (!u2s || !s2u)
|
||||
goto internal_error;
|
||||
}
|
||||
|
||||
if (ss->ss_local->ssd_sdp != local &&
|
||||
sdp_session_cmp(ss->ss_local->ssd_sdp, local)) {
|
||||
/* We have modfied local session: update origin-line */
|
||||
/* We have modified local session: update origin-line */
|
||||
if (local->sdp_origin != o)
|
||||
*o = *local->sdp_origin, local->sdp_origin = o;
|
||||
o->o_version++;
|
||||
@ -1151,10 +1326,24 @@ static int offer_answer_step(soa_session_t *ss,
|
||||
|
||||
/* Update the unparsed and pretty-printed descriptions */
|
||||
if (soa_description_set(ss, ss->ss_local, local, NULL, 0) < 0) {
|
||||
if (action == generate_offer) {
|
||||
/* Remove 2nd reference to local session state */
|
||||
memset(ss->ss_previous, 0, (sizeof *ss->ss_previous));
|
||||
ss->ss_previous_user_version = 0;
|
||||
ss->ss_previous_remote_version = 0;
|
||||
}
|
||||
|
||||
su_free(ss->ss_home, u2s), su_free(ss->ss_home, s2u);
|
||||
|
||||
goto internal_error;
|
||||
}
|
||||
}
|
||||
|
||||
if (u2s) {
|
||||
tbf = sss->sss_u2s, sss->sss_u2s = u2s, su_free(ss->ss_home, tbf);
|
||||
tbf = sss->sss_s2u, sss->sss_s2u = s2u, su_free(ss->ss_home, tbf);
|
||||
}
|
||||
|
||||
/* Update version numbers */
|
||||
switch (action) {
|
||||
case generate_offer:
|
||||
|
@ -604,3 +604,32 @@ tag_typedef_t soatag_srtp_integrity = BOOLTAG_TYPEDEF(srtp_integrity);
|
||||
* @sa soa_set_params(), nua_invite(), @ref nua_event_diagram_call_hold
|
||||
*/
|
||||
tag_typedef_t soatag_hold = STRTAG_TYPEDEF(hold);
|
||||
|
||||
|
||||
/**@def SOATAG_ORDERED_USER(x)
|
||||
*
|
||||
* Take account strict ordering of user SDP m=lines. If user SDP has been
|
||||
* updated, the new media lines replace old ones even if the media type has
|
||||
* been changed. This allows the application to replace @b m=audio with
|
||||
* @b m=image/t38, for instance.
|
||||
*
|
||||
* @par Used with
|
||||
* soa_set_params(), soa_get_params(), soa_get_paramlist() \n
|
||||
*
|
||||
* @par Parameter type
|
||||
* boolean
|
||||
*
|
||||
* @par Values
|
||||
* - false (0) - update session with user SDP based on media type
|
||||
* - true (1) - update session with m= line in user SDP based on their order
|
||||
*
|
||||
* The default value is false and session are updated based on media types.
|
||||
*
|
||||
*
|
||||
* Corresponding tag taking a reference parameter is SOATAG_RTP_SELECT_REF().
|
||||
*
|
||||
* @sa @RFC3264 section 8.3.3, T.38
|
||||
*/
|
||||
tag_typedef_t soatag_ordered_user = BOOLTAG_TYPEDEF(ordered_user);
|
||||
|
||||
tag_typedef_t soatag_reuse_rejected = BOOLTAG_TYPEDEF(reuse_rejected);
|
||||
|
@ -244,6 +244,20 @@ SOFIAPUBVAR tag_typedef_t soatag_hold;
|
||||
#define SOATAG_HOLD_REF(x) soatag_hold_ref, tag_str_vr(&(x))
|
||||
SOFIAPUBVAR tag_typedef_t soatag_hold_ref;
|
||||
|
||||
#define SOATAG_ORDERED_USER(x) soatag_ordered_user, tag_bool_v(x)
|
||||
SOFIAPUBVAR tag_typedef_t soatag_ordered_user;
|
||||
|
||||
#define SOATAG_ORDERED_USER_REF(x) \
|
||||
soatag_ordered_user_ref, tag_bool_vr(&(x))
|
||||
SOFIAPUBVAR tag_typedef_t soatag_ordered_user_ref;
|
||||
|
||||
#define SOATAG_REUSE_REJECTED(x) soatag_reuse_rejected, tag_bool_v(x)
|
||||
SOFIAPUBVAR tag_typedef_t soatag_reuse_rejected;
|
||||
|
||||
#define SOATAG_REUSE_REJECTED_REF(x) \
|
||||
soatag_reuse_rejected_ref, tag_bool_vr(&(x))
|
||||
SOFIAPUBVAR tag_typedef_t soatag_reuse_rejected_ref;
|
||||
|
||||
SOFIA_END_DECLS
|
||||
|
||||
#endif /* SOA_TAG_H */
|
||||
|
@ -519,7 +519,7 @@ int test_static_offer_answer(struct context *ctx)
|
||||
/* 'B' will reject. */
|
||||
TEST(soa_set_params(a,
|
||||
SOATAG_HOLD(NULL), /* 'A' will release hold. */
|
||||
SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8\r\n"
|
||||
SOATAG_USER_SDP_STR("m=audio 5008 RTP/AVP 0 8\r\ni=x\r\n"
|
||||
"m=video 5006 RTP/AVP 34\r\n"),
|
||||
TAG_END()), 2);
|
||||
|
||||
@ -663,7 +663,7 @@ int test_codec_selection(struct context *ctx)
|
||||
TEST_1(m = b_sdp->sdp_media); TEST_1(m->m_rejected);
|
||||
TEST_1(rm = m->m_rtpmaps); TEST(rm->rm_pt, 96);
|
||||
TEST_S(rm->rm_encoding, "G7231");
|
||||
/* Not using payload type 97 from offer */
|
||||
/* Not reusing payload type 97 from offer */
|
||||
TEST_1(rm = rm->rm_next); TEST(rm->rm_pt, 98);
|
||||
TEST_S(rm->rm_encoding, "G729");
|
||||
TEST_1(!rm->rm_next);
|
||||
@ -1141,6 +1141,128 @@ int test_codec_selection(struct context *ctx)
|
||||
END();
|
||||
}
|
||||
|
||||
int test_media_replace(struct context *ctx)
|
||||
{
|
||||
BEGIN();
|
||||
int n;
|
||||
|
||||
soa_session_t *a, *b;
|
||||
|
||||
char const *offer = NONE, *answer = NONE;
|
||||
isize_t offerlen = (isize_t)-1, answerlen = (isize_t)-1;
|
||||
|
||||
sdp_session_t const *a_sdp, *b_sdp;
|
||||
sdp_media_t const *m;
|
||||
|
||||
char const a_caps[] =
|
||||
"v=0\r\n"
|
||||
"o=left 219498671 2 IN IP4 127.0.0.2\r\n"
|
||||
"c=IN IP4 127.0.0.2\r\n"
|
||||
"m=audio 5008 RTP/AVP 0 8\r\n"
|
||||
;
|
||||
|
||||
char const b_caps[] =
|
||||
"m=audio 5004 RTP/AVP 0 8\n"
|
||||
"a=rtpmap:96 G7231/8000\n"
|
||||
"a=rtpmap:97 G729/8000\n"
|
||||
"m=image 5556 UDPTL t38\r\n"
|
||||
"a=T38FaxVersion:0\r\n"
|
||||
"a=T38MaxBitRate:9600\r\n"
|
||||
"a=T38FaxFillBitRemoval:0\r\n"
|
||||
"a=T38FaxTranscodingMMR:0\r\n"
|
||||
"a=T38FaxTranscodingJBIG:0\r\n"
|
||||
"a=T38FaxRateManagement:transferredTCF\r\n"
|
||||
"a=T38FaxMaxDatagram:400\r\n";
|
||||
|
||||
TEST_1(a = soa_create("static", ctx->root, ctx));
|
||||
TEST_1(b = soa_create("static", ctx->root, ctx));
|
||||
|
||||
TEST(soa_set_user_sdp(a, 0, a_caps, strlen(a_caps)), 1);
|
||||
TEST(soa_set_user_sdp(b, 0, b_caps, strlen(b_caps)), 1);
|
||||
|
||||
n = soa_generate_offer(a, 1, test_completed); TEST(n, 0);
|
||||
n = soa_get_local_sdp(a, NULL, &offer, &offerlen); TEST(n, 1);
|
||||
TEST_1(offer != NULL && offer != NONE);
|
||||
n = soa_set_remote_sdp(b, 0, offer, offerlen); TEST(n, 1);
|
||||
n = soa_get_local_sdp(b, NULL, &answer, &answerlen); TEST(n, 0);
|
||||
n = soa_generate_answer(b, test_completed); TEST(n, 0);
|
||||
n = soa_get_local_sdp(b, &b_sdp, &answer, &answerlen); TEST(n, 1);
|
||||
TEST_1(answer != NULL && answer != NONE);
|
||||
n = soa_set_remote_sdp(a, 0, answer, -1); TEST(n, 1);
|
||||
n = soa_process_answer(a, test_completed); TEST(n, 0);
|
||||
|
||||
TEST_1(soa_is_complete(b));
|
||||
TEST(soa_activate(b, NULL), 0);
|
||||
|
||||
TEST_1(soa_is_complete(a));
|
||||
TEST(soa_activate(a, NULL), 0);
|
||||
|
||||
TEST(soa_is_audio_active(a), SOA_ACTIVE_SENDRECV);
|
||||
TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_SENDRECV);
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
/* Re-O/A: replace media stream */
|
||||
|
||||
/* Accept media without common codecs */
|
||||
TEST_1(soa_set_params(a, SOATAG_RTP_MISMATCH(0),
|
||||
SOATAG_ORDERED_USER(1),
|
||||
SOATAG_USER_SDP_STR(
|
||||
"v=0\r\n"
|
||||
"o=left 219498671 2 IN IP4 127.0.0.2\r\n"
|
||||
"c=IN IP4 127.0.0.2\r\n"
|
||||
"m=image 16384 UDPTL t38\r\n"
|
||||
"a=T38FaxVersion:0\r\n"
|
||||
"a=T38MaxBitRate:9600\r\n"
|
||||
"a=T38FaxFillBitRemoval:0\r\n"
|
||||
"a=T38FaxTranscodingMMR:0\r\n"
|
||||
"a=T38FaxTranscodingJBIG:0\r\n"
|
||||
"a=T38FaxRateManagement:transferredTCF\r\n"
|
||||
"a=T38FaxMaxDatagram:400\r\n"
|
||||
),
|
||||
TAG_END()));
|
||||
|
||||
n = soa_generate_offer(a, 1, test_completed); TEST(n, 0);
|
||||
n = soa_get_local_sdp(a, &a_sdp, &offer, &offerlen); TEST(n, 1);
|
||||
TEST_1(offer != NULL && offer != NONE);
|
||||
n = soa_set_remote_sdp(b, 0, offer, offerlen); TEST(n, 1);
|
||||
n = soa_generate_answer(b, test_completed); TEST(n, 0);
|
||||
n = soa_get_local_sdp(b, &b_sdp, &answer, &answerlen); TEST(n, 1);
|
||||
TEST_1(answer != NULL && answer != NONE);
|
||||
n = soa_set_remote_sdp(a, 0, answer, -1); TEST(n, 1);
|
||||
n = soa_process_answer(a, test_completed); TEST(n, 0);
|
||||
n = soa_get_local_sdp(a, &a_sdp, NULL, NULL); TEST(n, 1);
|
||||
|
||||
TEST_1(soa_is_complete(b));
|
||||
TEST(soa_activate(b, NULL), 0);
|
||||
|
||||
TEST_1(soa_is_complete(a));
|
||||
TEST(soa_activate(a, NULL), 0);
|
||||
|
||||
TEST_1(m = a_sdp->sdp_media); TEST_1(!m->m_rejected);
|
||||
TEST(m->m_type, sdp_media_image);
|
||||
TEST(m->m_proto, sdp_proto_udptl);
|
||||
TEST_1(m->m_format);
|
||||
TEST_S(m->m_format->l_text, "t38");
|
||||
|
||||
TEST_1(m = b_sdp->sdp_media); TEST_1(!m->m_rejected);
|
||||
TEST(m->m_type, sdp_media_image);
|
||||
TEST(m->m_proto, sdp_proto_udptl);
|
||||
TEST_1(m->m_format);
|
||||
TEST_S(m->m_format->l_text, "t38");
|
||||
|
||||
TEST(soa_is_audio_active(a), SOA_ACTIVE_DISABLED);
|
||||
TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_DISABLED);
|
||||
|
||||
TEST_VOID(soa_terminate(a, NULL));
|
||||
TEST_VOID(soa_terminate(b, NULL));
|
||||
|
||||
TEST_VOID(soa_destroy(a));
|
||||
TEST_VOID(soa_destroy(b));
|
||||
|
||||
END();
|
||||
}
|
||||
|
||||
|
||||
int test_asynch_offer_answer(struct context *ctx)
|
||||
{
|
||||
@ -1332,6 +1454,7 @@ int main(int argc, char *argv[])
|
||||
retval |= test_params(ctx); SINGLE_FAILURE_CHECK();
|
||||
retval |= test_static_offer_answer(ctx); SINGLE_FAILURE_CHECK();
|
||||
retval |= test_codec_selection(ctx); SINGLE_FAILURE_CHECK();
|
||||
retval |= test_media_replace(ctx); SINGLE_FAILURE_CHECK();
|
||||
|
||||
retval |= test_asynch_offer_answer(ctx); SINGLE_FAILURE_CHECK();
|
||||
}
|
||||
|
@ -88,6 +88,9 @@
|
||||
/** Define as suitable declarator static inline functions */
|
||||
#undef su_inline
|
||||
|
||||
/** Define as 1 the tag value casts use inlined functions */
|
||||
#undef SU_INLINE_TAG_CAST
|
||||
|
||||
/** Define this as 1 if we can use tags directly from stack. */
|
||||
#undef SU_HAVE_TAGSTACK
|
||||
|
||||
|
@ -171,7 +171,7 @@ SOFIAPUBFUN void tl_vfree(tagi_t *t);
|
||||
#define SU_ALIGN(x) \
|
||||
((sizeof(void *) - ((intptr_t)(x) & (sizeof(void *) - 1))) & (sizeof(void *) - 1))
|
||||
|
||||
#if SU_HAVE_INLINE
|
||||
#if SU_INLINE_TAG_CAST
|
||||
su_inline tag_value_t tag_int_v(int v) { return (tag_value_t)v; }
|
||||
su_inline tag_value_t tag_int_vr(int *vp) { return (tag_value_t)vp; }
|
||||
su_inline tag_value_t tag_uint_v(unsigned v) { return (tag_value_t)v; }
|
||||
|
@ -48,7 +48,7 @@ SOFIA_BEGIN_DECLS
|
||||
|
||||
SOFIAPUBFUN void tl_print(FILE *f, char const *title, tagi_t const lst[]);
|
||||
|
||||
#if SU_HAVE_INLINE
|
||||
#if SU_INLINE_TAG_CAST
|
||||
su_inline tag_value_t tag_socket_v(su_socket_t v) {
|
||||
return (tag_value_t)v;
|
||||
}
|
||||
|
@ -51,14 +51,18 @@
|
||||
#endif
|
||||
|
||||
int su_socket_close_on_exec = 0;
|
||||
int su_socket_blocking = 0;
|
||||
|
||||
/** Create an endpoint for communication. */
|
||||
su_socket_t su_socket(int af, int socktype, int proto)
|
||||
{
|
||||
su_socket_t s = socket(af, socktype, proto);
|
||||
#if SU_HAVE_BSDSOCK
|
||||
if (s != INVALID_SOCKET && su_socket_close_on_exec) {
|
||||
fcntl(s, F_SETFD, FD_CLOEXEC); /* Close on exec */
|
||||
if (s != INVALID_SOCKET) {
|
||||
if (su_socket_close_on_exec)
|
||||
fcntl(s, F_SETFD, FD_CLOEXEC); /* Close on exec */
|
||||
if (!su_socket_blocking) /* All sockets are born blocking */
|
||||
su_setblocking(s, 0);
|
||||
}
|
||||
#endif
|
||||
return s;
|
||||
|
@ -540,7 +540,6 @@ int su_base_port_start_shared(su_root_t *parent,
|
||||
init(child, magic) == 0)
|
||||
return 0;
|
||||
|
||||
deinit(child, magic);
|
||||
su_msg_destroy(return_clone);
|
||||
su_root_destroy(child);
|
||||
return -1;
|
||||
|
@ -204,6 +204,8 @@ int test_sendrecv(void)
|
||||
|
||||
TEST(getsockname(l, &su.su_sa, &sulen), 0);
|
||||
TEST(listen(l, 5), 0);
|
||||
|
||||
TEST(su_setblocking(s, 1), 0);
|
||||
|
||||
TEST(connect(s, &su.su_sa, sulen), 0);
|
||||
a = accept(l, &csu.su_sa, &csulen); TEST_1(a != -1);
|
||||
|
@ -279,6 +279,9 @@ TPORT_DLL int tport_is_shutdown(tport_t const *self);
|
||||
/** Test if transport is connected. @NEW_1_12_5 */
|
||||
TPORT_DLL int tport_is_connected(tport_t const *self);
|
||||
|
||||
/** Test if transport can be used to send message. @NEW_1_12_7 */
|
||||
TPORT_DLL int tport_is_clear_to_send(tport_t const *self);
|
||||
|
||||
/** Set transport magic. */
|
||||
TPORT_DLL void tport_set_magic(tport_t *self, tp_magic_t *magic);
|
||||
|
||||
|
@ -403,7 +403,7 @@ TPORT_DLL extern tag_typedef_t tptag_log;
|
||||
* Use with tport_tcreate(), nua_create(), nta_agent_create(),
|
||||
* nth_engine_create(), or initial nth_site_create().
|
||||
*
|
||||
* @sa #TPORT_DUMP, TPTAG_DUMP()
|
||||
* @sa #TPORT_LOG environment variable, TPTAG_DUMP()
|
||||
*
|
||||
* @NEW_1_12_5
|
||||
*/
|
||||
@ -418,7 +418,7 @@ TPORT_DLL extern tag_typedef_t tptag_dump;
|
||||
* Use with tport_tcreate(), nta_agent_create(), nua_create(),
|
||||
* nth_engine_create(), or initial nth_site_create().
|
||||
*
|
||||
* @sa #TPORT_DUMP, TPTAG_LOG().
|
||||
* @sa #TPORT_DUMP environment variable, TPTAG_LOG().
|
||||
*
|
||||
* @NEW_1_12_5
|
||||
*/
|
||||
|
@ -166,7 +166,7 @@ int tport_is_secondary(tport_t const *self)
|
||||
self->tp_pri->pri_primary != self;
|
||||
}
|
||||
|
||||
/** Test if transport has been registered */
|
||||
/** Test if transport has been registered to su_root_t */
|
||||
int tport_is_registered(tport_t const *self)
|
||||
{
|
||||
return self->tp_index != 0;
|
||||
@ -291,6 +291,19 @@ int tport_is_connected(tport_t const *self)
|
||||
return self->tp_is_connected;
|
||||
}
|
||||
|
||||
/** Test if transport can be used to send message. @NEW_1_12_7 */
|
||||
int tport_is_clear_to_send(tport_t const *self)
|
||||
{
|
||||
return
|
||||
tport_is_master(self) ||
|
||||
tport_is_primary(self) ||
|
||||
(tport_is_secondary(self) &&
|
||||
tport_is_registered(self) &&
|
||||
self->tp_reusable &&
|
||||
!self->tp_closed &&
|
||||
!self->tp_send_close);
|
||||
}
|
||||
|
||||
/** MTU for transport */
|
||||
su_inline unsigned tport_mtu(tport_t const *self)
|
||||
{
|
||||
@ -1164,7 +1177,7 @@ int tport_set_params(tport_t *self,
|
||||
if (self == NULL)
|
||||
return su_seterrno(EINVAL);
|
||||
|
||||
memcpy(tpp, tpp0 = self->tp_params, sizeof *tpp);
|
||||
memcpy(tpp, tpp0 = self->tp_params, sizeof tpp);
|
||||
|
||||
mtu = tpp->tpp_mtu;
|
||||
connect = tpp->tpp_conn_orient;
|
||||
@ -1220,9 +1233,10 @@ int tport_set_params(tport_t *self,
|
||||
if (tport_is_secondary(self) &&
|
||||
self->tp_params == self->tp_pri->pri_primary->tp_params) {
|
||||
tpp0 = su_zalloc(self->tp_home, sizeof *tpp0); if (!tpp0) return -1;
|
||||
self->tp_params = tpp0;
|
||||
}
|
||||
|
||||
memcpy(tpp0, tpp, sizeof *tpp);
|
||||
memcpy(tpp0, tpp, sizeof tpp);
|
||||
|
||||
return n;
|
||||
}
|
||||
@ -1963,7 +1977,7 @@ int tport_addrinfo_copy(su_addrinfo_t *dst, void *addr, socklen_t addrlen,
|
||||
*/
|
||||
void tport_close(tport_t *self)
|
||||
{
|
||||
SU_DEBUG_5(("%s(%p): " TPN_FORMAT "\n", "tport_close", (void *)self,
|
||||
SU_DEBUG_5(("%s(%p): " TPN_FORMAT "\n", "tport_close", (void *)self,
|
||||
TPN_ARGS(self->tp_name)));
|
||||
|
||||
self->tp_closed = 1;
|
||||
@ -2360,6 +2374,7 @@ void tport_error_report(tport_t *self, int errcode,
|
||||
else if (errcode > 0)
|
||||
errmsg = su_strerror(errcode);
|
||||
else
|
||||
/* Should be something like ENOTCONN */
|
||||
errcode = 0, errmsg = "stream closed";
|
||||
|
||||
if (addr && addr->su_family == AF_UNSPEC)
|
||||
@ -2369,12 +2384,12 @@ void tport_error_report(tport_t *self, int errcode,
|
||||
if (errcode > 0 && tport_has_connection(self))
|
||||
self->tp_reusable = 0;
|
||||
|
||||
if (addr == NULL && tport_is_connection_oriented(self))
|
||||
addr = self->tp_addr;
|
||||
|
||||
/* Report error */
|
||||
if (addr && tport_pending_error(self, addr, errcode))
|
||||
;
|
||||
else if (tport_is_secondary(self) &&
|
||||
tport_pending_error(self, NULL, errcode) > 0)
|
||||
;
|
||||
else if (self->tp_master->mr_tpac->tpac_error) {
|
||||
char *dstname = NULL;
|
||||
char hp[TPORT_HOSTPORTSIZE];
|
||||
@ -3070,30 +3085,24 @@ tport_t *tport_tsend(tport_t *self,
|
||||
/* Select a primary protocol, make a fresh connection */
|
||||
self = primary->pri_primary;
|
||||
}
|
||||
else if (tport_is_secondary(self) && tport_is_clear_to_send(self)) {
|
||||
self = self;
|
||||
}
|
||||
/*
|
||||
* Try to find an already open connection to the destination,
|
||||
* or get a primary protocol
|
||||
*/
|
||||
else {
|
||||
if (tport_is_secondary(self) &&
|
||||
tport_is_registered(self) &&
|
||||
self->tp_reusable &&
|
||||
!self->tp_closed &&
|
||||
!self->tp_send_close) {
|
||||
self = self;
|
||||
/* If primary, resolve the destination address, store it in the msg */
|
||||
if (tport_resolve(primary->pri_primary, msg, tpn) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
* Try to find an already open connection to the destination,
|
||||
* or get a primary protocol
|
||||
*/
|
||||
else {
|
||||
/* If primary, resolve the destination address, store it in the msg */
|
||||
if (tport_resolve(primary->pri_primary, msg, tpn) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
resolved = 1;
|
||||
resolved = 1;
|
||||
|
||||
self = tport_by_addrinfo(primary, msg_addrinfo(msg), tpn);
|
||||
|
||||
self = tport_by_addrinfo(primary, msg_addrinfo(msg), tpn);
|
||||
|
||||
if (!self)
|
||||
self = primary->pri_primary;
|
||||
}
|
||||
if (!self)
|
||||
self = primary->pri_primary;
|
||||
}
|
||||
|
||||
if (tport_is_primary(self)) {
|
||||
@ -3878,9 +3887,12 @@ int tport_pend(tport_t *self,
|
||||
{
|
||||
tport_pending_t *pending;
|
||||
|
||||
if (self == NULL || msg == NULL || callback == NULL || client == NULL)
|
||||
if (self == NULL || callback == NULL || client == NULL)
|
||||
return -1;
|
||||
|
||||
|
||||
if (msg == NULL && tport_is_primary(self))
|
||||
return -1;
|
||||
|
||||
SU_DEBUG_7(("tport_pend(%p): pending %p for %s/%s:%s (already %u)\n",
|
||||
(void *)self, (void *)msg,
|
||||
self->tp_protoname, self->tp_host, self->tp_port,
|
||||
@ -3930,7 +3942,7 @@ int tport_release(tport_t *self,
|
||||
{
|
||||
tport_pending_t *pending;
|
||||
|
||||
if (self == NULL || msg == NULL || pendd <= 0 || pendd > (int)self->tp_plen)
|
||||
if (self == NULL || pendd <= 0 || pendd > (int)self->tp_plen)
|
||||
return su_seterrno(EINVAL), -1;
|
||||
|
||||
pending = self->tp_pending + (pendd - 1);
|
||||
@ -3968,7 +3980,7 @@ tport_pending_error(tport_t *self, su_sockaddr_t const *dst, int error)
|
||||
msg_t *msg;
|
||||
su_addrinfo_t const *ai;
|
||||
|
||||
assert(self); assert(dst);
|
||||
assert(self);
|
||||
|
||||
callbacks = 0;
|
||||
reported = ++self->tp_reported;
|
||||
@ -3979,22 +3991,25 @@ tport_pending_error(tport_t *self, su_sockaddr_t const *dst, int error)
|
||||
for (i = 0; i < self->tp_plen; i++) {
|
||||
pending = self->tp_pending + i;
|
||||
|
||||
if (!pending->p_callback || !pending->p_msg)
|
||||
if (!pending->p_callback)
|
||||
continue;
|
||||
|
||||
if (pending->p_reported == reported)
|
||||
continue;
|
||||
|
||||
msg = pending->p_msg;
|
||||
ai = msg_addrinfo(msg);
|
||||
|
||||
if (su_cmp_sockaddr(dst, (su_sockaddr_t *)ai->ai_addr) != 0)
|
||||
continue;
|
||||
if (dst && msg) {
|
||||
ai = msg_addrinfo(msg);
|
||||
|
||||
pending->p_reported = reported;
|
||||
if (su_cmp_sockaddr(dst, (su_sockaddr_t *)ai->ai_addr) != 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
msg_set_errno(msg, error);
|
||||
|
||||
pending->p_reported = reported;
|
||||
|
||||
pending->p_callback(self->TP_STACK, pending->p_client, self, msg, error);
|
||||
|
||||
callbacks++;
|
||||
|
@ -252,9 +252,9 @@ int tport_recv_stream(tport_t *self)
|
||||
tport_dump_iovec(self, msg, n, iovec, veclen, "recv", "from");
|
||||
|
||||
/* Mark buffer as used */
|
||||
msg_recv_commit(msg, n, 0);
|
||||
msg_recv_commit(msg, n, n == 0);
|
||||
|
||||
return 1;
|
||||
return n != 0;
|
||||
}
|
||||
|
||||
ssize_t tport_send_stream(tport_t const *self, msg_t *msg,
|
||||
|
@ -214,6 +214,15 @@ int test_any(void)
|
||||
TEST_S(u->url_fragment, "foo");
|
||||
}
|
||||
|
||||
{
|
||||
url_t u[1];
|
||||
char b2[6] = "";
|
||||
|
||||
memset(u, 0xff, sizeof u);
|
||||
TEST(url_d(u, b2), 0);
|
||||
TEST(u->url_type, url_unknown);
|
||||
}
|
||||
|
||||
su_home_deinit(home);
|
||||
|
||||
END();
|
||||
|
@ -2,11 +2,11 @@ dnl ======================================================================
|
||||
dnl su module
|
||||
dnl ======================================================================
|
||||
|
||||
AC_DEFUN([SAC_SU])
|
||||
|
||||
AC_DEFUN([SAC_SOFIA_SU], [
|
||||
# Beginning of SAC_SOFIA_SU
|
||||
|
||||
AC_REQUIRE([SAC_WITH_RT])
|
||||
|
||||
# ======================================================================
|
||||
# Check for features used by su
|
||||
|
||||
@ -66,6 +66,16 @@ AC_REQUIRE([AC_C_MACRO_FUNCTION])
|
||||
|
||||
AC_REQUIRE([AC_C_INLINE])
|
||||
|
||||
AC_ARG_ENABLE(tag-cast,
|
||||
[ --disable-tag-cast cast tag values with inlined functions [[enabled]]],
|
||||
, enable_tag_cast=yes)
|
||||
|
||||
if test "$enable_tag_cast" = "yes"; then
|
||||
tag_cast=1
|
||||
else
|
||||
tag_cast=0
|
||||
fi
|
||||
|
||||
case "$ac_cv_c_inline" in
|
||||
yes) SAC_SU_DEFINE(su_inline, static inline, [
|
||||
Define to declarator for static inline functions.
|
||||
@ -76,15 +86,20 @@ case "$ac_cv_c_inline" in
|
||||
SAC_SU_DEFINE(SU_HAVE_INLINE, 1, [
|
||||
Define to 1 if you have inline functions.
|
||||
])dnl
|
||||
SAC_SU_DEFINE_UNQUOTED(SU_INLINE_TAG_CAST, $tag_cast, [
|
||||
Define to 1 if you use inline function to cast tag values.
|
||||
])dnl
|
||||
;;
|
||||
no | "" )
|
||||
SAC_SU_DEFINE(su_inline, static)dnl
|
||||
SAC_SU_DEFINE(SU_INLINE, /*inline*/)dnl
|
||||
SAC_SU_DEFINE(SU_HAVE_INLINE, 0)dnl
|
||||
SAC_SU_DEFINE(SU_INLINE_TAG_CAST, 0)dnl
|
||||
;;
|
||||
*) SAC_SU_DEFINE_UNQUOTED(su_inline, static $ac_cv_c_inline)dnl
|
||||
SAC_SU_DEFINE_UNQUOTED(SU_INLINE, $ac_cv_c_inline)dnl
|
||||
SAC_SU_DEFINE(SU_HAVE_INLINE, 1)dnl
|
||||
SAC_SU_DEFINE_UNQUOTED(SU_INLINE_TAG_CAST, $tag_cast)dnl
|
||||
;;
|
||||
esac
|
||||
|
||||
@ -368,7 +383,15 @@ fi
|
||||
# Checks for libraries
|
||||
# ===========================================================================
|
||||
|
||||
SAC_CHECK_SU_LIBS
|
||||
AC_CHECK_LIB(pthread, pthread_create)
|
||||
AC_CHECK_LIB(socket, socketpair,,,-lnsl)
|
||||
|
||||
AC_ARG_WITH(rt,
|
||||
[ --with-rt use POSIX realtime library [[used by default]]])
|
||||
if test "${with_rt}" != no; then
|
||||
AC_SEARCH_LIBS(clock_gettime, rt)
|
||||
AC_CHECK_FUNCS([clock_gettime clock_getcpuclockid])
|
||||
fi
|
||||
|
||||
# No GLib path explicitly defined, use pkg-config
|
||||
AC_ARG_WITH(glib,
|
||||
@ -470,11 +493,6 @@ if test $ac_cv_func_if_nameindex = yes ; then
|
||||
[Define to 1 if you have if_nameindex().])
|
||||
fi
|
||||
|
||||
AC_REQUIRE([SAC_WITH_RT])
|
||||
if test "${with_rt}" != no; then
|
||||
AC_CHECK_FUNCS([clock_gettime clock_getcpuclockid])
|
||||
fi
|
||||
|
||||
SAC_REPLACE_FUNCS([memmem memccpy memspn memcspn strcasestr strtoull \
|
||||
inet_ntop inet_pton poll])
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user