blob: fda28d70706df66a1ffa789dfaf5984a1b68e527 [file] [log] [blame]
Benny Prijono5dcb38d2005-11-21 01:55:47 +00001/* $Id$ */
2/*
Benny Prijonoa771a512007-02-19 01:13:53 +00003 * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org>
Benny Prijono5dcb38d2005-11-21 01:55:47 +00004 *
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
Benny Prijono315999b2007-09-30 10:58:36 +000039#define THIS_FILE "sip_reg.c"
Benny Prijono5dcb38d2005-11-21 01:55:47 +000040
Benny Prijono0f35f912007-02-05 18:59:31 +000041/* Outgoing transaction timeout when server sends 100 but never replies
42 * with final response. Value is in MILISECONDS!
43 */
44#define REGC_TSX_TIMEOUT 33000
45
46
Benny Prijono5dcb38d2005-11-21 01:55:47 +000047/**
48 * SIP client registration structure.
49 */
50struct pjsip_regc
51{
Benny Prijono84126ab2006-02-09 09:30:09 +000052 pj_pool_t *pool;
53 pjsip_endpoint *endpt;
54 pj_bool_t _delete_flag;
Benny Prijono25a86c72006-12-01 20:50:01 +000055 pj_bool_t has_tsx;
56 pj_int32_t busy;
Benny Prijono5dcb38d2005-11-21 01:55:47 +000057
Benny Prijono84126ab2006-02-09 09:30:09 +000058 void *token;
59 pjsip_regc_cb *cb;
Benny Prijono5dcb38d2005-11-21 01:55:47 +000060
Benny Prijono84126ab2006-02-09 09:30:09 +000061 pj_str_t str_srv_url;
62 pjsip_uri *srv_url;
63 pjsip_cid_hdr *cid_hdr;
64 pjsip_cseq_hdr *cseq_hdr;
Benny Prijonobcaed6c2006-02-19 15:37:19 +000065 pj_str_t from_uri;
Benny Prijono84126ab2006-02-09 09:30:09 +000066 pjsip_from_hdr *from_hdr;
67 pjsip_to_hdr *to_hdr;
Benny Prijonoe56b5b12007-09-11 09:04:51 +000068 pjsip_hdr contact_hdr_list;
Benny Prijono84126ab2006-02-09 09:30:09 +000069 pjsip_expires_hdr *expires_hdr;
70 pjsip_contact_hdr *unreg_contact_hdr;
71 pjsip_expires_hdr *unreg_expires_hdr;
72 pj_uint32_t expires;
73 pjsip_route_hdr route_set;
Benny Prijono8fc6de02006-11-11 21:25:55 +000074 pjsip_hdr hdr_list;
Benny Prijono5dcb38d2005-11-21 01:55:47 +000075
Benny Prijono5dcb38d2005-11-21 01:55:47 +000076 /* Authorization sessions. */
Benny Prijono84126ab2006-02-09 09:30:09 +000077 pjsip_auth_clt_sess auth_sess;
Benny Prijono5dcb38d2005-11-21 01:55:47 +000078
79 /* Auto refresh registration. */
Benny Prijono84126ab2006-02-09 09:30:09 +000080 pj_bool_t auto_reg;
Benny Prijonobcaed6c2006-02-19 15:37:19 +000081 pj_time_val last_reg;
82 pj_time_val next_reg;
Benny Prijono84126ab2006-02-09 09:30:09 +000083 pj_timer_entry timer;
Benny Prijono720d0a82007-01-12 06:37:35 +000084
85 /* Transport selector */
86 pjsip_tpselector tp_sel;
Benny Prijonobdc093f2007-10-04 09:48:25 +000087
88 /* Last transport used. We acquire the transport to keep
89 * it open.
90 */
91 pjsip_transport *last_transport;
Benny Prijono5dcb38d2005-11-21 01:55:47 +000092};
93
94
95
Benny Prijonoccf95622006-02-07 18:48:01 +000096PJ_DEF(pj_status_t) pjsip_regc_create( pjsip_endpoint *endpt, void *token,
97 pjsip_regc_cb *cb,
98 pjsip_regc **p_regc)
Benny Prijono5dcb38d2005-11-21 01:55:47 +000099{
100 pj_pool_t *pool;
101 pjsip_regc *regc;
Benny Prijonoccf95622006-02-07 18:48:01 +0000102 pj_status_t status;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000103
Benny Prijonoccf95622006-02-07 18:48:01 +0000104 /* Verify arguments. */
105 PJ_ASSERT_RETURN(endpt && cb && p_regc, PJ_EINVAL);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000106
107 pool = pjsip_endpt_create_pool(endpt, "regc%p", 1024, 1024);
Benny Prijonoccf95622006-02-07 18:48:01 +0000108 PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
109
Benny Prijonoa1e69682007-05-11 15:14:34 +0000110 regc = PJ_POOL_ZALLOC_T(pool, pjsip_regc);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000111
112 regc->pool = pool;
113 regc->endpt = endpt;
114 regc->token = token;
115 regc->cb = cb;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000116 regc->expires = PJSIP_REGC_EXPIRATION_NOT_SPECIFIED;
117
Benny Prijonoccf95622006-02-07 18:48:01 +0000118 status = pjsip_auth_clt_init(&regc->auth_sess, endpt, regc->pool, 0);
119 if (status != PJ_SUCCESS)
120 return status;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000121
Benny Prijono84126ab2006-02-09 09:30:09 +0000122 pj_list_init(&regc->route_set);
Benny Prijono8fc6de02006-11-11 21:25:55 +0000123 pj_list_init(&regc->hdr_list);
Benny Prijonoe56b5b12007-09-11 09:04:51 +0000124 pj_list_init(&regc->contact_hdr_list);
Benny Prijono84126ab2006-02-09 09:30:09 +0000125
Benny Prijonoccf95622006-02-07 18:48:01 +0000126 /* Done */
127 *p_regc = regc;
128 return PJ_SUCCESS;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000129}
130
131
Benny Prijonoccf95622006-02-07 18:48:01 +0000132PJ_DEF(pj_status_t) pjsip_regc_destroy(pjsip_regc *regc)
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000133{
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000134 PJ_ASSERT_RETURN(regc, PJ_EINVAL);
135
Benny Prijono25a86c72006-12-01 20:50:01 +0000136 if (regc->has_tsx || regc->busy) {
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000137 regc->_delete_flag = 1;
138 regc->cb = NULL;
139 } else {
Benny Prijono720d0a82007-01-12 06:37:35 +0000140 pjsip_tpselector_dec_ref(&regc->tp_sel);
Benny Prijonobdc093f2007-10-04 09:48:25 +0000141 if (regc->last_transport) {
142 pjsip_transport_dec_ref(regc->last_transport);
143 regc->last_transport = NULL;
144 }
Benny Prijonoccf95622006-02-07 18:48:01 +0000145 pjsip_endpt_release_pool(regc->endpt, regc->pool);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000146 }
Benny Prijonoccf95622006-02-07 18:48:01 +0000147
148 return PJ_SUCCESS;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000149}
150
151
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000152PJ_DEF(pj_status_t) pjsip_regc_get_info( pjsip_regc *regc,
153 pjsip_regc_info *info )
154{
155 PJ_ASSERT_RETURN(regc && info, PJ_EINVAL);
156
157 info->server_uri = regc->str_srv_url;
158 info->client_uri = regc->from_uri;
Benny Prijono25a86c72006-12-01 20:50:01 +0000159 info->is_busy = (regc->busy || regc->has_tsx);
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000160 info->auto_reg = regc->auto_reg;
161 info->interval = regc->expires;
162
Benny Prijono25a86c72006-12-01 20:50:01 +0000163 if (regc->has_tsx)
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000164 info->next_reg = 0;
165 else if (regc->auto_reg == 0)
166 info->next_reg = 0;
167 else if (regc->expires < 0)
168 info->next_reg = regc->expires;
169 else {
170 pj_time_val now, next_reg;
171
172 next_reg = regc->next_reg;
173 pj_gettimeofday(&now);
174 PJ_TIME_VAL_SUB(next_reg, now);
175 info->next_reg = next_reg.sec;
176 }
177
178 return PJ_SUCCESS;
179}
180
181
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000182PJ_DEF(pj_pool_t*) pjsip_regc_get_pool(pjsip_regc *regc)
183{
184 return regc->pool;
185}
186
187static void set_expires( pjsip_regc *regc, pj_uint32_t expires)
188{
189 if (expires != regc->expires) {
Benny Prijonoccf95622006-02-07 18:48:01 +0000190 regc->expires_hdr = pjsip_expires_hdr_create(regc->pool, expires);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000191 } else {
192 regc->expires_hdr = NULL;
193 }
194}
195
196
197static pj_status_t set_contact( pjsip_regc *regc,
198 int contact_cnt,
199 const pj_str_t contact[] )
200{
Benny Prijonoe56b5b12007-09-11 09:04:51 +0000201 const pj_str_t CONTACT = { "Contact", 7 };
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000202 int i;
Benny Prijonoe56b5b12007-09-11 09:04:51 +0000203
204 /* Clear existing contacts */
205 pj_list_init(&regc->contact_hdr_list);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000206
Benny Prijonoe56b5b12007-09-11 09:04:51 +0000207 for (i=0; i<contact_cnt; ++i) {
208 pjsip_hdr *hdr;
209 pj_str_t tmp;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000210
Benny Prijonoe56b5b12007-09-11 09:04:51 +0000211 pj_strdup_with_null(regc->pool, &tmp, &contact[i]);
Benny Prijono91a5a3a2007-09-24 21:16:48 +0000212 hdr = (pjsip_hdr*)
213 pjsip_parse_hdr(regc->pool, &CONTACT, tmp.ptr, tmp.slen, NULL);
Benny Prijonoe56b5b12007-09-11 09:04:51 +0000214 if (hdr == NULL) {
215 PJ_LOG(4,(THIS_FILE, "Invalid Contact URI: \"%.*s\"",
216 (int)tmp.slen, tmp.ptr));
217 return PJSIP_EINVALIDURI;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000218 }
Benny Prijonoe56b5b12007-09-11 09:04:51 +0000219
220 pj_list_push_back(&regc->contact_hdr_list, hdr);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000221 }
222
Benny Prijonoccf95622006-02-07 18:48:01 +0000223 return PJ_SUCCESS;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000224}
225
226
227PJ_DEF(pj_status_t) pjsip_regc_init( pjsip_regc *regc,
228 const pj_str_t *srv_url,
229 const pj_str_t *from_url,
230 const pj_str_t *to_url,
231 int contact_cnt,
232 const pj_str_t contact[],
233 pj_uint32_t expires)
234{
235 pj_str_t tmp;
Benny Prijonoccf95622006-02-07 18:48:01 +0000236 pj_status_t status;
237
238 PJ_ASSERT_RETURN(regc && srv_url && from_url && to_url &&
239 contact_cnt && contact && expires, PJ_EINVAL);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000240
241 /* Copy server URL. */
242 pj_strdup_with_null(regc->pool, &regc->str_srv_url, srv_url);
243
244 /* Set server URL. */
245 tmp = regc->str_srv_url;
246 regc->srv_url = pjsip_parse_uri( regc->pool, tmp.ptr, tmp.slen, 0);
247 if (regc->srv_url == NULL) {
Benny Prijonoccf95622006-02-07 18:48:01 +0000248 return PJSIP_EINVALIDURI;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000249 }
250
251 /* Set "From" header. */
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000252 pj_strdup_with_null(regc->pool, &regc->from_uri, from_url);
253 tmp = regc->from_uri;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000254 regc->from_hdr = pjsip_from_hdr_create(regc->pool);
255 regc->from_hdr->uri = pjsip_parse_uri(regc->pool, tmp.ptr, tmp.slen,
256 PJSIP_PARSE_URI_AS_NAMEADDR);
257 if (!regc->from_hdr->uri) {
Benny Prijonoccf95622006-02-07 18:48:01 +0000258 PJ_LOG(4,(THIS_FILE, "regc: invalid source URI %.*s",
259 from_url->slen, from_url->ptr));
260 return PJSIP_EINVALIDURI;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000261 }
262
263 /* Set "To" header. */
264 pj_strdup_with_null(regc->pool, &tmp, to_url);
265 regc->to_hdr = pjsip_to_hdr_create(regc->pool);
266 regc->to_hdr->uri = pjsip_parse_uri(regc->pool, tmp.ptr, tmp.slen,
267 PJSIP_PARSE_URI_AS_NAMEADDR);
268 if (!regc->to_hdr->uri) {
269 PJ_LOG(4,(THIS_FILE, "regc: invalid target URI %.*s", to_url->slen, to_url->ptr));
Benny Prijonoccf95622006-02-07 18:48:01 +0000270 return PJSIP_EINVALIDURI;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000271 }
272
273
274 /* Set "Contact" header. */
Benny Prijonoccf95622006-02-07 18:48:01 +0000275 status = set_contact( regc, contact_cnt, contact);
276 if (status != PJ_SUCCESS)
277 return status;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000278
279 /* Set "Expires" header, if required. */
280 set_expires( regc, expires);
281
282 /* Set "Call-ID" header. */
283 regc->cid_hdr = pjsip_cid_hdr_create(regc->pool);
284 pj_create_unique_string(regc->pool, &regc->cid_hdr->id);
285
286 /* Set "CSeq" header. */
287 regc->cseq_hdr = pjsip_cseq_hdr_create(regc->pool);
Benny Prijono59ca70f2006-02-22 22:18:58 +0000288 regc->cseq_hdr->cseq = pj_rand() % 0xFFFF;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000289 pjsip_method_set( &regc->cseq_hdr->method, PJSIP_REGISTER_METHOD);
290
291 /* Create "Contact" header used in unregistration. */
292 regc->unreg_contact_hdr = pjsip_contact_hdr_create(regc->pool);
293 regc->unreg_contact_hdr->star = 1;
294
295 /* Create "Expires" header used in unregistration. */
Benny Prijonoccf95622006-02-07 18:48:01 +0000296 regc->unreg_expires_hdr = pjsip_expires_hdr_create( regc->pool, 0);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000297
298 /* Done. */
Benny Prijonoccf95622006-02-07 18:48:01 +0000299 return PJ_SUCCESS;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000300}
301
302PJ_DEF(pj_status_t) pjsip_regc_set_credentials( pjsip_regc *regc,
303 int count,
304 const pjsip_cred_info cred[] )
305{
Benny Prijonoccf95622006-02-07 18:48:01 +0000306 PJ_ASSERT_RETURN(regc && count && cred, PJ_EINVAL);
307 return pjsip_auth_clt_set_credentials(&regc->auth_sess, count, cred);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000308}
309
Benny Prijono48ab2b72007-11-08 09:24:30 +0000310PJ_DEF(pj_status_t) pjsip_regc_set_prefs( pjsip_regc *regc,
311 const pjsip_auth_clt_pref *pref)
312{
313 PJ_ASSERT_RETURN(regc && pref, PJ_EINVAL);
314 return pjsip_auth_clt_set_prefs(&regc->auth_sess, pref);
315}
316
Benny Prijono84126ab2006-02-09 09:30:09 +0000317PJ_DEF(pj_status_t) pjsip_regc_set_route_set( pjsip_regc *regc,
318 const pjsip_route_hdr *route_set)
319{
320 const pjsip_route_hdr *chdr;
321
322 PJ_ASSERT_RETURN(regc && route_set, PJ_EINVAL);
323
324 pj_list_init(&regc->route_set);
325
326 chdr = route_set->next;
327 while (chdr != route_set) {
328 pj_list_push_back(&regc->route_set, pjsip_hdr_clone(regc->pool, chdr));
329 chdr = chdr->next;
330 }
331
332 return PJ_SUCCESS;
333}
334
Benny Prijono720d0a82007-01-12 06:37:35 +0000335
336/*
337 * Bind client registration to a specific transport/listener.
338 */
339PJ_DEF(pj_status_t) pjsip_regc_set_transport( pjsip_regc *regc,
340 const pjsip_tpselector *sel)
341{
342 PJ_ASSERT_RETURN(regc && sel, PJ_EINVAL);
343
344 pjsip_tpselector_dec_ref(&regc->tp_sel);
345 pj_memcpy(&regc->tp_sel, sel, sizeof(*sel));
346 pjsip_tpselector_add_ref(&regc->tp_sel);
347
348 return PJ_SUCCESS;
349}
350
351
Benny Prijono8fc6de02006-11-11 21:25:55 +0000352PJ_DEF(pj_status_t) pjsip_regc_add_headers( pjsip_regc *regc,
353 const pjsip_hdr *hdr_list)
354{
355 const pjsip_hdr *hdr;
356
357 PJ_ASSERT_RETURN(regc && hdr_list, PJ_EINVAL);
358
359 //This is "add" operation, so don't remove headers.
360 //pj_list_init(&regc->hdr_list);
361
362 hdr = hdr_list->next;
363 while (hdr != hdr_list) {
364 pj_list_push_back(&regc->hdr_list, pjsip_hdr_clone(regc->pool, hdr));
365 hdr = hdr->next;
366 }
367
368 return PJ_SUCCESS;
369}
370
Benny Prijonoccf95622006-02-07 18:48:01 +0000371static pj_status_t create_request(pjsip_regc *regc,
372 pjsip_tx_data **p_tdata)
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000373{
Benny Prijonoccf95622006-02-07 18:48:01 +0000374 pj_status_t status;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000375 pjsip_tx_data *tdata;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000376
Benny Prijonoccf95622006-02-07 18:48:01 +0000377 PJ_ASSERT_RETURN(regc && p_tdata, PJ_EINVAL);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000378
Benny Prijonoccf95622006-02-07 18:48:01 +0000379 /* Create the request. */
380 status = pjsip_endpt_create_request_from_hdr( regc->endpt,
Benny Prijono1f61a8f2007-08-16 10:11:44 +0000381 pjsip_get_register_method(),
Benny Prijonoccf95622006-02-07 18:48:01 +0000382 regc->srv_url,
383 regc->from_hdr,
384 regc->to_hdr,
385 NULL,
386 regc->cid_hdr,
387 regc->cseq_hdr->cseq,
388 NULL,
389 &tdata);
390 if (status != PJ_SUCCESS)
391 return status;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000392
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000393 /* Add cached authorization headers. */
Benny Prijonoccf95622006-02-07 18:48:01 +0000394 pjsip_auth_clt_init_req( &regc->auth_sess, tdata );
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000395
Benny Prijono84126ab2006-02-09 09:30:09 +0000396 /* Add Route headers from route set, ideally after Via header */
397 if (!pj_list_empty(&regc->route_set)) {
398 pjsip_hdr *route_pos;
399 const pjsip_route_hdr *route;
400
Benny Prijonoa1e69682007-05-11 15:14:34 +0000401 route_pos = (pjsip_hdr*)
402 pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
Benny Prijono84126ab2006-02-09 09:30:09 +0000403 if (!route_pos)
404 route_pos = &tdata->msg->hdr;
405
406 route = regc->route_set.next;
407 while (route != &regc->route_set) {
Benny Prijonoa1e69682007-05-11 15:14:34 +0000408 pjsip_hdr *new_hdr = (pjsip_hdr*)
409 pjsip_hdr_shallow_clone(tdata->pool, route);
Benny Prijono84126ab2006-02-09 09:30:09 +0000410 pj_list_insert_after(route_pos, new_hdr);
411 route_pos = new_hdr;
412 route = route->next;
413 }
414 }
415
Benny Prijono8fc6de02006-11-11 21:25:55 +0000416 /* Add additional request headers */
417 if (!pj_list_empty(&regc->hdr_list)) {
418 const pjsip_hdr *hdr;
419
420 hdr = regc->hdr_list.next;
421 while (hdr != &regc->hdr_list) {
Benny Prijonoa1e69682007-05-11 15:14:34 +0000422 pjsip_hdr *new_hdr = (pjsip_hdr*)
423 pjsip_hdr_shallow_clone(tdata->pool, hdr);
Benny Prijono8fc6de02006-11-11 21:25:55 +0000424 pjsip_msg_add_hdr(tdata->msg, new_hdr);
425 hdr = hdr->next;
426 }
427 }
428
Benny Prijonoccf95622006-02-07 18:48:01 +0000429 /* Done. */
430 *p_tdata = tdata;
431 return PJ_SUCCESS;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000432}
433
434
Benny Prijonoccf95622006-02-07 18:48:01 +0000435PJ_DEF(pj_status_t) pjsip_regc_register(pjsip_regc *regc, pj_bool_t autoreg,
436 pjsip_tx_data **p_tdata)
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000437{
438 pjsip_msg *msg;
Benny Prijonoe56b5b12007-09-11 09:04:51 +0000439 pjsip_hdr *hdr;
Benny Prijonoccf95622006-02-07 18:48:01 +0000440 pj_status_t status;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000441 pjsip_tx_data *tdata;
442
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000443 PJ_ASSERT_RETURN(regc && p_tdata, PJ_EINVAL);
444
Benny Prijonoccf95622006-02-07 18:48:01 +0000445 status = create_request(regc, &tdata);
446 if (status != PJ_SUCCESS)
447 return status;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000448
449 msg = tdata->msg;
Benny Prijonoe56b5b12007-09-11 09:04:51 +0000450
451 /* Add Contact headers. */
452 hdr = regc->contact_hdr_list.next;
453 while (hdr != &regc->contact_hdr_list) {
454 pjsip_msg_add_hdr(msg, (pjsip_hdr*)
455 pjsip_hdr_shallow_clone(tdata->pool, hdr));
456 hdr = hdr->next;
457 }
458
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000459 if (regc->expires_hdr)
Benny Prijonoa1e69682007-05-11 15:14:34 +0000460 pjsip_msg_add_hdr(msg, (pjsip_hdr*)
461 pjsip_hdr_shallow_clone(tdata->pool,
Benny Prijono4093f7c2006-09-13 23:48:45 +0000462 regc->expires_hdr));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000463
464 if (regc->timer.id != 0) {
465 pjsip_endpt_cancel_timer(regc->endpt, &regc->timer);
466 regc->timer.id = 0;
467 }
468
469 regc->auto_reg = autoreg;
470
Benny Prijonoccf95622006-02-07 18:48:01 +0000471 /* Done */
472 *p_tdata = tdata;
473 return PJ_SUCCESS;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000474}
475
476
Benny Prijonoccf95622006-02-07 18:48:01 +0000477PJ_DEF(pj_status_t) pjsip_regc_unregister(pjsip_regc *regc,
478 pjsip_tx_data **p_tdata)
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000479{
480 pjsip_tx_data *tdata;
481 pjsip_msg *msg;
Benny Prijonoe56b5b12007-09-11 09:04:51 +0000482 pjsip_hdr *hdr;
Benny Prijonoccf95622006-02-07 18:48:01 +0000483 pj_status_t status;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000484
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000485 PJ_ASSERT_RETURN(regc && p_tdata, PJ_EINVAL);
486
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000487 if (regc->timer.id != 0) {
488 pjsip_endpt_cancel_timer(regc->endpt, &regc->timer);
489 regc->timer.id = 0;
490 }
491
Benny Prijonoccf95622006-02-07 18:48:01 +0000492 status = create_request(regc, &tdata);
493 if (status != PJ_SUCCESS)
494 return status;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000495
496 msg = tdata->msg;
Benny Prijonoe56b5b12007-09-11 09:04:51 +0000497
498 /* Add Contact headers. */
499 hdr = regc->contact_hdr_list.next;
500 while (hdr != &regc->contact_hdr_list) {
501 pjsip_msg_add_hdr(msg, (pjsip_hdr*)
502 pjsip_hdr_shallow_clone(tdata->pool, hdr));
503 hdr = hdr->next;
504 }
505
Benny Prijonodfc4c482006-12-02 07:25:29 +0000506 pjsip_msg_add_hdr( msg, (pjsip_hdr*)regc->unreg_expires_hdr);
507
508 *p_tdata = tdata;
509 return PJ_SUCCESS;
510}
511
512PJ_DEF(pj_status_t) pjsip_regc_unregister_all(pjsip_regc *regc,
513 pjsip_tx_data **p_tdata)
514{
515 pjsip_tx_data *tdata;
516 pjsip_msg *msg;
517 pj_status_t status;
518
519 PJ_ASSERT_RETURN(regc && p_tdata, PJ_EINVAL);
520
521 if (regc->timer.id != 0) {
522 pjsip_endpt_cancel_timer(regc->endpt, &regc->timer);
523 regc->timer.id = 0;
524 }
525
526 status = create_request(regc, &tdata);
527 if (status != PJ_SUCCESS)
528 return status;
529
530 msg = tdata->msg;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000531 pjsip_msg_add_hdr( msg, (pjsip_hdr*)regc->unreg_contact_hdr);
532 pjsip_msg_add_hdr( msg, (pjsip_hdr*)regc->unreg_expires_hdr);
533
Benny Prijonoccf95622006-02-07 18:48:01 +0000534 *p_tdata = tdata;
535 return PJ_SUCCESS;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000536}
537
538
539PJ_DEF(pj_status_t) pjsip_regc_update_contact( pjsip_regc *regc,
540 int contact_cnt,
541 const pj_str_t contact[] )
542{
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000543 PJ_ASSERT_RETURN(regc, PJ_EINVAL);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000544 return set_contact( regc, contact_cnt, contact );
545}
546
547
548PJ_DEF(pj_status_t) pjsip_regc_update_expires( pjsip_regc *regc,
549 pj_uint32_t expires )
550{
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000551 PJ_ASSERT_RETURN(regc, PJ_EINVAL);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000552 set_expires( regc, expires );
Benny Prijonoccf95622006-02-07 18:48:01 +0000553 return PJ_SUCCESS;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000554}
555
556
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000557static void call_callback(pjsip_regc *regc, pj_status_t status, int st_code,
558 const pj_str_t *reason,
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000559 pjsip_rx_data *rdata, pj_int32_t expiration,
560 int contact_cnt, pjsip_contact_hdr *contact[])
561{
562 struct pjsip_regc_cbparam cbparam;
563
564
Benny Prijonof2651802007-01-26 17:13:56 +0000565 if (!regc->cb)
566 return;
567
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000568 cbparam.regc = regc;
569 cbparam.token = regc->token;
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000570 cbparam.status = status;
571 cbparam.code = st_code;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000572 cbparam.reason = *reason;
573 cbparam.rdata = rdata;
574 cbparam.contact_cnt = contact_cnt;
575 cbparam.expiration = expiration;
576 if (contact_cnt) {
577 pj_memcpy( cbparam.contact, contact,
578 contact_cnt*sizeof(pjsip_contact_hdr*));
579 }
580
581 (*regc->cb)(&cbparam);
582}
583
584static void regc_refresh_timer_cb( pj_timer_heap_t *timer_heap,
585 struct pj_timer_entry *entry)
586{
Benny Prijonoa1e69682007-05-11 15:14:34 +0000587 pjsip_regc *regc = (pjsip_regc*) entry->user_data;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000588 pjsip_tx_data *tdata;
Benny Prijonoccf95622006-02-07 18:48:01 +0000589 pj_status_t status;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000590
Benny Prijonoccf95622006-02-07 18:48:01 +0000591 PJ_UNUSED_ARG(timer_heap);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000592
Benny Prijonof2651802007-01-26 17:13:56 +0000593 /* Temporarily increase busy flag to prevent regc from being deleted
594 * in pjsip_regc_send()
595 */
596 regc->busy++;
597
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000598 entry->id = 0;
Benny Prijonoccf95622006-02-07 18:48:01 +0000599 status = pjsip_regc_register(regc, 1, &tdata);
600 if (status == PJ_SUCCESS) {
Benny Prijono27042582006-08-08 14:04:21 +0000601 status = pjsip_regc_send(regc, tdata);
602 }
603
Benny Prijonof2651802007-01-26 17:13:56 +0000604 if (status != PJ_SUCCESS && regc->cb) {
Benny Prijonoccf95622006-02-07 18:48:01 +0000605 char errmsg[PJ_ERR_MSG_SIZE];
606 pj_str_t reason = pj_strerror(status, errmsg, sizeof(errmsg));
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000607 call_callback(regc, status, 400, &reason, NULL, -1, 0, NULL);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000608 }
Benny Prijonof2651802007-01-26 17:13:56 +0000609
610 regc->busy--;
611
612 /* Delete the record if user destroy regc during the callback. */
613 if (regc->_delete_flag && regc->busy==0) {
614 pjsip_regc_destroy(regc);
615 }
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000616}
617
618static void tsx_callback(void *token, pjsip_event *event)
619{
Benny Prijonoccf95622006-02-07 18:48:01 +0000620 pj_status_t status;
Benny Prijonoa1e69682007-05-11 15:14:34 +0000621 pjsip_regc *regc = (pjsip_regc*) token;
Benny Prijonoccf95622006-02-07 18:48:01 +0000622 pjsip_transaction *tsx = event->body.tsx_state.tsx;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000623
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000624 /* Decrement pending transaction counter. */
Benny Prijono25a86c72006-12-01 20:50:01 +0000625 pj_assert(regc->has_tsx);
626 regc->has_tsx = PJ_FALSE;
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000627
Benny Prijonobdc093f2007-10-04 09:48:25 +0000628 /* Add reference to the transport */
629 if (tsx->transport != regc->last_transport) {
630 if (regc->last_transport) {
631 pjsip_transport_dec_ref(regc->last_transport);
632 regc->last_transport = NULL;
633 }
634
635 if (tsx->transport) {
636 regc->last_transport = tsx->transport;
637 pjsip_transport_add_ref(regc->last_transport);
638 }
639 }
640
Benny Prijono58990232007-01-21 16:11:18 +0000641 /* Handle 401/407 challenge (even when _delete_flag is set) */
642 if (tsx->status_code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED ||
643 tsx->status_code == PJSIP_SC_UNAUTHORIZED)
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000644 {
Benny Prijonoccf95622006-02-07 18:48:01 +0000645 pjsip_rx_data *rdata = event->body.tsx_state.src.rdata;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000646 pjsip_tx_data *tdata;
647
Benny Prijonoccf95622006-02-07 18:48:01 +0000648 status = pjsip_auth_clt_reinit_req( &regc->auth_sess,
649 rdata,
650 tsx->last_tx,
651 &tdata);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000652
Benny Prijonoccf95622006-02-07 18:48:01 +0000653 if (status == PJ_SUCCESS) {
Benny Prijono3fe034a2007-06-01 12:51:07 +0000654 ++regc->busy;
Benny Prijono27042582006-08-08 14:04:21 +0000655 status = pjsip_regc_send(regc, tdata);
Benny Prijono3fe034a2007-06-01 12:51:07 +0000656 --regc->busy;
657 }
Benny Prijono27042582006-08-08 14:04:21 +0000658
659 if (status != PJ_SUCCESS) {
Benny Prijono58990232007-01-21 16:11:18 +0000660
661 /* Only call callback if application is still interested
662 * in it.
663 */
664 if (regc->_delete_flag == 0) {
665 /* Increment busy flag temporarily to prevent regc from
666 * being destroyed.
667 */
668 ++regc->busy;
669
670 call_callback(regc, status, tsx->status_code,
671 &rdata->msg_info.msg->line.status.reason,
672 rdata, -1, 0, NULL);
673
674 /* Decrement busy flag */
675 --regc->busy;
676 }
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000677 }
Benny Prijono27042582006-08-08 14:04:21 +0000678
Benny Prijono58990232007-01-21 16:11:18 +0000679 } else if (regc->_delete_flag) {
680
681 /* User has called pjsip_regc_destroy(), so don't call callback.
682 * This regc will be destroyed later in this function.
683 */
684
685 /* Nothing to do */
686 ;
Benny Prijono27042582006-08-08 14:04:21 +0000687
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000688 } else {
689 int contact_cnt = 0;
690 pjsip_contact_hdr *contact[PJSIP_REGC_MAX_CONTACT];
691 pjsip_rx_data *rdata;
Benny Prijonoe1c984f2007-11-04 02:05:13 +0000692 enum { NOEXP = 0x1FFFFFFF };
693 pj_int32_t expiration = NOEXP;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000694
695 if (tsx->status_code/100 == 2) {
696 int i;
697 pjsip_contact_hdr *hdr;
698 pjsip_msg *msg;
Benny Prijonoe1c984f2007-11-04 02:05:13 +0000699 pj_bool_t has_our_contact = PJ_FALSE;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000700 pjsip_expires_hdr *expires;
701
Benny Prijonoccf95622006-02-07 18:48:01 +0000702 rdata = event->body.tsx_state.src.rdata;
703 msg = rdata->msg_info.msg;
Benny Prijonoe1c984f2007-11-04 02:05:13 +0000704
705 /* Record all Contact headers in the response */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000706 hdr = (pjsip_contact_hdr*)
707 pjsip_msg_find_hdr( msg, PJSIP_H_CONTACT, NULL);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000708 while (hdr) {
709 contact[contact_cnt++] = hdr;
710 hdr = hdr->next;
711 if (hdr == (void*)&msg->hdr)
712 break;
Benny Prijonoa1e69682007-05-11 15:14:34 +0000713 hdr = (pjsip_contact_hdr*)
714 pjsip_msg_find_hdr(msg, PJSIP_H_CONTACT, hdr);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000715 }
716
Benny Prijonoe1c984f2007-11-04 02:05:13 +0000717 /* Set default expiration value to the value of Expires hdr */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000718 expires = (pjsip_expires_hdr*)
719 pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000720
721 if (expires)
722 expiration = expires->ivalue;
723
Benny Prijonoe1c984f2007-11-04 02:05:13 +0000724 /* Enumerate all Contact headers found in the response and
725 * find the Contact(s) that we register.
726 */
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000727 for (i=0; i<contact_cnt; ++i) {
Benny Prijonoe1c984f2007-11-04 02:05:13 +0000728 pjsip_contact_hdr *our_contact;
729
730 our_contact = (pjsip_contact_hdr*)
731 regc->contact_hdr_list.next;
732
733 while ((void*)our_contact != (void*)&regc->contact_hdr_list) {
734
Benny Prijono522e7de2007-10-24 08:32:00 +0000735 const pjsip_uri *uri1, *uri2;
Benny Prijonoe56b5b12007-09-11 09:04:51 +0000736
Benny Prijonoe1c984f2007-11-04 02:05:13 +0000737 /* Compare URIs.
738 * Exclude the display name when comparing the URI since
739 * server may not return it.
Benny Prijonoe56b5b12007-09-11 09:04:51 +0000740 */
Benny Prijono522e7de2007-10-24 08:32:00 +0000741
Benny Prijonof0f8fd12007-11-10 12:05:59 +0000742 uri1=(const pjsip_uri*)pjsip_uri_get_uri(contact[i]->uri);
743 uri2=(const pjsip_uri*)pjsip_uri_get_uri(our_contact->uri);
Benny Prijono522e7de2007-10-24 08:32:00 +0000744 if (pjsip_uri_cmp(PJSIP_URI_IN_CONTACT_HDR, uri1, uri2)==0)
Benny Prijonoe56b5b12007-09-11 09:04:51 +0000745 {
Benny Prijonoe1c984f2007-11-04 02:05:13 +0000746 has_our_contact = PJ_TRUE;
747
748 if (contact[i]->expires >= 0 &&
749 contact[i]->expires < expiration)
750 {
751 /* Get the lowest expiration time. */
752 expiration = contact[i]->expires;
753 }
Benny Prijonoe56b5b12007-09-11 09:04:51 +0000754 }
Benny Prijonoe1c984f2007-11-04 02:05:13 +0000755
756 our_contact = our_contact->next;
Benny Prijonoe56b5b12007-09-11 09:04:51 +0000757 }
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000758 }
759
Benny Prijonoe1c984f2007-11-04 02:05:13 +0000760 /* When the response doesn't contain our Contact header, that
761 * means we have been unregistered.
762 */
763 if (!has_our_contact)
764 expiration = 0;
765
766 /* Schedule next registration */
767 if (regc->auto_reg && expiration != 0 && expiration != NOEXP) {
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000768 pj_time_val delay = { 0, 0};
769
770 delay.sec = expiration - DELAY_BEFORE_REFRESH;
771 if (regc->expires != PJSIP_REGC_EXPIRATION_NOT_SPECIFIED &&
772 delay.sec > (pj_int32_t)regc->expires)
773 {
774 delay.sec = regc->expires;
775 }
776 if (delay.sec < DELAY_BEFORE_REFRESH)
777 delay.sec = DELAY_BEFORE_REFRESH;
778 regc->timer.cb = &regc_refresh_timer_cb;
779 regc->timer.id = REFRESH_TIMER;
780 regc->timer.user_data = regc;
781 pjsip_endpt_schedule_timer( regc->endpt, &regc->timer, &delay);
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000782 pj_gettimeofday(&regc->last_reg);
783 regc->next_reg = regc->last_reg;
784 regc->next_reg.sec += delay.sec;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000785 }
786
787 } else {
Benny Prijonoccf95622006-02-07 18:48:01 +0000788 rdata = (event->body.tsx_state.type==PJSIP_EVENT_RX_MSG) ?
789 event->body.tsx_state.src.rdata : NULL;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000790 }
791
Benny Prijono25a86c72006-12-01 20:50:01 +0000792 /* Increment busy flag temporarily to prevent regc from
Benny Prijono197cabf2006-10-16 20:05:27 +0000793 * being destroyed.
794 */
Benny Prijono25a86c72006-12-01 20:50:01 +0000795 ++regc->busy;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000796
797 /* Call callback. */
Benny Prijonoe1c984f2007-11-04 02:05:13 +0000798 if (expiration == NOEXP) expiration = -1;
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000799 call_callback(regc, PJ_SUCCESS, tsx->status_code,
Benny Prijonoccf95622006-02-07 18:48:01 +0000800 (rdata ? &rdata->msg_info.msg->line.status.reason
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000801 : pjsip_get_status_text(tsx->status_code)),
802 rdata, expiration,
803 contact_cnt, contact);
804
Benny Prijono25a86c72006-12-01 20:50:01 +0000805 /* Decrement busy flag */
806 --regc->busy;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000807 }
808
809 /* Delete the record if user destroy regc during the callback. */
Benny Prijono25a86c72006-12-01 20:50:01 +0000810 if (regc->_delete_flag && regc->busy==0) {
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000811 pjsip_regc_destroy(regc);
812 }
813}
814
Benny Prijonoccf95622006-02-07 18:48:01 +0000815PJ_DEF(pj_status_t) pjsip_regc_send(pjsip_regc *regc, pjsip_tx_data *tdata)
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000816{
Benny Prijonoccf95622006-02-07 18:48:01 +0000817 pj_status_t status;
Benny Prijono59ca70f2006-02-22 22:18:58 +0000818 pjsip_cseq_hdr *cseq_hdr;
819 pj_uint32_t cseq;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000820
821 /* Make sure we don't have pending transaction. */
Benny Prijono25a86c72006-12-01 20:50:01 +0000822 if (regc->has_tsx) {
Benny Prijono5b656872006-08-08 00:41:00 +0000823 PJ_LOG(4,(THIS_FILE, "Unable to send request, regc has another "
824 "transaction pending"));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000825 pjsip_tx_data_dec_ref( tdata );
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000826 return PJSIP_EBUSY;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000827 }
828
829 /* Invalidate message buffer. */
830 pjsip_tx_data_invalidate_msg(tdata);
831
832 /* Increment CSeq */
Benny Prijono59ca70f2006-02-22 22:18:58 +0000833 cseq = ++regc->cseq_hdr->cseq;
Benny Prijonoa1e69682007-05-11 15:14:34 +0000834 cseq_hdr = (pjsip_cseq_hdr*)
835 pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
Benny Prijono59ca70f2006-02-22 22:18:58 +0000836 cseq_hdr->cseq = cseq;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000837
Benny Prijonodc39fe82006-05-26 12:17:46 +0000838 /* Increment pending transaction first, since transaction callback
839 * may be called even before send_request() returns!
840 */
Benny Prijono25a86c72006-12-01 20:50:01 +0000841 regc->has_tsx = PJ_TRUE;
842 ++regc->busy;
Benny Prijono0f35f912007-02-05 18:59:31 +0000843 status = pjsip_endpt_send_request(regc->endpt, tdata, REGC_TSX_TIMEOUT,
844 regc, &tsx_callback);
Benny Prijono5b656872006-08-08 00:41:00 +0000845 if (status!=PJ_SUCCESS) {
Benny Prijono5b656872006-08-08 00:41:00 +0000846 PJ_LOG(4,(THIS_FILE, "Error sending request, status=%d", status));
847 }
Benny Prijono25a86c72006-12-01 20:50:01 +0000848 --regc->busy;
Benny Prijono197cabf2006-10-16 20:05:27 +0000849
850 /* Delete the record if user destroy regc during the callback. */
Benny Prijono25a86c72006-12-01 20:50:01 +0000851 if (regc->_delete_flag && regc->busy==0) {
Benny Prijono197cabf2006-10-16 20:05:27 +0000852 pjsip_regc_destroy(regc);
853 }
Benny Prijonoccf95622006-02-07 18:48:01 +0000854
855 return status;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000856}
857
858