~ubuntu-branches/ubuntu/trusty/sflphone/trusty

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (4.3.4 sid)
  • Revision ID: package-import@ubuntu.com-20140128182336-jrsv0k9u6cawc068
Tags: 1.3.0-1
* New upstream release 
  - Fixes "New Upstream Release" (Closes: #735846)
  - Fixes "Ringtone does not stop" (Closes: #727164)
  - Fixes "[sflphone-kde] crash on startup" (Closes: #718178)
  - Fixes "sflphone GUI crashes when call is hung up" (Closes: #736583)
* Build-Depends: ensure GnuTLS 2.6
  - libucommon-dev (>= 6.0.7-1.1), libccrtp-dev (>= 2.0.6-3)
  - Fixes "FTBFS Build-Depends libgnutls{26,28}-dev" (Closes: #722040)
* Fix "boost 1.49 is going away" unversioned Build-Depends: (Closes: #736746)
* Add Build-Depends: libsndfile-dev, nepomuk-core-dev

Show diffs side-by-side

added added

removed removed

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