Author: mikej Date: Fri Apr 13 10:33:30 2007 New Revision: 4923 Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/iptsec/Doxyfile freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_client.c freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_client_plugin.h freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nta/nta.c freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_common.c freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.h freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_extension.c freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_notifier.c freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.c freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.h freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_publish.c freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_register.c freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_registrar.c freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.h freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_subnotref.c freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_tag.c freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua.h freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua_tag.h freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_100rel.c freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_basic_call.c freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_call_reject.c freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_cancel_bye.c freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_nua.c freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_offer_answer.c freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.c freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.h freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_register.c freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_session_timer.c freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_simple.c freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/sdp/run_test_sdp freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/sip/sip_feature.c freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/sip/torture_sip.c Log: sync with current darcs tree Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/iptsec/Doxyfile ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/iptsec/Doxyfile (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/iptsec/Doxyfile Fri Apr 13 10:33:30 2007 @@ -19,3 +19,6 @@ GENERATE_TAGFILE = ../docs/iptsec.doxytags ALIASES += + +PREDEFINED += SOFIA_EXTEND_AUTH_CLIENT=1 + Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_client.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_client.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/iptsec/auth_client.c Fri Apr 13 10:33:30 2007 @@ -31,6 +31,8 @@ #include "config.h" +#define SOFIA_EXTEND_AUTH_CLIENT 1 + #include <sofia-sip/su.h> #include <sofia-sip/su_md5.h> @@ -77,9 +79,7 @@ char const *user, char const *pass); -static int ca_clear_credentials(auth_client_t *ca, - char const *scheme, - char const *realm); +static int ca_clear_credentials(auth_client_t *ca); /** Initialize authenticators. @@ -340,8 +340,8 @@ * @param[in] user username * @param[in] pass password * - * @retval number of matching clients - * @retval 0 when no matching client was found + * @retval number of updated clients + * @retval 0 when no client was updated * @retval -1 upon an error */ int auc_all_credentials(auth_client_t **auc_list, @@ -375,6 +375,9 @@ char const *user, char const *pass) { + char *new_user, *new_pass; + char *old_user, *old_pass; + assert(ca); if (!ca || !ca->ca_scheme || !ca->ca_realm) @@ -384,12 +387,24 @@ (realm != NULL && strcmp(realm, ca->ca_realm))) return -1; - ca->ca_user = su_strdup(ca->ca_home, user); - ca->ca_pass = su_strdup(ca->ca_home, pass); + old_user = ca->ca_user, old_pass = ca->ca_pass; + + if (str0cmp(user, old_user) == 0 && str0cmp(pass, old_pass) == 0) + return 0; + + new_user = su_strdup(ca->ca_home, user); + new_pass = su_strdup(ca->ca_home, pass); - if (!ca->ca_user || !ca->ca_pass) + if (!new_user || !new_pass) return -1; + ca->ca_user = new_user, ca->ca_pass = new_pass; + if (AUTH_CLIENT_IS_EXTENDED(ca)) + ca->ca_clear = 0; + + su_free(ca->ca_home, old_user); + su_free(ca->ca_home, old_pass); + return 1; } @@ -416,12 +431,15 @@ char *u, *p; if (!ca->ca_user || !ca->ca_pass) continue; + if (AUTH_CLIENT_IS_EXTENDED(ca) && ca->ca_clear) + continue; if (!ca->ca_scheme[0] || strcmp(ca->ca_scheme, d->ca_scheme)) continue; if (!ca->ca_realm[0] || strcmp(ca->ca_realm, d->ca_realm)) continue; - if (d->ca_user && strcmp(d->ca_user, ca->ca_user) == 0 && + if (!(AUTH_CLIENT_IS_EXTENDED(d) && d->ca_clear) && + d->ca_user && strcmp(d->ca_user, ca->ca_user) == 0 && d->ca_pass && strcmp(d->ca_pass, ca->ca_pass) == 0) { retval++; break; @@ -435,6 +453,9 @@ if (d->ca_user) su_free(d->ca_home, (void *)d->ca_user); if (d->ca_pass) su_free(d->ca_home, (void *)d->ca_pass); d->ca_user = u, d->ca_pass = p; + if (AUTH_CLIENT_IS_EXTENDED(d)) + d->ca_clear = 0; + retval++; break; } @@ -457,13 +478,24 @@ * @retval -1 upon an error */ int auc_clear_credentials(auth_client_t **auc_list, - char const *scheme, - char const *realm) + char const *scheme, + char const *realm) { int retval = 0; + int match; for (; *auc_list; auc_list = &(*auc_list)->ca_next) { - int match = ca_clear_credentials(*auc_list, scheme, realm); + auth_client_t *ca = *auc_list; + + if (!AUTH_CLIENT_IS_EXTENDED(ca)) + continue; + + if ((scheme != NULL && strcasecmp(scheme, ca->ca_scheme)) || + (realm != NULL && strcmp(realm, ca->ca_realm))) + continue; + + match = ca->ca_auc->auc_clear(*auc_list); + if (match < 0) { retval = -1; break; @@ -476,21 +508,14 @@ } static -int ca_clear_credentials(auth_client_t *ca, - char const *scheme, - char const *realm) +int ca_clear_credentials(auth_client_t *ca) { - assert(ca); - - if (!ca || !ca->ca_scheme || !ca->ca_realm) - return -1; + assert(ca); assert(ca->ca_home->suh_size >= (int)(sizeof *ca)); - if ((scheme != NULL && strcasecmp(scheme, ca->ca_scheme)) || - (realm != NULL && strcmp(realm, ca->ca_realm))) + if (!ca) return -1; - su_free(ca->ca_home, (void *)ca->ca_user), ca->ca_user = NULL; - su_free(ca->ca_home, (void *)ca->ca_pass), ca->ca_pass = NULL; + ca->ca_clear = 1; return 1; } @@ -513,6 +538,8 @@ for (ca = *auc_list; ca; ca = ca->ca_next) { if (!ca->ca_user || !ca->ca_pass || !ca->ca_credential_class) return 0; + if (AUTH_CLIENT_IS_EXTENDED(ca) && ca->ca_clear) + return 0; } return 1; @@ -570,8 +597,11 @@ if (!ca->ca_auc) continue; - if (ca->ca_auc->auc_authorize(ca, home, method, url, body, &h) < 0 - || msg_header_insert(msg, pub, h) < 0) + if (ca->ca_auc->auc_authorize(ca, home, method, url, body, &h) < 0) + return -1; + if (h == NULL) + continue; + if (msg_header_insert(msg, pub, h) < 0) return -1; } @@ -639,14 +669,15 @@ msg_payload_t const *body, msg_header_t **); -const auth_client_plugin_t ca_basic_plugin = +static const auth_client_plugin_t ca_basic_plugin = { /* auc_plugin_size: */ sizeof ca_basic_plugin, /* auc_size: */ sizeof (auth_client_t), /* auc_name: */ "Basic", /* auc_challenge: */ NULL, /* auc_authorize: */ auc_basic_authorization, - /* auc_info: */ NULL + /* auc_info: */ NULL, + /* auc_clear: */ ca_clear_credentials }; /**Create a basic authorization header. @@ -683,6 +714,9 @@ if (user == NULL || pass == NULL) return -1; + if (AUTH_CLIENT_IS_EXTENDED(ca) && ca->ca_clear) + return 0; + ulen = strlen(user), plen = strlen(pass), uplen = ulen + 1 + plen; b64len = BASE64_SIZE(uplen); basiclen = strlen("Basic ") + b64len; @@ -746,7 +780,8 @@ /* auc_name: */ "Digest", /* auc_challenge: */ auc_digest_challenge, /* auc_authorize: */ auc_digest_authorization, - /* auc_info: */ auc_digest_info + /* auc_info: */ auc_digest_info, + /* auc_clear: */ ca_clear_credentials }; /** Store a digest authorization challenge. @@ -826,9 +861,9 @@ * sip_authorization_class or sip_proxy_authorization_class, as well as * http_authorization_class or http_proxy_authorization_class. * - * @return - * Returns a pointer to newly created authorization header, or NULL upon an - * error. + * @retval 1 when authorization headers has been created + * @retval 0 when there is no credentials + * @retval -1 upon an error */ static int auc_digest_authorization(auth_client_t *ca, @@ -854,6 +889,9 @@ auth_response_t ar[1] = {{ 0 }}; char ncount[17]; + if (!user || !pass || (AUTH_CLIENT_IS_EXTENDED(ca) && ca->ca_clear)) + return 0; + ar->ar_size = sizeof(ar); ar->ar_username = user; ar->ar_realm = ac->ac_realm; Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_client_plugin.h ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_client_plugin.h (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/iptsec/sofia-sip/auth_client_plugin.h Fri Apr 13 10:33:30 2007 @@ -29,6 +29,9 @@ /**@file sofia-sip/auth_client_plugin.h * @brief Client-side plugin interface for authentication * + * @note For extensions in 1.12.6 or later, + * you have to #define SOFIA_EXTEND_AUTH_CLIENT to 1. + * * @author Pekka Pessi <Pekka.Pessi@nokia.com> * * @date Created: Fri May 19 16:18:21 EEST 2006 @@ -58,6 +61,10 @@ char *ca_pass; msg_hclass_t *ca_credential_class; + +#if SOFIA_EXTEND_AUTH_CLIENT + int ca_clear; +#endif }; struct auth_client_plugin @@ -81,8 +88,19 @@ /** Store nextnonce from Authentication-Info or Proxy-Authentication-Info. */ int (*auc_info)(auth_client_t *ca, msg_auth_info_t const *ai); + +#if SOFIA_EXTEND_AUTH_CLIENT + /** Clear credentials (user/pass). @NEW_1_12_6 */ + int (*auc_clear)(auth_client_t *ca); +#endif }; +/** Check if authentication client has been extended. @NEW_1_12_6 */ +#define AUTH_CLIENT_IS_EXTENDED(ca) \ + ((ca)->ca_auc->auc_plugin_size > \ + offsetof(auth_client_plugin_t, auc_clear) \ + && (ca)->ca_auc->auc_clear != NULL) + SOFIA_END_DECLS #endif /* !defined AUTH_CLIENT_PLUGIN_H */ Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nta/nta.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nta/nta.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nta/nta.c Fri Apr 13 10:33:30 2007 @@ -8016,7 +8016,7 @@ { nta_agent_t *sa = orq->orq_agent; short orq_status = orq->orq_status; - int internal = sip == NULL || (sip->sip_flags & NTA_INTERNAL_MSG) == 0; + int internal = sip == NULL || (sip->sip_flags & NTA_INTERNAL_MSG) != 0; if (status < 100) status = 100; Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_common.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_common.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_common.c Fri Apr 13 10:33:30 2007 @@ -216,6 +216,50 @@ return su_strdup(home, str); } +/** Check if event is a request that can be responded with nua_respond(). + * + * Note that if event status is 200 or greater, it already has been + * responded. This function is provided for compatibility with future + * versions of nua. An unknown event can always be handled in the event + * callback like this: + * @code + * switch (event) { + * ... + * default: + * if (status < 200 && nua_event_is_incoming_request(event)) + * nua_respond(nh, SIP_501_NOT_IMPLEMENTED, + * NUTAG_WITH_THIS(nua), TAG_END()); + * if (hmagic == NULL) + * nua_handle_destroy(nh); + * return; + * ... + * @endcode + * + * @sa #nua_event_t, nua_respond() + * + * @NEW_1_12_6 + */ +int nua_event_is_incoming_request(nua_event_t event) +{ + switch (event) { + case nua_i_invite: return 1; + case nua_i_cancel: return 1; + case nua_i_register: return 1; + case nua_i_bye: return 1; + case nua_i_options: return 1; + case nua_i_refer: return 1; + case nua_i_publish: return 1; + case nua_i_prack: return 1; + case nua_i_info: return 1; + case nua_i_update: return 1; + case nua_i_message: return 1; + case nua_i_subscribe: return 1; + case nua_i_notify: return 1; + case nua_i_method: return 1; + default: return 0; + } +} + /** Get name for a NUA event. */ char const *nua_event_name(nua_event_t event) { Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c Fri Apr 13 10:33:30 2007 @@ -443,24 +443,6 @@ ds->ds_terminating = 0; } - -/**@internal - * Set expiration time. - */ -void nua_dialog_usage_set_expires(nua_dialog_usage_t *du, - unsigned delta) -{ - if (delta) { - sip_time_t now = sip_now(), expires = now + delta; - if (expires < now) - expires = SIP_TIME_MAX; - du->du_expires = expires; - nua_dialog_usage_set_refresh(du, delta); - } - else - du->du_expires = 0, du->du_refresh = 0; -} - /**@internal * Set refresh value suitably. * @@ -514,6 +496,15 @@ du->du_refresh = target; } +/** Set absolute refresh time */ +void nua_dialog_usage_refresh_at(nua_dialog_usage_t *du, + sip_time_t target) +{ + SU_DEBUG_7(("nua(): refresh %s after %lu seconds\n", + nua_dialog_usage_name(du), target - sip_now())); + du->du_refresh = target; +} + /**@internal Do not refresh. */ void nua_dialog_usage_reset_refresh(nua_dialog_usage_t *du) { @@ -561,8 +552,13 @@ return 1; } -/** (Gracefully) terminate usage */ -void nua_dialog_usage_shutdown(nua_owner_t *owner, +/** (Gracefully) terminate usage. + * + * @retval >0 shutdown done + * @retval 0 shutdown in progress + * @retval <0 try again later + */ +int nua_dialog_usage_shutdown(nua_owner_t *owner, nua_dialog_state_t *ds, nua_dialog_usage_t *du) { @@ -570,6 +566,8 @@ du->du_refresh = 0; du->du_shutdown = 1; assert(du->du_class->usage_shutdown); - du->du_class->usage_shutdown(owner, ds, du); + return du->du_class->usage_shutdown(owner, ds, du); } + else + return 200; } Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.h ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.h (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.h Fri Apr 13 10:33:30 2007 @@ -112,6 +112,7 @@ unsigned sr_event:1; /**< Reported to application */ unsigned sr_initial:1; /**< Handle was created by this request */ unsigned sr_add_contact:1; /**< Add Contact header to the response */ + unsigned sr_target_refresh:1; /**< Refresh target */ unsigned sr_terminating:1; /**< Terminate usage after final response */ unsigned sr_gracefully:1; /**< Terminate usage gracefully */ @@ -299,6 +300,7 @@ unsigned cr_auto:1; /**< Request was generated by stack */ unsigned cr_has_contact:1; /**< Request has user Contact */ unsigned cr_contactize:1; /**< Request needs Contact */ + unsigned cr_dialog:1; /**< Request can initiate dialog */ /* Current state */ unsigned cr_challenged:1; /**< Request was challenged */ @@ -396,7 +398,6 @@ * Non-zero if the usage is established, SIP_TIME_MAX if there no * expiration time. */ - sip_time_t du_expires; sip_time_t du_refresh; /**< When to refresh */ @@ -439,13 +440,14 @@ int nua_dialog_shutdown(nua_owner_t *owner, nua_dialog_state_t *ds); -void nua_dialog_usage_set_expires(nua_dialog_usage_t *du, unsigned delta); - void nua_dialog_usage_set_refresh(nua_dialog_usage_t *du, unsigned delta); void nua_dialog_usage_refresh_range(nua_dialog_usage_t *du, unsigned min, unsigned max); +void nua_dialog_usage_refresh_at(nua_dialog_usage_t *du, + sip_time_t target); + void nua_dialog_usage_reset_refresh(nua_dialog_usage_t *du); void nua_dialog_usage_refresh(nua_owner_t *owner, @@ -453,9 +455,9 @@ nua_dialog_usage_t *du, sip_time_t now); -void nua_dialog_usage_shutdown(nua_owner_t *owner, - nua_dialog_state_t *ds, - nua_dialog_usage_t *du); +int nua_dialog_usage_shutdown(nua_owner_t *owner, + nua_dialog_state_t *ds, + nua_dialog_usage_t *du); static inline int nua_dialog_is_established(nua_dialog_state_t const *ds) Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_extension.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_extension.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_extension.c Fri Apr 13 10:33:30 2007 @@ -75,7 +75,7 @@ { /* create_dialog */ 0, /* in_dialog */ 0, - /* target_refresh */ 0 + /* target_refresh */ 1, }, /* nua_method_client_template */ NULL, /* nua_method_client_init */ NULL, @@ -146,7 +146,7 @@ SIP_METHOD_UNKNOWN, nua_i_method, /* Event */ { - 0, /* Do not create dialog */ + 1, /* Do create dialog */ 0, /* Can be an initial request */ 1, /* Perhaps a target refresh request? */ 1, /* Add a contact? */ Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_notifier.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_notifier.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_notifier.c Fri Apr 13 10:33:30 2007 @@ -135,7 +135,7 @@ * (or SIPTAG_ALLOW_EVENTS() or SIPTAG_ALLOW_EVENTS_STR()). The application * can decide whether to accept the SUBSCRIBE request or reject it. The * nua_response() call responding to a SUBSCRIBE request must have - * NUTAG_WITH() (or NUTAG_WITH_CURRENT()/NUTAG_WITH_SAVED()) tag. + * NUTAG_WITH() (or NUTAG_WITH_THIS()/NUTAG_WITH_SAVED()) tag. * * If the application accepts the SUBSCRIBE request, it must immediately * send an initial NOTIFY establishing the dialog. This is because the @@ -690,9 +690,15 @@ SIPTAG_EVENT(du ? du->du_event : NULL), TAG_NEXT(tags)); - if (nu && nu->nu_requested && du->du_cr == cr) - /* Re-SUBSCRIBEd while NOTIFY was in progress, resend NOTIFY */ - nua_client_resend_request(cr, 0); + if (du && du->du_cr == cr && !cr->cr_terminated) { + if (nu->nu_requested) { + /* Re-SUBSCRIBEd while NOTIFY was in progress, resend NOTIFY */ + nua_client_resend_request(cr, 0); + } + else if (nu->nu_expires) { + nua_dialog_usage_refresh_at(du, nu->nu_expires); + } + } return 0; } @@ -710,7 +716,7 @@ if (cr) { int terminating = 0; - if (du->du_expires && du->du_expires <= now) + if (nu->nu_expires && nu->nu_expires <= now) terminating = 1; else if (nu->nu_requested && nu->nu_requested <= now) terminating = 1; Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.c Fri Apr 13 10:33:30 2007 @@ -149,9 +149,10 @@ NHP_SET(nhp, auto_ack, 1); NHP_SET(nhp, invite_timeout, 120); - NHP_SET(nhp, session_timer, 1800); + nhp->nhp_session_timer = 1800; + nhp->nhp_refresher = nua_no_refresher; + NHP_SET(nhp, min_se, 120); - NHP_SET(nhp, refresher, nua_no_refresher); NHP_SET(nhp, update_refresh, 0); NHP_SET(nhp, message_enable, 1); @@ -1503,6 +1504,11 @@ #define TIF(TAG, pref) \ TAG_IF(nhp->nhp_set.nhb_##pref, TAG(nhp->nhp_##pref)) + /* Include tag in the list returned to user + * if it has been earlier set (by user) returning default parameters */ +#define TIFD(TAG, pref) \ + TAG_IF(nh == dnh || nhp->nhp_set.nhb_##pref, TAG(nhp->nhp_##pref)) + /* Include string tag made out of SIP header * if it has been earlier set (by user) */ #define TIF_STR(TAG, pref) \ @@ -1540,9 +1546,9 @@ TIF(NUTAG_AUTOACK, auto_ack), TIF(NUTAG_INVITE_TIMER, invite_timeout), - TIF(NUTAG_SESSION_TIMER, session_timer), + TIFD(NUTAG_SESSION_TIMER, session_timer), TIF(NUTAG_MIN_SE, min_se), - TIF(NUTAG_SESSION_REFRESHER, refresher), + TIFD(NUTAG_SESSION_REFRESHER, refresher), TIF(NUTAG_UPDATE_REFRESH, update_refresh), TIF(NUTAG_ENABLEMESSAGE, message_enable), Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.h ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.h (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.h Fri Apr 13 10:33:30 2007 @@ -169,8 +169,8 @@ unsigned nhb_allow:1; unsigned nhb_supported:1; - unsigned nhb_allow_events:1; unsigned :0; /* at most 32 bits ... */ + unsigned nhb_allow_events:1; unsigned nhb_user_agent:1; unsigned nhb_organization:1; @@ -226,4 +226,9 @@ (NHP_ISSET((nh)->nh_prefs, pref) && \ (nh)->nh_nua->nua_dhandle->nh_prefs != (nh)->nh_prefs) +/* Check if preference has been set by applicationx */ +#define NUA_PISSET(nua, nh, pref) \ + (NHP_ISSET((nua)->nua_dhandle->nh_prefs, pref) || \ + ((nh) && NHP_ISSET((nh)->nh_prefs, pref))) + #endif /* NUA_PARAMS_H */ Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_publish.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_publish.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_publish.c Fri Apr 13 10:33:30 2007 @@ -443,7 +443,7 @@ * events with nua_set_params() tag NUTAG_ALLOW_EVENTS(). * * The nua_response() call responding to a PUBLISH request must have - * NUTAG_WITH() (or NUTAG_WITH_CURRENT()/NUTAG_WITH_SAVED()) tag. Note that + * NUTAG_WITH() (or NUTAG_WITH_THIS()/NUTAG_WITH_SAVED()) tag. Note that * a successful response to PUBLISH @b MUST include @Expires and @SIPETag * headers. * Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_register.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_register.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_register.c Fri Apr 13 10:33:30 2007 @@ -881,7 +881,7 @@ if (mindelta == SIP_TIME_MAX) mindelta = 3600; - nua_dialog_usage_set_expires(du, mindelta); + nua_dialog_usage_set_refresh(du, mindelta); /* RFC 3608 Section 6.1 Procedures at the UA @@ -935,7 +935,7 @@ nua_registration_set_ready(nr, 1); } else if (du) { - nua_dialog_usage_set_expires(du, 0); + nua_dialog_usage_set_refresh(du, 0); su_free(nh->nh_home, nr->nr_route); nr->nr_route = NULL; Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_registrar.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_registrar.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_registrar.c Fri Apr 13 10:33:30 2007 @@ -60,7 +60,7 @@ * the REGISTER method with NUTAG_ALLOW() tag. * * The nua_response() call responding to a REGISTER request must have - * NUTAG_WITH() (or NUTAG_WITH_CURRENT()/NUTAG_WITH_SAVED()) tag. Note that + * NUTAG_WITH() (or NUTAG_WITH_THIS()/NUTAG_WITH_SAVED()) tag. Note that * a successful response to REGISTER @b MUST include the @Contact header * bound to the the AoR URI (in @To header). * Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c Fri Apr 13 10:33:30 2007 @@ -149,14 +149,23 @@ unsigned ss_precondition:1; /**< Precondition required */ - unsigned ss_timer_set:1; /**< We have active session timer. */ - unsigned ss_reporting:1; /**< True if reporting state */ unsigned : 0; - - unsigned ss_session_timer; /**< Value of Session-Expires (delta) */ - unsigned ss_min_se; /**< Minimum session expires */ - enum nua_session_refresher ss_refresher; /**< none, local or remote */ + + struct session_timer { + unsigned interval; /**< Negotiated expiration time */ + enum nua_session_refresher refresher; /**< Our Negotiated role */ + + struct { + unsigned expires, defaults; /**< Value of Session-Expires (delta) */ + unsigned min_se; /**< Minimum session expires */ + /** none, local or remote */ + enum nua_session_refresher refresher; + unsigned supported:1, require:1, :0; + } local, remote; + + unsigned timer_set:1; /**< We have active session timer. */ + } ss_timer[1]; char const *ss_reason; /**< Reason for termination. */ @@ -204,11 +213,16 @@ nua_dialog_state_t *ds, nua_dialog_usage_t *du) { + nua_session_usage_t *ss = nua_dialog_usage_private(du); + if (ds->ds_has_session) return -1; ds->ds_has_session = 1; ds->ds_got_session = 1; + ss->ss_timer->local.refresher = nua_any_refresher; + ss->ss_timer->remote.refresher = nua_any_refresher; + return 0; } @@ -297,19 +311,29 @@ int nua_stack_prack(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags); -static void session_timer_preferences(nua_session_usage_t *ss, - unsigned expires, - unsigned min_se, - enum nua_session_refresher refresher); - -static int session_timer_is_supported(nua_handle_t const *nh); - -static int prefer_session_timer(nua_handle_t const *nh); - -static int use_session_timer(nua_session_usage_t *ss, int uas, int always, - msg_t *msg, sip_t *); -static int init_session_timer(nua_session_usage_t *ss, sip_t const *, int refresher); -static void set_session_timer(nua_session_usage_t *ss); +static int session_timer_is_supported(struct session_timer const *t); + +static void session_timer_preferences(struct session_timer *t, + sip_t const *sip, + sip_supported_t const *supported, + unsigned expires, int isset, + enum nua_session_refresher refresher, + unsigned min_se); + +static void session_timer_store(struct session_timer *t, + sip_t const *sip); + +static int session_timer_check_min_se(msg_t *msg, sip_t *sip, + sip_t const *request, + unsigned long min_se); + +static int session_timer_add_headers(struct session_timer *t, + int initial, + msg_t *msg, sip_t *sip); + +static void session_timer_negotiate(struct session_timer *t); + +static void session_timer_set(nua_session_usage_t *ss); static int session_timer_check_restart(nua_client_request_t *cr, int status, char const *phrase, @@ -551,6 +575,7 @@ { nua_handle_t *nh = cr->cr_owner; nua_dialog_usage_t *du; + nua_session_usage_t *ss; cr->cr_usage = du = nua_dialog_usage_for_session(nh->nh_ds); /* Errors returned by nua_invite_client_init() @@ -573,16 +598,22 @@ } else du = nua_dialog_usage_add(nh, nh->nh_ds, nua_session_usage, NULL); + if (!du) return -1; if (nua_client_bind(cr, du) < 0) return nua_client_return(cr, 900, "INVITE already in progress", msg); - session_timer_preferences(nua_dialog_usage_private(du), + ss = nua_dialog_usage_private(du); + + session_timer_preferences(ss->ss_timer, + sip, + NH_PGET(nh, supported), NH_PGET(nh, session_timer), - NH_PGET(nh, min_se), - NH_PGET(nh, refresher)); + NUA_PISSET(nh->nh_nua, nh, session_timer), + NH_PGET(nh, refresher), + NH_PGET(nh, min_se)); cr->cr_neutral = 0; @@ -608,12 +639,13 @@ if (invite_timeout == 0) invite_timeout = UINT_MAX; /* Send CANCEL if we don't get response within timeout*/ - nua_dialog_usage_set_expires(du, invite_timeout); + /* nua_dialog_usage_set_expires(du, invite_timeout); Xyzzy */ nua_dialog_usage_set_refresh(du, 0); /* Add session timer headers */ - if (session_timer_is_supported(nh)) - use_session_timer(ss, 0, prefer_session_timer(nh), msg, sip); + if (session_timer_is_supported(ss->ss_timer)) + session_timer_add_headers(ss->ss_timer, ss->ss_state == nua_callstate_init, + msg, sip); ss->ss_100rel = NH_PGET(nh, early_media); ss->ss_precondition = sip_has_feature(sip->sip_require, "precondition"); @@ -672,7 +704,6 @@ int status, char const *phrase, sip_t const *sip) { - 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); @@ -682,8 +713,10 @@ else if (status < 300) { du->du_ready = 1; - init_session_timer(ss, sip, NH_PGET(nh, refresher)); - set_session_timer(ss); + if (session_timer_is_supported(ss->ss_timer)) + session_timer_store(ss->ss_timer, sip); + + session_timer_set(ss); } return nua_session_client_response(cr, status, phrase, sip); @@ -1263,42 +1296,37 @@ nua_client_request_t const *cr = du->du_cr; nua_server_request_t const *sr; - assert(cr); - if (ss->ss_state >= nua_callstate_terminating || - /* No INVITE template */ - cr == NULL || /* INVITE is in progress or being authenticated */ - cr->cr_orq || cr->cr_wait_for_cred) + (cr && (cr->cr_orq || cr->cr_wait_for_cred))) return; - /* UPDATE in progress or being authenticated */ + /* UPDATE has been queued */ for (cr = ds->ds_cr; cr; cr = cr->cr_next) if (cr->cr_method == sip_method_update) return; - /* INVITE or UPDATE in progress */ + /* INVITE or UPDATE in progress on server side */ for (sr = ds->ds_sr; sr; sr = sr->sr_next) if (sr->sr_usage == du && (sr->sr_method == sip_method_invite || sr->sr_method == sip_method_update)) return; - if (!ss->ss_refresher) { - if (du->du_expires == 0 || now < du->du_expires) - /* Refresh contact & route set using re-INVITE */ - nua_client_resend_request(du->du_cr, 0); - else { - ss->ss_reason = "SIP;cause=408;text=\"Session timeout\""; - nua_stack_bye(nh->nh_nua, nh, nua_r_bye, NULL); - } + if (ss->ss_timer->refresher == nua_remote_refresher) { + ss->ss_reason = "SIP;cause=408;text=\"Session timeout\""; + nua_stack_bye(nh->nh_nua, nh, nua_r_bye, NULL); + return; } else if (NH_PGET(nh, update_refresh)) { nua_stack_update(nh->nh_nua, nh, nua_r_update, NULL); } - else { + else if (du->du_cr) { nua_client_resend_request(du->du_cr, 0); } + else { + nua_stack_invite(nh->nh_nua, nh, nua_r_invite, NULL); + } } /** @interal Shut down session usage. @@ -1787,8 +1815,6 @@ sip_t const *request = sr->sr_request.sip; - unsigned min = NH_PGET(nh, min_se); - if (!sr->sr_initial) sr->sr_usage = nua_dialog_usage_get(nh->nh_ds, nua_session_usage, NULL); @@ -1817,21 +1843,15 @@ } if (request->sip_session_expires && - nta_check_session_expires(NULL, request, min, TAG_END())) { - sip_min_se_t *min_se, min_se0[1]; - - min_se = sip_min_se_init(min_se0); - min_se->min_delta = min; - - if (request->sip_min_se && request->sip_min_se->min_delta > min) - min_se = request->sip_min_se; - - sip_add_dup(msg, sip, (sip_header_t *)min_se); - - return SR_STATUS1(sr, SIP_422_SESSION_TIMER_TOO_SMALL); + sip_has_feature(NH_PGET(nh, supported), "timer") && + session_timer_check_min_se(msg, sip, request, NH_PGET(nh, min_se))) { + if (sip->sip_min_se) + return SR_STATUS1(sr, SIP_422_SESSION_TIMER_TOO_SMALL); + else + return SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR); } - session_get_description(sr->sr_request.sip, &sr->sr_sdp, &sr->sr_sdp_len); + session_get_description(request, &sr->sr_sdp, &sr->sr_sdp_len); return 0; } @@ -1885,14 +1905,7 @@ if (ss->ss_precondition) ss->ss_100rel = 1; - session_timer_preferences(ss, - NH_PGET(nh, session_timer), - NH_PGET(nh, min_se), - NH_PGET(nh, refresher)); - - /* Session Timer negotiation */ - if (sip_has_supported(NH_PGET(nh, supported), "timer")) - init_session_timer(ss, request, ss->ss_refresher); + session_timer_store(ss->ss_timer, request); assert(ss->ss_state >= nua_callstate_ready || ss->ss_state == nua_callstate_init); @@ -2043,9 +2056,18 @@ return 0; } - if (ss->ss_refresher && 200 <= sr->sr_status && sr->sr_status < 300) - if (session_timer_is_supported(nh)) - use_session_timer(ss, 1, 1, msg, sip); + if (200 <= sr->sr_status && sr->sr_status < 300) { + session_timer_preferences(ss->ss_timer, + sip, + NH_PGET(nh, supported), + NH_PGET(nh, session_timer), + NUA_PISSET(nh->nh_nua, nh, session_timer), + NH_PGET(nh, refresher), + NH_PGET(nh, min_se)); + + if (session_timer_is_supported(ss->ss_timer)) + session_timer_add_headers(ss->ss_timer, 0, msg, sip); + } return nua_base_server_respond(sr, tags); } @@ -2249,7 +2271,7 @@ nua_stack_event(nh->nh_nua, nh, msg, nua_i_ack, SIP_200_OK, NULL); signal_call_state_change(nh, ss, 200, "OK", nua_callstate_ready); - set_session_timer(ss); + session_timer_set(ss); nua_server_request_destroy(sr); @@ -2560,171 +2582,6 @@ } /* ---------------------------------------------------------------------- */ -/* Session timer - RFC 4028 */ - -static int session_timer_is_supported(nua_handle_t const *nh) -{ - /* Is timer feature supported? */ - return sip_has_supported(NH_PGET(nh, supported), "timer"); -} - -static int prefer_session_timer(nua_handle_t const *nh) -{ - return - NH_PGET(nh, refresher) != nua_no_refresher || - NH_PGET(nh, session_timer) != 0; -} - -/* Initialize session timer */ -static -void session_timer_preferences(nua_session_usage_t *ss, - unsigned expires, - unsigned min_se, - enum nua_session_refresher refresher) -{ - if (expires < min_se) - expires = min_se; - if (refresher && expires == 0) - expires = 3600; - - ss->ss_min_se = min_se; - ss->ss_session_timer = expires; - ss->ss_refresher = refresher; -} - - -/** Add timer featuretag and Session-Expires/Min-SE headers */ -static int -use_session_timer(nua_session_usage_t *ss, int uas, int always, - msg_t *msg, sip_t *sip) -{ - sip_min_se_t min_se[1]; - sip_session_expires_t session_expires[1]; - - static sip_param_t const x_params_uac[] = {"refresher=uac", NULL}; - static sip_param_t const x_params_uas[] = {"refresher=uas", NULL}; - - /* Session-Expires timer */ - if (ss->ss_refresher == nua_no_refresher && !always) - return 0; - - sip_min_se_init(min_se)->min_delta = ss->ss_min_se; - sip_session_expires_init(session_expires)->x_delta = ss->ss_session_timer; - - if (ss->ss_refresher == nua_remote_refresher) - session_expires->x_params = uas ? x_params_uac : x_params_uas; - else if (ss->ss_refresher == nua_local_refresher) - session_expires->x_params = uas ? x_params_uas : x_params_uac; - - sip_add_tl(msg, sip, - TAG_IF(ss->ss_session_timer, - SIPTAG_SESSION_EXPIRES(session_expires)), - TAG_IF(ss->ss_min_se != 0 - /* Min-SE: 0 is optional with initial INVITE */ - || ss->ss_state != nua_callstate_init, - SIPTAG_MIN_SE(min_se)), - TAG_IF(ss->ss_refresher == nua_remote_refresher, - SIPTAG_REQUIRE_STR("timer")), - TAG_END()); - - return 1; -} - -static int -init_session_timer(nua_session_usage_t *ss, - sip_t const *sip, - int refresher) -{ - int server; - - /* Session timer is not needed */ - if (!sip->sip_session_expires) { - if (!sip_has_supported(sip->sip_supported, "timer")) - ss->ss_refresher = nua_local_refresher; - return 0; - } - - ss->ss_refresher = nua_no_refresher; - ss->ss_session_timer = sip->sip_session_expires->x_delta; - - if (sip->sip_min_se != NULL - && sip->sip_min_se->min_delta > ss->ss_min_se) - ss->ss_min_se = sip->sip_min_se->min_delta; - - server = sip->sip_request != NULL; - - if (!sip_has_supported(sip->sip_supported, "timer")) - ss->ss_refresher = nua_local_refresher; - else if (!str0casecmp("uac", sip->sip_session_expires->x_refresher)) - ss->ss_refresher = server ? nua_remote_refresher : nua_local_refresher; - else if (!str0casecmp("uas", sip->sip_session_expires->x_refresher)) - ss->ss_refresher = server ? nua_local_refresher : nua_remote_refresher; - else if (!server) - return 0; /* XXX */ - /* User preferences */ - else if (refresher == nua_local_refresher) - ss->ss_refresher = nua_local_refresher; - else - ss->ss_refresher = nua_remote_refresher; - - SU_DEBUG_7(("nua session: session expires in %u refreshed by %s (%s %s)\n", - ss->ss_session_timer, - ss->ss_refresher == nua_local_refresher ? "local" : "remote", - server ? sip->sip_request->rq_method_name : "response to", - server ? "request" : sip->sip_cseq->cs_method_name)); - - return 1; -} - -static int session_timer_check_restart(nua_client_request_t *cr, - int status, char const *phrase, - sip_t const *sip) -{ - if (cr->cr_usage && status == 422) { - nua_session_usage_t *ss = nua_dialog_usage_private(cr->cr_usage); - - if (sip->sip_min_se && ss->ss_min_se < sip->sip_min_se->min_delta) - ss->ss_min_se = sip->sip_min_se->min_delta; - if (ss->ss_min_se > ss->ss_session_timer) - ss->ss_session_timer = ss->ss_min_se; - - return nua_client_restart(cr, 100, "Re-Negotiating Session Timer"); - } - - return nua_base_client_check_restart(cr, status, phrase, sip); -} - -static void -set_session_timer(nua_session_usage_t *ss) -{ - nua_dialog_usage_t *du = nua_dialog_usage_public(ss); - - if (ss == NULL) - return; - - if (ss->ss_refresher == nua_local_refresher) { - ss->ss_timer_set = 1; - nua_dialog_usage_set_expires(du, ss->ss_session_timer); - } - else if (ss->ss_refresher == nua_remote_refresher) { - ss->ss_timer_set = 1; - nua_dialog_usage_set_expires(du, ss->ss_session_timer + 32); - nua_dialog_usage_reset_refresh(du); - } - else { - ss->ss_timer_set = 0; - nua_dialog_usage_set_expires(du, UINT_MAX); - nua_dialog_usage_reset_refresh(du); - } -} - -static inline int -is_session_timer_set(nua_session_usage_t *ss) -{ - return ss->ss_timer_set; -} - -/* ---------------------------------------------------------------------- */ /* Automatic notifications from a referral */ static int @@ -2787,7 +2644,6 @@ return 0; } - static void nh_referral_respond(nua_handle_t *nh, int status, char const *phrase) { @@ -3099,8 +2955,17 @@ } /* Add session timer headers */ - if (session_timer_is_supported(nh)) - use_session_timer(ss, 0, prefer_session_timer(nh), msg, sip); + session_timer_preferences(ss->ss_timer, + sip, + NH_PGET(nh, supported), + NH_PGET(nh, session_timer), + NUA_PISSET(nh->nh_nua, nh, session_timer), + NH_PGET(nh, refresher), + NH_PGET(nh, min_se)); + + if (session_timer_is_supported(ss->ss_timer)) + session_timer_add_headers(ss->ss_timer, ss->ss_state < nua_callstate_ready, + msg, sip); retval = nua_base_client_request(cr, msg, sip, NULL); @@ -3109,9 +2974,15 @@ ss->ss_update_needed = 0; if (!cr->cr_restarting) { + enum nua_callstate state = ss->ss_state; + + if (state == nua_callstate_ready) + state = nua_callstate_calling; + if (offer_sent) ss->ss_oa_sent = "offer"; - signal_call_state_change(nh, ss, 0, "UPDATE sent", ss->ss_state); + + signal_call_state_change(nh, ss, 0, "UPDATE sent", state); } } @@ -3129,9 +3000,18 @@ assert(200 <= status); if (ss && sip && status < 300) { - if (is_session_timer_set(ss)) { - init_session_timer(ss, sip, NH_PGET(nh, refresher)); - set_session_timer(ss); + if (session_timer_is_supported(ss->ss_timer)) { + nua_server_request_t *sr; + + for (sr = nh->nh_ds->ds_sr; sr; sr = sr->sr_next) + if (sr->sr_method == sip_method_invite || + sr->sr_method == sip_method_update) + break; + + if (!sr && (!du->du_cr || !du->du_cr->cr_orq)) { + session_timer_store(ss->ss_timer, sip); + session_timer_set(ss); + } } } @@ -3225,7 +3105,7 @@ /* Do session timer negotiation */ if (request->sip_session_expires) - init_session_timer(ss, request, NH_PGET(nh, refresher)); + session_timer_store(ss->ss_timer, request); if (sr->sr_sdp) { /* Check for overlap */ nua_client_request_t *cr; @@ -3306,11 +3186,28 @@ } } - if (ss->ss_refresher && 200 <= sr->sr_status && sr->sr_status < 300) - if (session_timer_is_supported(nh)) { - use_session_timer(ss, 1, 1, msg, sip); - set_session_timer(ss); /* XXX */ + if (200 <= sr->sr_status && sr->sr_status < 300) { + session_timer_preferences(ss->ss_timer, + sip, + NH_PGET(nh, supported), + NH_PGET(nh, session_timer), + NUA_PISSET(nh->nh_nua, nh, session_timer), + NH_PGET(nh, refresher), + NH_PGET(nh, min_se)); + + if (ss && session_timer_is_supported(ss->ss_timer)) { + nua_server_request_t *sr0; + + session_timer_add_headers(ss->ss_timer, 0, msg, sip); + + for (sr0 = nh->nh_ds->ds_sr; sr0; sr0 = sr0->sr_next) + if (sr0->sr_method == sip_method_invite) + break; + + if (!sr0 && (!sr->sr_usage->du_cr || !sr->sr_usage->du_cr->cr_orq)) + session_timer_set(ss); } + } return nua_base_server_respond(sr, tags); } @@ -3348,9 +3245,15 @@ return retval; } - if (offer_recv_or_answer_sent) + if (offer_recv_or_answer_sent) { /* signal offer received, answer sent */ - signal_call_state_change(nh, ss, status, phrase, ss->ss_state); + enum nua_callstate state = ss->ss_state; + + if (state == nua_callstate_ready && status < 200) + state = nua_callstate_received; + + signal_call_state_change(nh, ss, status, phrase, state); + } if (200 <= status && status < 300 && ss->ss_state < nua_callstate_ready @@ -3900,6 +3803,287 @@ } /* ======================================================================== */ +/* Session timer - RFC 4028 */ + +static int session_timer_is_supported(struct session_timer const *t) +{ + return t->local.supported; +} + +/** Set session timer preferences */ +static +void session_timer_preferences(struct session_timer *t, + sip_t const *sip, + sip_supported_t const *supported, + unsigned expires, + int isset, + enum nua_session_refresher refresher, + unsigned min_se) +{ + memset(&t->local, 0, sizeof t->local); + + t->local.require = sip_has_feature(sip->sip_require, "timer"); + t->local.supported = + sip_has_feature(supported, "timer") || + sip_has_feature(sip->sip_supported, "timer"); + if (isset || refresher != nua_no_refresher) + t->local.expires = expires; + else + t->local.defaults = expires; + t->local.min_se = min_se; + t->local.refresher = refresher; +} + +static int session_timer_check_restart(nua_client_request_t *cr, + int status, char const *phrase, + sip_t const *sip) +{ + if (status == 422) { + nua_session_usage_t *ss = nua_dialog_usage_private(cr->cr_usage); + + if (ss && session_timer_is_supported(ss->ss_timer)) { + struct session_timer *t = ss->ss_timer; + + if (sip->sip_min_se && t->local.min_se < sip->sip_min_se->min_delta) + t->local.min_se = sip->sip_min_se->min_delta; + if (t->local.expires != 0 && t->local.min_se > t->local.expires) + t->local.expires = t->local.min_se; + + return nua_client_restart(cr, 100, "Re-Negotiating Session Timer"); + } + } + + return nua_base_client_check_restart(cr, status, phrase, sip); +} + +/** Check that received Session-Expires is longer than Min-SE */ +static +int session_timer_check_min_se(msg_t *msg, + sip_t *sip, + sip_t const *request, + unsigned long min) +{ + if (min == 0) + min = 1; + + /* + If an incoming request contains a Supported header field with a value + 'timer' and a Session Expires header field, the UAS MAY reject the + INVITE request with a 422 (Session Interval Too Small) response if + the session interval in the Session-Expires header field is smaller + than the minimum interval defined by the UAS' local policy. When + sending the 422 response, the UAS MUST include a Min-SE header field + with the value of its minimum interval. This minimum interval MUST + NOT be lower than 90 seconds. + */ + if (request->sip_session_expires && + sip_has_feature(request->sip_supported, "timer") && + request->sip_session_expires->x_delta < min) { + sip_min_se_t min_se[1]; + + if (min < 90) + min = 90; + + sip_min_se_init(min_se)->min_delta = min; + + /* Include extension parameters, if any */ + if (request->sip_min_se) + min_se->min_params = request->sip_min_se->min_params; + + sip_add_dup(msg, sip, (sip_header_t *)min_se); + + return 422; + } + + return 0; +} + +/** Store session timer parameters in request from uac / response from uas */ +static +void session_timer_store(struct session_timer *t, + sip_t const *sip) +{ + sip_require_t const *require = sip->sip_require; + sip_supported_t const *supported = sip->sip_supported; + sip_session_expires_t const *x = sip->sip_session_expires; + + t->remote.require = require && sip_has_feature(require, "timer"); + t->remote.supported = + t->remote.supported || (supported && sip_has_feature(supported, "timer")); + + t->remote.expires = 0; + t->remote.refresher = nua_any_refresher; + t->remote.min_se = 0; + + if (x) { + t->remote.expires = x->x_delta; + + if (x->x_refresher) { + int uas = sip->sip_request != NULL; + + if (strcasecmp(x->x_refresher, "uac") == 0) + t->remote.refresher = uas ? nua_remote_refresher : nua_local_refresher; + else if (strcasecmp(x->x_refresher, "uas") == 0) + t->remote.refresher = uas ? nua_local_refresher : nua_remote_refresher; + } + } + + if (sip->sip_min_se) + t->remote.min_se = sip->sip_min_se->min_delta; +} + +/** Add timer feature and Session-Expires/Min-SE headers to request/response + * + */ +static int +session_timer_add_headers(struct session_timer *t, + int initial, + msg_t *msg, sip_t *sip) +{ + unsigned long expires, min; + sip_min_se_t min_se[1]; + sip_session_expires_t x[1]; + int uas; + + enum nua_session_refresher refresher = nua_any_refresher; + + static sip_param_t const x_params_uac[] = {"refresher=uac", NULL}; + static sip_param_t const x_params_uas[] = {"refresher=uas", NULL}; + + if (!t->local.supported) + return 0; + + uas = sip->sip_status != NULL; + + min = t->local.min_se; + if (min < t->remote.min_se) + min = t->remote.min_se; + + if (uas) { + session_timer_negotiate(t); + + refresher = t->refresher; + expires = t->interval; + } + else { + /* RFC 4028: + * The UAC MAY include the refresher parameter with value 'uac' if it + * wants to perform the refreshes. However, it is RECOMMENDED that the + * parameter be omitted so that it can be selected by the negotiation + * mechanisms described below. + */ + if (t->local.refresher == nua_local_refresher) + refresher = nua_local_refresher; + + expires = t->local.expires; + if (expires != 0 && expires < min) + expires = min; + } + + sip_min_se_init(min_se)->min_delta = min; + + sip_session_expires_init(x)->x_delta = expires; + if (refresher == nua_remote_refresher) + x->x_params = uas ? x_params_uac : x_params_uas; + else if (refresher == nua_local_refresher) + x->x_params = uas ? x_params_uas : x_params_uac; + + sip_add_tl(msg, sip, + TAG_IF(expires != 0, SIPTAG_SESSION_EXPIRES(x)), + TAG_IF(min != 0 + /* Min-SE: 0 is optional with initial INVITE */ + || !initial, + SIPTAG_MIN_SE(min_se)), + TAG_IF(refresher == nua_remote_refresher && expires != 0, + SIPTAG_REQUIRE_STR("timer")), + TAG_END()); + + return 1; +} + +static +void session_timer_negotiate(struct session_timer *t) +{ + if (!t->local.supported) + t->refresher = nua_no_refresher; + else if (!t->remote.supported) + t->refresher = nua_local_refresher; + else if (t->remote.refresher == nua_local_refresher) + t->refresher = nua_local_refresher; + else if (t->remote.refresher == nua_remote_refresher) + t->refresher = nua_remote_refresher; + else if (t->local.refresher == nua_local_refresher) + t->refresher = nua_local_refresher; + else + t->refresher = nua_remote_refresher; + + t->interval = t->remote.expires; + if (t->interval == 0) + t->interval = t->local.expires; + if (t->local.expires != 0 && t->interval > t->local.expires) + t->interval = t->local.expires; + if (t->local.defaults != 0 && t->interval > t->local.defaults) + t->interval = t->local.defaults; + + if (t->interval != 0) { + if (t->interval < t->local.min_se) + t->interval = t->local.min_se; + if (t->interval < t->remote.min_se) + t->interval = t->remote.min_se; + } + + if (t->interval == 0) + t->refresher = nua_no_refresher; +} + +static void +session_timer_set(nua_session_usage_t *ss) +{ + nua_dialog_usage_t *du = nua_dialog_usage_public(ss); + struct session_timer *t; + + if (ss == NULL) + return; + + t = ss->ss_timer; + + session_timer_negotiate(t); + + if (t->refresher == nua_local_refresher) { + unsigned low = t->interval / 2, high = t->interval / 2; + + if (t->interval >= 90) + low -=5, high += 5; + + nua_dialog_usage_refresh_range(du, low, high); + t->timer_set = 1; + } + else if (t->refresher == nua_remote_refresher) { + /* if the side not performing refreshes does not receive a + session refresh request before the session expiration, it SHOULD send + a BYE to terminate the session, slightly before the session + expiration. The minimum of 32 seconds and one third of the session + interval is RECOMMENDED. */ + unsigned interval = t->interval; + + interval -= 32 > interval / 6 ? interval / 3 : 32 + interval / 3; + + nua_dialog_usage_refresh_range(du, interval, interval); + t->timer_set = 1; + } + else { + nua_dialog_usage_reset_refresh(du); + t->timer_set = 0; + } +} + +static inline int +session_timer_has_been_set(struct session_timer const *t) +{ + return t->timer_set; +} + +/* ======================================================================== */ /** Get SDP from a SIP message. * @@ -4020,6 +4204,8 @@ return retval; } +/* ====================================================================== */ + /** @NUA_EVENT nua_i_options * * Incoming OPTIONS request. The user-agent should respond to an OPTIONS @@ -4093,4 +4279,3 @@ return nua_base_server_respond(sr, tags); } - Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c Fri Apr 13 10:33:30 2007 @@ -989,11 +989,10 @@ nua_stack_authenticate(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags) { + nua_client_request_t *cr = nh->nh_ds->ds_cr; int status = nh_authorize(nh, TAG_NEXT(tags)); if (status > 0) { - nua_client_request_t *cr = nh->nh_ds->ds_cr; - if (cr && cr->cr_wait_for_cred) { nua_client_restart_request(cr, cr->cr_terminating, tags); } @@ -1003,6 +1002,14 @@ NULL); } } + else if (cr && cr->cr_wait_for_cred) { + cr->cr_wait_for_cred = 0; + + if (status < 0) + nua_client_response(cr, 900, "Cannot add credentials", NULL); + else + nua_client_response(cr, 904, "No matching challenge", NULL); + } else if (status < 0) { nua_stack_event(nua, nh, NULL, e, 900, "Cannot add credentials", NULL); } @@ -1049,6 +1056,7 @@ nua_server_methods_t const *sm; nua_server_request_t *sr, sr0[1]; int status, initial = 1; + int create_dialog; char const *user_agent = NH_PGET(nh, user_agent); sip_supported_t const *supported = NH_PGET(nh, supported); @@ -1135,11 +1143,15 @@ return 481; } + create_dialog = sm->sm_flags.create_dialog; + if (method == sip_method_message && NH_PGET(nh, win_messenger_enable)) + create_dialog = 1; sr = memset(sr0, 0, (sizeof sr0)); sr->sr_methods = sm; sr->sr_method = method = sip->sip_request->rq_method; sr->sr_add_contact = sm->sm_flags.add_contact; + sr->sr_target_refresh = sm->sm_flags.target_refresh; sr->sr_owner = nh; sr->sr_initial = initial; @@ -1171,12 +1183,12 @@ } if (sr->sr_status < 300 && sm->sm_preprocess && sm->sm_preprocess(sr)) { - if (sr->sr_status < 200) /* Preprocess may have set response status */ + if (sr->sr_status < 200) /* Set response status if preprocess did not */ SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR); } if (sr->sr_status < 300) { - if (sm->sm_flags.target_refresh) + if (sr->sr_target_refresh) nua_dialog_uas_route(nh, nh->nh_ds, sip, 1); /* Set route and tags */ nua_dialog_store_peer_info(nh, nh->nh_ds, sip); } @@ -1273,7 +1285,7 @@ * content negotiation fails. * * When responding to an incoming INVITE request, the nua_respond() can be - * called without NUTAG_WITH() (or NUTAG_WITH_CURRENT() or + * called without NUTAG_WITH() (or NUTAG_WITH_THIS() or * NUTAG_WITH_SAVED()). Otherwise, NUTAG_WITH() will contain an indication * of the request being responded. * @@ -1302,7 +1314,7 @@ * nothing * * @par Related Tags: - * NUTAG_WITH(), NUTAG_WITH_CURRENT(), NUTAG_WITH_SAVED() \n + * NUTAG_WITH(), NUTAG_WITH_THIS(), NUTAG_WITH_SAVED() \n * NUTAG_EARLY_ANSWER() \n * SOATAG_ADDRESS() \n * SOATAG_AF() \n @@ -1696,6 +1708,7 @@ cr->cr_method = method; cr->cr_method_name = name; cr->cr_contactize = methods->crm_flags.target_refresh; + cr->cr_dialog = methods->crm_flags.create_dialog; cr->cr_auto = 1; if (su_msg_is_non_null(nh->nh_nua->nua_signal)) { @@ -1927,6 +1940,10 @@ has_contact = 1; else if (t->t_tag == nutag_url) url = (url_string_t const *)t->t_value; + else if (t->t_tag == nutag_dialog) { + cr->cr_dialog = t->t_value > 1; + cr->cr_contactize = t->t_value >= 1; + } else if (t->t_tag == nutag_auth && t->t_value) { /* XXX ignoring errors */ if (nh->nh_auth) @@ -1965,7 +1982,7 @@ sip_add_dup(msg, sip, (sip_header_t *)nua->nua_from) < 0) goto error; - if (cr->cr_methods->crm_flags.create_dialog) { + if (cr->cr_dialog) { ds->ds_leg = nta_leg_tcreate(nua->nua_nta, nua_stack_process_request, nh, SIPTAG_CALL_ID(sip->sip_call_id), @@ -2030,7 +2047,6 @@ if (sip_add_tagis(cr->cr_msg, NULL, &tags) < 0) /* XXX */; - cr->cr_retry_count = 0; cr->cr_terminating = terminating; return nua_client_request_try(cr); @@ -2125,6 +2141,8 @@ assert(cr->cr_orq == NULL); + cr->cr_retry_count++; + if (ds->ds_leg) leg = ds->ds_leg; else @@ -2161,7 +2179,7 @@ * are used: @Allow, @Supported, @Organization, and @UserAgent headers are * added to the request if they are not already set. */ - if (!sip->sip_allow && !ds->ds_route) + if (!sip->sip_allow) sip_add_dup(msg, sip, (sip_header_t*)NH_PGET(nh, allow)); if (!sip->sip_supported && NH_PGET(nh, supported)) @@ -2337,7 +2355,7 @@ } else { if (sip) { - if (cr->cr_methods->crm_flags.target_refresh) + if (cr->cr_contactize) nua_dialog_uac_route(nh, nh->nh_ds, sip, 1); nua_dialog_store_peer_info(nh, nh->nh_ds, sip); } @@ -2392,7 +2410,7 @@ assert(cr && status >= 200 && phrase && sip); - if (cr->cr_retry_count >= NH_PGET(nh, retry_count)) + if (cr->cr_retry_count > NH_PGET(nh, retry_count)) return 0; if (cr->cr_methods->crm_check_restart) @@ -2482,7 +2500,6 @@ orq = cr->cr_orq, cr->cr_orq = NULL; cr->cr_wait_for_cred = 1; - cr->cr_retry_count++; nua_client_report(cr, status, phrase, NULL, orq, NULL); nta_outgoing_destroy(orq); @@ -2507,7 +2524,7 @@ msg_t *msg; sip_t *sip; - if (++cr->cr_retry_count > NH_PGET(nh, retry_count)) + if (cr->cr_retry_count > NH_PGET(nh, retry_count)) return 0; orq = cr->cr_orq, cr->cr_orq = NULL; assert(orq); @@ -2641,22 +2658,23 @@ if (cr->cr_terminated < 0) { /* XXX - dialog has been terminated */; - nua_dialog_deinit(nh, nh->nh_ds); + nua_dialog_deinit(nh, nh->nh_ds), cr->cr_usage = NULL; } else if (du) { if (cr->cr_terminated || (!du->du_ready && status >= 300 && nua_client_is_bound(cr))) { /* Usage has been destroyed */ - nua_dialog_usage_remove(nh, nh->nh_ds, du); + nua_dialog_usage_remove(nh, nh->nh_ds, du), cr->cr_usage = NULL; } else if (cr->cr_graceful) { /* Terminate usage gracefully */ - nua_dialog_usage_shutdown(nh, nh->nh_ds, du); + if (nua_dialog_usage_shutdown(nh, nh->nh_ds, du) > 0) + cr->cr_usage = NULL; } } else if (cr->cr_terminated) { if (nh->nh_ds->ds_usage == NULL) - nua_dialog_remove(nh, nh->nh_ds, NULL); + nua_dialog_remove(nh, nh->nh_ds, NULL), cr->cr_usage = NULL; } cr->cr_reporting = 0, nh->nh_ds->ds_reporting = 0; Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.h ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.h (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.h Fri Apr 13 10:33:30 2007 @@ -336,8 +336,6 @@ sip_t const *sip, int create_dialog); -enum { create_dialog = 1 }; - int nua_stack_init_handle(nua_t *nua, nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...); Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_subnotref.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_subnotref.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_subnotref.c Fri Apr 13 10:33:30 2007 @@ -61,6 +61,7 @@ enum nua_substate eu_substate; /**< Subscription state */ sip_time_t eu_expires; /**< Proposed expiration time */ unsigned eu_notified; /**< Number of NOTIFYs received */ + unsigned eu_unsolicited:1; /**< Not SUBSCRIBEd or REFERed */ unsigned eu_refer:1; /**< Implied subscription by refer */ unsigned eu_final_wait:1; /**< Waiting for final NOTIFY */ unsigned eu_no_id:1; /**< Do not use "id" (even if we have one) */ @@ -443,11 +444,12 @@ */ } - nua_stack_tevent(nh->nh_nua, nh, NULL, - nua_i_notify, NUA_INTERNAL_ERROR, - NUTAG_SUBSTATE(nua_substate_terminated), - SIPTAG_EVENT(du->du_event), - TAG_END()); + if (!eu->eu_unsolicited) + nua_stack_tevent(nh->nh_nua, nh, NULL, + nua_i_notify, NUA_INTERNAL_ERROR, + NUTAG_SUBSTATE(nua_substate_terminated), + SIPTAG_EVENT(du->du_event), + TAG_END()); nua_dialog_usage_remove(nh, ds, du); } @@ -504,10 +506,10 @@ SIP_METHOD_NOTIFY, nua_i_notify, /* Event */ { - 1, /* Do create dialog */ - 0, /* Not always in-dialog request */ - 1, /* Target refresh request */ - 1, /* Add Contact to response */ + /* create_dialog: */ 1, /* Do create dialog */ + /* in_dialog: */ 0, /* Not always in-dialog request */ + /* target_refresh: */ 1, /* Target refresh request */ + /* add_contact: */ 1, /* Add Contact to response */ }, nua_notify_server_init, nua_notify_server_preprocess, @@ -557,17 +559,21 @@ enum nua_substate substate = nua_substate_terminated; sip_subscription_state_t *subs = sip->sip_subscription_state; char const *what = "", *reason = NULL; + int solicited = 1; du = nua_dialog_usage_get(ds, nua_subscribe_usage, o); - sr->sr_usage = du; if (du == NULL) { if (!sip_is_allowed(NH_PGET(sr->sr_owner, appl_method), SIP_METHOD_NOTIFY)) return SR_STATUS(sr, 481, "Subscription Does Not Exist"); - /* Let application to handle unsolicited NOTIFY */ - return 0; + + solicited = 0; /* Let application to handle unsolicited NOTIFY */ + du = nua_dialog_usage_add(sr->sr_owner, ds, nua_subscribe_usage, o); + if (!du) + return SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR); } + sr->sr_usage = du; eu = nua_dialog_usage_private(du); assert(eu); eu->eu_notified++; if (!o->o_id) @@ -602,12 +608,17 @@ } eu->eu_substate = substate; + if (!solicited) + eu->eu_unsolicited = 1; SU_DEBUG_5(("nua(%p): %s: %s (%s)\n", (void *)sr->sr_owner, "nua_notify_server_preprocess", what, reason ? reason : "")); - return SR_STATUS1(sr, SIP_200_OK); + if (solicited) + return SR_STATUS1(sr, SIP_200_OK); + + return 0; } @@ -656,10 +667,13 @@ NUTAG_SUBSTATE(substate), TAG_NEXT(tags)); - if (retval >= 2 || du == NULL) + if (retval != 1 || du == NULL) return retval; - if (retry >= 0) { /* Try to subscribe again */ + if (eu->eu_unsolicited) { + /* Xyzzy */; + } + else if (retry >= 0) { /* Try to subscribe again */ /* XXX - this needs through testing */ nua_dialog_remove(nh, nh->nh_ds, du); /* tear down */ nua_dialog_usage_refresh_range(du, retry, retry + 5); Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_tag.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_tag.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/nua_tag.c Fri Apr 13 10:33:30 2007 @@ -149,3 +149,4 @@ tag_typedef_t nutag_detect_network_updates = UINTTAG_TYPEDEF(detect_network_updates); tag_typedef_t nutag_with = PTRTAG_TYPEDEF(with); +tag_typedef_t nutag_dialog = UINTTAG_TYPEDEF(dialog); Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua.h ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua.h (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua.h Fri Apr 13 10:33:30 2007 @@ -346,6 +346,9 @@ tag_type_t, tag_value_t, ...); +/** Check if event can be responded with nua_respond() */ +SOFIAPUBFUN int nua_event_is_incoming_request(nua_event_t e); + #define nua_handle_home(nh) ((su_home_t *)(nh)) /** Generate an instance identifier */ Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua_tag.h ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua_tag.h (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua_tag.h Fri Apr 13 10:33:30 2007 @@ -157,6 +157,9 @@ */ #define NUTAG_WITH_THIS(nua) nutag_with, tag_ptr_v(nua_current_request((nua))) +#define NUTAG_WITH_CURRENT(nua) \ + nutag_with, tag_ptr_v(nua_current_request((nua))) + /**Specify request to respond to. * * @par Used with @@ -174,6 +177,26 @@ */ #define NUTAG_WITH_SAVED(e) nutag_with, tag_ptr_v(nua_saved_event_request((e))) +/**An (extension) method is used to create dialog or refresh target. + * + * @par Used with + * nua_method() + * + * @par Parameter type + * unsigned int (0, 1, 2) + * + * @par Values + * - 0 if dialog target is not refreshed + * - 1 if dialog target is refreshed + * - > 1 if dialog is to be created + * + * @NEW_1_12_6. + * + * @sa nua_method(), #nua_i_method + */ +#define NUTAG_DIALOG(b) nutag_dialog, tag_uint_v((b)) +SOFIAPUBVAR tag_typedef_t nutag_dialog; + /**Set request retry count. * * Retry count determines how many times stack will automatically retry @@ -471,40 +494,48 @@ /**Default session timer in seconds. * - * Set default session timer in seconds when using session timer extension. - * The value given here is the proposed session expiration time in seconds. - * Note that the session timer extension is ponly used + * Set default value for session timer in seconds when the session timer + * extension is used. The tag value is the proposed session expiration time + * in seconds, the session is refreshed twice during the expiration time. * * @par Sending INVITE and UPDATE Requests * - * If NUTAG_SESSION_TIMER() is used with non-zero value, the value is - * used in the @SessionExpires header included in the INVITE or UPDATE - * requests. The intermediate proxies or the ultimate destination can lower - * the interval in @SessionExpires header. If the value is too low, they can + * If NUTAG_SESSION_TIMER() is used with non-zero value, the value is used + * in the @SessionExpires header included in the INVITE or UPDATE requests. + * The intermediate proxies or the ultimate destination can lower the + * interval in @SessionExpires header. If the value is too low, they can * reject the request with the status code <i>422 Session Timer Too - * Small</i>. When Re-INVITE will be sent in given intervals. In that case, - * @b nua retries the request automatically. - * - * @par Returning Response to the INVITE and UPDATE Requests + * Small</i>. In that case, @b nua increases the value of @SessionExpires + * header and retries the request automatically. + * + * @par Returning a Response to the INVITE and UPDATE Requests * * The NUTAG_SESSION_TIMER() value is also used when sending the final * response to the INVITE or UPDATE requests. If the NUTAG_SESSION_TIMER() - * value is 0 or the value in the @SessionExpires header of the requeast is + * value is 0 or the value in the @SessionExpires header of the request is * lower than the value in NUTAG_SESSION_TIMER(), the value from the * incoming @SessionExpires header is used. However, if the value in * @SessionExpires is lower than the minimal acceptable session expiration * interval specified with the tag NUTAG_MIN_SE() the request is * automatically rejected with <i>422 Session Timer Too Small</i>. * + * @par Refreshes + * + * After the initial INVITE request, the SIP session is refreshed at the + * intervals indicated by the @SessionExpires header returned in the 2XX + * response. The party indicated with the "refresher" parameter of the + * @SessionExpires header sends a re-INVITE requests (or an UPDATE + * request if NUTAG_UPDATE_REFRESH(1) parameter tag has been set). + * * @par When to Use NUTAG_SESSION_TIMER()? * * The session time extension is enabled ("timer" feature tag is included in * @Supported header) but not activated by default (no @SessionExpires * header is included in the requests or responses by default). Using - * non-zero value with NUTAG_SESSION_TIMER() activates it. When the - * extension is activated, @nua refreshes the call state by sending periodic - * re-INVITE or UPDATE requests unless the remote end indicated that it will - * take care of refreshes. + * non-zero value with NUTAG_SESSION_TIMER() or NUTAG_SESSION_REFRESHER() + * activates it. When the extension is activated, @nua refreshes the call + * state by sending periodic re-INVITE or UPDATE requests unless the remote + * end indicated that it will take care of refreshes. * * The session timer extension is mainly useful for proxies or back-to-back * user agents that keep call state. The call state is "soft" meaning that @@ -512,6 +543,10 @@ * will be destroyed. An ordinary user-agent can also make use of session * timer if it cannot get any activity feedback from RTP or other media. * + * @note The session timer extension is used only if the feature + * tag "timer" is listed in the @Supported header, set by NUTAG_SUPPORTED(), + * SIPTAG_SUPPORTED(), or SIPTAG_SUPPORTED_STR() tags. + * * @par Used with * nua_invite(), nua_update(), nua_respond() \n * nua_set_params() or nua_set_hparams() \n @@ -530,8 +565,8 @@ * Corresponding tag taking reference parameter is NUTAG_SESSION_TIMER_REF() * * @sa NUTAG_SUPPORTED(), NUTAG_MIN_SE(), NUTAG_SESSION_REFRESHER(), - * nua_invite(), #nua_r_invite, #nua_i_invite, nua_update(), #nua_r_update, - * #nua_i_update, + * nua_invite(), #nua_r_invite, #nua_i_invite, nua_respond(), + * nua_update(), #nua_r_update, #nua_i_update, * NUTAG_UPDATE_REFRESH(), @RFC4028, @SessionExpires, @MinSE */ #define NUTAG_SESSION_TIMER(x) nutag_session_timer, tag_uint_v((x)) Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_100rel.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_100rel.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_100rel.c Fri Apr 13 10:33:30 2007 @@ -163,6 +163,7 @@ nua_set_params(ctx->b.nua, NUTAG_EARLY_MEDIA(1), + NUTAG_SESSION_TIMER(180), TAG_END()); run_b_until(ctx, nua_r_set_params, until_final_response); @@ -970,6 +971,8 @@ TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_update); TEST(e->data->e_status, 200); + TEST_1(sip = sip_object(e->data->e_msg)); + TEST_1(sip->sip_session_expires); TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state); TEST(callstate(e->data->e_tags), nua_callstate_proceeding); @@ -1197,14 +1200,14 @@ nua_set_params(ctx->a.nua, NUTAG_EARLY_MEDIA(1), - SIPTAG_SUPPORTED_STR("100rel, precondition"), + SIPTAG_SUPPORTED_STR("100rel, precondition, timer"), TAG_END()); run_a_until(ctx, nua_r_set_params, until_final_response); nua_set_params(ctx->b.nua, NUTAG_EARLY_MEDIA(1), NUTAG_ONLY183_100REL(1), - SIPTAG_SUPPORTED_STR("100rel, precondition"), + SIPTAG_SUPPORTED_STR("100rel, precondition, timer"), TAG_END()); run_b_until(ctx, nua_r_set_params, until_final_response); Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_basic_call.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_basic_call.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_basic_call.c Fri Apr 13 10:33:30 2007 @@ -205,9 +205,16 @@ sip_replaces_t *repa, *repb; nua_handle_t *nh; + static int once = 0; + sip_time_t se, min_se; + if (print_headings) printf("TEST NUA-3.1: Basic call\n"); + /* Disable session timer from proxy */ + test_proxy_get_session_timer(ctx->p, &se, &min_se); + test_proxy_set_session_timer(ctx->p, 0, 0); + a_call->sdp = "m=audio 5008 RTP/AVP 8"; b_call->sdp = "m=audio 5010 RTP/AVP 0 8"; @@ -272,6 +279,10 @@ TEST_1(sip->sip_contact); TEST_S(sip->sip_contact->m_display, "Bob"); TEST_S(sip->sip_contact->m_url->url_user, "b+b"); + if (!once) { + /* The session expiration is not used by default. */ + TEST_1(sip->sip_session_expires == NULL); + } /* Test that B uses application-specific contact */ if (ctx->proxy_tests) TEST_1(sip->sip_contact->m_url->url_user); @@ -293,6 +304,10 @@ TEST_1(sip->sip_contact); TEST_S(sip->sip_contact->m_display, "Alice"); TEST_S(sip->sip_contact->m_url->url_user, "a+a"); + if (!once++) { + /* The Session-Expires header is not used by default. */ + TEST_1(sip->sip_session_expires == NULL); + } TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state); TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */ TEST_1(is_offer_recv(e->data->e_tags)); @@ -342,6 +357,8 @@ nua_handle_destroy(a_call->nh), a_call->nh = NULL; nua_handle_destroy(b_call->nh), b_call->nh = NULL; + test_proxy_set_session_timer(ctx->p, se, min_se); + if (print_headings) printf("TEST NUA-3.1: PASSED\n"); Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_call_reject.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_call_reject.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_call_reject.c Fri Apr 13 10:33:30 2007 @@ -262,6 +262,7 @@ /* ------------------------------------------------------------------------ */ int reject_302(CONDITION_PARAMS), reject_305(CONDITION_PARAMS); +int redirect_always(CONDITION_PARAMS); int reject_604(CONDITION_PARAMS); /* @@ -336,6 +337,26 @@ } } +int redirect_always(CONDITION_PARAMS) +{ + if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR))) + return 0; + + if (event == nua_i_invite) { + char user[30]; + sip_contact_t m[1]; + *m = *ep->contact; + snprintf(user, sizeof user, "user-%u", ep->flags.n++); + m->m_url->url_user = user; + RESPOND(ep, call, nh, SIP_302_MOVED_TEMPORARILY, + SIPTAG_CONTACT(m), TAG_END()); + nua_handle_destroy(nh); + call->nh = NULL; + return 1; + } + + return 0; +} int reject_604(CONDITION_PARAMS) { @@ -476,6 +497,25 @@ if (print_headings) printf("TEST NUA-4.3: PASSED\n"); + if (print_headings) + printf("TEST NUA-4.3.1: redirect until retry count is exceeded\n"); + + TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END())); + INVITE(a, a_call, a_call->nh, + TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)), + SIPTAG_SUBJECT_STR("redirect always"), + SOATAG_USER_SDP_STR(a_call->sdp), + TAG_END()); + run_ab_until(ctx, -1, until_terminated, -1, redirect_always); + + free_events_in_list(ctx, a->events); + nua_handle_destroy(a_call->nh), a_call->nh = NULL; + free_events_in_list(ctx, b->events); + nua_handle_destroy(b_call->nh), b_call->nh = NULL; + + if (print_headings) + printf("TEST NUA-4.3: PASSED\n"); + END(); } @@ -874,7 +914,7 @@ } } -int authenticate_once(CONDITION_PARAMS) +int authenticate_bad(CONDITION_PARAMS) { if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR))) return 0; @@ -882,13 +922,8 @@ save_event_in_list(ctx, event, ep, call); if (event == nua_r_invite && status == 401) { - if (ep->flags.bit0) { - nua_handle_destroy(nh); if (call) call->nh = NULL; - return 1; - } - ep->flags.bit0 = 1; AUTHENTICATE(ep, call, nh, NUTAG_AUTH("Digest:\"No hope\":jaska:secret"), - SIPTAG_SUBJECT_STR("Got 401"), + SIPTAG_SUBJECT_STR("Bad password"), TAG_END()); return 0; } @@ -925,7 +960,8 @@ SOATAG_USER_SDP_STR(a_call->sdp), TAG_END()); - run_ab_until(ctx, -1, authenticate_once, -1, reject_401_bad); + + run_ab_until(ctx, -1, authenticate_bad, -1, reject_401_bad); /* Client transitions @@ -941,7 +977,12 @@ TEST_1(is_offer_sent(e->data->e_tags)); TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite); TEST(sip_object(e->data->e_msg)->sip_status->st_status, 401); - TEST_1(!e->next); + /* nua_authenticate() fails and INVITE returns an internal error response */ + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite); + TEST(e->data->e_status, 904); + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state); + TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */ + TEST_1(!e->next); free_events_in_list(ctx, a->events); Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_cancel_bye.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_cancel_bye.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_cancel_bye.c Fri Apr 13 10:33:30 2007 @@ -871,13 +871,12 @@ return len; } -int test_early_bye(struct context *ctx) +int test_bye_before_200(struct context *ctx) { BEGIN(); struct endpoint *a = &ctx->a, *b = &ctx->b; struct call *a_call = a->call, *b_call = b->call; struct event *e; - struct nat_filter *f = NULL; a_call->sdp = "m=audio 5008 RTP/AVP 8"; b_call->sdp = "m=audio 5010 RTP/AVP 0 8"; @@ -950,6 +949,41 @@ if (print_headings) printf("TEST NUA-6.1: 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; + } +} + + +int test_bye_before_ack(struct context *ctx) +{ + BEGIN(); + struct endpoint *a = &ctx->a, *b = &ctx->b; + struct call *a_call = a->call, *b_call = b->call; + struct event *e; + struct nat_filter *f = NULL; + + a_call->sdp = "m=audio 5008 RTP/AVP 8"; + b_call->sdp = "m=audio 5010 RTP/AVP 0 8"; + /* Early BYE 2 A B @@ -1048,21 +1082,275 @@ END(); } -int bye_when_completing(CONDITION_PARAMS) +int reject_reinvite_401(CONDITION_PARAMS); + +int test_bye_after_receiving_401(struct context *ctx) { - if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR))) - return 0; + BEGIN(); + struct endpoint *a = &ctx->a, *b = &ctx->b; + struct call *a_call = a->call, *b_call = b->call; + struct event *e; + + a_call->sdp = "m=audio 5008 RTP/AVP 8"; + b_call->sdp = "m=audio 5010 RTP/AVP 0 8"; + +/* BYE after receiving 401 + + A B + |-------INVITE------>| + |<----100 Trying-----| + | | + |<----180 Ringing----| + |<-------200---------| + |--------ACK-------->| + | | + |<------INVITE-------| + |--------401-------->| + |<--------ACK--------| + | | + |<--------BYE--------| + |------200 OK------->| + | | +*/ + if (print_headings) + printf("TEST NUA-6.3: BYE after receiving 401\n"); + + TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END())); + + INVITE(a, a_call, a_call->nh, + TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)), + SIPTAG_SUBJECT_STR("NUA-6.3"), + SOATAG_USER_SDP_STR(a_call->sdp), + NUTAG_AUTOANSWER(0), + TAG_END()); + + run_ab_until(ctx, -1, until_ready, -1, accept_call); + + free_events_in_list(ctx, a->events); + + TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite); + free_events_in_list(ctx, b->events); + + /* re-INVITE A. */ + INVITE(b, b_call, b_call->nh, + SIPTAG_SUBJECT_STR("NUA-6.3 re-INVITE"), + TAG_END()); + run_ab_until(ctx, -1, reject_reinvite_401, -1, until_final_response); + + TEST_1(nua_handle_has_active_call(a_call->nh)); + TEST_1(nua_handle_has_active_call(b_call->nh)); + + free_events_in_list(ctx, a->events); + free_events_in_list(ctx, b->events); + + BYE(b, b_call, b_call->nh, TAG_END()); + + run_ab_until(ctx, -1, until_terminated, -1, until_terminated); + + free_events_in_list(ctx, a->events); + nua_handle_destroy(a_call->nh), a_call->nh = NULL; + + free_events_in_list(ctx, b->events); + nua_handle_destroy(b_call->nh), b_call->nh = NULL; + + if (print_headings) + printf("TEST NUA-6.3: PASSED\n"); + + END(); +} + +int test_bye_after_sending_401(struct context *ctx) +{ + BEGIN(); + struct endpoint *a = &ctx->a, *b = &ctx->b; + struct call *a_call = a->call, *b_call = b->call; + struct event *e; + + a_call->sdp = "m=audio 5008 RTP/AVP 8"; + b_call->sdp = "m=audio 5010 RTP/AVP 0 8"; + +/* BYE after sending 401 + + A B + |-------INVITE------>| + |<----100 Trying-----| + | | + |<----180 Ringing----| + |<-------200---------| + |--------ACK-------->| + | | + |<------INVITE-------| + |--------401-------->| + |<--------ACK--------| + | | + |--------BYE-------->| + |<------200 OK-------| + | | +*/ + if (print_headings) + printf("TEST NUA-6.4: BYE after sending 401\n"); + + TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END())); + + INVITE(a, a_call, a_call->nh, + TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)), + SIPTAG_SUBJECT_STR("NUA-6.4"), + SOATAG_USER_SDP_STR(a_call->sdp), + NUTAG_AUTOANSWER(0), + TAG_END()); + + run_ab_until(ctx, -1, until_ready, -1, accept_call); + + free_events_in_list(ctx, a->events); + + TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite); + free_events_in_list(ctx, b->events); + + /* re-INVITE A. */ + INVITE(b, b_call, b_call->nh, + SIPTAG_SUBJECT_STR("NUA-6.4 re-INVITE"), + TAG_END()); + run_ab_until(ctx, -1, reject_reinvite_401, -1, until_final_response); + + TEST_1(nua_handle_has_active_call(a_call->nh)); + TEST_1(nua_handle_has_active_call(b_call->nh)); + + free_events_in_list(ctx, a->events); + free_events_in_list(ctx, b->events); + + BYE(a, a_call, a_call->nh, TAG_END()); + + run_ab_until(ctx, -1, until_terminated, -1, until_terminated); + + free_events_in_list(ctx, a->events); + nua_handle_destroy(a_call->nh), a_call->nh = NULL; + + free_events_in_list(ctx, b->events); + nua_handle_destroy(b_call->nh), b_call->nh = NULL; + + if (print_headings) + printf("TEST NUA-6.4: PASSED\n"); + + END(); +} + +int test_bye_after_receiving_401_to_update(struct context *ctx) +{ + BEGIN(); + struct endpoint *a = &ctx->a, *b = &ctx->b; + struct call *a_call = a->call, *b_call = b->call; + struct event *e; + + a_call->sdp = "m=audio 5008 RTP/AVP 8"; + b_call->sdp = "m=audio 5010 RTP/AVP 0 8"; + +/* BYE after receiving 401 + + A B + |-------INVITE------>| + |<----100 Trying-----| + | | + |<----180 Ringing----| + |<-------200---------| + |--------ACK-------->| + | | + |<------UPDATE-------| + |--------401-------->| + | | + |<--------BYE--------| + |------200 OK------->| + | | +*/ + if (print_headings) + printf("TEST NUA-6.5: BYE after receiving 401 to UPDATE\n"); + + TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END())); + + INVITE(a, a_call, a_call->nh, + TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)), + SIPTAG_SUBJECT_STR("NUA-6.5"), + SOATAG_USER_SDP_STR(a_call->sdp), + NUTAG_AUTOANSWER(0), + NUTAG_APPL_METHOD("UPDATE"), + TAG_END()); + + run_ab_until(ctx, -1, until_ready, -1, accept_call); + + free_events_in_list(ctx, a->events); + + TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite); + free_events_in_list(ctx, b->events); + + /* UPDATE A. */ + UPDATE(b, b_call, b_call->nh, + SIPTAG_SUBJECT_STR("NUA-6.4 UPDATE"), + TAG_END()); + BYE(b, b_call, b_call->nh, TAG_END()); /* Queued until nua_authenticate */ + run_ab_until(ctx, -1, reject_reinvite_401, -1, until_final_response); + + TEST_1(nua_handle_has_active_call(a_call->nh)); + TEST_1(nua_handle_has_active_call(b_call->nh)); + + free_events_in_list(ctx, a->events); + free_events_in_list(ctx, b->events); + + AUTHENTICATE(b, b_call, b_call->nh, TAG_END()); + + run_ab_until(ctx, -1, until_terminated, -1, until_terminated); + + free_events_in_list(ctx, a->events); + nua_handle_destroy(a_call->nh), a_call->nh = NULL; + + free_events_in_list(ctx, b->events); + nua_handle_destroy(b_call->nh), b_call->nh = NULL; + + if (print_headings) + printf("TEST NUA-6.3: PASSED\n"); + + END(); +} + +int reject_reinvite_401(CONDITION_PARAMS) +{ + void *request = nua_current_request(nua); save_event_in_list(ctx, event, ep, call); - switch (callstate(tags)) { - case nua_callstate_completing: - ack_sent = 0; - BYE(ep, call, nh, TAG_END()); + if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR))) + return 0; + + if (status < 200 && (event == nua_i_invite || event == nua_i_update)) { + RESPOND(ep, call, nh, SIP_401_UNAUTHORIZED, + NUTAG_WITH(request), + SIPTAG_WWW_AUTHENTICATE_STR("Digest realm=\"test_nua\", " + "nonce=\"nsdhfuds\", algorithm=MD5, " + "qop=\"auth\""), + TAG_END()); return 0; + } + + if (event == nua_i_state) switch (callstate(tags)) { + case nua_callstate_ready: + return 1; case nua_callstate_terminated: + if (call) + nua_handle_destroy(call->nh), call->nh = NULL; return 1; default: return 0; } + + return 0; +} + + +int test_early_bye(struct context *ctx) +{ + return + test_bye_before_200(ctx) || + test_bye_before_ack(ctx) || + test_bye_after_receiving_401(ctx) || + test_bye_after_sending_401(ctx) || + test_bye_after_receiving_401_to_update(ctx) || + 0; } Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_nua.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_nua.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_nua.c Fri Apr 13 10:33:30 2007 @@ -248,8 +248,15 @@ } #if HAVE_ALARM else if (o_alarm) { - alarm(o_expensive ? 60 : 120); signal(SIGALRM, sig_alarm); + if (o_expensive) { + printf("%s: extending timeout to %u because expensive tests\n", + name, 240); + alarm(240); + } + else { + alarm(120); + } } #endif @@ -316,8 +323,8 @@ retval |= test_session_timer(ctx); SINGLE_FAILURE_CHECK(); retval |= test_refer(ctx); SINGLE_FAILURE_CHECK(); retval |= test_100rel(ctx); SINGLE_FAILURE_CHECK(); - retval |= test_events(ctx); SINGLE_FAILURE_CHECK(); retval |= test_simple(ctx); SINGLE_FAILURE_CHECK(); + retval |= test_events(ctx); SINGLE_FAILURE_CHECK(); retval |= test_extension(ctx); SINGLE_FAILURE_CHECK(); if (!o_loop) break; Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_offer_answer.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_offer_answer.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_offer_answer.c Fri Apr 13 10:33:30 2007 @@ -86,7 +86,7 @@ sip_t *sip; if (print_headings) - printf("TEST NUA-6.3: No SDP answer from callee\n"); + printf("TEST NUA-6.5: No SDP answer from callee\n"); a_call->sdp = "m=audio 5008 RTP/AVP 8"; b_call->sdp = NULL; @@ -184,7 +184,7 @@ nua_handle_destroy(b_call->nh), b_call->nh = NULL; if (print_headings) - printf("TEST NUA-6.3: PASSED\n"); + printf("TEST NUA-6.5: PASSED\n"); END(); } @@ -229,7 +229,7 @@ sip_t const *sip; if (print_headings) - printf("TEST NUA-6.4: No SDP offer from caller\n"); + printf("TEST NUA-6.6: No SDP offer from caller\n"); a_call->sdp = "v=0\r\n" "o=- 1 1 IN IP4 127.0.0.1\r\n" @@ -330,7 +330,7 @@ nua_handle_destroy(b_call->nh), b_call->nh = NULL; if (print_headings) - printf("TEST NUA-6.4: PASSED\n"); + printf("TEST NUA-6.6: PASSED\n"); END(); } Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.c Fri Apr 13 10:33:30 2007 @@ -375,6 +375,27 @@ } } +void test_proxy_set_session_timer(struct proxy *p, + sip_time_t session_expires, + sip_time_t min_se) +{ + if (p) { + p->prefs.session_expires = session_expires; + p->prefs.min_se = min_se; + } +} + +void test_proxy_get_session_timer(struct proxy *p, + sip_time_t *return_session_expires, + sip_time_t *return_min_se) +{ + if (p) { + if (return_session_expires) + *return_session_expires = p->prefs.session_expires; + if (return_min_se) *return_min_se = p->prefs.min_se; + } +} + /* ---------------------------------------------------------------------- */ static sip_contact_t *create_transport_contacts(struct proxy *p) @@ -427,6 +448,7 @@ sip_session_expires_t *x = NULL, x0[1]; sip_min_se_t *min_se = NULL, min_se0[1]; + char const *require = NULL; mf = sip->sip_max_forwards; @@ -447,24 +469,33 @@ } if (method == sip_method_invite) { - if (!sip->sip_min_se || - sip->sip_min_se->min_delta < proxy->prefs.min_se) { - min_se = sip_min_se_init(min_se0); - min_se->min_delta = proxy->prefs.min_se; - } - - if (!sip->sip_session_expires) { - x = sip_session_expires_init(x0); - x->x_delta = proxy->prefs.session_expires; - } - else if (sip->sip_session_expires->x_delta < proxy->prefs.min_se - && sip_has_supported(sip->sip_supported, "timer")) { - if (min_se == NULL) - min_se = sip->sip_min_se; assert(min_se); - nta_incoming_treply(irq, SIP_422_SESSION_TIMER_TOO_SMALL, - SIPTAG_MIN_SE(min_se), - TAG_END()); - return 422; + if (proxy->prefs.min_se) { + if (!sip->sip_min_se || + sip->sip_min_se->min_delta < proxy->prefs.min_se) { + min_se = sip_min_se_init(min_se0); + min_se->min_delta = proxy->prefs.min_se; + } + + if (sip->sip_session_expires + && sip->sip_session_expires->x_delta < proxy->prefs.min_se + && sip_has_supported(sip->sip_supported, "timer")) { + if (min_se == NULL) + min_se = sip->sip_min_se; assert(min_se); + nta_incoming_treply(irq, SIP_422_SESSION_TIMER_TOO_SMALL, + SIPTAG_MIN_SE(min_se), + TAG_END()); + return 422; + } + } + + if (proxy->prefs.session_expires) { + if (!sip->sip_session_expires || + sip->sip_session_expires->x_delta > proxy->prefs.session_expires) { + x = sip_session_expires_init(x0); + x->x_delta = proxy->prefs.session_expires; + if (!sip_has_supported(sip->sip_supported, "timer")) + require = "timer"; + } } } @@ -528,6 +559,7 @@ SIPTAG_REQUEST(rq), SIPTAG_SESSION_EXPIRES(x), SIPTAG_MIN_SE(min_se), + SIPTAG_REQUIRE_STR(require), TAG_END()); if (t->client == NULL) { proxy_transaction_destroy(t); Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.h ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.h (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_proxy.h Fri Apr 13 10:33:30 2007 @@ -48,6 +48,14 @@ sip_time_t *return_expires, sip_time_t *return_max_expires); +void test_proxy_set_session_timer(struct proxy *p, + sip_time_t session_expires, + sip_time_t min_se); + +void test_proxy_get_session_timer(struct proxy *p, + sip_time_t *return_session_expires, + sip_time_t *return_min_se); + SOFIA_END_DECLS #endif Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_register.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_register.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_register.c Fri Apr 13 10:33:30 2007 @@ -685,6 +685,10 @@ run_a_until(ctx, -1, save_until_final_response); TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_unregister); + if (e->data->e_status == 100) { + TEST_1(e = e->next); + TEST_E(e->data->e_event, nua_r_unregister); + } TEST(e->data->e_status, 200); TEST_1(sip = sip_object(e->data->e_msg)); TEST_1(!sip->sip_contact); Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_session_timer.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_session_timer.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_session_timer.c Fri Apr 13 10:33:30 2007 @@ -22,7 +22,7 @@ * */ -/**@CFILE test_nua_re_invite.c +/**@CFILE test_session_timer.c * @brief NUA-8 tests: Session timer, UPDATE * * @author Pekka Pessi <Pekka.Pessi@nokia.com> @@ -40,11 +40,13 @@ #elif HAVE_FUNCTION #define __func__ __FUNCTION__ #else -#define __func__ "test_call_hold" +#define __func__ "test_session_timer" #endif /* ======================================================================== */ +static size_t remove_update(void *a, void *message, size_t len); + int test_session_timer(struct context *ctx) { BEGIN(); @@ -69,22 +71,6 @@ |--INVITE->| | |<--422----| | |---ACK--->| | - | | - |-------INVITE------>| - |<-------422---------| - |--------ACK-------->| - | | - |-------INVITE------>| - |<----100 Trying-----| - | | - |<----180 Ringing----| - | | - |<------200 OK-------| - |--------ACK-------->| - | | - |<-------BYE---------| - |-------200 OK-------| - | | */ @@ -94,8 +80,15 @@ a_call->sdp = "m=audio 5008 RTP/AVP 8"; b_call->sdp = "m=audio 5010 RTP/AVP 0 8"; + /* We negotiate session timer of 6 second */ + /* Disable session timer from proxy */ + test_proxy_set_session_timer(ctx->p, 0, 0); + nua_set_params(ctx->b.nua, NUTAG_SESSION_REFRESHER(nua_any_refresher), + NUTAG_MIN_SE(1), + NUTAG_SESSION_TIMER(6), + NTATAG_SIP_T1X64(8000), TAG_END()); run_b_until(ctx, nua_r_set_params, until_final_response); @@ -159,23 +152,132 @@ if (print_headings) printf("TEST NUA-8.1.1: PASSED\n"); + if (ctx->expensive) { + nua_set_hparams(a_call->nh, + NUTAG_SUPPORTED("timer"), + NUTAG_MIN_SE(1), + NUTAG_SESSION_TIMER(5), + TAG_END()); + run_a_until(ctx, nua_r_set_params, until_final_response); + + if (print_headings) + printf("TEST NUA-8.1.2: Wait for refresh using INVITE\n"); + + run_ab_until(ctx, -1, until_ready, -1, until_ready); + + free_events_in_list(ctx, a->events); + free_events_in_list(ctx, b->events); + + if (print_headings) + printf("TEST NUA-8.1.2: PASSED\n"); + + nua_set_hparams(b_call->nh, + NUTAG_UPDATE_REFRESH(1), + TAG_END()); + run_b_until(ctx, nua_r_set_params, until_final_response); + + if (print_headings) + printf("TEST NUA-8.1.3: Wait for refresh using UPDATE\n"); + + run_ab_until(ctx, -1, until_ready, -1, until_ready); + + TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_update); + + free_events_in_list(ctx, a->events); + free_events_in_list(ctx, b->events); + + if (print_headings) + printf("TEST NUA-8.1.3: PASSED\n"); + + if (ctx->nat) { + struct nat_filter *f; + + if (print_headings) + printf("TEST NUA-8.1.4: filter UPDATE, wait until session expires\n"); + + f = test_nat_add_filter(ctx->nat, remove_update, NULL, nat_inbound); + TEST_1(f); + + run_ab_until(ctx, -1, until_terminated, -1, until_terminated); + + TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_bye); + + free_events_in_list(ctx, a->events); + free_events_in_list(ctx, b->events); + + nua_handle_destroy(a_call->nh), a_call->nh = NULL; + nua_handle_destroy(b_call->nh), b_call->nh = NULL; + + test_nat_remove_filter(ctx->nat, f); + + if (print_headings) + printf("TEST NUA-8.1.4: PASSED\n"); + } + } + + if (b_call->nh) { + if (print_headings) + printf("TEST NUA-8.1.9: Terminate first session timer call\n"); + + BYE(b, b_call, b_call->nh, TAG_END()); + run_ab_until(ctx, -1, until_terminated, -1, until_terminated); + free_events_in_list(ctx, a->events); + 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-8.1.9: PASSED\n"); + } + + /* + | | + |-------INVITE------>| + |<-------422---------| + |--------ACK-------->| + | | + |-------INVITE------>| + |<----100 Trying-----| + | | + |<----180 Ringing----| + | | + |<------200 OK-------| + |--------ACK-------->| + | | + |<-------BYE---------| + |-------200 OK-------| + | | + */ + if (print_headings) - printf("TEST NUA-8.1.2: Session timers negotiation\n"); + printf("TEST NUA-8.2: Session timers negotiation\n"); + + test_proxy_set_session_timer(ctx->p, 180, 90); + + nua_set_params(a->nua, + NUTAG_SUPPORTED("timer"), + TAG_END()); + + run_a_until(ctx, nua_r_set_params, until_final_response); - nua_set_hparams(b_call->nh, - NUTAG_AUTOANSWER(0), - NUTAG_MIN_SE(120), - TAG_END()); + nua_set_params(b->nua, + NUTAG_AUTOANSWER(0), + NUTAG_MIN_SE(120), + NTATAG_SIP_T1X64(2000), + 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), SIPTAG_SUPPORTED_STR("100rel, timer"), - NUTAG_SESSION_TIMER(15), - NUTAG_MIN_SE(5), + NUTAG_SESSION_TIMER(4), + NUTAG_MIN_SE(3), TAG_END()); run_ab_until(ctx, -1, until_ready, -1, accept_call); @@ -252,17 +354,17 @@ free_events_in_list(ctx, b->events); if (print_headings) - printf("TEST NUA-8.1: PASSED\n"); + printf("TEST NUA-8.2: PASSED\n"); if (print_headings) - printf("TEST NUA-8.2: use UPDATE\n"); + printf("TEST NUA-8.3: UPDATE with session timer headers\n"); UPDATE(b, b_call, b_call->nh, TAG_END()); run_ab_until(ctx, -1, until_ready, -1, until_ready); /* Events from B (who sent UPDATE) */ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_state); - TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */ + TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */ TEST_1(is_offer_sent(e->data->e_tags)); if (!e->next) run_b_until(ctx, -1, until_ready); @@ -313,7 +415,20 @@ nua_handle_destroy(b_call->nh), b_call->nh = NULL; if (print_headings) - printf("TEST NUA-8.2: PASSED\n"); + printf("TEST NUA-8.3: PASSED\n"); END(); } + +static +size_t remove_update(void *a, void *message, size_t len) +{ + (void)a; + + if (strncmp("UPDATE ", message, 7) == 0) { + return 0; + } + + return len; +} + Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_simple.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_simple.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/nua/test_simple.c Fri Apr 13 10:33:30 2007 @@ -972,6 +972,7 @@ return ep->flags.bit0 && ep->flags.bit1; } + /* ---------------------------------------------------------------------- */ /* Unsolicited NOTIFY */ @@ -1122,7 +1123,7 @@ nua_handle_destroy(b_call->nh), b_call->nh = NULL; if (print_headings) - printf("TEST NUA-11.6: PASSED\n"); + printf("TEST NUA-11.7: PASSED\n"); END(); } @@ -1144,6 +1145,155 @@ } /* ======================================================================== */ + +int save_until_subscription_terminated(CONDITION_PARAMS); +int accept_subscription_until_terminated(CONDITION_PARAMS); + +/* Timeout subscription */ +int test_subscription_timeout(struct context *ctx) +{ + BEGIN(); + + struct endpoint *a = &ctx->a, *b = &ctx->b; + struct call *a_call = a->call, *b_call = b->call; + struct event *e; + sip_t const *sip; + tagi_t const *n_tags, *r_tags; + + if (print_headings) + printf("TEST NUA-11.8: subscribe and wait until subscription times out\n"); + + TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END())); + + METHOD(a, a_call, a_call->nh, + NUTAG_METHOD("SUBSCRIBE"), + NUTAG_URL(b->contact->m_url), + SIPTAG_EVENT_STR("presence"), + SIPTAG_ACCEPT_STR("application/xpidf, application/pidf+xml"), + SIPTAG_EXPIRES_STR("2"), + NUTAG_APPL_METHOD("NOTIFY"), + NUTAG_DIALOG(2), + TAG_END()); + + run_ab_until(ctx, + -1, save_until_subscription_terminated, + -1, accept_subscription_until_terminated); + + /* 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(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"); + TEST_1(sip->sip_subscription_state); + TEST_S(sip->sip_subscription_state->ss_substate, "pending"); + 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_pending); + + TEST_1(e = e->next); 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); + TEST_1(sip = sip_object(e->data->e_msg)); + 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(!e->next); + + free_events_in_list(ctx, a->events); + + /* Server events: nua_i_subscribe, nua_r_notify */ + TEST_1(e = b->events->head); + TEST_E(e->data->e_event, nua_i_subscribe); + TEST_E(e->data->e_status, 100); + TEST_1(sip = sip_object(e->data->e_msg)); + + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_notify); + 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_pending); + + /* Notifier events: 2nd nua_r_notify */ + TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_notify); + TEST_1(e->data->e_status >= 200); + 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_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-11.8: PASSED\n"); + + END(); +} + +int save_until_subscription_terminated(CONDITION_PARAMS) +{ + void *with = nua_current_request(nua); + + save_event_in_list(ctx, event, ep, call); + + if (event == nua_i_notify) { + if (status < 200) + RESPOND(ep, call, nh, SIP_200_OK, NUTAG_WITH(with), TAG_END()); + + tags = tl_find(tags, nutag_substate); + return tags && tags->t_value == nua_substate_terminated; + } + + return 0; +} + +int accept_subscription_until_terminated(CONDITION_PARAMS) +{ + void *with = nua_current_request(nua); + + save_event_in_list(ctx, event, ep, call); + + if (event == nua_i_subscribe && status < 200) { + RESPOND(ep, call, nh, SIP_202_ACCEPTED, + NUTAG_WITH(with), + SIPTAG_EXPIRES_STR("360"), + TAG_END()); + NOTIFY(ep, call, nh, + SIPTAG_EVENT(sip->sip_event), + SIPTAG_CONTENT_TYPE_STR("application/pidf+xml"), + SIPTAG_PAYLOAD_STR(presence_closed), + NUTAG_SUBSTATE(nua_substate_pending), + TAG_END()); + } + else if (event == nua_r_notify) { + tags = tl_find(tags, nutag_substate); + return tags && tags->t_value == nua_substate_terminated; + } + + return 0; +} + + +/* ======================================================================== */ /* Test simple methods: MESSAGE, PUBLISH, SUBSCRIBE/NOTIFY */ int test_simple(struct context *ctx) @@ -1154,5 +1304,6 @@ || test_subscribe_notify(ctx) || test_subscribe_notify_graceful(ctx) || test_newsub_notify(ctx) + || test_subscription_timeout(ctx) ; } Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/sdp/run_test_sdp ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/sdp/run_test_sdp (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/sdp/run_test_sdp Fri Apr 13 10:33:30 2007 @@ -6,7 +6,8 @@ # test_sdp="${1:-./test_sdp}" -tests="${2:-${0%/*}/tests}" +sdp_path=`dirname $0` +tests="${2:-${sdp_path}/tests}" if test -r $tests/message-1.sdp ; then @@ -20,4 +21,3 @@ echo "sdp run-tests: no tests found in $tests, skipping." exit 77 fi - Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/sip/sip_feature.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/sip/sip_feature.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/sip/sip_feature.c Fri Apr 13 10:33:30 2007 @@ -336,7 +336,7 @@ return msg_list_e(b, bsiz, h, f); } -/** Check if required feature is supported. +/** Check if required feature is not supported. * * @retval NULL if all the required features are supported * @retval pointer to a @Unsupported header or @@ -351,7 +351,7 @@ } -/** Check if required feature is supported. +/** Check if required feature is not supported. * * @retval NULL if all the required features are supported * @retval pointer to a @Unsupported header or @@ -370,7 +370,7 @@ } -/** Ensure that required features are supported. +/** Check if required features are not supported. * * The supported features can be listed in @Supported, @Require or * @ProxyRequire headers (in @a supported, @a by_require, or @a Modified: freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/sip/torture_sip.c ============================================================================== --- freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/sip/torture_sip.c (original) +++ freeswitch/branches/mikej/sofiasip-upgrade/libs/sofia-sip/libsofia-sip-ua/sip/torture_sip.c Fri Apr 13 10:33:30 2007 @@ -354,7 +354,7 @@ su_home_t home[1] = { SU_HOME_INIT(home) }; char const *display; url_t url[1]; - char const * const *params; + msg_param_t const *params; char const *comment; char const na[] = "Raaka Arska <tel:+358501970>;param=1;humppa (test) "; char const na2[] = "tel:+358501970;param=1;humppa (test) "; @@ -744,8 +744,6 @@ } END(); - - return 0; } msg_t *read_message(int flags, char const buffer[])