blob: 749959bba0859d526c36cf19caed79baf5abe047 [file] [log] [blame]
Benny Prijono21b9ad92006-08-15 13:11:22 +00001/* $Id$ */
2/*
3 * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
4 *
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 Prijonoc8141a82006-08-20 09:12:19 +000053 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 Prijono3a5e1ab2006-08-15 20:26:34 +0000125 pubc = pj_pool_zalloc(pool, sizeof(struct 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
294 route_pos = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
295 if (!route_pos)
296 route_pos = &tdata->msg->hdr;
297
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000298 route = pubc->route_set.next;
299 while (route != &pubc->route_set) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000300 pjsip_hdr *new_hdr = pjsip_hdr_shallow_clone(tdata->pool, route);
301 pj_list_insert_after(route_pos, new_hdr);
302 route_pos = new_hdr;
303 route = route->next;
304 }
305 }
306
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000307 /* Add Event header */
308 hdr = pjsip_generic_string_hdr_create(tdata->pool, &STR_EVENT,
309 &pubc->event);
310 if (hdr)
311 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);
312
313
314 /* Add SIP-If-Match if we have etag */
315 if (pubc->etag.slen) {
316 const pj_str_t STR_HNAME = { "SIP-If-Match", 12 };
317
318 hdr = pjsip_generic_string_hdr_create(tdata->pool, &STR_HNAME,
319 &pubc->etag);
320 if (hdr)
321 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);
322 }
323
324
Benny Prijono21b9ad92006-08-15 13:11:22 +0000325 /* Done. */
326 *p_tdata = tdata;
327 return PJ_SUCCESS;
328}
329
330
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000331PJ_DEF(pj_status_t) pjsip_publishc_publish(pjsip_publishc *pubc,
332 pj_bool_t auto_refresh,
333 pjsip_tx_data **p_tdata)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000334{
Benny Prijono21b9ad92006-08-15 13:11:22 +0000335 pj_status_t status;
336 pjsip_tx_data *tdata;
337
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000338 PJ_ASSERT_RETURN(pubc && p_tdata, PJ_EINVAL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000339
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000340 status = create_request(pubc, &tdata);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000341 if (status != PJ_SUCCESS)
342 return status;
343
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000344 /* Add Expires header */
345 if (pubc->expires_hdr) {
346 pjsip_hdr *dup;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000347
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000348 dup = pjsip_hdr_shallow_clone(tdata->pool, pubc->expires_hdr);
349 if (dup)
350 pjsip_msg_add_hdr(tdata->msg, dup);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000351 }
352
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000353 /* Cancel existing timer */
354 if (pubc->timer.id != 0) {
355 pjsip_endpt_cancel_timer(pubc->endpt, &pubc->timer);
356 pubc->timer.id = 0;
357 }
358
359 pubc->auto_refresh = auto_refresh;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000360
361 /* Done */
362 *p_tdata = tdata;
363 return PJ_SUCCESS;
364}
365
366
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000367PJ_DEF(pj_status_t) pjsip_publishc_unpublish(pjsip_publishc *pubc,
368 pjsip_tx_data **p_tdata)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000369{
370 pjsip_tx_data *tdata;
371 pjsip_msg *msg;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000372 pjsip_expires_hdr *expires;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000373 pj_status_t status;
374
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000375 PJ_ASSERT_RETURN(pubc && p_tdata, PJ_EINVAL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000376
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000377 if (pubc->timer.id != 0) {
378 pjsip_endpt_cancel_timer(pubc->endpt, &pubc->timer);
379 pubc->timer.id = 0;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000380 }
381
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000382 status = create_request(pubc, &tdata);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000383 if (status != PJ_SUCCESS)
384 return status;
385
386 msg = tdata->msg;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000387
388 /* Add Expires:0 header */
389 expires = pjsip_expires_hdr_create(tdata->pool, 0);
390 pjsip_msg_add_hdr( msg, (pjsip_hdr*)expires);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000391
392 *p_tdata = tdata;
393 return PJ_SUCCESS;
394}
395
396
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000397PJ_DEF(pj_status_t) pjsip_publishc_update_expires( pjsip_publishc *pubc,
398 pj_uint32_t expires )
Benny Prijono21b9ad92006-08-15 13:11:22 +0000399{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000400 PJ_ASSERT_RETURN(pubc, PJ_EINVAL);
401 set_expires( pubc, expires );
Benny Prijono21b9ad92006-08-15 13:11:22 +0000402 return PJ_SUCCESS;
403}
404
405
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000406static void call_callback(pjsip_publishc *pubc, pj_status_t status,
407 int st_code, const pj_str_t *reason,
408 pjsip_rx_data *rdata, pj_int32_t expiration)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000409{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000410 struct pjsip_publishc_cbparam cbparam;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000411
412
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000413 cbparam.pubc = pubc;
414 cbparam.token = pubc->token;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000415 cbparam.status = status;
416 cbparam.code = st_code;
417 cbparam.reason = *reason;
418 cbparam.rdata = rdata;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000419 cbparam.expiration = expiration;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000420
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000421 (*pubc->cb)(&cbparam);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000422}
423
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000424static void pubc_refresh_timer_cb( pj_timer_heap_t *timer_heap,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000425 struct pj_timer_entry *entry)
426{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000427 pjsip_publishc *pubc = entry->user_data;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000428 pjsip_tx_data *tdata;
429 pj_status_t status;
430
431 PJ_UNUSED_ARG(timer_heap);
432
433 entry->id = 0;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000434 status = pjsip_publishc_publish(pubc, 1, &tdata);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000435 if (status == PJ_SUCCESS) {
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000436 status = pjsip_publishc_send(pubc, tdata);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000437 }
438
439 if (status != PJ_SUCCESS) {
440 char errmsg[PJ_ERR_MSG_SIZE];
441 pj_str_t reason = pj_strerror(status, errmsg, sizeof(errmsg));
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000442 call_callback(pubc, status, 400, &reason, NULL, -1);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000443 }
444}
445
446static void tsx_callback(void *token, pjsip_event *event)
447{
448 pj_status_t status;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000449 pjsip_publishc *pubc = token;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000450 pjsip_transaction *tsx = event->body.tsx_state.tsx;
451
452 /* Decrement pending transaction counter. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000453 pj_assert(pubc->pending_tsx > 0);
454 --pubc->pending_tsx;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000455
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000456 /* If publication data has been deleted by user then remove publication
Benny Prijono21b9ad92006-08-15 13:11:22 +0000457 * data from transaction's callback, and don't call callback.
458 */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000459 if (pubc->_delete_flag) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000460
461 /* Nothing to do */
462 ;
463
464 } else if (tsx->status_code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED ||
465 tsx->status_code == PJSIP_SC_UNAUTHORIZED)
466 {
467 pjsip_rx_data *rdata = event->body.tsx_state.src.rdata;
468 pjsip_tx_data *tdata;
469
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000470 status = pjsip_auth_clt_reinit_req( &pubc->auth_sess,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000471 rdata,
472 tsx->last_tx,
473 &tdata);
474
475 if (status == PJ_SUCCESS) {
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000476 status = pjsip_publishc_send(pubc, tdata);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000477 }
478
479 if (status != PJ_SUCCESS) {
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000480 call_callback(pubc, status, tsx->status_code,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000481 &rdata->msg_info.msg->line.status.reason,
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000482 rdata, -1);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000483 }
484
485 return;
486
487 } else {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000488 pjsip_rx_data *rdata;
489 pj_int32_t expiration = 0xFFFF;
490
491 if (tsx->status_code/100 == 2) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000492 pjsip_msg *msg;
493 pjsip_expires_hdr *expires;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000494 pjsip_generic_string_hdr *etag_hdr;
495 const pj_str_t STR_ETAG = { "SIP-ETag", 8 };
Benny Prijono21b9ad92006-08-15 13:11:22 +0000496
497 rdata = event->body.tsx_state.src.rdata;
498 msg = rdata->msg_info.msg;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000499
500 /* Save ETag value */
501 etag_hdr = (pjsip_generic_string_hdr*)
502 pjsip_msg_find_hdr_by_name(msg, &STR_ETAG, NULL);
503 if (etag_hdr) {
504 pj_strdup(pubc->pool, &pubc->etag, &etag_hdr->hvalue);
505 } else {
506 pubc->etag.slen = 0;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000507 }
508
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000509 /* Update expires value */
Benny Prijono21b9ad92006-08-15 13:11:22 +0000510 expires = pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL);
511
512 if (expires)
513 expiration = expires->ivalue;
514
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000515 if (pubc->auto_refresh && expiration!=0 && expiration!=0xFFFF) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000516 pj_time_val delay = { 0, 0};
517
518 delay.sec = expiration - DELAY_BEFORE_REFRESH;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000519 if (pubc->expires != PJSIP_PUBC_EXPIRATION_NOT_SPECIFIED &&
520 delay.sec > (pj_int32_t)pubc->expires)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000521 {
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000522 delay.sec = pubc->expires;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000523 }
524 if (delay.sec < DELAY_BEFORE_REFRESH)
525 delay.sec = DELAY_BEFORE_REFRESH;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000526 pubc->timer.cb = &pubc_refresh_timer_cb;
527 pubc->timer.id = REFRESH_TIMER;
528 pubc->timer.user_data = pubc;
529 pjsip_endpt_schedule_timer( pubc->endpt, &pubc->timer, &delay);
530 pj_gettimeofday(&pubc->last_refresh);
531 pubc->next_refresh = pubc->last_refresh;
532 pubc->next_refresh.sec += delay.sec;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000533 }
534
535 } else {
536 rdata = (event->body.tsx_state.type==PJSIP_EVENT_RX_MSG) ?
537 event->body.tsx_state.src.rdata : NULL;
538 }
539
540
541 /* Call callback. */
542 if (expiration == 0xFFFF) expiration = -1;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000543 call_callback(pubc, PJ_SUCCESS, tsx->status_code,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000544 (rdata ? &rdata->msg_info.msg->line.status.reason
545 : pjsip_get_status_text(tsx->status_code)),
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000546 rdata, expiration);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000547
548 }
549
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000550 /* Delete the record if user destroy pubc during the callback. */
551 if (pubc->_delete_flag && pubc->pending_tsx==0) {
552 pjsip_publishc_destroy(pubc);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000553 }
554}
555
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000556
557PJ_DEF(pj_status_t) pjsip_publishc_send(pjsip_publishc *pubc,
558 pjsip_tx_data *tdata)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000559{
560 pj_status_t status;
561 pjsip_cseq_hdr *cseq_hdr;
562 pj_uint32_t cseq;
563
564 /* Make sure we don't have pending transaction. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000565 if (pubc->pending_tsx) {
566 PJ_LOG(4,(THIS_FILE, "Unable to send request, pubc has another "
Benny Prijono21b9ad92006-08-15 13:11:22 +0000567 "transaction pending"));
568 pjsip_tx_data_dec_ref( tdata );
569 return PJSIP_EBUSY;
570 }
571
572 /* Invalidate message buffer. */
573 pjsip_tx_data_invalidate_msg(tdata);
574
575 /* Increment CSeq */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000576 cseq = ++pubc->cseq_hdr->cseq;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000577 cseq_hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
578 cseq_hdr->cseq = cseq;
579
580 /* Increment pending transaction first, since transaction callback
581 * may be called even before send_request() returns!
582 */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000583 ++pubc->pending_tsx;
584 status = pjsip_endpt_send_request(pubc->endpt, tdata, -1, pubc,
585 &tsx_callback);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000586 if (status!=PJ_SUCCESS) {
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000587 --pubc->pending_tsx;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000588 PJ_LOG(4,(THIS_FILE, "Error sending request, status=%d", status));
589 }
590
591 return status;
592}
593
594