~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/publishc.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: publishc.c 4173 2012-06-20 10:39:05Z ming $ */
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/publish.h>
21
 
#include <pjsip/sip_auth.h>
22
 
#include <pjsip/sip_endpoint.h>
23
 
#include <pjsip/sip_errno.h>
24
 
#include <pjsip/sip_event.h>
25
 
#include <pjsip/sip_msg.h>
26
 
#include <pjsip/sip_transaction.h>
27
 
#include <pjsip/sip_uri.h>
28
 
#include <pjsip/sip_util.h>
29
 
#include <pj/assert.h>
30
 
#include <pj/guid.h>
31
 
#include <pj/log.h>
32
 
#include <pj/os.h>
33
 
#include <pj/pool.h>
34
 
#include <pj/rand.h>
35
 
#include <pj/string.h>
36
 
#include <pj/timer.h>
37
 
 
38
 
 
39
 
#define REFRESH_TIMER           1
40
 
#define DELAY_BEFORE_REFRESH    PJSIP_PUBLISHC_DELAY_BEFORE_REFRESH
41
 
#define THIS_FILE               "publishc.c"
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_PUBLISH_METHOD = PJSIP_OTHER_METHOD,
50
 
};
51
 
 
52
 
const pjsip_method pjsip_publish_method =
53
 
{
54
 
    (pjsip_method_e)PJSIP_PUBLISH_METHOD,
55
 
    { "PUBLISH", 7 }
56
 
};
57
 
 
58
 
 
59
 
/**
60
 
 * Pending request list.
61
 
 */
62
 
typedef struct pending_publish
63
 
{
64
 
    PJ_DECL_LIST_MEMBER(pjsip_tx_data);
65
 
} pending_publish;
66
 
 
67
 
 
68
 
/**
69
 
 * SIP client publication structure.
70
 
 */
71
 
struct pjsip_publishc
72
 
{
73
 
    pj_pool_t                   *pool;
74
 
    pjsip_endpoint              *endpt;
75
 
    pj_bool_t                    _delete_flag;
76
 
    int                          pending_tsx;
77
 
    pj_bool_t                    in_callback;
78
 
    pj_mutex_t                  *mutex;
79
 
 
80
 
    pjsip_publishc_opt           opt;
81
 
    void                        *token;
82
 
    pjsip_publishc_cb           *cb;
83
 
 
84
 
    pj_str_t                     event;
85
 
    pj_str_t                     str_target_uri;
86
 
    pjsip_uri                   *target_uri;
87
 
    pjsip_cid_hdr               *cid_hdr;
88
 
    pjsip_cseq_hdr              *cseq_hdr;
89
 
    pj_str_t                     from_uri;
90
 
    pjsip_from_hdr              *from_hdr;
91
 
    pjsip_to_hdr                *to_hdr;
92
 
    pj_str_t                     etag;
93
 
    pjsip_expires_hdr           *expires_hdr;
94
 
    pj_uint32_t                  expires;
95
 
    pjsip_route_hdr              route_set;
96
 
    pjsip_hdr                    usr_hdr;
97
 
    pjsip_host_port              via_addr;
98
 
    const void                  *via_tp;
99
 
 
100
 
    /* Authorization sessions. */
101
 
    pjsip_auth_clt_sess          auth_sess;
102
 
 
103
 
    /* Auto refresh publication. */
104
 
    pj_bool_t                    auto_refresh;
105
 
    pj_time_val                  last_refresh;
106
 
    pj_time_val                  next_refresh;
107
 
    pj_timer_entry               timer;
108
 
 
109
 
    /* Pending PUBLISH request */
110
 
    pending_publish              pending_reqs;
111
 
};
112
 
 
113
 
 
114
 
PJ_DEF(void) pjsip_publishc_opt_default(pjsip_publishc_opt *opt)
115
 
{
116
 
    pj_bzero(opt, sizeof(*opt));
117
 
    opt->queue_request = PJSIP_PUBLISHC_QUEUE_REQUEST;
118
 
}
119
 
 
120
 
 
121
 
/*
122
 
 * Initialize client publication module.
123
 
 */
124
 
PJ_DEF(pj_status_t) pjsip_publishc_init_module(pjsip_endpoint *endpt)
125
 
