diff --git a/libs/sofia-sip/.update b/libs/sofia-sip/.update index 7af6d92225..ad1351a68e 100644 --- a/libs/sofia-sip/.update +++ b/libs/sofia-sip/.update @@ -1 +1 @@ -Tue Feb 13 11:08:00 EST 2007 +Thu Feb 15 00:08:41 EST 2007 diff --git a/libs/sofia-sip/RELEASE b/libs/sofia-sip/RELEASE index 41f09c83cf..611367c1e3 100644 --- a/libs/sofia-sip/RELEASE +++ b/libs/sofia-sip/RELEASE @@ -5,135 +5,69 @@ Release notes for current version of Sofia-SIP Changes since last release -------------------------- -Support for request queuing has been added to the high-level user-agent -API. Various portability improvements have been made related to Linux, -Mac OS X, Windows and Solaris ports. SIP registrations have been -modified to utilize persistent transport connections. The GObject -interface to 'nua' (nua-glib) has been dropped from the package and is -now distributed separately. Severe bugs in 'su', 'nua', 'nta', 'stun' and -'su-glib' modules have been fixed. + + +Bugs in blaa and foo have been fixed. The stack now supports +use of foobar... API/ABI changes and versioning ------------------------------ -New features in API are marked with Doxytag macro @NEW_1_12_5. -Experimental features are marked with Doxytag macro @EXP_1_12_5. + -**template**: New features in API are marked with Doxytag macro @NEW_1_XX_X. +**template**: New features in API are marked with Doxytag macro @VERSION_1_XX_X. libsofia-sip-ua: - **template**: Added foobar() function (sofia-sip/foobar.h). -- Added nua tags NUTAG_APPL_METHOD() and NUTAG_NEWSUB() -- Added nua_substate_make(), nua_substate_name() -- Added nta_incoming_create_response() function -- Added tport tags TPTAG_TOS(), TPTAG_DUMP(), TPTAG_LOG() -- Added tport predicate function tport_is_connected() -- Added authentication functions auc_info() and auc_has_authorization(), - added type msg_auth_info_t for Authentication-Info header -- Added msg_header_join_items() function -- Added sip_is_allowed() function and k_bitmap field to the - sip_allow_t structure -- Added sl_header_log implementation, updated its prototype -- Added experimental SIP headers Suppress-Notify-If-Match and - Suppress-Body-If-Match and functions related to them, - enabled with ./configure option --enable-experimental -- Added SIP header Refer-Sub and related functions -- Added include file -- Added auc_info() function (sofia-sip/auth_client.h) -- Added alternative implementations to event reactor object (su_port_t, - referenced by su_root_t) that can be changed at runtime using SU_PORT - environment variable, for instance - - Internal semantics of su_port_t reference counting have changed: - now su_port_create() has one reference, and su_root_create_with_port() - always consumes one reference -- Changed return type of bm_memmem() and bm_memcasemem() to non-const - This release is ABI/API compatible with applications linked against any 1.12.x release. However, applications built against this release won't work against an older library. The ABI has been tested with the nua module unit test (test_nua) built against original 1.12.0 release. libsofia-sip-ua-glib: -- The 'nua-glib' module has been removed from the library and moved - to a separate package 'sofia-nua-glib'. The remaining library (su-glib) - is now considered stable and will be API/ABI compatible with later - releases in the 1.12.x series. -- ABI has been modified and applications built against 1.12.4 and earlier - releases, need to be rebuilt. -- Added su_glib_prefer_gsource() which makes glib-based su_port_t - implementation the default choice when su_root_create() is called +- No ABI/API changes, compatible with 1.12.0. Note, libsofia-sip-ua-glib + interface is not considered stable and may change in a future 1.12.x + release. Contributors to this release ---------------------------- -- Petteri Puolakka (patch to stun) -- Mikhail Zabaluev (patch to su-glib mainloop integration) -- Michael Jerris (patch to url parsing # in sip/sips userpart) -- Colin Whittaker (TPTAG_TOS()) -- Roman Filonenko (TPTAG_LOG(), TPTAG_DUMP(), - patch to query DNS-servers with IP-Helper on win32) -- Remi Denis-Courmont (patch to network change API) -- Martti Mela (poll() emulation with select(), IPv6 and OS X fixes) -- Kai Vehmanen (persistent registrations, release management) -- Pekka Pessi (all the rest) + + +- **template**: First Surname (patch to nua/soa/msg) See the AUTHORS file in the distribution package. Notes on new features --------------------- -- The su_root_t reactor uses different implementation (epoll, poll or select - on Linux), depending on SU_PORT environment variable. - -- nua now supports request queuing, for instance, an application can send - overlapping BYE and NOTIFY requests. The stack engine takes care of - sending the new request only after the previous one has been responded. - -- RFC 4488 defines the Refer-Sub header. Its datatypes, related functions and - methods declared in include file. The Refer-Sub - header structure can be accessed from sip_t structure with sip_refer_sub() - method, e.g., - - if (sip_refer_sub(sip) && - strcasecmp("false", sip_refer_sub(sip)->rs_value) == 0) { - /* Do not create implicit subscription */ - } - -- Unsolicited NOTIFYs are now supported. The application can accept incoming - NOTIFYs and send NOTIFYs without existing subscription. - -- Transport connections used for client registrations are now maintained - in a persistent fashion. For example a TCP connection used for - registration is not closed until client is unregisters, or the whole stack - is shut down. - -- New build time options have been added: ability to build without - STUN and HTTP support. See 'docs/devel_platform_notes.txt' for some - additional notes to distributors. + Bugs fixed in this release -------------------------- -- Fixed su_from_create() returning a sip_to_t instance. Problem reported by - Ludovico Cavedon. -- Partially fixed problem #1633969 with too frequent timer -- Fixed problem in dialog matching. Problem reported by Fabio Margarido. -- Fixed #1624446 - su_wait_clone() (and nua_destroy()) blocking for ever if - the root object was created using su_glib -- Fixed #1626330 - leak in nta.c which happened if INVITE never got a final - response nor timed out. -- Fixed handle leak (pthread_*_init without pthread_*_destroy). Problem - reported by Maxim Zaikin. -- Fixed crash when nua_bye() was called while a NOTIFY client transaction - was in progress. Problem reported by Anthony Minnessale. -- Not using close() with sockets in sres.c. Problem reported by - Roman Filonenko. -- Bug in zero-padding STUN messages with a message integrity - attribute. Patch by Petteri Puolakka. -- Fixed a severe problem with timer accuracy, when sofia-sip timers - where used under glib's mainloop. -- Improved glib mainloop integration to avoid warnings about already - active mainloop context, and potentially other issue. Patch by - Mikhail Zabaluev. Closes sf.net item #1606786. -- Ignore harmless syntax errors in incoming requests/responses by default -- If a TCP connection cannot be made within SIP T4 (because of a - firewall, for instance) nta now tries to use UDP instead. +< notable bugs fixed in this release + - check the sf.net bug tracker; see closed bugs, + sorted by closing date + - other bugs as fixed in CVS/darcs +/> + +- **template**: #9499652 sf.net bug item title diff --git a/libs/sofia-sip/configure.ac b/libs/sofia-sip/configure.ac index bd4fbe4d19..6278ae9064 100644 --- a/libs/sofia-sip/configure.ac +++ b/libs/sofia-sip/configure.ac @@ -11,7 +11,7 @@ dnl information on the package dnl --------------------------- dnl update both the version for AC_INIT and the LIBSOFIA_SIP_UA_MAJOR_MINOR -AC_INIT([sofia-sip], [1.12.5]) +AC_INIT([sofia-sip], [1.12.5work]) AC_CONFIG_SRCDIR([libsofia-sip-ua/sip/sofia-sip/sip.h]) AC_SUBST(VER_LIBSOFIA_SIP_UA_MAJOR_MINOR, [1.12]) dnl Includedir specific to this sofia version diff --git a/libs/sofia-sip/docs/release_management.txt b/libs/sofia-sip/docs/release_management.txt index faaf7c3467..ef1a0aef7d 100644 --- a/libs/sofia-sip/docs/release_management.txt +++ b/libs/sofia-sip/docs/release_management.txt @@ -61,7 +61,8 @@ Making the release tarball sh> cvs tag rel-sofia-sip-x_y_z - take a fresh checkout of the release using the release tag sh> darcs get http://sofia-sip.org/repos/sofia-sip --tag=rel-sofia-sip-1_yy_z -- create the release tarball with "make distcheck" +- create the release tarball with "make distcheck" (make sure depcomp et + al libtool scripts are correctly created) - calculate md5 and sha1 hashes using md5sum and sha1sum utilities, and copy the values to the release-notes (see below) diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/nta.c b/libs/sofia-sip/libsofia-sip-ua/nta/nta.c index 7eb7f5edff..08be2e658d 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nta/nta.c +++ b/libs/sofia-sip/libsofia-sip-ua/nta/nta.c @@ -5056,10 +5056,16 @@ nta_incoming_t *incoming_find(nta_agent_t const *agent, if (irq->irq_method == rq->rq_method) break; /* found */ - if (return_ack && rq->rq_method == sip_method_cancel) - *return_ack = irq; - else if (return_ack && rq->rq_method == sip_method_ack && - irq->irq_method == sip_method_invite) + if (!return_ack) + continue; + + if (irq->irq_method == sip_method_invite) { + if (rq->rq_method == sip_method_cancel) + *return_ack = irq; + else if (rq->rq_method == sip_method_ack) + *return_ack = irq; + } + else if (rq->rq_method == sip_method_cancel && !irq->irq_terminated) *return_ack = irq; } @@ -5179,10 +5185,18 @@ int incoming_cancel(nta_incoming_t *irq, msg_t *msg, sip_t *sip, nta_agent_t *agent = irq->irq_agent; /* Respond to the CANCEL */ - nta_msg_treply(agent, msg_ref_create(msg), SIP_200_OK, - NTATAG_TPORT(tport), - TAG_END()); + if (200 <= irq->irq_status && irq->irq_status < 300) { + nta_msg_treply(agent, msg_ref_create(msg), SIP_481_NO_TRANSACTION, + NTATAG_TPORT(tport), + TAG_END()); + } + else + nta_msg_treply(agent, msg_ref_create(msg), SIP_200_OK, + NTATAG_TPORT(tport), + TAG_END()); + + /* We have already sent final response */ if (irq->irq_completed || irq->irq_method != sip_method_invite) { msg_destroy(msg); return 0; diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c index 1be85fc9b7..840f17aedd 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c @@ -345,6 +345,15 @@ void nua_dialog_usage_remove_at(nua_owner_t *own, nua_client_request_t *cr, *cr_next; nua_server_request_t *sr, *sr_next; + *at = du->du_next; + + o = du->du_event; + + SU_DEBUG_5(("nua(%p): removing %s usage%s%s\n", + (void *)own, nua_dialog_usage_name(du), + o ? " with event " : "", o ? o->o_type :"")); + du->du_class->usage_remove(own, ds, du); + /* Destroy saved client request */ if (nua_client_is_bound(du->du_cr)) { nua_client_bind(cr = du->du_cr, NULL); @@ -366,26 +375,20 @@ void nua_dialog_usage_remove_at(nua_owner_t *own, nua_server_request_destroy(sr); } - *at = du->du_next; - - o = du->du_event; - - SU_DEBUG_5(("nua(%p): removing %s usage%s%s\n", - (void *)own, nua_dialog_usage_name(du), - o ? " with event " : "", o ? o->o_type :"")); - du->du_class->usage_remove(own, ds, du); su_home_unref(own); su_free(own, du); } /* Zap dialog if there are no more usages */ - if (ds->ds_usage == NULL) { + if (ds->ds_terminated) + ; + else if (ds->ds_usage == NULL) { nua_dialog_remove(own, ds, NULL); ds->ds_has_events = 0; ds->ds_terminated = 0; return; } - else if (!ds->ds_terminated) { + else { nua_dialog_log_usage(own, ds); } } @@ -561,6 +564,8 @@ int nua_dialog_shutdown(nua_owner_t *owner, nua_dialog_state_t *ds) { nua_dialog_usage_t *du; + ds->ds_terminated = 1; + do { for (du = ds->ds_usage; du; du = du->du_next) { if (!du->du_shutdown) { @@ -575,8 +580,8 @@ int nua_dialog_shutdown(nua_owner_t *owner, nua_dialog_state_t *ds) /** (Gracefully) terminate usage */ void nua_dialog_usage_shutdown(nua_owner_t *owner, - nua_dialog_state_t *ds, - nua_dialog_usage_t *du) + nua_dialog_state_t *ds, + nua_dialog_usage_t *du) { if (du) { du->du_refresh = 0; diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.h b/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.h index 3c852b0b22..03fbf1a48b 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.h +++ b/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.h @@ -115,6 +115,8 @@ struct nua_server_request { unsigned sr_terminating:1; /**< Terminate usage after final response */ unsigned sr_gracefully:1; /**< Terminate usage gracefully */ + unsigned sr_neutral:1; /**< No effect on session or other usage */ + /* Flags used with offer-answer */ unsigned sr_offer_recv:1; /**< We have received an offer */ unsigned sr_answer_sent:2; /**< We have answered (reliably, if >1) */ @@ -284,6 +286,9 @@ struct nua_client_request unsigned cr_offer_recv:1; /**< Recv offer in a response */ unsigned cr_answer_sent:1; /**< Sent answer in (PR)ACK */ + /* Flags with usage */ + unsigned cr_neutral:1; /**< No effect on session or other usage */ + /* Lifelong flags? */ unsigned cr_auto:1; /**< Request was generated by stack */ unsigned cr_has_contact:1; /**< Request has user Contact */ @@ -318,6 +323,7 @@ struct nua_dialog_state unsigned ds_has_register:1; /**< We have registration */ unsigned ds_has_publish:1; /**< We have publish */ + unsigned ds_got_session:1; /**< We have (or have had) session */ unsigned ds_got_referrals:1; /**< We have (or have had) referrals */ unsigned :0; @@ -573,6 +579,10 @@ int nua_client_report(nua_client_request_t *cr, nua_client_request_t *nua_client_request_pending(nua_client_request_t const *); +int nua_client_init_requests(nua_client_request_t *cr, + void const *cr0, + int invite); + /* ---------------------------------------------------------------------- */ extern nua_server_methods_t const @@ -590,6 +600,7 @@ extern nua_server_methods_t const nua_refer_server_methods, /**< REFER */ nua_publish_server_methods; /**< PUBLISH */ +/** Return true if we have not sent final response to request */ static inline int nua_server_request_is_pending(nua_server_request_t const *sr) { diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c index 54a9bc04b8..1d412ed19f 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c @@ -177,6 +177,9 @@ static int nua_session_usage_shutdown(nua_owner_t *, nua_dialog_state_t *, nua_dialog_usage_t *); +static int nua_invite_client_ack(nua_client_request_t *cr, tagi_t const *tags); +static int nua_invite_client_deinit(nua_client_request_t *cr); + static nua_usage_class const nua_session_usage[1] = { { sizeof (nua_session_usage_t), @@ -202,6 +205,7 @@ int nua_session_usage_add(nua_handle_t *nh, if (ds->ds_has_session) return -1; ds->ds_has_session = 1; + ds->ds_got_session = 1; return 0; } @@ -212,10 +216,44 @@ void nua_session_usage_remove(nua_handle_t *nh, nua_dialog_usage_t *du) { nua_session_usage_t *ss = nua_dialog_usage_private(du); + nua_client_request_t *cr, *cr_next; + + cr = du->du_cr; + + if (cr && cr->cr_orq && cr->cr_status >= 200) { + ss->ss_reporting = 1; + nua_invite_client_ack(cr, NULL); + ss->ss_reporting = 0; + } + + /* Destroy queued INVITE transactions */ + for (cr = ds->ds_cr; cr; cr = cr_next) { + cr_next = cr->cr_next; + + if (cr->cr_method != sip_method_invite) + continue; + if (cr == du->du_cr) + continue; + + nua_stack_event(nh->nh_nua, nh, + NULL, + cr->cr_event, + SIP_481_NO_TRANSACTION, + NULL); + + nua_client_request_destroy(cr); + + cr_next = ds->ds_cr; + } - ds->ds_has_session = 0; - (void)ss; + ds->ds_has_session = 0; + nh->nh_has_invite = 0; + nh->nh_active_call = 0; + nh->nh_hold_remote = 0; + + if (nh->nh_soa) + soa_destroy(nh->nh_soa), nh->nh_soa = NULL; } static @@ -228,7 +266,7 @@ nua_dialog_usage_t *nua_dialog_usage_for_session(nua_dialog_state_t const *ds) } static -nua_session_usage_t *nua_session_usage_get(nua_dialog_state_t const *ds) +nua_session_usage_t *nua_session_usage_for_dialog(nua_dialog_state_t const *ds) { nua_dialog_usage_t *du; @@ -245,13 +283,6 @@ static void nua_session_usage_destroy(nua_handle_t *nh, nua_session_usage_t *ss) { - nh->nh_has_invite = 0; - nh->nh_active_call = 0; - nh->nh_hold_remote = 0; - - if (nh->nh_soa) - soa_destroy(nh->nh_soa), nh->nh_soa = NULL; - /* Remove usage */ nua_dialog_usage_remove(nh, nh->nh_ds, nua_dialog_usage_public(ss)); @@ -482,13 +513,6 @@ static int nua_invite_client_report(nua_client_request_t *cr, nta_outgoing_t *orq, tagi_t const *tags); -static int nua_invite_client_ack(nua_client_request_t *cr, tagi_t const *tags); -static int nua_invite_client_ack_msg(nua_client_request_t *cr, - msg_t *msg, sip_t *sip, - tagi_t const *tags); - -static int nua_invite_client_deinit(nua_client_request_t *cr); - nua_client_methods_t const nua_invite_client_methods = { SIP_METHOD_INVITE, 0, @@ -527,6 +551,9 @@ static int nua_invite_client_init(nua_client_request_t *cr, nua_dialog_usage_t *du; cr->cr_usage = du = nua_dialog_usage_for_session(nh->nh_ds); + /* Errors returned by nua_invite_client_init() + are neutral to session state */ + cr->cr_neutral = 1; if (nh_is_special(nh) || nua_stack_set_handle_special(nh, nh_has_invite, nua_i_error)) @@ -534,7 +561,15 @@ static int nua_invite_client_init(nua_client_request_t *cr, else if (nh_referral_check(nh, tags) < 0) return nua_client_return(cr, 900, "Invalid referral", msg); - if (!du) + if (du) { + nua_server_request_t *sr; + for (sr = nh->nh_ds->ds_sr; sr; sr = sr->sr_next) + /* INVITE in progress? */ + if (sr->sr_usage == du && sr->sr_method == sip_method_invite && + nua_server_request_is_pending(sr)) + return nua_client_return(cr, SIP_491_REQUEST_PENDING, msg); + } + else du = nua_dialog_usage_add(nh, nh->nh_ds, nua_session_usage, NULL); if (!du) return -1; @@ -547,6 +582,8 @@ static int nua_invite_client_init(nua_client_request_t *cr, NH_PGET(nh, min_se), NH_PGET(nh, refresher)); + cr->cr_neutral = 0; + return 0; } @@ -568,7 +605,7 @@ static int nua_invite_client_request(nua_client_request_t *cr, invite_timeout = NH_PGET(nh, invite_timeout); if (invite_timeout == 0) invite_timeout = UINT_MAX; - /* Cancel if we don't get response within timeout*/ + /* Send CANCEL if we don't get response within timeout*/ nua_dialog_usage_set_expires(du, invite_timeout); nua_dialog_usage_set_refresh(du, 0); @@ -808,12 +845,20 @@ static int nua_invite_client_report(nua_client_request_t *cr, if (orq != cr->cr_orq && status != 100) return 1; + if (ss == NULL) { + signal_call_state_change(nh, ss, status, phrase, nua_callstate_terminated); + return 1; + } + ss->ss_reporting = 1; - if (ss == NULL) { - next_state = nua_callstate_terminated; + if (cr->cr_neutral) { + signal_call_state_change(nh, ss, status, phrase, ss->ss_state); + ss->ss_reporting = 0; + return 1; } - else if (status == 100) { + + if (status == 100) { next_state = nua_callstate_calling; } else if (status < 300 && cr->cr_graceful) { @@ -927,11 +972,10 @@ int nua_stack_ack(nua_t *nua, nua_handle_t *nh, nua_event_t e, { nua_dialog_usage_t *du = nua_dialog_usage_for_session(nh->nh_ds); nua_session_usage_t *ss = nua_dialog_usage_private(du); + nua_client_request_t *cr = du ? du->du_cr : NULL; + int error; - if (!du || - !du->du_cr || - du->du_cr->cr_orq == NULL || - du->du_cr->cr_status < 200) { + if (!cr || cr->cr_orq == NULL || cr->cr_status < 200) { UA_EVENT2(nua_i_error, 900, "No response to ACK"); return 1; } @@ -942,8 +986,9 @@ int nua_stack_ack(nua_t *nua, nua_handle_t *nh, nua_event_t e, soa_set_params(nh->nh_soa, TAG_NEXT(tags)); } - if (nua_invite_client_ack(du->du_cr, tags) < 0) { - int error; + error = nua_invite_client_ack(cr, tags); + + if (error < 0) { ss->ss_reason = "SIP;cause=500;text=\"Internal Error\""; ss->ss_reporting = 1; /* We report state here if BYE fails */ error = nua_client_create(nh, nua_r_bye, &nua_bye_client_methods, NULL); @@ -953,6 +998,12 @@ int nua_stack_ack(nua_t *nua, nua_handle_t *nh, nua_event_t e, ? nua_callstate_terminated : nua_callstate_terminating); } + else { + if (!nua_client_is_queued(cr) && !nua_client_is_bound(cr)) + nua_client_request_destroy(cr); + + nua_client_init_requests(nh->nh_ds->ds_cr, cr, 1); + } return 0; } @@ -967,6 +1018,7 @@ int nua_invite_client_ack(nua_client_request_t *cr, tagi_t const *tags) { nua_handle_t *nh = cr->cr_owner; nua_dialog_state_t *ds = nh->nh_ds; + nua_session_usage_t *ss = nua_dialog_usage_private(cr->cr_usage); msg_t *msg; sip_t *sip; @@ -974,6 +1026,9 @@ int nua_invite_client_ack(nua_client_request_t *cr, tagi_t const *tags) sip_authorization_t *wa; sip_proxy_authorization_t *pa; sip_cseq_t *cseq; + nta_outgoing_t *ack; + int status = 200; + char const *phrase = "OK", *reason = NULL; assert(ds->ds_leg); assert(cr->cr_orq); @@ -1009,94 +1064,75 @@ int nua_invite_client_ack(nua_client_request_t *cr, tagi_t const *tags) ; else if (nta_msg_request_complete(msg, ds->ds_leg, SIP_METHOD_ACK, NULL) < 0) ; - else - error = nua_invite_client_ack_msg(cr, msg, sip, tags); + else { + /* Remove extra headers */ + while (sip->sip_allow) + sip_header_remove(msg, sip, (sip_header_t*)sip->sip_allow); + while (sip->sip_priority) + sip_header_remove(msg, sip, (sip_header_t*)sip->sip_priority); + while (sip->sip_proxy_require) + sip_header_remove(msg, sip, (sip_header_t*)sip->sip_proxy_require); + while (sip->sip_require) + sip_header_remove(msg, sip, (sip_header_t*)sip->sip_require); + while (sip->sip_subject) + sip_header_remove(msg, sip, (sip_header_t*)sip->sip_subject); + while (sip->sip_supported) + sip_header_remove(msg, sip, (sip_header_t*)sip->sip_supported); - nta_outgoing_destroy(cr->cr_orq), cr->cr_orq = NULL; - - if (error == -1) - msg_destroy(msg); - - return error; -} - -/** Send ACK, destroy INVITE transaction. - * - * @retval 1 if successful - * @retval -2 if an error occurred - */ -static -int nua_invite_client_ack_msg(nua_client_request_t *cr, - msg_t *msg, sip_t *sip, - tagi_t const *tags) -{ - nua_handle_t *nh = cr->cr_owner; - nua_dialog_usage_t *du = cr->cr_usage; - nua_session_usage_t *ss = nua_dialog_usage_private(du); - - nta_outgoing_t *ack; - int status = 200; - char const *phrase = "OK", *reason = NULL; - - /* Remove extra headers */ - while (sip->sip_allow) - sip_header_remove(msg, sip, (sip_header_t*)sip->sip_allow); - while (sip->sip_priority) - sip_header_remove(msg, sip, (sip_header_t*)sip->sip_priority); - while (sip->sip_proxy_require) - sip_header_remove(msg, sip, (sip_header_t*)sip->sip_proxy_require); - while (sip->sip_require) - sip_header_remove(msg, sip, (sip_header_t*)sip->sip_require); - while (sip->sip_subject) - sip_header_remove(msg, sip, (sip_header_t*)sip->sip_subject); - while (sip->sip_supported) - sip_header_remove(msg, sip, (sip_header_t*)sip->sip_supported); - - if (!nh->nh_soa) - ; - else if (cr->cr_offer_recv && !cr->cr_answer_sent) { - if (soa_generate_answer(nh->nh_soa, NULL) < 0 || - session_include_description(nh->nh_soa, 1, msg, sip) < 0) { - status = 900, phrase = "Internal media error"; - reason = "SIP;cause=500;text=\"Internal media error\""; - /* reason = soa_error_as_sip_reason(nh->nh_soa); */ + if (!nh->nh_soa || ss == NULL) + ; + else if (cr->cr_offer_recv && !cr->cr_answer_sent) { + if (soa_generate_answer(nh->nh_soa, NULL) < 0 || + session_include_description(nh->nh_soa, 1, msg, sip) < 0) { + status = 900, phrase = "Internal media error"; + reason = "SIP;cause=500;text=\"Internal media error\""; + /* reason = soa_error_as_sip_reason(nh->nh_soa); */ + } + else { + cr->cr_answer_sent = 1; + soa_activate(nh->nh_soa, NULL); + /* signal that O/A round is complete */ + ss->ss_oa_sent = "answer"; + } + + if (!reason && + /* ss->ss_offer_sent && !ss->ss_answer_recv */ + !soa_is_complete(nh->nh_soa)) { + /* No SDP answer in 2XX response -> terminate call */ + status = 988, phrase = "Incomplete offer/answer"; + reason = "SIP;cause=488;text=\"Incomplete offer/answer\""; + } } - else { - cr->cr_answer_sent = 1; - soa_activate(nh->nh_soa, NULL); - /* signal that O/A round is complete */ - ss->ss_oa_sent = "answer"; + + if ((ack = nta_outgoing_mcreate(nh->nh_nua->nua_nta, NULL, NULL, NULL, + msg, + SIPTAG_END(), + TAG_NEXT(tags)))) { + nta_outgoing_destroy(ack); /* TR engine keeps this around for T2 */ + } + else if (!reason) { + status = 900, phrase = "Cannot send ACK"; + reason = "SIP;cause=500;text=\"Internal Error\""; } - if (!reason && - /* ss->ss_offer_sent && !ss->ss_answer_recv */ - !soa_is_complete(nh->nh_soa)) { - /* No SDP answer in 2XX response -> terminate call */ - status = 988, phrase = "Incomplete offer/answer"; - reason = "SIP;cause=488;text=\"Incomplete offer/answer\""; - } - } - - if ((ack = nta_outgoing_mcreate(nh->nh_nua->nua_nta, NULL, NULL, NULL, - msg, - SIPTAG_END(), - TAG_NEXT(tags)))) { - nta_outgoing_destroy(ack); /* TR engine keeps this around for T2 */ - } - else if (!reason) { - status = 900, phrase = "Cannot send ACK"; - reason = "SIP;cause=500;text=\"Internal Error\""; - } - - if (ss) { - if (reason) + if (ss && reason) ss->ss_reason = reason; - if (!ss->ss_reporting && status < 300) + if (status < 300) + error = 1; + else + error = -2; + } + + nta_outgoing_destroy(cr->cr_orq), cr->cr_orq = NULL; + nua_client_request_remove(cr); + + if (ss) { + if (!ss->ss_reporting && error >= 0) signal_call_state_change(nh, ss, status, phrase, nua_callstate_ready); } - return status < 300 ? 1 : -2; + return error; } /** Deinitialize client request */ @@ -1220,7 +1256,7 @@ static void nua_session_usage_refresh(nua_handle_t *nh, if (cr->cr_method == sip_method_update) return; - /* INVITE or UPDATE in progress or being authenticated */ + /* INVITE or UPDATE in progress */ for (sr = ds->ds_sr; sr; sr = sr->sr_next) if (sr->sr_usage == du && (sr->sr_method == sip_method_invite || @@ -1258,7 +1294,7 @@ static int nua_session_usage_shutdown(nua_handle_t *nh, nua_server_request_t *sr, *sr_next; nua_client_request_t *cri; - assert(ss == nua_session_usage_get(nh->nh_ds)); + assert(ss == nua_session_usage_for_dialog(nh->nh_ds)); /* Zap server-side transactions */ for (sr = ds->ds_sr; sr; sr = sr_next) { @@ -1663,6 +1699,8 @@ nua_invite_server_init(nua_server_request_t *sr) nua_handle_t *nh = sr->sr_owner; nua_t *nua = nh->nh_nua; + sr->sr_neutral = 1; + if (!NUA_PGET(nua, nh, invite_enable)) return SR_STATUS1(sr, SIP_403_FORBIDDEN); @@ -1688,9 +1726,10 @@ nua_invite_server_init(nua_server_request_t *sr) break; } - if (sr0) + if (sr0) { /* Overlapping invites - RFC 3261 14.2 */ return nua_server_retry_after(sr, 500, "Overlapping Requests", 0, 10); + } for (cr = nh->nh_ds->ds_cr; cr; cr = cr->cr_next) { if (cr->cr_usage == sr->sr_usage && cr->cr_orq && cr->cr_offer_sent) @@ -1699,6 +1738,8 @@ nua_invite_server_init(nua_server_request_t *sr) } } + sr->sr_neutral = 0; + return 0; } @@ -2024,6 +2065,7 @@ int nua_invite_server_report(nua_server_request_t *sr, tagi_t const *tags) nua_dialog_usage_t *du = sr->sr_usage; nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage); int initial = sr->sr_initial && !sr->sr_event; + int neutral = sr->sr_neutral; int application = sr->sr_application; int status = sr->sr_status; char const *phrase = sr->sr_phrase; int retval; @@ -2036,18 +2078,18 @@ int nua_invite_server_report(nua_server_request_t *sr, tagi_t const *tags) if (retval >= 2 || ss == NULL) { /* Session has been terminated. */ - if (!initial) + if (!initial && !neutral) signal_call_state_change(nh, NULL, status, phrase, nua_callstate_terminated); return retval; } assert(ss); - assert(ss->ss_state != nua_callstate_calling); - assert(ss->ss_state != nua_callstate_proceeding); /* Update session state */ - if (status < 300 || application != 0) + if (status < 300 || application != 0) { + assert(ss->ss_state != nua_callstate_calling); + assert(ss->ss_state != nua_callstate_proceeding); signal_call_state_change(nh, ss, status, phrase, status >= 300 ? nua_callstate_init @@ -2056,6 +2098,7 @@ int nua_invite_server_report(nua_server_request_t *sr, tagi_t const *tags) : status > 100 ? nua_callstate_early : nua_callstate_received); + } if (status == 180) ss->ss_alerting = 1; @@ -2065,7 +2108,7 @@ int nua_invite_server_report(nua_server_request_t *sr, tagi_t const *tags) if (200 <= status && status < 300) { du->du_ready = 1; } - else if (300 <= status) { + else if (300 <= status && !neutral) { if (nh->nh_soa) soa_init_offer_answer(nh->nh_soa); } @@ -2196,16 +2239,20 @@ int process_cancel(nua_server_request_t *sr, { nua_handle_t *nh = sr->sr_owner; nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage); - msg_t *cancel = nta_incoming_getrequest_ackcancel(irq); - if (nta_incoming_status(irq) < 200 && nua_server_request_is_pending(sr) && - ss && (ss == nua_session_usage_get(nh->nh_ds))) { - nua_stack_event(nh->nh_nua, nh, cancel, nua_i_cancel, SIP_200_OK, NULL); + assert(ss); assert(ss == nua_session_usage_for_dialog(nh->nh_ds)); (void)ss; - SR_STATUS1(sr, SIP_487_REQUEST_TERMINATED); + if (nua_server_request_is_pending(sr)) { + msg_t *cancel = nta_incoming_getrequest_ackcancel(irq); - nua_server_respond(sr, NULL); - nua_server_report(sr); + assert(nta_incoming_status(irq) < 200); + + nua_stack_event(nh->nh_nua, nh, cancel, nua_i_cancel, SIP_200_OK, NULL); + + SR_STATUS1(sr, SIP_487_REQUEST_TERMINATED); + + nua_server_respond(sr, NULL); + nua_server_report(sr); } return 0; @@ -2222,7 +2269,7 @@ int process_timeout(nua_server_request_t *sr, char const *reason = "SIP;cause=408;text=\"ACK Timeout\""; int error; - assert(ss); assert(ss == nua_session_usage_get(nh->nh_ds)); + assert(ss); assert(ss == nua_session_usage_for_dialog(nh->nh_ds)); if (nua_server_request_is_pending(sr)) { phrase = "PRACK Timeout"; @@ -3328,7 +3375,7 @@ nua_client_methods_t const nua_bye_client_methods = { int nua_stack_bye(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags) { - nua_session_usage_t *ss = nua_session_usage_get(nh->nh_ds); + nua_session_usage_t *ss = nua_session_usage_for_dialog(nh->nh_ds); if (ss && nua_callstate_calling <= ss->ss_state && @@ -3430,9 +3477,11 @@ static int nua_bye_client_report(nua_client_request_t *cr, signal_call_state_change(nh, ss, status, "to BYE", nua_callstate_terminated); - if (ss && !ss->ss_reporting && !nua_client_is_queued(du->du_cr)) { - /* Do not destroy session usage while INVITE is alive */ - nua_session_usage_destroy(nh, ss); + if (ss && !ss->ss_reporting) { + if (nua_client_is_queued(du->du_cr) && du->du_cr->cr_status < 200) + /* No final response to INVITE received yet */; + else + nua_session_usage_destroy(nh, ss); } } diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c index bcc473bf66..9cda773175 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c @@ -743,14 +743,14 @@ void nh_destroy(nua_t *nua, nua_handle_t *nh) if (nh->nh_notifier) nea_server_destroy(nh->nh_notifier), nh->nh_notifier = NULL; - nua_dialog_deinit(nh, nh->nh_ds); - while (nh->nh_ds->ds_cr) nua_client_request_destroy(nh->nh_ds->ds_cr); while (nh->nh_ds->ds_sr) nua_server_request_destroy(nh->nh_ds->ds_sr); + nua_dialog_deinit(nh, nh->nh_ds); + if (nh->nh_soa) soa_destroy(nh->nh_soa), nh->nh_soa = NULL; @@ -1090,6 +1090,9 @@ int nua_stack_process_request(nua_handle_t *nh, nta_incoming_tag(irq, NULL); + if (method == sip_method_cancel) + return 481; + /* Hook to outbound */ if (method == sip_method_options) { status = nua_registration_process_request(nua->nua_registrations, @@ -1485,6 +1488,8 @@ int nua_server_respond(nua_server_request_t *sr, tagi_t const *tags) else if (next.msg) msg_destroy(next.msg); + assert(sr->sr_status >= 200 || sr->sr_response.msg); + return retval; } @@ -1521,7 +1526,7 @@ int nua_server_report(nua_server_request_t *sr) if (sr) return sr->sr_methods->sm_report(sr, NULL); else - return 2; + return 1; } int nua_base_server_treport(nua_server_request_t *sr, @@ -1763,8 +1768,11 @@ inline int nua_client_request_queue(nua_client_request_t *cr) } } else { - while (*queue) + while (*queue) { queue = &(*queue)->cr_next; + if (cr->cr_method == sip_method_invite) + queued = 1; + } } if ((cr->cr_next = *queue)) @@ -2543,7 +2551,7 @@ int nua_base_client_response(nua_client_request_t *cr, tagi_t const *tags) { nua_handle_t *nh = cr->cr_owner; - int next; + sip_method_t method = cr->cr_method; cr->cr_reporting = 1; @@ -2552,14 +2560,15 @@ int nua_base_client_response(nua_client_request_t *cr, nua_client_report(cr, status, phrase, sip, cr->cr_orq, tags); - if (status >= 200) - nua_client_request_remove(cr); - - if (cr->cr_method == sip_method_invite ? status < 300 : status < 200) { + if (status < 200 || + /* Un-ACKed 2XX response to INVITE */ + (cr->cr_method == sip_method_invite && status < 300 && cr->cr_orq)) { cr->cr_reporting = 0; return 1; } + nua_client_request_remove(cr); + if (cr->cr_orq) nta_outgoing_destroy(cr->cr_orq), cr->cr_orq = NULL; @@ -2585,16 +2594,12 @@ int nua_base_client_response(nua_client_request_t *cr, if (nua_client_is_queued(cr)) return 1; - next = cr->cr_method != sip_method_invite && cr->cr_method != sip_method_cancel; - if (!nua_client_is_bound(cr)) nua_client_request_destroy(cr); - if (next && nh->nh_ds->ds_cr != NULL && nh->nh_ds->ds_cr != cr) { - cr = nh->nh_ds->ds_cr; - if (cr->cr_method != sip_method_invite && cr->cr_method != sip_method_cancel) - nua_client_init_request(cr); - } + if (method != sip_method_cancel) + return nua_client_init_requests(nh->nh_ds->ds_cr, cr, + method == sip_method_invite); return 1; } @@ -2638,6 +2643,29 @@ int nua_client_treport(nua_client_request_t *cr, return retval; } +int nua_client_init_requests(nua_client_request_t *cr, + void const *cr0, + int invite) +{ + if (cr0 == cr) /* already initialized! */ + return 1; + + for (; cr; cr = cr->cr_next) { + if (cr->cr_method == sip_method_cancel) + continue; + + if (invite + ? cr->cr_method == sip_method_invite + : cr->cr_method != sip_method_invite) + break; + } + + if (cr) + nua_client_init_request(cr); + + return 1; +} + nua_client_request_t * nua_client_request_pending(nua_client_request_t const *cr) { diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/test_100rel.c b/libs/sofia-sip/libsofia-sip-ua/nua/test_100rel.c index 2c18dfd85d..6927cd53f3 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/test_100rel.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/test_100rel.c @@ -1578,6 +1578,310 @@ int test_update_by_uas(struct context *ctx) END(); } +int cancel_when_pracked(CONDITION_PARAMS); +int alert_call(CONDITION_PARAMS); + +int test_180rel_cancel1(struct context *ctx) +{ + BEGIN(); + + struct endpoint *a = &ctx->a, *b = &ctx->b; + struct call *a_call = a->call, *b_call = b->call; + struct event *e; + + if (print_headings) + printf("TEST NUA-10.6: CANCEL after PRACK\n"); + +/* Test for 100rel: + + A B + |-------INVITE------>| + |<----100 Trying-----| + | | + |<-------180---------| + |-------PRACK------->| + |<-------200---------| + | | + |------CANCEL------->| + |<------200 OK-------| + | | + |<-------487---------| + |--------ACK-------->| + | | + +*/ + + a_call->sdp = "m=audio 5008 RTP/AVP 8"; + b_call->sdp = "m=audio 5010 RTP/AVP 0 8"; + + nua_set_params(ctx->a.nua, + NUTAG_EARLY_MEDIA(1), + NUTAG_ONLY183_100REL(0), + TAG_END()); + run_a_until(ctx, nua_r_set_params, until_final_response); + + nua_set_params(ctx->b.nua, + NUTAG_EARLY_MEDIA(1), + NUTAG_ONLY183_100REL(0), + TAG_END()); + run_b_until(ctx, nua_r_set_params, until_final_response); + + TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END())); + + INVITE(a, a_call, a_call->nh, + TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)), + SOATAG_USER_SDP_STR(a_call->sdp), + TAG_END()); + + run_ab_until(ctx, -1, cancel_when_pracked, -1, alert_call); + + /* Client transitions: + INIT -(C1)-> CALLING: nua_invite(), nua_i_state + CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state, nua_r_prack + PROCEEDING -(C3+C4)-> TERMINATED: nua_r_invite, nua_i_state + */ + TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state); + TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */ + TEST_1(is_offer_sent(e->data->e_tags)); + + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite); + TEST(e->data->e_status, 180); + + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state); + TEST(callstate(e->data->e_tags), nua_callstate_proceeding); + TEST_1(is_answer_recv(e->data->e_tags)); + TEST_1(!is_offer_sent(e->data->e_tags)); + + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_prack); + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_cancel); + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite); + TEST(e->data->e_status, 487); + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state); + TEST(callstate(e->data->e_tags), nua_callstate_terminated); + TEST_1(!e->next); + + free_events_in_list(ctx, a->events); + + /* + Server transitions: + INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state + RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state + Option A: + EARLY -(S10)-> TERMINATED: nua_i_cancel, nua_i_state + Option B: + EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state + COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state + READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state + */ + TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite); + TEST(e->data->e_status, 100); + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state); + TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */ + TEST_1(is_offer_recv(e->data->e_tags)); + + /* Responded with 180 Ringing */ + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state); + TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */ + TEST_1(is_answer_sent(e->data->e_tags)); + + /* 180 is PRACKed */ + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_prack); + /* Does not have effect on call state */ + + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_cancel); + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state); + TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */ + + free_events_in_list(ctx, b->events); + + nua_handle_destroy(a_call->nh), a_call->nh = NULL; + nua_handle_destroy(b_call->nh), b_call->nh = NULL; + + if (print_headings) + printf("TEST NUA-10.6: PASSED\n"); + + END(); +} + +int cancel_when_pracked(CONDITION_PARAMS) +{ + if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR))) + return 0; + + save_event_in_list(ctx, event, ep, call); + + if (event == nua_r_prack) + CANCEL(ep, call, nh, TAG_END()); + + switch (callstate(tags)) { + case nua_callstate_proceeding: + return 0; + case nua_callstate_ready: + return 1; + case nua_callstate_terminated: + return 1; + default: + return 0; + } +} + +int test_180rel_cancel2(struct context *ctx) +{ + BEGIN(); + + struct endpoint *a = &ctx->a, *b = &ctx->b; + struct call *a_call = a->call, *b_call = b->call; + struct event *e; + + if (print_headings) + printf("TEST NUA-10.7: CANCEL after 100rel 180\n"); + +/* Test for 100rel: + + A B + |-------INVITE------>| + |<----100 Trying-----| + | | + |<-------180---------| + |-------PRACK------->| + |<-------200---------| + | | + |------CANCEL------->| + |<------200 OK-------| + | | + |<-------487---------| + |--------ACK-------->| + | | + +*/ + + a_call->sdp = "m=audio 5008 RTP/AVP 8"; + b_call->sdp = "m=audio 5010 RTP/AVP 0 8"; + + nua_set_params(ctx->a.nua, + NUTAG_EARLY_MEDIA(1), + NUTAG_ONLY183_100REL(0), + TAG_END()); + run_a_until(ctx, nua_r_set_params, until_final_response); + + nua_set_params(ctx->b.nua, + NUTAG_EARLY_MEDIA(1), + NUTAG_ONLY183_100REL(0), + TAG_END()); + run_b_until(ctx, nua_r_set_params, until_final_response); + + TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END())); + + INVITE(a, a_call, a_call->nh, + TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)), + SOATAG_USER_SDP_STR(a_call->sdp), + TAG_END()); + + run_ab_until(ctx, -1, cancel_when_ringing, -1, accept_pracked2); + + /* Client transitions: + INIT -(C1)-> CALLING: nua_invite(), nua_i_state + CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state, nua_r_prack + PROCEEDING -(C3+C4)-> TERMINATED: nua_r_invite, nua_i_state + */ + TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state); + TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */ + TEST_1(is_offer_sent(e->data->e_tags)); + + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite); + TEST(e->data->e_status, 180); + + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state); + TEST(callstate(e->data->e_tags), nua_callstate_proceeding); + TEST_1(is_answer_recv(e->data->e_tags)); + TEST_1(!is_offer_sent(e->data->e_tags)); + +#define NEXT_SKIP_PRACK_CANCEL() \ + do { TEST_1(e = e->next); } \ + while (e->data->e_event == nua_r_prack || e->data->e_event == nua_r_cancel) + + NEXT_SKIP_PRACK_CANCEL(); + + TEST_E(e->data->e_event, nua_r_invite); + if (e->data->e_status == 487) { + TEST(e->data->e_status, 487); + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state); + TEST(callstate(e->data->e_tags), nua_callstate_terminated); + TEST_1(!e->next); + } + else { + TEST(e->data->e_status, 200); + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state); + TEST(callstate(e->data->e_tags), nua_callstate_ready); + + BYE(a, a_call, a_call->nh, TAG_END()); + run_ab_until(ctx, -1, until_terminated, -1, until_terminated); + + NEXT_SKIP_PRACK_CANCEL(); TEST_E(e->data->e_event, nua_r_bye); + TEST(e->data->e_status, 200); + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state); + TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */ + TEST_1(!e->next); + } + + free_events_in_list(ctx, a->events); + + /* + Server transitions: + INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state + RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state + Option A: + EARLY -(S10)-> TERMINATED: nua_i_cancel, nua_i_state + Option B: + EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state + COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state + READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state + */ + TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite); + TEST(e->data->e_status, 100); + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state); + TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */ + TEST_1(is_offer_recv(e->data->e_tags)); + + /* Responded with 180 Ringing */ + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state); + TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */ + TEST_1(is_answer_sent(e->data->e_tags)); + + /* 180 is PRACKed */ + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_prack); + /* Does not have effect on call state */ + + if (e->next->data->e_event == nua_i_cancel) { + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_cancel); + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state); + TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */ + } + else { + /* Respond with 200 OK */ + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state); + TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */ + TEST_1(!is_offer_answer_done(e->data->e_tags)); + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack); + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state); + TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */ + TEST_1(!is_offer_answer_done(e->data->e_tags)); + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_bye); + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state); + TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */ + } + + free_events_in_list(ctx, b->events); + + nua_handle_destroy(a_call->nh), a_call->nh = NULL; + nua_handle_destroy(b_call->nh), b_call->nh = NULL; + + if (print_headings) + printf("TEST NUA-10.7: PASSED\n"); + + END(); +} + int test_100rel(struct context *ctx) { @@ -1589,6 +1893,8 @@ int test_100rel(struct context *ctx) retval = test_preconditions(ctx); RETURN_ON_SINGLE_FAILURE(retval); retval = test_preconditions2(ctx); RETURN_ON_SINGLE_FAILURE(retval); retval = test_update_by_uas(ctx); RETURN_ON_SINGLE_FAILURE(retval); + retval = test_180rel_cancel1(ctx); RETURN_ON_SINGLE_FAILURE(retval); + retval = test_180rel_cancel2(ctx); RETURN_ON_SINGLE_FAILURE(retval); nua_set_params(ctx->a.nua, NUTAG_EARLY_MEDIA(0), @@ -1612,3 +1918,4 @@ int test_100rel(struct context *ctx) return retval; } + diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/test_call_hold.c b/libs/sofia-sip/libsofia-sip-ua/nua/test_call_hold.c index 2f5fb07eea..c3cbd5dcb0 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/test_call_hold.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/test_call_hold.c @@ -467,7 +467,7 @@ int test_call_hold(struct context *ctx) */ if (print_headings) - printf("TEST NUA-7.6: re-INVITE without auto-ack\n"); + printf("TEST NUA-7.6.1: re-INVITE without auto-ack\n"); /* Turn off auto-ack */ nua_set_hparams(b_call->nh, NUTAG_AUTOACK(0), TAG_END()); @@ -517,7 +517,7 @@ int test_call_hold(struct context *ctx) free_events_in_list(ctx, a->events); if (print_headings) - printf("TEST NUA-7.6: PASSED\n"); + printf("TEST NUA-7.6.1: PASSED\n"); /* ---------------------------------------------------------------------- */ @@ -528,7 +528,7 @@ int test_call_hold(struct context *ctx) */ if (print_headings) - printf("TEST NUA-7.6: terminate call\n"); + printf("TEST NUA-7.6.2: terminate call\n"); BYE(a, a_call, a_call->nh, TAG_END()); run_ab_until(ctx, -1, until_terminated, -1, until_terminated); @@ -555,7 +555,7 @@ int test_call_hold(struct context *ctx) free_events_in_list(ctx, b->events); if (print_headings) - printf("TEST NUA-7.6: PASSED\n"); + printf("TEST NUA-7.6.2: PASSED\n"); nua_handle_destroy(a_call->nh), a_call->nh = NULL; nua_handle_destroy(b_call->nh), b_call->nh = NULL; @@ -725,9 +725,6 @@ int test_reinvite(struct context *ctx) nua_handle_destroy(a_call->nh), a_call->nh = NULL; nua_handle_destroy(b_call->nh), b_call->nh = NULL; - if (print_headings) - printf("TEST NUA-7.8: PASSED\n"); - END(); } @@ -784,6 +781,211 @@ int ringing_until_terminated(CONDITION_PARAMS) } } +/* ======================================================================== */ + +int accept_and_attempt_reinvite(CONDITION_PARAMS); +int until_ready2(CONDITION_PARAMS); + +/* test_reinvite2 message sequence looks like this: + + A B + | | + |-------INVITE------>| + |<----100 Trying-----| + | | + |<----180 Ringing----| + | | + | /-INVITE-| + | \---900->| + | | + |<--------200--------| + |---------ACK------->| + : : + : queue INVITE : + : : + |-----re-INVITE----->| + |<--------200--------| + |---------ACK------->| + |-----re-INVITE----->| + |<--------200--------| + |---------ACK------->| + : : + : glare : + : : + |-----re-INVITE----->| + |<----re-INVITE------| + |<--------491--------| + |---------491------->| + |---------ACK------->| + |<--------ACK--------| + : : + |---------BYE------->| + |<--------200--------| +*/ + +int test_reinvite2(struct context *ctx) +{ + BEGIN(); + + struct endpoint *a = &ctx->a, *b = &ctx->b; + struct call *a_call = a->call, *b_call = b->call; + struct event *e; + + if (print_headings) + printf("TEST NUA-7.8.1: Test re-INVITE glare\n"); + + a_call->sdp = "m=audio 5008 RTP/AVP 0 8\n"; + b_call->sdp = "m=audio 5010 RTP/AVP 8\n"; + + TEST_1(a_call->nh = + nua_handle(a->nua, a_call, + SIPTAG_FROM_STR("Alice "), + SIPTAG_TO(b->to), + TAG_END())); + INVITE(a, a_call, a_call->nh, + TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)), + SOATAG_USER_SDP_STR(a_call->sdp), + TAG_END()); + + run_ab_until(ctx, -1, until_ready, -1, accept_and_attempt_reinvite); + + TEST_1(nua_handle_has_active_call(a_call->nh)); + TEST_1(nua_handle_has_active_call(b_call->nh)); + + free_events_in_list(ctx, a->events); + free_events_in_list(ctx, b->events); + + /* Check that we can queue INVITEs */ + INVITE(a, a_call, a_call->nh, TAG_END()); + INVITE(a, a_call, a_call->nh, TAG_END()); + + run_ab_until(ctx, -1, until_ready2, -1, until_ready2); + + free_events_in_list(ctx, a->events); + free_events_in_list(ctx, b->events); + + /* Check that INVITE glare works */ + INVITE(a, a_call, a_call->nh, TAG_END()); + INVITE(b, b_call, b_call->nh, TAG_END()); + + a->flags.n = 0, b->flags.n = 0; + run_ab_until(ctx, -1, until_ready2, -1, until_ready2); + + free_events_in_list(ctx, a->events); + free_events_in_list(ctx, b->events); + + if (print_headings) + printf("TEST NUA-7.8.1: PASSED\n"); + + + + /* ---------------------------------------------------------------------- */ + /* + A B + |---------BYE------->| + |<--------200--------| + */ + + if (print_headings) + printf("TEST NUA-7.8.2: terminate call\n"); + + BYE(a, a_call, a_call->nh, TAG_END()); + run_ab_until(ctx, -1, until_terminated, -1, until_terminated); + + /* + Transitions of A: + READY --(T2)--> TERMINATING: nua_bye() + TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state + */ + TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_bye); + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state); + TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */ + TEST_1(!e->next); + free_events_in_list(ctx, a->events); + + /* Transitions of B: + READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state + */ + TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_bye); + TEST(e->data->e_status, 200); + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state); + TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */ + TEST_1(!e->next); + free_events_in_list(ctx, b->events); + + if (print_headings) + printf("TEST NUA-7.8.2: PASSED\n"); + + nua_handle_destroy(a_call->nh), a_call->nh = NULL; + nua_handle_destroy(b_call->nh), b_call->nh = NULL; + + END(); +} + +int accept_and_attempt_reinvite(CONDITION_PARAMS) +{ + if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR))) + return 0; + + save_event_in_list(ctx, event, ep, call); + + if (event == nua_i_prack) { + INVITE(ep, call, nh, TAG_END()); + RESPOND(ep, call, nh, SIP_200_OK, + TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)), + TAG_END()); + } + else switch (callstate(tags)) { + case nua_callstate_received: + RESPOND(ep, call, nh, SIP_180_RINGING, + SIPTAG_REQUIRE_STR("100rel"), + TAG_END()); + return 0; + case nua_callstate_early: + return 0; + case nua_callstate_ready: + return 1; + case nua_callstate_terminated: + if (call) + nua_handle_destroy(call->nh), call->nh = NULL; + return 1; + default: + return 0; + } + return 0; +} + +/* + X INVITE + | | + |-------INVITE------>| + |<--------200--------| + |---------ACK------->| +*/ +int until_ready2(CONDITION_PARAMS) +{ + if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR))) + return 0; + + save_event_in_list(ctx, event, ep, call); + + if (event == nua_r_invite && status == 491) { + if (ep == &ctx->a && ++ctx->b.flags.n >= 2) ctx->b.running = 0; + if (ep == &ctx->b && ++ctx->a.flags.n >= 2) ctx->a.running = 0; + } + + switch (callstate(tags)) { + case nua_callstate_ready: + return ++ep->flags.n >= 2; + case nua_callstate_terminated: + if (call) + nua_handle_destroy(call->nh), call->nh = NULL; + return 1; + default: + return 0; + } +} + int test_reinvites(struct context *ctx) { int retval = 0; @@ -794,7 +996,10 @@ int test_reinvites(struct context *ctx) retval = test_call_hold(ctx); if (retval == 0) - retval |= test_reinvite(ctx); + retval = test_reinvite(ctx); + + if (retval == 0) + retval = test_reinvite2(ctx); if (print_headings && retval == 0) printf("TEST NUA-7: PASSED\n"); diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/test_cancel_bye.c b/libs/sofia-sip/libsofia-sip-ua/nua/test_cancel_bye.c index 71577509a2..ac1cf2f175 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/test_cancel_bye.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/test_cancel_bye.c @@ -118,6 +118,8 @@ int cancel_when_ringing(CONDITION_PARAMS) case nua_callstate_proceeding: CANCEL(ep, call, nh, TAG_END()); return 0; + case nua_callstate_ready: + return 1; case nua_callstate_terminated: return 1; default: @@ -673,6 +675,82 @@ int test_call_destroy_4(struct context *ctx) END(); } +/* Destroy when one INVITE is queued. */ +int test_call_destroy_5(struct context *ctx) +{ + BEGIN(); + + struct endpoint *a = &ctx->a, *b = &ctx->b; + struct call *a_call = a->call, *b_call = b->call; + struct event *e; + + if (print_headings) + printf("TEST NUA-5.7: destroy when re-INVITE is queued\n"); + + TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END())); + + INVITE(a, a_call, a_call->nh, + TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)), + NUTAG_AUTOACK(0), + SOATAG_USER_SDP_STR(a_call->sdp), + TAG_END()); + + INVITE(a, a_call, a_call->nh, TAG_END()); + + run_ab_until(ctx, -1, until_terminated, -1, destroy_when_completed); + + /* Client transitions: + INIT -(C1)-> CALLING: nua_invite(), ... + */ + TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state); + TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */ + TEST_1(is_offer_sent(e->data->e_tags)); + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite); + TEST(e->data->e_status, 180); + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state); + TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */ + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite); + TEST(e->data->e_status, 200); + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state); + TEST(callstate(e->data->e_tags), nua_callstate_completing); /* COMPLETING */ + TEST_1(is_answer_recv(e->data->e_tags)); + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_bye); + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite); + TEST(e->data->e_status, 481); + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state); + TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */ + TEST_1(!e->next); + + free_events_in_list(ctx, a->events); + nua_handle_destroy(a_call->nh), a_call->nh = NULL; + + /* + Server transitions: + INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state + RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state + EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state ... DESTROY + */ + TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite); + TEST(e->data->e_status, 100); + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state); + TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */ + TEST_1(is_offer_recv(e->data->e_tags)); + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state); + TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */ + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state); + TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */ + TEST_1(is_answer_sent(e->data->e_tags)); + TEST_1(!e->next); + + free_events_in_list(ctx, b->events); + nua_handle_destroy(b_call->nh), b_call->nh = NULL; + + if (print_headings) + printf("TEST NUA-5.7: PASSED\n"); + + END(); +} + int test_call_destroy(struct context *ctx) { struct endpoint *a = &ctx->a, *b = &ctx->b; @@ -685,10 +763,12 @@ int test_call_destroy(struct context *ctx) test_call_destroy_1(ctx) || test_call_destroy_2(ctx) || test_call_destroy_3(ctx) || - test_call_destroy_4(ctx); + test_call_destroy_4(ctx) || + test_call_destroy_5(ctx); } /* ======================================================================== */ + /* Early BYE A B @@ -731,12 +811,27 @@ int bye_when_ringing(CONDITION_PARAMS) } } +int bye_when_completing(CONDITION_PARAMS); + +static int ack_sent = 0; + +size_t count_acks(void *message, size_t len) +{ + if (strncasecmp(message, "ACK sip:", 8) == 0) + ack_sent++; + return len; +} + int test_early_bye(struct context *ctx) { BEGIN(); struct endpoint *a = &ctx->a, *b = &ctx->b; struct call *a_call = a->call, *b_call = b->call; struct event *e; + struct nat_filter *f = NULL; + + a_call->sdp = "m=audio 5008 RTP/AVP 8"; + b_call->sdp = "m=audio 5010 RTP/AVP 0 8"; if (print_headings) printf("TEST NUA-6.1: BYE call when ringing\n"); @@ -806,6 +901,119 @@ int test_early_bye(struct context *ctx) if (print_headings) printf("TEST NUA-6.1: PASSED\n"); +/* Early BYE 2 + + A B + |-------INVITE------>| + |<----100 Trying-----| + | | + |<----180 Ringing----| + |<-------200---------| + | | + |--------BYE-------->| + |<------200 OK-------| + |--------ACK-------->| + | | + | | +*/ + if (print_headings) + printf("TEST NUA-6.2: BYE call when completing\n"); + + if (ctx->nat) + TEST_1(f = test_nat_add_filter(ctx->nat, count_acks, nat_outbound)); + ack_sent = 0; + + TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END())); + + INVITE(a, a_call, a_call->nh, + TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)), + SOATAG_USER_SDP_STR(a_call->sdp), + NUTAG_AUTOACK(0), + TAG_END()); + + run_ab_until(ctx, -1, bye_when_completing, -1, accept_until_terminated); + + /* Client transitions: + INIT -(C1)-> CALLING: nua_invite(), nua_i_state + CALLING -(C2)-> PROCEEDING: nua_r_invite(180, nua_i_state, nua_cancel() + PROCEEDING -(C6b)-> TERMINATED: nua_r_invite(487), nua_i_state + */ + TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state); + TEST(callstate(e->data->e_tags), nua_callstate_calling); + TEST_1(is_offer_sent(e->data->e_tags)); + + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite); + TEST(e->data->e_status, 180); + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state); + TEST(callstate(e->data->e_tags), nua_callstate_proceeding); + + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite); + TEST(e->data->e_status, 200); + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state); + TEST(callstate(e->data->e_tags), nua_callstate_completing); + TEST_1(e = e->next); + + TEST_E(e->data->e_event, nua_r_bye); TEST(e->data->e_status, 200); + TEST_1(e->data->e_msg); + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state); + TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */ + TEST_1(!e->next); + + if (ctx->nat) { + while (ack_sent == 0) + su_root_step(ctx->root, 100); + TEST_1(ack_sent > 0); + TEST_1(test_nat_remove_filter(ctx->nat, f) == 0); + } + + /* + Server transitions: + INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state + RECEIVED -(S2a)-> EARLY: nua_respond(180), nua_i_state + EARLY -(S6b)--> TERMINATED: nua_i_cancel, nua_i_state + */ + TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite); + TEST(e->data->e_status, 100); + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state); + TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */ + TEST_1(is_offer_recv(e->data->e_tags)); + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state); + TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */ + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state); + TEST(callstate(e->data->e_tags), nua_callstate_completed); /* EARLY */ + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_bye); + TEST(e->data->e_status, 200); + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state); + TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */ + TEST_1(!e->next); + + free_events_in_list(ctx, a->events); + nua_handle_destroy(a_call->nh), a_call->nh = NULL; + + free_events_in_list(ctx, b->events); + nua_handle_destroy(b_call->nh), b_call->nh = NULL; + + if (print_headings) + printf("TEST NUA-6.2: PASSED\n"); + END(); } +int bye_when_completing(CONDITION_PARAMS) +{ + if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR))) + return 0; + + save_event_in_list(ctx, event, ep, call); + + switch (callstate(tags)) { + case nua_callstate_completing: + ack_sent = 0; + BYE(ep, call, nh, TAG_END()); + return 0; + case nua_callstate_terminated: + return 1; + default: + return 0; + } +} diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/test_nua.h b/libs/sofia-sip/libsofia-sip-ua/nua/test_nua.h index 0ad5cb08e4..cab1373270 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/test_nua.h +++ b/libs/sofia-sip/libsofia-sip-ua/nua/test_nua.h @@ -166,12 +166,11 @@ struct context struct eventlist specials[1]; /* State flags for complex scenarios */ - union { - struct { - unsigned bit0:1, bit1:1, bit2:1, bit3:1; - unsigned bit4:1, bit5:1, bit6:1, bit7:1; - } b; + struct { unsigned n; + unsigned bit0:1, bit1:1, bit2:1, bit3:1; + unsigned bit4:1, bit5:1, bit6:1, bit7:1; + unsigned :0; } flags; } a, b, c; @@ -215,6 +214,7 @@ int save_until_special(CONDITION_PARAMS); int until_terminated(CONDITION_PARAMS); int until_ready(CONDITION_PARAMS); int accept_call(CONDITION_PARAMS); +int cancel_when_ringing(CONDITION_PARAMS); int accept_notify(CONDITION_PARAMS); diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/test_ops.c b/libs/sofia-sip/libsofia-sip-ua/nua/test_ops.c index 1b82885d81..ec7700975c 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/test_ops.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/test_ops.c @@ -272,21 +272,21 @@ void run_abc_until(struct context *ctx, a->last_event = -1; a->running = a_condition != NULL && a_condition != save_events; a->running |= a_event != -1; - a->flags.n = 0; + memset(&a->flags, 0, sizeof a->flags); b->next_event = b_event; b->next_condition = b_condition; b->last_event = -1; b->running = b_condition != NULL && b_condition != save_events; b->running |= b_event != -1; - b->flags.n = 0; + memset(&b->flags, 0, sizeof b->flags); c->next_event = c_event; c->next_condition = c_condition; c->last_event = -1; c->running = c_condition != NULL && c_condition != save_events; c->running |= c_event != -1; - c->flags.n = 0; + memset(&c->flags, 0, sizeof c->flags); for (; a->running || b->running || c->running;) { su_root_step(ctx->root, 1000); diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.c b/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.c index b184f1a37b..861ebb3fc2 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.c @@ -228,6 +228,7 @@ test_proxy_init(su_root_t *root, struct proxy *proxy) URL_STRING_MAKE("sip:0.0.0.0:*"), NULL, NULL, NTATAG_UA(0), + NTATAG_CANCEL_487(0), NTATAG_SERVER_RPORT(1), NTATAG_CLIENT_RPORT(1), TAG_NEXT(proxy->tags)); diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/test_sip_events.c b/libs/sofia-sip/libsofia-sip-ua/nua/test_sip_events.c index 90524a58ed..34b5ee85fe 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/test_sip_events.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/test_sip_events.c @@ -64,15 +64,15 @@ int save_until_notified(CONDITION_PARAMS) int save_until_notified_and_responded(CONDITION_PARAMS) { save_event_in_list(ctx, event, ep, call); - if (event == nua_i_notify) ep->flags.b.bit0 = 1; + if (event == nua_i_notify) ep->flags.bit0 = 1; if (event == nua_r_subscribe || event == nua_r_unsubscribe) { if (status >= 300) return 1; else if (status >= 200) - ep->flags.b.bit1 = 1; + ep->flags.bit1 = 1; } - return ep->flags.b.bit0 && ep->flags.b.bit1; + return ep->flags.bit0 && ep->flags.bit1; } diff --git a/libs/sofia-sip/libsofia-sip-ua/su/su_pthread_port.c b/libs/sofia-sip/libsofia-sip-ua/su/su_pthread_port.c index e5471ff857..5f2b0a9b0a 100644 --- a/libs/sofia-sip/libsofia-sip-ua/su/su_pthread_port.c +++ b/libs/sofia-sip/libsofia-sip-ua/su/su_pthread_port.c @@ -422,6 +422,7 @@ void su_pthread_port_wait(su_clone_r rclone) pthread_mutex_unlock(mom->mutex); pthread_mutex_destroy(mom->mutex); + pthread_cond_destroy(mom->cv); } struct su_pthread_port_execute