blob: 2f5b415ef621c9dc0042905d8d14bb03fcc5bb29 [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;
Benny Prijono53984d12009-04-28 22:19:49 +000084 pjsip_hdr usr_hdr;
Benny Prijono21b9ad92006-08-15 13:11:22 +000085
86 /* Authorization sessions. */
87 pjsip_auth_clt_sess auth_sess;
88
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000089 /* Auto refresh publication. */
90 pj_bool_t auto_refresh;
91 pj_time_val last_refresh;
92 pj_time_val next_refresh;
Benny Prijono21b9ad92006-08-15 13:11:22 +000093 pj_timer_entry timer;
94};
95
96
97
Benny Prijono3a5e1ab2006-08-15 20:26:34 +000098/*
99 * Initialize client publication module.
100 */
101PJ_DEF(pj_status_t) pjsip_publishc_init_module(pjsip_endpoint *endpt)
102{
Benny Prijono7741c8a2008-07-07 19:57:16 +0000103 /* Note:
104 Commented out the capability registration below, since it's
105 wrong to include PUBLISH in Allow header of INVITE requests/
106 responses.
107
108 13.2.1 Creating the Initial INVITE
109 An Allow header field (Section 20.5) SHOULD be present in the
110 INVITE. It indicates what methods can be invoked within a dialog
111
112 20.5 Allow
113 The Allow header field lists the set of methods supported by the
114 UA generating the message.
115
116 While the semantic of Allow header in non-dialog requests is unclear,
117 it's probably best not to include PUBLISH in Allow header for now
118 until we can find out how to customize the inclusion of methods in
119 Allow header for in-dialog vs out-dialog requests.
120
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000121 return pjsip_endpt_add_capability( endpt, NULL, PJSIP_H_ALLOW, NULL,
122 1, &pjsip_publish_method.name);
Benny Prijono7741c8a2008-07-07 19:57:16 +0000123 */
Benny Prijono10d8dbd2008-07-13 13:12:36 +0000124 PJ_UNUSED_ARG(endpt);
Benny Prijono7741c8a2008-07-07 19:57:16 +0000125 return PJ_SUCCESS;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000126}
127
128
129PJ_DEF(pj_status_t) pjsip_publishc_create( pjsip_endpoint *endpt,
130 unsigned options,
131 void *token,
132 pjsip_publishc_cb *cb,
133 pjsip_publishc **p_pubc)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000134{
135 pj_pool_t *pool;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000136 pjsip_publishc *pubc;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000137 pj_status_t status;
138
139 /* Verify arguments. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000140 PJ_ASSERT_RETURN(endpt && cb && p_pubc, PJ_EINVAL);
141 PJ_ASSERT_RETURN(options == 0, PJ_EINVAL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000142
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000143 PJ_UNUSED_ARG(options);
144
145 pool = pjsip_endpt_create_pool(endpt, "pubc%p", 1024, 1024);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000146 PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
147
Benny Prijono9d4469d2007-05-02 05:14:29 +0000148 pubc = PJ_POOL_ZALLOC_T(pool, pjsip_publishc);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000149
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000150 pubc->pool = pool;
151 pubc->endpt = endpt;
152 pubc->token = token;
153 pubc->cb = cb;
154 pubc->expires = PJSIP_PUBC_EXPIRATION_NOT_SPECIFIED;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000155
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000156 status = pjsip_auth_clt_init(&pubc->auth_sess, endpt, pubc->pool, 0);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000157 if (status != PJ_SUCCESS)
158 return status;
159
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000160 pj_list_init(&pubc->route_set);
Benny Prijono53984d12009-04-28 22:19:49 +0000161 pj_list_init(&pubc->usr_hdr);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000162
163 /* Done */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000164 *p_pubc = pubc;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000165 return PJ_SUCCESS;
166}
167
168
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000169PJ_DEF(pj_status_t) pjsip_publishc_destroy(pjsip_publishc *pubc)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000170{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000171 PJ_ASSERT_RETURN(pubc, PJ_EINVAL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000172
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000173 if (pubc->pending_tsx) {
174 pubc->_delete_flag = 1;
175 pubc->cb = NULL;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000176 } else {
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000177 pjsip_endpt_release_pool(pubc->endpt, pubc->pool);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000178 }
179
180 return PJ_SUCCESS;
181}
182
183
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000184PJ_DEF(pj_pool_t*) pjsip_publishc_get_pool(pjsip_publishc *pubc)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000185{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000186 return pubc->pool;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000187}
188
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000189static void set_expires( pjsip_publishc *pubc, pj_uint32_t expires)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000190{
Benny Prijono53984d12009-04-28 22:19:49 +0000191 if (expires != pubc->expires &&
192 expires != PJSIP_PUBC_EXPIRATION_NOT_SPECIFIED)
193 {
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000194 pubc->expires_hdr = pjsip_expires_hdr_create(pubc->pool, expires);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000195 } else {
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000196 pubc->expires_hdr = NULL;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000197 }
198}
199
200
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000201PJ_DEF(pj_status_t) pjsip_publishc_init(pjsip_publishc *pubc,
202 const pj_str_t *event,
203 const pj_str_t *target_uri,
204 const pj_str_t *from_uri,
205 const pj_str_t *to_uri,
206 pj_uint32_t expires)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000207{
208 pj_str_t tmp;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000209
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000210 PJ_ASSERT_RETURN(pubc && event && target_uri && from_uri && to_uri &&
211 expires, PJ_EINVAL);
212
213 /* Copy event type */
214 pj_strdup_with_null(pubc->pool, &pubc->event, event);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000215
216 /* Copy server URL. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000217 pj_strdup_with_null(pubc->pool, &pubc->str_target_uri, target_uri);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000218
219 /* Set server URL. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000220 tmp = pubc->str_target_uri;
221 pubc->target_uri = pjsip_parse_uri( pubc->pool, tmp.ptr, tmp.slen, 0);
222 if (pubc->target_uri == NULL) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000223 return PJSIP_EINVALIDURI;
224 }
225
226 /* Set "From" header. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000227 pj_strdup_with_null(pubc->pool, &pubc->from_uri, from_uri);
228 tmp = pubc->from_uri;
229 pubc->from_hdr = pjsip_from_hdr_create(pubc->pool);
230 pubc->from_hdr->uri = pjsip_parse_uri(pubc->pool, tmp.ptr, tmp.slen,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000231 PJSIP_PARSE_URI_AS_NAMEADDR);
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000232 if (!pubc->from_hdr->uri) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000233 return PJSIP_EINVALIDURI;
234 }
235
236 /* Set "To" header. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000237 pj_strdup_with_null(pubc->pool, &tmp, to_uri);
238 pubc->to_hdr = pjsip_to_hdr_create(pubc->pool);
239 pubc->to_hdr->uri = pjsip_parse_uri(pubc->pool, tmp.ptr, tmp.slen,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000240 PJSIP_PARSE_URI_AS_NAMEADDR);
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000241 if (!pubc->to_hdr->uri) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000242 return PJSIP_EINVALIDURI;
243 }
244
245
Benny Prijono21b9ad92006-08-15 13:11:22 +0000246 /* Set "Expires" header, if required. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000247 set_expires( pubc, expires);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000248
249 /* Set "Call-ID" header. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000250 pubc->cid_hdr = pjsip_cid_hdr_create(pubc->pool);
251 pj_create_unique_string(pubc->pool, &pubc->cid_hdr->id);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000252
253 /* Set "CSeq" header. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000254 pubc->cseq_hdr = pjsip_cseq_hdr_create(pubc->pool);
255 pubc->cseq_hdr->cseq = pj_rand() % 0xFFFF;
256 pjsip_method_set( &pubc->cseq_hdr->method, PJSIP_REGISTER_METHOD);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000257
258 /* Done. */
259 return PJ_SUCCESS;
260}
261
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000262PJ_DEF(pj_status_t) pjsip_publishc_set_credentials( pjsip_publishc *pubc,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000263 int count,
264 const pjsip_cred_info cred[] )
265{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000266 PJ_ASSERT_RETURN(pubc && count && cred, PJ_EINVAL);
267 return pjsip_auth_clt_set_credentials(&pubc->auth_sess, count, cred);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000268}
269
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000270PJ_DEF(pj_status_t) pjsip_publishc_set_route_set( pjsip_publishc *pubc,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000271 const pjsip_route_hdr *route_set)
272{
273 const pjsip_route_hdr *chdr;
274
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000275 PJ_ASSERT_RETURN(pubc && route_set, PJ_EINVAL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000276
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000277 pj_list_init(&pubc->route_set);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000278
279 chdr = route_set->next;
280 while (chdr != route_set) {
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000281 pj_list_push_back(&pubc->route_set, pjsip_hdr_clone(pubc->pool, chdr));
Benny Prijono21b9ad92006-08-15 13:11:22 +0000282 chdr = chdr->next;
283 }
284
285 return PJ_SUCCESS;
286}
287
Benny Prijono53984d12009-04-28 22:19:49 +0000288PJ_DEF(pj_status_t) pjsip_publishc_set_headers( pjsip_publishc *pubc,
289 const pjsip_hdr *hdr_list)
290{
291 const pjsip_hdr *h;
292
293 PJ_ASSERT_RETURN(pubc && hdr_list, PJ_EINVAL);
294
295 pj_list_init(&pubc->usr_hdr);
296 h = hdr_list->next;
297 while (h != hdr_list) {
298 pj_list_push_back(&pubc->usr_hdr, pjsip_hdr_clone(pubc->pool, h));
299 h = h->next;
300 }
301
302 return PJ_SUCCESS;
303}
304
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000305static pj_status_t create_request(pjsip_publishc *pubc,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000306 pjsip_tx_data **p_tdata)
307{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000308 const pj_str_t STR_EVENT = { "Event", 5 };
Benny Prijono21b9ad92006-08-15 13:11:22 +0000309 pj_status_t status;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000310 pjsip_generic_string_hdr *hdr;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000311 pjsip_tx_data *tdata;
312
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000313 PJ_ASSERT_RETURN(pubc && p_tdata, PJ_EINVAL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000314
315 /* Create the request. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000316 status = pjsip_endpt_create_request_from_hdr( pubc->endpt,
317 &pjsip_publish_method,
318 pubc->target_uri,
319 pubc->from_hdr,
320 pubc->to_hdr,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000321 NULL,
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000322 pubc->cid_hdr,
323 pubc->cseq_hdr->cseq,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000324 NULL,
325 &tdata);
326 if (status != PJ_SUCCESS)
327 return status;
328
329 /* Add cached authorization headers. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000330 pjsip_auth_clt_init_req( &pubc->auth_sess, tdata );
Benny Prijono21b9ad92006-08-15 13:11:22 +0000331
332 /* Add Route headers from route set, ideally after Via header */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000333 if (!pj_list_empty(&pubc->route_set)) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000334 pjsip_hdr *route_pos;
335 const pjsip_route_hdr *route;
336
Benny Prijono9d4469d2007-05-02 05:14:29 +0000337 route_pos = (pjsip_hdr*)
338 pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000339 if (!route_pos)
340 route_pos = &tdata->msg->hdr;
341
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000342 route = pubc->route_set.next;
343 while (route != &pubc->route_set) {
Benny Prijono9d4469d2007-05-02 05:14:29 +0000344 pjsip_hdr *new_hdr = (pjsip_hdr*)
345 pjsip_hdr_shallow_clone(tdata->pool, route);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000346 pj_list_insert_after(route_pos, new_hdr);
347 route_pos = new_hdr;
348 route = route->next;
349 }
350 }
351
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000352 /* Add Event header */
353 hdr = pjsip_generic_string_hdr_create(tdata->pool, &STR_EVENT,
354 &pubc->event);
355 if (hdr)
356 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);
357
358
359 /* Add SIP-If-Match if we have etag */
360 if (pubc->etag.slen) {
361 const pj_str_t STR_HNAME = { "SIP-If-Match", 12 };
362
363 hdr = pjsip_generic_string_hdr_create(tdata->pool, &STR_HNAME,
364 &pubc->etag);
365 if (hdr)
366 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);
367 }
368
Benny Prijono53984d12009-04-28 22:19:49 +0000369 /* Add user headers */
370 if (!pj_list_empty(&pubc->usr_hdr)) {
371 const pjsip_hdr *hdr;
372
373 hdr = pubc->usr_hdr.next;
374 while (hdr != &pubc->usr_hdr) {
375 pjsip_hdr *new_hdr = (pjsip_hdr*)
376 pjsip_hdr_shallow_clone(tdata->pool, hdr);
377 pjsip_msg_add_hdr(tdata->msg, new_hdr);
378 hdr = hdr->next;
379 }
380 }
381
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000382
Benny Prijono21b9ad92006-08-15 13:11:22 +0000383 /* Done. */
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_publish(pjsip_publishc *pubc,
390 pj_bool_t auto_refresh,
391 pjsip_tx_data **p_tdata)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000392{
Benny Prijono21b9ad92006-08-15 13:11:22 +0000393 pj_status_t status;
394 pjsip_tx_data *tdata;
395
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000396 PJ_ASSERT_RETURN(pubc && p_tdata, PJ_EINVAL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000397
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000398 status = create_request(pubc, &tdata);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000399 if (status != PJ_SUCCESS)
400 return status;
401
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000402 /* Add Expires header */
403 if (pubc->expires_hdr) {
404 pjsip_hdr *dup;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000405
Benny Prijono9d4469d2007-05-02 05:14:29 +0000406 dup = (pjsip_hdr*)
407 pjsip_hdr_shallow_clone(tdata->pool, pubc->expires_hdr);
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000408 if (dup)
409 pjsip_msg_add_hdr(tdata->msg, dup);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000410 }
411
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000412 /* Cancel existing timer */
413 if (pubc->timer.id != 0) {
414 pjsip_endpt_cancel_timer(pubc->endpt, &pubc->timer);
415 pubc->timer.id = 0;
416 }
417
418 pubc->auto_refresh = auto_refresh;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000419
420 /* Done */
421 *p_tdata = tdata;
422 return PJ_SUCCESS;
423}
424
425
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000426PJ_DEF(pj_status_t) pjsip_publishc_unpublish(pjsip_publishc *pubc,
427 pjsip_tx_data **p_tdata)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000428{
429 pjsip_tx_data *tdata;
430 pjsip_msg *msg;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000431 pjsip_expires_hdr *expires;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000432 pj_status_t status;
433
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000434 PJ_ASSERT_RETURN(pubc && p_tdata, PJ_EINVAL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000435
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000436 if (pubc->timer.id != 0) {
437 pjsip_endpt_cancel_timer(pubc->endpt, &pubc->timer);
438 pubc->timer.id = 0;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000439 }
440
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000441 status = create_request(pubc, &tdata);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000442 if (status != PJ_SUCCESS)
443 return status;
444
445 msg = tdata->msg;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000446
447 /* Add Expires:0 header */
448 expires = pjsip_expires_hdr_create(tdata->pool, 0);
449 pjsip_msg_add_hdr( msg, (pjsip_hdr*)expires);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000450
451 *p_tdata = tdata;
452 return PJ_SUCCESS;
453}
454
455
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000456PJ_DEF(pj_status_t) pjsip_publishc_update_expires( pjsip_publishc *pubc,
457 pj_uint32_t expires )
Benny Prijono21b9ad92006-08-15 13:11:22 +0000458{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000459 PJ_ASSERT_RETURN(pubc, PJ_EINVAL);
460 set_expires( pubc, expires );
Benny Prijono21b9ad92006-08-15 13:11:22 +0000461 return PJ_SUCCESS;
462}
463
464
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000465static void call_callback(pjsip_publishc *pubc, pj_status_t status,
466 int st_code, const pj_str_t *reason,
467 pjsip_rx_data *rdata, pj_int32_t expiration)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000468{
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000469 struct pjsip_publishc_cbparam cbparam;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000470
471
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000472 cbparam.pubc = pubc;
473 cbparam.token = pubc->token;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000474 cbparam.status = status;
475 cbparam.code = st_code;
476 cbparam.reason = *reason;
477 cbparam.rdata = rdata;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000478 cbparam.expiration = expiration;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000479
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000480 (*pubc->cb)(&cbparam);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000481}
482
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000483static void pubc_refresh_timer_cb( pj_timer_heap_t *timer_heap,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000484 struct pj_timer_entry *entry)
485{
Benny Prijono9d4469d2007-05-02 05:14:29 +0000486 pjsip_publishc *pubc = (pjsip_publishc*) entry->user_data;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000487 pjsip_tx_data *tdata;
488 pj_status_t status;
489
490 PJ_UNUSED_ARG(timer_heap);
491
492 entry->id = 0;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000493 status = pjsip_publishc_publish(pubc, 1, &tdata);
Benny Prijono0e9f7622008-07-01 19:11:55 +0000494 if (status != PJ_SUCCESS) {
495 char errmsg[PJ_ERR_MSG_SIZE];
496 pj_str_t reason = pj_strerror(status, errmsg, sizeof(errmsg));
497 call_callback(pubc, status, 400, &reason, NULL, -1);
498 return;
499 }
500
501 status = pjsip_publishc_send(pubc, tdata);
502 /* No need to call callback as it should have been called */
Benny Prijono21b9ad92006-08-15 13:11:22 +0000503}
504
505static void tsx_callback(void *token, pjsip_event *event)
506{
507 pj_status_t status;
Benny Prijono9d4469d2007-05-02 05:14:29 +0000508 pjsip_publishc *pubc = (pjsip_publishc*) token;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000509 pjsip_transaction *tsx = event->body.tsx_state.tsx;
510
511 /* Decrement pending transaction counter. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000512 pj_assert(pubc->pending_tsx > 0);
513 --pubc->pending_tsx;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000514
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000515 /* If publication data has been deleted by user then remove publication
Benny Prijono21b9ad92006-08-15 13:11:22 +0000516 * data from transaction's callback, and don't call callback.
517 */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000518 if (pubc->_delete_flag) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000519
520 /* Nothing to do */
521 ;
522
523 } else if (tsx->status_code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED ||
524 tsx->status_code == PJSIP_SC_UNAUTHORIZED)
525 {
526 pjsip_rx_data *rdata = event->body.tsx_state.src.rdata;
527 pjsip_tx_data *tdata;
528
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000529 status = pjsip_auth_clt_reinit_req( &pubc->auth_sess,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000530 rdata,
531 tsx->last_tx,
532 &tdata);
Benny Prijono0e9f7622008-07-01 19:11:55 +0000533 if (status != PJ_SUCCESS) {
534 call_callback(pubc, status, tsx->status_code,
535 &rdata->msg_info.msg->line.status.reason,
536 rdata, -1);
537 } else {
538 status = pjsip_publishc_send(pubc, tdata);
539 }
Benny Prijono21b9ad92006-08-15 13:11:22 +0000540
541 } else {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000542 pjsip_rx_data *rdata;
543 pj_int32_t expiration = 0xFFFF;
544
545 if (tsx->status_code/100 == 2) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000546 pjsip_msg *msg;
547 pjsip_expires_hdr *expires;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000548 pjsip_generic_string_hdr *etag_hdr;
549 const pj_str_t STR_ETAG = { "SIP-ETag", 8 };
Benny Prijono21b9ad92006-08-15 13:11:22 +0000550
551 rdata = event->body.tsx_state.src.rdata;
552 msg = rdata->msg_info.msg;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000553
554 /* Save ETag value */
555 etag_hdr = (pjsip_generic_string_hdr*)
556 pjsip_msg_find_hdr_by_name(msg, &STR_ETAG, NULL);
557 if (etag_hdr) {
558 pj_strdup(pubc->pool, &pubc->etag, &etag_hdr->hvalue);
559 } else {
560 pubc->etag.slen = 0;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000561 }
562
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000563 /* Update expires value */
Benny Prijono9d4469d2007-05-02 05:14:29 +0000564 expires = (pjsip_expires_hdr*)
565 pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000566
Benny Prijono53984d12009-04-28 22:19:49 +0000567 if (pubc->auto_refresh && expires)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000568 expiration = expires->ivalue;
569
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000570 if (pubc->auto_refresh && expiration!=0 && expiration!=0xFFFF) {
Benny Prijono21b9ad92006-08-15 13:11:22 +0000571 pj_time_val delay = { 0, 0};
572
573 delay.sec = expiration - DELAY_BEFORE_REFRESH;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000574 if (pubc->expires != PJSIP_PUBC_EXPIRATION_NOT_SPECIFIED &&
575 delay.sec > (pj_int32_t)pubc->expires)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000576 {
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000577 delay.sec = pubc->expires;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000578 }
579 if (delay.sec < DELAY_BEFORE_REFRESH)
580 delay.sec = DELAY_BEFORE_REFRESH;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000581 pubc->timer.cb = &pubc_refresh_timer_cb;
582 pubc->timer.id = REFRESH_TIMER;
583 pubc->timer.user_data = pubc;
584 pjsip_endpt_schedule_timer( pubc->endpt, &pubc->timer, &delay);
585 pj_gettimeofday(&pubc->last_refresh);
586 pubc->next_refresh = pubc->last_refresh;
587 pubc->next_refresh.sec += delay.sec;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000588 }
589
590 } else {
591 rdata = (event->body.tsx_state.type==PJSIP_EVENT_RX_MSG) ?
592 event->body.tsx_state.src.rdata : NULL;
593 }
594
595
596 /* Call callback. */
597 if (expiration == 0xFFFF) expiration = -1;
Benny Prijonoda1e0632007-05-23 14:12:35 +0000598
599 /* Temporarily increment pending_tsx to prevent callback from
600 * destroying pubc.
601 */
602 ++pubc->pending_tsx;
603
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000604 call_callback(pubc, PJ_SUCCESS, tsx->status_code,
Benny Prijono21b9ad92006-08-15 13:11:22 +0000605 (rdata ? &rdata->msg_info.msg->line.status.reason
606 : pjsip_get_status_text(tsx->status_code)),
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000607 rdata, expiration);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000608
Benny Prijonoda1e0632007-05-23 14:12:35 +0000609 --pubc->pending_tsx;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000610 }
611
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000612 /* Delete the record if user destroy pubc during the callback. */
613 if (pubc->_delete_flag && pubc->pending_tsx==0) {
614 pjsip_publishc_destroy(pubc);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000615 }
616}
617
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000618
619PJ_DEF(pj_status_t) pjsip_publishc_send(pjsip_publishc *pubc,
620 pjsip_tx_data *tdata)
Benny Prijono21b9ad92006-08-15 13:11:22 +0000621{
622 pj_status_t status;
623 pjsip_cseq_hdr *cseq_hdr;
624 pj_uint32_t cseq;
625
626 /* Make sure we don't have pending transaction. */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000627 if (pubc->pending_tsx) {
628 PJ_LOG(4,(THIS_FILE, "Unable to send request, pubc has another "
Benny Prijono21b9ad92006-08-15 13:11:22 +0000629 "transaction pending"));
630 pjsip_tx_data_dec_ref( tdata );
631 return PJSIP_EBUSY;
632 }
633
634 /* Invalidate message buffer. */
635 pjsip_tx_data_invalidate_msg(tdata);
636
637 /* Increment CSeq */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000638 cseq = ++pubc->cseq_hdr->cseq;
Benny Prijono9d4469d2007-05-02 05:14:29 +0000639 cseq_hdr = (pjsip_cseq_hdr*)
640 pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000641 cseq_hdr->cseq = cseq;
642
643 /* Increment pending transaction first, since transaction callback
644 * may be called even before send_request() returns!
645 */
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000646 ++pubc->pending_tsx;
647 status = pjsip_endpt_send_request(pubc->endpt, tdata, -1, pubc,
648 &tsx_callback);
Benny Prijono21b9ad92006-08-15 13:11:22 +0000649 if (status!=PJ_SUCCESS) {
Benny Prijono29438152007-06-28 02:47:32 +0000650 // no need to decrement, callback has been called and it should
651 // already decremented pending_tsx. Decrementing this here may
652 // cause accessing freed memory location.
653 //--pubc->pending_tsx;
Benny Prijono21b9ad92006-08-15 13:11:22 +0000654 PJ_LOG(4,(THIS_FILE, "Error sending request, status=%d", status));
655 }
656
657 return status;
658}
659