{
126
 
    /* Note:
127
 
        Commented out the capability registration below, since it's
128
 
        wrong to include PUBLISH in Allow header of INVITE requests/
129
 
        responses.
130
 
 
131
 
        13.2.1 Creating the Initial INVITE
132
 
          An Allow header field (Section 20.5) SHOULD be present in the
133
 
          INVITE. It indicates what methods can be invoked within a dialog
134
 
 
135
 
        20.5 Allow
136
 
          The Allow header field lists the set of methods supported by the
137
 
          UA generating the message.
138
 
 
139
 
        While the semantic of Allow header in non-dialog requests is unclear,
140
 
        it's probably best not to include PUBLISH in Allow header for now
141
 
        until we can find out how to customize the inclusion of methods in
142
 
        Allow header for in-dialog vs out-dialog requests.
143
 
 
144
 
    return pjsip_endpt_add_capability( endpt, NULL, PJSIP_H_ALLOW, NULL,
145
 
                                       1, &pjsip_publish_method.name);
146
 
     */
147
 
    PJ_UNUSED_ARG(endpt);
148
 
    return PJ_SUCCESS;
149
 
}
150
 
 
151
 
 
152
 
PJ_DEF(pj_status_t) pjsip_publishc_create( pjsip_endpoint *endpt,
153
 
                                           const pjsip_publishc_opt *opt,
154
 
                                           void *token,
155
 
                                           pjsip_publishc_cb *cb,
156
 
                                           pjsip_publishc **p_pubc)
157
 
{
158
 
    pj_pool_t *pool;
159
 
    pjsip_publishc *pubc;
160
 
    pjsip_publishc_opt default_opt;
161
 
    pj_status_t status;
162
 
 
163
 
    /* Verify arguments. */
164
 
    PJ_ASSERT_RETURN(endpt && cb && p_pubc, PJ_EINVAL);
165
 
 
166
 
    pool = pjsip_endpt_create_pool(endpt, "pubc%p", 1024, 1024);
167
 
    PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
168
 
 
169
 
    pubc = PJ_POOL_ZALLOC_T(pool, pjsip_publishc);
170
 
 
171
 
    pubc->pool = pool;
172
 
    pubc->endpt = endpt;
173
 
    pubc->token = token;
174
 
    pubc->cb = cb;
175
 
    pubc->expires = PJSIP_PUBC_EXPIRATION_NOT_SPECIFIED;
176
 
 
177
 
    if (!opt) {
178
 
        pjsip_publishc_opt_default(&default_opt);
179
 
        opt = &default_opt;
180
 
    }
181
 
    pj_memcpy(&pubc->opt, opt, sizeof(*opt));
182
 
    pj_list_init(&pubc->pending_reqs);
183
 
 
184
 
    status = pj_mutex_create_recursive(pubc->pool, "pubc%p", &pubc->mutex);
185
 
    if (status != PJ_SUCCESS) {
186
 
        pj_pool_release(pool);
187
 
        return status;
188
 
    }
189
 
 
190
 
    status = pjsip_auth_clt_init(&pubc->auth_sess, endpt, pubc->pool, 0);
191
 
    if (status != PJ_SUCCESS) {
192
 
        pj_mutex_destroy(pubc->mutex);
193
 
        pj_pool_release(pool);
194
 
        return status;
195
 
    }
196
 
 
197
 
    pj_list_init(&pubc->route_set);
198
 
    pj_list_init(&pubc->usr_hdr);
199
 
 
200
 
    /* Done */
201
 
    *p_pubc = pubc;
202
 
    return PJ_SUCCESS;
203
 
}
204
 
 
205
 
 
206
 
PJ_DEF(pj_status_t) pjsip_publishc_destroy(pjsip_publishc *pubc)
207
 
{
208
 
    PJ_ASSERT_RETURN(pubc, PJ_EINVAL);
209
 
 
210
 
    if (pubc->pending_tsx || pubc->in_callback) {
211
 
        pubc->_delete_flag = 1;
212
 
        pubc->cb = NULL;
213
 
    } else {
214
 
        /* Cancel existing timer, if any */
215
 
        if (pubc->timer.id != 0) {
216
 
            pjsip_endpt_cancel_timer(pubc->endpt, &pubc->timer);
217
 
            pubc->timer.id = 0;
218
 
        }
219
 
 
220
 
        if (pubc->mutex)
221
 
            pj_mutex_destroy(pubc->mutex);
222
 
        pjsip_endpt_release_pool(pubc->endpt, pubc->pool);
223
 
    }
224
 
 
225
 
    return PJ_SUCCESS;
226
 
}
227
 
 
228
 
 
229
 
