blob: 3f11ad13e3d84bbae540e09fc328ebb1a6ea01ec [file] [log] [blame]
Benny Prijono21b9ad92006-08-15 13:11:22 +00001/* $Id$ */
2/*
Benny Prijonoa771a512007-02-19 01:13:53 +00003 * Copyright (C) 2003-2007 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
442 if (status != PJ_SUCCESS) {
443 char errmsg[PJ_ERR_MSG_SIZE];
444 pj_str_t reason = pj_strerror(status, errmsg, sizeof(errmsg));
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000445 call_callback(pubc, status, 400, &reason, NULL, -1);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000446 }
447}
448
449static void tsx_callback(void *token, pjsip_event *event)
450{
451 pj_status_t status;
Benny Prijono9d4469d2007-05-02 05:14:29 +0000452 pjsip_publishc *pubc = (pjsip_publishc*) token;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000453 pjsip_transaction *tsx = event->body.tsx_state.tsx;
454
455 /* Decrement pending transaction counter. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000456 pj_assert(pubc->pending_tsx > 0);
457 --pubc->pending_tsx;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000458
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000459 /* If publication data has been deleted by user then remove publication
Benny Prijono21b9ad92006-08-15 13:11:22 +0000460 * data from transaction's callback, and don't call callback.
461 */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000462 if (pubc->_delete_flag) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000463
464 /* Nothing to do */
465 ;
466
467 } else if (tsx->status_code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED ||
468 tsx->status_code == PJSIP_SC_UNAUTHORIZED)
469 {
470 pjsip_rx_data *rdata = event->body.tsx_state.src.rdata;
471 pjsip_tx_data *tdata;
472
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000473 status = pjsip_auth_clt_reinit_req( &pubc->auth_sess,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000474 rdata,
475 tsx->last_tx,
476 &tdata);
477
478 if (status == PJ_SUCCESS) {
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000479 status = pjsip_publishc_send(pubc, tdata);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000480 }
481
482 if (status != PJ_SUCCESS) {
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000483 call_callback(pubc, status, tsx->status_code,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000484 &rdata->msg_info.msg->line.status.reason,
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000485 rdata, -1);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000486 }
487
488 return;
489
490 } else {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000491 pjsip_rx_data *rdata;
492 pj_int32_t expiration = 0xFFFF;
493
494 if (tsx->status_code/100 == 2) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000495 pjsip_msg *msg;
496 pjsip_expires_hdr *expires;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000497 pjsip_generic_string_hdr *etag_hdr;
498 const pj_str_t STR_ETAG = { "SIP-ETag", 8 };
Benny Prijono21b9ad92006-08-15 13:11:22 +0000499
500 rdata = event->body.tsx_state.src.rdata;
501 msg = rdata->msg_info.msg;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000502
503 /* Save ETag value */
504 etag_hdr = (pjsip_generic_string_hdr*)
505 pjsip_msg_find_hdr_by_name(msg, &STR_ETAG, NULL);
506 if (etag_hdr) {
507 pj_strdup(pubc->pool, &pubc->etag, &etag_hdr->hvalue);
508 } else {
509 pubc->etag.slen = 0;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000510 }
511
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000512 /* Update expires value */
Benny Prijono9d4469d2007-05-02 05:14:29 +0000513 expires = (pjsip_expires_hdr*)
514 pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000515
516 if (expires)
517 expiration = expires->ivalue;
518
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000519 if (pubc->auto_refresh && expiration!=0 && expiration!=0xFFFF) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000520 pj_time_val delay = { 0, 0};
521
522 delay.sec = expiration - DELAY_BEFORE_REFRESH;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000523 if (pubc->expires != PJSIP_PUBC_EXPIRATION_NOT_SPECIFIED &&
524 delay.sec > (pj_int32_t)pubc->expires)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000525 {
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000526 delay.sec = pubc->expires;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000527 }
528 if (delay.sec < DELAY_BEFORE_REFRESH)
529 delay.sec = DELAY_BEFORE_REFRESH;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000530 pubc->timer.cb = &pubc_refresh_timer_cb;
531 pubc->timer.id = REFRESH_TIMER;
532 pubc->timer.user_data = pubc;
533 pjsip_endpt_schedule_timer( pubc->endpt, &pubc->timer, &delay);
534 pj_gettimeofday(&pubc->last_refresh);
535 pubc->next_refresh = pubc->last_refresh;
536 pubc->next_refresh.sec += delay.sec;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000537 }
538
539 } else {
540 rdata = (event->body.tsx_state.type==PJSIP_EVENT_RX_MSG) ?
541 event->body.tsx_state.src.rdata : NULL;
542 }
543
544
545 /* Call callback. */
546 if (expiration == 0xFFFF) expiration = -1;
Benny Prijonoda1e0632007-05-23 14:12:35 +0000547
548 /* Temporarily increment pending_tsx to prevent callback from
549 * destroying pubc.
550 */
551 ++pubc->pending_tsx;
552
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000553 call_callback(pubc, PJ_SUCCESS, tsx->status_code,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000554 (rdata ? &rdata->msg_info.msg->line.status.reason
555 : pjsip_get_status_text(tsx->status_code)),
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000556 rdata, expiration);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000557
Benny Prijonoda1e0632007-05-23 14:12:35 +0000558 --pubc->pending_tsx;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000559 }
560
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000561 /* Delete the record if user destroy pubc during the callback. */
562 if (pubc->_delete_flag && pubc->pending_tsx==0) {
563 pjsip_publishc_destroy(pubc);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000564 }
565}
566
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000567
568PJ_DEF(pj_status_t) pjsip_publishc_send(pjsip_publishc *pubc,
569 pjsip_tx_data *tdata)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000570{
571 pj_status_t status;
572 pjsip_cseq_hdr *cseq_hdr;
573 pj_uint32_t cseq;
574
575 /* Make sure we don't have pending transaction. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000576 if (pubc->pending_tsx) {
577 PJ_LOG(4,(THIS_FILE, "Unable to send request, pubc has another "
Benny Prijono21b9ad92006-08-15 13:11:22 +0000578 "transaction pending"));
579 pjsip_tx_data_dec_ref( tdata );
580 return PJSIP_EBUSY;
581 }
582
583 /* Invalidate message buffer. */
584 pjsip_tx_data_invalidate_msg(tdata);
585
586 /* Increment CSeq */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000587 cseq = ++pubc->cseq_hdr->cseq;
Benny Prijono9d4469d2007-05-02 05:14:29 +0000588 cseq_hdr = (pjsip_cseq_hdr*)
589 pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000590 cseq_hdr->cseq = cseq;
591
592 /* Increment pending transaction first, since transaction callback
593 * may be called even before send_request() returns!
594 */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000595 ++pubc->pending_tsx;
596 status = pjsip_endpt_send_request(pubc->endpt, tdata, -1, pubc,
597 &tsx_callback);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000598 if (status!=PJ_SUCCESS) {
Benny Prijono29438152007-06-28 02:47:32 +0000599 // no need to decrement, callback has been called and it should
600 // already decremented pending_tsx. Decrementing this here may
601 // cause accessing freed memory location.
602 //--pubc->pending_tsx;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000603 PJ_LOG(4,(THIS_FILE, "Error sending request, status=%d", status));
604 }
605
606 return status;
607}
608