[commit] r5413 - in freeswitch/trunk/libs/sofia-sip: . libsofia-sip-ua/docs libsofia-sip-ua/http/sofia-sip libsofia-sip-ua/iptsec/sofia-sip libsofia-sip-ua/msg libsofia-sip-ua/nta libsofia-sip-ua/nth libsofia-sip-ua/nth/sofia-sip libsofia-sip-ua/nua libsofia-sip-ua/nua/sofia-sip libsofia-sip-ua/sip libsofia-sip-ua/sip/sofia-sip libsofia-sip-ua/soa libsofia-sip-ua/soa/sofia-sip libsofia-sip-ua/su libsofia-sip-ua/su/sofia-sip libsofia-sip-ua/tport libsofia-sip-ua/tport/sofia-sip libsofia-si
Author: mikej Date: Wed Jun 20 06:41:15 2007 New Revision: 5413 Modified: freeswitch/trunk/libs/sofia-sip/Makefile.am freeswitch/trunk/libs/sofia-sip/RELEASE freeswitch/trunk/libs/sofia-sip/configure.ac freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/hide_emails.sh freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_tag.h.in freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_module.h freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_parser.c freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/test_msg.c freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta.c freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta_internal.h freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/sofia-sip/nth_tag.h freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/test_nth.c freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua.c freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_message.c freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_register.c freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_subnotref.c freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua_tag.h freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_100rel.c freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_basic_call.c freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_call_reject.c freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_cancel_bye.c freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_init.c freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nua.c freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nua.h freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_ops.c freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.c freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.h freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_refer.c freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_register.c freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_simple.c freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_sip_events.c freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_basic.c freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_tag.h.in freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/torture_sip.c freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa_static.c freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa_tag.c freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_tag.h freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/test_soa.c freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_configure.h.in freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag.h freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag_io.h freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su.c freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_base_port.c freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su.c freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport.h freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport_tag.h freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport.c freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tcp.c freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/torture_url.c freeswitch/trunk/libs/sofia-sip/m4/sac-su2.m4 Log: 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 Modified: freeswitch/trunk/libs/sofia-sip/Makefile.am ============================================================================== --- freeswitch/trunk/libs/sofia-sip/Makefile.am (original) +++ freeswitch/trunk/libs/sofia-sip/Makefile.am Wed Jun 20 06:41:15 2007 @@ -24,7 +24,7 @@ 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 \ Modified: freeswitch/trunk/libs/sofia-sip/RELEASE ============================================================================== --- freeswitch/trunk/libs/sofia-sip/RELEASE (original) +++ freeswitch/trunk/libs/sofia-sip/RELEASE Wed Jun 20 06:41:15 2007 @@ -24,6 +24,9 @@ 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 Modified: freeswitch/trunk/libs/sofia-sip/configure.ac ============================================================================== --- freeswitch/trunk/libs/sofia-sip/configure.ac (original) +++ freeswitch/trunk/libs/sofia-sip/configure.ac Wed Jun 20 06:41:15 2007 @@ -69,7 +69,6 @@ SAC_SOFIA_SU SAC_OPENSSL SAC_TPORT -SAC_SU ### internal modules ### ---------------- Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/hide_emails.sh ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/hide_emails.sh (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/docs/hide_emails.sh Wed Jun 20 06:41:15 2007 @@ -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; +' Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_tag.h.in ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_tag.h.in (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http_tag.h.in Wed Jun 20 06:41:15 2007 @@ -102,7 +102,7 @@ #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 @@ #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 @@ #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; } Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_module.h ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_module.h (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_module.h Wed Jun 20 06:41:15 2007 @@ -253,7 +253,7 @@ #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; } Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_parser.c ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_parser.c (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/msg_parser.c Wed Jun 20 06:41:15 2007 @@ -1840,6 +1840,8 @@ return NULL; } + b = b2; + continue; } } Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/test_msg.c ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/test_msg.c (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/msg/test_msg.c Wed Jun 20 06:41:15 2007 @@ -797,7 +797,21 @@ { 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 @@ "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); Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta.c ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta.c (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta.c Wed Jun 20 06:41:15 2007 @@ -2198,7 +2198,8 @@ TPTAG_SDWN_AFTER(stream), TAG_END()); } - } else { + } + else { msg_destroy(msg); if (stream) /* Send FIN */ tport_shutdown(tport, 1); @@ -6172,13 +6173,6 @@ 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 @@ /* 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 @@ 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 @@ } +/** 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, Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta_internal.h ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta_internal.h (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nta/nta_internal.h Wed Jun 20 06:41:15 2007 @@ -504,6 +504,7 @@ 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 */ Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/sofia-sip/nth_tag.h ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/sofia-sip/nth_tag.h (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/sofia-sip/nth_tag.h Wed Jun 20 06:41:15 2007 @@ -101,7 +101,7 @@ 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_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) Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/test_nth.c ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/test_nth.c (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nth/test_nth.c Wed Jun 20 06:41:15 2007 @@ -570,6 +570,7 @@ 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); Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua.c ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua.c (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua.c Wed Jun 20 06:41:15 2007 @@ -1049,7 +1049,7 @@ /** 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 */ Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_message.c ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_message.c (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_message.c Wed Jun 20 06:41:15 2007 @@ -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. * Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_register.c ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_register.c (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_register.c Wed Jun 20 06:41:15 2007 @@ -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 @@ /** 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 @@ 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 @@ 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 @@ /* ======================================================================== */ /* 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ * @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); Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c Wed Jun 20 06:41:15 2007 @@ -1627,7 +1627,8 @@ * (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 @@ * #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 Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_subnotref.c ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_subnotref.c (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/nua_subnotref.c Wed Jun 20 06:41:15 2007 @@ -121,7 +121,9 @@ /* ====================================================================== */ /* 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 @@ * @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 @@ /* ======================================================================== */ /* 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. * Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua_tag.h ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua_tag.h (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua_tag.h Wed Jun 20 06:41:15 2007 @@ -166,7 +166,7 @@ * 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_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 Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_100rel.c ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_100rel.c (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_100rel.c Wed Jun 20 06:41:15 2007 @@ -128,7 +128,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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); Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_basic_call.c ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_basic_call.c (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_basic_call.c Wed Jun 20 06:41:15 2007 @@ -1100,7 +1100,7 @@ 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(); } Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_call_reject.c ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_call_reject.c (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_call_reject.c Wed Jun 20 06:41:15 2007 @@ -1520,7 +1520,7 @@ 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; } Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_cancel_bye.c ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_cancel_bye.c (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_cancel_bye.c Wed Jun 20 06:41:15 2007 @@ -1349,11 +1349,14 @@ 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 @@ |<----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 @@ 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(); } Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_init.c ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_init.c (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_init.c Wed Jun 20 06:41:15 2007 @@ -70,8 +70,9 @@ 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 @@ 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 @@ 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"), Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nua.c ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nua.c (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nua.c Wed Jun 20 06:41:15 2007 @@ -211,6 +211,18 @@ 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 @@ 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(); Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nua.h ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nua.h (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_nua.h Wed Jun 20 06:41:15 2007 @@ -124,6 +124,7 @@ 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 *ctx; /* Backpointer */ int logging; + int print_tags; int running; @@ -196,6 +198,9 @@ 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, \ Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_ops.c ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_ops.c (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_ops.c Wed Jun 20 06:41:15 2007 @@ -190,7 +190,8 @@ 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 @@ } } +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) Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.c ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.c (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.c Wed Jun 20 06:41:15 2007 @@ -53,6 +53,8 @@ #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 @@ 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 @@ 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 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 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 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 @@ 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 @@ 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_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 @@ 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 @@ 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 @@ 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 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 @@ 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 @@ 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 @@ 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 @@ *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 @@ } 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 @@ 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 @@ 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 @@ *bb = b, b->prev = bb, bb = &b->next; } + tport_unref(tport); + last = NULL; if (m == NULL) { @@ -1095,3 +1153,25 @@ 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; +} Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.h ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.h (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.h Wed Jun 20 06:41:15 2007 @@ -56,6 +56,8 @@ sip_time_t *return_session_expires, sip_time_t *return_min_se); +int test_proxy_close_tports(struct proxy *p); + SOFIA_END_DECLS #endif Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_refer.c ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_refer.c (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_refer.c Wed Jun 20 06:41:15 2007 @@ -113,7 +113,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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); Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_register.c ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_register.c (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_register.c Wed Jun 20 06:41:15 2007 @@ -200,6 +200,10 @@ 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 @@ 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"); Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_simple.c ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_simple.c (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_simple.c Wed Jun 20 06:41:15 2007 @@ -1194,7 +1194,7 @@ 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 @@ /* 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 @@ 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); Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_sip_events.c ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_sip_events.c (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/nua/test_sip_events.c Wed Jun 20 06:41:15 2007 @@ -89,9 +89,9 @@ 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 @@ /* 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 @@ 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 @@ 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 @@ 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); - } - 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 = e->next); } - 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 @@ /* 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 @@ 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); /* Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_basic.c ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_basic.c (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sip_basic.c Wed Jun 20 06:41:15 2007 @@ -718,6 +718,9 @@ * 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 */ Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_tag.h.in ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_tag.h.in (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_tag.h.in Wed Jun 20 06:41:15 2007 @@ -104,7 +104,7 @@ #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 @@ #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 @@ #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; } Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/torture_sip.c ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/torture_sip.c (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/sip/torture_sip.c Wed Jun 20 06:41:15 2007 @@ -405,6 +405,8 @@ 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); Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa_static.c ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa_static.c (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa_static.c Wed Jun 20 06:41:15 2007 @@ -80,9 +80,19 @@ { 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 @@ { 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 @@ 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 @@ 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 @@ 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 @@ } /** 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 @@ /** 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 @@ } /** 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 @@ 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; + + for (rm = anylist; rm; rm = rm->rm_next) { + /* Ignore auxiliary codecs */ + if (auxiliary && soa_sdp_is_auxiliary_codec(rm, auxiliary)) + continue; -/** 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) + 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 @@ * * @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 @@ * * @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 @@ 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 (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 (caps != upgrader) { + 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]; + + if (!m) { + int codec_mismatch = 0; + + if (!rm->m_rejected) + j = soa_sdp_matching_mindex(ss, u_media, rm, &codec_mismatch); + else + j = -1; + + 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; + } + + s_media[i] = m = u_media[j]; u_media[j] = SDP_MEDIA_NONE; + u2s[j] = i, s2u[i] = j; + } - m = soa_sdp_matching(ss, c_media, u_media[i], &common_codecs); + 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 (!m || u_media[i]->m_rejected) { - m = soa_sdp_make_rejected_media(home, u_media[i], session, 0); + 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); } - else if (sdp_media_uses_rtp(m)) { - /* Process rtpmaps */ - char const *auxiliary = - m->m_type == sdp_media_audio ? sss->sss_audio_aux : NULL; - - 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 (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); - } + 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; } - s_media[i] = m; + 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 @@ } *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 @@ } /** 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 @@ } /** 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 @@ /** 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 @@ 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 @@ 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 @@ *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 @@ *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 @@ *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 @@ 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 @@ /* 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: Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa_tag.c ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa_tag.c (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/soa_tag.c Wed Jun 20 06:41:15 2007 @@ -604,3 +604,32 @@ * @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); Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_tag.h ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_tag.h (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_tag.h Wed Jun 20 06:41:15 2007 @@ -244,6 +244,20 @@ #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 */ Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/test_soa.c ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/test_soa.c (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/soa/test_soa.c Wed Jun 20 06:41:15 2007 @@ -519,7 +519,7 @@ /* '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 @@ 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 @@ 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 @@ 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(); } Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_configure.h.in ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_configure.h.in (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_configure.h.in Wed Jun 20 06:41:15 2007 @@ -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 Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag.h ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag.h (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag.h Wed Jun 20 06:41:15 2007 @@ -171,7 +171,7 @@ #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; } Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag_io.h ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag_io.h (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag_io.h Wed Jun 20 06:41:15 2007 @@ -48,7 +48,7 @@ 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; } Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su.c ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su.c (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su.c Wed Jun 20 06:41:15 2007 @@ -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; Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_base_port.c ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_base_port.c (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/su_base_port.c Wed Jun 20 06:41:15 2007 @@ -540,7 +540,6 @@ init(child, magic) == 0) return 0; - deinit(child, magic); su_msg_destroy(return_clone); su_root_destroy(child); return -1; Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su.c ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su.c (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/su/torture_su.c Wed Jun 20 06:41:15 2007 @@ -204,6 +204,8 @@ 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); Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport.h ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport.h (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport.h Wed Jun 20 06:41:15 2007 @@ -279,6 +279,9 @@ /** 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); Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport_tag.h ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport_tag.h (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/sofia-sip/tport_tag.h Wed Jun 20 06:41:15 2007 @@ -403,7 +403,7 @@ * 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 @@ * 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 */ Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport.c ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport.c (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport.c Wed Jun 20 06:41:15 2007 @@ -166,7 +166,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ */ 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 @@ 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 @@ 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 @@ /* 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; - } - /* - * 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; - - self = tport_by_addrinfo(primary, msg_addrinfo(msg), tpn); - - if (!self) - self = primary->pri_primary; + /* If primary, resolve the destination address, store it in the msg */ + if (tport_resolve(primary->pri_primary, msg, tpn) < 0) { + return NULL; } + resolved = 1; + + self = tport_by_addrinfo(primary, msg_addrinfo(msg), tpn); + + if (!self) + self = primary->pri_primary; } if (tport_is_primary(self)) { @@ -3878,9 +3887,12 @@ { 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 @@ { 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 @@ msg_t *msg; su_addrinfo_t const *ai; - assert(self); assert(dst); + assert(self); callbacks = 0; reported = ++self->tp_reported; @@ -3979,22 +3991,25 @@ 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++; Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tcp.c ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tcp.c (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tcp.c Wed Jun 20 06:41:15 2007 @@ -252,9 +252,9 @@ 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, Modified: freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/torture_url.c ============================================================================== --- freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/torture_url.c (original) +++ freeswitch/trunk/libs/sofia-sip/libsofia-sip-ua/url/torture_url.c Wed Jun 20 06:41:15 2007 @@ -214,6 +214,15 @@ 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(); Modified: freeswitch/trunk/libs/sofia-sip/m4/sac-su2.m4 ============================================================================== --- freeswitch/trunk/libs/sofia-sip/m4/sac-su2.m4 (original) +++ freeswitch/trunk/libs/sofia-sip/m4/sac-su2.m4 Wed Jun 20 06:41:15 2007 @@ -2,11 +2,11 @@ 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_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 @@ 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 @@ # 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 @@ [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])
participants (1)
-
Freeswitch SVN