PJ_DEF(pj_pool_t*) pjsip_publishc_get_pool(pjsip_publishc *pubc)
230
 
{
231
 
    return pubc->pool;
232
 
}
233
 
 
234
 
static void set_expires( pjsip_publishc *pubc, pj_uint32_t expires)
235
 
{
236
 
    if (expires != pubc->expires &&
237
 
        expires != PJSIP_PUBC_EXPIRATION_NOT_SPECIFIED)
238
 
    {
239
 
        pubc->expires_hdr = pjsip_expires_hdr_create(pubc->pool, expires);
240
 
    } else {
241
 
        pubc->expires_hdr = NULL;
242
 
    }
243
 
}
244
 
 
245
 
 
246
 
PJ_DEF(pj_status_t) pjsip_publishc_init(pjsip_publishc *pubc,
247
 
                                        const pj_str_t *event,
248
 
                                        const pj_str_t *target_uri,
249
 
                                        const pj_str_t *from_uri,
250
 
                                        const pj_str_t *to_uri,
251
 
                                        pj_uint32_t expires)
252
 
{
253
 
    pj_str_t tmp;
254
 
 
255
 
    PJ_ASSERT_RETURN(pubc && event && target_uri && from_uri && to_uri &&
256
 
                     expires, PJ_EINVAL);
257
 
 
258
 
    /* Copy event type */
259
 
    pj_strdup_with_null(pubc->pool, &pubc->event, event);
260
 
 
261
 
    /* Copy server URL. */
262
 
    pj_strdup_with_null(pubc->pool, &pubc->str_target_uri, target_uri);
263
 
 
264
 
    /* Set server URL. */
265
 
    tmp = pubc->str_target_uri;
266
 
    pubc->target_uri = pjsip_parse_uri( pubc->pool, tmp.ptr, tmp.slen, 0);
267
 
    if (pubc->target_uri == NULL) {
268
 
        return PJSIP_EINVALIDURI;
269
 
    }
270
 
 
271
 
    /* Set "From" header. */
272
 
    pj_strdup_with_null(pubc->pool, &pubc->from_uri, from_uri);
273
 
    tmp = pubc->from_uri;
274
 
    pubc->from_hdr = pjsip_from_hdr_create(pubc->pool);
275
 
    pubc->from_hdr->uri = pjsip_parse_uri(pubc->pool, tmp.ptr, tmp.slen,
276
 
                                          PJSIP_PARSE_URI_AS_NAMEADDR);
277
 
    if (!pubc->from_hdr->uri) {
278
 
        return PJSIP_EINVALIDURI;
279
 
    }
280
 
 
281
 
    /* Set "To" header. */
282
 
    pj_strdup_with_null(pubc->pool, &tmp, to_uri);
283
 
    pubc->to_hdr = pjsip_to_hdr_create(pubc->pool);
284
 
    pubc->to_hdr->uri = pjsip_parse_uri(pubc->pool, tmp.ptr, tmp.slen,
285
 
                                        PJSIP_PARSE_URI_AS_NAMEADDR);
286
 
    if (!pubc->to_hdr->uri) {
287
 
        return PJSIP_EINVALIDURI;
288
 
    }
289
 
 
290
 
 
291
 
    /* Set "Expires" header, if required. */
292
 
    set_expires( pubc, expires);
293
 
 
294
 
    /* Set "Call-ID" header. */
295
 
    pubc->cid_hdr = pjsip_cid_hdr_create(pubc->pool);
296
 
    pj_create_unique_string(pubc->pool, &pubc->cid_hdr->id);
297
 
 
298
 
    /* Set "CSeq" header. */
299
 
    pubc->cseq_hdr = pjsip_cseq_hdr_create(pubc->pool);
300
 
    pubc->cseq_hdr->cseq = pj_rand() % 0xFFFF;
301
 
    pjsip_method_set( &pubc->cseq_hdr->method, PJSIP_REGISTER_METHOD);
302
 
 
303
 
    /* Done. */
304
 
    return PJ_SUCCESS;
305
 
}
306
 
 
307
 
PJ_DEF(pj_status_t) pjsip_publishc_set_credentials( pjsip_publishc *pubc,
308
 
                                                int count,
309
 
                                                const pjsip_cred_info cred[] )
310
 
