merge to sofia darcs:

Mon Feb 25 09:49:39 EST 2008  Pekka.Pessi@nokia.com
  * nua_subnotref.c: fixed problems re-calculating the subscription duration upon NOTIFY
  
  Thanks for Colin Whittaker for reporting this problem.

Wed Feb  6 12:05:13 EST 2008  Pekka.Pessi@nokia.com
  * nua_stack.c: pass events while in shutdown if NUTAG_SHUTDOWN_EVENTS(1) has been set

Wed Feb  6 12:05:46 EST 2008  Pekka.Pessi@nokia.com
  * nua: using global preferences. Added NUTAG_SHUTDOWN_EVENTS().

Mon Feb 25 12:10:31 EST 2008  Pekka.Pessi@nokia.com
  * nua: renamed crm_deinit as crm_complete, commented nua_client_methods_t initializers

Mon Feb 25 14:14:15 EST 2008  Pekka.Pessi@nokia.com
  * nua: added NUTAG_SUB_EXPIRES()

Tue Feb 26 11:09:37 EST 2008  Pekka.Pessi@nokia.com
  * nua: initial fix for sf.net bug #1827511
  
  BYE can now be challenged.

Tue Feb 26 11:19:40 EST 2008  Pekka.Pessi@nokia.com
  * nua_session.c: ensure correct call state
  
  Avoid assert() on bad input from network - crash reported by Michael Jerris.
  
  Also if calls are being terminated, reject new INVITE/UPDATE/PRACK requests
  with 481.

Tue Feb 26 11:33:19 EST 2008  Pekka.Pessi@nokia.com
  * sdp_print.c: pt 9 is, like, g722. 19 is used by nobody, so it can be used as filler?

Tue Feb 26 11:40:00 EST 2008  Pekka.Pessi@nokia.com
  * nua_session.c: fixed non-compiling fix on session state check



git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@7738 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Michael Jerris 2008-02-26 17:00:03 +00:00
parent be1abfe573
commit 6307891557
24 changed files with 1283 additions and 464 deletions

View File

@ -373,8 +373,12 @@ void nua_dialog_usage_remove_at(nua_owner_t *own,
/* Destroy saved client request */
if (nua_client_is_bound(du->du_cr)) {
nua_client_bind(cr = du->du_cr, NULL);
if (!nua_client_is_queued(cr) &&
!nua_client_is_reporting(cr))
if (nua_client_is_queued(cr))
nua_client_request_complete(cr);
else if (nua_client_is_reporting(cr))
;
else
nua_client_request_destroy(cr);
}

View File

@ -253,11 +253,11 @@ typedef struct {
nta_outgoing_t *orq,
tagi_t const *tags);
/** @a crm_deinit is called when a client-side request is destroyed.
/** @a crm_complete is called when a client-side request is destroyed.
*
* @return The return value should be 0. It is currently ignored.
*/
int (*crm_deinit)(nua_client_request_t *);
int (*crm_complete)(nua_client_request_t *);
} nua_client_methods_t;
@ -516,6 +516,8 @@ void *nua_private_client_request(nua_client_request_t const *cr)
return (void *)(cr + 1);
}
void nua_client_request_complete(nua_client_request_t *);
void nua_client_request_destroy(nua_client_request_t *);
int nua_client_request_queue(nua_client_request_t *cr);

View File

