~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.2.1/pjsip/src/pjsip-simple/evsub.c

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2015-01-07 14:51:16 UTC
  • mfrom: (4.3.5 sid)
  • Revision ID: package-import@ubuntu.com-20150107145116-yxnafinf4lrdvrmx
Tags: 1.4.1-0.1ubuntu1
* Merge with Debian, remaining changes:
 - Drop soprano, nepomuk build-dep
* Drop ubuntu patches, now upstream

Show diffs side-by-side

added added

removed removed

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