{
311
 
    PJ_ASSERT_RETURN(pubc && count && cred, PJ_EINVAL);
312
 
    return pjsip_auth_clt_set_credentials(&pubc->auth_sess, count, cred);
313
 
}
314
 
 
315
 
PJ_DEF(pj_status_t) pjsip_publishc_set_route_set( pjsip_publishc *pubc,
316
 
                                              const pjsip_route_hdr *route_set)
317
 
{
318
 
    const pjsip_route_hdr *chdr;
319
 
 
320
 
    PJ_ASSERT_RETURN(pubc && route_set, PJ_EINVAL);
321
 
 
322
 
    pj_list_init(&pubc->route_set);
323
 
 
324
 
    chdr = route_set->next;
325
 
    while (chdr != route_set) {
326
 
        pj_list_push_back(&pubc->route_set, pjsip_hdr_clone(pubc->pool, chdr));
327
 
        chdr = chdr->next;
328
 
    }
329
 
 
330
 
    return PJ_SUCCESS;
331
 
}
332
 
 
333
 
PJ_DEF(pj_status_t) pjsip_publishc_set_headers( pjsip_publishc *pubc,
334
 
                                                const pjsip_hdr *hdr_list)
335
 
{
336
 
    const pjsip_hdr *h;
337
 
 
338
 
    PJ_ASSERT_RETURN(pubc && hdr_list, PJ_EINVAL);
339
 
 
340
 
    pj_list_init(&pubc->usr_hdr);
341
 
    h = hdr_list->next;
342
 
    while (h != hdr_list) {
343
 
        pj_list_push_back(&pubc->usr_hdr, pjsip_hdr_clone(pubc->pool, h));
344
 
        h = h->next;
345
 
    }
346
 
 
347
 
    return PJ_SUCCESS;
348
 
}
349
 
 
350
 
PJ_DEF(pj_status_t) pjsip_publishc_set_via_sent_by(pjsip_publishc *pubc,
351
 
                                                   pjsip_host_port *via_addr,
352
 
                                                   pjsip_transport *via_tp)
353
 
{
354
 
    PJ_ASSERT_RETURN(pubc, PJ_EINVAL);
355
 
 
356
 
    if (!via_addr)
357
 
        pj_bzero(&pubc->via_addr, sizeof(pubc->via_addr));
358
 
    else
359
 
        pubc->via_addr = *via_addr;
360
 
    pubc->via_tp = via_tp;
361
 
 
362
 
    return PJ_SUCCESS;
363
 
}
364
 
 
365
 
static pj_status_t create_request(pjsip_publishc *pubc,
366
 
                                  pjsip_tx_data **p_tdata)
367
 
{
368
 
    const pj_str_t STR_EVENT = { "Event", 5 };
369
 
    pj_status_t status;
370
 
    pjsip_generic_string_hdr *hdr;
371
 
    pjsip_tx_data *tdata;
372
 
 
373
 
    PJ_ASSERT_RETURN(pubc && p_tdata, PJ_EINVAL);
374
 
 
375
 
    /* Create the request. */
376
 
    status = pjsip_endpt_create_request_from_hdr( pubc->endpt,
377
 
                                                  &pjsip_publish_method,
378
 
                                                  pubc->target_uri,
379
 
                                                  pubc->from_hdr,
380
 
                                                  pubc->to_hdr,
381
 
                                                  NULL,
382
 
                                                  pubc->cid_hdr,
383
 
                                                  pubc->cseq_hdr->cseq,
384
 
                                                  NULL,
385
 
                                                  &tdata);
386
 
    if (status != PJ_SUCCESS)
387
 
        return status;
388
 
 
389
 
    /* Add cached authorization headers. */
390
 
    pjsip_auth_clt_init_req( &pubc->auth_sess, tdata );
391
 
 
392
 
    /* Add Route headers from route set, ideally after Via header */
393
 
    if (!pj_list_empty(&pubc->route_set)) {
394
 
        pjsip_hdr *route_pos;
395
 
        const pjsip_route_hdr *route;
396
 
 
397
 
        route_pos = (pjsip_hdr*)
398
 
                    pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
399
 
        if (!route_pos)
400
 
            route_pos = &tdata->msg->hdr;
401
 
 
402
 
        route = pubc->route_set.next;
403
 
        while (route != &pubc->route_set) {
404
 
            pjsip_hdr *new_hdr = (pjsip_hdr*)
405
 
                                 pjsip_hdr_shallow_clone(tdata->pool, route);
406
 
            pj_list_insert_after(route_pos, new_hdr);
407
 
            route_pos = new_hdr;
408
 
            route = route->next;
409
 
        }
410
 
    }
411
 
 
412
 
    /* Add Event header */
413
 
    hdr = pjsip_generic_string_hdr_create(tdata->pool, &STR_EVENT,
414
 
                                          &pubc->event);
415
 
    if (hdr)
416
 
        pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);
