blob: f55c8051930f4351fe8f79715c0428e89a3578aa [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{
Benny Prijono7741c8a2008-07-07 19:57:16 +0000101 /* Note:
102 Commented out the capability registration below, since it's
103 wrong to include PUBLISH in Allow header of INVITE requests/
104 responses.
105
106 13.2.1 Creating the Initial INVITE
107 An Allow header field (Section 20.5) SHOULD be present in the
108 INVITE. It indicates what methods can be invoked within a dialog
109
110 20.5 Allow
111 The Allow header field lists the set of methods supported by the
112 UA generating the message.
113
114 While the semantic of Allow header in non-dialog requests is unclear,
115 it's probably best not to include PUBLISH in Allow header for now
116 until we can find out how to customize the inclusion of methods in
117 Allow header for in-dialog vs out-dialog requests.
118
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000119 return pjsip_endpt_add_capability( endpt, NULL, PJSIP_H_ALLOW, NULL,
120 1, &pjsip_publish_method.name);
Benny Prijono7741c8a2008-07-07 19:57:16 +0000121 */
Benny Prijono10d8dbd2008-07-13 13:12:36 +0000122 PJ_UNUSED_ARG(endpt);
Benny Prijono7741c8a2008-07-07 19:57:16 +0000123 return PJ_SUCCESS;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000124}
125
126
127PJ_DEF(pj_status_t) pjsip_publishc_create( pjsip_endpoint *endpt,
128 unsigned options,
129 void *token,
130 pjsip_publishc_cb *cb,
131 pjsip_publishc **p_pubc)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000132{
133 pj_pool_t *pool;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000134 pjsip_publishc *pubc;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000135 pj_status_t status;
136
137 /* Verify arguments. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000138 PJ_ASSERT_RETURN(endpt && cb && p_pubc, PJ_EINVAL);
139 PJ_ASSERT_RETURN(options == 0, PJ_EINVAL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000140
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000141 PJ_UNUSED_ARG(options);
142
143 pool = pjsip_endpt_create_pool(endpt, "pubc%p", 1024, 1024);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000144 PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
145
Benny Prijono9d4469d2007-05-02 05:14:29 +0000146 pubc = PJ_POOL_ZALLOC_T(pool, pjsip_publishc);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000147
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000148 pubc->pool = pool;
149 pubc->endpt = endpt;
150 pubc->token = token;
151 pubc->cb = cb;
152 pubc->expires = PJSIP_PUBC_EXPIRATION_NOT_SPECIFIED;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000153
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000154 status = pjsip_auth_clt_init(&pubc->auth_sess, endpt, pubc->pool, 0);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000155 if (status != PJ_SUCCESS)
156 return status;
157
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000158 pj_list_init(&pubc->route_set);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000159
160 /* Done */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000161 *p_pubc = pubc;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000162 return PJ_SUCCESS;
163}
164
165
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000166PJ_DEF(pj_status_t) pjsip_publishc_destroy(pjsip_publishc *pubc)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000167{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000168 PJ_ASSERT_RETURN(pubc, PJ_EINVAL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000169
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000170 if (pubc->pending_tsx) {
171 pubc->_delete_flag = 1;
172 pubc->cb = NULL;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000173 } else {
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000174 pjsip_endpt_release_pool(pubc->endpt, pubc->pool);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000175 }
176
177 return PJ_SUCCESS;
178}
179
180
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000181PJ_DEF(pj_pool_t*) pjsip_publishc_get_pool(pjsip_publishc *pubc)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000182{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000183 return pubc->pool;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000184}
185
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000186static void set_expires( pjsip_publishc *pubc, pj_uint32_t expires)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000187{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000188 if (expires != pubc->expires) {
189 pubc->expires_hdr = pjsip_expires_hdr_create(pubc->pool, expires);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000190 } else {
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000191 pubc->expires_hdr = NULL;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000192 }
193}
194
195
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000196PJ_DEF(pj_status_t) pjsip_publishc_init(pjsip_publishc *pubc,
197 const pj_str_t *event,
198 const pj_str_t *target_uri,
199 const pj_str_t *from_uri,
200 const pj_str_t *to_uri,
201 pj_uint32_t expires)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000202{
203 pj_str_t tmp;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000204
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000205 PJ_ASSERT_RETURN(pubc && event && target_uri && from_uri && to_uri &&
206 expires, PJ_EINVAL);
207
208 /* Copy event type */
209 pj_strdup_with_null(pubc->pool, &pubc->event, event);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000210
211 /* Copy server URL. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000212 pj_strdup_with_null(pubc->pool, &pubc->str_target_uri, target_uri);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000213
214 /* Set server URL. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000215 tmp = pubc->str_target_uri;
216 pubc->target_uri = pjsip_parse_uri( pubc->pool, tmp.ptr, tmp.slen, 0);
217 if (pubc->target_uri == NULL) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000218 return PJSIP_EINVALIDURI;
219 }
220
221 /* Set "From" header. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000222 pj_strdup_with_null(pubc->pool, &pubc->from_uri, from_uri);
223 tmp = pubc->from_uri;
224 pubc->from_hdr = pjsip_from_hdr_create(pubc->pool);
225 pubc->from_hdr->uri = pjsip_parse_uri(pubc->pool, tmp.ptr, tmp.slen,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000226 PJSIP_PARSE_URI_AS_NAMEADDR);
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000227 if (!pubc->from_hdr->uri) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000228 return PJSIP_EINVALIDURI;
229 }
230
231 /* Set "To" header. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000232 pj_strdup_with_null(pubc->pool, &tmp, to_uri);
233 pubc->to_hdr = pjsip_to_hdr_create(pubc->pool);
234 pubc->to_hdr->uri = pjsip_parse_uri(pubc->pool, tmp.ptr, tmp.slen,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000235 PJSIP_PARSE_URI_AS_NAMEADDR);
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000236 if (!pubc->to_hdr->uri) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000237 return PJSIP_EINVALIDURI;
238 }
239
240
Benny Prijono21b9ad92006-08-15 13:11:22 +0000241 /* Set "Expires" header, if required. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000242 set_expires( pubc, expires);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000243
244 /* Set "Call-ID" header. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000245 pubc->cid_hdr = pjsip_cid_hdr_create(pubc->pool);
246 pj_create_unique_string(pubc->pool, &pubc->cid_hdr->id);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000247
248 /* Set "CSeq" header. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000249 pubc->cseq_hdr = pjsip_cseq_hdr_create(pubc->pool);
250 pubc->cseq_hdr->cseq = pj_rand() % 0xFFFF;
251 pjsip_method_set( &pubc->cseq_hdr->method, PJSIP_REGISTER_METHOD);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000252
253 /* Done. */
254 return PJ_SUCCESS;
255}
256
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000257PJ_DEF(pj_status_t) pjsip_publishc_set_credentials( pjsip_publishc *pubc,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000258 int count,
259 const pjsip_cred_info cred[] )
260{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000261 PJ_ASSERT_RETURN(pubc && count && cred, PJ_EINVAL);
262 return pjsip_auth_clt_set_credentials(&pubc->auth_sess, count, cred);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000263}
264
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000265PJ_DEF(pj_status_t) pjsip_publishc_set_route_set( pjsip_publishc *pubc,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000266 const pjsip_route_hdr *route_set)
267{
268 const pjsip_route_hdr *chdr;
269
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000270 PJ_ASSERT_RETURN(pubc && route_set, PJ_EINVAL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000271
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000272 pj_list_init(&pubc->route_set);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000273
274 chdr = route_set->next;
275 while (chdr != route_set) {
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000276 pj_list_push_back(&pubc->route_set, pjsip_hdr_clone(pubc->pool, chdr));
Benny Prijono21b9ad92006-08-15 13:11:22 +0000277 chdr = chdr->next;
278 }
279
280 return PJ_SUCCESS;
281}
282
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000283static pj_status_t create_request(pjsip_publishc *pubc,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000284 pjsip_tx_data **p_tdata)
285{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000286 const pj_str_t STR_EVENT = { "Event", 5 };
Benny Prijono21b9ad92006-08-15 13:11:22 +0000287 pj_status_t status;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000288 pjsip_generic_string_hdr *hdr;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000289 pjsip_tx_data *tdata;
290
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000291 PJ_ASSERT_RETURN(pubc && p_tdata, PJ_EINVAL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000292
293 /* Create the request. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000294 status = pjsip_endpt_create_request_from_hdr( pubc->endpt,
295 &pjsip_publish_method,
296 pubc->target_uri,
297 pubc->from_hdr,
298 pubc->to_hdr,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000299 NULL,
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000300 pubc->cid_hdr,
301 pubc->cseq_hdr->cseq,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000302 NULL,
303 &tdata);
304 if (status != PJ_SUCCESS)
305 return status;
306
307 /* Add cached authorization headers. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000308 pjsip_auth_clt_init_req( &pubc->auth_sess, tdata );
Benny Prijono21b9ad92006-08-15 13:11:22 +0000309
310 /* Add Route headers from route set, ideally after Via header */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000311 if (!pj_list_empty(&pubc->route_set)) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000312 pjsip_hdr *route_pos;
313 const pjsip_route_hdr *route;
314
Benny Prijono9d4469d2007-05-02 05:14:29 +0000315 route_pos = (pjsip_hdr*)
316 pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000317 if (!route_pos)
318 route_pos = &tdata->msg->hdr;
319
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000320 route = pubc->route_set.next;
321 while (route != &pubc->route_set) {
Benny Prijono9d4469d2007-05-02 05:14:29 +0000322 pjsip_hdr *new_hdr = (pjsip_hdr*)
323 pjsip_hdr_shallow_clone(tdata->pool, route);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000324 pj_list_insert_after(route_pos, new_hdr);
325 route_pos = new_hdr;
326 route = route->next;
327 }
328 }
329
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000330 /* Add Event header */
331 hdr = pjsip_generic_string_hdr_create(tdata->pool, &STR_EVENT,
332 &pubc->event);
333 if (hdr)
334 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);
335
336
337 /* Add SIP-If-Match if we have etag */
338 if (pubc->etag.slen) {
339 const pj_str_t STR_HNAME = { "SIP-If-Match", 12 };
340
341 hdr = pjsip_generic_string_hdr_create(tdata->pool, &STR_HNAME,
342 &pubc->etag);
343 if (hdr)
344 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);
345 }
346
347
Benny Prijono21b9ad92006-08-15 13:11:22 +0000348 /* Done. */
349 *p_tdata = tdata;
350 return PJ_SUCCESS;
351}
352
353
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000354PJ_DEF(pj_status_t) pjsip_publishc_publish(pjsip_publishc *pubc,
355 pj_bool_t auto_refresh,
356 pjsip_tx_data **p_tdata)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000357{
Benny Prijono21b9ad92006-08-15 13:11:22 +0000358 pj_status_t status;
359 pjsip_tx_data *tdata;
360
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000361 PJ_ASSERT_RETURN(pubc && p_tdata, PJ_EINVAL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000362
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000363 status = create_request(pubc, &tdata);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000364 if (status != PJ_SUCCESS)
365 return status;
366
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000367 /* Add Expires header */
368 if (pubc->expires_hdr) {
369 pjsip_hdr *dup;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000370
Benny Prijono9d4469d2007-05-02 05:14:29 +0000371 dup = (pjsip_hdr*)
372 pjsip_hdr_shallow_clone(tdata->pool, pubc->expires_hdr);
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000373 if (dup)
374 pjsip_msg_add_hdr(tdata->msg, dup);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000375 }
376
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000377 /* Cancel existing timer */
378 if (pubc->timer.id != 0) {
379 pjsip_endpt_cancel_timer(pubc->endpt, &pubc->timer);
380 pubc->timer.id = 0;
381 }
382
383 pubc->auto_refresh = auto_refresh;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000384
385 /* Done */
386 *p_tdata = tdata;
387 return PJ_SUCCESS;
388}
389
390
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000391PJ_DEF(pj_status_t) pjsip_publishc_unpublish(pjsip_publishc *pubc,
392 pjsip_tx_data **p_tdata)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000393{
394 pjsip_tx_data *tdata;
395 pjsip_msg *msg;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000396 pjsip_expires_hdr *expires;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000397 pj_status_t status;
398
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000399 PJ_ASSERT_RETURN(pubc && p_tdata, PJ_EINVAL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000400
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000401 if (pubc->timer.id != 0) {
402 pjsip_endpt_cancel_timer(pubc->endpt, &pubc->timer);
403 pubc->timer.id = 0;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000404 }
405
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000406 status = create_request(pubc, &tdata);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000407 if (status != PJ_SUCCESS)
408 return status;
409
410 msg = tdata->msg;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000411
412 /* Add Expires:0 header */
413 expires = pjsip_expires_hdr_create(tdata->pool, 0);
414 pjsip_msg_add_hdr( msg, (pjsip_hdr*)expires);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000415
416 *p_tdata = tdata;
417 return PJ_SUCCESS;
418}
419
420
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000421PJ_DEF(pj_status_t) pjsip_publishc_update_expires( pjsip_publishc *pubc,
422 pj_uint32_t expires )
Benny Prijono21b9ad92006-08-15 13:11:22 +0000423{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000424 PJ_ASSERT_RETURN(pubc, PJ_EINVAL);
425 set_expires( pubc, expires );
Benny Prijono21b9ad92006-08-15 13:11:22 +0000426 return PJ_SUCCESS;
427}
428
429
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000430static void call_callback(pjsip_publishc *pubc, pj_status_t status,
431 int st_code, const pj_str_t *reason,
432 pjsip_rx_data *rdata, pj_int32_t expiration)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000433{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000434 struct pjsip_publishc_cbparam cbparam;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000435
436
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000437 cbparam.pubc = pubc;
438 cbparam.token = pubc->token;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000439 cbparam.status = status;
440 cbparam.code = st_code;
441 cbparam.reason = *reason;
442 cbparam.rdata = rdata;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000443 cbparam.expiration = expiration;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000444
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000445 (*pubc->cb)(&cbparam);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000446}
447
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000448static void pubc_refresh_timer_cb( pj_timer_heap_t *timer_heap,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000449 struct pj_timer_entry *entry)
450{
Benny Prijono9d4469d2007-05-02 05:14:29 +0000451 pjsip_publishc *pubc = (pjsip_publishc*) entry->user_data;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000452 pjsip_tx_data *tdata;
453 pj_status_t status;
454
455 PJ_UNUSED_ARG(timer_heap);
456
457 entry->id = 0;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000458 status = pjsip_publishc_publish(pubc, 1, &tdata);
Benny Prijono0e9f7622008-07-01 19:11:55 +0000459 if (status != PJ_SUCCESS) {
460 char errmsg[PJ_ERR_MSG_SIZE];
461 pj_str_t reason = pj_strerror(status, errmsg, sizeof(errmsg));
462 call_callback(pubc, status, 400, &reason, NULL, -1);
463 return;
464 }
465
466 status = pjsip_publishc_send(pubc, tdata);
467 /* No need to call callback as it should have been called */
Benny Prijono21b9ad92006-08-15 13:11:22 +0000468}
469
470static void tsx_callback(void *token, pjsip_event *event)
471{
472 pj_status_t status;
Benny Prijono9d4469d2007-05-02 05:14:29 +0000473 pjsip_publishc *pubc = (pjsip_publishc*) token;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000474 pjsip_transaction *tsx = event->body.tsx_state.tsx;
475
476 /* Decrement pending transaction counter. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000477 pj_assert(pubc->pending_tsx > 0);
478 --pubc->pending_tsx;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000479
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000480 /* If publication data has been deleted by user then remove publication
Benny Prijono21b9ad92006-08-15 13:11:22 +0000481 * data from transaction's callback, and don't call callback.
482 */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000483 if (pubc->_delete_flag) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000484
485 /* Nothing to do */
486 ;
487
488 } else if (tsx->status_code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED ||
489 tsx->status_code == PJSIP_SC_UNAUTHORIZED)
490 {
491 pjsip_rx_data *rdata = event->body.tsx_state.src.rdata;
492 pjsip_tx_data *tdata;
493
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000494 status = pjsip_auth_clt_reinit_req( &pubc->auth_sess,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000495 rdata,
496 tsx->last_tx,
497 &tdata);
Benny Prijono0e9f7622008-07-01 19:11:55 +0000498 if (status != PJ_SUCCESS) {
499 call_callback(pubc, status, tsx->status_code,
500 &rdata->msg_info.msg->line.status.reason,
501 rdata, -1);
502 } else {
503 status = pjsip_publishc_send(pubc, tdata);
504 }
Benny Prijono21b9ad92006-08-15 13:11:22 +0000505
506 } else {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000507 pjsip_rx_data *rdata;
508 pj_int32_t expiration = 0xFFFF;
509
510 if (tsx->status_code/100 == 2) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000511 pjsip_msg *msg;
512 pjsip_expires_hdr *expires;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000513 pjsip_generic_string_hdr *etag_hdr;
514 const pj_str_t STR_ETAG = { "SIP-ETag", 8 };
Benny Prijono21b9ad92006-08-15 13:11:22 +0000515
516 rdata = event->body.tsx_state.src.rdata;
517 msg = rdata->msg_info.msg;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000518
519 /* Save ETag value */
520 etag_hdr = (pjsip_generic_string_hdr*)
521 pjsip_msg_find_hdr_by_name(msg, &STR_ETAG, NULL);
522 if (etag_hdr) {
523 pj_strdup(pubc->pool, &pubc->etag, &etag_hdr->hvalue);
524 } else {
525 pubc->etag.slen = 0;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000526 }
527
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000528 /* Update expires value */
Benny Prijono9d4469d2007-05-02 05:14:29 +0000529 expires = (pjsip_expires_hdr*)
530 pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000531
532 if (expires)
533 expiration = expires->ivalue;
534
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000535 if (pubc->auto_refresh && expiration!=0 && expiration!=0xFFFF) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000536 pj_time_val delay = { 0, 0};
537
538 delay.sec = expiration - DELAY_BEFORE_REFRESH;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000539 if (pubc->expires != PJSIP_PUBC_EXPIRATION_NOT_SPECIFIED &&
540 delay.sec > (pj_int32_t)pubc->expires)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000541 {
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000542 delay.sec = pubc->expires;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000543 }
544 if (delay.sec < DELAY_BEFORE_REFRESH)
545 delay.sec = DELAY_BEFORE_REFRESH;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000546 pubc->timer.cb = &pubc_refresh_timer_cb;
547 pubc->timer.id = REFRESH_TIMER;
548 pubc->timer.user_data = pubc;
549 pjsip_endpt_schedule_timer( pubc->endpt, &pubc->timer, &delay);
550 pj_gettimeofday(&pubc->last_refresh);
551 pubc->next_refresh = pubc->last_refresh;
552 pubc->next_refresh.sec += delay.sec;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000553 }
554
555 } else {
556 rdata = (event->body.tsx_state.type==PJSIP_EVENT_RX_MSG) ?
557 event->body.tsx_state.src.rdata : NULL;
558 }
559
560
561 /* Call callback. */
562 if (expiration == 0xFFFF) expiration = -1;
Benny Prijonoda1e0632007-05-23 14:12:35 +0000563
564 /* Temporarily increment pending_tsx to prevent callback from
565 * destroying pubc.
566 */
567 ++pubc->pending_tsx;
568
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000569 call_callback(pubc, PJ_SUCCESS, tsx->status_code,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000570 (rdata ? &rdata->msg_info.msg->line.status.reason
571 : pjsip_get_status_text(tsx->status_code)),
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000572 rdata, expiration);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000573
Benny Prijonoda1e0632007-05-23 14:12:35 +0000574 --pubc->pending_tsx;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000575 }
576
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000577 /* Delete the record if user destroy pubc during the callback. */
578 if (pubc->_delete_flag && pubc->pending_tsx==0) {
579 pjsip_publishc_destroy(pubc);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000580 }
581}
582
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000583
584PJ_DEF(pj_status_t) pjsip_publishc_send(pjsip_publishc *pubc,
585 pjsip_tx_data *tdata)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000586{
587 pj_status_t status;
588 pjsip_cseq_hdr *cseq_hdr;
589 pj_uint32_t cseq;
590
591 /* Make sure we don't have pending transaction. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000592 if (pubc->pending_tsx) {
593 PJ_LOG(4,(THIS_FILE, "Unable to send request, pubc has another "
Benny Prijono21b9ad92006-08-15 13:11:22 +0000594 "transaction pending"));
595 pjsip_tx_data_dec_ref( tdata );
596 return PJSIP_EBUSY;
597 }
598
599 /* Invalidate message buffer. */
600 pjsip_tx_data_invalidate_msg(tdata);
601
602 /* Increment CSeq */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000603 cseq = ++pubc->cseq_hdr->cseq;
Benny Prijono9d4469d2007-05-02 05:14:29 +0000604 cseq_hdr = (pjsip_cseq_hdr*)
605 pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000606 cseq_hdr->cseq = cseq;
607
608 /* Increment pending transaction first, since transaction callback
609 * may be called even before send_request() returns!
610 */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000611 ++pubc->pending_tsx;
612 status = pjsip_endpt_send_request(pubc->endpt, tdata, -1, pubc,
613 &tsx_callback);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000614 if (status!=PJ_SUCCESS) {
Benny Prijono29438152007-06-28 02:47:32 +0000615 // no need to decrement, callback has been called and it should
616 // already decremented pending_tsx. Decrementing this here may
617 // cause accessing freed memory location.
618 //--pubc->pending_tsx;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000619 PJ_LOG(4,(THIS_FILE, "Error sending request, status=%d", status));
620 }
621
622 return status;
623}
624