Commit b2381780 authored by Pekka Pessi's avatar Pekka Pessi

nua: allow unsolicited NOTIFY.

When NUTAG_NEWSUB(1) is included in nua_notify() tags, notifier will allow
sending unsolicited NOTIFY without existing subscription.

When NUTAG_APPL_METHOD("NOTIFY") is included in nua_set_params() tags,
incoming NOTIFYs are to be processed and accepted by application.

darcs-hash:20070202001221-65a35-398f052ec1badc0bc6ef370fa602a160b7dda300.gz
parent 6169cc04
...@@ -424,9 +424,24 @@ static int nua_notify_client_init(nua_client_request_t *cr, ...@@ -424,9 +424,24 @@ static int nua_notify_client_init(nua_client_request_t *cr,
o = NONE; o = NONE;
du = nua_dialog_usage_get(nh->nh_ds, nua_notify_usage, o); du = nua_dialog_usage_get(nh->nh_ds, nua_notify_usage, o);
nu = nua_dialog_usage_private(du);
if (!du) if (!du) {
return -1; tagi_t const *newsub = tl_find_last(tags, nutag_newsub);
if (!newsub || !newsub->t_value)
return 0; /* Rejected eventually by nua_notify_client_request() */
/* Create new notifier */
du = nua_dialog_usage_add(nh, nh->nh_ds, nua_notify_usage, o);
if (du == NULL)
return -1;
nu = nua_dialog_usage_private(du);
nu->nu_expires = now;
}
else
nu = nua_dialog_usage_private(du);
if (nu->nu_substate == nua_substate_terminated) { if (nu->nu_substate == nua_substate_terminated) {
/*Xyzzy*/; /*Xyzzy*/;
...@@ -437,8 +452,8 @@ static int nua_notify_client_init(nua_client_request_t *cr, ...@@ -437,8 +452,8 @@ static int nua_notify_client_init(nua_client_request_t *cr,
if (ss->ss_expires) { if (ss->ss_expires) {
unsigned long expires = strtoul(ss->ss_expires, NULL, 10); unsigned long expires = strtoul(ss->ss_expires, NULL, 10);
if (expires > 3600) /* Why? */ if (now + expires < now)
expires = 3600; expires = SIP_TIME_MAX - now - 1;
/* Notifier can only shorten the subscription time */ /* Notifier can only shorten the subscription time */
if (nu->nu_requested == 0 || nu->nu_requested >= now + expires) if (nu->nu_requested == 0 || nu->nu_requested >= now + expires)
......
...@@ -508,10 +508,10 @@ nua_server_methods_t const nua_notify_server_methods = ...@@ -508,10 +508,10 @@ nua_server_methods_t const nua_notify_server_methods =
SIP_METHOD_NOTIFY, SIP_METHOD_NOTIFY,
nua_i_notify, /* Event */ nua_i_notify, /* Event */
{ {
0, /* Do not create dialog */ 1, /* Do create dialog */
1, /* In-dialog request */ 0, /* Not always in-dialog request */
1, /* Target refresh request */ 1, /* Target refresh request */
1, /* Add Contact */ 1, /* Add Contact to response */
}, },
nua_notify_server_init, nua_notify_server_init,
nua_notify_server_preprocess, nua_notify_server_preprocess,
...@@ -563,9 +563,14 @@ int nua_notify_server_preprocess(nua_server_request_t *sr) ...@@ -563,9 +563,14 @@ int nua_notify_server_preprocess(nua_server_request_t *sr)
char const *what = "", *reason = NULL; char const *what = "", *reason = NULL;
du = nua_dialog_usage_get(ds, nua_subscribe_usage, o); du = nua_dialog_usage_get(ds, nua_subscribe_usage, o);
if (du == NULL)
return SR_STATUS(sr, 481, "Subscription Does Not Exist");
sr->sr_usage = du; 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;
}
eu = nua_dialog_usage_private(du); assert(eu); eu = nua_dialog_usage_private(du); assert(eu);
eu->eu_notified++; eu->eu_notified++;
......
...@@ -68,6 +68,7 @@ tag_typedef_t nutag_answer_recv = BOOLTAG_TYPEDEF(answer_recv); ...@@ -68,6 +68,7 @@ tag_typedef_t nutag_answer_recv = BOOLTAG_TYPEDEF(answer_recv);
tag_typedef_t nutag_offer_sent = BOOLTAG_TYPEDEF(offer_sent); tag_typedef_t nutag_offer_sent = BOOLTAG_TYPEDEF(offer_sent);
tag_typedef_t nutag_answer_sent = BOOLTAG_TYPEDEF(answer_sent); tag_typedef_t nutag_answer_sent = BOOLTAG_TYPEDEF(answer_sent);
tag_typedef_t nutag_substate = INTTAG_TYPEDEF(substate); tag_typedef_t nutag_substate = INTTAG_TYPEDEF(substate);
tag_typedef_t nutag_newsub = BOOLTAG_TYPEDEF(newsub);
tag_typedef_t nutag_invite_timer = UINTTAG_TYPEDEF(invite_timer); tag_typedef_t nutag_invite_timer = UINTTAG_TYPEDEF(invite_timer);
tag_typedef_t nutag_session_timer = UINTTAG_TYPEDEF(session_timer); tag_typedef_t nutag_session_timer = UINTTAG_TYPEDEF(session_timer);
tag_typedef_t nutag_min_se = UINTTAG_TYPEDEF(min_se); tag_typedef_t nutag_min_se = UINTTAG_TYPEDEF(min_se);
......
...@@ -1915,6 +1915,40 @@ SOFIAPUBFUN char const *nua_substate_name(enum nua_substate substate); ...@@ -1915,6 +1915,40 @@ SOFIAPUBFUN char const *nua_substate_name(enum nua_substate substate);
/** Convert string to enum nua_substate. @NEW_1_12_5. */ /** Convert string to enum nua_substate. @NEW_1_12_5. */
SOFIAPUBFUN enum nua_substate nua_substate_make(char const *sip_substate); SOFIAPUBFUN enum nua_substate nua_substate_make(char const *sip_substate);
/**Send unsolicited NOTIFY request.
*
* Some applications may require sending unsolicited NOTIFY requests, that
* is, NOTIFY without SUBSCRIBE or REFER request sent by event watcher.
* However, sending NOTIFY request requires an existing dialog usage by
* default. If NUTAG_NEWSUB(1) is included in the nua_notify() the usage
* is create the usage by itself.
*
* If you want to create a subscription that does not terminate immediately
* include SIPTAG_SUBSCRIPTION_STATE_STR() with an "expires" parameter in
* the argument list, too.
*
* @par Used with
* nua_notify()
*
* @par Parameter type
* int (boolean)
*
* @par Values
* - 0 - false (default) - do not create new subscription
* but reject NOTIFY with 481 locally \n
* - 1 - true - create a subscription if it does not exist \n
*
* Corresponding tag taking reference parameter is NUTAG_NEWSUB().
*
* @since @NEW_1_12_5.
*/
#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;
/**Default lifetime for implicit subscriptions created by REFER. /**Default lifetime for implicit subscriptions created by REFER.
* *
* Default expiration time in seconds for implicit subscriptions created by * Default expiration time in seconds for implicit subscriptions created by
......
...@@ -760,6 +760,146 @@ int test_subscribe_notify(struct context *ctx) ...@@ -760,6 +760,146 @@ int test_subscribe_notify(struct context *ctx)
END(); END();
} }
/* ---------------------------------------------------------------------- */
/* Unsolicited NOTIFY */
int accept_notify(CONDITION_PARAMS);
int test_newsub_notify(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.7.1: rejecting NOTIFY without subscription locally\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),
SIPTAG_SUBJECT_STR("NUA-11.7.1"),
SIPTAG_EVENT_STR("message-summary"),
SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"),
SIPTAG_PAYLOAD_STR("Messages-Waiting: yes"),
TAG_END());
run_a_until(ctx, -1, save_until_final_response);
/* Client events:
nua_notify(), nua_r_notify
*/
TEST_1(e = a->events->head);
TEST_E(e->data->e_event, nua_r_notify);
TEST(e->data->e_status, 481);
TEST_1(!e->data->e_msg);
TEST_1(!e->next);
free_events_in_list(ctx, a->events);
if (print_headings)
printf("TEST NUA-11.7.1: PASSED\n");
if (print_headings)
printf("TEST NUA-11.7.2: rejecting NOTIFY without subscription\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_SUBJECT_STR("NUA-11.7.2"),
SIPTAG_EVENT_STR("message-summary"),
SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"),
SIPTAG_PAYLOAD_STR("Messages-Waiting: yes"),
TAG_END());
run_a_until(ctx, -1, save_until_final_response);
/* Client events:
nua_notify(), nua_r_notify
*/
TEST_1(e = a->events->head);
TEST_E(e->data->e_event, nua_r_notify);
TEST(e->data->e_status, 481);
TEST_1(e->data->e_msg);
TEST_1(!e->next);
free_events_in_list(ctx, a->events);
if (print_headings)
printf("TEST NUA-11.7.2: PASSED\n");
/* ---------------------------------------------------------------------- */
if (print_headings)
printf("TEST NUA-11.7.3: accept NOTIFY\n");
nua_set_params(b->nua, NUTAG_APPL_METHOD("NOTIFY"), TAG_END());
run_b_until(ctx, nua_r_set_params, until_final_response);
NOTIFY(a, a_call, a_call->nh,
NUTAG_URL(b->contact->m_url),
NUTAG_NEWSUB(1),
SIPTAG_SUBJECT_STR("NUA-11.7.3"),
SIPTAG_EVENT_STR("message-summary"),
SIPTAG_CONTENT_TYPE_STR("application/simple-message-summary"),
SIPTAG_PAYLOAD_STR("Messages-Waiting: yes"),
TAG_END());
run_ab_until(ctx, -1, save_until_final_response, -1, accept_notify);
/* Notifier events: 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);
/* 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->next);
free_events_in_list(ctx, a->events);
free_events_in_list(ctx, b->events);
if (print_headings)
printf("TEST NUA-11.7.3: PASSED\n");
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.6: PASSED\n");
END();
}
/**Terminate when received notify.
* Respond to NOTIFY with 200 OK if it has not been responded.
* Save events (except nua_i_active or terminated).
*/
int accept_notify(CONDITION_PARAMS)
{
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);
return event == nua_i_notify;
}
/* ======================================================================== */ /* ======================================================================== */
/* Test simple methods: MESSAGE, PUBLISH, SUBSCRIBE/NOTIFY */ /* Test simple methods: MESSAGE, PUBLISH, SUBSCRIBE/NOTIFY */
...@@ -769,5 +909,6 @@ int test_simple(struct context *ctx) ...@@ -769,5 +909,6 @@ int test_simple(struct context *ctx)
/* test_message(ctx) /* test_message(ctx)
|| */ test_publish(ctx) || */ test_publish(ctx)
|| test_subscribe_notify(ctx) || test_subscribe_notify(ctx)
|| test_newsub_notify(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