417
 
 
418
 
 
419
 
    /* Add SIP-If-Match if we have etag */
420
 
    if (pubc->etag.slen) {
421
 
        const pj_str_t STR_HNAME = { "SIP-If-Match", 12 };
422
 
 
423
 
        hdr = pjsip_generic_string_hdr_create(tdata->pool, &STR_HNAME,
424
 
                                              &pubc->etag);
425
 
        if (hdr)
426
 
            pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);
427
 
    }
428
 
 
429
 
    /* Add user headers */
430
 
    if (!pj_list_empty(&pubc->usr_hdr)) {
431
 
        const pjsip_hdr *hdr;
432
 
 
433
 
        hdr = pubc->usr_hdr.next;
434
 
        while (hdr != &pubc->usr_hdr) {
435
 
            pjsip_hdr *new_hdr = (pjsip_hdr*)
436
 
                                 pjsip_hdr_shallow_clone(tdata->pool, hdr);
437
 
            pjsip_msg_add_hdr(tdata->msg, new_hdr);
438
 
            hdr = hdr->next;
439
 
        }
440
 
    }
441
 
 
442
 
 
443
 
    /* Done. */
444
 
    *p_tdata = tdata;
445
 
    return PJ_SUCCESS;
446
 
}
447
 
 
448
 
 
449
 
PJ_DEF(pj_status_t) pjsip_publishc_publish(pjsip_publishc *pubc,
450
 
                                           pj_bool_t auto_refresh,
451
 
                                           pjsip_tx_data **p_tdata)
452
 
{
453
 
    pj_status_t status;
454
 
    pjsip_tx_data *tdata;
455
 
 
456
 
    PJ_ASSERT_RETURN(pubc && p_tdata, PJ_EINVAL);
457
 
 
458
 
    status = create_request(pubc, &tdata);
459
 
    if (status != PJ_SUCCESS)
460
 
        return status;
461
 
 
462
 
    /* Add Expires header */
463
 
    if (pubc->expires_hdr) {
464
 
        pjsip_hdr *dup;
465
 
 
466
 
        dup = (pjsip_hdr*)
467
 
              pjsip_hdr_shallow_clone(tdata->pool, pubc->expires_hdr);
468
 
        if (dup)
469
 
            pjsip_msg_add_hdr(tdata->msg, dup);
470
 
    }
471
 
 
472
 
    /* Cancel existing timer */
473
 
    if (pubc->timer.id != 0) {
474
 
        pjsip_endpt_cancel_timer(pubc->endpt, &pubc->timer);
475
 
        pubc->timer.id = 0;
476
 
    }
477
 
 
478
 
    pubc->auto_refresh = auto_refresh;
479
 
 
480
 
    /* Done */
481
 
    *p_tdata = tdata;
482
 
    return PJ_SUCCESS;
483
 
}
484
 
 
485
 
 
486
 
PJ_DEF(pj_status_t) pjsip_publishc_unpublish(pjsip_publishc *pubc,
487
 
                                             pjsip_tx_data **p_tdata)
488
 
{
489
 
    pjsip_tx_data *tdata;
490
 
    pjsip_msg *msg;
491
 
    pjsip_expires_hdr *expires;
492
 
    pj_status_t status;
493
 
 
494
 
    PJ_ASSERT_RETURN(pubc && p_tdata, PJ_EINVAL);
495
 
 
496
 
    if (pubc->timer.id != 0) {
497
 
        pjsip_endpt_cancel_timer(pubc->endpt, &pubc->timer);
498
 
        pubc->timer.id = 0;
499
 
    }
500
 
 
501
 
    status = create_request(pubc, &tdata);
502
 
    if (status != PJ_SUCCESS)
503
 
        return status;
504
 
 
505
 
    msg = tdata->msg;
506
 
 
507
 
    /* Add Expires:0 header */
508
 
    expires = pjsip_expires_hdr_create(tdata->pool, 0);
509
 
    pjsip_msg_add_hdr( msg, (pjsip_hdr*)expires);
510
 
 
511
 
    *p_tdata = tdata;
512
 
    return PJ_SUCCESS;
513
 
}
514
 
 
515
 
 
516
 