@ -74,18 +74,21 @@
*/
static nua_client_methods_t const nua_method_client_methods = {
SIP_METHOD_UNKNOWN,
0,
{
SIP_METHOD_UNKNOWN, /* crm_method, crm_method_name */
0, /* crm_extra */
{ /* crm_flags */
/* create_dialog */ 0,
/* in_dialog */ 0,
/* target_refresh */ 1,
},
/* nua_method_client_template */ NULL,
/* nua_method_client_init */ NULL,
/* nua_method_client_request */ NULL,
/* nua_method_client_check_restart */ NULL,
/* nua_method_client_response */ NULL
NULL, /* crm_template */
NULL, /* crm_init */
NULL, /* crm_send */
NULL, /* crm_check_restart */
NULL, /* crm_recv */
NULL, /* crm_preliminary */
NULL, /* crm_report */
NULL, /* crm_complete */
};
int

View File

@ -77,18 +77,22 @@ static int nua_message_client_init(nua_client_request_t *cr,
tagi_t const *tags);
static nua_client_methods_t const nua_message_client_methods = {
SIP_METHOD_MESSAGE,
0,
{
SIP_METHOD_MESSAGE, /* crm_method, crm_method_name */
0, /* crm_extra */
{ /* crm_flags */
/* create_dialog */ 0,
/* in_dialog */ 0,
/* target refresh */ 0
},
/* nua_message_client_template */ NULL,
nua_message_client_init,
/*nua_message_client_request*/ NULL,
/* nua_message_client_check_restart */ NULL,
/*nua_message_client_response*/ NULL
NULL, /* crm_template */
nua_message_client_init, /* crm_init */
NULL, /* crm_send */
NULL, /* crm_check_restart */
NULL, /* crm_recv */
NULL, /* crm_preliminary */
NULL, /* crm_report */
NULL, /* crm_complete */
};
int

View File

@ -237,7 +237,8 @@ int nua_subscribe_server_preprocess(nua_server_request_t *sr)
sip_event_t *o = sip->sip_event;
char const *event = o ? o->o_type : NULL;
/* Maximum expiration time */
unsigned long expires = 3600;
unsigned long expires = sip->sip_expires ? sip->sip_expires->ex_delta : 3600;
sip_time_t now = sip_now();
assert(nh && nh->nh_nua->nua_dhandle != nh);
@ -259,9 +260,10 @@ int nua_subscribe_server_preprocess(nua_server_request_t *sr)
nu = nua_dialog_usage_private(du);
if (sip->sip_expires && sip->sip_expires->ex_delta < expires)
expires = sip->sip_expires->ex_delta;
nu->nu_requested = sip_now() + expires;
if (now + expires >= now)
nu->nu_requested = now + expires;
else
nu->nu_requested = SIP_TIME_MAX - 1;
#if SU_HAVE_EXPERIMENTAL
nu->nu_etags =
@ -295,9 +297,23 @@ int nua_subscribe_server_respond(nua_server_request_t *sr, tagi_t const *tags)
sip_time_t now = sip_now();
if (nu->nu_requested) {
if (nu->nu_requested > nu->nu_expires)
if (sip->sip_expires) {
/* Expires in response can only shorten the expiration time */
if (nu->nu_requested > now + sip->sip_expires->ex_delta)
nu->nu_requested = now + sip->sip_expires->ex_delta;
}
else {
unsigned sub_expires = NH_PGET(sr->sr_owner, sub_expires);
if (nu->nu_requested > now + sub_expires)
nu->nu_requested = now + sub_expires;
}
if (nu->nu_requested >= now)
nu->nu_expires = nu->nu_requested;
else if (nu->nu_expires <= now || nu->nu_requested <= now)
else
nu->nu_expires = now;
if (nu->nu_expires <= now)
nu->nu_substate = nua_substate_terminated;
}
@ -305,7 +321,7 @@ int nua_subscribe_server_respond(nua_server_request_t *sr, tagi_t const *tags)
ex->ex_delta = nu->nu_expires - now;
}
else {
/* Add header Expires: 0 */
/* Always add header Expires: 0 */
}
if (!sip->sip_expires || sip->sip_expires->ex_delta > ex->ex_delta)
@ -420,20 +436,21 @@ static int nua_notify_client_report(nua_client_request_t *cr,
tagi_t const *tags);
static nua_client_methods_t const nua_notify_client_methods = {
SIP_METHOD_NOTIFY,
0,
{
SIP_METHOD_NOTIFY, /* crm_method, crm_method_name */
0, /* crm_extra */
{ /* crm_flags */
/* create_dialog */ 1,
/* in_dialog */ 1,
/* target refresh */ 1
},
/* nua_notify_client_template */ NULL,
nua_notify_client_init,
nua_notify_client_request,
/* nua_notify_client_check_restart */ NULL,
/* nua_notify_client_response */ NULL,
/* nua_notify_client_preliminary */ NULL,
nua_notify_client_report
NULL, /* crm_template */
nua_notify_client_init, /* crm_init */
nua_notify_client_request, /* crm_send */
NULL, /* crm_check_restart */
NULL, /* crm_recv */
NULL, /* crm_preliminary */
nua_notify_client_report, /* crm_report */
NULL, /* crm_complete */
};
/**@internal Send NOTIFY. */

View File

@ -88,18 +88,21 @@
*/
static nua_client_methods_t const nua_options_client_methods = {
SIP_METHOD_OPTIONS,
0,
{
SIP_METHOD_OPTIONS, /* crm_method, crm_method_name */
0, /* crm_extra */
{ /* crm_flags */
/* create_dialog */ 0,
/* in_dialog */ 0,
/* target refresh */ 0
},
/*nua_options_client_template*/ NULL,
/*nua_options_client_init*/ NULL,
/*nua_options_client_request*/ NULL,
/* nua_options_client_check_restart */ NULL,
/*nua_options_client_response*/ NULL
NULL, /* crm_template */
NULL, /* crm_init */
NULL, /* crm_send */
NULL, /* crm_check_restart */
NULL, /* crm_recv */
NULL, /* crm_preliminary */
NULL, /* crm_report */
NULL, /* crm_complete */
};
int nua_stack_options(nua_t *nua,

View File

@ -77,19 +77,27 @@ su_inline int nhp_is_any_set(nua_handle_preferences_t const *nhp)
su_inline void nhp_or_set(nua_handle_preferences_t *a,
nua_handle_preferences_t const *b)
{
unsigned *ap = a->nhp_set_.set_unsigned;
unsigned const *bp = b->nhp_set_.set_unsigned;
size_t i;
memcpy(a, b, offsetof(nua_handle_preferences_t, nhp_set));
/* Bitwise or of bitfields, casted to unsigned */
a->nhp_set_.set_unsigned[0] |= b->nhp_set_.set_unsigned[0];
a->nhp_set_.set_unsigned[1] |= b->nhp_set_.set_unsigned[1];
/*
unsigned *ap, const *bp;
size_t i;
ap = a->nhp_set_.set_unsigned;
bp = b->nhp_set_.set_unsigned;
for (i = 0; i < (sizeof a->nhp_set); i += (sizeof *ap))
*ap++ |= *bp++;
*/
}
static int nhp_set_tags(su_home_t *home,
nua_handle_preferences_t *nhp,
int global,
nua_global_preferences_t *ngp,
tagi_t const *tags);
static int nhp_merge_lists(su_home_t *home,
@ -101,11 +109,11 @@ static int nhp_merge_lists(su_home_t *home,
int always_merge,
tag_value_t value);
static
nua_handle_preferences_t *nhp_move_params(su_home_t *home,
nua_handle_preferences_t *dst,
su_home_t *tmphome,
nua_handle_preferences_t const *src);
static int nhp_save_params(nua_handle_t *nh,
su_home_t *tmphome,
nua_global_preferences_t *gsrc,
nua_handle_preferences_t *src);
/* ====================================================================== */
/* Magical NUTAG_USER_AGENT() - add NHP_USER_AGENT there if it is not there */
@ -169,6 +177,7 @@ int nua_stack_set_defaults(nua_handle_t *nh,
NHP_SET(nhp, refer_with_id, 1);
NHP_SET(nhp, substate, nua_substate_active);
NHP_SET(nhp, sub_expires, 3600);
NHP_SET(nhp, allow, sip_allow_make(home, nua_allow_str));
NHP_SET(nhp, supported, sip_supported_make(home, "timer, 100rel"));
@ -198,20 +207,12 @@ int nua_stack_set_from(nua_t *nua, int initial, tagi_t const *tags)
sip_from_t *f = NULL, f0[1];
int set;
char const *uicc_name = "default";
tl_gets(tags,
/* By nua_stack_set_from() */
SIPTAG_FROM_REF(from),
SIPTAG_FROM_STR_REF(str),
NUTAG_UICC_REF(uicc_name),
TAG_END());
#if HAVE_UICC_H
if (initial && uicc_name)
nua->nua_uicc = uicc_create(root, uicc_name);
#endif
if (!initial && from == NONE && str == NONE)
return 0;
@ -325,6 +326,7 @@ int nua_stack_init_instance(nua_handle_t *nh, tagi_t const *tags)
* NUTAG_SMIME_SIGNATURE() \n
* NUTAG_SOA_NAME() \n
* NUTAG_SUBSTATE() \n
* NUTAG_SUB_EXPIRES() \n
* NUTAG_SUPPORTED(), SIPTAG_SUPPORTED(), and SIPTAG_SUPPORTED_STR() \n
* NUTAG_UPDATE_REFRESH() \n
* NUTAG_USER_AGENT(), SIPTAG_USER_AGENT() and SIPTAG_USER_AGENT_STR() \n
@ -437,6 +439,7 @@ int nua_stack_init_instance(nua_handle_t *nh, tagi_t const *tags)
* NUTAG_SESSION_TIMER() \n
* NUTAG_SOA_NAME() \n
* NUTAG_SUBSTATE() \n
* NUTAG_SUB_EXPIRES() \n
* NUTAG_SUPPORTED(), SIPTAG_SUPPORTED(), and SIPTAG_SUPPORTED_STR() \n
* NUTAG_UPDATE_REFRESH() \n
* NUTAG_USER_AGENT(), SIPTAG_USER_AGENT() and SIPTAG_USER_AGENT_STR() \n
@ -475,146 +478,124 @@ int nua_stack_set_params(nua_t *nua, nua_handle_t *nh, nua_event_t e,
tagi_t const *tags)
{
nua_handle_t *dnh = nua->nua_dhandle;
nua_handle_preferences_t tmp[1], *nhp = nh->nh_prefs;
nua_handle_preferences_t const *dnhp = dnh->nh_prefs;
su_home_t tmphome[1] = { SU_HOME_INIT(tmphome) };
tagi_t const *ptags;
int error, global;
int status = 900;
char const *phrase = "Error storing parameters";
sip_supported_t const *supported = NULL;
sip_allow_t const *allow = NULL;
sip_allow_events_t const *allow_events = NULL;
sip_allow_t const *appl_method = NULL;
int status;
char const *phrase;
enter;
ptags = !nh->nh_used_ptags ? nh->nh_ptags : NULL;
{
su_home_t tmphome[1] = { SU_HOME_INIT(tmphome) };
nua_handle_preferences_t *nhp = nh->nh_prefs;
nua_handle_preferences_t const *dnhp = dnh->nh_prefs;
nua_handle_preferences_t tmp[1];
nua_global_preferences_t gtmp[1], *ngp = NULL;
*tmp = *nhp; NHP_UNSET_ALL(tmp);
*tmp = *nhp; NHP_UNSET_ALL(tmp);
/* Supported features, allowed methods and events are merged
with previous ones */
if (!NHP_ISSET(nhp, supported))
supported = tmp->nhp_supported = dnhp->nhp_supported;
if (!NHP_ISSET(nhp, allow))
allow = tmp->nhp_allow = dnhp->nhp_allow;
if (!NHP_ISSET(nhp, allow_events))
allow_events = tmp->nhp_allow_events = dnhp->nhp_allow_events;
if (!NHP_ISSET(nhp, appl_method))
appl_method = tmp->nhp_appl_method = dnhp->nhp_appl_method;
error = 0;
global = nh == dnh; /* save also stack-specific params */
/*
* Supported features, allowed methods and events are merged
* with previous or default settings.
*
* Here we just copy pointers from default settings. However when saving
* settings we have to be extra careful so that we
* 1) zero the pointers if the setting has not been modified
* 2) do not free pointer if the setting has been modified
* See NHP_ZAP_OVERRIDEN() below for gorier details.
*/
if (!NHP_ISSET(nhp, supported))
tmp->nhp_supported = dnhp->nhp_supported;
if (!NHP_ISSET(nhp, allow))
tmp->nhp_allow = dnhp->nhp_allow;
if (!NHP_ISSET(nhp, allow_events))
tmp->nhp_allow_events = dnhp->nhp_allow_events;
if (!NHP_ISSET(nhp, appl_method))
tmp->nhp_appl_method = dnhp->nhp_appl_method;
/* Set and save parameters to tmp */
if (nhp_set_tags(tmphome, tmp, global, ptags) < 0)
error = 1, phrase = "Error storing default handle parameters";
else if (nhp_set_tags(tmphome, tmp, global, tags) < 0)
error = 1, phrase = "Error storing parameters";
else {
if (NHP_IS_ANY_SET(tmp)) {
if (tmp->nhp_supported == supported)
tmp->nhp_supported = NULL;
if (nh == dnh) /* nua_set_params() call, save stack-wide params, too */
ngp = gtmp, *gtmp = *nua->nua_prefs;
if (tmp->nhp_allow == allow)
tmp->nhp_allow = NULL;
/* Set and save parameters to tmp */
if (!nh->nh_used_ptags &&
nhp_set_tags(tmphome, tmp, NULL, nh->nh_ptags) < 0)
status = 900, phrase = "Error storing default handle parameters";
else if (nhp_set_tags(tmphome, tmp, ngp, tags) < 0)
status = 900, phrase = "Error storing parameters";
else if (nhp_save_params(nh, tmphome, ngp, tmp) < 0)
status = 900, phrase = su_strerror(ENOMEM);
else
status = 200, phrase = "OK", nh->nh_used_ptags = 1;
if (tmp->nhp_allow_events == allow_events)
tmp->nhp_allow_events = NULL;
su_home_deinit(tmphome);
}
if (tmp->nhp_appl_method == appl_method)
tmp->nhp_appl_method = NULL;
if (status == 200) {
nua_handle_preferences_t const *nhp = nh->nh_prefs;
nua_handle_preferences_t const *dnhp = dnh->nh_prefs;
/* Move parameters from tmp to nhp (or allocate new nhp) */
if (nh != dnh && nhp == dnh->nh_prefs)
nhp = NULL;
nhp = nhp_move_params(nh->nh_home, nhp, tmphome, tmp);
if (!nh->nh_soa && NHP_GET(nhp, dnhp, media_enable)) {
/* Create soa when needed */
char const *soa_name = NHP_GET(nhp, dnhp, soa_name);
if (nhp)
nh->nh_prefs = nhp;
else
/* Fail miserably with ENOMEM */
error = 1, status = 900, phrase = su_strerror(ENOMEM);
if (dnh->nh_soa)
nh->nh_soa = soa_clone(dnh->nh_soa, nua->nua_root, nh);
else
nh->nh_soa = soa_create(soa_name, nua->nua_root, nh);
if (!nh->nh_soa)
status = 900, phrase = "Error Creating SOA Object";
else if (soa_set_params(nh->nh_soa, TAG_NEXT(nh->nh_ptags)) < 0)
status = 900, phrase = "Error Setting SOA Parameters";
}
else if (nh->nh_soa && !NHP_GET(nhp, dnhp, media_enable)) {
/* ... destroy soa when not needed */
soa_destroy(nh->nh_soa), nh->nh_soa = NULL;
}
if (!error)
nh->nh_used_ptags = 1;
if (status == 200 && tags && nh->nh_soa &&
soa_set_params(nh->nh_soa, TAG_NEXT(tags)) < 0)
status = 900, phrase = "Error Setting SOA Parameters";
}
su_home_deinit(tmphome);
if (status == 200 && nh == dnh) {
/* Set stack-specific things below */
if (nua_stack_set_smime_params(nua, tags) < 0) {
status = 900, phrase = "Error setting S/MIME parameters";
}
else if (nua->nua_nta && nta_agent_set_params(nua->nua_nta, TAG_NEXT(tags)) < 0) {
status = 900, phrase = "Error setting NTA parameters";
}
else {
nua_stack_set_from(nua, 0, tags);
if (error)
;
else if (!nh->nh_soa && NHP_GET(nhp, dnhp, media_enable)) {
/* Create soa when needed */
char const *soa_name = NHP_GET(nhp, dnhp, soa_name);
if (dnh->nh_soa)
nh->nh_soa = soa_clone(dnh->nh_soa, nua->nua_root, nh);
else
nh->nh_soa = soa_create(soa_name, nua->nua_root, nh);
ptags = nh->nh_ptags;
if (!nh->nh_soa)
error = 1, status = 900, phrase = "Error Creating SOA Object";
}
else if (nh->nh_soa && !NHP_GET(nhp, dnhp, media_enable)) {
/* ... destroy soa when not needed */
soa_destroy(nh->nh_soa), nh->nh_soa = NULL;
if (nua->nua_prefs->ngp_detect_network_updates)
nua_stack_launch_network_change_detector(nua);
}
}
if (!error && nh->nh_soa) {
if ((ptags && soa_set_params(nh->nh_soa, TAG_NEXT(ptags)) < 0) ||
(tags && soa_set_params(nh->nh_soa, TAG_NEXT(tags)) < 0))
error = 1, status = 900, phrase = "Error Setting SOA Parameters";
}
if (error || nh != dnh) {
;
}
else if (nua_stack_set_smime_params(nua, tags) < 0) {
error = 1, status = 900, phrase = "Error setting S/MIME parameters";
}
else if (!nua->nua_nta) {
}
/* Set stack-specific things below */
else if (nta_agent_set_params(nua->nua_nta, TAG_NEXT(tags)) < 0) {
status = 900, phrase = "Error setting NTA parameters";
error = 1;
}
else {
nua_stack_set_from(nua, 0, tags);
if (NHP_ISSET(nhp, detect_network_updates))
nua_stack_launch_network_change_detector(nua);
}
if (error) {
if (status != 200) {
if (e == nua_i_none)
SU_DEBUG_1(("nua_set_params(): failed: %s\n", phrase));
return UA_EVENT2(e, status, phrase), -1;
}
if (e == nua_r_set_params)
UA_EVENT2(e, 200, "OK");
return 0;
else {
if (e == nua_r_set_params)
UA_EVENT2(e, status, phrase);
return 0;
}
}
/** Parse parameters from tags to @a nhp.
/** Parse parameters from tags to @a nhp or @a ngp.
*
* @param home allocate new values from @a home
* @param nhp structure to store handle preferences
* @param global if true, save also global parameters
* @param ngp structure to store global preferences
* @param tags list of tags to parse
*/
static int nhp_set_tags(su_home_t *home,
nua_handle_preferences_t *nhp,
int global,
nua_global_preferences_t *ngp,
tagi_t const *tags)
{
@ -826,6 +807,10 @@ static int nhp_set_tags(su_home_t *home,
else if (tag == nutag_substate) {
NHP_SET(nhp, substate, (int)value);
}
/* NUTAG_SUB_EXPIRES(sub_expires) */
else if (tag == nutag_sub_expires) {
NHP_SET(nhp, sub_expires, value);
}
/* NUTAG_KEEPALIVE(keepalive) */
else if (tag == nutag_keepalive) {
NHP_SET(nhp, keepalive, (unsigned)value);
@ -997,7 +982,7 @@ static int nhp_set_tags(su_home_t *home,
NHP_SET_STR(nhp, outbound, value);
}
/* NUTAG_DETECT_NETWORK_UPDATES(detect_network_updates) */
else if (global && tag == nutag_detect_network_updates) {
else if (ngp && tag == nutag_detect_network_updates) {
int detector = (int)value;
if (detector < NUA_NW_DETECT_NOTHING)
@ -1005,7 +990,13 @@ static int nhp_set_tags(su_home_t *home,
else if (detector > NUA_NW_DETECT_TRY_FULL)
detector = NUA_NW_DETECT_TRY_FULL;
NHP_SET(nhp, detect_network_updates, detector);
ngp->ngp_detect_network_updates = detector;
ngp->ngp_set.ngp_detect_network_updates = 1;
}
/* NUTAG_SHUTDOWN_EVENTS() */
else if (ngp && tag == nutag_shutdown_events) {
ngp->ngp_shutdown_events = value != 0;
ngp->ngp_set.ngp_shutdown_events = 1;
}
}
@ -1078,54 +1069,70 @@ static int nhp_merge_lists(su_home_t *home,
return 1;
}
static
nua_handle_preferences_t *nhp_move_params(su_home_t *home,
nua_handle_preferences_t *dst,
su_home_t *tmphome,
nua_handle_preferences_t const *src)
/** Save parameters in @a gtmp and @a tmp.
*/
static
int nhp_save_params(nua_handle_t *nh,
su_home_t *tmphome,
nua_global_preferences_t *gsrc,
nua_handle_preferences_t *src)
{
/* Update prefs structure */
nua_handle_preferences_t tbf[1];
su_home_t *home = nh->nh_home;
nua_t *nua = nh->nh_nua;
nua_handle_t *dnh = nua->nua_dhandle;
nua_handle_preferences_t *dst = nh->nh_prefs, old[1];
if (dst == NULL)
dst = su_zalloc(home, sizeof *dst);
if (dst == NULL)
return NULL;
if (su_home_move(home, tmphome) < 0)
return NULL;
if (gsrc) {
*nua->nua_prefs = *gsrc; /* No pointers this far */
}
*tbf = *dst;
if (!NHP_IS_ANY_SET(src))
return 0;
if (nh == dnh || nh->nh_prefs != dnh->nh_prefs) {
dst = nh->nh_prefs, *old = *dst;
assert(dst);
}
else {
dst = su_zalloc(home, sizeof *dst), memset(old, 0, sizeof *old);
if (!dst)
return -1;
}
/* Move allocations from tmphome to home */
su_home_move(nh->nh_home, tmphome);
/* Copy parameters that are set from src to dst */
nhp_or_set(dst, src);
/* Handle pointer items. Free changed ones and zap unset ones. */
#define NHP_ZAP_OVERRIDEN(tbf, nhp, pref) \
(((tbf)->nhp_set.nhb_##pref \
&& (tbf)->nhp_##pref != (nhp)->nhp_##pref \
? su_free(home, (void *)(tbf)->nhp_##pref) : (void)0), \
(void)(!(nhp)->nhp_set.nhb_##pref ? (nhp)->nhp_##pref = NULL : NULL))
/* Note that pointer items where !NHP_ISSET(old, pref) are not freed
(because they were just on loan from the default preference set) */
#define NHP_ZAP_OVERRIDEN(old, dst, free, pref) \
(((NHP_ISSET(old, pref) && \
(old)->nhp_##pref && (old)->nhp_##pref != (dst)->nhp_##pref) \
? (free)(home, (void *)(old)->nhp_##pref) : (void)0), \
(void)(!(dst)->nhp_set.nhb_##pref ? (dst)->nhp_##pref = NULL : NULL))
NHP_ZAP_OVERRIDEN(tbf, dst, soa_name);
NHP_ZAP_OVERRIDEN(tbf, dst, registrar);
NHP_ZAP_OVERRIDEN(tbf, dst, supported);
NHP_ZAP_OVERRIDEN(tbf, dst, allow);
NHP_ZAP_OVERRIDEN(tbf, dst, user_agent);
NHP_ZAP_OVERRIDEN(tbf, dst, organization);
NHP_ZAP_OVERRIDEN(tbf, dst, instance);
NHP_ZAP_OVERRIDEN(tbf, dst, m_display);
NHP_ZAP_OVERRIDEN(tbf, dst, m_username);
NHP_ZAP_OVERRIDEN(tbf, dst, m_params);
NHP_ZAP_OVERRIDEN(tbf, dst, m_features);
NHP_ZAP_OVERRIDEN(tbf, dst, outbound);
NHP_ZAP_OVERRIDEN(old, dst, su_free, soa_name);
NHP_ZAP_OVERRIDEN(old, dst, su_free, registrar);
NHP_ZAP_OVERRIDEN(old, dst, msg_header_free, allow);
NHP_ZAP_OVERRIDEN(old, dst, msg_header_free, supported);
NHP_ZAP_OVERRIDEN(old, dst, msg_header_free, allow_events);
NHP_ZAP_OVERRIDEN(old, dst, su_free, user_agent);
NHP_ZAP_OVERRIDEN(old, dst, su_free, organization);
NHP_ZAP_OVERRIDEN(old, dst, su_free, m_display);
NHP_ZAP_OVERRIDEN(old, dst, su_free, m_username);
NHP_ZAP_OVERRIDEN(old, dst, su_free, m_params);
NHP_ZAP_OVERRIDEN(old, dst, su_free, m_features);
NHP_ZAP_OVERRIDEN(old, dst, su_free, instance);
NHP_ZAP_OVERRIDEN(old, dst, su_free, outbound);
NHP_ZAP_OVERRIDEN(old, dst, msg_header_free, appl_method);
NHP_ZAP_OVERRIDEN(old, dst, msg_header_free, initial_route);
#define NHP_ZAP_OVERRIDEN_HDR(tbf, nhp, pref) \
(((tbf)->nhp_set.nhb_##pref \
&& (tbf)->nhp_##pref != (nhp)->nhp_##pref \
? msg_header_free(home, (void *)(tbf)->nhp_##pref) : (void)0), \
(void)(!(nhp)->nhp_set.nhb_##pref ? (nhp)->nhp_##pref = NULL : NULL))
NHP_ZAP_OVERRIDEN_HDR(tbf, dst, initial_route);
return dst;
nh->nh_prefs = dst;
return 0;
}
static int nua_handle_tags_filter(tagi_t const *f, tagi_t const *t);
@ -1475,6 +1482,7 @@ int nua_stack_set_smime_params(nua_t *nua, tagi_t const *tags)
* NUTAG_SMIME_SIGNATURE() \n
* NUTAG_SOA_NAME() \n
* NUTAG_SUBSTATE() \n
* NUTAG_SUB_EXPIRES() \n
* NUTAG_UPDATE_REFRESH() \n
* NUTAG_USER_AGENT() \n
* SIPTAG_ALLOW() \n
@ -1515,6 +1523,7 @@ int nua_stack_get_params(nua_t *nua, nua_handle_t *nh, nua_event_t e,
tagi_t const *tags)
{
nua_handle_t *dnh = nua->nua_dhandle;
nua_global_preferences_t const *ngp = nua->nua_prefs;
nua_handle_preferences_t const *nhp = nh->nh_prefs;
tagi_t *lst;
@ -1540,8 +1549,6 @@ int nua_stack_get_params(nua_t *nua, nua_handle_t *nh, nua_event_t e,
enter;
su_home_auto(tmphome, sizeof(tmphome));
nta_agent_get_params(nua->nua_nta,
NTATAG_UDP_MTU_REF(udp_mtu),
NTATAG_MAX_PROCEEDING_REF(max_proceeding),
@ -1590,6 +1597,8 @@ int nua_stack_get_params(nua_t *nua, nua_handle_t *nh, nua_event_t e,
? sip_##pref##_make(tmphome, (char *)nhp->nhp_##pref) \
: NULL))
su_home_auto(tmphome, sizeof(tmphome));
lst = tl_filtered_tlist
(tmphome, tags,
TAG_IF(has_from, SIPTAG_FROM(from)),
@ -1630,6 +1639,7 @@ int nua_stack_get_params(nua_t *nua, nua_handle_t *nh, nua_event_t e,
TIF(NUTAG_REFER_WITH_ID, refer_with_id),
TIF(NUTAG_SUBSTATE, substate),
TIF(NUTAG_SUB_EXPIRES, sub_expires),
TIF(SIPTAG_SUPPORTED, supported),
TIF_STR(SIPTAG_SUPPORTED_STR, supported),
@ -1658,11 +1668,18 @@ int nua_stack_get_params(nua_t *nua, nua_handle_t *nh, nua_event_t e,
TIF(NUTAG_M_PARAMS, m_params),
TIF(NUTAG_M_FEATURES, m_features),
TIF(NUTAG_OUTBOUND, outbound),
TIF(NUTAG_DETECT_NETWORK_UPDATES, detect_network_updates),
/* Skip user-agent-level parameters if parameters are for handle only */
TAG_IF(nh != dnh, TAG_NEXT(media_params)),
/* Include tag in the list returned to user
* if it has been earlier set (by user) */
#define GIF(TAG, pref) \
TAG_IF(ngp->ngp_set.ngp_##pref, TAG(ngp->ngp_##pref))
GIF(NUTAG_DETECT_NETWORK_UPDATES, detect_network_updates),
GIF(NUTAG_SHUTDOWN_EVENTS, shutdown_events),
NTATAG_CONTACT(m),
#if HAVE_SOFIA_SMIME

View File

@ -107,6 +107,7 @@ typedef struct nua_handle_preferences
/* Subscriber state, i.e. nua_substate_pending */
unsigned nhp_substate;
unsigned nhp_sub_expires;
/* REGISTER keepalive intervals */
unsigned nhp_keepalive, nhp_keepalive_stream;
@ -127,9 +128,6 @@ typedef struct nua_handle_preferences
/** Outbound OPTIONS */
char const *nhp_outbound;
/** Network detection: NONE, INFORMAL, TRY_FULL */
int nhp_detect_network_updates;
sip_allow_t *nhp_appl_method;
/** Initial route set */
@ -137,6 +135,12 @@ typedef struct nua_handle_preferences
union { struct {
/* A bit for each feature set by application */
/* NOTE:
Some compilers behave weird if there are bitfields
together with width > 32
So there should be a padding field (unsigned:0;)
every 32 bits.
*/
unsigned nhb_retry_count:1;
unsigned nhb_max_subscriptions:1;
@ -166,13 +170,15 @@ typedef struct nua_handle_preferences
unsigned nhb_refer_with_id:1;
unsigned nhb_refer_expires:1;
unsigned nhb_substate:1;
unsigned nhb_sub_expires:1;
unsigned nhb_keepalive:1;
unsigned nhb_keepalive_stream:1;
unsigned nhb_registrar:1;
unsigned nhb_allow:1;
unsigned :0; /* at most 32 bits before this point */
unsigned nhb_supported:1;
unsigned :0; /* at most 32 bits ... */
unsigned nhb_allow_events:1;
unsigned nhb_user_agent:1;
unsigned nhb_organization:1;
@ -183,7 +189,6 @@ typedef struct nua_handle_preferences
unsigned nhb_m_features:1;
unsigned nhb_instance:1;
unsigned nhb_outbound:1;
unsigned nhb_detect_network_updates:1;
unsigned nhb_appl_method:1;
unsigned nhb_initial_route:1;
unsigned :0;
@ -194,6 +199,26 @@ typedef struct nua_handle_preferences
#define nhp_set nhp_set_.set_bits
/** Global preferences for nua. */
typedef struct {
/** Network detection: NONE, INFORMAL, TRY_FULL */
signed int ngp_detect_network_updates:3;
/** Pass events during shutdown, too */
int ngp_shutdown_events:1;
unsigned :0; /* pad */
union { struct {
/* A bit for each feature set by application */
unsigned ngp_detect_network_updates:1;
unsigned ngp_shutdown_events:1;
unsigned :0;
} set_bits;
unsigned set_unsigned[2];
} ngp_set_;
} nua_global_preferences_t;
#define ngp_set ngp_set_.set_bits
#define DNHP_GET(dnhp, pref) ((dnhp)->nhp_##pref)
#define NHP_GET(nhp, dnhp, pref) \

View File

@ -244,19 +244,21 @@ static int nua_publish_client_response(nua_client_request_t *cr,
sip_t const *sip);
static nua_client_methods_t const nua_publish_client_methods = {
SIP_METHOD_PUBLISH,
0,
{
SIP_METHOD_PUBLISH, /* crm_method, crm_method_name */
0, /* crm_extra */
{ /* crm_flags */
/* create_dialog */ 0,
/* in_dialog */ 0,
/* target refresh */ 0
},
nua_publish_client_template,
nua_publish_client_init,
nua_publish_client_request,
nua_publish_client_check_restart,
nua_publish_client_response,
/* nua_publish_client_preliminary */ NULL
nua_publish_client_template, /* crm_template */
nua_publish_client_init, /* crm_init */
nua_publish_client_request, /* crm_send */
nua_publish_client_check_restart, /* crm_check_restart */
nua_publish_client_response, /* crm_recv */
NULL, /* crm_preliminary */
NULL, /* crm_report */
NULL, /* crm_complete */
};
/**@internal Send PUBLISH. */

View File

@ -570,18 +570,21 @@ static int nua_register_client_response(nua_client_request_t *cr,
sip_t const *sip);
static nua_client_methods_t const nua_register_client_methods = {
SIP_METHOD_REGISTER,
0,
{
SIP_METHOD_REGISTER, /* crm_method, crm_method_name */
0, /* crm_extra */
{ /* crm_flags */
/* create_dialog */ 1,
/* in_dialog */ 0,
/* target refresh */ 0
},
nua_register_client_template,
nua_register_client_init,
nua_register_client_request,
nua_register_client_check_restart,
nua_register_client_response
nua_register_client_template, /* crm_template */
nua_register_client_init, /* crm_init */
nua_register_client_request, /* crm_send */
nua_register_client_check_restart, /* crm_check_restart */
nua_register_client_response, /* crm_recv */
NULL, /* crm_preliminary */
NULL, /* crm_report */
NULL, /* crm_complete */
};
/**@internal Send REGISTER. */

View File

@ -191,7 +191,7 @@ static int nua_session_usage_shutdown(nua_owner_t *,
nua_dialog_usage_t *);
static int nua_invite_client_ack(nua_client_request_t *cr, tagi_t const *tags);
static int nua_invite_client_deinit(nua_client_request_t *cr);
static int nua_invite_client_complete(nua_client_request_t *cr);
static nua_usage_class const nua_session_usage[1] = {
{
@ -238,7 +238,8 @@ void nua_session_usage_remove(nua_handle_t *nh,
cr = du->du_cr;
if (cr && cr->cr_orq && cr->cr_status >= 200) {
if (cr && cr->cr_orq && cr->cr_status >= 200 &&
cr->cr_method == sip_method_invite) {
ss->ss_reporting = 1;
nua_invite_client_ack(cr, NULL);
ss->ss_reporting = 0;
@ -250,14 +251,17 @@ void nua_session_usage_remove(nua_handle_t *nh,
if (cr->cr_method != sip_method_invite)
continue;
if (cr == du->du_cr)
continue;
nua_stack_event(nh->nh_nua, nh,
NULL,
cr->cr_event,
SIP_481_NO_TRANSACTION,
NULL);
if (cr->cr_status < 200) {
nua_stack_event(nh->nh_nua, nh,
NULL,
cr->cr_event,
SIP_481_NO_TRANSACTION,
NULL);
}
nua_client_request_destroy(cr);
@ -542,21 +546,21 @@ static int nua_invite_client_report(nua_client_request_t *cr,
tagi_t const *tags);
nua_client_methods_t const nua_invite_client_methods = {
SIP_METHOD_INVITE,
0,
{
SIP_METHOD_INVITE, /* crm_method, crm_method_name */
0, /* crm_extra */
{ /* crm_flags */
/* create_dialog */ 1,
/* in_dialog */ 1,
/* target refresh */ 1
},
NULL,
nua_invite_client_init,
nua_invite_client_request,
session_timer_check_restart,
nua_invite_client_response,
nua_invite_client_preliminary,
nua_invite_client_report,
nua_invite_client_deinit
NULL, /* crm_template */
nua_invite_client_init, /* crm_init */
nua_invite_client_request, /* crm_send */
session_timer_check_restart, /* crm_check_restart */
nua_invite_client_response, /* crm_recv */
nua_invite_client_preliminary, /* crm_preliminary */
nua_invite_client_report, /* crm_report */
nua_invite_client_complete, /* crm_complete */
};
extern nua_client_methods_t const nua_bye_client_methods;
@ -604,10 +608,15 @@ static int nua_invite_client_init(nua_client_request_t *cr,
if (!du)
return -1;
ss = nua_dialog_usage_private(du);
if (ss->ss_state >= nua_callstate_terminating)
return nua_client_return(cr, 900, "Session is terminating", msg);
if (nua_client_bind(cr, du) < 0)
return nua_client_return(cr, 900, "INVITE already in progress", msg);
ss = nua_dialog_usage_private(du);
cr->cr_neutral = 0;
session_timer_preferences(ss->ss_timer,
sip,
@ -617,8 +626,6 @@ static int nua_invite_client_init(nua_client_request_t *cr,
NH_PGET(nh, refresher),
NH_PGET(nh, min_se));
cr->cr_neutral = 0;
return 0;
}
@ -635,6 +642,9 @@ static int nua_invite_client_request(nua_client_request_t *cr,
if (du == NULL) /* Call terminated */
return nua_client_return(cr, SIP_481_NO_TRANSACTION, msg);
if (ss->ss_state >= nua_callstate_terminating)
return nua_client_return(cr, 900, "Session is terminating", msg);
assert(ss);
invite_timeout = NH_PGET(nh, invite_timeout);
@ -1047,7 +1057,7 @@ int nua_stack_ack(nua_t *nua, nua_handle_t *nh, nua_event_t e,
if (error < 0) {
if (ss->ss_reason == NULL)
ss->ss_reason = "SIP;cause=500;text=\"Internal Error\"";
ss->ss_reporting = 1; /* We report state here if BYE fails */
ss->ss_reporting = 1; /* We report terminated state here if BYE fails */
error = nua_client_create(nh, nua_r_bye, &nua_bye_client_methods, NULL);
ss->ss_reporting = 0;
signal_call_state_change(nh, ss, 500, "Internal Error",
@ -1090,6 +1100,7 @@ int nua_invite_client_ack(nua_client_request_t *cr, tagi_t const *tags)
char const *invite_branch;
assert(cr->cr_orq);
assert(cr->cr_method == sip_method_invite);
if (!ds->ds_leg) {
@ -1226,8 +1237,8 @@ int nua_invite_client_ack(nua_client_request_t *cr, tagi_t const *tags)
return error;
}
/** Deinitialize client request */
static int nua_invite_client_deinit(nua_client_request_t *cr)
/** Complete client request */
static int nua_invite_client_complete(nua_client_request_t *cr)
{
if (cr->cr_orq == NULL)
/* Xyzzy */;
@ -1263,18 +1274,21 @@ static int nua_cancel_client_request(nua_client_request_t *cr,
tagi_t const *tags);
nua_client_methods_t const nua_cancel_client_methods = {
SIP_METHOD_CANCEL,
0,
{
SIP_METHOD_CANCEL, /* crm_method, crm_method_name */
0, /* crm_extra */
{ /* crm_flags */
/* create_dialog */ 0,
/* in_dialog */ 1,
/* target refresh */ 0
},
NULL,
NULL,
nua_cancel_client_request,
/* nua_cancel_client_check_restart */ NULL,
/* nua_cancel_client_response */ NULL
NULL, /* crm_template */
NULL, /* crm_init */
nua_cancel_client_request, /* crm_send */
NULL, /* crm_check_restart */
NULL, /* crm_recv */
NULL, /* crm_preliminary */
NULL, /* crm_report */
NULL, /* crm_complete */
};
int nua_stack_cancel(nua_t *nua, nua_handle_t *nh, nua_event_t e,
@ -1493,20 +1507,21 @@ static int nua_prack_client_report(nua_client_request_t *cr,
tagi_t const *tags);
nua_client_methods_t const nua_prack_client_methods = {
SIP_METHOD_PRACK,
0,
{
SIP_METHOD_PRACK, /* crm_method, crm_method_name */
0, /* crm_extra */
{ /* crm_flags */
/* create_dialog */ 0,
/* in_dialog */ 1,
/* target refresh */ 0
},
NULL,
nua_prack_client_init,
nua_prack_client_request,
/* nua_prack_client_check_restart */ NULL,
nua_prack_client_response,
NULL,
nua_prack_client_report
NULL, /* crm_template */
nua_prack_client_init, /* crm_init */
nua_prack_client_request, /* crm_send */
NULL, /* crm_check_restart */
nua_prack_client_response, /* crm_recv */
NULL, /* crm_preliminary */
nua_prack_client_report, /* crm_report */
NULL, /* crm_complete */
};
int nua_stack_prack(nua_t *nua, nua_handle_t *nh, nua_event_t e,
@ -1542,6 +1557,8 @@ static int nua_prack_client_request(nua_client_request_t *cr,
if (du == NULL) /* Call terminated */
return nua_client_return(cr, SIP_481_NO_TRANSACTION, msg);
assert(ss);
if (ss->ss_state >= nua_callstate_terminating)
return nua_client_return(cr, 900, "Session is terminating", msg);
cri = du->du_cr;
@ -1820,6 +1837,7 @@ nua_invite_server_init(nua_server_request_t *sr)
{
nua_handle_t *nh = sr->sr_owner;
nua_t *nua = nh->nh_nua;
nua_session_usage_t *ss;
sr->sr_neutral = 1;
@ -1858,6 +1876,15 @@ nua_invite_server_init(nua_server_request_t *sr)
/* Glare - RFC 3261 14.2 and RFC 3311 section 5.2 */
return SR_STATUS1(sr, SIP_491_REQUEST_PENDING);
}
ss = nua_dialog_usage_private(sr->sr_usage);
if (ss->ss_state < nua_callstate_completed &&
ss->ss_state != nua_callstate_init) {
/* We should never trigger this,
but better not to assert() on network input */
return nua_server_retry_after(sr, 500, "Overlapping Requests 2", 0, 10);
}
}
sr->sr_neutral = 0;
@ -1887,6 +1914,11 @@ nua_session_server_init(nua_server_request_t *sr)
/* UPDATE/PRACK sent within an existing dialog? */
return SR_STATUS(sr, 481, "Call Does Not Exist");
}
else if (sr->sr_usage) {
nua_session_usage_t *ss = nua_dialog_usage_private(sr->sr_usage);
if (ss->ss_state >= nua_callstate_terminating)
return SR_STATUS(sr, 481, "Call is being terminated");
}
if (nh->nh_soa) {
sip_accept_t *a = nua->nua_invite_accept;
@ -1972,8 +2004,10 @@ int nua_invite_server_preprocess(nua_server_request_t *sr)
session_timer_store(ss->ss_timer, request);
if (!(ss->ss_state >= nua_callstate_ready || ss->ss_state == nua_callstate_init))
return SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR);
#if 0 /* The glare and overlap tests should take care of this. */
assert(ss->ss_state >= nua_callstate_completed ||
ss->ss_state == nua_callstate_init);
#endif
if (NH_PGET(nh, auto_answer) ||
/* Auto-answer to re-INVITE unless auto_answer is set to 0 on handle */
@ -2319,7 +2353,7 @@ int process_ack(nua_server_request_t *sr,
nua_stack_event(nh->nh_nua, nh, NULL,
nua_i_media_error, status, phrase, NULL);
ss->ss_reporting = 1; /* We report state here if BYE fails */
ss->ss_reporting = 1; /* We report terminated state here if BYE fails */
error = nua_client_create(nh, nua_r_bye, &nua_bye_client_methods, NULL);
ss->ss_reporting = 0;
@ -2416,7 +2450,7 @@ int process_timeout(nua_server_request_t *sr,
/* send BYE, too, if 200 OK (or 183 to re-INVITE) timeouts */
ss->ss_reason = reason;
ss->ss_reporting = 1; /* We report state here if BYE fails */
ss->ss_reporting = 1; /* We report terminated state here if BYE fails */
error = nua_client_create(nh, nua_r_bye, &nua_bye_client_methods, NULL);
ss->ss_reporting = 0;
@ -2787,18 +2821,21 @@ static int nua_info_client_request(nua_client_request_t *cr,
tagi_t const *tags);
nua_client_methods_t const nua_info_client_methods = {
SIP_METHOD_INFO,
0,
{
SIP_METHOD_INFO, /* crm_method, crm_method_name */
0, /* crm_extra */
{ /* crm_flags */
/* create_dialog */ 0,
/* in_dialog */ 1,
/* target refresh */ 0
},
/*nua_info_client_template*/ NULL,
nua_info_client_init,
nua_info_client_request,
/*nua_info_client_check_restart*/ NULL,
/*nua_info_client_response*/ NULL
NULL, /* crm_template */
nua_info_client_init, /* crm_init */
nua_info_client_request, /* crm_send */
NULL, /* crm_check_restart */
NULL, /* crm_recv */
NULL, /* crm_preliminary */
NULL, /* crm_report */
NULL, /* crm_complete */
};
int
@ -2934,20 +2971,21 @@ static int nua_update_client_report(nua_client_request_t *cr,
tagi_t const *tags);
nua_client_methods_t const nua_update_client_methods = {
SIP_METHOD_UPDATE,
0, /* size of private data */
{
SIP_METHOD_UPDATE, /* crm_method, crm_method_name */
0, /* crm_extrasize of private data */
{ /* crm_flags */
/* create_dialog */ 0,
/* in_dialog */ 1,
/* target refresh */ 1
},
NULL,
nua_update_client_init,
nua_update_client_request,
session_timer_check_restart,
nua_update_client_response,
NULL,
nua_update_client_report
NULL, /* crm_template */
nua_update_client_init, /* crm_init */
nua_update_client_request, /* crm_send */
session_timer_check_restart, /* crm_check_restart */
nua_update_client_response, /* crm_recv */
NULL, /* crm_preliminary */
nua_update_client_report, /* crm_report */
NULL, /* crm_complete */
};
int nua_stack_update(nua_t *nua, nua_handle_t *nh, nua_event_t e,
@ -2982,6 +3020,8 @@ static int nua_update_client_request(nua_client_request_t *cr,
if (du == NULL) /* Call terminated */
return nua_client_return(cr, SIP_481_NO_TRANSACTION, msg);
assert(ss);
if (ss->ss_state >= nua_callstate_terminating)
return nua_client_return(cr, 900, "Session is terminating", msg);
cri = du->du_cr;
@ -3397,20 +3437,21 @@ static int nua_bye_client_report(nua_client_request_t *cr,
tagi_t const *tags);
nua_client_methods_t const nua_bye_client_methods = {
SIP_METHOD_BYE,
0,
{
SIP_METHOD_BYE, /* crm_method, crm_method_name */
0, /* crm_extrasize */
{ /* crm_flags */
/* create_dialog */ 0,
/* in_dialog */ 1,
/* target refresh */ 0
},
NULL,
nua_bye_client_init,
nua_bye_client_request,
/*nua_bye_client_check_restart*/ NULL,
/*nua_bye_client_response*/ NULL,
/*nua_bye_client_preliminary*/ NULL,
nua_bye_client_report
NULL, /* crm_template */
nua_bye_client_init, /* crm_init */
nua_bye_client_request, /* crm_send */
NULL, /* crm_check_restart */
NULL, /* crm_recv */
NULL, /* crm_preliminary */
nua_bye_client_report, /* crm_report */
NULL, /* crm_complete */
};
int
@ -3443,7 +3484,9 @@ static int nua_bye_client_init(nua_client_request_t *cr,
if (nh->nh_soa)
soa_terminate(nh->nh_soa, 0);
cr->cr_usage = du;
du->du_cr = NULL;
nua_client_bind(cr, du);
return 0;
}
@ -3515,17 +3558,23 @@ static int nua_bye_client_report(nua_client_request_t *cr,
else {
nua_session_usage_t *ss = nua_dialog_usage_private(du);
if (ss->ss_reporting) {
return 1; /* Somebody else's problem */
}
else if (cr->cr_waiting) {
return 1; /* Application problem */
}
signal_call_state_change(nh, ss, status, "to BYE",
nua_callstate_terminated);
if (ss && !ss->ss_reporting) {
if (du->du_cr == NULL ||
!nua_client_is_queued(du->du_cr) ||
du->du_cr->cr_status >= 200) {
/* INVITE is completed, we can zap the session... */;
cr->cr_usage = NULL;
nua_session_usage_destroy(nh, ss);
}
if (du &&
(du->du_cr == NULL ||
!nua_client_is_queued(du->du_cr) ||
du->du_cr->cr_status >= 200)) {
/* INVITE is completed, we can zap the session... */;
cr->cr_usage = NULL;
nua_session_usage_destroy(nh, ss);
}
}

View File

@ -209,7 +209,7 @@ int nua_stack_init(su_root_t *root, nua_t *nua)
if (nua_stack_set_from(nua, 1, nua->nua_args) < 0)
return -1;
if (NHP_ISSET(dnh->nh_prefs, detect_network_updates))
if (nua->nua_prefs->ngp_detect_network_updates)
nua_stack_launch_network_change_detector(nua);
nua_stack_timer(nua, nua->nua_timer, NULL);
@ -293,7 +293,8 @@ int nua_stack_event(nua_t *nua, nua_handle_t *nh, msg_t *msg,
if ((event > nua_r_authenticate && event <= nua_r_ack)
|| event < nua_i_error
|| (nh && !nh->nh_valid)
) {
|| (nua->nua_shutdown && event != nua_r_shutdown &&
!nua->nua_prefs->ngp_shutdown_events)) {
if (msg)
msg_destroy(msg);
return event;
@ -2075,6 +2076,13 @@ nua_client_request_t *nua_client_request_remove(nua_client_request_t *cr)
return cr;
}
void nua_client_request_complete(nua_client_request_t *cr)
{
nua_client_request_remove(cr);
if (cr && cr->cr_methods->crm_complete)
cr->cr_methods->crm_complete(cr);
}
void nua_client_request_destroy(nua_client_request_t *cr)
{
nua_handle_t *nh;
@ -2082,14 +2090,12 @@ void nua_client_request_destroy(nua_client_request_t *cr)
if (cr == NULL)
return;
if (cr->cr_methods->crm_deinit)
cr->cr_methods->crm_deinit(cr);
nua_client_request_complete(cr);
nh = cr->cr_owner;
nua_destroy_signal(cr->cr_signal);
nua_client_request_remove(cr);
nua_client_bind(cr, NULL);
if (cr->cr_msg)
@ -2098,7 +2104,6 @@ void nua_client_request_destroy(nua_client_request_t *cr)
if (cr->cr_orq)
nta_outgoing_destroy(cr->cr_orq);
cr->cr_orq = NULL;
if (cr->cr_timer)

View File

@ -217,28 +217,31 @@ struct nua_s {
su_clone_r nua_clone;
su_task_r nua_client;
su_network_changed_t *nua_nw_changed;
nua_callback_f nua_callback;
nua_magic_t *nua_magic;
nua_event_frame_t *nua_current;
nua_saved_event_t nua_signal[1];
/**< Used by stop-and-wait args calls */
tagi_t const *nua_args;
/* Engine state flags */
sip_time_t nua_shutdown;
unsigned nua_shutdown_started:1; /**< Shutdown initiated */
unsigned nua_shutdown_final:1; /**< Shutdown is complete */
unsigned nua_from_is_set;
unsigned :0;
/**< Used by stop-and-wait args calls */
tagi_t const *nua_args;
/**< Local SIP address. Contents are kept around for ever. */
sip_from_t nua_from[1];
sip_from_t nua_from[1];
/* ---------------------------------------------------------------------- */
/* Protocol (server) side */
su_network_changed_t *nua_nw_changed;
nua_registration_t *nua_registrations; /**< Active registrations */
@ -250,21 +253,8 @@ struct nua_s {
nta_agent_t *nua_nta;
su_timer_t *nua_timer;
void *nua_sip_parser;
sip_time_t nua_shutdown;
/* Route */
sip_service_route_t *nua_service_route;
/* User-agent parameters */
unsigned nua_media_enable:1;
unsigned :0;
#if HAVE_SMIME /* Start NRC Boston */
sm_object_t *sm;
#endif /* End NRC Boston */
nua_global_preferences_t nua_prefs[1];
nua_handle_t *nua_handles;
nua_handle_t **nua_handles_tail;

View File

@ -183,18 +183,21 @@ static int nua_subscribe_client_response(nua_client_request_t *cr,
sip_t const *sip);
static nua_client_methods_t const nua_subscribe_client_methods = {
SIP_METHOD_SUBSCRIBE,
0,
{
SIP_METHOD_SUBSCRIBE, /* crm_method, crm_method_name */
0, /* crm_extra */
{ /* crm_flags */
/* create_dialog */ 1,
/* in_dialog */ 1,
/* target refresh */ 1
},
NULL,
nua_subscribe_client_init,
nua_subscribe_client_request,
/* nua_subscribe_client_check_restart */ NULL,
nua_subscribe_client_response
NULL, /* crm_template */
nua_subscribe_client_init, /* crm_init */
nua_subscribe_client_request, /* crm_send */
NULL, /* crm_check_restart */
nua_subscribe_client_response, /* crm_recv */
NULL, /* crm_preliminary */
NULL, /* crm_report */
NULL, /* crm_complete */
};
int
@ -368,6 +371,9 @@ static int nua_subscribe_client_response(nua_client_request_t *cr,
else
delta = 0;
if (delta > eu->eu_expires)
delta = eu->eu_expires;
if (win_messenger_enable && !nua_dialog_is_established(nh->nh_ds)) {
/* Notify from messanger does not match with dialog tag */
nh->nh_ds->ds_remote_tag = su_strdup(nh->nh_home, "");
@ -647,8 +653,6 @@ int nua_notify_server_report(nua_server_request_t *sr, tagi_t const *tags)
if (substate == nua_substate_active || substate == nua_substate_pending) {
if (subs && subs->ss_expires)
delta = strtoul(subs->ss_expires, NULL, 10);
else
delta = eu->eu_expires;
}
else if (substate == nua_substate_embryonic) {
if (subs && subs->ss_reason) {
@ -686,7 +690,8 @@ int nua_notify_server_report(nua_server_request_t *sr, tagi_t const *tags)
nua_dialog_usage_set_refresh_range(du, retry, retry + 5);
}
else {
nua_dialog_usage_set_refresh(du, delta);
if (delta < SIP_TIME_MAX)
nua_dialog_usage_set_refresh(du, delta);
}
return retval;
@ -777,20 +782,21 @@ static int nua_refer_client_response(nua_client_request_t *cr,
sip_t const *sip);
static nua_client_methods_t const nua_refer_client_methods = {
SIP_METHOD_REFER,
0,
{
SIP_METHOD_REFER, /* crm_method, crm_method_name */
0, /* crm_extra */
{ /* crm_flags */
/* create_dialog */ 1,
/* in_dialog */ 1,
/* target refresh */ 1
},
/*nua_refer_client_template*/ NULL,
nua_refer_client_init,
nua_refer_client_request,
/* nua_refer_client_check_restart */ NULL,
nua_refer_client_response,
nua_refer_client_response, /* Preliminary */
NULL
NULL, /* crm_template */
nua_refer_client_init, /* crm_init */
nua_refer_client_request, /* crm_send */
NULL, /* crm_check_restart */
nua_refer_client_response, /* crm_recv */
nua_refer_client_response, /* crm_preliminary */
NULL, /* crm_report */
NULL, /* crm_complete */
};
int

View File

@ -227,21 +227,22 @@
* - NUTAG_ALLOW_EVENTS(), SIPTAG_ALLOW_EVENTS(), and
* SIPTAG_ALLOW_EVENTS_STR()
* - NUTAG_MAX_SUBSCRIPTIONS()
* - NUTAG_SUBSTATE()
* - NUTAG_SUBSTATE(), NUTAG_SUB_EXPIRES()
* @par Specifications
* - @RFC3265
*
* @par SIP Event Subscriber
* - nua_subscribe(), #nua_r_subscribe, #nua_i_notify, NUTAG_SUBSTATE(),
* SIPTAG_EVENT(), SIPTAG_EXPIRES(),
* SIPTAG_EVENT(), SIPTAG_EXPIRES()
* - nua_unsubscribe(), #nua_r_unsubscribe()
* @par Specifications
* - @RFC3265
*
* @par SIP Event Notifier
* - #nua_i_subscribe(), nua_notify(), #nua_r_notify,
* NUTAG_SUBSTATE(), SIPTAG_EVENT()
* NUTAG_SUBSTATE(), NUTAG_SUB_EXPIRES(), SIPTAG_EVENT()
* Settings:
* - NUTAG_SUB_EXPIRES()
* - NUTAG_ALLOW_EVENTS(), SIPTAG_ALLOW_EVENTS(), and
* SIPTAG_ALLOW_EVENTS_STR()
* - NUTAG_ALLOW("SUBSCRIBE"), NUTAG_APPL_METHOD("SUBSCRIBE")
@ -267,6 +268,8 @@
* Settings:
* - NUTAG_ALLOW(x), NUTAG_APPL_METHOD(x)
*
* @par Server Shutdown
* - nua_shutdown(), NUTAG_SHUTDOWN_EVENTS(), nua_destroy().
*/
/* @par S/MIME
@ -767,14 +770,14 @@ tag_typedef_t nutag_answer_sent = BOOLTAG_TYPEDEF(answer_sent);
*
* @par Used with
* - with nua_create(), nua_set_params(), nua_get_params(),
* nua_handle(), nua_set_hparams(), nua_get_hparams(), and
* nua_notifier() to change the default subscription state returned by
* the intenal event server
* nua_handle(), nua_set_hparams(), nua_get_hparams(), and
* nua_notifier() to change the default subscription state returned by
* the internal event server
* - with nua_notify() and nua_respond() to SUBSCRIBE to determine the
* subscription state (if application include @SubscriptionState
* header in the tag list, the NUTAG_SUBSTATE() value is ignored)
* subscription state (if application include @SubscriptionState
* header in the tag list, the NUTAG_SUBSTATE() value is ignored)
* - with #nua_r_subscribe, #nua_i_notify, #nua_i_subscribe, and #nua_r_notify
* to indicate the current subscription state
* to indicate the current subscription state
*
* @par Parameter type
* int
@ -806,6 +809,39 @@ tag_typedef_t nutag_substate = INTTAG_TYPEDEF(substate);
*/
/**@def NUTAG_SUB_EXPIRES()
*
* Default expiration time of subscriptions.
*
* @par Used with
* - with nua_create(), nua_set_params(), nua_get_params(), nua_handle(),
* nua_set_hparams(), nua_get_hparams(), nua_respond(), nua_notify(), and
* nua_notifier() to change the default expiration time of subscriptions
*
* @par Parameter type
* unsigned int
*
* @par Values
* - default expiration time in seconds
*
* Note that the expires parameter in @SubscriptionState or @Expires header
* in the nua_response() to the SUBSCRIBE overrides the default subscription
* expiration specified by NUTAG_SUB_EXPIRES().
*
* @sa @RFC3265, NUTAG_REFER_EXPIRES(), @Expires, SIPTAG_EXPIRES(),
* SIPTAG_EXPIRES_STR(), @SubscriptionState, nua_respond(), nua_notifier(),
* #nua_r_subscribe, #nua_i_subscribe, #nua_r_refer, #nua_r_notify,
* #nua_i_notify.
*
* Corresponding tag taking reference parameter is NUTAG_SUB_EXPIRES_REF().
*/
tag_typedef_t nutag_sub_expires = UINTTAG_TYPEDEF(substate);
/**@def NUTAG_SUB_EXPIRES_REF(x)
* Reference tag for NUTAG_SUB_EXPIRES().
*/
/**@def NUTAG_NEWSUB()
*
* Send unsolicited NOTIFY request.
@ -1075,17 +1111,17 @@ tag_typedef_t nutag_update_refresh = BOOLTAG_TYPEDEF(update_refresh);
* REFER.
*
* @par Used with
* nua_set_params() \n
* nua_get_params() \n
* nua_set_hparams() \n
* nua_get_hparams() \n
* nua_handle(), nua_respond() \n
* nua_set_params() or nua_set_hparams() \n
* nua_get_params() or nua_get_hparams()
*
* @par Parameter type
* unsigned int
*
* @par Values
* @c 0 disable \n
* @c >0 interval in seconds
* - default interval in seconds
*
* @sa NUTAG_SUB_EXPIRES()
*
* Corresponding tag taking reference parameter is NUTAG_REFER_EXPIRES_REF().
*/
@ -1570,6 +1606,9 @@ extern msg_hclass_t sip_route_class[];
* NUTAG_INITIAL_ROUTE_STR() tags, the route set is constructed from them
* all.
*
* The initial route is inserted into request message before the route
* entries set with SIPTAG_ROUTE() or SIPTAG_ROUTE_STR().
*
* @par Used with
* nua_set_params() \n
* nua_set_hparams() \n
@ -2736,6 +2775,39 @@ tag_typedef_t nutag_dialog = UINTTAG_TYPEDEF(dialog);
* Reference tag for NUTAG_SIP_PARSER().
*/
/**@def NUTAG_SHUTDOWN_EVENTS(x)
*
* Allow passing of normal events when stack is being shut down.
*
* By default, only #nua_r_shutdown events are passed to application after
* calling nua_shutdown(). If application is interested in nua events during
* shutdown, it should give NUTAG_SHUTDOWN_EVENTS(1) to nua_create() or
* nua_set_params() called before nua_shutdown().
*
* @par Used with
* nua_create(), nua_set_params().
*
* @par Parameter type
* int (boolean)
*
* @par Values
* @c 0 False \n
* @c !=0 True
*
* Corresponding tag taking reference parameter is NUTAG_SHUTDOWN_EVENTS_REF().
*
* @sa nua_shutdown(), nua_destroy().
*
* @NEW_1_12_9.
*/
tag_typedef_t nutag_shutdown_events = BOOLTAG_TYPEDEF(shutdown_events);
/**@def NUTAG_SHUTDOWN_EVENTS_REF(x)
* Reference tag for NUTAG_SHUTDOWN_EVENTS().
*/
/* ---------------------------------------------------------------------- */
tag_typedef_t nutag_soa_session = PTRTAG_TYPEDEF(soa_session);

View File

@ -497,12 +497,16 @@ SOFIAPUBFUN char const *nua_substate_name(enum nua_substate substate);
/** Convert string to enum nua_substate. @NEW_1_12_5. */
SOFIAPUBFUN enum nua_substate nua_substate_make(char const *sip_substate);
#define NUTAG_SUB_EXPIRES(x) nutag_sub_expires, tag_uint_v(x)
SOFIAPUBVAR tag_typedef_t nutag_sub_expires;
#define NUTAG_SUB_EXPIRES_REF(x) nutag_sub_expires_ref, tag_uint_vr(&(x))
SOFIAPUBVAR tag_typedef_t nutag_sub_expires_ref;
#define NUTAG_NEWSUB(x) nutag_newsub, tag_bool_v(x)
SOFIAPUBVAR tag_typedef_t nutag_newsub;
#define NUTAG_NEWSUB_REF(x) nutag_newsub_ref, tag_bool_vr(&(x))
SOFIAPUBVAR tag_typedef_t nutag_newsub_ref;
#define NUTAG_REFER_EXPIRES(x) nutag_refer_expires, tag_uint_v((x))
SOFIAPUBVAR tag_typedef_t nutag_refer_expires;
#define NUTAG_REFER_EXPIRES_REF(x) nutag_refer_expires_ref, tag_uint_vr((&(x)))
@ -569,6 +573,13 @@ SOFIAPUBVAR tag_typedef_t nutag_detect_network_updates;
nutag_detect_network_updates_ref, tag_int_vr(&(x))
SOFIAPUBVAR tag_typedef_t nutag_detect_network_updates_ref;
#define NUTAG_SHUTDOWN_EVENTS(x) \
nutag_shutdown_events, tag_bool_v(x)
SOFIAPUBVAR tag_typedef_t nutag_shutdown_events;
#define NUTAG_SHUTDOWN_EVENTS_REF(x) \
nutag_shutdown_events_ref, tag_bool_vr(&(x))
SOFIAPUBVAR tag_typedef_t nutag_shutdown_events_ref;
/* Pass nua handle as tagged argument */
#if SU_INLINE_TAG_CAST
su_inline tag_value_t nutag_handle_v(nua_handle_t *v) { return (tag_value_t)v; }

View File

@ -726,9 +726,8 @@ int test_183rel(struct context *ctx)
if (e->data->e_event == nua_r_bye) {
TEST_E(e->data->e_event, nua_r_bye);
TEST(e->data->e_status, 200);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminated);
bye = 0;
break;
}
else if (e->data->e_event == nua_r_invite) {
TEST_E(e->data->e_event, nua_r_invite);
@ -741,7 +740,10 @@ int test_183rel(struct context *ctx)
cancel = 0;
}
}
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminated);
}
TEST_1(!e->next);
free_events_in_list(ctx, a->events);

View File

@ -1133,7 +1133,7 @@ int test_bye_before_ack(struct context *ctx)
Server transitions:
INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
RECEIVED -(S2a)-> EARLY: nua_respond(180), nua_i_state
EARLY -(S6b)--> TERMINATED: nua_i_cancel, nua_i_state
EARLY -(S6b)--> TERMINATED: nua_i_bye, nua_i_state
*/
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
TEST(e->data->e_status, 100);
@ -1423,6 +1423,79 @@ int reject_reinvite_401(CONDITION_PARAMS)
return 0;
}
int test_bye_with_407(struct context *ctx)
{
BEGIN();
struct endpoint *a = &ctx->a, *c = &ctx->c;
struct call *a_call = a->call, *c_call = c->call;
struct event *e;
a_call->sdp = "m=audio 5008 RTP/AVP 8";
c_call->sdp = "m=audio 5010 RTP/AVP 0 8";
/* BYE after receiving 401
A C
|-------INVITE------>|
|<----100 Trying-----|
| |
|<----180 Ringing----|
|<-------200---------|
|--------ACK-------->|
| |
| |<----BYE----|
| |-----407--->|
|<-------BYE---------|
|--------200-------->|
| |
*/
if (print_headings)
printf("TEST NUA-6.4.5: BYE with 407\n");
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(c->to), TAG_END()));
INVITE(a, a_call, a_call->nh,
TAG_IF(!ctx->proxy_tests, NUTAG_URL(c->contact->m_url)),
SIPTAG_SUBJECT_STR("NUA-6.4.2"),
SOATAG_USER_SDP_STR(a_call->sdp),
NUTAG_AUTOANSWER(0),
NUTAG_APPL_METHOD("UPDATE"),
TAG_END());
run_abc_until(ctx, -1, until_ready, -1, NULL, -1, accept_call);
free_events_in_list(ctx, a->events);
TEST_1(e = c->events->head); TEST_E(e->data->e_event, nua_i_invite);
free_events_in_list(ctx, c->events);
BYE(c, c_call, c_call->nh,
TAG_END());
run_c_until(ctx, -1, save_until_final_response);
TEST_1(nua_handle_has_active_call(a_call->nh));
TEST_1(nua_handle_has_active_call(c_call->nh));
free_events_in_list(ctx, a->events);
free_events_in_list(ctx, c->events);
AUTHENTICATE(c, c_call, c_call->nh,
NUTAG_AUTH("Digest:\"test-proxy\":charlie:secret"), TAG_END());
run_abc_until(ctx, -1, until_terminated, -1, NULL, -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, c->events);
nua_handle_destroy(c_call->nh), c_call->nh = NULL;
if (print_headings)
printf("TEST NUA-6.4.5: PASSED\n");
END();
}
int test_bye_to_invalid_contact(struct context *ctx)
{
BEGIN();
@ -1576,6 +1649,7 @@ int test_bye_to_invalid_contact(struct context *ctx)
int test_early_bye(struct context *ctx)
{
return
test_bye_with_407(ctx) ||
test_bye_before_200(ctx) ||
test_bye_before_ack(ctx) ||
test_bye_after_receiving_401(ctx) ||

View File

@ -151,8 +151,11 @@ int test_nua_init(struct context *ctx,
AUTHTAG_ALGORITHM("md5"),
AUTHTAG_NEXT_EXPIRES(60),
AUTHTAG_MAX_NCOUNT(1),
AUTHTAG_ALLOW("ACK, CANCEL"),
TAG_END());
test_proxy_domain_set_record_route(ctx->c.domain, 1);
ctx->proxy_tests = 1;
}

View File

@ -203,6 +203,7 @@ int test_nua_params(struct context *ctx)
NUTAG_REFER_EXPIRES(333),
NUTAG_REFER_WITH_ID(0),
NUTAG_SUBSTATE(nua_substate_pending),
NUTAG_SUB_EXPIRES(3700),
NUTAG_KEEPALIVE(66),
NUTAG_KEEPALIVE_STREAM(33),
@ -284,6 +285,7 @@ int test_nua_params(struct context *ctx)
int auth_cache = -1;
unsigned refer_expires = (unsigned)-1;
int refer_with_id = -1;
unsigned sub_expires = (unsigned)-1;
int substate = -1;
sip_allow_t const *allow = NONE;
@ -352,6 +354,7 @@ int test_nua_params(struct context *ctx)
NUTAG_REFER_EXPIRES_REF(refer_expires),
NUTAG_REFER_WITH_ID_REF(refer_with_id),
NUTAG_SUBSTATE_REF(substate),
NUTAG_SUB_EXPIRES_REF(sub_expires),
SIPTAG_SUPPORTED_REF(supported),
SIPTAG_SUPPORTED_STR_REF(supported_str),
@ -382,7 +385,7 @@ int test_nua_params(struct context *ctx)
NUTAG_INSTANCE_REF(instance),
TAG_END());
TEST(n, 50);
TEST(n, 51);
TEST_S(sip_header_as_string(tmphome, (void *)from), Alice);
TEST_S(from_str, Alice);
@ -416,6 +419,7 @@ int test_nua_params(struct context *ctx)
TEST(refer_expires, 333);
TEST(refer_with_id, 0);
TEST(substate, nua_substate_pending);
TEST(sub_expires, 3700);
TEST_S(sip_header_as_string(tmphome, (void *)allow), "OPTIONS, INFO, ACK");
TEST_S(allow_str, "OPTIONS, INFO, ACK");
@ -492,6 +496,7 @@ int test_nua_params(struct context *ctx)
unsigned refer_expires = (unsigned)-1;
int refer_with_id = -1;
int substate = -1;
unsigned sub_expires = (unsigned)-1;
sip_allow_t const *allow = NONE;
char const *allow_str = "NONE";
@ -552,6 +557,7 @@ int test_nua_params(struct context *ctx)
NUTAG_PATH_ENABLE_REF(path_enable),
NUTAG_AUTH_CACHE_REF(auth_cache),
NUTAG_SUBSTATE_REF(substate),
NUTAG_SUB_EXPIRES_REF(sub_expires),
SIPTAG_SUPPORTED_REF(supported),
SIPTAG_SUPPORTED_STR_REF(supported_str),
@ -607,6 +613,7 @@ int test_nua_params(struct context *ctx)
TEST(refer_expires, (unsigned)-1);
TEST(refer_with_id, -1);
TEST(substate, -1);
TEST(sub_expires, -1);
TEST_P(allow, NONE);
TEST_S(allow_str, "NONE");

View File

@ -135,6 +135,7 @@ struct domain {
sip_time_t min_expires, expires, max_expires;
int outbound_tcp; /**< Use inbound TCP connection as outbound */
char const *authorize; /**< Authorization realm to use */
int record_route;
} prefs;
tagi_t *tags;
@ -478,6 +479,23 @@ void test_proxy_domain_get_outbound(struct domain *d,
}
}
void test_proxy_domain_set_record_route(struct domain *d,
int use_record_route)
{
if (d) {
d->prefs.record_route = use_record_route;
}
}
void test_proxy_domain_get_record_route(struct domain *d,
int *return_use_record_route)
{
if (d) {
if (return_use_record_route)
*return_use_record_route = d->prefs.record_route;
}
}
int test_proxy_domain_set_authorize(struct domain *d,
char const *realm)
{
@ -743,6 +761,9 @@ static int proxy_tr_with(struct proxy *proxy,
if (t->method != sip_method_ack && t->method != sip_method_cancel)
nta_incoming_bind(irq, proxy_ack_cancel, t);
if (domain && domain->prefs.record_route)
t->rr = 1;
if (process(t) < 200)
return 0;
@ -818,6 +839,9 @@ static int originating_transaction(struct proxy_tr *t)
t->use_auth = 407;
}
if (o && o->prefs.record_route)
t->rr = 1;
return 0;
}
@ -841,7 +865,6 @@ static int validate_transaction(struct proxy_tr *t)
url_cmp(t->proxy->rr_uri, t->sip->sip_route->r_url) == 0)) {
sip_route_remove(t->msg, t->sip);
/* add record-route also to the forwarded request */
t->rr = 1;
}
if (t->use_auth)
@ -947,12 +970,17 @@ static int target_transaction(struct proxy_tr *t,
msg_header_insert(c->msg, (msg_pub_t *)c->sip, (msg_header_t *)c->rq);
if (t->rr && 0) {
if (t->rr) {
sip_record_route_t rr[1];
*sip_record_route_init(rr)->r_url = *t->proxy->rr_uri;
msg_header_add_dup(c->msg, (msg_pub_t *)c->sip, (msg_header_t *)rr);
if (t->proxy->rr_uri) {
*sip_record_route_init(rr)->r_url = *t->proxy->rr_uri;
msg_header_add_dup(c->msg, (msg_pub_t *)c->sip, (msg_header_t *)rr);
}
else if (t->proxy->lr) {
*sip_record_route_init(rr)->r_url = *t->proxy->lr->r_url;
msg_header_add_dup(c->msg, (msg_pub_t *)c->sip, (msg_header_t *)rr);
}
}
if (c->rq)

View File

@ -73,6 +73,11 @@ void test_proxy_domain_set_outbound(struct domain *d,
void test_proxy_domain_get_outbound(struct domain *d,
int *return_use_outbound);
void test_proxy_domain_set_record_route(struct domain *d,
int use_record_route);
void test_proxy_domain_get_record_route(struct domain *d,
int *return_use_record_route);
int test_proxy_close_tports(struct proxy *p);
SOFIA_END_DECLS

View File

@ -45,6 +45,9 @@
extern int accept_request(CONDITION_PARAMS);
int save_until_nth_final_response(CONDITION_PARAMS);
int accept_n_notifys(CONDITION_PARAMS);
int test_message(struct context *ctx)
{
BEGIN();
@ -564,6 +567,47 @@ static char const presence_closed[] =
"</presence>\n";
int accept_and_notify_twice(CONDITION_PARAMS)
{
msg_t *with = nua_current_request(nua);
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
return 0;
save_event_in_list(ctx, event, ep, call);
switch (event) {
case nua_i_subscribe:
if (status < 200) {
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());
NOTIFY(ep, call, nh,
SIPTAG_EVENT(sip->sip_event),
SIPTAG_CONTENT_TYPE_STR("application/pidf+xml"),
SIPTAG_PAYLOAD_STR(presence_open),
NUTAG_SUBSTATE(nua_substate_active),
TAG_END());
RESPOND(ep, call, nh, SIP_202_ACCEPTED,
NUTAG_WITH(with),
SIPTAG_EXPIRES_STR("360"),
TAG_END());
}
return 0;
case nua_r_notify:
return status >= 200 &&
tl_find(tags, nutag_substate)->t_value == nua_substate_active;
default:
return 0;
}
}
int accept_and_notify(CONDITION_PARAMS)
{
msg_t *with = nua_current_request(nua);
@ -580,12 +624,14 @@ int accept_and_notify(CONDITION_PARAMS)
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());
}
return 0;
@ -597,6 +643,31 @@ int accept_and_notify(CONDITION_PARAMS)
}
}
int save_and_notify(CONDITION_PARAMS)
{
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
return 0;
save_event_in_list(ctx, event, ep, call);
switch (event) {
case nua_i_subscribe:
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_active),
TAG_END());
return 0;
case nua_r_notify:
return status >= 200;
default:
return 0;
}
}
extern int save_until_notified_and_responded(CONDITION_PARAMS);
extern int save_until_notified(CONDITION_PARAMS);
@ -606,7 +677,7 @@ int test_subscribe_notify(struct context *ctx)
struct endpoint *a = &ctx->a, *b = &ctx->b;
struct call *a_call = a->call, *b_call = b->call;
struct event *e;
struct event *e, *en1, *en2, *es;
sip_t const *sip;
tagi_t const *n_tags, *r_tags;
@ -620,44 +691,47 @@ int test_subscribe_notify(struct context *ctx)
SUBSCRIBE(a, a_call, a_call->nh, NUTAG_URL(b->contact->m_url),
SIPTAG_EVENT_STR("presence"),
SIPTAG_EXPIRES_STR("333"),
SIPTAG_ACCEPT_STR("application/xpidf, application/pidf+xml"),
TAG_END());
run_ab_until(ctx, -1, save_until_notified_and_responded,
-1, accept_and_notify);
-1, accept_and_notify_twice);
/* Client events:
nua_subscribe(), nua_i_notify/nua_r_subscribe
nua_subscribe(), nua_i_notify/nua_r_subscribe/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;
TEST_1(tl_find(r_tags, nutag_substate));
TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_pending);
}
else {
TEST_E(e->data->e_event, nua_r_subscribe);
TEST(e->data->e_status, 202);
r_tags = e->data->e_tags;
TEST_1(tl_find(r_tags, nutag_substate));
TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_embryonic);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
TEST_1(sip = sip_object(e->data->e_msg));
n_tags = e->data->e_tags;
for (en1 = en2 = es = NULL, e = a->events->head; e; e = e->next) {
if (en1 == NULL && e->data->e_event == nua_i_notify)
en1 = e;
else if (en2 == NULL && e->data->e_event == nua_i_notify)
en2 = e;
else if (e->data->e_event == nua_r_subscribe)
es = e;
else
TEST_1(!e);
}
TEST_1(e = en1);
TEST_E(e->data->e_event, nua_i_notify);
TEST_1(tl_find(e->data->e_tags, nutag_substate));
TEST(tl_find(e->data->e_tags, nutag_substate)->t_value, nua_substate_pending);
TEST_1(sip = sip_object(e->data->e_msg));
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->next);
TEST_1(e = es); TEST_E(e->data->e_event, nua_r_subscribe);
TEST_1(e->data->e_status == 202 || e->data->e_status == 200);
TEST_1(tl_find(e->data->e_tags, nutag_substate));
TEST(tl_find(e->data->e_tags, nutag_substate)->t_value, nua_substate_pending);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_expires);
TEST_1(sip->sip_expires->ex_delta <= 333);
free_events_in_list(ctx, a->events);
/* Server events: nua_i_subscribe, nua_r_notify */
@ -731,6 +805,80 @@ int test_subscribe_notify(struct context *ctx)
/* ---------------------------------------------------------------------- */
/* Re-SUBSCRIBE
A B
| |
|<------NOTIFY-------|
|-------200 OK------>|
| |
*/
if (print_headings)
printf("TEST NUA-11.4.3: re-SUBSCRIBE\n");
/* Set default expiration time */
nua_set_hparams(b_call->nh, NUTAG_SUB_EXPIRES(365), TAG_END());
run_b_until(ctx, nua_r_set_params, until_final_response);
SUBSCRIBE(a, a_call, a_call->nh, NUTAG_URL(b->contact->m_url),
SIPTAG_EVENT_STR("presence"),
SIPTAG_EXPIRES_STR("3600"),
SIPTAG_ACCEPT_STR("application/xpidf, application/pidf+xml"),
TAG_END());
run_ab_until(ctx, -1, save_until_notified_and_responded,
-1, save_until_final_response);
/* Client events:
nua_subscribe(), nua_i_notify/nua_r_subscribe
*/
for (en1 = en2 = es = NULL, e = a->events->head; e; e = e->next) {
if (en1 == NULL && e->data->e_event == nua_i_notify)
en1 = e;
else if (e->data->e_event == nua_r_subscribe)
es = e;
else
TEST_1(!e);
}
TEST_1(e = en1);
TEST_E(e->data->e_event, nua_i_notify);
TEST_1(sip = sip_object(e->data->e_msg));
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, "active");
TEST_1(sip->sip_subscription_state->ss_expires);
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_active);
TEST_1(e = es); TEST_E(e->data->e_event, nua_r_subscribe);
TEST_1(tl_find(e->data->e_tags, nutag_substate));
TEST(tl_find(e->data->e_tags, nutag_substate)->t_value, nua_substate_active);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_expires);
TEST_1(sip->sip_expires->ex_delta <= 365);
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_active);
free_events_in_list(ctx, b->events);
if (print_headings)
printf("TEST NUA-11.4.3: PASSED\n");
/* ---------------------------------------------------------------------- */
/* un-SUBSCRIBE
A B
@ -742,7 +890,7 @@ int test_subscribe_notify(struct context *ctx)
| |
*/
if (print_headings)
printf("TEST NUA-11.4.3: un-SUBSCRIBE\n");
printf("TEST NUA-11.4.4: un-SUBSCRIBE\n");
UNSUBSCRIBE(a, a_call, a_call->nh, TAG_END());
@ -752,31 +900,35 @@ int test_subscribe_notify(struct context *ctx)
/* Client events:
nua_unsubscribe(), nua_i_notify/nua_r_unsubscribe
*/
TEST_1(e = a->events->head);
if (e->data->e_event == nua_i_notify) {
TEST_E(e->data->e_event, nua_i_notify);
n_tags = e->data->e_tags;
for (en1 = en2 = es = NULL, e = a->events->head; e; e = e->next) {
if (en1 == NULL && e->data->e_event == nua_i_notify)
en1 = e;
else if (e->data->e_event == nua_r_unsubscribe)
es = e;
else
TEST_1(!e);
}
if (en1) {
TEST_1(e = en1); TEST_E(e->data->e_event, nua_i_notify);
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);
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(e = e->next); TEST_E(e->data->e_event, nua_r_unsubscribe);
TEST(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);
}
else {
TEST_E(e->data->e_event, nua_r_unsubscribe);
TEST(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);
}
TEST_1(!e->next);
TEST_1(e = es); TEST_E(e->data->e_event, nua_r_unsubscribe);
TEST(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);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_expires);
TEST_1(sip->sip_expires->ex_delta == 0);
free_events_in_list(ctx, a->events);
/* Notifier events: nua_r_notify */
@ -799,7 +951,7 @@ int test_subscribe_notify(struct context *ctx)
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
if (print_headings)
printf("TEST NUA-11.4.3: PASSED\n");
printf("TEST NUA-11.4.4: PASSED\n");
if (print_headings)
printf("TEST NUA-11.4: PASSED\n");
@ -825,7 +977,7 @@ int test_subscribe_notify_graceful(struct context *ctx)
struct endpoint *a = &ctx->a, *b = &ctx->b;
struct call *a_call = a->call, *b_call = b->call;
struct event *e;
struct event *e, *en1, *en2, *es;
sip_t const *sip;
tagi_t const *n_tags, *r_tags;
struct nat_filter *f;
@ -846,35 +998,33 @@ int test_subscribe_notify_graceful(struct context *ctx)
/* Client events:
nua_subscribe(), nua_i_notify/nua_r_subscribe
*/
TEST_1(e = a->events->head);
if (e->data->e_event == nua_i_notify) {
TEST_E(e->data->e_event, nua_i_notify);
TEST_1(sip = sip_object(e->data->e_msg));
n_tags = e->data->e_tags;
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_subscribe);
r_tags = e->data->e_tags;
TEST_1(tl_find(r_tags, nutag_substate));
TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_pending);
}
else {
TEST_E(e->data->e_event, nua_r_subscribe);
TEST(e->data->e_status, 202);
r_tags = e->data->e_tags;
TEST_1(tl_find(r_tags, nutag_substate));
TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_embryonic);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
TEST_1(sip = sip_object(e->data->e_msg));
n_tags = e->data->e_tags;
for (en1 = en2 = es = NULL, e = a->events->head; e; e = e->next) {
if (en1 == NULL && e->data->e_event == nua_i_notify)
en1 = e;
else if (es == NULL && e->data->e_event == nua_r_subscribe)
es = e;
else
TEST_1(!e);
}
TEST_1(e = en1); TEST_E(e->data->e_event, nua_i_notify);
TEST_1(sip = sip_object(e->data->e_msg));
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);
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_pending);
TEST_1(!e->next);
TEST_1(e = es); TEST_E(e->data->e_event, nua_r_subscribe);
r_tags = e->data->e_tags;
TEST_1(tl_find(r_tags, nutag_substate));
if (es == a->events->head)
TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_embryonic);
else
TEST(tl_find(r_tags, nutag_substate)->t_value, nua_substate_pending);
free_events_in_list(ctx, a->events);
/* Server events: nua_i_subscribe, nua_r_notify */
@ -1011,7 +1161,6 @@ int save_until_notify_responded_twice(CONDITION_PARAMS)
return ep->flags.bit0 && ep->flags.bit1;
}
/* ---------------------------------------------------------------------- */
/* Unsolicited NOTIFY */
@ -1028,6 +1177,8 @@ int test_newsub_notify(struct context *ctx)
sip_call_id_t *i;
tagi_t const *n_tags, *r_tags;
#if 0
if (print_headings)
printf("TEST NUA-11.7.1: rejecting NOTIFY without subscription locally\n");
@ -1161,6 +1312,298 @@ int test_newsub_notify(struct context *ctx)
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
#else
(void)i;
nua_set_params(b->nua, NUTAG_APPL_METHOD("NOTIFY"), TAG_END());
run_b_until(ctx, nua_r_set_params, until_final_response);
#endif
/* ---------------------------------------------------------------------- */
if (print_headings)
printf("TEST NUA-11.7.4: multiple unsolicited NOTIFYs\n");
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
NOTIFY(a, a_call, a_call->nh,
NUTAG_URL(b->contact->m_url),
NUTAG_NEWSUB(1),
SIPTAG_EXPIRES_STR("10"),
SIPTAG_SUBJECT_STR("NUA-11.7.4aa"),
SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"),
SIPTAG_PAYLOAD_STR("Messages-Waiting: no"),
TAG_END());
NOTIFY(a, a_call, a_call->nh,
NUTAG_URL(b->contact->m_url),
NUTAG_NEWSUB(1),
SIPTAG_SUBSCRIPTION_STATE_STR("active; expires=333"),
SIPTAG_SUBJECT_STR("NUA-11.7.4a"),
SIPTAG_EVENT_STR("message-summary"),
SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"),
SIPTAG_PAYLOAD_STR("Messages-Waiting: no"),
TAG_END());
NOTIFY(a, a_call, a_call->nh,
NUTAG_URL(b->contact->m_url),
NUTAG_NEWSUB(1),
SIPTAG_SUBSCRIPTION_STATE_STR("active; expires=3000"),
SIPTAG_SUBJECT_STR("NUA-11.7.4b"),
SIPTAG_EVENT_STR("message-summary"),
SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"),
SIPTAG_PAYLOAD_STR("Messages-Waiting: yes"),
TAG_END());
NOTIFY(a, a_call, a_call->nh,
NUTAG_URL(b->contact->m_url),
NUTAG_NEWSUB(1),
SIPTAG_SUBSCRIPTION_STATE_STR("terminated"),
SIPTAG_SUBJECT_STR("NUA-11.7.4c"),
SIPTAG_EVENT_STR("message-summary"),
SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"),
SIPTAG_PAYLOAD_STR("Messages-Waiting: yes"),
TAG_END());
a->state.n = 4;
b->state.n = 4;
run_ab_until(ctx, -1, save_until_nth_final_response,
-1, accept_n_notifys);
/* Notifier events: nua_r_notify nua_r_notify */
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_notify);
TEST(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);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_notify);
TEST(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_active);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_notify);
TEST(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_active);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_notify);
TEST(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);
TEST_1(!e->next);
/* subscriber events:
nua_i_notify
*/
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_notify);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_subscription_state);
TEST_S(sip->sip_subscription_state->ss_substate, "terminated");
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(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_subscription_state);
TEST_S(sip->sip_subscription_state->ss_substate, "active");
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_active);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_subscription_state);
TEST_S(sip->sip_subscription_state->ss_substate, "active");
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_active);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_subscription_state);
TEST_S(sip->sip_subscription_state->ss_substate, "terminated");
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(!e->next);
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-11.7.4: PASSED\n");
/* ---------------------------------------------------------------------- */
if (print_headings)
printf("TEST NUA-11.7.5: multiple unsolicited NOTIFYs\n");
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
NOTIFY(a, a_call, a_call->nh,
NUTAG_URL(b->contact->m_url),
NUTAG_NEWSUB(1),
SIPTAG_SUBSCRIPTION_STATE_STR("active; expires=333"),
SIPTAG_SUBJECT_STR("NUA-11.7.5a"),
SIPTAG_EVENT_STR("message-summary"),
SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"),
SIPTAG_PAYLOAD_STR("Messages-Waiting: no"),
TAG_END());
NOTIFY(a, a_call, a_call->nh,
NUTAG_URL(b->contact->m_url),
NUTAG_NEWSUB(1),
SIPTAG_SUBSCRIPTION_STATE_STR("active; expires=3000"),
SIPTAG_SUBJECT_STR("NUA-11.7.5b"),
SIPTAG_EVENT_STR("message-summary"),
SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"),
SIPTAG_PAYLOAD_STR("Messages-Waiting: yes"),
TAG_END());
NOTIFY(a, a_call, a_call->nh,
NUTAG_URL(b->contact->m_url),
NUTAG_NEWSUB(1),
SIPTAG_SUBSCRIPTION_STATE_STR("terminated"),
SIPTAG_SUBJECT_STR("NUA-11.7.5c"),
SIPTAG_EVENT_STR("message-summary"),
SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"),
SIPTAG_PAYLOAD_STR("Messages-Waiting: yes"),
TAG_END());
a->state.n = 3;
b->state.n = 3;
run_ab_until(ctx, -1, save_until_nth_final_response,
-1, accept_n_notifys);
/* Notifier events: nua_r_notify nua_r_notify */
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_notify);
TEST(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_active);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_notify);
TEST(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_active);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_notify);
TEST(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);
TEST_1(!e->next);
/* subscriber events:
nua_i_notify
*/
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_notify);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_subscription_state);
TEST_S(sip->sip_subscription_state->ss_substate, "active");
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_active);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_subscription_state);
TEST_S(sip->sip_subscription_state->ss_substate, "active");
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_active);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_subscription_state);
TEST_S(sip->sip_subscription_state->ss_substate, "terminated");
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(!e->next);
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-11.7.5: PASSED\n");
/* ---------------------------------------------------------------------- */
#if 0
if (print_headings)
printf("TEST NUA-11.7.6: unsolicited NOTIFY handle destroyed\n");
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
NOTIFY(a, a_call, a_call->nh,
NUTAG_URL(b->contact->m_url),
NUTAG_NEWSUB(1),
SIPTAG_SUBSCRIPTION_STATE_STR("active; expires=333"),
SIPTAG_SUBJECT_STR("NUA-11.7.6a"),
SIPTAG_EVENT_STR("message-summary"),
SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"),
SIPTAG_PAYLOAD_STR("Messages-Waiting: no"),
TAG_END());
NOTIFY(a, a_call, a_call->nh,
NUTAG_URL(b->contact->m_url),
NUTAG_NEWSUB(1),
SIPTAG_SUBSCRIPTION_STATE_STR("active; expires=3000"),
SIPTAG_SUBJECT_STR("NUA-11.7.6b"),
SIPTAG_EVENT_STR("message-summary"),
SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"),
SIPTAG_PAYLOAD_STR("Messages-Waiting: yes"),
TAG_END());
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
a->state.n = 3;
b->state.n = 3;
run_b_until(ctx, -1, accept_n_notifys);
/* subscriber events:
nua_i_notify
*/
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_notify);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_subscription_state);
TEST_S(sip->sip_subscription_state->ss_substate, "active");
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_active);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_subscription_state);
TEST_S(sip->sip_subscription_state->ss_substate, "active");
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_active);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_notify);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_subscription_state);
TEST_S(sip->sip_subscription_state->ss_substate, "terminated");
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(!e->next);
free_events_in_list(ctx, b->events);
if (print_headings)
printf("TEST NUA-11.7.6: PASSED\n");
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
#endif
if (print_headings)
printf("TEST NUA-11.7: PASSED\n");
@ -1183,6 +1626,50 @@ int accept_notify(CONDITION_PARAMS)
return event == nua_i_notify;
}
int save_until_nth_final_response(CONDITION_PARAMS)
{
save_event_in_list(ctx, event, ep, call);
if (nua_r_set_params <= event && event < nua_i_network_changed
&& status >= 200) {
if (ep->state.n > 0)
ep->state.n--;
return ep->state.n == 0;
}
return 0;
}
int accept_n_notifys(CONDITION_PARAMS)
{
tagi_t const *substate = tl_find(tags, nutag_substate);
if (event == nua_i_notify && status < 200)
RESPOND(ep, call, nh, SIP_200_OK,
NUTAG_WITH_THIS(ep->nua),
TAG_END());
save_event_in_list(ctx, event, ep, call);
if (event != nua_i_notify)
return 0;
if (ep->state.n > 0)
ep->state.n--;
if (ep->state.n == 0)
return 1;
if (substate && substate->t_value == nua_substate_terminated) {
if (call && call->nh == nh) {
call->nh = NULL;
nua_handle_destroy(nh);
}
}
return 0;
}
/* ======================================================================== */
int save_until_subscription_terminated(CONDITION_PARAMS);
@ -1336,8 +1823,8 @@ int accept_subscription_until_terminated(CONDITION_PARAMS)
int test_simple(struct context *ctx)
{
return
test_message(ctx)
return 0
|| test_message(ctx)
|| test_publish(ctx)
|| test_subscribe_notify(ctx)
|| test_subscribe_notify_graceful(ctx)

View File

@ -613,8 +613,8 @@ static void print_media(sdp_printer_t *p,
sdp_printf(p, " %s", l->l_text);
}
else {
sdp_printf(p, " 9"); /* SDP syntax requires at least one format.
9 is used by nobody, right?. */
sdp_printf(p, " 19"); /* SDP syntax requires at least one format.
19 is used by nobody, right?. */
}