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