PJ_DEF(pj_status_t) pjsip_publishc_update_expires( pjsip_publishc *pubc,
517
 
                                                   pj_uint32_t expires )
518
 
{
519
 
    PJ_ASSERT_RETURN(pubc, PJ_EINVAL);
520
 
    set_expires( pubc, expires );
521
 
    return PJ_SUCCESS;
522
 
}
523
 
 
524
 
 
525
 
static void call_callback(pjsip_publishc *pubc, pj_status_t status,
526
 
                          int st_code, const pj_str_t *reason,
527
 
                          pjsip_rx_data *rdata, pj_int32_t expiration)
528
 
{
529
 
    struct pjsip_publishc_cbparam cbparam;
530
 
 
531
 
 
532
 
    cbparam.pubc = pubc;
533
 
    cbparam.token = pubc->token;
534
 
    cbparam.status = status;
535
 
    cbparam.code = st_code;
536
 
    cbparam.reason = *reason;
537
 
    cbparam.rdata = rdata;
538
 
    cbparam.expiration = expiration;
539
 
 
540
 
    (*pubc->cb)(&cbparam);
541
 
}
542
 
 
543
 
static void pubc_refresh_timer_cb( pj_timer_heap_t *timer_heap,
544
 
                                   struct pj_timer_entry *entry)
545
 
{
546
 
    pjsip_publishc *pubc = (pjsip_publishc*) entry->user_data;
547
 
    pjsip_tx_data *tdata;
548
 
    pj_status_t status;
549
 
 
550
 
    PJ_UNUSED_ARG(timer_heap);
551
 
 
552
 
    entry->id = 0;
553
 
    status = pjsip_publishc_publish(pubc, 1, &tdata);
554
 
    if (status != PJ_SUCCESS) {
555
 
        char errmsg[PJ_ERR_MSG_SIZE];
556
 
        pj_str_t reason = pj_strerror(status, errmsg, sizeof(errmsg));
557
 
        call_callback(pubc, status, 400, &reason, NULL, -1);
558
 
        return;
559
 
    }
560
 
 
561
 
    status = pjsip_publishc_send(pubc, tdata);
562
 
    /* No need to call callback as it should have been called */
563
 
}
564
 
 
565
 
static void tsx_callback(void *token, pjsip_event *event)
566
 
