blob: a62060613b20927cc0fbc0b98d32a52e9670bf9a [file] [log] [blame]
Benny Prijono21b9ad92006-08-15 13:11:22 +00001/* $Id$ */
2/*
Benny Prijono32177c02008-06-20 22:44:47 +00003 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijono21b9ad92006-08-15 13:11:22 +00004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000019#include <pjsip-simple/publish.h>
20#include <pjsip/sip_auth.h>
Benny Prijono21b9ad92006-08-15 13:11:22 +000021#include <pjsip/sip_endpoint.h>
Benny Prijono21b9ad92006-08-15 13:11:22 +000022#include <pjsip/sip_errno.h>
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000023#include <pjsip/sip_event.h>
24#include <pjsip/sip_msg.h>
25#include <pjsip/sip_transaction.h>
26#include <pjsip/sip_uri.h>
27#include <pjsip/sip_util.h>
Benny Prijono21b9ad92006-08-15 13:11:22 +000028#include <pj/assert.h>
29#include <pj/guid.h>
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000030#include <pj/log.h>
Benny Prijono21b9ad92006-08-15 13:11:22 +000031#include <pj/os.h>
32#include <pj/pool.h>
Benny Prijono21b9ad92006-08-15 13:11:22 +000033#include <pj/rand.h>
34#include <pj/string.h>
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000035#include <pj/timer.h>
Benny Prijono21b9ad92006-08-15 13:11:22 +000036
37
38#define REFRESH_TIMER 1
39#define DELAY_BEFORE_REFRESH 5
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000040#define THIS_FILE "publishc.c"
41
42
Benny Prijonoc8141a82006-08-20 09:12:19 +000043/* Let's define this enum, so that it'll trigger compilation error
44 * when somebody define the same enum in sip_msg.h
45 */
46enum
47{
48 PJSIP_PUBLISH_METHOD = PJSIP_OTHER_METHOD,
49};
50
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000051const pjsip_method pjsip_publish_method =
52{
Benny Prijono9d4469d2007-05-02 05:14:29 +000053 (pjsip_method_e)PJSIP_PUBLISH_METHOD,
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000054 { "PUBLISH", 7 }
55};
56
Benny Prijono21b9ad92006-08-15 13:11:22 +000057
58/**
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000059 * SIP client publication structure.
Benny Prijono21b9ad92006-08-15 13:11:22 +000060 */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000061struct pjsip_publishc
Benny Prijono21b9ad92006-08-15 13:11:22 +000062{
63 pj_pool_t *pool;
64 pjsip_endpoint *endpt;
65 pj_bool_t _delete_flag;
66 int pending_tsx;
67
68 void *token;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000069 pjsip_publishc_cb *cb;
Benny Prijono21b9ad92006-08-15 13:11:22 +000070
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000071 pj_str_t event;
72 pj_str_t str_target_uri;
73 pjsip_uri *target_uri;
Benny Prijono21b9ad92006-08-15 13:11:22 +000074 pjsip_cid_hdr *cid_hdr;
75 pjsip_cseq_hdr *cseq_hdr;
76 pj_str_t from_uri;
77 pjsip_from_hdr *from_hdr;
78 pjsip_to_hdr *to_hdr;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000079 pj_str_t etag;
Benny Prijono21b9ad92006-08-15 13:11:22 +000080 pjsip_expires_hdr *expires_hdr;
Benny Prijono21b9ad92006-08-15 13:11:22 +000081 pj_uint32_t expires;
82 pjsip_route_hdr route_set;
83
84 /* Authorization sessions. */
85 pjsip_auth_clt_sess auth_sess;
86
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000087 /* Auto refresh publication. */
88 pj_bool_t auto_refresh;
89 pj_time_val last_refresh;
90 pj_time_val next_refresh;
Benny Prijono21b9ad92006-08-15 13:11:22 +000091 pj_timer_entry timer;
92};
93
94
95
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000096/*
97 * Initialize client publication module.
98 */
99PJ_DEF(pj_status_t) pjsip_publishc_init_module(pjsip_endpoint *endpt)
100{
101 return pjsip_endpt_add_capability( endpt, NULL, PJSIP_H_ALLOW, NULL,
102 1, &pjsip_publish_method.name);
103}
104
105
106PJ_DEF(pj_status_t) pjsip_publishc_create( pjsip_endpoint *endpt,
107 unsigned options,
108 void *token,
109 pjsip_publishc_cb *cb,
110 pjsip_publishc **p_pubc)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000111{
112 pj_pool_t *pool;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000113 pjsip_publishc *pubc;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000114 pj_status_t status;
115
116 /* Verify arguments. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000117 PJ_ASSERT_RETURN(endpt && cb && p_pubc, PJ_EINVAL);
118 PJ_ASSERT_RETURN(options == 0, PJ_EINVAL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000119
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000120 PJ_UNUSED_ARG(options);
121
122 pool = pjsip_endpt_create_pool(endpt, "pubc%p", 1024, 1024);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000123 PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
124
Benny Prijono9d4469d2007-05-02 05:14:29 +0000125 pubc = PJ_POOL_ZALLOC_T(pool, pjsip_publishc);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000126
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000127 pubc->pool = pool;
128 pubc->endpt = endpt;
129 pubc->token = token;
130 pubc->cb = cb;
131 pubc->expires = PJSIP_PUBC_EXPIRATION_NOT_SPECIFIED;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000132
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000133 status = pjsip_auth_clt_init(&pubc->auth_sess, endpt, pubc->pool, 0);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000134 if (status != PJ_SUCCESS)
135 return status;
136
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000137 pj_list_init(&pubc->route_set);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000138
139 /* Done */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000140 *p_pubc = pubc;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000141 return PJ_SUCCESS;
142}
143
144
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000145PJ_DEF(pj_status_t) pjsip_publishc_destroy(pjsip_publishc *pubc)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000146{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000147 PJ_ASSERT_RETURN(pubc, PJ_EINVAL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000148
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000149 if (pubc->pending_tsx) {
150 pubc->_delete_flag = 1;
151 pubc->cb = NULL;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000152 } else {
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000153 pjsip_endpt_release_pool(pubc->endpt, pubc->pool);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000154 }
155
156 return PJ_SUCCESS;
157}
158
159
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000160PJ_DEF(pj_pool_t*) pjsip_publishc_get_pool(pjsip_publishc *pubc)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000161{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000162 return pubc->pool;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000163}
164
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000165static void set_expires( pjsip_publishc *pubc, pj_uint32_t expires)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000166{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000167 if (expires != pubc->expires) {
168 pubc->expires_hdr = pjsip_expires_hdr_create(pubc->pool, expires);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000169 } else {
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000170 pubc->expires_hdr = NULL;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000171 }
172}
173
174
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000175PJ_DEF(pj_status_t) pjsip_publishc_init(pjsip_publishc *pubc,
176 const pj_str_t *event,
177 const pj_str_t *target_uri,
178 const pj_str_t *from_uri,
179 const pj_str_t *to_uri,
180 pj_uint32_t expires)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000181{
182 pj_str_t tmp;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000183
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000184 PJ_ASSERT_RETURN(pubc && event && target_uri && from_uri && to_uri &&
185 expires, PJ_EINVAL);
186
187 /* Copy event type */
188 pj_strdup_with_null(pubc->pool, &pubc->event, event);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000189
190 /* Copy server URL. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000191 pj_strdup_with_null(pubc->pool, &pubc->str_target_uri, target_uri);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000192
193 /* Set server URL. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000194 tmp = pubc->str_target_uri;
195 pubc->target_uri = pjsip_parse_uri( pubc->pool, tmp.ptr, tmp.slen, 0);
196 if (pubc->target_uri == NULL) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000197 return PJSIP_EINVALIDURI;
198 }
199
200 /* Set "From" header. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000201 pj_strdup_with_null(pubc->pool, &pubc->from_uri, from_uri);
202 tmp = pubc->from_uri;
203 pubc->from_hdr = pjsip_from_hdr_create(pubc->pool);
204 pubc->from_hdr->uri = pjsip_parse_uri(pubc->pool, tmp.ptr, tmp.slen,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000205 PJSIP_PARSE_URI_AS_NAMEADDR);
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000206 if (!pubc->from_hdr->uri) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000207 return PJSIP_EINVALIDURI;
208 }
209
210 /* Set "To" header. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000211 pj_strdup_with_null(pubc->pool, &tmp, to_uri);
212 pubc->to_hdr = pjsip_to_hdr_create(pubc->pool);
213 pubc->to_hdr->uri = pjsip_parse_uri(pubc->pool, tmp.ptr, tmp.slen,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000214 PJSIP_PARSE_URI_AS_NAMEADDR);
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000215 if (!pubc->to_hdr->uri) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000216 return PJSIP_EINVALIDURI;
217 }
218
219
Benny Prijono21b9ad92006-08-15 13:11:22 +0000220 /* Set "Expires" header, if required. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000221 set_expires( pubc, expires);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000222
223 /* Set "Call-ID" header. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000224 pubc->cid_hdr = pjsip_cid_hdr_create(pubc->pool);
225 pj_create_unique_string(pubc->pool, &pubc->cid_hdr->id);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000226
227 /* Set "CSeq" header. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000228 pubc->cseq_hdr = pjsip_cseq_hdr_create(pubc->pool);
229 pubc->cseq_hdr->cseq = pj_rand() % 0xFFFF;
230 pjsip_method_set( &pubc->cseq_hdr->method, PJSIP_REGISTER_METHOD);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000231
232 /* Done. */
233 return PJ_SUCCESS;
234}
235
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000236PJ_DEF(pj_status_t) pjsip_publishc_set_credentials( pjsip_publishc *pubc,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000237 int count,
238 const pjsip_cred_info cred[] )
239{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000240 PJ_ASSERT_RETURN(pubc && count && cred, PJ_EINVAL);
241 return pjsip_auth_clt_set_credentials(&pubc->auth_sess, count, cred);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000242}
243
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000244PJ_DEF(pj_status_t) pjsip_publishc_set_route_set( pjsip_publishc *pubc,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000245 const pjsip_route_hdr *route_set)
246{
247 const pjsip_route_hdr *chdr;
248
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000249 PJ_ASSERT_RETURN(pubc && route_set, PJ_EINVAL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000250
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000251 pj_list_init(&pubc->route_set);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000252
253 chdr = route_set->next;
254 while (chdr != route_set) {
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000255 pj_list_push_back(&pubc->route_set, pjsip_hdr_clone(pubc->pool, chdr));
Benny Prijono21b9ad92006-08-15 13:11:22 +0000256 chdr = chdr->next;
257 }
258
259 return PJ_SUCCESS;
260}
261
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000262static pj_status_t create_request(pjsip_publishc *pubc,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000263 pjsip_tx_data **p_tdata)
264{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000265 const pj_str_t STR_EVENT = { "Event", 5 };
Benny Prijono21b9ad92006-08-15 13:11:22 +0000266 pj_status_t status;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000267 pjsip_generic_string_hdr *hdr;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000268 pjsip_tx_data *tdata;
269
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000270 PJ_ASSERT_RETURN(pubc && p_tdata, PJ_EINVAL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000271
272 /* Create the request. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000273 status = pjsip_endpt_create_request_from_hdr( pubc->endpt,
274 &pjsip_publish_method,
275 pubc->target_uri,
276 pubc->from_hdr,
277 pubc->to_hdr,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000278 NULL,
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000279 pubc->cid_hdr,
280 pubc->cseq_hdr->cseq,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000281 NULL,
282 &tdata);
283 if (status != PJ_SUCCESS)
284 return status;
285
286 /* Add cached authorization headers. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000287 pjsip_auth_clt_init_req( &pubc->auth_sess, tdata );
Benny Prijono21b9ad92006-08-15 13:11:22 +0000288
289 /* Add Route headers from route set, ideally after Via header */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000290 if (!pj_list_empty(&pubc->route_set)) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000291 pjsip_hdr *route_pos;
292 const pjsip_route_hdr *route;
293
Benny Prijono9d4469d2007-05-02 05:14:29 +0000294 route_pos = (pjsip_hdr*)
295 pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000296 if (!route_pos)
297 route_pos = &tdata->msg->hdr;
298
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000299 route = pubc->route_set.next;
300 while (route != &pubc->route_set) {
Benny Prijono9d4469d2007-05-02 05:14:29 +0000301 pjsip_hdr *new_hdr = (pjsip_hdr*)
302 pjsip_hdr_shallow_clone(tdata->pool, route);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000303 pj_list_insert_after(route_pos, new_hdr);
304 route_pos = new_hdr;
305 route = route->next;
306 }
307 }
308
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000309 /* Add Event header */
310 hdr = pjsip_generic_string_hdr_create(tdata->pool, &STR_EVENT,
311 &pubc->event);
312 if (hdr)
313 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);
314
315
316 /* Add SIP-If-Match if we have etag */
317 if (pubc->etag.slen) {
318 const pj_str_t STR_HNAME = { "SIP-If-Match", 12 };
319
320 hdr = pjsip_generic_string_hdr_create(tdata->pool, &STR_HNAME,
321 &pubc->etag);
322 if (hdr)
323 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);
324 }
325
326
Benny Prijono21b9ad92006-08-15 13:11:22 +0000327 /* Done. */
328 *p_tdata = tdata;
329 return PJ_SUCCESS;
330}
331
332
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000333PJ_DEF(pj_status_t) pjsip_publishc_publish(pjsip_publishc *pubc,
334 pj_bool_t auto_refresh,
335 pjsip_tx_data **p_tdata)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000336{
Benny Prijono21b9ad92006-08-15 13:11:22 +0000337 pj_status_t status;
338 pjsip_tx_data *tdata;
339
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000340 PJ_ASSERT_RETURN(pubc && p_tdata, PJ_EINVAL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000341
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000342 status = create_request(pubc, &tdata);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000343 if (status != PJ_SUCCESS)
344 return status;
345
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000346 /* Add Expires header */
347 if (pubc->expires_hdr) {
348 pjsip_hdr *dup;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000349
Benny Prijono9d4469d2007-05-02 05:14:29 +0000350 dup = (pjsip_hdr*)
351 pjsip_hdr_shallow_clone(tdata->pool, pubc->expires_hdr);
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000352 if (dup)
353 pjsip_msg_add_hdr(tdata->msg, dup);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000354 }
355
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000356 /* Cancel existing timer */
357 if (pubc->timer.id != 0) {
358 pjsip_endpt_cancel_timer(pubc->endpt, &pubc->timer);
359 pubc->timer.id = 0;
360 }
361
362 pubc->auto_refresh = auto_refresh;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000363
364 /* Done */
365 *p_tdata = tdata;
366 return PJ_SUCCESS;
367}
368
369
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000370PJ_DEF(pj_status_t) pjsip_publishc_unpublish(pjsip_publishc *pubc,
371 pjsip_tx_data **p_tdata)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000372{
373 pjsip_tx_data *tdata;
374 pjsip_msg *msg;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000375 pjsip_expires_hdr *expires;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000376 pj_status_t status;
377
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000378 PJ_ASSERT_RETURN(pubc && p_tdata, PJ_EINVAL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000379
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000380 if (pubc->timer.id != 0) {
381 pjsip_endpt_cancel_timer(pubc->endpt, &pubc->timer);
382 pubc->timer.id = 0;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000383 }
384
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000385 status = create_request(pubc, &tdata);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000386 if (status != PJ_SUCCESS)
387 return status;
388
389 msg = tdata->msg;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000390
391 /* Add Expires:0 header */
392 expires = pjsip_expires_hdr_create(tdata->pool, 0);
393 pjsip_msg_add_hdr( msg, (pjsip_hdr*)expires);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000394
395 *p_tdata = tdata;
396 return PJ_SUCCESS;
397}
398
399
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000400PJ_DEF(pj_status_t) pjsip_publishc_update_expires( pjsip_publishc *pubc,
401 pj_uint32_t expires )
Benny Prijono21b9ad92006-08-15 13:11:22 +0000402{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000403 PJ_ASSERT_RETURN(pubc, PJ_EINVAL);
404 set_expires( pubc, expires );
Benny Prijono21b9ad92006-08-15 13:11:22 +0000405 return PJ_SUCCESS;
406}
407
408
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000409static void call_callback(pjsip_publishc *pubc, pj_status_t status,
410 int st_code, const pj_str_t *reason,
411 pjsip_rx_data *rdata, pj_int32_t expiration)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000412{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000413 struct pjsip_publishc_cbparam cbparam;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000414
415
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000416 cbparam.pubc = pubc;
417 cbparam.token = pubc->token;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000418 cbparam.status = status;
419 cbparam.code = st_code;
420 cbparam.reason = *reason;
421 cbparam.rdata = rdata;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000422 cbparam.expiration = expiration;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000423
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000424 (*pubc->cb)(&cbparam);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000425}
426
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000427static void pubc_refresh_timer_cb( pj_timer_heap_t *timer_heap,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000428 struct pj_timer_entry *entry)
429{
Benny Prijono9d4469d2007-05-02 05:14:29 +0000430 pjsip_publishc *pubc = (pjsip_publishc*) entry->user_data;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000431 pjsip_tx_data *tdata;
432 pj_status_t status;
433
434 PJ_UNUSED_ARG(timer_heap);
435
436 entry->id = 0;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000437 status = pjsip_publishc_publish(pubc, 1, &tdata);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000438 if (status == PJ_SUCCESS) {
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000439 status = pjsip_publishc_send(pubc, tdata);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000440 }
441
Benny Prijonodf51a282007-09-12 17:25:15 +0000442 // Callback should have been called.
443 // Calling it here will crash the system since pubc might have been
444 // destroyed
445 //
446 //if (status != PJ_SUCCESS) {
447 // char errmsg[PJ_ERR_MSG_SIZE];
448 // pj_str_t reason = pj_strerror(status, errmsg, sizeof(errmsg));
449 // call_callback(pubc, status, 400, &reason, NULL, -1);
450 //}
Benny Prijono21b9ad92006-08-15 13:11:22 +0000451}
452
453static void tsx_callback(void *token, pjsip_event *event)
454{
455 pj_status_t status;
Benny Prijono9d4469d2007-05-02 05:14:29 +0000456 pjsip_publishc *pubc = (pjsip_publishc*) token;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000457 pjsip_transaction *tsx = event->body.tsx_state.tsx;
458
459 /* Decrement pending transaction counter. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000460 pj_assert(pubc->pending_tsx > 0);
461 --pubc->pending_tsx;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000462
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000463 /* If publication data has been deleted by user then remove publication
Benny Prijono21b9ad92006-08-15 13:11:22 +0000464 * data from transaction's callback, and don't call callback.
465 */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000466 if (pubc->_delete_flag) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000467
468 /* Nothing to do */
469 ;
470
471 } else if (tsx->status_code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED ||
472 tsx->status_code == PJSIP_SC_UNAUTHORIZED)
473 {
474 pjsip_rx_data *rdata = event->body.tsx_state.src.rdata;
475 pjsip_tx_data *tdata;
476
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000477 status = pjsip_auth_clt_reinit_req( &pubc->auth_sess,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000478 rdata,
479 tsx->last_tx,
480 &tdata);
481
482 if (status == PJ_SUCCESS) {
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000483 status = pjsip_publishc_send(pubc, tdata);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000484 }
485
Benny Prijonodf51a282007-09-12 17:25:15 +0000486 // Callback should have been called.
487 // Calling it here will crash the system since pubc might have been
488 // destroyed
489 //
490 //if (status != PJ_SUCCESS) {
491 // call_callback(pubc, status, tsx->status_code,
492 // &rdata->msg_info.msg->line.status.reason,
493 // rdata, -1);
494 //}
Benny Prijono21b9ad92006-08-15 13:11:22 +0000495
496 return;
497
498 } else {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000499 pjsip_rx_data *rdata;
500 pj_int32_t expiration = 0xFFFF;
501
502 if (tsx->status_code/100 == 2) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000503 pjsip_msg *msg;
504 pjsip_expires_hdr *expires;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000505 pjsip_generic_string_hdr *etag_hdr;
506 const pj_str_t STR_ETAG = { "SIP-ETag", 8 };
Benny Prijono21b9ad92006-08-15 13:11:22 +0000507
508 rdata = event->body.tsx_state.src.rdata;
509 msg = rdata->msg_info.msg;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000510
511 /* Save ETag value */
512 etag_hdr = (pjsip_generic_string_hdr*)
513 pjsip_msg_find_hdr_by_name(msg, &STR_ETAG, NULL);
514 if (etag_hdr) {
515 pj_strdup(pubc->pool, &pubc->etag, &etag_hdr->hvalue);
516 } else {
517 pubc->etag.slen = 0;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000518 }
519
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000520 /* Update expires value */
Benny Prijono9d4469d2007-05-02 05:14:29 +0000521 expires = (pjsip_expires_hdr*)
522 pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000523
524 if (expires)
525 expiration = expires->ivalue;
526
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000527 if (pubc->auto_refresh && expiration!=0 && expiration!=0xFFFF) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000528 pj_time_val delay = { 0, 0};
529
530 delay.sec = expiration - DELAY_BEFORE_REFRESH;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000531 if (pubc->expires != PJSIP_PUBC_EXPIRATION_NOT_SPECIFIED &&
532 delay.sec > (pj_int32_t)pubc->expires)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000533 {
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000534 delay.sec = pubc->expires;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000535 }
536 if (delay.sec < DELAY_BEFORE_REFRESH)
537 delay.sec = DELAY_BEFORE_REFRESH;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000538 pubc->timer.cb = &pubc_refresh_timer_cb;
539 pubc->timer.id = REFRESH_TIMER;
540 pubc->timer.user_data = pubc;
541 pjsip_endpt_schedule_timer( pubc->endpt, &pubc->timer, &delay);
542 pj_gettimeofday(&pubc->last_refresh);
543 pubc->next_refresh = pubc->last_refresh;
544 pubc->next_refresh.sec += delay.sec;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000545 }
546
547 } else {
548 rdata = (event->body.tsx_state.type==PJSIP_EVENT_RX_MSG) ?
549 event->body.tsx_state.src.rdata : NULL;
550 }
551
552
553 /* Call callback. */
554 if (expiration == 0xFFFF) expiration = -1;
Benny Prijonoda1e0632007-05-23 14:12:35 +0000555
556 /* Temporarily increment pending_tsx to prevent callback from
557 * destroying pubc.
558 */
559 ++pubc->pending_tsx;
560
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000561 call_callback(pubc, PJ_SUCCESS, tsx->status_code,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000562 (rdata ? &rdata->msg_info.msg->line.status.reason
563 : pjsip_get_status_text(tsx->status_code)),
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000564 rdata, expiration);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000565
Benny Prijonoda1e0632007-05-23 14:12:35 +0000566 --pubc->pending_tsx;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000567 }
568
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000569 /* Delete the record if user destroy pubc during the callback. */
570 if (pubc->_delete_flag && pubc->pending_tsx==0) {
571 pjsip_publishc_destroy(pubc);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000572 }
573}
574
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000575
576PJ_DEF(pj_status_t) pjsip_publishc_send(pjsip_publishc *pubc,
577 pjsip_tx_data *tdata)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000578{
579 pj_status_t status;
580 pjsip_cseq_hdr *cseq_hdr;
581 pj_uint32_t cseq;
582
583 /* Make sure we don't have pending transaction. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000584 if (pubc->pending_tsx) {
585 PJ_LOG(4,(THIS_FILE, "Unable to send request, pubc has another "
Benny Prijono21b9ad92006-08-15 13:11:22 +0000586 "transaction pending"));
587 pjsip_tx_data_dec_ref( tdata );
588 return PJSIP_EBUSY;
589 }
590
591 /* Invalidate message buffer. */
592 pjsip_tx_data_invalidate_msg(tdata);
593
594 /* Increment CSeq */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000595 cseq = ++pubc->cseq_hdr->cseq;
Benny Prijono9d4469d2007-05-02 05:14:29 +0000596 cseq_hdr = (pjsip_cseq_hdr*)
597 pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000598 cseq_hdr->cseq = cseq;
599
600 /* Increment pending transaction first, since transaction callback
601 * may be called even before send_request() returns!
602 */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000603 ++pubc->pending_tsx;
604 status = pjsip_endpt_send_request(pubc->endpt, tdata, -1, pubc,
605 &tsx_callback);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000606 if (status!=PJ_SUCCESS) {
Benny Prijono29438152007-06-28 02:47:32 +0000607 // no need to decrement, callback has been called and it should
608 // already decremented pending_tsx. Decrementing this here may
609 // cause accessing freed memory location.
610 //--pubc->pending_tsx;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000611 PJ_LOG(4,(THIS_FILE, "Error sending request, status=%d", status));
612 }
613
614 return status;
615}
616