~ubuntu-branches/ubuntu/maverick/sflphone/maverick

« back to all changes in this revision

Viewing changes to sflphone-common/libs/pjproject/pjsip/src/pjsip-simple/publishc.c

  • Committer: Bazaar Package Importer
  • Author(s): Francois Marier
  • Date: 2010-06-03 15:59:46 UTC
  • Revision ID: james.westby@ubuntu.com-20100603155946-ybe8d8o8zx8lp0m8
Tags: upstream-0.9.8.3
ImportĀ upstreamĀ versionĀ 0.9.8.3

Show diffs side-by-side

added added

removed removed

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