{
567
 
    pj_status_t status;
568
 
    pjsip_publishc *pubc = (pjsip_publishc*) token;
569
 
    pjsip_transaction *tsx = event->body.tsx_state.tsx;
570
 
 
571
 
    /* Decrement pending transaction counter. */
572
 
    pj_assert(pubc->pending_tsx > 0);
573
 
    --pubc->pending_tsx;
574
 
 
575
 
    /* Mark that we're in callback to prevent deletion (#1164) */
576
 
    ++pubc->in_callback;
577
 
 
578
 
    /* If publication data has been deleted by user then remove publication
579
 
     * data from transaction's callback, and don't call callback.
580
 
     */
581
 
    if (pubc->_delete_flag) {
582
 
 
583
 
        /* Nothing to do */
584
 
        ;
585
 
 
586
 
    } else if (tsx->status_code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED ||
587
 
               tsx->status_code == PJSIP_SC_UNAUTHORIZED)
588
 
    {
589
 
        pjsip_rx_data *rdata = event->body.tsx_state.src.rdata;
590
 
        pjsip_tx_data *tdata;
591
 
 
592
 
        status = pjsip_auth_clt_reinit_req( &pubc->auth_sess,
593
 
                                            rdata,
594
 
                                            tsx->last_tx,
595
 
                                            &tdata);
596
 
        if (status != PJ_SUCCESS) {
597
 
            call_callback(pubc, status, tsx->status_code,
598
 
                          &rdata->msg_info.msg->line.status.reason,
599
 
                          rdata, -1);
600
 
        } else {
601
 
            status = pjsip_publishc_send(pubc, tdata);
602
 
        }
603
 
 
604
 
    } else {
605
 
        pjsip_rx_data *rdata;
606
 
        pj_int32_t expiration = 0xFFFF;
607
 
 
608
 
        if (tsx->status_code/100 == 2) {
609
 
            pjsip_msg *msg;
610
 
            pjsip_expires_hdr *expires;
611
 
            pjsip_generic_string_hdr *etag_hdr;
612
 
            const pj_str_t STR_ETAG = { "SIP-ETag", 8 };
613
 
 
614
 
            rdata = event->body.tsx_state.src.rdata;
615
 
            msg = rdata->msg_info.msg;
616
 
 
617
 
            /* Save ETag value */
618
 
            etag_hdr = (pjsip_generic_string_hdr*)
619
 
                       pjsip_msg_find_hdr_by_name(msg, &STR_ETAG, NULL);
620
 
            if (etag_hdr) {
621
 
                pj_strdup(pubc->pool, &pubc->etag, &etag_hdr->hvalue);
622
 
            } else {
623
 
                pubc->etag.slen = 0;
624
 
            }
625
 
 
626
 
            /* Update expires value */
627
 
            expires = (pjsip_expires_hdr*)
628
 
                      pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL);
629
 
 
630
 
            if (pubc->auto_refresh && expires)
631
 
                expiration = expires->ivalue;
632
 
 
633
 
            if (pubc->auto_refresh && expiration!=0 && expiration!=0xFFFF) {
634
 
                pj_time_val delay = { 0, 0};
635
 
 
636
 
                /* Cancel existing timer, if any */
637
 
                if (pubc->timer.id != 0) {
638
 
                    pjsip_endpt_cancel_timer(pubc->endpt, &pubc->timer);
639
 
                    pubc->timer.id = 0;
640
 
                }
641
 
 
642
 
                delay.sec = expiration - DELAY_BEFORE_REFRESH;
643
 
                if (pubc->expires != PJSIP_PUBC_EXPIRATION_NOT_SPECIFIED &&
644
 
                    delay.sec > (pj_int32_t)pubc->expires)
645
 
                {
646
 
                    delay.sec = pubc->expires;
647
 
                }
648
 
                if (delay.sec < DELAY_BEFORE_REFRESH)
649
 
                    delay.sec = DELAY_BEFORE_REFRESH;
650
 
                pubc->timer.cb = &pubc_refresh_timer_cb;
651
 
                pubc->timer.id = REFRESH_TIMER;
652
 
                pubc->timer.user_data = pubc;
653
 
                pjsip_endpt_schedule_timer( pubc->endpt, &pubc->timer, &delay);
654
 
                pj_gettimeofday(&pubc->last_refresh);
655
 
                pubc->next_refresh = pubc->last_refresh;
656
 
                pubc->next_refresh.sec += delay.sec;
657
 
            }
658
 
 
659
 
        } else {
660
 
            rdata = (event->body.tsx_state.type==PJSIP_EVENT_RX_MSG) ?
661
 
                        event->body.tsx_state.src.rdata : NULL;
662
 
        }
663
 
 
664
 
 
665
 
        /* Call callback. */
666
 
        if (expiration == 0xFFFF) expiration = -1;
667
 
 
668
 
        /* Temporarily increment pending_tsx to prevent callback from
669
 
         * destroying pubc.
670
 
         */
671
 
        ++pubc->pending_tsx;
672
 
 
673
 
        call_callback(pubc, PJ_SUCCESS, tsx->status_code,
674
 
                      (rdata ? &rdata->msg_info.msg->line.status.reason
675
 
                        : pjsip_get_status_text(tsx->status_code)),
676
 
                      rdata, expiration);
677
 
 
678
 
        --pubc->pending_tsx;
679
 
 
680
 
        /* If we have pending request(s), send them now */
681
 
        pj_mutex_lock(pubc->mutex);
682
 
        while (!pj_list_empty(&pubc->pending_reqs)) {
683
 
            pjsip_tx_data *tdata = pubc->pending_reqs.next;
684
 
            pj_list_erase(tdata);
685
 
 
686
 
            /* Add SIP-If-Match if we have etag and the request doesn't have
687
 
             * one (http://trac.pjsip.org/repos/ticket/996)
688
 
             */
689
 
            if (pubc->etag.slen) {
690
 
                const pj_str_t STR_HNAME = { "SIP-If-Match", 12 };
691
 
                pjsip_generic_string_hdr *sim_hdr;
692
 
 
693
 
                sim_hdr = (pjsip_generic_string_hdr*)
694
 
                          pjsip_msg_find_hdr_by_name(tdata->msg, &STR_HNAME, NULL);
695
 
                if (!sim_hdr) {
696
 
                    /* Create the header */
697
 
                    sim_hdr = pjsip_generic_string_hdr_create(tdata->pool,
698
 
                                                              &STR_HNAME,
699
 
                                                              &pubc->etag);
700
 
                    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)sim_hdr);
701
 
 
702
 
                } else {
703
 
                    /* Update */
704
 
                    if (pj_strcmp(&pubc->etag, &sim_hdr->hvalue))
705
 
                        pj_strdup(tdata->pool, &sim_hdr->hvalue, &pubc->etag);
706
 
                }
707
 
            }
