Commit 5a15741f authored by Pekka Pessi's avatar Pekka Pessi

nua_notifier.c, nua_subnotref.c: fixed timeout of nua_notify(), fixed handling...

nua_notifier.c, nua_subnotref.c: fixed timeout of nua_notify(), fixed handling of unsolicited NOTIFYs.

test_simple.c: added test case for subscription timeout, nua_method() with NUTAG_DIALOG(2).

darcs-hash:20070411134416-65a35-c5769e80202a17de328bd194ba2abcf92acd6823.gz
parent 0dc5a421
......@@ -514,6 +514,15 @@ void nua_dialog_usage_refresh_range(nua_dialog_usage_t *du,
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)
{
......
......@@ -448,6 +448,9 @@ 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,
......
......@@ -690,9 +690,15 @@ static int nua_notify_client_report(nua_client_request_t *cr,
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 @@ static void nua_notify_usage_refresh(nua_handle_t *nh,
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;
......
......@@ -61,6 +61,7 @@ struct event_usage
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 @@ static void nua_subscribe_usage_refresh(nua_handle_t *nh,
*/
}
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 @@ nua_server_methods_t const nua_notify_server_methods =
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 @@ int nua_notify_server_preprocess(nua_server_request_t *sr)
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 @@ int nua_notify_server_preprocess(nua_server_request_t *sr)
}
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 @@ int nua_notify_server_report(nua_server_request_t *sr, tagi_t const *tags)
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);
......
......@@ -323,8 +323,8 @@ int main(int argc, char *argv[])
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;
......
......@@ -972,6 +972,7 @@ int save_until_notify_responded_twice(CONDITION_PARAMS)
return ep->flags.bit0 && ep->flags.bit1;
}
/* ---------------------------------------------------------------------- */
/* Unsolicited NOTIFY */
......@@ -1122,7 +1123,7 @@ int test_newsub_notify(struct context *ctx)
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();
}
......@@ -1143,6 +1144,155 @@ int accept_notify(CONDITION_PARAMS)
return event == nua_i_notify;
}
/* ======================================================================== */
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 */
......@@ -1154,5 +1304,6 @@ int test_simple(struct context *ctx)
|| test_subscribe_notify(ctx)
|| test_subscribe_notify_graceful(ctx)
|| test_newsub_notify(ctx)
|| test_subscription_timeout(ctx)
;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment