blob: 6840d028a40f8ade2c65443a3e4acdbb35fc86a5 [file] [log] [blame]
Benny Prijono21b9ad92006-08-15 13:11:22 +00001/* $Id$ */
2/*
Benny Prijono844653c2008-12-23 17:27:53 +00003 * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
Benny Prijono32177c02008-06-20 22:44:47 +00004 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijono21b9ad92006-08-15 13:11:22 +00005 *
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 */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000020#include <pjsip-simple/publish.h>
21#include <pjsip/sip_auth.h>
Benny Prijono21b9ad92006-08-15 13:11:22 +000022#include <pjsip/sip_endpoint.h>
Benny Prijono21b9ad92006-08-15 13:11:22 +000023#include <pjsip/sip_errno.h>
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000024#include <pjsip/sip_event.h>
25#include <pjsip/sip_msg.h>
26#include <pjsip/sip_transaction.h>
27#include <pjsip/sip_uri.h>
28#include <pjsip/sip_util.h>
Benny Prijono21b9ad92006-08-15 13:11:22 +000029#include <pj/assert.h>
30#include <pj/guid.h>
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000031#include <pj/log.h>
Benny Prijono21b9ad92006-08-15 13:11:22 +000032#include <pj/os.h>
33#include <pj/pool.h>
Benny Prijono21b9ad92006-08-15 13:11:22 +000034#include <pj/rand.h>
35#include <pj/string.h>
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000036#include <pj/timer.h>
Benny Prijono21b9ad92006-08-15 13:11:22 +000037
38
39#define REFRESH_TIMER 1
40#define DELAY_BEFORE_REFRESH 5
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000041#define THIS_FILE "publishc.c"
42
43
Benny Prijonoc8141a82006-08-20 09:12:19 +000044/* Let's define this enum, so that it'll trigger compilation error
45 * when somebody define the same enum in sip_msg.h
46 */
47enum
48{
49 PJSIP_PUBLISH_METHOD = PJSIP_OTHER_METHOD,
50};
51
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000052const pjsip_method pjsip_publish_method =
53{
Benny Prijono9d4469d2007-05-02 05:14:29 +000054 (pjsip_method_e)PJSIP_PUBLISH_METHOD,
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000055 { "PUBLISH", 7 }
56};
57
Benny Prijono21b9ad92006-08-15 13:11:22 +000058
59/**
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000060 * SIP client publication structure.
Benny Prijono21b9ad92006-08-15 13:11:22 +000061 */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000062struct pjsip_publishc
Benny Prijono21b9ad92006-08-15 13:11:22 +000063{
64 pj_pool_t *pool;
65 pjsip_endpoint *endpt;
66 pj_bool_t _delete_flag;
67 int pending_tsx;
68
69 void *token;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000070 pjsip_publishc_cb *cb;
Benny Prijono21b9ad92006-08-15 13:11:22 +000071
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000072 pj_str_t event;
73 pj_str_t str_target_uri;
74 pjsip_uri *target_uri;
Benny Prijono21b9ad92006-08-15 13:11:22 +000075 pjsip_cid_hdr *cid_hdr;
76 pjsip_cseq_hdr *cseq_hdr;
77 pj_str_t from_uri;
78 pjsip_from_hdr *from_hdr;
79 pjsip_to_hdr *to_hdr;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000080 pj_str_t etag;
Benny Prijono21b9ad92006-08-15 13:11:22 +000081 pjsip_expires_hdr *expires_hdr;
Benny Prijono21b9ad92006-08-15 13:11:22 +000082 pj_uint32_t expires;
83 pjsip_route_hdr route_set;
84
85 /* Authorization sessions. */
86 pjsip_auth_clt_sess auth_sess;
87
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000088 /* Auto refresh publication. */
89 pj_bool_t auto_refresh;
90 pj_time_val last_refresh;
91 pj_time_val next_refresh;
Benny Prijono21b9ad92006-08-15 13:11:22 +000092 pj_timer_entry timer;
93};
94
95
96
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000097/*
98 * Initialize client publication module.
99 */
100PJ_DEF(pj_status_t) pjsip_publishc_init_module(pjsip_endpoint *endpt)
101{
Benny Prijono7741c8a2008-07-07 19:57:16 +0000102 /* Note:
103 Commented out the capability registration below, since it's
104 wrong to include PUBLISH in Allow header of INVITE requests/
105 responses.
106
107 13.2.1 Creating the Initial INVITE
108 An Allow header field (Section 20.5) SHOULD be present in the
109 INVITE. It indicates what methods can be invoked within a dialog
110
111 20.5 Allow
112 The Allow header field lists the set of methods supported by the
113 UA generating the message.
114
115 While the semantic of Allow header in non-dialog requests is unclear,
116 it's probably best not to include PUBLISH in Allow header for now
117 until we can find out how to customize the inclusion of methods in
118 Allow header for in-dialog vs out-dialog requests.
119
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000120 return pjsip_endpt_add_capability( endpt, NULL, PJSIP_H_ALLOW, NULL,
121 1, &pjsip_publish_method.name);
Benny Prijono7741c8a2008-07-07 19:57:16 +0000122 */
Benny Prijono10d8dbd2008-07-13 13:12:36 +0000123 PJ_UNUSED_ARG(endpt);
Benny Prijono7741c8a2008-07-07 19:57:16 +0000124 return PJ_SUCCESS;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000125}
126
127
128PJ_DEF(pj_status_t) pjsip_publishc_create( pjsip_endpoint *endpt,
129 unsigned options,
130 void *token,
131 pjsip_publishc_cb *cb,
132 pjsip_publishc **p_pubc)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000133{
134 pj_pool_t *pool;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000135 pjsip_publishc *pubc;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000136 pj_status_t status;
137
138 /* Verify arguments. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000139 PJ_ASSERT_RETURN(endpt && cb && p_pubc, PJ_EINVAL);
140 PJ_ASSERT_RETURN(options == 0, PJ_EINVAL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000141
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000142 PJ_UNUSED_ARG(options);
143
144 pool = pjsip_endpt_create_pool(endpt, "pubc%p", 1024, 1024);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000145 PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
146
Benny Prijono9d4469d2007-05-02 05:14:29 +0000147 pubc = PJ_POOL_ZALLOC_T(pool, pjsip_publishc);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000148
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000149 pubc->pool = pool;
150 pubc->endpt = endpt;
151 pubc->token = token;
152 pubc->cb = cb;
153 pubc->expires = PJSIP_PUBC_EXPIRATION_NOT_SPECIFIED;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000154
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000155 status = pjsip_auth_clt_init(&pubc->auth_sess, endpt, pubc->pool, 0);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000156 if (status != PJ_SUCCESS)
157 return status;
158
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000159 pj_list_init(&pubc->route_set);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000160
161 /* Done */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000162 *p_pubc = pubc;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000163 return PJ_SUCCESS;
164}
165
166
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000167PJ_DEF(pj_status_t) pjsip_publishc_destroy(pjsip_publishc *pubc)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000168{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000169 PJ_ASSERT_RETURN(pubc, PJ_EINVAL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000170
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000171 if (pubc->pending_tsx) {
172 pubc->_delete_flag = 1;
173 pubc->cb = NULL;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000174 } else {
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000175 pjsip_endpt_release_pool(pubc->endpt, pubc->pool);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000176 }
177
178 return PJ_SUCCESS;
179}
180
181
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000182PJ_DEF(pj_pool_t*) pjsip_publishc_get_pool(pjsip_publishc *pubc)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000183{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000184 return pubc->pool;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000185}
186
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000187static void set_expires( pjsip_publishc *pubc, pj_uint32_t expires)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000188{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000189 if (expires != pubc->expires) {
190 pubc->expires_hdr = pjsip_expires_hdr_create(pubc->pool, expires);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000191 } else {
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000192 pubc->expires_hdr = NULL;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000193 }
194}
195
196
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000197PJ_DEF(pj_status_t) pjsip_publishc_init(pjsip_publishc *pubc,
198 const pj_str_t *event,
199 const pj_str_t *target_uri,
200 const pj_str_t *from_uri,
201 const pj_str_t *to_uri,
202 pj_uint32_t expires)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000203{
204 pj_str_t tmp;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000205
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000206 PJ_ASSERT_RETURN(pubc && event && target_uri && from_uri && to_uri &&
207 expires, PJ_EINVAL);
208
209 /* Copy event type */
210 pj_strdup_with_null(pubc->pool, &pubc->event, event);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000211
212 /* Copy server URL. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000213 pj_strdup_with_null(pubc->pool, &pubc->str_target_uri, target_uri);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000214
215 /* Set server URL. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000216 tmp = pubc->str_target_uri;
217 pubc->target_uri = pjsip_parse_uri( pubc->pool, tmp.ptr, tmp.slen, 0);
218 if (pubc->target_uri == NULL) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000219 return PJSIP_EINVALIDURI;
220 }
221
222 /* Set "From" header. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000223 pj_strdup_with_null(pubc->pool, &pubc->from_uri, from_uri);
224 tmp = pubc->from_uri;
225 pubc->from_hdr = pjsip_from_hdr_create(pubc->pool);
226 pubc->from_hdr->uri = pjsip_parse_uri(pubc->pool, tmp.ptr, tmp.slen,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000227 PJSIP_PARSE_URI_AS_NAMEADDR);
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000228 if (!pubc->from_hdr->uri) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000229 return PJSIP_EINVALIDURI;
230 }
231
232 /* Set "To" header. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000233 pj_strdup_with_null(pubc->pool, &tmp, to_uri);
234 pubc->to_hdr = pjsip_to_hdr_create(pubc->pool);
235 pubc->to_hdr->uri = pjsip_parse_uri(pubc->pool, tmp.ptr, tmp.slen,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000236 PJSIP_PARSE_URI_AS_NAMEADDR);
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000237 if (!pubc->to_hdr->uri) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000238 return PJSIP_EINVALIDURI;
239 }
240
241
Benny Prijono21b9ad92006-08-15 13:11:22 +0000242 /* Set "Expires" header, if required. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000243 set_expires( pubc, expires);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000244
245 /* Set "Call-ID" header. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000246 pubc->cid_hdr = pjsip_cid_hdr_create(pubc->pool);
247 pj_create_unique_string(pubc->pool, &pubc->cid_hdr->id);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000248
249 /* Set "CSeq" header. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000250 pubc->cseq_hdr = pjsip_cseq_hdr_create(pubc->pool);
251 pubc->cseq_hdr->cseq = pj_rand() % 0xFFFF;
252 pjsip_method_set( &pubc->cseq_hdr->method, PJSIP_REGISTER_METHOD);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000253
254 /* Done. */
255 return PJ_SUCCESS;
256}
257
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000258PJ_DEF(pj_status_t) pjsip_publishc_set_credentials( pjsip_publishc *pubc,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000259 int count,
260 const pjsip_cred_info cred[] )
261{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000262 PJ_ASSERT_RETURN(pubc && count && cred, PJ_EINVAL);
263 return pjsip_auth_clt_set_credentials(&pubc->auth_sess, count, cred);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000264}
265
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000266PJ_DEF(pj_status_t) pjsip_publishc_set_route_set( pjsip_publishc *pubc,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000267 const pjsip_route_hdr *route_set)
268{
269 const pjsip_route_hdr *chdr;
270
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000271 PJ_ASSERT_RETURN(pubc && route_set, PJ_EINVAL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000272
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000273 pj_list_init(&pubc->route_set);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000274
275 chdr = route_set->next;
276 while (chdr != route_set) {
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000277 pj_list_push_back(&pubc->route_set, pjsip_hdr_clone(pubc->pool, chdr));
Benny Prijono21b9ad92006-08-15 13:11:22 +0000278 chdr = chdr->next;
279 }
280
281 return PJ_SUCCESS;
282}
283
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000284static pj_status_t create_request(pjsip_publishc *pubc,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000285 pjsip_tx_data **p_tdata)
286{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000287 const pj_str_t STR_EVENT = { "Event", 5 };
Benny Prijono21b9ad92006-08-15 13:11:22 +0000288 pj_status_t status;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000289 pjsip_generic_string_hdr *hdr;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000290 pjsip_tx_data *tdata;
291
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000292 PJ_ASSERT_RETURN(pubc && p_tdata, PJ_EINVAL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000293
294 /* Create the request. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000295 status = pjsip_endpt_create_request_from_hdr( pubc->endpt,
296 &pjsip_publish_method,
297 pubc->target_uri,
298 pubc->from_hdr,
299 pubc->to_hdr,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000300 NULL,
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000301 pubc->cid_hdr,
302 pubc->cseq_hdr->cseq,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000303 NULL,
304 &tdata);
305 if (status != PJ_SUCCESS)
306 return status;
307
308 /* Add cached authorization headers. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000309 pjsip_auth_clt_init_req( &pubc->auth_sess, tdata );
Benny Prijono21b9ad92006-08-15 13:11:22 +0000310
311 /* Add Route headers from route set, ideally after Via header */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000312 if (!pj_list_empty(&pubc->route_set)) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000313 pjsip_hdr *route_pos;
314 const pjsip_route_hdr *route;
315
Benny Prijono9d4469d2007-05-02 05:14:29 +0000316 route_pos = (pjsip_hdr*)
317 pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000318 if (!route_pos)
319 route_pos = &tdata->msg->hdr;
320
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000321 route = pubc->route_set.next;
322 while (route != &pubc->route_set) {
Benny Prijono9d4469d2007-05-02 05:14:29 +0000323 pjsip_hdr *new_hdr = (pjsip_hdr*)
324 pjsip_hdr_shallow_clone(tdata->pool, route);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000325 pj_list_insert_after(route_pos, new_hdr);
326 route_pos = new_hdr;
327 route = route->next;
328 }
329 }
330
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000331 /* Add Event header */
332 hdr = pjsip_generic_string_hdr_create(tdata->pool, &STR_EVENT,
333 &pubc->event);
334 if (hdr)
335 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);
336
337
338 /* Add SIP-If-Match if we have etag */
339 if (pubc->etag.slen) {
340 const pj_str_t STR_HNAME = { "SIP-If-Match", 12 };
341
342 hdr = pjsip_generic_string_hdr_create(tdata->pool, &STR_HNAME,
343 &pubc->etag);
344 if (hdr)
345 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);
346 }
347
348
Benny Prijono21b9ad92006-08-15 13:11:22 +0000349 /* Done. */
350 *p_tdata = tdata;
351 return PJ_SUCCESS;
352}
353
354
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000355PJ_DEF(pj_status_t) pjsip_publishc_publish(pjsip_publishc *pubc,
356 pj_bool_t auto_refresh,
357 pjsip_tx_data **p_tdata)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000358{
Benny Prijono21b9ad92006-08-15 13:11:22 +0000359 pj_status_t status;
360 pjsip_tx_data *tdata;
361
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000362 PJ_ASSERT_RETURN(pubc && p_tdata, PJ_EINVAL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000363
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000364 status = create_request(pubc, &tdata);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000365 if (status != PJ_SUCCESS)
366 return status;
367
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000368 /* Add Expires header */
369 if (pubc->expires_hdr) {
370 pjsip_hdr *dup;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000371
Benny Prijono9d4469d2007-05-02 05:14:29 +0000372 dup = (pjsip_hdr*)
373 pjsip_hdr_shallow_clone(tdata->pool, pubc->expires_hdr);
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000374 if (dup)
375 pjsip_msg_add_hdr(tdata->msg, dup);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000376 }
377
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000378 /* Cancel existing timer */
379 if (pubc->timer.id != 0) {
380 pjsip_endpt_cancel_timer(pubc->endpt, &pubc->timer);
381 pubc->timer.id = 0;
382 }
383
384 pubc->auto_refresh = auto_refresh;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000385
386 /* Done */
387 *p_tdata = tdata;
388 return PJ_SUCCESS;
389}
390
391
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000392PJ_DEF(pj_status_t) pjsip_publishc_unpublish(pjsip_publishc *pubc,
393 pjsip_tx_data **p_tdata)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000394{
395 pjsip_tx_data *tdata;
396 pjsip_msg *msg;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000397 pjsip_expires_hdr *expires;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000398 pj_status_t status;
399
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000400 PJ_ASSERT_RETURN(pubc && p_tdata, PJ_EINVAL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000401
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000402 if (pubc->timer.id != 0) {
403 pjsip_endpt_cancel_timer(pubc->endpt, &pubc->timer);
404 pubc->timer.id = 0;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000405 }
406
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000407 status = create_request(pubc, &tdata);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000408 if (status != PJ_SUCCESS)
409 return status;
410
411 msg = tdata->msg;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000412
413 /* Add Expires:0 header */
414 expires = pjsip_expires_hdr_create(tdata->pool, 0);
415 pjsip_msg_add_hdr( msg, (pjsip_hdr*)expires);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000416
417 *p_tdata = tdata;
418 return PJ_SUCCESS;
419}
420
421
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000422PJ_DEF(pj_status_t) pjsip_publishc_update_expires( pjsip_publishc *pubc,
423 pj_uint32_t expires )
Benny Prijono21b9ad92006-08-15 13:11:22 +0000424{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000425 PJ_ASSERT_RETURN(pubc, PJ_EINVAL);
426 set_expires( pubc, expires );
Benny Prijono21b9ad92006-08-15 13:11:22 +0000427 return PJ_SUCCESS;
428}
429
430
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000431static void call_callback(pjsip_publishc *pubc, pj_status_t status,
432 int st_code, const pj_str_t *reason,
433 pjsip_rx_data *rdata, pj_int32_t expiration)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000434{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000435 struct pjsip_publishc_cbparam cbparam;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000436
437
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000438 cbparam.pubc = pubc;
439 cbparam.token = pubc->token;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000440 cbparam.status = status;
441 cbparam.code = st_code;
442 cbparam.reason = *reason;
443 cbparam.rdata = rdata;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000444 cbparam.expiration = expiration;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000445
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000446 (*pubc->cb)(&cbparam);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000447}
448
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000449static void pubc_refresh_timer_cb( pj_timer_heap_t *timer_heap,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000450 struct pj_timer_entry *entry)
451{
Benny Prijono9d4469d2007-05-02 05:14:29 +0000452 pjsip_publishc *pubc = (pjsip_publishc*) entry->user_data;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000453 pjsip_tx_data *tdata;
454 pj_status_t status;
455
456 PJ_UNUSED_ARG(timer_heap);
457
458 entry->id = 0;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000459 status = pjsip_publishc_publish(pubc, 1, &tdata);
Benny Prijono0e9f7622008-07-01 19:11:55 +0000460 if (status != PJ_SUCCESS) {
461 char errmsg[PJ_ERR_MSG_SIZE];
462 pj_str_t reason = pj_strerror(status, errmsg, sizeof(errmsg));
463 call_callback(pubc, status, 400, &reason, NULL, -1);
464 return;
465 }
466
467 status = pjsip_publishc_send(pubc, tdata);
468 /* No need to call callback as it should have been called */
Benny Prijono21b9ad92006-08-15 13:11:22 +0000469}
470
471static void tsx_callback(void *token, pjsip_event *event)
472{
473 pj_status_t status;
Benny Prijono9d4469d2007-05-02 05:14:29 +0000474 pjsip_publishc *pubc = (pjsip_publishc*) token;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000475 pjsip_transaction *tsx = event->body.tsx_state.tsx;
476
477 /* Decrement pending transaction counter. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000478 pj_assert(pubc->pending_tsx > 0);
479 --pubc->pending_tsx;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000480
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000481 /* If publication data has been deleted by user then remove publication
Benny Prijono21b9ad92006-08-15 13:11:22 +0000482 * data from transaction's callback, and don't call callback.
483 */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000484 if (pubc->_delete_flag) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000485
486 /* Nothing to do */
487 ;
488
489 } else if (tsx->status_code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED ||
490 tsx->status_code == PJSIP_SC_UNAUTHORIZED)
491 {
492 pjsip_rx_data *rdata = event->body.tsx_state.src.rdata;
493 pjsip_tx_data *tdata;
494
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000495 status = pjsip_auth_clt_reinit_req( &pubc->auth_sess,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000496 rdata,
497 tsx->last_tx,
498 &tdata);
Benny Prijono0e9f7622008-07-01 19:11:55 +0000499 if (status != PJ_SUCCESS) {
500 call_callback(pubc, status, tsx->status_code,
501 &rdata->msg_info.msg->line.status.reason,
502 rdata, -1);
503 } else {
504 status = pjsip_publishc_send(pubc, tdata);
505 }
Benny Prijono21b9ad92006-08-15 13:11:22 +0000506
507 } else {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000508 pjsip_rx_data *rdata;
509 pj_int32_t expiration = 0xFFFF;
510
511 if (tsx->status_code/100 == 2) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000512 pjsip_msg *msg;
513 pjsip_expires_hdr *expires;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000514 pjsip_generic_string_hdr *etag_hdr;
515 const pj_str_t STR_ETAG = { "SIP-ETag", 8 };
Benny Prijono21b9ad92006-08-15 13:11:22 +0000516
517 rdata = event->body.tsx_state.src.rdata;
518 msg = rdata->msg_info.msg;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000519
520 /* Save ETag value */
521 etag_hdr = (pjsip_generic_string_hdr*)
522 pjsip_msg_find_hdr_by_name(msg, &STR_ETAG, NULL);
523 if (etag_hdr) {
524 pj_strdup(pubc->pool, &pubc->etag, &etag_hdr->hvalue);
525 } else {
526 pubc->etag.slen = 0;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000527 }
528
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000529 /* Update expires value */
Benny Prijono9d4469d2007-05-02 05:14:29 +0000530 expires = (pjsip_expires_hdr*)
531 pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000532
533 if (expires)
534 expiration = expires->ivalue;
535
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000536 if (pubc->auto_refresh && expiration!=0 && expiration!=0xFFFF) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000537 pj_time_val delay = { 0, 0};
538
539 delay.sec = expiration - DELAY_BEFORE_REFRESH;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000540 if (pubc->expires != PJSIP_PUBC_EXPIRATION_NOT_SPECIFIED &&
541 delay.sec > (pj_int32_t)pubc->expires)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000542 {
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000543 delay.sec = pubc->expires;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000544 }
545 if (delay.sec < DELAY_BEFORE_REFRESH)
546 delay.sec = DELAY_BEFORE_REFRESH;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000547 pubc->timer.cb = &pubc_refresh_timer_cb;
548 pubc->timer.id = REFRESH_TIMER;
549 pubc->timer.user_data = pubc;
550 pjsip_endpt_schedule_timer( pubc->endpt, &pubc->timer, &delay);
551 pj_gettimeofday(&pubc->last_refresh);
552 pubc->next_refresh = pubc->last_refresh;
553 pubc->next_refresh.sec += delay.sec;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000554 }
555
556 } else {
557 rdata = (event->body.tsx_state.type==PJSIP_EVENT_RX_MSG) ?
558 event->body.tsx_state.src.rdata : NULL;
559 }
560
561
562 /* Call callback. */
563 if (expiration == 0xFFFF) expiration = -1;
Benny Prijonoda1e0632007-05-23 14:12:35 +0000564
565 /* Temporarily increment pending_tsx to prevent callback from
566 * destroying pubc.
567 */
568 ++pubc->pending_tsx;
569
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000570 call_callback(pubc, PJ_SUCCESS, tsx->status_code,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000571 (rdata ? &rdata->msg_info.msg->line.status.reason
572 : pjsip_get_status_text(tsx->status_code)),
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000573 rdata, expiration);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000574
Benny Prijonoda1e0632007-05-23 14:12:35 +0000575 --pubc->pending_tsx;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000576 }
577
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000578 /* Delete the record if user destroy pubc during the callback. */
579 if (pubc->_delete_flag && pubc->pending_tsx==0) {
580 pjsip_publishc_destroy(pubc);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000581 }
582}
583
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000584
585PJ_DEF(pj_status_t) pjsip_publishc_send(pjsip_publishc *pubc,
586 pjsip_tx_data *tdata)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000587{
588 pj_status_t status;
589 pjsip_cseq_hdr *cseq_hdr;
590 pj_uint32_t cseq;
591
592 /* Make sure we don't have pending transaction. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000593 if (pubc->pending_tsx) {
594 PJ_LOG(4,(THIS_FILE, "Unable to send request, pubc has another "
Benny Prijono21b9ad92006-08-15 13:11:22 +0000595 "transaction pending"));
596 pjsip_tx_data_dec_ref( tdata );
597 return PJSIP_EBUSY;
598 }
599
600 /* Invalidate message buffer. */
601 pjsip_tx_data_invalidate_msg(tdata);
602
603 /* Increment CSeq */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000604 cseq = ++pubc->cseq_hdr->cseq;
Benny Prijono9d4469d2007-05-02 05:14:29 +0000605 cseq_hdr = (pjsip_cseq_hdr*)
606 pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000607 cseq_hdr->cseq = cseq;
608
609 /* Increment pending transaction first, since transaction callback
610 * may be called even before send_request() returns!
611 */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000612 ++pubc->pending_tsx;
613 status = pjsip_endpt_send_request(pubc->endpt, tdata, -1, pubc,
614 &tsx_callback);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000615 if (status!=PJ_SUCCESS) {
Benny Prijono29438152007-06-28 02:47:32 +0000616 // no need to decrement, callback has been called and it should
617 // already decremented pending_tsx. Decrementing this here may
618 // cause accessing freed memory location.
619 //--pubc->pending_tsx;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000620 PJ_LOG(4,(THIS_FILE, "Error sending request, status=%d", status));
621 }
622
623 return status;
624}
625