1 /* $Id$ */
2 /*
3 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5 *
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.
10 *
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.
15 *
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
19 */
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>
31 #include <pj/guid.h>
32 #include <pj/log.h>
33 #include <pj/os.h>
34 #include <pj/pool.h>
35 #include <pj/rand.h>
36 #include <pj/string.h>
37
38
39 #define THIS_FILE "evsub.c"
40
41 /*
42 * Global constant
43 */
44
45 /* Let's define this enum, so that it'll trigger compilation error
46 * when somebody define the same enum in sip_msg.h
47 */
48 enum
49 {
50 PJSIP_SUBSCRIBE_METHOD = PJSIP_OTHER_METHOD,
51 PJSIP_NOTIFY_METHOD = PJSIP_OTHER_METHOD
52 };
53
54 PJ_DEF_DATA(const pjsip_method) pjsip_subscribe_method =
55 {
56 (pjsip_method_e) PJSIP_SUBSCRIBE_METHOD,
57 { "SUBSCRIBE", 9 }
58 };
59
60 PJ_DEF_DATA(const pjsip_method) pjsip_notify_method =
61 {
62 (pjsip_method_e) PJSIP_NOTIFY_METHOD,
63 { "NOTIFY", 6 }
64 };
65
66 /**
67 * SUBSCRIBE method constant.
68 */
pjsip_get_subscribe_method()69 PJ_DEF(const pjsip_method*) pjsip_get_subscribe_method()
70 {
71 return &pjsip_subscribe_method;
72 }
73
74 /**
75 * NOTIFY method constant.
76 */
pjsip_get_notify_method()77 PJ_DEF(const pjsip_method*) pjsip_get_notify_method()
78 {
79 return &pjsip_notify_method;
80 }
81
82
83 /*
84 * Static prototypes.
85 */
86 static void mod_evsub_on_tsx_state(pjsip_transaction*, pjsip_event*);
87 static pj_status_t mod_evsub_unload(void);
88
89
90 /*
91 * State names.
92 */
93 static pj_str_t evsub_state_names[] =
94 {
95 { "NULL", 4},
96 { "SENT", 4},
97 { "ACCEPTED", 8},
98 { "PENDING", 7},
99 { "ACTIVE", 6},
100 { "TERMINATED", 10},
101 { "UNKNOWN", 7}
102 };
103
104 /*
105 * Timer constants.
106 */
107
108 /* Number of seconds to send SUBSCRIBE before the actual expiration */
109 #define TIME_UAC_REFRESH PJSIP_EVSUB_TIME_UAC_REFRESH
110
111 /* Time to wait for the final NOTIFY after sending unsubscription */
112 #define TIME_UAC_TERMINATE PJSIP_EVSUB_TIME_UAC_TERMINATE
113
114 /* If client responds NOTIFY with non-2xx final response (such as 401),
115 * wait for this seconds for further NOTIFY, otherwise client will
116 * unsubscribe
117 */
118 #define TIME_UAC_WAIT_NOTIFY PJSIP_EVSUB_TIME_UAC_WAIT_NOTIFY
119
120
121 /*
122 * Timer id
123 */
124 enum timer_id
125 {
126 /* No timer. */
127 TIMER_TYPE_NONE,
128
129 /* Time to refresh client subscription.
130 * The action is to call on_client_refresh() callback.
131 */
132 TIMER_TYPE_UAC_REFRESH,
133
134 /* UAS timeout after to subscription refresh.
135 * The action is to call on_server_timeout() callback.
136 */
137 TIMER_TYPE_UAS_TIMEOUT,
138
139 /* UAC waiting for final NOTIFY after unsubscribing
140 * The action is to terminate.
141 */
142 TIMER_TYPE_UAC_TERMINATE,
143
144 /* UAC waiting for further NOTIFY after sending non-2xx response to
145 * NOTIFY. The action is to unsubscribe.
146 */
147 TIMER_TYPE_UAC_WAIT_NOTIFY,
148
149 /* Max nb of timer types. */
150 TIMER_TYPE_MAX
151 };
152
153 static const char *timer_names[] =
154 {
155 "None",
156 "UAC_REFRESH",
157 "UAS_TIMEOUT",
158 "UAC_TERMINATE",
159 "UAC_WAIT_NOTIFY",
160 "INVALID_TIMER"
161 };
162
163 /*
164 * Definition of event package.
165 */
166 struct evpkg
167 {
168 PJ_DECL_LIST_MEMBER(struct evpkg);
169
170 pj_str_t pkg_name;
171 pjsip_module *pkg_mod;
172 unsigned pkg_expires;
173 pjsip_accept_hdr *pkg_accept;
174 };
175
176
177 /*
178 * Event subscription module (mod-evsub).
179 */
180 static struct mod_evsub
181 {
182 pjsip_module mod;
183 pj_pool_t *pool;
184 pjsip_endpoint *endpt;
185 struct evpkg pkg_list;
186 pjsip_allow_events_hdr *allow_events_hdr;
187
188 } mod_evsub =
189 {
190 {
191 NULL, NULL, /* prev, next. */
192 { "mod-evsub", 9 }, /* Name. */
193 -1, /* Id */
194 PJSIP_MOD_PRIORITY_DIALOG_USAGE, /* Priority */
195 NULL, /* load() */
196 NULL, /* start() */
197 NULL, /* stop() */
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() */
204 }
205 };
206
207
208 /*
209 * Event subscription session.
210 */
211 struct pjsip_evsub
212 {
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. */
232
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. */
237 pj_timer_entry *pending_sub_timer; /**< Stop pending sub timer. */
238 pj_grp_lock_t *grp_lock; /* Session group lock */
239
240 void *mod_data[PJSIP_MAX_MODULE]; /**< Module data. */
241 };
242
243
244 /*
245 * This is the structure that will be "attached" to dialog.
246 * The purpose is to allow multiple subscriptions inside a dialog.
247 */
248 struct dlgsub
249 {
250 PJ_DECL_LIST_MEMBER(struct dlgsub);
251 pjsip_evsub *sub;
252 };
253
254
255 /* Static vars. */
256 static const pj_str_t STR_EVENT = { "Event", 5 };
257 static const pj_str_t STR_EVENT_S = { "o", 1 };
258 static const pj_str_t STR_SUB_STATE = { "Subscription-State", 18 };
259 static const pj_str_t STR_TERMINATED = { "terminated", 10 };
260 static const pj_str_t STR_ACTIVE = { "active", 6 };
261 static const pj_str_t STR_PENDING = { "pending", 7 };
262 static const pj_str_t STR_TIMEOUT = { "timeout", 7};
263 static const pj_str_t STR_RETRY_AFTER = { "Retry-After", 11 };
264
265
266 /*
267 * On unload module.
268 */
mod_evsub_unload(void)269 static pj_status_t mod_evsub_unload(void)
270 {
271 pjsip_endpt_release_pool(mod_evsub.endpt, mod_evsub.pool);
272 mod_evsub.pool = NULL;
273
274 return PJ_SUCCESS;
275 }
276
277 /* Proto for pjsipsimple_strerror().
278 * Defined in errno.c
279 */
280 PJ_DECL(pj_str_t) pjsipsimple_strerror( pj_status_t statcode,
281 char *buf, pj_size_t bufsize );
282
283 /*
284 * Init and register module.
285 */
pjsip_evsub_init_module(pjsip_endpoint * endpt)286 PJ_DEF(pj_status_t) pjsip_evsub_init_module(pjsip_endpoint *endpt)
287 {
288 pj_status_t status;
289 pj_str_t method_tags[] = {
290 { "SUBSCRIBE", 9},
291 { "NOTIFY", 6}
292 };
293
294 status = pj_register_strerror(PJSIP_SIMPLE_ERRNO_START,
295 PJ_ERRNO_SPACE_SIZE,
296 &pjsipsimple_strerror);
297 pj_assert(status == PJ_SUCCESS);
298
299 PJ_ASSERT_RETURN(endpt != NULL, PJ_EINVAL);
300 PJ_ASSERT_RETURN(mod_evsub.mod.id == -1, PJ_EINVALIDOP);
301
302 /* Keep endpoint for future reference: */
303 mod_evsub.endpt = endpt;
304
305 /* Init event package list: */
306 pj_list_init(&mod_evsub.pkg_list);
307
308 /* Create pool: */
309 mod_evsub.pool = pjsip_endpt_create_pool(endpt, "evsub",
310 PJSIP_POOL_EVSUB_LEN,
311 PJSIP_POOL_EVSUB_INC);
312 if (!mod_evsub.pool)
313 return PJ_ENOMEM;
314
315 /* Register module: */
316 status = pjsip_endpt_register_module(endpt, &mod_evsub.mod);
317 if (status != PJ_SUCCESS)
318 goto on_error;
319
320 /* Create Allow-Events header: */
321 mod_evsub.allow_events_hdr = pjsip_allow_events_hdr_create(mod_evsub.pool);
322
323 /* Register SIP-event specific headers parser: */
324 pjsip_evsub_init_parser();
325
326 /* Register new methods SUBSCRIBE and NOTIFY in Allow-ed header */
327 pjsip_endpt_add_capability(endpt, &mod_evsub.mod, PJSIP_H_ALLOW, NULL,
328 2, method_tags);
329
330 /* Done. */
331 return PJ_SUCCESS;
332
333 on_error:
334 if (mod_evsub.pool) {
335 pjsip_endpt_release_pool(endpt, mod_evsub.pool);
336 mod_evsub.pool = NULL;
337 }
338 mod_evsub.endpt = NULL;
339 return status;
340 }
341
342
343 /*
344 * Get the instance of the module.
345 */
pjsip_evsub_instance(void)346 PJ_DEF(pjsip_module*) pjsip_evsub_instance(void)
347 {
348 PJ_ASSERT_RETURN(mod_evsub.mod.id != -1, NULL);
349
350 return &mod_evsub.mod;
351 }
352
353
354 /*
355 * Get the event subscription instance in the transaction.
356 */
pjsip_tsx_get_evsub(pjsip_transaction * tsx)357 PJ_DEF(pjsip_evsub*) pjsip_tsx_get_evsub(pjsip_transaction *tsx)
358 {
359 return (pjsip_evsub*) tsx->mod_data[mod_evsub.mod.id];
360 }
361
362
363 /*
364 * Set event subscription's module data.
365 */
pjsip_evsub_set_mod_data(pjsip_evsub * sub,unsigned mod_id,void * data)366 PJ_DEF(void) pjsip_evsub_set_mod_data( pjsip_evsub *sub, unsigned mod_id,
367 void *data )
368 {
369 PJ_ASSERT_ON_FAIL(mod_id < PJSIP_MAX_MODULE, return);
370 sub->mod_data[mod_id] = data;
371 }
372
373
374 /*
375 * Get event subscription's module data.
376 */
pjsip_evsub_get_mod_data(pjsip_evsub * sub,unsigned mod_id)377 PJ_DEF(void*) pjsip_evsub_get_mod_data( pjsip_evsub *sub, unsigned mod_id )
378 {
379 PJ_ASSERT_RETURN(mod_id < PJSIP_MAX_MODULE, NULL);
380 return sub->mod_data[mod_id];
381 }
382
383
384 /*
385 * Find registered event package with matching name.
386 */
find_pkg(const pj_str_t * event_name)387 static struct evpkg* find_pkg(const pj_str_t *event_name)
388 {
389 struct evpkg *pkg;
390
391 pkg = mod_evsub.pkg_list.next;
392 while (pkg != &mod_evsub.pkg_list) {
393
394 if (pj_stricmp(&pkg->pkg_name, event_name) == 0) {
395 return pkg;
396 }
397
398 pkg = pkg->next;
399 }
400
401 return NULL;
402 }
403
404 /*
405 * Register an event package
406 */
pjsip_evsub_register_pkg(pjsip_module * pkg_mod,const pj_str_t * event_name,unsigned expires,unsigned accept_cnt,const pj_str_t accept[])407 PJ_DEF(pj_status_t) pjsip_evsub_register_pkg( pjsip_module *pkg_mod,
408 const pj_str_t *event_name,
409 unsigned expires,
410 unsigned accept_cnt,
411 const pj_str_t accept[])
412 {
413 struct evpkg *pkg;
414 unsigned i;
415
416 PJ_ASSERT_RETURN(pkg_mod && event_name, PJ_EINVAL);
417
418 /* Make sure accept_cnt < PJ_ARRAY_SIZE(pkg->pkg_accept->values) */
419 PJ_ASSERT_RETURN(accept_cnt <= PJSIP_GENERIC_ARRAY_MAX_COUNT,
420 PJ_ETOOMANY);
421
422 /* Make sure evsub module has been initialized */
423 PJ_ASSERT_RETURN(mod_evsub.mod.id != -1, PJ_EINVALIDOP);
424
425 /* Make sure no module with the specified name already registered: */
426
427 PJ_ASSERT_RETURN(find_pkg(event_name) == NULL, PJSIP_SIMPLE_EPKGEXISTS);
428
429
430 /* Create new event package: */
431
432 pkg = PJ_POOL_ALLOC_T(mod_evsub.pool, struct evpkg);
433 pkg->pkg_mod = pkg_mod;
434 pkg->pkg_expires = expires;
435 pj_strdup(mod_evsub.pool, &pkg->pkg_name, event_name);
436
437 pkg->pkg_accept = pjsip_accept_hdr_create(mod_evsub.pool);
438 pkg->pkg_accept->count = accept_cnt;
439 for (i=0; i<accept_cnt; ++i) {
440 pj_strdup(mod_evsub.pool, &pkg->pkg_accept->values[i], &accept[i]);
441 }
442
443 /* Add to package list: */
444
445 pj_list_push_back(&mod_evsub.pkg_list, pkg);
446
447 /* Add to Allow-Events header: */
448
449 if (mod_evsub.allow_events_hdr->count !=
450 PJ_ARRAY_SIZE(mod_evsub.allow_events_hdr->values))
451 {
452 mod_evsub.allow_events_hdr->values[mod_evsub.allow_events_hdr->count] =
453 pkg->pkg_name;
454 ++mod_evsub.allow_events_hdr->count;
455 }
456
457 /* Add to endpoint's Accept header */
458 pjsip_endpt_add_capability(mod_evsub.endpt, &mod_evsub.mod,
459 PJSIP_H_ACCEPT, NULL,
460 pkg->pkg_accept->count,
461 pkg->pkg_accept->values);
462
463
464 /* Done */
465
466 PJ_LOG(5,(THIS_FILE, "Event pkg \"%.*s\" registered by %.*s",
467 (int)event_name->slen, event_name->ptr,
468 (int)pkg_mod->name.slen, pkg_mod->name.ptr));
469
470 return PJ_SUCCESS;
471 }
472
473
474 /*
475 * Retrieve Allow-Events header
476 */
pjsip_evsub_get_allow_events_hdr(pjsip_module * m)477 PJ_DEF(const pjsip_hdr*) pjsip_evsub_get_allow_events_hdr(pjsip_module *m)
478 {
479 struct mod_evsub *mod;
480
481 if (m == NULL)
482 m = pjsip_evsub_instance();
483
484 mod = (struct mod_evsub*)m;
485
486 return (pjsip_hdr*) mod->allow_events_hdr;
487 }
488
489
490 /*
491 * Update expiration time.
492 */
update_expires(pjsip_evsub * sub,pj_uint32_t interval)493 static void update_expires( pjsip_evsub *sub, pj_uint32_t interval )
494 {
495 pj_gettimeofday(&sub->refresh_time);
496 sub->refresh_time.sec += interval;
497 }
498
499
500 /*
501 * Schedule timer.
502 */
set_timer(pjsip_evsub * sub,int timer_id,pj_uint32_t seconds)503 static void set_timer( pjsip_evsub *sub, int timer_id,
504 pj_uint32_t seconds)
505 {
506 if (sub->timer.id != TIMER_TYPE_NONE) {
507 PJ_LOG(5,(sub->obj_name, "%s %s timer",
508 (timer_id==sub->timer.id ? "Updating" : "Cancelling"),
509 timer_names[sub->timer.id]));
510 pjsip_endpt_cancel_timer(sub->endpt, &sub->timer);
511 sub->timer.id = TIMER_TYPE_NONE;
512 }
513
514 if (timer_id != TIMER_TYPE_NONE && seconds != PJSIP_EXPIRES_NOT_SPECIFIED)
515 {
516 pj_time_val timeout;
517
518 PJ_ASSERT_ON_FAIL(timer_id>TIMER_TYPE_NONE && timer_id<TIMER_TYPE_MAX,
519 return);
520
521 timeout.sec = seconds;
522 timeout.msec = 0;
523
524 pj_timer_heap_schedule_w_grp_lock(
525 pjsip_endpt_get_timer_heap(sub->endpt),
526 &sub->timer, &timeout, timer_id, sub->grp_lock);
527
528 PJ_LOG(5,(sub->obj_name, "Timer %s scheduled in %d seconds",
529 timer_names[sub->timer.id], timeout.sec));
530 }
531 }
532
533
534 /*
535 * Set event subscription UAS timout.
536 */
pjsip_evsub_uas_set_timeout(pjsip_evsub * sub,pj_uint32_t seconds)537 PJ_DEF(void) pjsip_evsub_uas_set_timeout(pjsip_evsub *sub, pj_uint32_t seconds)
538 {
539 set_timer(sub, TIMER_TYPE_UAS_TIMEOUT, (pj_int32_t)seconds);
540 }
541
542
543 /*
544 * Destructor.
545 */
evsub_on_destroy(void * obj)546 static void evsub_on_destroy(void *obj)
547 {
548 pjsip_evsub *sub = (pjsip_evsub*)obj;
549
550 /* Decrement dialog's session */
551 pjsip_dlg_dec_session(sub->dlg, &mod_evsub.mod);
552 }
553
554
555 /*
556 * Destroy session.
557 */
evsub_destroy(pjsip_evsub * sub)558 static void evsub_destroy( pjsip_evsub *sub )
559 {
560 struct dlgsub *dlgsub_head, *dlgsub;
561
562 PJ_LOG(4,(sub->obj_name, "Subscription destroyed"));
563
564 /* Kill timer */
565 set_timer(sub, TIMER_TYPE_NONE, 0);
566
567 /* Kill timer for stopping pending sub (see ticket #1807) */
568 if (sub->pending_sub_timer && sub->pending_sub_timer->id == 1) {
569 pjsip_endpt_cancel_timer(sub->endpt, sub->pending_sub_timer);
570 sub->pending_sub_timer->id = 0;
571 sub->pending_sub_timer = NULL;
572 }
573
574 /* Remove this session from dialog's list of subscription */
575 dlgsub_head = (struct dlgsub *) sub->dlg->mod_data[mod_evsub.mod.id];
576 dlgsub = dlgsub_head->next;
577 while (dlgsub != dlgsub_head) {
578
579 if (dlgsub->sub == sub) {
580 pj_list_erase(dlgsub);
581 break;
582 }
583
584 dlgsub = dlgsub->next;
585 }
586
587 pj_grp_lock_dec_ref(sub->grp_lock);
588 }
589
590 /*
591 * Set subscription session state.
592 */
set_state(pjsip_evsub * sub,pjsip_evsub_state state,const pj_str_t * state_str,pjsip_event * event,const pj_str_t * reason)593 static void set_state( pjsip_evsub *sub, pjsip_evsub_state state,
594 const pj_str_t *state_str, pjsip_event *event,
595 const pj_str_t *reason)
596 {
597 pjsip_evsub_state prev_state = sub->state;
598 pj_str_t old_state_str = sub->state_str;
599 pjsip_event dummy_event;
600
601 sub->state = state;
602
603 if (state_str && state_str->slen)
604 pj_strdup_with_null(sub->pool, &sub->state_str, state_str);
605 else
606 sub->state_str = evsub_state_names[state];
607
608 if (reason && sub->term_reason.slen==0)
609 pj_strdup(sub->pool, &sub->term_reason, reason);
610
611 PJ_LOG(4,(sub->obj_name,
612 "Subscription state changed %.*s --> %.*s",
613 (int)old_state_str.slen,
614 old_state_str.ptr,
615 (int)sub->state_str.slen,
616 sub->state_str.ptr));
617 pj_log_push_indent();
618
619 /* don't call the callback with NULL event, it may crash the app! */
620 if (!event) {
621 PJSIP_EVENT_INIT_USER(dummy_event, 0, 0, 0, 0);
622 event = &dummy_event;
623 }
624
625 if (sub->user.on_evsub_state && sub->call_cb)
626 (*sub->user.on_evsub_state)(sub, event);
627
628 if (state == PJSIP_EVSUB_STATE_TERMINATED &&
629 prev_state != PJSIP_EVSUB_STATE_TERMINATED)
630 {
631 /* Kill any timer. */
632 set_timer(sub, TIMER_TYPE_NONE, 0);
633
634 if (sub->pending_tsx == 0) {
635 evsub_destroy(sub);
636 }
637 }
638
639 pj_log_pop_indent();
640 }
641
642
643 /*
644 * Timer callback.
645 */
on_timer(pj_timer_heap_t * timer_heap,struct pj_timer_entry * entry)646 static void on_timer( pj_timer_heap_t *timer_heap,
647 struct pj_timer_entry *entry)
648 {
649 pjsip_evsub *sub;
650 int timer_id;
651
652 PJ_UNUSED_ARG(timer_heap);
653
654 sub = (pjsip_evsub*) entry->user_data;
655
656 pjsip_dlg_inc_lock(sub->dlg);
657
658 /* If this timer entry has just been rescheduled or cancelled
659 * while waiting for dialog mutex, just return (see #1885 scenario 1).
660 */
661 if (pj_timer_entry_running(entry) || entry->id == TIMER_TYPE_NONE) {
662 pjsip_dlg_dec_lock(sub->dlg);
663 return;
664 }
665
666 timer_id = entry->id;
667 entry->id = TIMER_TYPE_NONE;
668
669 switch (timer_id) {
670
671 case TIMER_TYPE_UAC_REFRESH:
672 /* Time for UAC to refresh subscription */
673 if (sub->user.on_client_refresh && sub->call_cb) {
674 (*sub->user.on_client_refresh)(sub);
675 } else {
676 pjsip_tx_data *tdata;
677 pj_status_t status;
678
679 PJ_LOG(5,(sub->obj_name, "Refreshing subscription."));
680 pj_log_push_indent();
681 status = pjsip_evsub_initiate(sub, NULL,
682 sub->expires->ivalue,
683 &tdata);
684 if (status == PJ_SUCCESS)
685 pjsip_evsub_send_request(sub, tdata);
686
687 pj_log_pop_indent();
688 }
689 break;
690
691 case TIMER_TYPE_UAS_TIMEOUT:
692 /* Refresh from UAC has not been received */
693 if (sub->user.on_server_timeout && sub->call_cb) {
694 (*sub->user.on_server_timeout)(sub);
695 } else {
696 pjsip_tx_data *tdata;
697 pj_status_t status;
698
699 PJ_LOG(5,(sub->obj_name, "Timeout waiting for refresh. "
700 "Sending NOTIFY to terminate."));
701 pj_log_push_indent();
702 status = pjsip_evsub_notify( sub, PJSIP_EVSUB_STATE_TERMINATED,
703 NULL, &STR_TIMEOUT, &tdata);
704 if (status == PJ_SUCCESS)
705 pjsip_evsub_send_request(sub, tdata);
706
707 pj_log_pop_indent();
708 }
709 break;
710
711 case TIMER_TYPE_UAC_TERMINATE:
712 {
713 pj_str_t timeout = {"timeout", 7};
714
715 PJ_LOG(5,(sub->obj_name, "Timeout waiting for final NOTIFY. "
716 "Terminating.."));
717 pj_log_push_indent();
718 set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, NULL,
719 &timeout);
720 pj_log_pop_indent();
721 }
722 break;
723
724 case TIMER_TYPE_UAC_WAIT_NOTIFY:
725 {
726 pjsip_tx_data *tdata;
727 pj_status_t status;
728
729 PJ_LOG(5,(sub->obj_name,
730 "Timeout waiting for subsequent NOTIFY (we did "
731 "send non-2xx response for previous NOTIFY). "
732 "Unsubscribing.."));
733 pj_log_push_indent();
734 status = pjsip_evsub_initiate( sub, NULL, 0, &tdata);
735 if (status == PJ_SUCCESS)
736 pjsip_evsub_send_request(sub, tdata);
737
738 pj_log_pop_indent();
739 }
740 break;
741
742 default:
743 pj_assert(!"Invalid timer id");
744 }
745
746 pjsip_dlg_dec_lock(sub->dlg);
747 }
748
749
750 /*
751 * Create subscription session, used for both client and notifier.
752 */
evsub_create(pjsip_dialog * dlg,pjsip_role_e role,const pjsip_evsub_user * user_cb,const pj_str_t * event,unsigned option,pjsip_evsub ** p_evsub)753 static pj_status_t evsub_create( pjsip_dialog *dlg,
754 pjsip_role_e role,
755 const pjsip_evsub_user *user_cb,
756 const pj_str_t *event,
757 unsigned option,
758 pjsip_evsub **p_evsub )
759 {
760 pjsip_evsub *sub;
761 struct evpkg *pkg;
762 struct dlgsub *dlgsub_head, *dlgsub;
763 pj_status_t status;
764
765 /* Make sure there's package register for the event name: */
766
767 pkg = find_pkg(event);
768 if (pkg == NULL)
769 return PJSIP_SIMPLE_ENOPKG;
770
771
772 /* Must lock dialog before using pool etc. */
773 pjsip_dlg_inc_lock(dlg);
774
775 /* Init attributes: */
776
777 sub = PJ_POOL_ZALLOC_T(dlg->pool, struct pjsip_evsub);
778 sub->pool = dlg->pool;
779 sub->endpt = dlg->endpt;
780 sub->dlg = dlg;
781 sub->pkg = pkg;
782 sub->role = role;
783 sub->call_cb = PJ_TRUE;
784 sub->option = option;
785 sub->state = PJSIP_EVSUB_STATE_NULL;
786 sub->state_str = evsub_state_names[sub->state];
787 sub->expires = pjsip_expires_hdr_create(sub->pool, pkg->pkg_expires);
788 sub->accept = (pjsip_accept_hdr*)
789 pjsip_hdr_clone(sub->pool, pkg->pkg_accept);
790 pj_list_init(&sub->sub_hdr_list);
791
792 sub->timer.user_data = sub;
793 sub->timer.cb = &on_timer;
794
795 /* Set name. */
796 pj_ansi_snprintf(sub->obj_name, PJ_ARRAY_SIZE(sub->obj_name),
797 "evsub%p", sub);
798
799
800 /* Copy callback, if any: */
801 if (user_cb)
802 pj_memcpy(&sub->user, user_cb, sizeof(pjsip_evsub_user));
803
804
805 /* Create Event header: */
806 sub->event = pjsip_event_hdr_create(sub->pool);
807 pj_strdup(sub->pool, &sub->event->event_type, event);
808
809
810 /* Check if another subscription has been registered to the dialog. In
811 * that case, just add ourselves to the subscription list, otherwise
812 * create and register a new subscription list.
813 */
814 if (pjsip_dlg_has_usage(dlg, &mod_evsub.mod)) {
815 dlgsub_head = (struct dlgsub*) dlg->mod_data[mod_evsub.mod.id];
816 dlgsub = PJ_POOL_ALLOC_T(sub->pool, struct dlgsub);
817 dlgsub->sub = sub;
818 pj_list_push_back(dlgsub_head, dlgsub);
819 } else {
820 dlgsub_head = PJ_POOL_ALLOC_T(sub->pool, struct dlgsub);
821 dlgsub = PJ_POOL_ALLOC_T(sub->pool, struct dlgsub);
822 dlgsub->sub = sub;
823
824 pj_list_init(dlgsub_head);
825 pj_list_push_back(dlgsub_head, dlgsub);
826
827
828 /* Register as dialog usage: */
829
830 status = pjsip_dlg_add_usage(dlg, &mod_evsub.mod, dlgsub_head);
831 if (status != PJ_SUCCESS) {
832 pjsip_dlg_dec_lock(dlg);
833 return status;
834 }
835 }
836
837 PJ_LOG(5,(sub->obj_name, "%s subscription created, using dialog %s",
838 (role==PJSIP_ROLE_UAC ? "UAC" : "UAS"),
839 dlg->obj_name));
840
841 *p_evsub = sub;
842 pjsip_dlg_dec_lock(dlg);
843
844 return PJ_SUCCESS;
845 }
846
847 /*
848 * Increment the event subscription's group lock.
849 */
pjsip_evsub_add_ref(pjsip_evsub * sub)850 PJ_DEF(pj_status_t) pjsip_evsub_add_ref(pjsip_evsub *sub)
851 {
852 return pj_grp_lock_add_ref(sub->grp_lock);
853 }
854
855 /*
856 * Decrement the event subscription's group lock.
857 */
pjsip_evsub_dec_ref(pjsip_evsub * sub)858 PJ_DEF(pj_status_t) pjsip_evsub_dec_ref(pjsip_evsub *sub)
859 {
860 return pj_grp_lock_dec_ref(sub->grp_lock);
861 }
862
863 /*
864 * Create client subscription session.
865 */
pjsip_evsub_create_uac(pjsip_dialog * dlg,const pjsip_evsub_user * user_cb,const pj_str_t * event,unsigned option,pjsip_evsub ** p_evsub)866 PJ_DEF(pj_status_t) pjsip_evsub_create_uac( pjsip_dialog *dlg,
867 const pjsip_evsub_user *user_cb,
868 const pj_str_t *event,
869 unsigned option,
870 pjsip_evsub **p_evsub)
871 {
872 pjsip_evsub *sub;
873 pj_status_t status;
874
875 PJ_ASSERT_RETURN(dlg && event && p_evsub, PJ_EINVAL);
876
877 pjsip_dlg_inc_lock(dlg);
878 status = evsub_create(dlg, PJSIP_UAC_ROLE, user_cb, event, option, &sub);
879 if (status != PJ_SUCCESS)
880 goto on_return;
881
882 /* Add unique Id to Event header, only when PJSIP_EVSUB_NO_EVENT_ID
883 * is not specified.
884 */
885 if ((option & PJSIP_EVSUB_NO_EVENT_ID) == 0) {
886 pj_create_unique_string(sub->pool, &sub->event->id_param);
887 }
888
889 /* Increment dlg session. */
890 pjsip_dlg_inc_session(sub->dlg, &mod_evsub.mod);
891
892 /* Init group lock */
893 status = pj_grp_lock_create(dlg->pool, NULL, &sub->grp_lock);
894 if (status != PJ_SUCCESS) {
895 pjsip_dlg_dec_session(sub->dlg, &mod_evsub.mod);
896 goto on_return;
897 }
898
899 pj_grp_lock_add_ref(sub->grp_lock);
900 pj_grp_lock_add_handler(sub->grp_lock, dlg->pool, sub, &evsub_on_destroy);
901
902 /* Done */
903 *p_evsub = sub;
904
905 on_return:
906 pjsip_dlg_dec_lock(dlg);
907 return status;
908 }
909
910
911 /*
912 * Create server subscription session from incoming request.
913 */
pjsip_evsub_create_uas(pjsip_dialog * dlg,const pjsip_evsub_user * user_cb,pjsip_rx_data * rdata,unsigned option,pjsip_evsub ** p_evsub)914 PJ_DEF(pj_status_t) pjsip_evsub_create_uas( pjsip_dialog *dlg,
915 const pjsip_evsub_user *user_cb,
916 pjsip_rx_data *rdata,
917 unsigned option,
918 pjsip_evsub **p_evsub)
919 {
920 pjsip_evsub *sub;
921 pjsip_transaction *tsx;
922 pjsip_accept_hdr *accept_hdr;
923 pjsip_event_hdr *event_hdr;
924 pjsip_expires_hdr *expires_hdr;
925 pj_status_t status;
926
927 /* Check arguments: */
928 PJ_ASSERT_RETURN(dlg && rdata && p_evsub, PJ_EINVAL);
929
930 /* MUST be request message: */
931 PJ_ASSERT_RETURN(rdata->msg_info.msg->type == PJSIP_REQUEST_MSG,
932 PJSIP_ENOTREQUESTMSG);
933
934 /* Transaction MUST have been created (in the dialog) */
935 tsx = pjsip_rdata_get_tsx(rdata);
936 PJ_ASSERT_RETURN(tsx != NULL, PJSIP_ENOTSX);
937
938 /* No subscription must have been attached to transaction */
939 PJ_ASSERT_RETURN(tsx->mod_data[mod_evsub.mod.id] == NULL,
940 PJSIP_ETYPEEXISTS);
941
942 /* Package MUST implement on_rx_refresh */
943 PJ_ASSERT_RETURN(user_cb->on_rx_refresh, PJ_EINVALIDOP);
944
945 /* Request MUST have "Event" header. We need the Event header to get
946 * the package name (don't want to add more arguments in the function).
947 */
948 event_hdr = (pjsip_event_hdr*)
949 pjsip_msg_find_hdr_by_names(rdata->msg_info.msg, &STR_EVENT,
950 &STR_EVENT_S, NULL);
951 if (event_hdr == NULL) {
952 return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_BAD_REQUEST);
953 }
954
955 /* Start locking the mutex: */
956
957 pjsip_dlg_inc_lock(dlg);
958
959 /* Create the session: */
960
961 status = evsub_create(dlg, PJSIP_UAS_ROLE, user_cb,
962 &event_hdr->event_type, option, &sub);
963 if (status != PJ_SUCCESS)
964 goto on_return;
965
966 /* Just duplicate Event header from the request */
967 sub->event = (pjsip_event_hdr*) pjsip_hdr_clone(sub->pool, event_hdr);
968
969 /* Set the method: */
970 pjsip_method_copy(sub->pool, &sub->method,
971 &rdata->msg_info.msg->line.req.method);
972
973 /* Update expiration time according to client request: */
974
975 expires_hdr = (pjsip_expires_hdr*)
976 pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);
977 if (expires_hdr) {
978 sub->expires->ivalue = expires_hdr->ivalue;
979 }
980
981 /* Update time. */
982 update_expires(sub, sub->expires->ivalue);
983
984 /* Update Accept header: */
985
986 accept_hdr = (pjsip_accept_hdr*)
987 pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_ACCEPT, NULL);
988 if (accept_hdr)
989 sub->accept = (pjsip_accept_hdr*)pjsip_hdr_clone(sub->pool,accept_hdr);
990
991 /* Increment dlg session. */
992 pjsip_dlg_inc_session(dlg, &mod_evsub.mod);
993
994 /* Init group lock */
995 status = pj_grp_lock_create(dlg->pool, NULL, &sub->grp_lock);
996 if (status != PJ_SUCCESS) {
997 pjsip_dlg_dec_session(sub->dlg, &mod_evsub.mod);
998 goto on_return;
999 }
1000
1001 pj_grp_lock_add_ref(sub->grp_lock);
1002 pj_grp_lock_add_handler(sub->grp_lock, dlg->pool, sub, &evsub_on_destroy);
1003
1004 /* We can start the session: */
1005
1006 sub->pending_tsx++;
1007 tsx->mod_data[mod_evsub.mod.id] = sub;
1008
1009 /* Done. */
1010 *p_evsub = sub;
1011
1012
1013 on_return:
1014 pjsip_dlg_dec_lock(dlg);
1015 return status;
1016 }
1017
1018
1019 /*
1020 * Forcefully destroy subscription.
1021 */
pjsip_evsub_terminate(pjsip_evsub * sub,pj_bool_t notify)1022 PJ_DEF(pj_status_t) pjsip_evsub_terminate( pjsip_evsub *sub,
1023 pj_bool_t notify )
1024 {
1025 PJ_ASSERT_RETURN(sub, PJ_EINVAL);
1026
1027 pjsip_dlg_inc_lock(sub->dlg);
1028
1029 /* I think it's pretty safe to disable this check.
1030
1031 if (sub->pending_tsx) {
1032 pj_assert(!"Unable to terminate when there's pending tsx");
1033 pjsip_dlg_dec_lock(sub->dlg);
1034 return PJ_EINVALIDOP;
1035 }
1036 */
1037
1038 sub->call_cb = notify;
1039 set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, NULL, NULL);
1040
1041 pjsip_dlg_dec_lock(sub->dlg);
1042 return PJ_SUCCESS;
1043 }
1044
1045 /*
1046 * Get subscription state.
1047 */
pjsip_evsub_get_state(pjsip_evsub * sub)1048 PJ_DEF(pjsip_evsub_state) pjsip_evsub_get_state(pjsip_evsub *sub)
1049 {
1050 return sub->state;
1051 }
1052
1053 /*
1054 * Get state name.
1055 */
pjsip_evsub_get_state_name(pjsip_evsub * sub)1056 PJ_DEF(const char*) pjsip_evsub_get_state_name(pjsip_evsub *sub)
1057 {
1058 return sub->state_str.ptr;
1059 }
1060
1061 /*
1062 * Get termination reason.
1063 */
pjsip_evsub_get_termination_reason(pjsip_evsub * sub)1064 PJ_DEF(const pj_str_t*) pjsip_evsub_get_termination_reason(pjsip_evsub *sub)
1065 {
1066 return &sub->term_reason;
1067 }
1068
1069 /*
1070 * Initiate client subscription
1071 */
pjsip_evsub_initiate(pjsip_evsub * sub,const pjsip_method * method,pj_uint32_t expires,pjsip_tx_data ** p_tdata)1072 PJ_DEF(pj_status_t) pjsip_evsub_initiate( pjsip_evsub *sub,
1073 const pjsip_method *method,
1074 pj_uint32_t expires,
1075 pjsip_tx_data **p_tdata)
1076 {
1077 pjsip_tx_data *tdata;
1078 pj_status_t status;
1079
1080 PJ_ASSERT_RETURN(sub!=NULL && p_tdata!=NULL, PJ_EINVAL);
1081
1082 /* Use SUBSCRIBE if method is not specified */
1083 if (method == NULL)
1084 method = &pjsip_subscribe_method;
1085
1086 pjsip_dlg_inc_lock(sub->dlg);
1087
1088 /* Update method: */
1089 if (sub->state == PJSIP_EVSUB_STATE_NULL)
1090 pjsip_method_copy(sub->pool, &sub->method, method);
1091
1092 status = pjsip_dlg_create_request( sub->dlg, method, -1, &tdata);
1093 if (status != PJ_SUCCESS)
1094 goto on_return;
1095
1096
1097 /* Add Event header: */
1098 pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)
1099 pjsip_hdr_shallow_clone(tdata->pool, sub->event));
1100
1101 /* Update and add expires header: */
1102 if (expires != PJSIP_EXPIRES_NOT_SPECIFIED)
1103 sub->expires->ivalue = expires;
1104 pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)
1105 pjsip_hdr_shallow_clone(tdata->pool, sub->expires));
1106
1107 /* Add Supported header (it's optional in RFC 3265, but some event package
1108 * RFC may bring this requirement to SHOULD strength - e.g. RFC 5373)
1109 */
1110 {
1111 const pjsip_hdr *hdr = pjsip_endpt_get_capability(sub->endpt,
1112 PJSIP_H_SUPPORTED,
1113 NULL);
1114 if (hdr) {
1115 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
1116 pjsip_hdr_shallow_clone(tdata->pool, hdr));
1117 }
1118 }
1119
1120 /* Add Accept header: */
1121 pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)
1122 pjsip_hdr_shallow_clone(tdata->pool, sub->accept));
1123
1124
1125 /* Add Allow-Events header: */
1126 pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)
1127 pjsip_hdr_shallow_clone(tdata->pool,
1128 mod_evsub.allow_events_hdr));
1129
1130
1131 /* Add custom headers */
1132 {
1133 const pjsip_hdr *hdr = sub->sub_hdr_list.next;
1134 while (hdr != &sub->sub_hdr_list) {
1135 pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)
1136 pjsip_hdr_shallow_clone(tdata->pool, hdr));
1137 hdr = hdr->next;
1138 }
1139 }
1140
1141
1142 *p_tdata = tdata;
1143
1144
1145 on_return:
1146
1147 pjsip_dlg_dec_lock(sub->dlg);
1148 return status;
1149 }
1150
1151
1152 /*
1153 * Add custom headers.
1154 */
pjsip_evsub_add_header(pjsip_evsub * sub,const pjsip_hdr * hdr_list)1155 PJ_DEF(pj_status_t) pjsip_evsub_add_header( pjsip_evsub *sub,
1156 const pjsip_hdr *hdr_list )
1157 {
1158 const pjsip_hdr *hdr;
1159
1160 PJ_ASSERT_RETURN(sub && hdr_list, PJ_EINVAL);
1161
1162 hdr = hdr_list->next;
1163 while (hdr != hdr_list) {
1164 pj_list_push_back(&sub->sub_hdr_list, (pjsip_hdr*)
1165 pjsip_hdr_clone(sub->pool, hdr));
1166 hdr = hdr->next;
1167 }
1168
1169 return PJ_SUCCESS;
1170 }
1171
1172
1173 /*
1174 * Accept incoming subscription request.
1175 */
pjsip_evsub_accept(pjsip_evsub * sub,pjsip_rx_data * rdata,int st_code,const pjsip_hdr * hdr_list)1176 PJ_DEF(pj_status_t) pjsip_evsub_accept( pjsip_evsub *sub,
1177 pjsip_rx_data *rdata,
1178 int st_code,
1179 const pjsip_hdr *hdr_list )
1180 {
1181 pjsip_tx_data *tdata;
1182 pjsip_transaction *tsx;
1183 pj_status_t status;
1184
1185 /* Check arguments */
1186 PJ_ASSERT_RETURN(sub && rdata, PJ_EINVAL);
1187
1188 /* Can only be for server subscription: */
1189 PJ_ASSERT_RETURN(sub->role == PJSIP_ROLE_UAS, PJ_EINVALIDOP);
1190
1191 /* Only expect 2xx status code (for now) */
1192 PJ_ASSERT_RETURN(st_code/100 == 2, PJ_EINVALIDOP);
1193
1194 /* Subscription MUST have been attached to the transaction.
1195 * Initial subscription request will be attached on evsub_create_uas(),
1196 * while subsequent requests will be attached in tsx_state()
1197 */
1198 tsx = pjsip_rdata_get_tsx(rdata);
1199 PJ_ASSERT_RETURN(tsx->mod_data[mod_evsub.mod.id] != NULL,
1200 PJ_EINVALIDOP);
1201
1202 /* Lock dialog */
1203 pjsip_dlg_inc_lock(sub->dlg);
1204
1205 /* Create response: */
1206 status = pjsip_dlg_create_response( sub->dlg, rdata, st_code, NULL,
1207 &tdata);
1208 if (status != PJ_SUCCESS)
1209 goto on_return;
1210
1211
1212 /* Add expires header: */
1213 pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)
1214 pjsip_hdr_shallow_clone(tdata->pool, sub->expires));
1215
1216 /* Add additional header, if any. */
1217 if (hdr_list) {
1218 const pjsip_hdr *hdr = hdr_list->next;
1219 while (hdr != hdr_list) {
1220 pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)
1221 pjsip_hdr_clone(tdata->pool, hdr));
1222 hdr = hdr->next;
1223 }
1224 }
1225
1226 /* Send the response: */
1227 status = pjsip_dlg_send_response( sub->dlg, tsx, tdata );
1228 if (status != PJ_SUCCESS)
1229 goto on_return;
1230
1231 /* Set UAS timeout timer, when status code is 2xx and state is not
1232 * terminated.
1233 */
1234 if (st_code/100 == 2 && sub->state != PJSIP_EVSUB_STATE_TERMINATED) {
1235 PJ_LOG(5,(sub->obj_name, "UAS timeout in %d seconds",
1236 sub->expires->ivalue));
1237 set_timer(sub, TIMER_TYPE_UAS_TIMEOUT, sub->expires->ivalue);
1238 }
1239
1240 on_return:
1241
1242 pjsip_dlg_dec_lock(sub->dlg);
1243 return status;
1244 }
1245
1246
1247 /*
1248 * Create Subscription-State header based on current server subscription
1249 * state.
1250 */
sub_state_create(pj_pool_t * pool,pjsip_evsub * sub,pjsip_evsub_state state,const pj_str_t * state_str,const pj_str_t * reason)1251 static pjsip_sub_state_hdr* sub_state_create( pj_pool_t *pool,
1252 pjsip_evsub *sub,
1253 pjsip_evsub_state state,
1254 const pj_str_t *state_str,
1255 const pj_str_t *reason )
1256 {
1257 pjsip_sub_state_hdr *sub_state;
1258 pj_time_val now, delay;
1259
1260 /* Get the remaining time before refresh is required */
1261 pj_gettimeofday(&now);
1262 delay = sub->refresh_time;
1263 PJ_TIME_VAL_SUB(delay, now);
1264
1265 /* Create the Subscription-State header */
1266 sub_state = pjsip_sub_state_hdr_create(pool);
1267
1268 /* Fill up the header */
1269 switch (state) {
1270 case PJSIP_EVSUB_STATE_NULL:
1271 case PJSIP_EVSUB_STATE_SENT:
1272 pj_assert(!"Invalid state!");
1273 /* Treat as pending */
1274
1275 case PJSIP_EVSUB_STATE_ACCEPTED:
1276 case PJSIP_EVSUB_STATE_PENDING:
1277 sub_state->sub_state = STR_PENDING;
1278 sub_state->expires_param = delay.sec;
1279 break;
1280
1281 case PJSIP_EVSUB_STATE_ACTIVE:
1282 sub_state->sub_state = STR_ACTIVE;
1283 sub_state->expires_param = delay.sec;
1284 break;
1285
1286 case PJSIP_EVSUB_STATE_TERMINATED:
1287 sub_state->sub_state = STR_TERMINATED;
1288 if (reason != NULL)
1289 pj_strdup(pool, &sub_state->reason_param, reason);
1290 break;
1291
1292 case PJSIP_EVSUB_STATE_UNKNOWN:
1293 pj_assert(state_str != NULL);
1294 pj_strdup(pool, &sub_state->sub_state, state_str);
1295 break;
1296 }
1297
1298 return sub_state;
1299 }
1300
1301 /*
1302 * Create and send NOTIFY request.
1303 */
pjsip_evsub_notify(pjsip_evsub * sub,pjsip_evsub_state state,const pj_str_t * state_str,const pj_str_t * reason,pjsip_tx_data ** p_tdata)1304 PJ_DEF(pj_status_t) pjsip_evsub_notify( pjsip_evsub *sub,
1305 pjsip_evsub_state state,
1306 const pj_str_t *state_str,
1307 const pj_str_t *reason,
1308 pjsip_tx_data **p_tdata)
1309 {
1310 pjsip_tx_data *tdata;
1311 pjsip_sub_state_hdr *sub_state;
1312 pj_status_t status;
1313
1314 /* Check arguments. */
1315 PJ_ASSERT_RETURN(sub!=NULL && p_tdata!=NULL, PJ_EINVAL);
1316
1317 /* Lock dialog. */
1318 pjsip_dlg_inc_lock(sub->dlg);
1319
1320 /* Create NOTIFY request */
1321 status = pjsip_dlg_create_request( sub->dlg, pjsip_get_notify_method(),
1322 -1, &tdata);
1323 if (status != PJ_SUCCESS)
1324 goto on_return;
1325
1326 /* Add Event header */
1327 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
1328 pjsip_hdr_shallow_clone(tdata->pool, sub->event));
1329
1330 /* Add Subscription-State header */
1331 sub_state = sub_state_create(tdata->pool, sub, state, state_str,
1332 reason);
1333 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)sub_state);
1334
1335 /* Add Allow-Events header */
1336 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
1337 pjsip_hdr_shallow_clone(tdata->pool, mod_evsub.allow_events_hdr));
1338
1339 /* Add Authentication headers. */
1340 pjsip_auth_clt_init_req( &sub->dlg->auth_sess, tdata );
1341
1342 /* Update reason */
1343 if (reason)
1344 pj_strdup(sub->dlg->pool, &sub->term_reason, reason);
1345
1346 /* Save destination state. */
1347 sub->dst_state = state;
1348 if (state_str)
1349 pj_strdup(sub->pool, &sub->dst_state_str, state_str);
1350 else
1351 sub->dst_state_str.slen = 0;
1352
1353
1354 *p_tdata = tdata;
1355
1356 on_return:
1357 /* Unlock dialog */
1358 pjsip_dlg_dec_lock(sub->dlg);
1359 return status;
1360 }
1361
1362
1363 /*
1364 * Create NOTIFY to reflect current status.
1365 */
pjsip_evsub_current_notify(pjsip_evsub * sub,pjsip_tx_data ** p_tdata)1366 PJ_DEF(pj_status_t) pjsip_evsub_current_notify( pjsip_evsub *sub,
1367 pjsip_tx_data **p_tdata )
1368 {
1369 return pjsip_evsub_notify( sub, sub->state, &sub->state_str,
1370 NULL, p_tdata );
1371 }
1372
1373
1374 /*
1375 * Send request.
1376 */
pjsip_evsub_send_request(pjsip_evsub * sub,pjsip_tx_data * tdata)1377 PJ_DEF(pj_status_t) pjsip_evsub_send_request( pjsip_evsub *sub,
1378 pjsip_tx_data *tdata)
1379 {
1380 pj_status_t status;
1381
1382 /* Must be request message. */
1383 PJ_ASSERT_RETURN(tdata->msg->type == PJSIP_REQUEST_MSG,
1384 PJSIP_ENOTREQUESTMSG);
1385
1386 /* Lock */
1387 pjsip_dlg_inc_lock(sub->dlg);
1388
1389 /* Send the request. */
1390 status = pjsip_dlg_send_request(sub->dlg, tdata, -1, NULL);
1391 if (status != PJ_SUCCESS)
1392 goto on_return;
1393
1394
1395 /* Special case for NOTIFY:
1396 * The new state was set in pjsip_evsub_notify(), but we apply the
1397 * new state now, when the request was actually sent.
1398 */
1399 if (pjsip_method_cmp(&tdata->msg->line.req.method,
1400 &pjsip_notify_method)==0)
1401 {
1402 PJ_ASSERT_ON_FAIL( sub->dst_state!=PJSIP_EVSUB_STATE_NULL,
1403 {goto on_return;});
1404
1405 set_state(sub, sub->dst_state,
1406 (sub->dst_state_str.slen ? &sub->dst_state_str : NULL),
1407 NULL, NULL);
1408
1409 sub->dst_state = PJSIP_EVSUB_STATE_NULL;
1410 sub->dst_state_str.slen = 0;
1411
1412 }
1413
1414
1415 on_return:
1416 pjsip_dlg_dec_lock(sub->dlg);
1417 return status;
1418 }
1419
1420
1421 /* Callback to be called to terminate transaction. */
terminate_timer_cb(pj_timer_heap_t * timer_heap,struct pj_timer_entry * entry)1422 static void terminate_timer_cb(pj_timer_heap_t *timer_heap,
1423 struct pj_timer_entry *entry)
1424 {
1425 pj_str_t *key;
1426 pjsip_transaction *tsx;
1427
1428 PJ_UNUSED_ARG(timer_heap);
1429
1430 /* Clear timer ID */
1431 entry->id = 0;
1432
1433 key = (pj_str_t*)entry->user_data;
1434 tsx = pjsip_tsx_layer_find_tsx(key, PJ_FALSE);
1435 /* Chance of race condition here */
1436 if (tsx) {
1437 pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_UPDATED);
1438 }
1439 }
1440
1441
1442 /*
1443 * Attach subscription session to newly created transaction, if appropriate.
1444 */
on_new_transaction(pjsip_transaction * tsx,pjsip_event * event)1445 static pjsip_evsub *on_new_transaction( pjsip_transaction *tsx,
1446 pjsip_event *event)
1447 {
1448 /*
1449 * Newly created transaction will not have subscription session
1450 * attached to it. Find the subscription session from the dialog,
1451 * by matching the Event header.
1452 */
1453 pjsip_dialog *dlg;
1454 pjsip_event_hdr *event_hdr;
1455 pjsip_msg *msg;
1456 struct dlgsub *dlgsub_head, *dlgsub;
1457 pjsip_evsub *sub;
1458
1459 dlg = pjsip_tsx_get_dlg(tsx);
1460 if (!dlg) {
1461 pj_assert(!"Transaction should have a dialog instance!");
1462 return NULL;
1463 }
1464
1465
1466 switch (event->body.tsx_state.type) {
1467 case PJSIP_EVENT_RX_MSG:
1468 msg = event->body.tsx_state.src.rdata->msg_info.msg;
1469 break;
1470 case PJSIP_EVENT_TX_MSG:
1471 msg = event->body.tsx_state.src.tdata->msg;
1472 break;
1473 default:
1474 if (tsx->role == PJSIP_ROLE_UAC)
1475 msg = tsx->last_tx->msg;
1476 else
1477 msg = NULL;
1478 break;
1479 }
1480
1481 if (!msg) {
1482 //Note:
1483 // this transaction can be other transaction in the dialog.
1484 // The assertion below probably only valid for dialog that
1485 // only has one event subscription usage.
1486 //pj_assert(!"First transaction event is not TX or RX!");
1487 return NULL;
1488 }
1489
1490 event_hdr = (pjsip_event_hdr*)
1491 pjsip_msg_find_hdr_by_names(msg, &STR_EVENT,
1492 &STR_EVENT_S, NULL);
1493 if (!event_hdr) {
1494 /* Not subscription related message */
1495 return NULL;
1496 }
1497
1498 /* Find the subscription in the dialog, based on the content
1499 * of Event header:
1500 */
1501
1502 dlgsub_head = (struct dlgsub*) dlg->mod_data[mod_evsub.mod.id];
1503 if (dlgsub_head == NULL) {
1504 dlgsub_head = PJ_POOL_ALLOC_T(dlg->pool, struct dlgsub);
1505 pj_list_init(dlgsub_head);
1506 dlg->mod_data[mod_evsub.mod.id] = dlgsub_head;
1507 }
1508 dlgsub = dlgsub_head->next;
1509
1510 while (dlgsub != dlgsub_head) {
1511
1512 if (pj_stricmp(&dlgsub->sub->event->event_type,
1513 &event_hdr->event_type)==0)
1514 {
1515 /* Event type matched.
1516 * Check if event ID matched too.
1517 */
1518 if (pj_strcmp(&dlgsub->sub->event->id_param,
1519 &event_hdr->id_param)==0)
1520 {
1521 /* Skip this subscription if it has no event ID and has been
1522 * terminated (see ticket #1647).
1523 */
1524 if ((dlgsub->sub->option & PJSIP_EVSUB_NO_EVENT_ID) &&
1525 (pjsip_evsub_get_state(dlgsub->sub)==
1526 PJSIP_EVSUB_STATE_TERMINATED))
1527 {
1528 dlgsub = dlgsub->next;
1529 continue;
1530 } else {
1531 break;
1532 }
1533
1534 }
1535 /*
1536 * Otherwise if it is an UAC subscription, AND
1537 * PJSIP_EVSUB_NO_EVENT_ID flag is set, AND
1538 * the session's event id is NULL, AND
1539 * the incoming request is NOTIFY with event ID, then
1540 * we consider it as a match, and update the
1541 * session's event id.
1542 */
1543 else if (dlgsub->sub->role == PJSIP_ROLE_UAC &&
1544 (dlgsub->sub->option & PJSIP_EVSUB_NO_EVENT_ID)!=0 &&
1545 dlgsub->sub->event->id_param.slen==0 &&
1546 !pjsip_method_cmp(&tsx->method, &pjsip_notify_method))
1547 {
1548 /* Update session's event id. */
1549 pj_strdup(dlgsub->sub->pool,
1550 &dlgsub->sub->event->id_param,
1551 &event_hdr->id_param);
1552
1553 break;
1554 }
1555 }
1556
1557
1558
1559 dlgsub = dlgsub->next;
1560 }
1561
1562 /* Note:
1563 * the second condition is for http://trac.pjsip.org/repos/ticket/911
1564 */
1565 if (dlgsub == dlgsub_head ||
1566 (dlgsub->sub &&
1567 pjsip_evsub_get_state(dlgsub->sub)==PJSIP_EVSUB_STATE_TERMINATED))
1568 {
1569 const char *reason_msg =
1570 (dlgsub == dlgsub_head ? "Subscription Does Not Exist" :
1571 "Subscription already terminated");
1572
1573 /* This could be incoming request to create new subscription */
1574 PJ_LOG(4,(THIS_FILE,
1575 "%s for %.*s, event=%.*s;id=%.*s",
1576 reason_msg,
1577 (int)tsx->method.name.slen,
1578 tsx->method.name.ptr,
1579 (int)event_hdr->event_type.slen,
1580 event_hdr->event_type.ptr,
1581 (int)event_hdr->id_param.slen,
1582 event_hdr->id_param.ptr));
1583
1584 /* If this is an incoming NOTIFY, reject with 481 */
1585 if (tsx->state == PJSIP_TSX_STATE_TRYING &&
1586 pjsip_method_cmp(&tsx->method, &pjsip_notify_method)==0)
1587 {
1588 pj_str_t reason;
1589 pjsip_tx_data *tdata;
1590 pj_status_t status;
1591
1592 pj_cstr(&reason, reason_msg);
1593 status = pjsip_dlg_create_response(dlg,
1594 event->body.tsx_state.src.rdata,
1595 481, &reason,
1596 &tdata);
1597 if (status == PJ_SUCCESS) {
1598 status = pjsip_dlg_send_response(dlg, tsx, tdata);
1599 }
1600 }
1601 return NULL;
1602 }
1603
1604 /* Found! */
1605 sub = dlgsub->sub;
1606
1607 /* Attach session to the transaction */
1608 tsx->mod_data[mod_evsub.mod.id] = sub;
1609 sub->pending_tsx++;
1610
1611 /* Special case for outgoing/UAC SUBSCRIBE/REFER transaction.
1612 * We can only have one pending UAC SUBSCRIBE/REFER, so if another
1613 * transaction is started while previous one still alive, terminate
1614 * the older one.
1615 *
1616 * Sample scenario:
1617 * - subscribe sent to destination that doesn't exist, transaction
1618 * is still retransmitting request, then unsubscribe is sent.
1619 */
1620 if (tsx->role == PJSIP_ROLE_UAC &&
1621 tsx->state == PJSIP_TSX_STATE_CALLING &&
1622 (pjsip_method_cmp(&tsx->method, &sub->method) == 0 ||
1623 pjsip_method_cmp(&tsx->method, &pjsip_subscribe_method) == 0))
1624 {
1625
1626 if (sub->pending_sub &&
1627 sub->pending_sub->state < PJSIP_TSX_STATE_COMPLETED)
1628 {
1629 pj_timer_entry *timer;
1630 pj_str_t *key;
1631 pj_time_val timeout = {0, 0};
1632
1633 PJ_LOG(4,(sub->obj_name,
1634 "Cancelling pending subscription request"));
1635
1636 /* By convention, we use 490 (Request Updated) status code.
1637 * When transaction handler (below) see this status code, it
1638 * will ignore the transaction.
1639 */
1640 /* This unfortunately may cause deadlock, because at the moment
1641 * we are holding dialog's mutex. If a response to this
1642 * transaction is in progress in another thread, that thread
1643 * will deadlock when trying to acquire dialog mutex, because
1644 * it is holding the transaction mutex.
1645 *
1646 * So the solution is to register timer to kill this transaction.
1647 */
1648 //pjsip_tsx_terminate(sub->pending_sub, PJSIP_SC_REQUEST_UPDATED);
1649 timer = PJ_POOL_ZALLOC_T(dlg->pool, pj_timer_entry);
1650 key = PJ_POOL_ALLOC_T(dlg->pool, pj_str_t);
1651 pj_strdup(dlg->pool, key, &sub->pending_sub->transaction_key);
1652 timer->cb = &terminate_timer_cb;
1653 timer->user_data = key;
1654 timer->id = 1;
1655 sub->pending_sub_timer = timer;
1656
1657 pjsip_endpt_schedule_timer(dlg->endpt, timer, &timeout);
1658 }
1659
1660 sub->pending_sub = tsx;
1661
1662 }
1663
1664 return sub;
1665 }
1666
1667
1668 /*
1669 * Create response, adding custome headers and msg body.
1670 */
create_response(pjsip_evsub * sub,pjsip_rx_data * rdata,int st_code,const pj_str_t * st_text,const pjsip_hdr * res_hdr,const pjsip_msg_body * body,pjsip_tx_data ** p_tdata)1671 static pj_status_t create_response( pjsip_evsub *sub,
1672 pjsip_rx_data *rdata,
1673 int st_code,
1674 const pj_str_t *st_text,
1675 const pjsip_hdr *res_hdr,
1676 const pjsip_msg_body *body,
1677 pjsip_tx_data **p_tdata)
1678 {
1679 pjsip_tx_data *tdata;
1680 pjsip_hdr *hdr;
1681 pj_status_t status;
1682
1683 status = pjsip_dlg_create_response(sub->dlg, rdata,
1684 st_code, st_text, &tdata);
1685 if (status != PJ_SUCCESS)
1686 return status;
1687
1688 *p_tdata = tdata;
1689
1690 /* Add response headers. */
1691 hdr = res_hdr->next;
1692 while (hdr != res_hdr) {
1693 pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)
1694 pjsip_hdr_clone(tdata->pool, hdr));
1695 hdr = hdr->next;
1696 }
1697
1698 /* Add msg body, if any */
1699 if (body) {
1700 tdata->msg->body = pjsip_msg_body_clone(tdata->pool, body);
1701 if (tdata->msg->body == NULL) {
1702
1703 PJ_LOG(4,(THIS_FILE, "Error: unable to clone msg body"));
1704
1705 /* Ignore */
1706 return PJ_SUCCESS;
1707 }
1708 }
1709
1710 return PJ_SUCCESS;
1711 }
1712
1713 /*
1714 * Get subscription state from the value of Subscription-State header.
1715 */
get_hdr_state(pjsip_sub_state_hdr * sub_state,pjsip_evsub_state * state,pj_str_t ** state_str)1716 static void get_hdr_state( pjsip_sub_state_hdr *sub_state,
1717 pjsip_evsub_state *state,
1718 pj_str_t **state_str )
1719 {
1720 if (pj_stricmp(&sub_state->sub_state, &STR_TERMINATED)==0) {
1721
1722 *state = PJSIP_EVSUB_STATE_TERMINATED;
1723 *state_str = NULL;
1724
1725 } else if (pj_stricmp(&sub_state->sub_state, &STR_ACTIVE)==0) {
1726
1727 *state = PJSIP_EVSUB_STATE_ACTIVE;
1728 *state_str = NULL;
1729
1730 } else if (pj_stricmp(&sub_state->sub_state, &STR_PENDING)==0) {
1731
1732 *state = PJSIP_EVSUB_STATE_PENDING;
1733 *state_str = NULL;
1734
1735 } else {
1736
1737 *state = PJSIP_EVSUB_STATE_UNKNOWN;
1738 *state_str = &sub_state->sub_state;
1739
1740 }
1741 }
1742
1743 /*
1744 * Transaction event processing by UAC, after subscription is sent.
1745 */
on_tsx_state_uac(pjsip_evsub * sub,pjsip_transaction * tsx,pjsip_event * event)1746 static void on_tsx_state_uac( pjsip_evsub *sub, pjsip_transaction *tsx,
1747 pjsip_event *event )
1748 {
1749
1750 if (pjsip_method_cmp(&tsx->method, &sub->method)==0 ||
1751 pjsip_method_cmp(&tsx->method, &pjsip_subscribe_method)==0)
1752 {
1753
1754 /* Received response to outgoing request that establishes/refresh
1755 * subscription.
1756 */
1757
1758 /* First time initial request is sent. */
1759 if (sub->state == PJSIP_EVSUB_STATE_NULL &&
1760 tsx->state == PJSIP_TSX_STATE_CALLING)
1761 {
1762 set_state(sub, PJSIP_EVSUB_STATE_SENT, NULL, event, NULL);
1763 return;
1764 }
1765
1766 /* Only interested in final response */
1767 if (tsx->state != PJSIP_TSX_STATE_COMPLETED &&
1768 tsx->state != PJSIP_TSX_STATE_TERMINATED)
1769 {
1770 return;
1771 }
1772
1773 /* Clear pending subscription */
1774 if (tsx == sub->pending_sub) {
1775 sub->pending_sub = NULL;
1776 } else if (sub->pending_sub != NULL) {
1777 /* This SUBSCRIBE transaction has been "renewed" with another
1778 * SUBSCRIBE, so we can just ignore this. For example, user
1779 * sent SUBSCRIBE followed immediately with UN-SUBSCRIBE.
1780 */
1781 return;
1782 }
1783
1784 /* Handle authentication. */
1785 if (tsx->status_code==401 || tsx->status_code==407) {
1786 pjsip_tx_data *tdata;
1787 pj_status_t status;
1788
1789 if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
1790 /* Previously failed transaction has terminated */
1791 return;
1792 }
1793
1794 status = pjsip_auth_clt_reinit_req(&sub->dlg->auth_sess,
1795 event->body.tsx_state.src.rdata,
1796 tsx->last_tx, &tdata);
1797 if (status == PJ_SUCCESS)
1798 status = pjsip_dlg_send_request(sub->dlg, tdata, -1, NULL);
1799
1800 if (status != PJ_SUCCESS) {
1801 /* Authentication failed! */
1802 set_state(sub, PJSIP_EVSUB_STATE_TERMINATED,
1803 NULL, event, &tsx->status_text);
1804 return;
1805 }
1806
1807 return;
1808 }
1809
1810 if (tsx->status_code/100 == 2) {
1811
1812 /* Successfull SUBSCRIBE request!
1813 * This could be:
1814 * - response to initial SUBSCRIBE request
1815 * - response to subsequent refresh
1816 * - response to unsubscription
1817 */
1818
1819 if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
1820 /* Ignore; this transaction has been processed before */
1821 return;
1822 }
1823
1824 /* Update UAC refresh time, if response contains Expires header,
1825 * only when we're not unsubscribing.
1826 */
1827 if (sub->expires->ivalue != 0) {
1828 pjsip_msg *msg;
1829 pjsip_expires_hdr *expires;
1830
1831 msg = event->body.tsx_state.src.rdata->msg_info.msg;
1832 expires = (pjsip_expires_hdr*)
1833 pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL);
1834 if (expires) {
1835 sub->expires->ivalue = expires->ivalue;
1836 }
1837 }
1838
1839 /* Update time */
1840 update_expires(sub, sub->expires->ivalue);
1841
1842 /* Start UAC refresh timer, only when we're not unsubscribing */
1843 if (sub->expires->ivalue != 0) {
1844 unsigned timeout = (sub->expires->ivalue > TIME_UAC_REFRESH) ?
1845 sub->expires->ivalue - TIME_UAC_REFRESH : sub->expires->ivalue;
1846
1847 /* Reduce timeout by about 1 - 10 secs (randomized) */
1848 if (timeout > 10)
1849 timeout += -10 + (pj_rand() % 10);
1850
1851 PJ_LOG(5,(sub->obj_name, "Will refresh in %d seconds",
1852 timeout));
1853 set_timer(sub, TIMER_TYPE_UAC_REFRESH, timeout);
1854
1855 } else {
1856 /* Otherwise set timer to terminate client subscription when
1857 * NOTIFY to end subscription is not received.
1858 */
1859 set_timer(sub, TIMER_TYPE_UAC_TERMINATE, TIME_UAC_TERMINATE);
1860 }
1861
1862 /* Set state, if necessary */
1863 pj_assert(sub->state != PJSIP_EVSUB_STATE_NULL);
1864 if (sub->state == PJSIP_EVSUB_STATE_SENT) {
1865 set_state(sub, PJSIP_EVSUB_STATE_ACCEPTED, NULL, event, NULL);
1866 }
1867
1868 } else {
1869
1870 /* Failed SUBSCRIBE request!
1871 *
1872 * The RFC 3265 says that if outgoing SUBSCRIBE fails with status
1873 * other than 481, the subscription is still considered valid for
1874 * the duration of the last Expires.
1875 *
1876 * Since we send refresh about 5 seconds (TIME_UAC_REFRESH) before
1877 * expiration, theoritically the expiration is still valid for the
1878 * next 5 seconds even when we receive non-481 failed response.
1879 *
1880 * Ah, what the heck!
1881 *
1882 * Just terminate now!
1883 *
1884 */
1885
1886 if (sub->state == PJSIP_EVSUB_STATE_TERMINATED) {
1887 /* Ignore, has been handled before */
1888 return;
1889 }
1890
1891 /* Ignore 490 (Request Updated) status.
1892 * This happens when application sends SUBSCRIBE/REFER while
1893 * another one is still in progress.
1894 */
1895 if (tsx->status_code == PJSIP_SC_REQUEST_UPDATED) {
1896 return;
1897 }
1898
1899 /* Set state to TERMINATED */
1900 set_state(sub, PJSIP_EVSUB_STATE_TERMINATED,
1901 NULL, event, &tsx->status_text);
1902
1903 }
1904
1905 } else if (pjsip_method_cmp(&tsx->method, &pjsip_notify_method) == 0) {
1906
1907 /* Incoming NOTIFY.
1908 * This can be the result of:
1909 * - Initial subscription response
1910 * - UAS updating the resource info.
1911 * - Unsubscription response.
1912 */
1913 int st_code = 200;
1914 pj_str_t *st_text = NULL;
1915 pjsip_hdr res_hdr;
1916 pjsip_msg_body *body = NULL;
1917
1918 pjsip_rx_data *rdata;
1919 pjsip_msg *msg;
1920 pjsip_sub_state_hdr *sub_state;
1921
1922 pjsip_evsub_state new_state;
1923 pj_str_t *new_state_str;
1924
1925 pjsip_tx_data *tdata;
1926 pj_status_t status;
1927
1928 /* Only want to handle initial NOTIFY receive event. */
1929 if (tsx->state != PJSIP_TSX_STATE_TRYING)
1930 return;
1931
1932
1933 rdata = event->body.tsx_state.src.rdata;
1934 msg = rdata->msg_info.msg;
1935
1936 pj_list_init(&res_hdr);
1937
1938 /* Get subscription state header. */
1939 sub_state = (pjsip_sub_state_hdr*)
1940 pjsip_msg_find_hdr_by_name(msg, &STR_SUB_STATE, NULL);
1941 if (sub_state == NULL) {
1942
1943 pjsip_warning_hdr *warn_hdr;
1944 pj_str_t warn_text = { "Missing Subscription-State header", 33};
1945
1946 /* Bad request! Add warning header. */
1947 st_code = PJSIP_SC_BAD_REQUEST;
1948 warn_hdr = pjsip_warning_hdr_create(rdata->tp_info.pool, 399,
1949 pjsip_endpt_name(sub->endpt),
1950 &warn_text);
1951 pj_list_push_back(&res_hdr, warn_hdr);
1952 }
1953
1954 /* Call application registered callback to handle incoming NOTIFY,
1955 * if any.
1956 */
1957 if (st_code==200 && sub->user.on_rx_notify && sub->call_cb) {
1958 (*sub->user.on_rx_notify)(sub, rdata, &st_code, &st_text,
1959 &res_hdr, &body);
1960
1961 /* Application MUST specify final response! */
1962 PJ_ASSERT_ON_FAIL(st_code >= 200, {st_code=200; });
1963
1964 /* Must be a valid status code */
1965 PJ_ASSERT_ON_FAIL(st_code <= 699, {st_code=500; });
1966 }
1967
1968
1969 /* If non-2xx should be returned, then send the response.
1970 * No need to update server subscription state.
1971 */
1972 if (st_code >= 300) {
1973 status = create_response(sub, rdata, st_code, st_text, &res_hdr,
1974 body, &tdata);
1975 if (status == PJ_SUCCESS) {
1976 status = pjsip_dlg_send_response(sub->dlg, tsx, tdata);
1977 }
1978
1979 /* Start timer to terminate subscription, just in case server
1980 * is not able to generate NOTIFY to our response.
1981 */
1982 if (status == PJ_SUCCESS) {
1983 unsigned timeout = TIME_UAC_WAIT_NOTIFY;
1984 set_timer(sub, TIMER_TYPE_UAC_WAIT_NOTIFY, timeout);
1985 } else {
1986 char errmsg[PJ_ERR_MSG_SIZE];
1987 pj_str_t reason;
1988
1989 reason = pj_strerror(status, errmsg, sizeof(errmsg));
1990 set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, NULL,
1991 &reason);
1992 }
1993
1994 return;
1995 }
1996
1997 /* Update expiration from the value of expires param in
1998 * Subscription-State header, but ONLY when subscription state
1999 * is "active" or "pending", AND the header contains expires param.
2000 */
2001 if (sub->expires->ivalue != 0 &&
2002 sub_state->expires_param != PJSIP_EXPIRES_NOT_SPECIFIED &&
2003 (pj_stricmp(&sub_state->sub_state, &STR_ACTIVE)==0 ||
2004 pj_stricmp(&sub_state->sub_state, &STR_PENDING)==0))
2005 {
2006 unsigned next_refresh = sub_state->expires_param;
2007 unsigned timeout;
2008
2009 update_expires(sub, next_refresh);
2010
2011 /* Start UAC refresh timer, only when we're not unsubscribing */
2012 timeout = (next_refresh > TIME_UAC_REFRESH) ?
2013 next_refresh - TIME_UAC_REFRESH : next_refresh;
2014
2015 PJ_LOG(5,(sub->obj_name, "Will refresh in %d seconds", timeout));
2016 set_timer(sub, TIMER_TYPE_UAC_REFRESH, timeout);
2017 }
2018
2019 /* Find out the state */
2020 get_hdr_state(sub_state, &new_state, &new_state_str);
2021
2022 /* Send response. */
2023 status = create_response(sub, rdata, st_code, st_text, &res_hdr,
2024 body, &tdata);
2025 if (status == PJ_SUCCESS)
2026 status = pjsip_dlg_send_response(sub->dlg, tsx, tdata);
2027
2028 /* Set the state */
2029 if (status == PJ_SUCCESS) {
2030 set_state(sub, new_state, new_state_str, event,
2031 &sub_state->reason_param);
2032 } else {
2033 char errmsg[PJ_ERR_MSG_SIZE];
2034 pj_str_t reason;
2035
2036 reason = pj_strerror(status, errmsg, sizeof(errmsg));
2037 set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, event,
2038 &reason);
2039 }
2040
2041
2042 } else {
2043
2044 /*
2045 * Unexpected method!
2046 */
2047 PJ_LOG(4,(sub->obj_name, "Unexpected transaction method %.*s",
2048 (int)tsx->method.name.slen, tsx->method.name.ptr));
2049 }
2050 }
2051
2052
2053 /*
2054 * Transaction event processing by UAS, after subscription is accepted.
2055 */
on_tsx_state_uas(pjsip_evsub * sub,pjsip_transaction * tsx,pjsip_event * event)2056 static void on_tsx_state_uas( pjsip_evsub *sub, pjsip_transaction *tsx,
2057 pjsip_event *event)
2058 {
2059
2060 if (pjsip_method_cmp(&tsx->method, &sub->method) == 0 ||
2061 pjsip_method_cmp(&tsx->method, &pjsip_subscribe_method) == 0)
2062 {
2063
2064 /*
2065 * Incoming request (e.g. SUBSCRIBE or REFER) to refresh subsciption.
2066 *
2067 */
2068 pjsip_rx_data *rdata;
2069 pjsip_event_hdr *event_hdr;
2070 pjsip_expires_hdr *expires;
2071 pjsip_msg *msg;
2072 pjsip_tx_data *tdata;
2073 int st_code = 200;
2074 pj_str_t *st_text = NULL;
2075 pjsip_hdr res_hdr;
2076 pjsip_msg_body *body = NULL;
2077 pjsip_evsub_state old_state;
2078 pj_str_t old_state_str;
2079 pj_str_t reason = { NULL, 0 };
2080 pj_status_t status;
2081
2082
2083 /* Only wants to handle the first event when the request is
2084 * received.
2085 */
2086 if (tsx->state != PJSIP_TSX_STATE_TRYING)
2087 return;
2088
2089 rdata = event->body.tsx_state.src.rdata;
2090 msg = rdata->msg_info.msg;
2091
2092 /* Set expiration time based on client request (in Expires header),
2093 * or package default expiration time.
2094 */
2095 event_hdr = (pjsip_event_hdr*)
2096 pjsip_msg_find_hdr_by_names(msg, &STR_EVENT,
2097 &STR_EVENT, NULL);
2098 expires = (pjsip_expires_hdr*)
2099 pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL);
2100 if (event_hdr && expires) {
2101 struct evpkg *evpkg;
2102
2103 evpkg = find_pkg(&event_hdr->event_type);
2104 if (evpkg) {
2105 if (expires->ivalue < evpkg->pkg_expires)
2106 sub->expires->ivalue = expires->ivalue;
2107 else
2108 sub->expires->ivalue = evpkg->pkg_expires;
2109 }
2110 }
2111
2112 /* Update time (before calling on_rx_refresh, since application
2113 * will send NOTIFY.
2114 */
2115 update_expires(sub, sub->expires->ivalue);
2116
2117
2118 /* Save old state.
2119 * If application respond with non-2xx, revert to old state.
2120 */
2121 old_state = sub->state;
2122 old_state_str = sub->state_str;
2123
2124 if (sub->expires->ivalue == 0) {
2125 sub->state = PJSIP_EVSUB_STATE_TERMINATED;
2126 sub->state_str = evsub_state_names[sub->state];
2127 } else if (sub->state == PJSIP_EVSUB_STATE_NULL) {
2128 sub->state = PJSIP_EVSUB_STATE_ACCEPTED;
2129 sub->state_str = evsub_state_names[sub->state];
2130 }
2131
2132 /* Call application's on_rx_refresh, just in case it wants to send
2133 * response other than 200 (OK)
2134 */
2135 pj_list_init(&res_hdr);
2136
2137 if (sub->user.on_rx_refresh && sub->call_cb) {
2138 (*sub->user.on_rx_refresh)(sub, rdata, &st_code, &st_text,
2139 &res_hdr, &body);
2140 }
2141
2142 /* Application MUST specify final response! */
2143 PJ_ASSERT_ON_FAIL(st_code >= 200, {st_code=200; });
2144
2145 /* Must be a valid status code */
2146 PJ_ASSERT_ON_FAIL(st_code <= 699, {st_code=500; });
2147
2148
2149 /* Create and send response */
2150 status = create_response(sub, rdata, st_code, st_text, &res_hdr,
2151 body, &tdata);
2152 if (status == PJ_SUCCESS) {
2153 /* Add expires header: */
2154 pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)
2155 pjsip_hdr_shallow_clone(tdata->pool,
2156 sub->expires));
2157
2158 /* Send */
2159 status = pjsip_dlg_send_response(sub->dlg, tsx, tdata);
2160 }
2161
2162 /* Update state or revert state */
2163 if (st_code/100==2) {
2164
2165 if (sub->expires->ivalue == 0) {
2166 set_state(sub, sub->state, NULL, event, &reason);
2167 } else if (sub->state == PJSIP_EVSUB_STATE_NULL) {
2168 set_state(sub, sub->state, NULL, event, &reason);
2169 }
2170
2171 /* Set UAS timeout timer, when state is not terminated. */
2172 if (sub->state != PJSIP_EVSUB_STATE_TERMINATED) {
2173 PJ_LOG(5,(sub->obj_name, "UAS timeout in %d seconds",
2174 sub->expires->ivalue));
2175 set_timer(sub, TIMER_TYPE_UAS_TIMEOUT,
2176 sub->expires->ivalue);
2177 }
2178
2179 } else {
2180 sub->state = old_state;
2181 sub->state_str = old_state_str;
2182 }
2183
2184
2185 } else if (pjsip_method_cmp(&tsx->method, &pjsip_notify_method)==0) {
2186
2187 /* Handle authentication */
2188 if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
2189 (tsx->status_code==401 || tsx->status_code==407))
2190 {
2191 pjsip_tx_data *tdata;
2192 pj_status_t status;
2193 pjsip_rx_data *rdata = event->body.tsx_state.src.rdata;
2194
2195 /* Handled by other module already (e.g: invite module) */
2196 if (tsx->last_tx->auth_retry)
2197 return;
2198
2199 status = pjsip_auth_clt_reinit_req(&sub->dlg->auth_sess, rdata,
2200 tsx->last_tx, &tdata);
2201 if (status == PJ_SUCCESS)
2202 status = pjsip_dlg_send_request(sub->dlg, tdata, -1, NULL);
2203
2204 if (status != PJ_SUCCESS) {
2205 /* Can't authenticate. Terminate session (?) */
2206 set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, NULL,
2207 &tsx->status_text);
2208 }
2209 return;
2210
2211 }
2212
2213 if (sub->state == PJSIP_EVSUB_STATE_TERMINATED)
2214 return;
2215
2216 /* NOTIFY failure check */
2217 if (tsx->status_code/100 != 2) {
2218 pj_bool_t should_terminate_sub = PJ_FALSE;
2219
2220 if (event->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
2221 if (tsx->status_code == 481) {
2222 should_terminate_sub = PJ_TRUE;
2223 } else {
2224 pjsip_retry_after_hdr *retry_after;
2225 pjsip_rx_data *rdata = event->body.tsx_state.src.rdata;
2226 pjsip_msg *msg = rdata->msg_info.msg;
2227
2228 retry_after = (pjsip_retry_after_hdr*)
2229 pjsip_msg_find_hdr_by_name(msg, &STR_RETRY_AFTER, NULL);
2230
2231 if (!retry_after) {
2232 should_terminate_sub = PJ_TRUE;
2233 }
2234 }
2235 } else if (event->body.tsx_state.type == PJSIP_EVENT_TIMER) {
2236 if (tsx->status_code == 408) {
2237 should_terminate_sub = PJ_TRUE;
2238 }
2239 }
2240
2241 /*
2242 * Terminate event usage if we receive non 2xx without retry_after
2243 * parameter, 481, 408 responses.
2244 */
2245 if (should_terminate_sub) {
2246 set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, event,
2247 &tsx->status_text);
2248 return;
2249 }
2250 }
2251 } else {
2252
2253 /*
2254 * Unexpected method!
2255 */
2256 PJ_LOG(4,(sub->obj_name, "Unexpected transaction method %.*s",
2257 (int)tsx->method.name.slen, tsx->method.name.ptr));
2258
2259 }
2260 }
2261
2262
2263 /*
2264 * Notification when transaction state has changed!
2265 */
mod_evsub_on_tsx_state(pjsip_transaction * tsx,pjsip_event * event)2266 static void mod_evsub_on_tsx_state(pjsip_transaction *tsx, pjsip_event *event)
2267 {
2268 pjsip_evsub *sub = pjsip_tsx_get_evsub(tsx);
2269
2270 if (sub == NULL) {
2271 sub = on_new_transaction(tsx, event);
2272 if (sub == NULL)
2273 return;
2274 }
2275
2276
2277 /* Call on_tsx_state callback, if any. */
2278 if (sub->user.on_tsx_state && sub->call_cb)
2279 (*sub->user.on_tsx_state)(sub, tsx, event);
2280
2281
2282 /* Process the event: */
2283
2284 if (sub->role == PJSIP_ROLE_UAC) {
2285 on_tsx_state_uac(sub, tsx, event);
2286 } else {
2287 on_tsx_state_uas(sub, tsx, event);
2288 }
2289
2290
2291 /* Check transaction TERMINATE event */
2292 if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
2293
2294 --sub->pending_tsx;
2295
2296 if (sub->state == PJSIP_EVSUB_STATE_TERMINATED &&
2297 sub->pending_tsx == 0)
2298 {
2299 evsub_destroy(sub);
2300 }
2301
2302 }
2303 }
2304
2305
2306