1
/* $Id: evsub.c 4747 2014-02-18 01:33:17Z bennylp $ */
3
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
#include <pjsip-simple/evsub.h>
21
#include <pjsip-simple/evsub_msg.h>
22
#include <pjsip-simple/errno.h>
23
#include <pjsip/sip_errno.h>
24
#include <pjsip/sip_module.h>
25
#include <pjsip/sip_endpoint.h>
26
#include <pjsip/sip_dialog.h>
27
#include <pjsip/sip_auth.h>
28
#include <pjsip/sip_transaction.h>
29
#include <pjsip/sip_event.h>
30
#include <pj/assert.h>
36
#include <pj/string.h>
39
#define THIS_FILE "evsub.c"
45
/* Let's define this enum, so that it'll trigger compilation error
46
* when somebody define the same enum in sip_msg.h
50
PJSIP_SUBSCRIBE_METHOD = PJSIP_OTHER_METHOD,
51
PJSIP_NOTIFY_METHOD = PJSIP_OTHER_METHOD
54
PJ_DEF_DATA(const pjsip_method) pjsip_subscribe_method =
56
(pjsip_method_e) PJSIP_SUBSCRIBE_METHOD,
60
PJ_DEF_DATA(const pjsip_method) pjsip_notify_method =
62
(pjsip_method_e) PJSIP_NOTIFY_METHOD,
67
* SUBSCRIBE method constant.
69
PJ_DEF(const pjsip_method*) pjsip_get_subscribe_method()
71
return &pjsip_subscribe_method;
75
* NOTIFY method constant.
77
PJ_DEF(const pjsip_method*) pjsip_get_notify_method()
79
return &pjsip_notify_method;
86
static void mod_evsub_on_tsx_state(pjsip_transaction*, pjsip_event*);
87
static pj_status_t mod_evsub_unload(void);
93
static pj_str_t evsub_state_names[] =
108
/* Number of seconds to send SUBSCRIBE before the actual expiration */
109
#define TIME_UAC_REFRESH PJSIP_EVSUB_TIME_UAC_REFRESH
111
/* Time to wait for the final NOTIFY after sending unsubscription */
112
#define TIME_UAC_TERMINATE PJSIP_EVSUB_TIME_UAC_TERMINATE
114
/* If client responds NOTIFY with non-2xx final response (such as 401),
115
* wait for this seconds for further NOTIFY, otherwise client will
118
#define TIME_UAC_WAIT_NOTIFY PJSIP_EVSUB_TIME_UAC_WAIT_NOTIFY
129
/* Time to refresh client subscription.
130
* The action is to call on_client_refresh() callback.
132
TIMER_TYPE_UAC_REFRESH,
134
/* UAS timeout after to subscription refresh.
135
* The action is to call on_server_timeout() callback.
137
TIMER_TYPE_UAS_TIMEOUT,
139
/* UAC waiting for final NOTIFY after unsubscribing
140
* The action is to terminate.
142
TIMER_TYPE_UAC_TERMINATE,
144
/* UAC waiting for further NOTIFY after sending non-2xx response to
145
* NOTIFY. The action is to unsubscribe.
147
TIMER_TYPE_UAC_WAIT_NOTIFY,
149
/* Max nb of timer types. */
153
static const char *timer_names[] =
164
* Definition of event package.
168
PJ_DECL_LIST_MEMBER(struct evpkg);
171
pjsip_module *pkg_mod;
172
unsigned pkg_expires;
173
pjsip_accept_hdr *pkg_accept;
178
* Event subscription module (mod-evsub).
180
static struct mod_evsub
184
pjsip_endpoint *endpt;
185
struct evpkg pkg_list;
186
pjsip_allow_events_hdr *allow_events_hdr;
191
NULL, NULL, /* prev, next. */
192
{ "mod-evsub", 9 }, /* Name. */
194
PJSIP_MOD_PRIORITY_DIALOG_USAGE, /* Priority */
198
&mod_evsub_unload, /* unload() */
199
NULL, /* on_rx_request() */
200
NULL, /* on_rx_response() */
201
NULL, /* on_tx_request. */
202
NULL, /* on_tx_response() */
203
&mod_evsub_on_tsx_state, /* on_tsx_state() */
209
* Event subscription session.
213
char obj_name[PJ_MAX_OBJ_NAME]; /**< Name. */
214
pj_pool_t *pool; /**< Pool. */
215
pjsip_endpoint *endpt; /**< Endpoint instance. */
216
pjsip_dialog *dlg; /**< Underlying dialog. */
217
struct evpkg *pkg; /**< The event package. */
218
unsigned option; /**< Options. */
219
pjsip_evsub_user user; /**< Callback. */
220
pj_bool_t call_cb; /**< Notify callback? */
221
pjsip_role_e role; /**< UAC=subscriber, UAS=notifier */
222
pjsip_evsub_state state; /**< Subscription state. */
223
pj_str_t state_str; /**< String describing the state. */
224
pjsip_evsub_state dst_state; /**< Pending state to be set. */
225
pj_str_t dst_state_str;/**< Pending state to be set. */
226
pj_str_t term_reason; /**< Termination reason. */
227
pjsip_method method; /**< Method that established subscr.*/
228
pjsip_event_hdr *event; /**< Event description. */
229
pjsip_expires_hdr *expires; /**< Expires header */
230
pjsip_accept_hdr *accept; /**< Local Accept header. */
231
pjsip_hdr sub_hdr_list; /**< User-defined header. */
233
pj_time_val refresh_time; /**< Time to refresh. */
234
pj_timer_entry timer; /**< Internal timer. */
235
int pending_tsx; /**< Number of pending transactions.*/
236
pjsip_transaction *pending_sub; /**< Pending UAC SUBSCRIBE tsx. */
238
void *mod_data[PJSIP_MAX_MODULE]; /**< Module data. */
243
* This is the structure that will be "attached" to dialog.
244
* The purpose is to allow multiple subscriptions inside a dialog.
248
PJ_DECL_LIST_MEMBER(struct dlgsub);
254
static const pj_str_t STR_EVENT = { "Event", 5 };
255
static const pj_str_t STR_EVENT_S = { "o", 1 };
256
static const pj_str_t STR_SUB_STATE = { "Subscription-State", 18 };
257
static const pj_str_t STR_TERMINATED = { "terminated", 10 };
258
static const pj_str_t STR_ACTIVE = { "active", 6 };
259
static const pj_str_t STR_PENDING = { "pending", 7 };
260
static const pj_str_t STR_TIMEOUT = { "timeout", 7};
266
static pj_status_t mod_evsub_unload(void)
268
pjsip_endpt_release_pool(mod_evsub.endpt, mod_evsub.pool);
269
mod_evsub.pool = NULL;
274
/* Proto for pjsipsimple_strerror().
277
PJ_DECL(pj_str_t) pjsipsimple_strerror( pj_status_t statcode,
278
char *buf, pj_size_t bufsize );
281
* Init and register module.
283
PJ_DEF(pj_status_t) pjsip_evsub_init_module(pjsip_endpoint *endpt)
286
pj_str_t method_tags[] = {
291
status = pj_register_strerror(PJSIP_SIMPLE_ERRNO_START,
293
&pjsipsimple_strerror);
294
pj_assert(status == PJ_SUCCESS);
296
PJ_ASSERT_RETURN(endpt != NULL, PJ_EINVAL);
297
PJ_ASSERT_RETURN(mod_evsub.mod.id == -1, PJ_EINVALIDOP);
299
/* Keep endpoint for future reference: */
300
mod_evsub.endpt = endpt;
302
/* Init event package list: */
303
pj_list_init(&mod_evsub.pkg_list);
306
mod_evsub.pool = pjsip_endpt_create_pool(endpt, "evsub", 512, 512);
310
/* Register module: */
311
status = pjsip_endpt_register_module(endpt, &mod_evsub.mod);
312
if (status != PJ_SUCCESS)
315
/* Create Allow-Events header: */
316
mod_evsub.allow_events_hdr = pjsip_allow_events_hdr_create(mod_evsub.pool);
318
/* Register SIP-event specific headers parser: */
319
pjsip_evsub_init_parser();
321
/* Register new methods SUBSCRIBE and NOTIFY in Allow-ed header */
322
pjsip_endpt_add_capability(endpt, &mod_evsub.mod, PJSIP_H_ALLOW, NULL,
329
if (mod_evsub.pool) {
330
pjsip_endpt_release_pool(endpt, mod_evsub.pool);
331
mod_evsub.pool = NULL;
333
mod_evsub.endpt = NULL;
339
* Get the instance of the module.
341
PJ_DEF(pjsip_module*) pjsip_evsub_instance(void)
343
PJ_ASSERT_RETURN(mod_evsub.mod.id != -1, NULL);
345
return &mod_evsub.mod;
350
* Get the event subscription instance in the transaction.
352
PJ_DEF(pjsip_evsub*) pjsip_tsx_get_evsub(pjsip_transaction *tsx)
354
return (pjsip_evsub*) tsx->mod_data[mod_evsub.mod.id];
359
* Set event subscription's module data.
361
PJ_DEF(void) pjsip_evsub_set_mod_data( pjsip_evsub *sub, unsigned mod_id,
364
PJ_ASSERT_ON_FAIL(mod_id < PJSIP_MAX_MODULE, return);
365
sub->mod_data[mod_id] = data;
370
* Get event subscription's module data.
372
PJ_DEF(void*) pjsip_evsub_get_mod_data( pjsip_evsub *sub, unsigned mod_id )
374
PJ_ASSERT_RETURN(mod_id < PJSIP_MAX_MODULE, NULL);
375
return sub->mod_data[mod_id];
380
* Find registered event package with matching name.
382
static struct evpkg* find_pkg(const pj_str_t *event_name)
386
pkg = mod_evsub.pkg_list.next;
387
while (pkg != &mod_evsub.pkg_list) {
389
if (pj_stricmp(&pkg->pkg_name, event_name) == 0) {
400
* Register an event package
402
PJ_DEF(pj_status_t) pjsip_evsub_register_pkg( pjsip_module *pkg_mod,
403
const pj_str_t *event_name,
406
const pj_str_t accept[])
411
PJ_ASSERT_RETURN(pkg_mod && event_name, PJ_EINVAL);
412
PJ_ASSERT_RETURN(accept_cnt < PJ_ARRAY_SIZE(pkg->pkg_accept->values),
415
/* Make sure evsub module has been initialized */
416
PJ_ASSERT_RETURN(mod_evsub.mod.id != -1, PJ_EINVALIDOP);
418
/* Make sure no module with the specified name already registered: */
420
PJ_ASSERT_RETURN(find_pkg(event_name) == NULL, PJSIP_SIMPLE_EPKGEXISTS);
423
/* Create new event package: */
425
pkg = PJ_POOL_ALLOC_T(mod_evsub.pool, struct evpkg);
426
pkg->pkg_mod = pkg_mod;
427
pkg->pkg_expires = expires;
428
pj_strdup(mod_evsub.pool, &pkg->pkg_name, event_name);
430
pkg->pkg_accept = pjsip_accept_hdr_create(mod_evsub.pool);
431
pkg->pkg_accept->count = accept_cnt;
432
for (i=0; i<accept_cnt; ++i) {
433
pj_strdup(mod_evsub.pool, &pkg->pkg_accept->values[i], &accept[i]);
436
/* Add to package list: */
438
pj_list_push_back(&mod_evsub.pkg_list, pkg);
440
/* Add to Allow-Events header: */
442
if (mod_evsub.allow_events_hdr->count !=
443
PJ_ARRAY_SIZE(mod_evsub.allow_events_hdr->values))
445
mod_evsub.allow_events_hdr->values[mod_evsub.allow_events_hdr->count] =
447
++mod_evsub.allow_events_hdr->count;
450
/* Add to endpoint's Accept header */
451
pjsip_endpt_add_capability(mod_evsub.endpt, &mod_evsub.mod,
452
PJSIP_H_ACCEPT, NULL,
453
pkg->pkg_accept->count,
454
pkg->pkg_accept->values);
459
PJ_LOG(5,(THIS_FILE, "Event pkg \"%.*s\" registered by %.*s",
460
(int)event_name->slen, event_name->ptr,
461
(int)pkg_mod->name.slen, pkg_mod->name.ptr));
468
* Retrieve Allow-Events header
470
PJ_DEF(const pjsip_hdr*) pjsip_evsub_get_allow_events_hdr(pjsip_module *m)
472
struct mod_evsub *mod;
475
m = pjsip_evsub_instance();
477
mod = (struct mod_evsub*)m;
479
return (pjsip_hdr*) mod->allow_events_hdr;
484
* Update expiration time.
486
static void update_expires( pjsip_evsub *sub, pj_uint32_t interval )
488
pj_gettimeofday(&sub->refresh_time);
489
sub->refresh_time.sec += interval;
496
static void set_timer( pjsip_evsub *sub, int timer_id,
499
if (sub->timer.id != TIMER_TYPE_NONE) {
500
PJ_LOG(5,(sub->obj_name, "%s %s timer",
501
(timer_id==sub->timer.id ? "Updating" : "Cancelling"),
502
timer_names[sub->timer.id]));
503
pjsip_endpt_cancel_timer(sub->endpt, &sub->timer);
504
sub->timer.id = TIMER_TYPE_NONE;
507
if (timer_id != TIMER_TYPE_NONE) {
510
PJ_ASSERT_ON_FAIL(seconds > 0, return);
511
PJ_ASSERT_ON_FAIL(timer_id>TIMER_TYPE_NONE && timer_id<TIMER_TYPE_MAX,
514
timeout.sec = seconds;
516
sub->timer.id = timer_id;
518
pjsip_endpt_schedule_timer(sub->endpt, &sub->timer, &timeout);
520
PJ_LOG(5,(sub->obj_name, "Timer %s scheduled in %d seconds",
521
timer_names[sub->timer.id], timeout.sec));
529
static void evsub_destroy( pjsip_evsub *sub )
531
struct dlgsub *dlgsub_head, *dlgsub;
533
PJ_LOG(4,(sub->obj_name, "Subscription destroyed"));
536
set_timer(sub, TIMER_TYPE_NONE, 0);
538
/* Remove this session from dialog's list of subscription */
539
dlgsub_head = (struct dlgsub *) sub->dlg->mod_data[mod_evsub.mod.id];
540
dlgsub = dlgsub_head->next;
541
while (dlgsub != dlgsub_head) {
543
if (dlgsub->sub == sub) {
544
pj_list_erase(dlgsub);
548
dlgsub = dlgsub->next;
551
/* Decrement dialog's session */
552
pjsip_dlg_dec_session(sub->dlg, &mod_evsub.mod);
556
* Set subscription session state.
558
static void set_state( pjsip_evsub *sub, pjsip_evsub_state state,
559
const pj_str_t *state_str, pjsip_event *event,
560
const pj_str_t *reason)
562
pjsip_evsub_state prev_state = sub->state;
563
pj_str_t old_state_str = sub->state_str;
564
pjsip_event dummy_event;
568
if (state_str && state_str->slen)
569
pj_strdup_with_null(sub->pool, &sub->state_str, state_str);
571
sub->state_str = evsub_state_names[state];
573
if (reason && sub->term_reason.slen==0)
574
pj_strdup(sub->pool, &sub->term_reason, reason);
576
PJ_LOG(4,(sub->obj_name,
577
"Subscription state changed %.*s --> %.*s",
578
(int)old_state_str.slen,
580
(int)sub->state_str.slen,
581
sub->state_str.ptr));
582
pj_log_push_indent();
584
/* don't call the callback with NULL event, it may crash the app! */
586
PJSIP_EVENT_INIT_USER(dummy_event, 0, 0, 0, 0);
587
event = &dummy_event;
590
if (sub->user.on_evsub_state && sub->call_cb)
591
(*sub->user.on_evsub_state)(sub, event);
593
if (state == PJSIP_EVSUB_STATE_TERMINATED &&
594
prev_state != PJSIP_EVSUB_STATE_TERMINATED)
596
/* Kill any timer. */
597
set_timer(sub, TIMER_TYPE_NONE, 0);
599
if (sub->pending_tsx == 0) {
611
static void on_timer( pj_timer_heap_t *timer_heap,
612
struct pj_timer_entry *entry)
617
PJ_UNUSED_ARG(timer_heap);
619
sub = (pjsip_evsub*) entry->user_data;
621
pjsip_dlg_inc_lock(sub->dlg);
623
timer_id = entry->id;
624
entry->id = TIMER_TYPE_NONE;
628
case TIMER_TYPE_UAC_REFRESH:
629
/* Time for UAC to refresh subscription */
630
if (sub->user.on_client_refresh && sub->call_cb) {
631
(*sub->user.on_client_refresh)(sub);
633
pjsip_tx_data *tdata;
636
PJ_LOG(5,(sub->obj_name, "Refreshing subscription."));
637
pj_log_push_indent();
638
status = pjsip_evsub_initiate(sub, NULL,
639
sub->expires->ivalue,
641
if (status == PJ_SUCCESS)
642
pjsip_evsub_send_request(sub, tdata);
648
case TIMER_TYPE_UAS_TIMEOUT:
649
/* Refresh from UAC has not been received */
650
if (sub->user.on_server_timeout && sub->call_cb) {
651
(*sub->user.on_server_timeout)(sub);
653
pjsip_tx_data *tdata;
656
PJ_LOG(5,(sub->obj_name, "Timeout waiting for refresh. "
657
"Sending NOTIFY to terminate."));
658
pj_log_push_indent();
659
status = pjsip_evsub_notify( sub, PJSIP_EVSUB_STATE_TERMINATED,
660
NULL, &STR_TIMEOUT, &tdata);
661
if (status == PJ_SUCCESS)
662
pjsip_evsub_send_request(sub, tdata);
668
case TIMER_TYPE_UAC_TERMINATE:
670
pj_str_t timeout = {"timeout", 7};
672
PJ_LOG(5,(sub->obj_name, "Timeout waiting for final NOTIFY. "
674
pj_log_push_indent();
675
set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, NULL,
681
case TIMER_TYPE_UAC_WAIT_NOTIFY:
683
pjsip_tx_data *tdata;
686
PJ_LOG(5,(sub->obj_name,
687
"Timeout waiting for subsequent NOTIFY (we did "
688
"send non-2xx response for previous NOTIFY). "
690
pj_log_push_indent();
691
status = pjsip_evsub_initiate( sub, NULL, 0, &tdata);
692
if (status == PJ_SUCCESS)
693
pjsip_evsub_send_request(sub, tdata);
700
pj_assert(!"Invalid timer id");
703
pjsip_dlg_dec_lock(sub->dlg);
708
* Create subscription session, used for both client and notifier.
710
static pj_status_t evsub_create( pjsip_dialog *dlg,
712
const pjsip_evsub_user *user_cb,
713
const pj_str_t *event,
715
pjsip_evsub **p_evsub )
719
struct dlgsub *dlgsub_head, *dlgsub;
722
/* Make sure there's package register for the event name: */
724
pkg = find_pkg(event);
726
return PJSIP_SIMPLE_ENOPKG;
729
/* Must lock dialog before using pool etc. */
730
pjsip_dlg_inc_lock(dlg);
732
/* Init attributes: */
734
sub = PJ_POOL_ZALLOC_T(dlg->pool, struct pjsip_evsub);
735
sub->pool = dlg->pool;
736
sub->endpt = dlg->endpt;
740
sub->call_cb = PJ_TRUE;
741
sub->option = option;
742
sub->state = PJSIP_EVSUB_STATE_NULL;
743
sub->state_str = evsub_state_names[sub->state];
744
sub->expires = pjsip_expires_hdr_create(sub->pool, pkg->pkg_expires);
745
sub->accept = (pjsip_accept_hdr*)
746
pjsip_hdr_clone(sub->pool, pkg->pkg_accept);
747
pj_list_init(&sub->sub_hdr_list);
749
sub->timer.user_data = sub;
750
sub->timer.cb = &on_timer;
753
pj_ansi_snprintf(sub->obj_name, PJ_ARRAY_SIZE(sub->obj_name),
757
/* Copy callback, if any: */
759
pj_memcpy(&sub->user, user_cb, sizeof(pjsip_evsub_user));
762
/* Create Event header: */
763
sub->event = pjsip_event_hdr_create(sub->pool);
764
pj_strdup(sub->pool, &sub->event->event_type, event);
767
/* Check if another subscription has been registered to the dialog. In
768
* that case, just add ourselves to the subscription list, otherwise
769
* create and register a new subscription list.
771
if (pjsip_dlg_has_usage(dlg, &mod_evsub.mod)) {
772
dlgsub_head = (struct dlgsub*) dlg->mod_data[mod_evsub.mod.id];
773
dlgsub = PJ_POOL_ALLOC_T(sub->pool, struct dlgsub);
775
pj_list_push_back(dlgsub_head, dlgsub);
777
dlgsub_head = PJ_POOL_ALLOC_T(sub->pool, struct dlgsub);
778
dlgsub = PJ_POOL_ALLOC_T(sub->pool, struct dlgsub);
781
pj_list_init(dlgsub_head);
782
pj_list_push_back(dlgsub_head, dlgsub);
785
/* Register as dialog usage: */
787
status = pjsip_dlg_add_usage(dlg, &mod_evsub.mod, dlgsub_head);
788
if (status != PJ_SUCCESS) {
789
pjsip_dlg_dec_lock(dlg);
794
PJ_LOG(5,(sub->obj_name, "%s subscription created, using dialog %s",
795
(role==PJSIP_ROLE_UAC ? "UAC" : "UAS"),
799
pjsip_dlg_dec_lock(dlg);
807
* Create client subscription session.
809
PJ_DEF(pj_status_t) pjsip_evsub_create_uac( pjsip_dialog *dlg,
810
const pjsip_evsub_user *user_cb,
811
const pj_str_t *event,
813
pjsip_evsub **p_evsub)
818
PJ_ASSERT_RETURN(dlg && event && p_evsub, PJ_EINVAL);
820
pjsip_dlg_inc_lock(dlg);
821
status = evsub_create(dlg, PJSIP_UAC_ROLE, user_cb, event, option, &sub);
822
if (status != PJ_SUCCESS)
825
/* Add unique Id to Event header, only when PJSIP_EVSUB_NO_EVENT_ID
828
if ((option & PJSIP_EVSUB_NO_EVENT_ID) == 0) {
829
pj_create_unique_string(sub->pool, &sub->event->id_param);
832
/* Increment dlg session. */
833
pjsip_dlg_inc_session(sub->dlg, &mod_evsub.mod);
839
pjsip_dlg_dec_lock(dlg);
845
* Create server subscription session from incoming request.
847
PJ_DEF(pj_status_t) pjsip_evsub_create_uas( pjsip_dialog *dlg,
848
const pjsip_evsub_user *user_cb,
849
pjsip_rx_data *rdata,
851
pjsip_evsub **p_evsub)
854
pjsip_transaction *tsx;
855
pjsip_accept_hdr *accept_hdr;
856
pjsip_event_hdr *event_hdr;
857
pjsip_expires_hdr *expires_hdr;
860
/* Check arguments: */
861
PJ_ASSERT_RETURN(dlg && rdata && p_evsub, PJ_EINVAL);
863
/* MUST be request message: */
864
PJ_ASSERT_RETURN(rdata->msg_info.msg->type == PJSIP_REQUEST_MSG,
865
PJSIP_ENOTREQUESTMSG);
867
/* Transaction MUST have been created (in the dialog) */
868
tsx = pjsip_rdata_get_tsx(rdata);
869
PJ_ASSERT_RETURN(tsx != NULL, PJSIP_ENOTSX);
871
/* No subscription must have been attached to transaction */
872
PJ_ASSERT_RETURN(tsx->mod_data[mod_evsub.mod.id] == NULL,
875
/* Package MUST implement on_rx_refresh */
876
PJ_ASSERT_RETURN(user_cb->on_rx_refresh, PJ_EINVALIDOP);
878
/* Request MUST have "Event" header. We need the Event header to get
879
* the package name (don't want to add more arguments in the function).
881
event_hdr = (pjsip_event_hdr*)
882
pjsip_msg_find_hdr_by_names(rdata->msg_info.msg, &STR_EVENT,
884
if (event_hdr == NULL) {
885
return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_BAD_REQUEST);
888
/* Start locking the mutex: */
890
pjsip_dlg_inc_lock(dlg);
892
/* Create the session: */
894
status = evsub_create(dlg, PJSIP_UAS_ROLE, user_cb,
895
&event_hdr->event_type, option, &sub);
896
if (status != PJ_SUCCESS)
899
/* Just duplicate Event header from the request */
900
sub->event = (pjsip_event_hdr*) pjsip_hdr_clone(sub->pool, event_hdr);
902
/* Set the method: */
903
pjsip_method_copy(sub->pool, &sub->method,
904
&rdata->msg_info.msg->line.req.method);
906
/* Update expiration time according to client request: */
908
expires_hdr = (pjsip_expires_hdr*)
909
pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);
911
sub->expires->ivalue = expires_hdr->ivalue;
915
update_expires(sub, sub->expires->ivalue);
917
/* Update Accept header: */
919
accept_hdr = (pjsip_accept_hdr*)
920
pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_ACCEPT, NULL);
922
sub->accept = (pjsip_accept_hdr*)pjsip_hdr_clone(sub->pool,accept_hdr);
924
/* We can start the session: */
926
pjsip_dlg_inc_session(dlg, &mod_evsub.mod);
928
tsx->mod_data[mod_evsub.mod.id] = sub;
936
pjsip_dlg_dec_lock(dlg);
942
* Forcefully destroy subscription.
944
PJ_DEF(pj_status_t) pjsip_evsub_terminate( pjsip_evsub *sub,
947
PJ_ASSERT_RETURN(sub, PJ_EINVAL);
949
pjsip_dlg_inc_lock(sub->dlg);
951
/* I think it's pretty safe to disable this check.
953
if (sub->pending_tsx) {
954
pj_assert(!"Unable to terminate when there's pending tsx");
955
pjsip_dlg_dec_lock(sub->dlg);
956
return PJ_EINVALIDOP;
960
sub->call_cb = notify;
961
set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, NULL, NULL);
963
pjsip_dlg_dec_lock(sub->dlg);
968
* Get subscription state.
970
PJ_DEF(pjsip_evsub_state) pjsip_evsub_get_state(pjsip_evsub *sub)
978
PJ_DEF(const char*) pjsip_evsub_get_state_name(pjsip_evsub *sub)
980
return sub->state_str.ptr;
984
* Get termination reason.
986
PJ_DEF(const pj_str_t*) pjsip_evsub_get_termination_reason(pjsip_evsub *sub)
988
return &sub->term_reason;
992
* Initiate client subscription
994
PJ_DEF(pj_status_t) pjsip_evsub_initiate( pjsip_evsub *sub,
995
const pjsip_method *method,
997
pjsip_tx_data **p_tdata)
999
pjsip_tx_data *tdata;
1002
PJ_ASSERT_RETURN(sub!=NULL && p_tdata!=NULL, PJ_EINVAL);
1004
/* Use SUBSCRIBE if method is not specified */
1006
method = &pjsip_subscribe_method;
1008
pjsip_dlg_inc_lock(sub->dlg);
1010
/* Update method: */
1011
if (sub->state == PJSIP_EVSUB_STATE_NULL)
1012
pjsip_method_copy(sub->pool, &sub->method, method);
1014
status = pjsip_dlg_create_request( sub->dlg, method, -1, &tdata);
1015
if (status != PJ_SUCCESS)
1019
/* Add Event header: */
1020
pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)
1021
pjsip_hdr_shallow_clone(tdata->pool, sub->event));
1023
/* Update and add expires header: */
1025
sub->expires->ivalue = expires;
1026
pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)
1027
pjsip_hdr_shallow_clone(tdata->pool, sub->expires));
1029
/* Add Supported header (it's optional in RFC 3265, but some event package
1030
* RFC may bring this requirement to SHOULD strength - e.g. RFC 5373)
1033
const pjsip_hdr *hdr = pjsip_endpt_get_capability(sub->endpt,
1037
pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
1038
pjsip_hdr_shallow_clone(tdata->pool, hdr));
1042
/* Add Accept header: */
1043
pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)
1044
pjsip_hdr_shallow_clone(tdata->pool, sub->accept));
1047
/* Add Allow-Events header: */
1048
pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)
1049
pjsip_hdr_shallow_clone(tdata->pool,
1050
mod_evsub.allow_events_hdr));
1053
/* Add custom headers */
1055
const pjsip_hdr *hdr = sub->sub_hdr_list.next;
1056
while (hdr != &sub->sub_hdr_list) {
1057
pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)
1058
pjsip_hdr_shallow_clone(tdata->pool, hdr));
1069
pjsip_dlg_dec_lock(sub->dlg);
1075
* Add custom headers.
1077
PJ_DEF(pj_status_t) pjsip_evsub_add_header( pjsip_evsub *sub,
1078
const pjsip_hdr *hdr_list )
1080
const pjsip_hdr *hdr;
1082
PJ_ASSERT_RETURN(sub && hdr_list, PJ_EINVAL);
1084
hdr = hdr_list->next;
1085
while (hdr != hdr_list) {
1086
pj_list_push_back(&sub->sub_hdr_list, (pjsip_hdr*)
1087
pjsip_hdr_clone(sub->pool, hdr));
1096
* Accept incoming subscription request.
1098
PJ_DEF(pj_status_t) pjsip_evsub_accept( pjsip_evsub *sub,
1099
pjsip_rx_data *rdata,
1101
const pjsip_hdr *hdr_list )
1103
pjsip_tx_data *tdata;
1104
pjsip_transaction *tsx;
1107
/* Check arguments */
1108
PJ_ASSERT_RETURN(sub && rdata, PJ_EINVAL);
1110
/* Can only be for server subscription: */
1111
PJ_ASSERT_RETURN(sub->role == PJSIP_ROLE_UAS, PJ_EINVALIDOP);
1113
/* Only expect 2xx status code (for now) */
1114
PJ_ASSERT_RETURN(st_code/100 == 2, PJ_EINVALIDOP);
1116
/* Subscription MUST have been attached to the transaction.
1117
* Initial subscription request will be attached on evsub_create_uas(),
1118
* while subsequent requests will be attached in tsx_state()
1120
tsx = pjsip_rdata_get_tsx(rdata);
1121
PJ_ASSERT_RETURN(tsx->mod_data[mod_evsub.mod.id] != NULL,
1125
pjsip_dlg_inc_lock(sub->dlg);
1127
/* Create response: */
1128
status = pjsip_dlg_create_response( sub->dlg, rdata, st_code, NULL,
1130
if (status != PJ_SUCCESS)
1134
/* Add expires header: */
1135
pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)
1136
pjsip_hdr_shallow_clone(tdata->pool, sub->expires));
1138
/* Add additional header, if any. */
1140
const pjsip_hdr *hdr = hdr_list->next;
1141
while (hdr != hdr_list) {
1142
pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)
1143
pjsip_hdr_clone(tdata->pool, hdr));
1148
/* Send the response: */
1149
status = pjsip_dlg_send_response( sub->dlg, tsx, tdata );
1150
if (status != PJ_SUCCESS)
1153
/* Set UAS timeout timer, when status code is 2xx and state is not
1156
if (st_code/100 == 2 && sub->state != PJSIP_EVSUB_STATE_TERMINATED) {
1157
PJ_LOG(5,(sub->obj_name, "UAS timeout in %d seconds",
1158
sub->expires->ivalue));
1159
set_timer(sub, TIMER_TYPE_UAS_TIMEOUT, sub->expires->ivalue);
1164
pjsip_dlg_dec_lock(sub->dlg);
1170
* Create Subscription-State header based on current server subscription
1173
static pjsip_sub_state_hdr* sub_state_create( pj_pool_t *pool,
1175
pjsip_evsub_state state,
1176
const pj_str_t *state_str,
1177
const pj_str_t *reason )
1179
pjsip_sub_state_hdr *sub_state;
1180
pj_time_val now, delay;
1182
/* Get the remaining time before refresh is required */
1183
pj_gettimeofday(&now);
1184
delay = sub->refresh_time;
1185
PJ_TIME_VAL_SUB(delay, now);
1187
/* Create the Subscription-State header */
1188
sub_state = pjsip_sub_state_hdr_create(pool);
1190
/* Fill up the header */
1192
case PJSIP_EVSUB_STATE_NULL:
1193
case PJSIP_EVSUB_STATE_SENT:
1194
pj_assert(!"Invalid state!");
1195
/* Treat as pending */
1197
case PJSIP_EVSUB_STATE_ACCEPTED:
1198
case PJSIP_EVSUB_STATE_PENDING:
1199
sub_state->sub_state = STR_PENDING;
1200
sub_state->expires_param = delay.sec;
1203
case PJSIP_EVSUB_STATE_ACTIVE:
1204
sub_state->sub_state = STR_ACTIVE;
1205
sub_state->expires_param = delay.sec;
1208
case PJSIP_EVSUB_STATE_TERMINATED:
1209
sub_state->sub_state = STR_TERMINATED;
1211
pj_strdup(pool, &sub_state->reason_param, reason);
1214
case PJSIP_EVSUB_STATE_UNKNOWN:
1215
pj_assert(state_str != NULL);
1216
pj_strdup(pool, &sub_state->sub_state, state_str);
1224
* Create and send NOTIFY request.
1226
PJ_DEF(pj_status_t) pjsip_evsub_notify( pjsip_evsub *sub,
1227
pjsip_evsub_state state,
1228
const pj_str_t *state_str,
1229
const pj_str_t *reason,
1230
pjsip_tx_data **p_tdata)
1232
pjsip_tx_data *tdata;
1233
pjsip_sub_state_hdr *sub_state;
1236
/* Check arguments. */
1237
PJ_ASSERT_RETURN(sub!=NULL && p_tdata!=NULL, PJ_EINVAL);
1240
pjsip_dlg_inc_lock(sub->dlg);
1242
/* Create NOTIFY request */
1243
status = pjsip_dlg_create_request( sub->dlg, pjsip_get_notify_method(),
1245
if (status != PJ_SUCCESS)
1248
/* Add Event header */
1249
pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
1250
pjsip_hdr_shallow_clone(tdata->pool, sub->event));
1252
/* Add Subscription-State header */
1253
sub_state = sub_state_create(tdata->pool, sub, state, state_str,
1255
pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)sub_state);
1257
/* Add Allow-Events header */
1258
pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
1259
pjsip_hdr_shallow_clone(tdata->pool, mod_evsub.allow_events_hdr));
1261
/* Add Authentication headers. */
1262
pjsip_auth_clt_init_req( &sub->dlg->auth_sess, tdata );
1266
pj_strdup(sub->dlg->pool, &sub->term_reason, reason);
1268
/* Save destination state. */
1269
sub->dst_state = state;
1271
pj_strdup(sub->pool, &sub->dst_state_str, state_str);
1273
sub->dst_state_str.slen = 0;
1280
pjsip_dlg_dec_lock(sub->dlg);
1286
* Create NOTIFY to reflect current status.
1288
PJ_DEF(pj_status_t) pjsip_evsub_current_notify( pjsip_evsub *sub,
1289
pjsip_tx_data **p_tdata )
1291
return pjsip_evsub_notify( sub, sub->state, &sub->state_str,
1299
PJ_DEF(pj_status_t) pjsip_evsub_send_request( pjsip_evsub *sub,
1300
pjsip_tx_data *tdata)
1304
/* Must be request message. */
1305
PJ_ASSERT_RETURN(tdata->msg->type == PJSIP_REQUEST_MSG,
1306
PJSIP_ENOTREQUESTMSG);
1309
pjsip_dlg_inc_lock(sub->dlg);
1311
/* Send the request. */
1312
status = pjsip_dlg_send_request(sub->dlg, tdata, -1, NULL);
1313
if (status != PJ_SUCCESS)
1317
/* Special case for NOTIFY:
1318
* The new state was set in pjsip_evsub_notify(), but we apply the
1319
* new state now, when the request was actually sent.
1321
if (pjsip_method_cmp(&tdata->msg->line.req.method,
1322
&pjsip_notify_method)==0)
1324
PJ_ASSERT_ON_FAIL( sub->dst_state!=PJSIP_EVSUB_STATE_NULL,
1327
set_state(sub, sub->dst_state,
1328
(sub->dst_state_str.slen ? &sub->dst_state_str : NULL),
1331
sub->dst_state = PJSIP_EVSUB_STATE_NULL;
1332
sub->dst_state_str.slen = 0;
1338
pjsip_dlg_dec_lock(sub->dlg);
1343
/* Callback to be called to terminate transaction. */
1344
static void terminate_timer_cb(pj_timer_heap_t *timer_heap,
1345
struct pj_timer_entry *entry)
1348
pjsip_transaction *tsx;
1350
PJ_UNUSED_ARG(timer_heap);
1352
key = (pj_str_t*)entry->user_data;
1353
tsx = pjsip_tsx_layer_find_tsx(key, PJ_FALSE);
1354
/* Chance of race condition here */
1356
pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_UPDATED);
1362
* Attach subscription session to newly created transaction, if appropriate.
1364
static pjsip_evsub *on_new_transaction( pjsip_transaction *tsx,
1368
* Newly created transaction will not have subscription session
1369
* attached to it. Find the subscription session from the dialog,
1370
* by matching the Event header.
1373
pjsip_event_hdr *event_hdr;
1375
struct dlgsub *dlgsub_head, *dlgsub;
1378
dlg = pjsip_tsx_get_dlg(tsx);
1380
pj_assert(!"Transaction should have a dialog instance!");
1385
switch (event->body.tsx_state.type) {
1386
case PJSIP_EVENT_RX_MSG:
1387
msg = event->body.tsx_state.src.rdata->msg_info.msg;
1389
case PJSIP_EVENT_TX_MSG:
1390
msg = event->body.tsx_state.src.tdata->msg;
1393
if (tsx->role == PJSIP_ROLE_UAC)
1394
msg = tsx->last_tx->msg;
1402
// this transaction can be other transaction in the dialog.
1403
// The assertion below probably only valid for dialog that
1404
// only has one event subscription usage.
1405
//pj_assert(!"First transaction event is not TX or RX!");
1409
event_hdr = (pjsip_event_hdr*)
1410
pjsip_msg_find_hdr_by_names(msg, &STR_EVENT,
1411
&STR_EVENT_S, NULL);
1413
/* Not subscription related message */
1417
/* Find the subscription in the dialog, based on the content
1421
dlgsub_head = (struct dlgsub*) dlg->mod_data[mod_evsub.mod.id];
1422
if (dlgsub_head == NULL) {
1423
dlgsub_head = PJ_POOL_ALLOC_T(dlg->pool, struct dlgsub);
1424
pj_list_init(dlgsub_head);
1425
dlg->mod_data[mod_evsub.mod.id] = dlgsub_head;
1427
dlgsub = dlgsub_head->next;
1429
while (dlgsub != dlgsub_head) {
1431
if (pj_stricmp(&dlgsub->sub->event->event_type,
1432
&event_hdr->event_type)==0)
1434
/* Event type matched.
1435
* Check if event ID matched too.
1437
if (pj_strcmp(&dlgsub->sub->event->id_param,
1438
&event_hdr->id_param)==0)
1440
/* Skip this subscription if it has no event ID and has been
1441
* terminated (see ticket #1647).
1443
if ((dlgsub->sub->option & PJSIP_EVSUB_NO_EVENT_ID) &&
1444
(pjsip_evsub_get_state(dlgsub->sub)==
1445
PJSIP_EVSUB_STATE_TERMINATED))
1447
dlgsub = dlgsub->next;
1455
* Otherwise if it is an UAC subscription, AND
1456
* PJSIP_EVSUB_NO_EVENT_ID flag is set, AND
1457
* the session's event id is NULL, AND
1458
* the incoming request is NOTIFY with event ID, then
1459
* we consider it as a match, and update the
1460
* session's event id.
1462
else if (dlgsub->sub->role == PJSIP_ROLE_UAC &&
1463
(dlgsub->sub->option & PJSIP_EVSUB_NO_EVENT_ID)!=0 &&
1464
dlgsub->sub->event->id_param.slen==0 &&
1465
!pjsip_method_cmp(&tsx->method, &pjsip_notify_method))
1467
/* Update session's event id. */
1468
pj_strdup(dlgsub->sub->pool,
1469
&dlgsub->sub->event->id_param,
1470
&event_hdr->id_param);
1478
dlgsub = dlgsub->next;
1482
* the second condition is for http://trac.pjsip.org/repos/ticket/911
1484
if (dlgsub == dlgsub_head ||
1486
pjsip_evsub_get_state(dlgsub->sub)==PJSIP_EVSUB_STATE_TERMINATED))
1488
const char *reason_msg =
1489
(dlgsub == dlgsub_head ? "Subscription Does Not Exist" :
1490
"Subscription already terminated");
1492
/* This could be incoming request to create new subscription */
1493
PJ_LOG(4,(THIS_FILE,
1494
"%s for %.*s, event=%.*s;id=%.*s",
1496
(int)tsx->method.name.slen,
1497
tsx->method.name.ptr,
1498
(int)event_hdr->event_type.slen,
1499
event_hdr->event_type.ptr,
1500
(int)event_hdr->id_param.slen,
1501
event_hdr->id_param.ptr));
1503
/* If this is an incoming NOTIFY, reject with 481 */
1504
if (tsx->state == PJSIP_TSX_STATE_TRYING &&
1505
pjsip_method_cmp(&tsx->method, &pjsip_notify_method)==0)
1508
pjsip_tx_data *tdata;
1511
pj_cstr(&reason, reason_msg);
1512
status = pjsip_dlg_create_response(dlg,
1513
event->body.tsx_state.src.rdata,
1516
if (status == PJ_SUCCESS) {
1517
status = pjsip_dlg_send_response(dlg, tsx, tdata);
1526
/* Attach session to the transaction */
1527
tsx->mod_data[mod_evsub.mod.id] = sub;
1530
/* Special case for outgoing/UAC SUBSCRIBE/REFER transaction.
1531
* We can only have one pending UAC SUBSCRIBE/REFER, so if another
1532
* transaction is started while previous one still alive, terminate
1536
* - subscribe sent to destination that doesn't exist, transaction
1537
* is still retransmitting request, then unsubscribe is sent.
1539
if (tsx->role == PJSIP_ROLE_UAC &&
1540
tsx->state == PJSIP_TSX_STATE_CALLING &&
1541
(pjsip_method_cmp(&tsx->method, &sub->method) == 0 ||
1542
pjsip_method_cmp(&tsx->method, &pjsip_subscribe_method) == 0))
1545
if (sub->pending_sub &&
1546
sub->pending_sub->state < PJSIP_TSX_STATE_COMPLETED)
1548
pj_timer_entry *timer;
1550
pj_time_val timeout = {0, 0};
1552
PJ_LOG(4,(sub->obj_name,
1553
"Cancelling pending subscription request"));
1555
/* By convention, we use 490 (Request Updated) status code.
1556
* When transaction handler (below) see this status code, it
1557
* will ignore the transaction.
1559
/* This unfortunately may cause deadlock, because at the moment
1560
* we are holding dialog's mutex. If a response to this
1561
* transaction is in progress in another thread, that thread
1562
* will deadlock when trying to acquire dialog mutex, because
1563
* it is holding the transaction mutex.
1565
* So the solution is to register timer to kill this transaction.
1567
//pjsip_tsx_terminate(sub->pending_sub, PJSIP_SC_REQUEST_UPDATED);
1568
timer = PJ_POOL_ZALLOC_T(dlg->pool, pj_timer_entry);
1569
key = PJ_POOL_ALLOC_T(dlg->pool, pj_str_t);
1570
pj_strdup(dlg->pool, key, &sub->pending_sub->transaction_key);
1571
timer->cb = &terminate_timer_cb;
1572
timer->user_data = key;
1574
pjsip_endpt_schedule_timer(dlg->endpt, timer, &timeout);
1577
sub->pending_sub = tsx;
1586
* Create response, adding custome headers and msg body.
1588
static pj_status_t create_response( pjsip_evsub *sub,
1589
pjsip_rx_data *rdata,
1591
const pj_str_t *st_text,
1592
const pjsip_hdr *res_hdr,
1593
const pjsip_msg_body *body,
1594
pjsip_tx_data **p_tdata)
1596
pjsip_tx_data *tdata;
1600
status = pjsip_dlg_create_response(sub->dlg, rdata,
1601
st_code, st_text, &tdata);
1602
if (status != PJ_SUCCESS)
1607
/* Add response headers. */
1608
hdr = res_hdr->next;
1609
while (hdr != res_hdr) {
1610
pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)
1611
pjsip_hdr_clone(tdata->pool, hdr));
1615
/* Add msg body, if any */
1617
tdata->msg->body = pjsip_msg_body_clone(tdata->pool, body);
1618
if (tdata->msg->body == NULL) {
1620
PJ_LOG(4,(THIS_FILE, "Error: unable to clone msg body"));
1631
* Get subscription state from the value of Subscription-State header.
1633
static void get_hdr_state( pjsip_sub_state_hdr *sub_state,
1634
pjsip_evsub_state *state,
1635
pj_str_t **state_str )
1637
if (pj_stricmp(&sub_state->sub_state, &STR_TERMINATED)==0) {
1639
*state = PJSIP_EVSUB_STATE_TERMINATED;
1642
} else if (pj_stricmp(&sub_state->sub_state, &STR_ACTIVE)==0) {
1644
*state = PJSIP_EVSUB_STATE_ACTIVE;
1647
} else if (pj_stricmp(&sub_state->sub_state, &STR_PENDING)==0) {
1649
*state = PJSIP_EVSUB_STATE_PENDING;
1654
*state = PJSIP_EVSUB_STATE_UNKNOWN;
1655
*state_str = &sub_state->sub_state;
1661
* Transaction event processing by UAC, after subscription is sent.
1663
static void on_tsx_state_uac( pjsip_evsub *sub, pjsip_transaction *tsx,
1664
pjsip_event *event )
1667
if (pjsip_method_cmp(&tsx->method, &sub->method)==0 ||
1668
pjsip_method_cmp(&tsx->method, &pjsip_subscribe_method)==0)
1671
/* Received response to outgoing request that establishes/refresh
1675
/* First time initial request is sent. */
1676
if (sub->state == PJSIP_EVSUB_STATE_NULL &&
1677
tsx->state == PJSIP_TSX_STATE_CALLING)
1679
set_state(sub, PJSIP_EVSUB_STATE_SENT, NULL, event, NULL);
1683
/* Only interested in final response */
1684
if (tsx->state != PJSIP_TSX_STATE_COMPLETED &&
1685
tsx->state != PJSIP_TSX_STATE_TERMINATED)
1690
/* Clear pending subscription */
1691
if (tsx == sub->pending_sub) {
1692
sub->pending_sub = NULL;
1693
} else if (sub->pending_sub != NULL) {
1694
/* This SUBSCRIBE transaction has been "renewed" with another
1695
* SUBSCRIBE, so we can just ignore this. For example, user
1696
* sent SUBSCRIBE followed immediately with UN-SUBSCRIBE.
1701
/* Handle authentication. */
1702
if (tsx->status_code==401 || tsx->status_code==407) {
1703
pjsip_tx_data *tdata;
1706
if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
1707
/* Previously failed transaction has terminated */
1711
status = pjsip_auth_clt_reinit_req(&sub->dlg->auth_sess,
1712
event->body.tsx_state.src.rdata,
1713
tsx->last_tx, &tdata);
1714
if (status == PJ_SUCCESS)
1715
status = pjsip_dlg_send_request(sub->dlg, tdata, -1, NULL);
1717
if (status != PJ_SUCCESS) {
1718
/* Authentication failed! */
1719
set_state(sub, PJSIP_EVSUB_STATE_TERMINATED,
1720
NULL, event, &tsx->status_text);
1727
if (tsx->status_code/100 == 2) {
1729
/* Successfull SUBSCRIBE request!
1731
* - response to initial SUBSCRIBE request
1732
* - response to subsequent refresh
1733
* - response to unsubscription
1736
if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
1737
/* Ignore; this transaction has been processed before */
1741
/* Update UAC refresh time, if response contains Expires header,
1742
* only when we're not unsubscribing.
1744
if (sub->expires->ivalue != 0) {
1746
pjsip_expires_hdr *expires;
1748
msg = event->body.tsx_state.src.rdata->msg_info.msg;
1749
expires = (pjsip_expires_hdr*)
1750
pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL);
1752
sub->expires->ivalue = expires->ivalue;
1757
update_expires(sub, sub->expires->ivalue);
1759
/* Start UAC refresh timer, only when we're not unsubscribing */
1760
if (sub->expires->ivalue != 0) {
1761
unsigned timeout = (sub->expires->ivalue > TIME_UAC_REFRESH) ?
1762
sub->expires->ivalue - TIME_UAC_REFRESH : sub->expires->ivalue;
1764
/* Reduce timeout by about 1 - 10 secs (randomized) */
1766
timeout += -10 + (pj_rand() % 10);
1768
PJ_LOG(5,(sub->obj_name, "Will refresh in %d seconds",
1770
set_timer(sub, TIMER_TYPE_UAC_REFRESH, timeout);
1773
/* Otherwise set timer to terminate client subscription when
1774
* NOTIFY to end subscription is not received.
1776
set_timer(sub, TIMER_TYPE_UAC_TERMINATE, TIME_UAC_TERMINATE);
1779
/* Set state, if necessary */
1780
pj_assert(sub->state != PJSIP_EVSUB_STATE_NULL);
1781
if (sub->state == PJSIP_EVSUB_STATE_SENT) {
1782
set_state(sub, PJSIP_EVSUB_STATE_ACCEPTED, NULL, event, NULL);
1787
/* Failed SUBSCRIBE request!
1789
* The RFC 3265 says that if outgoing SUBSCRIBE fails with status
1790
* other than 481, the subscription is still considered valid for
1791
* the duration of the last Expires.
1793
* Since we send refresh about 5 seconds (TIME_UAC_REFRESH) before
1794
* expiration, theoritically the expiration is still valid for the
1795
* next 5 seconds even when we receive non-481 failed response.
1797
* Ah, what the heck!
1799
* Just terminate now!
1803
if (sub->state == PJSIP_EVSUB_STATE_TERMINATED) {
1804
/* Ignore, has been handled before */
1808
/* Ignore 490 (Request Updated) status.
1809
* This happens when application sends SUBSCRIBE/REFER while
1810
* another one is still in progress.
1812
if (tsx->status_code == PJSIP_SC_REQUEST_UPDATED) {
1816
/* Set state to TERMINATED */
1817
set_state(sub, PJSIP_EVSUB_STATE_TERMINATED,
1818
NULL, event, &tsx->status_text);
1822
} else if (pjsip_method_cmp(&tsx->method, &pjsip_notify_method) == 0) {
1825
* This can be the result of:
1826
* - Initial subscription response
1827
* - UAS updating the resource info.
1828
* - Unsubscription response.
1831
pj_str_t *st_text = NULL;
1833
pjsip_msg_body *body = NULL;
1835
pjsip_rx_data *rdata;
1837
pjsip_sub_state_hdr *sub_state;
1839
pjsip_evsub_state new_state;
1840
pj_str_t *new_state_str;
1842
pjsip_tx_data *tdata;
1845
/* Only want to handle initial NOTIFY receive event. */
1846
if (tsx->state != PJSIP_TSX_STATE_TRYING)
1850
rdata = event->body.tsx_state.src.rdata;
1851
msg = rdata->msg_info.msg;
1853
pj_list_init(&res_hdr);
1855
/* Get subscription state header. */
1856
sub_state = (pjsip_sub_state_hdr*)
1857
pjsip_msg_find_hdr_by_name(msg, &STR_SUB_STATE, NULL);
1858
if (sub_state == NULL) {
1860
pjsip_warning_hdr *warn_hdr;
1861
pj_str_t warn_text = { "Missing Subscription-State header", 33};
1863
/* Bad request! Add warning header. */
1864
st_code = PJSIP_SC_BAD_REQUEST;
1865
warn_hdr = pjsip_warning_hdr_create(rdata->tp_info.pool, 399,
1866
pjsip_endpt_name(sub->endpt),
1868
pj_list_push_back(&res_hdr, warn_hdr);
1871
/* Call application registered callback to handle incoming NOTIFY,
1874
if (st_code==200 && sub->user.on_rx_notify && sub->call_cb) {
1875
(*sub->user.on_rx_notify)(sub, rdata, &st_code, &st_text,
1878
/* Application MUST specify final response! */
1879
PJ_ASSERT_ON_FAIL(st_code >= 200, {st_code=200; });
1881
/* Must be a valid status code */
1882
PJ_ASSERT_ON_FAIL(st_code <= 699, {st_code=500; });
1886
/* If non-2xx should be returned, then send the response.
1887
* No need to update server subscription state.
1889
if (st_code >= 300) {
1890
status = create_response(sub, rdata, st_code, st_text, &res_hdr,
1892
if (status == PJ_SUCCESS) {
1893
status = pjsip_dlg_send_response(sub->dlg, tsx, tdata);
1896
/* Start timer to terminate subscription, just in case server
1897
* is not able to generate NOTIFY to our response.
1899
if (status == PJ_SUCCESS) {
1900
unsigned timeout = TIME_UAC_WAIT_NOTIFY;
1901
set_timer(sub, TIMER_TYPE_UAC_WAIT_NOTIFY, timeout);
1903
char errmsg[PJ_ERR_MSG_SIZE];
1906
reason = pj_strerror(status, errmsg, sizeof(errmsg));
1907
set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, NULL,
1914
/* Update expiration from the value of expires param in
1915
* Subscription-State header, but ONLY when subscription state
1916
* is "active" or "pending", AND the header contains expires param.
1918
if (sub->expires->ivalue != 0 &&
1919
sub_state->expires_param >= 0 &&
1920
(pj_stricmp(&sub_state->sub_state, &STR_ACTIVE)==0 ||
1921
pj_stricmp(&sub_state->sub_state, &STR_PENDING)==0))
1923
int next_refresh = sub_state->expires_param;
1926
update_expires(sub, next_refresh);
1928
/* Start UAC refresh timer, only when we're not unsubscribing */
1929
timeout = (next_refresh > TIME_UAC_REFRESH) ?
1930
next_refresh - TIME_UAC_REFRESH : next_refresh;
1932
PJ_LOG(5,(sub->obj_name, "Will refresh in %d seconds", timeout));
1933
set_timer(sub, TIMER_TYPE_UAC_REFRESH, timeout);
1936
/* Find out the state */
1937
get_hdr_state(sub_state, &new_state, &new_state_str);
1939
/* Send response. */
1940
status = create_response(sub, rdata, st_code, st_text, &res_hdr,
1942
if (status == PJ_SUCCESS)
1943
status = pjsip_dlg_send_response(sub->dlg, tsx, tdata);
1946
if (status == PJ_SUCCESS) {
1947
set_state(sub, new_state, new_state_str, event,
1948
&sub_state->reason_param);
1950
char errmsg[PJ_ERR_MSG_SIZE];
1953
reason = pj_strerror(status, errmsg, sizeof(errmsg));
1954
set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, event,
1962
* Unexpected method!
1964
PJ_LOG(4,(sub->obj_name, "Unexpected transaction method %.*s",
1965
(int)tsx->method.name.slen, tsx->method.name.ptr));
1971
* Transaction event processing by UAS, after subscription is accepted.
1973
static void on_tsx_state_uas( pjsip_evsub *sub, pjsip_transaction *tsx,
1977
if (pjsip_method_cmp(&tsx->method, &sub->method) == 0 ||
1978
pjsip_method_cmp(&tsx->method, &pjsip_subscribe_method) == 0)
1982
* Incoming request (e.g. SUBSCRIBE or REFER) to refresh subsciption.
1985
pjsip_rx_data *rdata;
1986
pjsip_event_hdr *event_hdr;
1987
pjsip_expires_hdr *expires;
1989
pjsip_tx_data *tdata;
1991
pj_str_t *st_text = NULL;
1993
pjsip_msg_body *body = NULL;
1994
pjsip_evsub_state old_state;
1995
pj_str_t old_state_str;
1996
pj_str_t reason = { NULL, 0 };
2000
/* Only wants to handle the first event when the request is
2003
if (tsx->state != PJSIP_TSX_STATE_TRYING)
2006
rdata = event->body.tsx_state.src.rdata;
2007
msg = rdata->msg_info.msg;
2009
/* Set expiration time based on client request (in Expires header),
2010
* or package default expiration time.
2012
event_hdr = (pjsip_event_hdr*)
2013
pjsip_msg_find_hdr_by_names(msg, &STR_EVENT,
2015
expires = (pjsip_expires_hdr*)
2016
pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL);
2017
if (event_hdr && expires) {
2018
struct evpkg *evpkg;
2020
evpkg = find_pkg(&event_hdr->event_type);
2022
if (expires->ivalue < (pj_int32_t)evpkg->pkg_expires)
2023
sub->expires->ivalue = expires->ivalue;
2025
sub->expires->ivalue = evpkg->pkg_expires;
2029
/* Update time (before calling on_rx_refresh, since application
2032
update_expires(sub, sub->expires->ivalue);
2036
* If application respond with non-2xx, revert to old state.
2038
old_state = sub->state;
2039
old_state_str = sub->state_str;
2041
if (sub->expires->ivalue == 0) {
2042
sub->state = PJSIP_EVSUB_STATE_TERMINATED;
2043
sub->state_str = evsub_state_names[sub->state];
2044
} else if (sub->state == PJSIP_EVSUB_STATE_NULL) {
2045
sub->state = PJSIP_EVSUB_STATE_ACCEPTED;
2046
sub->state_str = evsub_state_names[sub->state];
2049
/* Call application's on_rx_refresh, just in case it wants to send
2050
* response other than 200 (OK)
2052
pj_list_init(&res_hdr);
2054
if (sub->user.on_rx_refresh && sub->call_cb) {
2055
(*sub->user.on_rx_refresh)(sub, rdata, &st_code, &st_text,
2059
/* Application MUST specify final response! */
2060
PJ_ASSERT_ON_FAIL(st_code >= 200, {st_code=200; });
2062
/* Must be a valid status code */
2063
PJ_ASSERT_ON_FAIL(st_code <= 699, {st_code=500; });
2066
/* Create and send response */
2067
status = create_response(sub, rdata, st_code, st_text, &res_hdr,
2069
if (status == PJ_SUCCESS) {
2070
/* Add expires header: */
2071
pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)
2072
pjsip_hdr_shallow_clone(tdata->pool,
2076
status = pjsip_dlg_send_response(sub->dlg, tsx, tdata);
2079
/* Update state or revert state */
2080
if (st_code/100==2) {
2082
if (sub->expires->ivalue == 0) {
2083
set_state(sub, sub->state, NULL, event, &reason);
2084
} else if (sub->state == PJSIP_EVSUB_STATE_NULL) {
2085
set_state(sub, sub->state, NULL, event, &reason);
2088
/* Set UAS timeout timer, when state is not terminated. */
2089
if (sub->state != PJSIP_EVSUB_STATE_TERMINATED) {
2090
PJ_LOG(5,(sub->obj_name, "UAS timeout in %d seconds",
2091
sub->expires->ivalue));
2092
set_timer(sub, TIMER_TYPE_UAS_TIMEOUT,
2093
sub->expires->ivalue);
2097
sub->state = old_state;
2098
sub->state_str = old_state_str;
2102
} else if (pjsip_method_cmp(&tsx->method, &pjsip_notify_method)==0) {
2104
/* Handle authentication */
2105
if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
2106
(tsx->status_code==401 || tsx->status_code==407))
2108
pjsip_rx_data *rdata = event->body.tsx_state.src.rdata;
2109
pjsip_tx_data *tdata;
2112
status = pjsip_auth_clt_reinit_req( &sub->dlg->auth_sess, rdata,
2113
tsx->last_tx, &tdata);
2114
if (status == PJ_SUCCESS)
2115
status = pjsip_dlg_send_request( sub->dlg, tdata, -1, NULL );
2117
if (status != PJ_SUCCESS) {
2118
/* Can't authenticate. Terminate session (?) */
2119
set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, NULL,
2126
* Terminate event usage if we receive 481, 408, and 7 class
2129
if (sub->state != PJSIP_EVSUB_STATE_TERMINATED &&
2130
(tsx->status_code==481 || tsx->status_code==408 ||
2131
tsx->status_code/100 == 7))
2133
set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, event,
2141
* Unexpected method!
2143
PJ_LOG(4,(sub->obj_name, "Unexpected transaction method %.*s",
2144
(int)tsx->method.name.slen, tsx->method.name.ptr));
2151
* Notification when transaction state has changed!
2153
static void mod_evsub_on_tsx_state(pjsip_transaction *tsx, pjsip_event *event)
2155
pjsip_evsub *sub = pjsip_tsx_get_evsub(tsx);
2158
sub = on_new_transaction(tsx, event);
2164
/* Call on_tsx_state callback, if any. */
2165
if (sub->user.on_tsx_state && sub->call_cb)
2166
(*sub->user.on_tsx_state)(sub, tsx, event);
2169
/* Process the event: */
2171
if (sub->role == PJSIP_ROLE_UAC) {
2172
on_tsx_state_uac(sub, tsx, event);
2174
on_tsx_state_uas(sub, tsx, event);
2178
/* Check transaction TERMINATE event */
2179
if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
2183
if (sub->state == PJSIP_EVSUB_STATE_TERMINATED &&
2184
sub->pending_tsx == 0)