blob: b77704885532e53eb6eabdbc433c6b9656265f28 [file] [log] [blame]
Benny Prijono5dcb38d2005-11-21 01:55:47 +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 Prijonoccf95622006-02-07 18:48:01 +000019#include <pjsip-ua/sip_regc.h>
Benny Prijono5dcb38d2005-11-21 01:55:47 +000020#include <pjsip/sip_endpoint.h>
21#include <pjsip/sip_parser.h>
22#include <pjsip/sip_module.h>
23#include <pjsip/sip_transaction.h>
24#include <pjsip/sip_event.h>
25#include <pjsip/sip_util.h>
26#include <pjsip/sip_auth_msg.h>
Benny Prijonoccf95622006-02-07 18:48:01 +000027#include <pjsip/sip_errno.h>
Benny Prijonoccf95622006-02-07 18:48:01 +000028#include <pj/assert.h>
Benny Prijonobcaed6c2006-02-19 15:37:19 +000029#include <pj/guid.h>
30#include <pj/os.h>
31#include <pj/pool.h>
32#include <pj/log.h>
Benny Prijono59ca70f2006-02-22 22:18:58 +000033#include <pj/rand.h>
Benny Prijonobcaed6c2006-02-19 15:37:19 +000034#include <pj/string.h>
Benny Prijonoccf95622006-02-07 18:48:01 +000035
Benny Prijono5dcb38d2005-11-21 01:55:47 +000036
37#define REFRESH_TIMER 1
38#define DELAY_BEFORE_REFRESH 5
39#define THIS_FILE "sip_regc.c"
40
41/**
42 * SIP client registration structure.
43 */
44struct pjsip_regc
45{
Benny Prijono84126ab2006-02-09 09:30:09 +000046 pj_pool_t *pool;
47 pjsip_endpoint *endpt;
48 pj_bool_t _delete_flag;
49 int pending_tsx;
Benny Prijono5dcb38d2005-11-21 01:55:47 +000050
Benny Prijono84126ab2006-02-09 09:30:09 +000051 void *token;
52 pjsip_regc_cb *cb;
Benny Prijono5dcb38d2005-11-21 01:55:47 +000053
Benny Prijono84126ab2006-02-09 09:30:09 +000054 pj_str_t str_srv_url;
55 pjsip_uri *srv_url;
56 pjsip_cid_hdr *cid_hdr;
57 pjsip_cseq_hdr *cseq_hdr;
Benny Prijonobcaed6c2006-02-19 15:37:19 +000058 pj_str_t from_uri;
Benny Prijono84126ab2006-02-09 09:30:09 +000059 pjsip_from_hdr *from_hdr;
60 pjsip_to_hdr *to_hdr;
61 char *contact_buf;
Benny Prijono5dcb38d2005-11-21 01:55:47 +000062 pjsip_generic_string_hdr *contact_hdr;
Benny Prijono84126ab2006-02-09 09:30:09 +000063 pjsip_expires_hdr *expires_hdr;
64 pjsip_contact_hdr *unreg_contact_hdr;
65 pjsip_expires_hdr *unreg_expires_hdr;
66 pj_uint32_t expires;
67 pjsip_route_hdr route_set;
Benny Prijono5dcb38d2005-11-21 01:55:47 +000068
Benny Prijono5dcb38d2005-11-21 01:55:47 +000069 /* Authorization sessions. */
Benny Prijono84126ab2006-02-09 09:30:09 +000070 pjsip_auth_clt_sess auth_sess;
Benny Prijono5dcb38d2005-11-21 01:55:47 +000071
72 /* Auto refresh registration. */
Benny Prijono84126ab2006-02-09 09:30:09 +000073 pj_bool_t auto_reg;
Benny Prijonobcaed6c2006-02-19 15:37:19 +000074 pj_time_val last_reg;
75 pj_time_val next_reg;
Benny Prijono84126ab2006-02-09 09:30:09 +000076 pj_timer_entry timer;
Benny Prijono5dcb38d2005-11-21 01:55:47 +000077};
78
79
80
Benny Prijonoccf95622006-02-07 18:48:01 +000081PJ_DEF(pj_status_t) pjsip_regc_create( pjsip_endpoint *endpt, void *token,
82 pjsip_regc_cb *cb,
83 pjsip_regc **p_regc)
Benny Prijono5dcb38d2005-11-21 01:55:47 +000084{
85 pj_pool_t *pool;
86 pjsip_regc *regc;
Benny Prijonoccf95622006-02-07 18:48:01 +000087 pj_status_t status;
Benny Prijono5dcb38d2005-11-21 01:55:47 +000088
Benny Prijonoccf95622006-02-07 18:48:01 +000089 /* Verify arguments. */
90 PJ_ASSERT_RETURN(endpt && cb && p_regc, PJ_EINVAL);
Benny Prijono5dcb38d2005-11-21 01:55:47 +000091
92 pool = pjsip_endpt_create_pool(endpt, "regc%p", 1024, 1024);
Benny Prijonoccf95622006-02-07 18:48:01 +000093 PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
94
95 regc = pj_pool_zalloc(pool, sizeof(struct pjsip_regc));
Benny Prijono5dcb38d2005-11-21 01:55:47 +000096
97 regc->pool = pool;
98 regc->endpt = endpt;
99 regc->token = token;
100 regc->cb = cb;
101 regc->contact_buf = pj_pool_alloc(pool, PJSIP_REGC_CONTACT_BUF_SIZE);
102 regc->expires = PJSIP_REGC_EXPIRATION_NOT_SPECIFIED;
103
Benny Prijonoccf95622006-02-07 18:48:01 +0000104 status = pjsip_auth_clt_init(&regc->auth_sess, endpt, regc->pool, 0);
105 if (status != PJ_SUCCESS)
106 return status;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000107
Benny Prijono84126ab2006-02-09 09:30:09 +0000108 pj_list_init(&regc->route_set);
109
Benny Prijonoccf95622006-02-07 18:48:01 +0000110 /* Done */
111 *p_regc = regc;
112 return PJ_SUCCESS;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000113}
114
115
Benny Prijonoccf95622006-02-07 18:48:01 +0000116PJ_DEF(pj_status_t) pjsip_regc_destroy(pjsip_regc *regc)
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000117{
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000118 PJ_ASSERT_RETURN(regc, PJ_EINVAL);
119
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000120 if (regc->pending_tsx) {
121 regc->_delete_flag = 1;
122 regc->cb = NULL;
123 } else {
Benny Prijonoccf95622006-02-07 18:48:01 +0000124 pjsip_endpt_release_pool(regc->endpt, regc->pool);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000125 }
Benny Prijonoccf95622006-02-07 18:48:01 +0000126
127 return PJ_SUCCESS;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000128}
129
130
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000131PJ_DEF(pj_status_t) pjsip_regc_get_info( pjsip_regc *regc,
132 pjsip_regc_info *info )
133{
134 PJ_ASSERT_RETURN(regc && info, PJ_EINVAL);
135
136 info->server_uri = regc->str_srv_url;
137 info->client_uri = regc->from_uri;
138 info->is_busy = (regc->pending_tsx != 0);
139 info->auto_reg = regc->auto_reg;
140 info->interval = regc->expires;
141
142 if (regc->pending_tsx)
143 info->next_reg = 0;
144 else if (regc->auto_reg == 0)
145 info->next_reg = 0;
146 else if (regc->expires < 0)
147 info->next_reg = regc->expires;
148 else {
149 pj_time_val now, next_reg;
150
151 next_reg = regc->next_reg;
152 pj_gettimeofday(&now);
153 PJ_TIME_VAL_SUB(next_reg, now);
154 info->next_reg = next_reg.sec;
155 }
156
157 return PJ_SUCCESS;
158}
159
160
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000161PJ_DEF(pj_pool_t*) pjsip_regc_get_pool(pjsip_regc *regc)
162{
163 return regc->pool;
164}
165
166static void set_expires( pjsip_regc *regc, pj_uint32_t expires)
167{
168 if (expires != regc->expires) {
Benny Prijonoccf95622006-02-07 18:48:01 +0000169 regc->expires_hdr = pjsip_expires_hdr_create(regc->pool, expires);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000170 } else {
171 regc->expires_hdr = NULL;
172 }
173}
174
175
176static pj_status_t set_contact( pjsip_regc *regc,
177 int contact_cnt,
178 const pj_str_t contact[] )
179{
180 int i;
181 char *s;
182 const pj_str_t contact_STR = { "Contact", 7};
183
184 /* Concatenate contacts. */
185 for (i=0, s=regc->contact_buf; i<contact_cnt; ++i) {
186 if ((s-regc->contact_buf) + contact[i].slen + 2 > PJSIP_REGC_CONTACT_BUF_SIZE) {
Benny Prijonoccf95622006-02-07 18:48:01 +0000187 return PJSIP_EURITOOLONG;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000188 }
189 pj_memcpy(s, contact[i].ptr, contact[i].slen);
190 s += contact[i].slen;
191
192 if (i != contact_cnt - 1) {
193 *s++ = ',';
194 *s++ = ' ';
195 }
196 }
197
198 /* Set "Contact" header. */
Benny Prijonoccf95622006-02-07 18:48:01 +0000199 regc->contact_hdr = pjsip_generic_string_hdr_create(regc->pool,
200 &contact_STR,
201 NULL);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000202 regc->contact_hdr->hvalue.ptr = regc->contact_buf;
203 regc->contact_hdr->hvalue.slen = (s - regc->contact_buf);
204
Benny Prijonoccf95622006-02-07 18:48:01 +0000205 return PJ_SUCCESS;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000206}
207
208
209PJ_DEF(pj_status_t) pjsip_regc_init( pjsip_regc *regc,
210 const pj_str_t *srv_url,
211 const pj_str_t *from_url,
212 const pj_str_t *to_url,
213 int contact_cnt,
214 const pj_str_t contact[],
215 pj_uint32_t expires)
216{
217 pj_str_t tmp;
Benny Prijonoccf95622006-02-07 18:48:01 +0000218 pj_status_t status;
219
220 PJ_ASSERT_RETURN(regc && srv_url && from_url && to_url &&
221 contact_cnt && contact && expires, PJ_EINVAL);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000222
223 /* Copy server URL. */
224 pj_strdup_with_null(regc->pool, &regc->str_srv_url, srv_url);
225
226 /* Set server URL. */
227 tmp = regc->str_srv_url;
228 regc->srv_url = pjsip_parse_uri( regc->pool, tmp.ptr, tmp.slen, 0);
229 if (regc->srv_url == NULL) {
Benny Prijonoccf95622006-02-07 18:48:01 +0000230 return PJSIP_EINVALIDURI;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000231 }
232
233 /* Set "From" header. */
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000234 pj_strdup_with_null(regc->pool, &regc->from_uri, from_url);
235 tmp = regc->from_uri;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000236 regc->from_hdr = pjsip_from_hdr_create(regc->pool);
237 regc->from_hdr->uri = pjsip_parse_uri(regc->pool, tmp.ptr, tmp.slen,
238 PJSIP_PARSE_URI_AS_NAMEADDR);
239 if (!regc->from_hdr->uri) {
Benny Prijonoccf95622006-02-07 18:48:01 +0000240 PJ_LOG(4,(THIS_FILE, "regc: invalid source URI %.*s",
241 from_url->slen, from_url->ptr));
242 return PJSIP_EINVALIDURI;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000243 }
244
245 /* Set "To" header. */
246 pj_strdup_with_null(regc->pool, &tmp, to_url);
247 regc->to_hdr = pjsip_to_hdr_create(regc->pool);
248 regc->to_hdr->uri = pjsip_parse_uri(regc->pool, tmp.ptr, tmp.slen,
249 PJSIP_PARSE_URI_AS_NAMEADDR);
250 if (!regc->to_hdr->uri) {
251 PJ_LOG(4,(THIS_FILE, "regc: invalid target URI %.*s", to_url->slen, to_url->ptr));
Benny Prijonoccf95622006-02-07 18:48:01 +0000252 return PJSIP_EINVALIDURI;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000253 }
254
255
256 /* Set "Contact" header. */
Benny Prijonoccf95622006-02-07 18:48:01 +0000257 status = set_contact( regc, contact_cnt, contact);
258 if (status != PJ_SUCCESS)
259 return status;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000260
261 /* Set "Expires" header, if required. */
262 set_expires( regc, expires);
263
264 /* Set "Call-ID" header. */
265 regc->cid_hdr = pjsip_cid_hdr_create(regc->pool);
266 pj_create_unique_string(regc->pool, &regc->cid_hdr->id);
267
268 /* Set "CSeq" header. */
269 regc->cseq_hdr = pjsip_cseq_hdr_create(regc->pool);
Benny Prijono59ca70f2006-02-22 22:18:58 +0000270 regc->cseq_hdr->cseq = pj_rand() % 0xFFFF;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000271 pjsip_method_set( &regc->cseq_hdr->method, PJSIP_REGISTER_METHOD);
272
273 /* Create "Contact" header used in unregistration. */
274 regc->unreg_contact_hdr = pjsip_contact_hdr_create(regc->pool);
275 regc->unreg_contact_hdr->star = 1;
276
277 /* Create "Expires" header used in unregistration. */
Benny Prijonoccf95622006-02-07 18:48:01 +0000278 regc->unreg_expires_hdr = pjsip_expires_hdr_create( regc->pool, 0);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000279
280 /* Done. */
Benny Prijonoccf95622006-02-07 18:48:01 +0000281 return PJ_SUCCESS;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000282}
283
284PJ_DEF(pj_status_t) pjsip_regc_set_credentials( pjsip_regc *regc,
285 int count,
286 const pjsip_cred_info cred[] )
287{
Benny Prijonoccf95622006-02-07 18:48:01 +0000288 PJ_ASSERT_RETURN(regc && count && cred, PJ_EINVAL);
289 return pjsip_auth_clt_set_credentials(&regc->auth_sess, count, cred);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000290}
291
Benny Prijono84126ab2006-02-09 09:30:09 +0000292PJ_DEF(pj_status_t) pjsip_regc_set_route_set( pjsip_regc *regc,
293 const pjsip_route_hdr *route_set)
294{
295 const pjsip_route_hdr *chdr;
296
297 PJ_ASSERT_RETURN(regc && route_set, PJ_EINVAL);
298
299 pj_list_init(&regc->route_set);
300
301 chdr = route_set->next;
302 while (chdr != route_set) {
303 pj_list_push_back(&regc->route_set, pjsip_hdr_clone(regc->pool, chdr));
304 chdr = chdr->next;
305 }
306
307 return PJ_SUCCESS;
308}
309
Benny Prijonoccf95622006-02-07 18:48:01 +0000310static pj_status_t create_request(pjsip_regc *regc,
311 pjsip_tx_data **p_tdata)
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000312{
Benny Prijonoccf95622006-02-07 18:48:01 +0000313 pj_status_t status;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000314 pjsip_tx_data *tdata;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000315
Benny Prijonoccf95622006-02-07 18:48:01 +0000316 PJ_ASSERT_RETURN(regc && p_tdata, PJ_EINVAL);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000317
Benny Prijonoccf95622006-02-07 18:48:01 +0000318 /* Create the request. */
319 status = pjsip_endpt_create_request_from_hdr( regc->endpt,
320 &pjsip_register_method,
321 regc->srv_url,
322 regc->from_hdr,
323 regc->to_hdr,
324 NULL,
325 regc->cid_hdr,
326 regc->cseq_hdr->cseq,
327 NULL,
328 &tdata);
329 if (status != PJ_SUCCESS)
330 return status;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000331
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000332 /* Add cached authorization headers. */
Benny Prijonoccf95622006-02-07 18:48:01 +0000333 pjsip_auth_clt_init_req( &regc->auth_sess, tdata );
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000334
Benny Prijono84126ab2006-02-09 09:30:09 +0000335 /* Add Route headers from route set, ideally after Via header */
336 if (!pj_list_empty(&regc->route_set)) {
337 pjsip_hdr *route_pos;
338 const pjsip_route_hdr *route;
339
340 route_pos = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
341 if (!route_pos)
342 route_pos = &tdata->msg->hdr;
343
344 route = regc->route_set.next;
345 while (route != &regc->route_set) {
346 pjsip_hdr *new_hdr = pjsip_hdr_shallow_clone(tdata->pool, route);
347 pj_list_insert_after(route_pos, new_hdr);
348 route_pos = new_hdr;
349 route = route->next;
350 }
351 }
352
Benny Prijonoccf95622006-02-07 18:48:01 +0000353 /* Done. */
354 *p_tdata = tdata;
355 return PJ_SUCCESS;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000356}
357
358
Benny Prijonoccf95622006-02-07 18:48:01 +0000359PJ_DEF(pj_status_t) pjsip_regc_register(pjsip_regc *regc, pj_bool_t autoreg,
360 pjsip_tx_data **p_tdata)
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000361{
362 pjsip_msg *msg;
Benny Prijonoccf95622006-02-07 18:48:01 +0000363 pj_status_t status;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000364 pjsip_tx_data *tdata;
365
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000366 PJ_ASSERT_RETURN(regc && p_tdata, PJ_EINVAL);
367
Benny Prijonoccf95622006-02-07 18:48:01 +0000368 status = create_request(regc, &tdata);
369 if (status != PJ_SUCCESS)
370 return status;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000371
Benny Prijonoccf95622006-02-07 18:48:01 +0000372 /* Add Contact header. */
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000373 msg = tdata->msg;
Benny Prijono4093f7c2006-09-13 23:48:45 +0000374 pjsip_msg_add_hdr(msg, pjsip_hdr_shallow_clone(tdata->pool,
375 regc->contact_hdr));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000376 if (regc->expires_hdr)
Benny Prijono4093f7c2006-09-13 23:48:45 +0000377 pjsip_msg_add_hdr(msg, pjsip_hdr_shallow_clone(tdata->pool,
378 regc->expires_hdr));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000379
380 if (regc->timer.id != 0) {
381 pjsip_endpt_cancel_timer(regc->endpt, &regc->timer);
382 regc->timer.id = 0;
383 }
384
385 regc->auto_reg = autoreg;
386
Benny Prijonoccf95622006-02-07 18:48:01 +0000387 /* Done */
388 *p_tdata = tdata;
389 return PJ_SUCCESS;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000390}
391
392
Benny Prijonoccf95622006-02-07 18:48:01 +0000393PJ_DEF(pj_status_t) pjsip_regc_unregister(pjsip_regc *regc,
394 pjsip_tx_data **p_tdata)
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000395{
396 pjsip_tx_data *tdata;
397 pjsip_msg *msg;
Benny Prijonoccf95622006-02-07 18:48:01 +0000398 pj_status_t status;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000399
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000400 PJ_ASSERT_RETURN(regc && p_tdata, PJ_EINVAL);
401
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000402 if (regc->timer.id != 0) {
403 pjsip_endpt_cancel_timer(regc->endpt, &regc->timer);
404 regc->timer.id = 0;
405 }
406
Benny Prijonoccf95622006-02-07 18:48:01 +0000407 status = create_request(regc, &tdata);
408 if (status != PJ_SUCCESS)
409 return status;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000410
411 msg = tdata->msg;
412 pjsip_msg_add_hdr( msg, (pjsip_hdr*)regc->unreg_contact_hdr);
413 pjsip_msg_add_hdr( msg, (pjsip_hdr*)regc->unreg_expires_hdr);
414
Benny Prijonoccf95622006-02-07 18:48:01 +0000415 *p_tdata = tdata;
416 return PJ_SUCCESS;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000417}
418
419
420PJ_DEF(pj_status_t) pjsip_regc_update_contact( pjsip_regc *regc,
421 int contact_cnt,
422 const pj_str_t contact[] )
423{
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000424 PJ_ASSERT_RETURN(regc, PJ_EINVAL);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000425 return set_contact( regc, contact_cnt, contact );
426}
427
428
429PJ_DEF(pj_status_t) pjsip_regc_update_expires( pjsip_regc *regc,
430 pj_uint32_t expires )
431{
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000432 PJ_ASSERT_RETURN(regc, PJ_EINVAL);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000433 set_expires( regc, expires );
Benny Prijonoccf95622006-02-07 18:48:01 +0000434 return PJ_SUCCESS;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000435}
436
437
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000438static void call_callback(pjsip_regc *regc, pj_status_t status, int st_code,
439 const pj_str_t *reason,
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000440 pjsip_rx_data *rdata, pj_int32_t expiration,
441 int contact_cnt, pjsip_contact_hdr *contact[])
442{
443 struct pjsip_regc_cbparam cbparam;
444
445
446 cbparam.regc = regc;
447 cbparam.token = regc->token;
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000448 cbparam.status = status;
449 cbparam.code = st_code;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000450 cbparam.reason = *reason;
451 cbparam.rdata = rdata;
452 cbparam.contact_cnt = contact_cnt;
453 cbparam.expiration = expiration;
454 if (contact_cnt) {
455 pj_memcpy( cbparam.contact, contact,
456 contact_cnt*sizeof(pjsip_contact_hdr*));
457 }
458
459 (*regc->cb)(&cbparam);
460}
461
462static void regc_refresh_timer_cb( pj_timer_heap_t *timer_heap,
463 struct pj_timer_entry *entry)
464{
465 pjsip_regc *regc = entry->user_data;
466 pjsip_tx_data *tdata;
Benny Prijonoccf95622006-02-07 18:48:01 +0000467 pj_status_t status;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000468
Benny Prijonoccf95622006-02-07 18:48:01 +0000469 PJ_UNUSED_ARG(timer_heap);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000470
471 entry->id = 0;
Benny Prijonoccf95622006-02-07 18:48:01 +0000472 status = pjsip_regc_register(regc, 1, &tdata);
473 if (status == PJ_SUCCESS) {
Benny Prijono27042582006-08-08 14:04:21 +0000474 status = pjsip_regc_send(regc, tdata);
475 }
476
477 if (status != PJ_SUCCESS) {
Benny Prijonoccf95622006-02-07 18:48:01 +0000478 char errmsg[PJ_ERR_MSG_SIZE];
479 pj_str_t reason = pj_strerror(status, errmsg, sizeof(errmsg));
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000480 call_callback(regc, status, 400, &reason, NULL, -1, 0, NULL);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000481 }
482}
483
484static void tsx_callback(void *token, pjsip_event *event)
485{
Benny Prijonoccf95622006-02-07 18:48:01 +0000486 pj_status_t status;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000487 pjsip_regc *regc = token;
Benny Prijonoccf95622006-02-07 18:48:01 +0000488 pjsip_transaction *tsx = event->body.tsx_state.tsx;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000489
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000490 /* Decrement pending transaction counter. */
Benny Prijonodc39fe82006-05-26 12:17:46 +0000491 pj_assert(regc->pending_tsx > 0);
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000492 --regc->pending_tsx;
493
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000494 /* If registration data has been deleted by user then remove registration
495 * data from transaction's callback, and don't call callback.
496 */
497 if (regc->_delete_flag) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000498
499 /* Nothing to do */
500 ;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000501
502 } else if (tsx->status_code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED ||
503 tsx->status_code == PJSIP_SC_UNAUTHORIZED)
504 {
Benny Prijonoccf95622006-02-07 18:48:01 +0000505 pjsip_rx_data *rdata = event->body.tsx_state.src.rdata;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000506 pjsip_tx_data *tdata;
507
Benny Prijonoccf95622006-02-07 18:48:01 +0000508 status = pjsip_auth_clt_reinit_req( &regc->auth_sess,
509 rdata,
510 tsx->last_tx,
511 &tdata);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000512
Benny Prijonoccf95622006-02-07 18:48:01 +0000513 if (status == PJ_SUCCESS) {
Benny Prijono27042582006-08-08 14:04:21 +0000514 status = pjsip_regc_send(regc, tdata);
515 }
516
517 if (status != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000518 call_callback(regc, status, tsx->status_code,
519 &rdata->msg_info.msg->line.status.reason,
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000520 rdata, -1, 0, NULL);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000521 }
Benny Prijono27042582006-08-08 14:04:21 +0000522
523 return;
524
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000525 } else {
526 int contact_cnt = 0;
527 pjsip_contact_hdr *contact[PJSIP_REGC_MAX_CONTACT];
528 pjsip_rx_data *rdata;
529 pj_int32_t expiration = 0xFFFF;
530
531 if (tsx->status_code/100 == 2) {
532 int i;
533 pjsip_contact_hdr *hdr;
534 pjsip_msg *msg;
535 pjsip_expires_hdr *expires;
536
Benny Prijonoccf95622006-02-07 18:48:01 +0000537 rdata = event->body.tsx_state.src.rdata;
538 msg = rdata->msg_info.msg;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000539 hdr = pjsip_msg_find_hdr( msg, PJSIP_H_CONTACT, NULL);
540 while (hdr) {
541 contact[contact_cnt++] = hdr;
542 hdr = hdr->next;
543 if (hdr == (void*)&msg->hdr)
544 break;
545 hdr = pjsip_msg_find_hdr(msg, PJSIP_H_CONTACT, hdr);
546 }
547
548 expires = pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL);
549
550 if (expires)
551 expiration = expires->ivalue;
552
553 for (i=0; i<contact_cnt; ++i) {
554 hdr = contact[i];
555 if (hdr->expires >= 0 && hdr->expires < expiration)
556 expiration = contact[i]->expires;
557 }
558
559 if (regc->auto_reg && expiration != 0 && expiration != 0xFFFF) {
560 pj_time_val delay = { 0, 0};
561
562 delay.sec = expiration - DELAY_BEFORE_REFRESH;
563 if (regc->expires != PJSIP_REGC_EXPIRATION_NOT_SPECIFIED &&
564 delay.sec > (pj_int32_t)regc->expires)
565 {
566 delay.sec = regc->expires;
567 }
568 if (delay.sec < DELAY_BEFORE_REFRESH)
569 delay.sec = DELAY_BEFORE_REFRESH;
570 regc->timer.cb = &regc_refresh_timer_cb;
571 regc->timer.id = REFRESH_TIMER;
572 regc->timer.user_data = regc;
573 pjsip_endpt_schedule_timer( regc->endpt, &regc->timer, &delay);
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000574 pj_gettimeofday(&regc->last_reg);
575 regc->next_reg = regc->last_reg;
576 regc->next_reg.sec += delay.sec;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000577 }
578
579 } else {
Benny Prijonoccf95622006-02-07 18:48:01 +0000580 rdata = (event->body.tsx_state.type==PJSIP_EVENT_RX_MSG) ?
581 event->body.tsx_state.src.rdata : NULL;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000582 }
583
Benny Prijono197cabf2006-10-16 20:05:27 +0000584 /* Increment pending_tsx temporarily to prevent regc from
585 * being destroyed.
586 */
587 ++regc->pending_tsx;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000588
589 /* Call callback. */
590 if (expiration == 0xFFFF) expiration = -1;
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000591 call_callback(regc, PJ_SUCCESS, tsx->status_code,
Benny Prijonoccf95622006-02-07 18:48:01 +0000592 (rdata ? &rdata->msg_info.msg->line.status.reason
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000593 : pjsip_get_status_text(tsx->status_code)),
594 rdata, expiration,
595 contact_cnt, contact);
596
Benny Prijono197cabf2006-10-16 20:05:27 +0000597 /* Decrement pending_tsx */
598 --regc->pending_tsx;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000599 }
600
601 /* Delete the record if user destroy regc during the callback. */
602 if (regc->_delete_flag && regc->pending_tsx==0) {
603 pjsip_regc_destroy(regc);
604 }
605}
606
Benny Prijonoccf95622006-02-07 18:48:01 +0000607PJ_DEF(pj_status_t) pjsip_regc_send(pjsip_regc *regc, pjsip_tx_data *tdata)
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000608{
Benny Prijonoccf95622006-02-07 18:48:01 +0000609 pj_status_t status;
Benny Prijono59ca70f2006-02-22 22:18:58 +0000610 pjsip_cseq_hdr *cseq_hdr;
611 pj_uint32_t cseq;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000612
613 /* Make sure we don't have pending transaction. */
614 if (regc->pending_tsx) {
Benny Prijono5b656872006-08-08 00:41:00 +0000615 PJ_LOG(4,(THIS_FILE, "Unable to send request, regc has another "
616 "transaction pending"));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000617 pjsip_tx_data_dec_ref( tdata );
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000618 return PJSIP_EBUSY;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000619 }
620
621 /* Invalidate message buffer. */
622 pjsip_tx_data_invalidate_msg(tdata);
623
624 /* Increment CSeq */
Benny Prijono59ca70f2006-02-22 22:18:58 +0000625 cseq = ++regc->cseq_hdr->cseq;
626 cseq_hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
627 cseq_hdr->cseq = cseq;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000628
Benny Prijonodc39fe82006-05-26 12:17:46 +0000629 /* Increment pending transaction first, since transaction callback
630 * may be called even before send_request() returns!
631 */
Benny Prijono197cabf2006-10-16 20:05:27 +0000632 regc->pending_tsx += 2;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000633 status = pjsip_endpt_send_request(regc->endpt, tdata, -1, regc, &tsx_callback);
Benny Prijono5b656872006-08-08 00:41:00 +0000634 if (status!=PJ_SUCCESS) {
Benny Prijono5b656872006-08-08 00:41:00 +0000635 PJ_LOG(4,(THIS_FILE, "Error sending request, status=%d", status));
636 }
Benny Prijono197cabf2006-10-16 20:05:27 +0000637 --regc->pending_tsx;
638
639 /* Delete the record if user destroy regc during the callback. */
640 if (regc->_delete_flag && regc->pending_tsx==0) {
641 pjsip_regc_destroy(regc);
642 }
Benny Prijonoccf95622006-02-07 18:48:01 +0000643
644 return status;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000645}
646
647