blob: 5a0df96368225a3299d77d09186d94e1e53ff0a7 [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
43const pjsip_method pjsip_publish_method =
44{
45 PJSIP_OTHER_METHOD,
46 { "PUBLISH", 7 }
47};
48
Benny Prijono21b9ad92006-08-15 13:11:22 +000049
50/**
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000051 * SIP client publication structure.
Benny Prijono21b9ad92006-08-15 13:11:22 +000052 */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000053struct pjsip_publishc
Benny Prijono21b9ad92006-08-15 13:11:22 +000054{
55 pj_pool_t *pool;
56 pjsip_endpoint *endpt;
57 pj_bool_t _delete_flag;
58 int pending_tsx;
59
60 void *token;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000061 pjsip_publishc_cb *cb;
Benny Prijono21b9ad92006-08-15 13:11:22 +000062
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000063 pj_str_t event;
64 pj_str_t str_target_uri;
65 pjsip_uri *target_uri;
Benny Prijono21b9ad92006-08-15 13:11:22 +000066 pjsip_cid_hdr *cid_hdr;
67 pjsip_cseq_hdr *cseq_hdr;
68 pj_str_t from_uri;
69 pjsip_from_hdr *from_hdr;
70 pjsip_to_hdr *to_hdr;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000071 pj_str_t etag;
Benny Prijono21b9ad92006-08-15 13:11:22 +000072 pjsip_expires_hdr *expires_hdr;
Benny Prijono21b9ad92006-08-15 13:11:22 +000073 pj_uint32_t expires;
74 pjsip_route_hdr route_set;
75
76 /* Authorization sessions. */
77 pjsip_auth_clt_sess auth_sess;
78
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000079 /* Auto refresh publication. */
80 pj_bool_t auto_refresh;
81 pj_time_val last_refresh;
82 pj_time_val next_refresh;
Benny Prijono21b9ad92006-08-15 13:11:22 +000083 pj_timer_entry timer;
84};
85
86
87
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000088/*
89 * Initialize client publication module.
90 */
91PJ_DEF(pj_status_t) pjsip_publishc_init_module(pjsip_endpoint *endpt)
92{
93 return pjsip_endpt_add_capability( endpt, NULL, PJSIP_H_ALLOW, NULL,
94 1, &pjsip_publish_method.name);
95}
96
97
98PJ_DEF(pj_status_t) pjsip_publishc_create( pjsip_endpoint *endpt,
99 unsigned options,
100 void *token,
101 pjsip_publishc_cb *cb,
102 pjsip_publishc **p_pubc)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000103{
104 pj_pool_t *pool;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000105 pjsip_publishc *pubc;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000106 pj_status_t status;
107
108 /* Verify arguments. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000109 PJ_ASSERT_RETURN(endpt && cb && p_pubc, PJ_EINVAL);
110 PJ_ASSERT_RETURN(options == 0, PJ_EINVAL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000111
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000112 PJ_UNUSED_ARG(options);
113
114 pool = pjsip_endpt_create_pool(endpt, "pubc%p", 1024, 1024);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000115 PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
116
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000117 pubc = pj_pool_zalloc(pool, sizeof(struct pjsip_publishc));
Benny Prijono21b9ad92006-08-15 13:11:22 +0000118
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000119 pubc->pool = pool;
120 pubc->endpt = endpt;
121 pubc->token = token;
122 pubc->cb = cb;
123 pubc->expires = PJSIP_PUBC_EXPIRATION_NOT_SPECIFIED;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000124
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000125 status = pjsip_auth_clt_init(&pubc->auth_sess, endpt, pubc->pool, 0);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000126 if (status != PJ_SUCCESS)
127 return status;
128
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000129 pj_list_init(&pubc->route_set);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000130
131 /* Done */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000132 *p_pubc = pubc;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000133 return PJ_SUCCESS;
134}
135
136
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000137PJ_DEF(pj_status_t) pjsip_publishc_destroy(pjsip_publishc *pubc)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000138{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000139 PJ_ASSERT_RETURN(pubc, PJ_EINVAL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000140
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000141 if (pubc->pending_tsx) {
142 pubc->_delete_flag = 1;
143 pubc->cb = NULL;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000144 } else {
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000145 pjsip_endpt_release_pool(pubc->endpt, pubc->pool);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000146 }
147
148 return PJ_SUCCESS;
149}
150
151
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000152PJ_DEF(pj_pool_t*) pjsip_publishc_get_pool(pjsip_publishc *pubc)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000153{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000154 return pubc->pool;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000155}
156
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000157static void set_expires( pjsip_publishc *pubc, pj_uint32_t expires)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000158{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000159 if (expires != pubc->expires) {
160 pubc->expires_hdr = pjsip_expires_hdr_create(pubc->pool, expires);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000161 } else {
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000162 pubc->expires_hdr = NULL;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000163 }
164}
165
166
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000167PJ_DEF(pj_status_t) pjsip_publishc_init(pjsip_publishc *pubc,
168 const pj_str_t *event,
169 const pj_str_t *target_uri,
170 const pj_str_t *from_uri,
171 const pj_str_t *to_uri,
172 pj_uint32_t expires)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000173{
174 pj_str_t tmp;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000175
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000176 PJ_ASSERT_RETURN(pubc && event && target_uri && from_uri && to_uri &&
177 expires, PJ_EINVAL);
178
179 /* Copy event type */
180 pj_strdup_with_null(pubc->pool, &pubc->event, event);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000181
182 /* Copy server URL. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000183 pj_strdup_with_null(pubc->pool, &pubc->str_target_uri, target_uri);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000184
185 /* Set server URL. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000186 tmp = pubc->str_target_uri;
187 pubc->target_uri = pjsip_parse_uri( pubc->pool, tmp.ptr, tmp.slen, 0);
188 if (pubc->target_uri == NULL) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000189 return PJSIP_EINVALIDURI;
190 }
191
192 /* Set "From" header. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000193 pj_strdup_with_null(pubc->pool, &pubc->from_uri, from_uri);
194 tmp = pubc->from_uri;
195 pubc->from_hdr = pjsip_from_hdr_create(pubc->pool);
196 pubc->from_hdr->uri = pjsip_parse_uri(pubc->pool, tmp.ptr, tmp.slen,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000197 PJSIP_PARSE_URI_AS_NAMEADDR);
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000198 if (!pubc->from_hdr->uri) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000199 return PJSIP_EINVALIDURI;
200 }
201
202 /* Set "To" header. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000203 pj_strdup_with_null(pubc->pool, &tmp, to_uri);
204 pubc->to_hdr = pjsip_to_hdr_create(pubc->pool);
205 pubc->to_hdr->uri = pjsip_parse_uri(pubc->pool, tmp.ptr, tmp.slen,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000206 PJSIP_PARSE_URI_AS_NAMEADDR);
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000207 if (!pubc->to_hdr->uri) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000208 return PJSIP_EINVALIDURI;
209 }
210
211
Benny Prijono21b9ad92006-08-15 13:11:22 +0000212 /* Set "Expires" header, if required. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000213 set_expires( pubc, expires);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000214
215 /* Set "Call-ID" header. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000216 pubc->cid_hdr = pjsip_cid_hdr_create(pubc->pool);
217 pj_create_unique_string(pubc->pool, &pubc->cid_hdr->id);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000218
219 /* Set "CSeq" header. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000220 pubc->cseq_hdr = pjsip_cseq_hdr_create(pubc->pool);
221 pubc->cseq_hdr->cseq = pj_rand() % 0xFFFF;
222 pjsip_method_set( &pubc->cseq_hdr->method, PJSIP_REGISTER_METHOD);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000223
224 /* Done. */
225 return PJ_SUCCESS;
226}
227
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000228PJ_DEF(pj_status_t) pjsip_publishc_set_credentials( pjsip_publishc *pubc,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000229 int count,
230 const pjsip_cred_info cred[] )
231{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000232 PJ_ASSERT_RETURN(pubc && count && cred, PJ_EINVAL);
233 return pjsip_auth_clt_set_credentials(&pubc->auth_sess, count, cred);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000234}
235
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000236PJ_DEF(pj_status_t) pjsip_publishc_set_route_set( pjsip_publishc *pubc,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000237 const pjsip_route_hdr *route_set)
238{
239 const pjsip_route_hdr *chdr;
240
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000241 PJ_ASSERT_RETURN(pubc && route_set, PJ_EINVAL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000242
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000243 pj_list_init(&pubc->route_set);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000244
245 chdr = route_set->next;
246 while (chdr != route_set) {
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000247 pj_list_push_back(&pubc->route_set, pjsip_hdr_clone(pubc->pool, chdr));
Benny Prijono21b9ad92006-08-15 13:11:22 +0000248 chdr = chdr->next;
249 }
250
251 return PJ_SUCCESS;
252}
253
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000254static pj_status_t create_request(pjsip_publishc *pubc,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000255 pjsip_tx_data **p_tdata)
256{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000257 const pj_str_t STR_EVENT = { "Event", 5 };
Benny Prijono21b9ad92006-08-15 13:11:22 +0000258 pj_status_t status;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000259 pjsip_generic_string_hdr *hdr;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000260 pjsip_tx_data *tdata;
261
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000262 PJ_ASSERT_RETURN(pubc && p_tdata, PJ_EINVAL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000263
264 /* Create the request. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000265 status = pjsip_endpt_create_request_from_hdr( pubc->endpt,
266 &pjsip_publish_method,
267 pubc->target_uri,
268 pubc->from_hdr,
269 pubc->to_hdr,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000270 NULL,
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000271 pubc->cid_hdr,
272 pubc->cseq_hdr->cseq,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000273 NULL,
274 &tdata);
275 if (status != PJ_SUCCESS)
276 return status;
277
278 /* Add cached authorization headers. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000279 pjsip_auth_clt_init_req( &pubc->auth_sess, tdata );
Benny Prijono21b9ad92006-08-15 13:11:22 +0000280
281 /* Add Route headers from route set, ideally after Via header */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000282 if (!pj_list_empty(&pubc->route_set)) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000283 pjsip_hdr *route_pos;
284 const pjsip_route_hdr *route;
285
286 route_pos = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
287 if (!route_pos)
288 route_pos = &tdata->msg->hdr;
289
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000290 route = pubc->route_set.next;
291 while (route != &pubc->route_set) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000292 pjsip_hdr *new_hdr = pjsip_hdr_shallow_clone(tdata->pool, route);
293 pj_list_insert_after(route_pos, new_hdr);
294 route_pos = new_hdr;
295 route = route->next;
296 }
297 }
298
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000299 /* Add Event header */
300 hdr = pjsip_generic_string_hdr_create(tdata->pool, &STR_EVENT,
301 &pubc->event);
302 if (hdr)
303 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);
304
305
306 /* Add SIP-If-Match if we have etag */
307 if (pubc->etag.slen) {
308 const pj_str_t STR_HNAME = { "SIP-If-Match", 12 };
309
310 hdr = pjsip_generic_string_hdr_create(tdata->pool, &STR_HNAME,
311 &pubc->etag);
312 if (hdr)
313 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);
314 }
315
316
Benny Prijono21b9ad92006-08-15 13:11:22 +0000317 /* Done. */
318 *p_tdata = tdata;
319 return PJ_SUCCESS;
320}
321
322
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000323PJ_DEF(pj_status_t) pjsip_publishc_publish(pjsip_publishc *pubc,
324 pj_bool_t auto_refresh,
325 pjsip_tx_data **p_tdata)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000326{
Benny Prijono21b9ad92006-08-15 13:11:22 +0000327 pj_status_t status;
328 pjsip_tx_data *tdata;
329
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000330 PJ_ASSERT_RETURN(pubc && p_tdata, PJ_EINVAL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000331
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000332 status = create_request(pubc, &tdata);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000333 if (status != PJ_SUCCESS)
334 return status;
335
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000336 /* Add Expires header */
337 if (pubc->expires_hdr) {
338 pjsip_hdr *dup;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000339
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000340 dup = pjsip_hdr_shallow_clone(tdata->pool, pubc->expires_hdr);
341 if (dup)
342 pjsip_msg_add_hdr(tdata->msg, dup);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000343 }
344
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000345 /* Cancel existing timer */
346 if (pubc->timer.id != 0) {
347 pjsip_endpt_cancel_timer(pubc->endpt, &pubc->timer);
348 pubc->timer.id = 0;
349 }
350
351 pubc->auto_refresh = auto_refresh;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000352
353 /* Done */
354 *p_tdata = tdata;
355 return PJ_SUCCESS;
356}
357
358
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000359PJ_DEF(pj_status_t) pjsip_publishc_unpublish(pjsip_publishc *pubc,
360 pjsip_tx_data **p_tdata)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000361{
362 pjsip_tx_data *tdata;
363 pjsip_msg *msg;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000364 pjsip_expires_hdr *expires;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000365 pj_status_t status;
366
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000367 PJ_ASSERT_RETURN(pubc && p_tdata, PJ_EINVAL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000368
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000369 if (pubc->timer.id != 0) {
370 pjsip_endpt_cancel_timer(pubc->endpt, &pubc->timer);
371 pubc->timer.id = 0;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000372 }
373
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000374 status = create_request(pubc, &tdata);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000375 if (status != PJ_SUCCESS)
376 return status;
377
378 msg = tdata->msg;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000379
380 /* Add Expires:0 header */
381 expires = pjsip_expires_hdr_create(tdata->pool, 0);
382 pjsip_msg_add_hdr( msg, (pjsip_hdr*)expires);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000383
384 *p_tdata = tdata;
385 return PJ_SUCCESS;
386}
387
388
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000389PJ_DEF(pj_status_t) pjsip_publishc_update_expires( pjsip_publishc *pubc,
390 pj_uint32_t expires )
Benny Prijono21b9ad92006-08-15 13:11:22 +0000391{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000392 PJ_ASSERT_RETURN(pubc, PJ_EINVAL);
393 set_expires( pubc, expires );
Benny Prijono21b9ad92006-08-15 13:11:22 +0000394 return PJ_SUCCESS;
395}
396
397
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000398static void call_callback(pjsip_publishc *pubc, pj_status_t status,
399 int st_code, const pj_str_t *reason,
400 pjsip_rx_data *rdata, pj_int32_t expiration)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000401{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000402 struct pjsip_publishc_cbparam cbparam;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000403
404
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000405 cbparam.pubc = pubc;
406 cbparam.token = pubc->token;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000407 cbparam.status = status;
408 cbparam.code = st_code;
409 cbparam.reason = *reason;
410 cbparam.rdata = rdata;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000411 cbparam.expiration = expiration;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000412
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000413 (*pubc->cb)(&cbparam);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000414}
415
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000416static void pubc_refresh_timer_cb( pj_timer_heap_t *timer_heap,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000417 struct pj_timer_entry *entry)
418{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000419 pjsip_publishc *pubc = entry->user_data;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000420 pjsip_tx_data *tdata;
421 pj_status_t status;
422
423 PJ_UNUSED_ARG(timer_heap);
424
425 entry->id = 0;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000426 status = pjsip_publishc_publish(pubc, 1, &tdata);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000427 if (status == PJ_SUCCESS) {
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000428 status = pjsip_publishc_send(pubc, tdata);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000429 }
430
431 if (status != PJ_SUCCESS) {
432 char errmsg[PJ_ERR_MSG_SIZE];
433 pj_str_t reason = pj_strerror(status, errmsg, sizeof(errmsg));
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000434 call_callback(pubc, status, 400, &reason, NULL, -1);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000435 }
436}
437
438static void tsx_callback(void *token, pjsip_event *event)
439{
440 pj_status_t status;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000441 pjsip_publishc *pubc = token;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000442 pjsip_transaction *tsx = event->body.tsx_state.tsx;
443
444 /* Decrement pending transaction counter. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000445 pj_assert(pubc->pending_tsx > 0);
446 --pubc->pending_tsx;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000447
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000448 /* If publication data has been deleted by user then remove publication
Benny Prijono21b9ad92006-08-15 13:11:22 +0000449 * data from transaction's callback, and don't call callback.
450 */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000451 if (pubc->_delete_flag) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000452
453 /* Nothing to do */
454 ;
455
456 } else if (tsx->status_code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED ||
457 tsx->status_code == PJSIP_SC_UNAUTHORIZED)
458 {
459 pjsip_rx_data *rdata = event->body.tsx_state.src.rdata;
460 pjsip_tx_data *tdata;
461
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000462 status = pjsip_auth_clt_reinit_req( &pubc->auth_sess,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000463 rdata,
464 tsx->last_tx,
465 &tdata);
466
467 if (status == PJ_SUCCESS) {
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000468 status = pjsip_publishc_send(pubc, tdata);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000469 }
470
471 if (status != PJ_SUCCESS) {
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000472 call_callback(pubc, status, tsx->status_code,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000473 &rdata->msg_info.msg->line.status.reason,
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000474 rdata, -1);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000475 }
476
477 return;
478
479 } else {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000480 pjsip_rx_data *rdata;
481 pj_int32_t expiration = 0xFFFF;
482
483 if (tsx->status_code/100 == 2) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000484 pjsip_msg *msg;
485 pjsip_expires_hdr *expires;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000486 pjsip_generic_string_hdr *etag_hdr;
487 const pj_str_t STR_ETAG = { "SIP-ETag", 8 };
Benny Prijono21b9ad92006-08-15 13:11:22 +0000488
489 rdata = event->body.tsx_state.src.rdata;
490 msg = rdata->msg_info.msg;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000491
492 /* Save ETag value */
493 etag_hdr = (pjsip_generic_string_hdr*)
494 pjsip_msg_find_hdr_by_name(msg, &STR_ETAG, NULL);
495 if (etag_hdr) {
496 pj_strdup(pubc->pool, &pubc->etag, &etag_hdr->hvalue);
497 } else {
498 pubc->etag.slen = 0;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000499 }
500
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000501 /* Update expires value */
Benny Prijono21b9ad92006-08-15 13:11:22 +0000502 expires = pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL);
503
504 if (expires)
505 expiration = expires->ivalue;
506
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000507 if (pubc->auto_refresh && expiration!=0 && expiration!=0xFFFF) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000508 pj_time_val delay = { 0, 0};
509
510 delay.sec = expiration - DELAY_BEFORE_REFRESH;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000511 if (pubc->expires != PJSIP_PUBC_EXPIRATION_NOT_SPECIFIED &&
512 delay.sec > (pj_int32_t)pubc->expires)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000513 {
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000514 delay.sec = pubc->expires;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000515 }
516 if (delay.sec < DELAY_BEFORE_REFRESH)
517 delay.sec = DELAY_BEFORE_REFRESH;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000518 pubc->timer.cb = &pubc_refresh_timer_cb;
519 pubc->timer.id = REFRESH_TIMER;
520 pubc->timer.user_data = pubc;
521 pjsip_endpt_schedule_timer( pubc->endpt, &pubc->timer, &delay);
522 pj_gettimeofday(&pubc->last_refresh);
523 pubc->next_refresh = pubc->last_refresh;
524 pubc->next_refresh.sec += delay.sec;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000525 }
526
527 } else {
528 rdata = (event->body.tsx_state.type==PJSIP_EVENT_RX_MSG) ?
529 event->body.tsx_state.src.rdata : NULL;
530 }
531
532
533 /* Call callback. */
534 if (expiration == 0xFFFF) expiration = -1;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000535 call_callback(pubc, PJ_SUCCESS, tsx->status_code,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000536 (rdata ? &rdata->msg_info.msg->line.status.reason
537 : pjsip_get_status_text(tsx->status_code)),
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000538 rdata, expiration);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000539
540 }
541
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000542 /* Delete the record if user destroy pubc during the callback. */
543 if (pubc->_delete_flag && pubc->pending_tsx==0) {
544 pjsip_publishc_destroy(pubc);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000545 }
546}
547
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000548
549PJ_DEF(pj_status_t) pjsip_publishc_send(pjsip_publishc *pubc,
550 pjsip_tx_data *tdata)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000551{
552 pj_status_t status;
553 pjsip_cseq_hdr *cseq_hdr;
554 pj_uint32_t cseq;
555
556 /* Make sure we don't have pending transaction. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000557 if (pubc->pending_tsx) {
558 PJ_LOG(4,(THIS_FILE, "Unable to send request, pubc has another "
Benny Prijono21b9ad92006-08-15 13:11:22 +0000559 "transaction pending"));
560 pjsip_tx_data_dec_ref( tdata );
561 return PJSIP_EBUSY;
562 }
563
564 /* Invalidate message buffer. */
565 pjsip_tx_data_invalidate_msg(tdata);
566
567 /* Increment CSeq */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000568 cseq = ++pubc->cseq_hdr->cseq;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000569 cseq_hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
570 cseq_hdr->cseq = cseq;
571
572 /* Increment pending transaction first, since transaction callback
573 * may be called even before send_request() returns!
574 */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000575 ++pubc->pending_tsx;
576 status = pjsip_endpt_send_request(pubc->endpt, tdata, -1, pubc,
577 &tsx_callback);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000578 if (status!=PJ_SUCCESS) {
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000579 --pubc->pending_tsx;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000580 PJ_LOG(4,(THIS_FILE, "Error sending request, status=%d", status));
581 }
582
583 return status;
584}
585
586