708
 
 
709
 
            status = pjsip_publishc_send(pubc, tdata);
710
 
            if (status == PJ_EPENDING) {
711
 
                pj_assert(!"Not expected");
712
 
                pj_list_erase(tdata);
713
 
                pjsip_tx_data_dec_ref(tdata);
714
 
            } else if (status == PJ_SUCCESS) {
715
 
                break;
716
 
            }
717
 
        }
718
 
        pj_mutex_unlock(pubc->mutex);
719
 
    }
720
 
 
721
 
    /* No longer in callback. */
722
 
    --pubc->in_callback;
723
 
 
724
 
    /* Delete the record if user destroy pubc during the callback. */
725
 
    if (pubc->_delete_flag && pubc->pending_tsx==0) {
726
 
        pjsip_publishc_destroy(pubc);
727
 
    }
728
 
}
729
 
 
730
 
 
731
 
PJ_DEF(pj_status_t) pjsip_publishc_send(pjsip_publishc *pubc,
732
 
                                        pjsip_tx_data *tdata)
733
 
{
734
 
    pj_status_t status;
735
 
    pjsip_cseq_hdr *cseq_hdr;
736
 
    pj_uint32_t cseq;
737
 
 
738
 
    PJ_ASSERT_RETURN(pubc && tdata, PJ_EINVAL);
739
 
 
740
 
    /* Make sure we don't have pending transaction. */
741
 
    pj_mutex_lock(pubc->mutex);
742
 
    if (pubc->pending_tsx) {
743
 
        if (pubc->opt.queue_request) {
744
 
            pj_list_push_back(&pubc->pending_reqs, tdata);
745
 
            pj_mutex_unlock(pubc->mutex);
746
 
            PJ_LOG(4,(THIS_FILE, "Request is queued, pubc has another "
747
 
                                 "transaction pending"));
748
 
            return PJ_EPENDING;
749
 
        } else {
750
 
            pjsip_tx_data_dec_ref(tdata);
751
 
            pj_mutex_unlock(pubc->mutex);
752
 
            PJ_LOG(4,(THIS_FILE, "Unable to send request, pubc has another "
753
 
                                 "transaction pending"));
754
 
            return PJ_EBUSY;
755
 
        }
756
 
    }
757
 
    pj_mutex_unlock(pubc->mutex);
758
 
 
759
 
    /* If via_addr is set, use this address for the Via header. */
760
 
    if (pubc->via_addr.host.slen > 0) {
761
 
        tdata->via_addr = pubc->via_addr;
762
 
        tdata->via_tp = pubc->via_tp;
763
 
    }
764
 
 
765
 
    /* Invalidate message buffer. */
766
 
    pjsip_tx_data_invalidate_msg(tdata);
767
 
 
768
 
    /* Increment CSeq */
769
 
    cseq = ++pubc->cseq_hdr->cseq;
770
 
    cseq_hdr = (pjsip_cseq_hdr*)
771
 
               pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
772
 
    cseq_hdr->cseq = cseq;
773
 
 
774
 
    /* Increment pending transaction first, since transaction callback
775
 
     * may be called even before send_request() returns!
776
 
     */
777
 
    ++pubc->pending_tsx;
778
 
    status = pjsip_endpt_send_request(pubc->endpt, tdata, -1, pubc,
779
 
                                      &tsx_callback);
780
 
    if (status!=PJ_SUCCESS) {
781
 
        // no need to decrement, callback has been called and it should
782
 
        // already decremented pending_tsx. Decrementing this here may
783
 
        // cause accessing freed memory location.
784
 
        //--pubc->pending_tsx;
785
 
        PJ_LOG(4,(THIS_FILE, "Error sending request, status=%d", status));
786
 
    }
787
 
 
788
 
    return status;
789
 
}