blob: 461205e8437bea101258f99dfd3a953e06df9872 [file] [log] [blame]
Benny Prijonoeebe9af2006-06-13 22:57:13 +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 Prijonoeebe9af2006-06-13 22:57:13 +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 */
20#include <pjsua-lib/pjsua.h>
21#include <pjsua-lib/pjsua_internal.h>
22
23
24#define THIS_FILE "pjsua_acc.c"
25
26
27/*
28 * Get number of current accounts.
29 */
30PJ_DEF(unsigned) pjsua_acc_get_count(void)
31{
32 return pjsua_var.acc_cnt;
33}
34
35
36/*
37 * Check if the specified account ID is valid.
38 */
39PJ_DEF(pj_bool_t) pjsua_acc_is_valid(pjsua_acc_id acc_id)
40{
Benny Prijonoa1e69682007-05-11 15:14:34 +000041 return acc_id>=0 && acc_id<(int)PJ_ARRAY_SIZE(pjsua_var.acc) &&
Benny Prijonoeebe9af2006-06-13 22:57:13 +000042 pjsua_var.acc[acc_id].valid;
43}
44
45
46/*
Benny Prijono21b9ad92006-08-15 13:11:22 +000047 * Set default account
48 */
49PJ_DEF(pj_status_t) pjsua_acc_set_default(pjsua_acc_id acc_id)
50{
51 pjsua_var.default_acc = acc_id;
52 return PJ_SUCCESS;
53}
54
55
56/*
57 * Get default account.
58 */
59PJ_DEF(pjsua_acc_id) pjsua_acc_get_default(void)
60{
61 return pjsua_var.default_acc;
62}
63
64
65/*
Benny Prijonoeebe9af2006-06-13 22:57:13 +000066 * Copy account configuration.
67 */
Benny Prijonobddef2c2007-10-31 13:28:08 +000068PJ_DEF(void) pjsua_acc_config_dup( pj_pool_t *pool,
69 pjsua_acc_config *dst,
70 const pjsua_acc_config *src)
Benny Prijonoeebe9af2006-06-13 22:57:13 +000071{
72 unsigned i;
73
74 pj_memcpy(dst, src, sizeof(pjsua_acc_config));
75
76 pj_strdup_with_null(pool, &dst->id, &src->id);
77 pj_strdup_with_null(pool, &dst->reg_uri, &src->reg_uri);
Benny Prijonob4a17c92006-07-10 14:40:21 +000078 pj_strdup_with_null(pool, &dst->force_contact, &src->force_contact);
Benny Prijonofe04fb52007-08-24 08:28:52 +000079 pj_strdup_with_null(pool, &dst->pidf_tuple_id, &src->pidf_tuple_id);
Benny Prijonoeebe9af2006-06-13 22:57:13 +000080
81 dst->proxy_cnt = src->proxy_cnt;
82 for (i=0; i<src->proxy_cnt; ++i)
83 pj_strdup_with_null(pool, &dst->proxy[i], &src->proxy[i]);
84
85 dst->reg_timeout = src->reg_timeout;
86 dst->cred_count = src->cred_count;
87
88 for (i=0; i<src->cred_count; ++i) {
89 pjsip_cred_dup(pool, &dst->cred_info[i], &src->cred_info[i]);
90 }
Benny Prijonobddef2c2007-10-31 13:28:08 +000091
92 dst->ka_interval = src->ka_interval;
93 pj_strdup(pool, &dst->ka_data, &src->ka_data);
Benny Prijonoeebe9af2006-06-13 22:57:13 +000094}
95
96
97/*
Benny Prijonoeebe9af2006-06-13 22:57:13 +000098 * Initialize a new account (after configuration is set).
99 */
100static pj_status_t initialize_acc(unsigned acc_id)
101{
102 pjsua_acc_config *acc_cfg = &pjsua_var.acc[acc_id].cfg;
103 pjsua_acc *acc = &pjsua_var.acc[acc_id];
Benny Prijonoc570f2d2006-07-18 00:33:02 +0000104 pjsip_name_addr *name_addr;
Benny Prijonob4a17c92006-07-10 14:40:21 +0000105 pjsip_sip_uri *sip_uri, *sip_reg_uri;
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000106 pj_status_t status;
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000107 unsigned i;
108
109 /* Need to parse local_uri to get the elements: */
110
Benny Prijonoc570f2d2006-07-18 00:33:02 +0000111 name_addr = (pjsip_name_addr*)
Benny Prijonoc91ed8d2008-07-13 12:24:55 +0000112 pjsip_parse_uri(acc->pool, acc_cfg->id.ptr,
Benny Prijonoc570f2d2006-07-18 00:33:02 +0000113 acc_cfg->id.slen,
114 PJSIP_PARSE_URI_AS_NAMEADDR);
115 if (name_addr == NULL) {
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000116 pjsua_perror(THIS_FILE, "Invalid local URI",
117 PJSIP_EINVALIDURI);
118 return PJSIP_EINVALIDURI;
119 }
120
121 /* Local URI MUST be a SIP or SIPS: */
122
Benny Prijonoc570f2d2006-07-18 00:33:02 +0000123 if (!PJSIP_URI_SCHEME_IS_SIP(name_addr) &&
124 !PJSIP_URI_SCHEME_IS_SIPS(name_addr))
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000125 {
126 pjsua_perror(THIS_FILE, "Invalid local URI",
127 PJSIP_EINVALIDSCHEME);
128 return PJSIP_EINVALIDSCHEME;
129 }
130
131
132 /* Get the SIP URI object: */
Benny Prijonoc570f2d2006-07-18 00:33:02 +0000133 sip_uri = (pjsip_sip_uri*) pjsip_uri_get_uri(name_addr);
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000134
Benny Prijonob4a17c92006-07-10 14:40:21 +0000135
136 /* Parse registrar URI, if any */
137 if (acc_cfg->reg_uri.slen) {
138 pjsip_uri *reg_uri;
139
Benny Prijonoc91ed8d2008-07-13 12:24:55 +0000140 reg_uri = pjsip_parse_uri(acc->pool, acc_cfg->reg_uri.ptr,
Benny Prijonob4a17c92006-07-10 14:40:21 +0000141 acc_cfg->reg_uri.slen, 0);
142 if (reg_uri == NULL) {
143 pjsua_perror(THIS_FILE, "Invalid registrar URI",
144 PJSIP_EINVALIDURI);
145 return PJSIP_EINVALIDURI;
146 }
147
148 /* Registrar URI MUST be a SIP or SIPS: */
149 if (!PJSIP_URI_SCHEME_IS_SIP(reg_uri) &&
150 !PJSIP_URI_SCHEME_IS_SIPS(reg_uri))
151 {
152 pjsua_perror(THIS_FILE, "Invalid registar URI",
153 PJSIP_EINVALIDSCHEME);
154 return PJSIP_EINVALIDSCHEME;
155 }
156
157 sip_reg_uri = (pjsip_sip_uri*) pjsip_uri_get_uri(reg_uri);
158
159 } else {
160 sip_reg_uri = NULL;
161 }
162
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000163 /* Save the user and domain part. These will be used when finding an
164 * account for incoming requests.
165 */
Benny Prijonoc570f2d2006-07-18 00:33:02 +0000166 acc->display = name_addr->display;
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000167 acc->user_part = sip_uri->user;
Benny Prijonob4a17c92006-07-10 14:40:21 +0000168 acc->srv_domain = sip_uri->host;
169 acc->srv_port = 0;
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000170
Benny Prijonob4a17c92006-07-10 14:40:21 +0000171 if (sip_reg_uri) {
172 acc->srv_port = sip_reg_uri->port;
173 }
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000174
175 /* Create Contact header if not present. */
Benny Prijonob4a17c92006-07-10 14:40:21 +0000176 //if (acc_cfg->contact.slen == 0) {
177 // acc_cfg->contact = acc_cfg->id;
178 //}
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000179
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000180 /* Build account route-set from outbound proxies and route set from
181 * account configuration.
182 */
183 pj_list_init(&acc->route_set);
184
185 for (i=0; i<pjsua_var.ua_cfg.outbound_proxy_cnt; ++i) {
186 pj_str_t hname = { "Route", 5};
187 pjsip_route_hdr *r;
188 pj_str_t tmp;
189
Benny Prijonoc91ed8d2008-07-13 12:24:55 +0000190 pj_strdup_with_null(acc->pool, &tmp,
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000191 &pjsua_var.ua_cfg.outbound_proxy[i]);
Benny Prijonoa1e69682007-05-11 15:14:34 +0000192 r = (pjsip_route_hdr*)
Benny Prijonoc91ed8d2008-07-13 12:24:55 +0000193 pjsip_parse_hdr(acc->pool, &hname, tmp.ptr, tmp.slen, NULL);
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000194 if (r == NULL) {
195 pjsua_perror(THIS_FILE, "Invalid outbound proxy URI",
196 PJSIP_EINVALIDURI);
197 return PJSIP_EINVALIDURI;
198 }
199 pj_list_push_back(&acc->route_set, r);
200 }
201
202 for (i=0; i<acc_cfg->proxy_cnt; ++i) {
203 pj_str_t hname = { "Route", 5};
204 pjsip_route_hdr *r;
205 pj_str_t tmp;
206
Benny Prijonoc91ed8d2008-07-13 12:24:55 +0000207 pj_strdup_with_null(acc->pool, &tmp, &acc_cfg->proxy[i]);
Benny Prijonoa1e69682007-05-11 15:14:34 +0000208 r = (pjsip_route_hdr*)
Benny Prijonoc91ed8d2008-07-13 12:24:55 +0000209 pjsip_parse_hdr(acc->pool, &hname, tmp.ptr, tmp.slen, NULL);
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000210 if (r == NULL) {
211 pjsua_perror(THIS_FILE, "Invalid URI in account route set",
212 PJ_EINVAL);
213 return PJ_EINVAL;
214 }
215 pj_list_push_back(&acc->route_set, r);
216 }
217
218
219 /* Concatenate credentials from account config and global config */
220 acc->cred_cnt = 0;
221 for (i=0; i<acc_cfg->cred_count; ++i) {
222 acc->cred[acc->cred_cnt++] = acc_cfg->cred_info[i];
223 }
224 for (i=0; i<pjsua_var.ua_cfg.cred_count &&
225 acc->cred_cnt < PJ_ARRAY_SIZE(acc->cred); ++i)
226 {
227 acc->cred[acc->cred_cnt++] = pjsua_var.ua_cfg.cred_info[i];
228 }
229
Benny Prijono3a5e1ab2006-08-15 20:26:34 +0000230 status = pjsua_pres_init_acc(acc_id);
231 if (status != PJ_SUCCESS)
232 return status;
233
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000234 /* Mark account as valid */
235 pjsua_var.acc[acc_id].valid = PJ_TRUE;
236
Benny Prijono093d3022006-09-24 00:07:11 +0000237 /* Insert account ID into account ID array, sorted by priority */
238 for (i=0; i<pjsua_var.acc_cnt; ++i) {
239 if ( pjsua_var.acc[pjsua_var.acc_ids[i]].cfg.priority <
240 pjsua_var.acc[acc_id].cfg.priority)
241 {
242 break;
243 }
244 }
245 pj_array_insert(pjsua_var.acc_ids, sizeof(pjsua_var.acc_ids[0]),
246 pjsua_var.acc_cnt, i, &acc_id);
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000247
248 return PJ_SUCCESS;
249}
250
251
252/*
253 * Add a new account to pjsua.
254 */
255PJ_DEF(pj_status_t) pjsua_acc_add( const pjsua_acc_config *cfg,
256 pj_bool_t is_default,
257 pjsua_acc_id *p_acc_id)
258{
Benny Prijonoc91ed8d2008-07-13 12:24:55 +0000259 pjsua_acc *acc;
Benny Prijono91d06b62008-09-20 12:16:56 +0000260 unsigned i, id;
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000261 pj_status_t status;
262
263 PJ_ASSERT_RETURN(pjsua_var.acc_cnt < PJ_ARRAY_SIZE(pjsua_var.acc),
264 PJ_ETOOMANY);
265
266 /* Must have a transport */
Benny Prijonoe93e2872006-06-28 16:46:49 +0000267 PJ_ASSERT_RETURN(pjsua_var.tpdata[0].data.ptr != NULL, PJ_EINVALIDOP);
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000268
269 PJSUA_LOCK();
270
271 /* Find empty account id. */
272 for (id=0; id < PJ_ARRAY_SIZE(pjsua_var.acc); ++id) {
273 if (pjsua_var.acc[id].valid == PJ_FALSE)
274 break;
275 }
276
277 /* Expect to find a slot */
278 PJ_ASSERT_ON_FAIL( id < PJ_ARRAY_SIZE(pjsua_var.acc),
279 {PJSUA_UNLOCK(); return PJ_EBUG;});
280
Benny Prijonoc91ed8d2008-07-13 12:24:55 +0000281 acc = &pjsua_var.acc[id];
282
283 /* Create pool for this account. */
284 if (acc->pool)
285 pj_pool_reset(acc->pool);
286 else
287 acc->pool = pjsua_pool_create("acc%p", 512, 256);
288
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000289 /* Copy config */
Benny Prijonoc91ed8d2008-07-13 12:24:55 +0000290 pjsua_acc_config_dup(acc->pool, &pjsua_var.acc[id].cfg, cfg);
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000291
292 /* Normalize registration timeout */
293 if (pjsua_var.acc[id].cfg.reg_uri.slen &&
294 pjsua_var.acc[id].cfg.reg_timeout == 0)
295 {
296 pjsua_var.acc[id].cfg.reg_timeout = PJSUA_REG_INTERVAL;
297 }
298
Benny Prijono91d06b62008-09-20 12:16:56 +0000299 /* Check the route URI's and force loose route if required */
300 for (i=0; i<acc->cfg.proxy_cnt; ++i) {
301 status = normalize_route_uri(acc->pool, &acc->cfg.proxy[i]);
302 if (status != PJ_SUCCESS)
303 return status;
304 }
305
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000306 status = initialize_acc(id);
307 if (status != PJ_SUCCESS) {
308 pjsua_perror(THIS_FILE, "Error adding account", status);
Benny Prijonoc91ed8d2008-07-13 12:24:55 +0000309 pj_pool_release(acc->pool);
310 acc->pool = NULL;
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000311 PJSUA_UNLOCK();
312 return status;
313 }
314
315 if (is_default)
316 pjsua_var.default_acc = id;
317
318 if (p_acc_id)
319 *p_acc_id = id;
320
321 pjsua_var.acc_cnt++;
322
323 PJSUA_UNLOCK();
324
325 PJ_LOG(4,(THIS_FILE, "Account %.*s added with id %d",
326 (int)cfg->id.slen, cfg->id.ptr, id));
327
328 /* If accounts has registration enabled, start registration */
329 if (pjsua_var.acc[id].cfg.reg_uri.slen)
330 pjsua_acc_set_registration(id, PJ_TRUE);
331
332
333 return PJ_SUCCESS;
334}
335
336
337/*
338 * Add local account
339 */
340PJ_DEF(pj_status_t) pjsua_acc_add_local( pjsua_transport_id tid,
341 pj_bool_t is_default,
342 pjsua_acc_id *p_acc_id)
343{
344 pjsua_acc_config cfg;
Benny Prijono62c5c5b2007-01-13 23:22:40 +0000345 pjsua_transport_data *t = &pjsua_var.tpdata[tid];
Benny Prijonod0bd4982007-12-02 15:40:52 +0000346 const char *beginquote, *endquote;
347 char transport_param[32];
Benny Prijonoe85bc412006-07-29 20:29:24 +0000348 char uri[PJSIP_MAX_URL_SIZE];
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000349
Benny Prijonoe93e2872006-06-28 16:46:49 +0000350 /* ID must be valid */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000351 PJ_ASSERT_RETURN(tid>=0 && tid<(int)PJ_ARRAY_SIZE(pjsua_var.tpdata),
352 PJ_EINVAL);
Benny Prijonoe93e2872006-06-28 16:46:49 +0000353
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000354 /* Transport must be valid */
Benny Prijonoe93e2872006-06-28 16:46:49 +0000355 PJ_ASSERT_RETURN(t->data.ptr != NULL, PJ_EINVAL);
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000356
357 pjsua_acc_config_default(&cfg);
358
Benny Prijono093d3022006-09-24 00:07:11 +0000359 /* Lower the priority of local account */
360 --cfg.priority;
361
Benny Prijonod0bd4982007-12-02 15:40:52 +0000362 /* Enclose IPv6 address in square brackets */
363 if (t->type & PJSIP_TRANSPORT_IPV6) {
364 beginquote = "[";
365 endquote = "]";
366 } else {
367 beginquote = endquote = "";
368 }
369
370 /* Don't add transport parameter if it's UDP */
Benny Prijono4c82c1e2008-10-16 08:14:51 +0000371 if (t->type!=PJSIP_TRANSPORT_UDP && t->type!=PJSIP_TRANSPORT_UDP6) {
Benny Prijonod0bd4982007-12-02 15:40:52 +0000372 pj_ansi_snprintf(transport_param, sizeof(transport_param),
373 ";transport=%s",
374 pjsip_transport_get_type_name(t->type));
375 } else {
376 transport_param[0] = '\0';
377 }
378
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000379 /* Build URI for the account */
Benny Prijonoe85bc412006-07-29 20:29:24 +0000380 pj_ansi_snprintf(uri, PJSIP_MAX_URL_SIZE,
Benny Prijonod0bd4982007-12-02 15:40:52 +0000381 "<sip:%s%.*s%s:%d%s>",
382 beginquote,
Benny Prijonoe85bc412006-07-29 20:29:24 +0000383 (int)t->local_name.host.slen,
384 t->local_name.host.ptr,
Benny Prijonod0bd4982007-12-02 15:40:52 +0000385 endquote,
Benny Prijonoe85bc412006-07-29 20:29:24 +0000386 t->local_name.port,
Benny Prijonod0bd4982007-12-02 15:40:52 +0000387 transport_param);
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000388
389 cfg.id = pj_str(uri);
390
391 return pjsua_acc_add(&cfg, is_default, p_acc_id);
392}
393
394
395/*
Benny Prijono705e7842008-07-21 18:12:51 +0000396 * Set arbitrary data to be associated with the account.
397 */
398PJ_DEF(pj_status_t) pjsua_acc_set_user_data(pjsua_acc_id acc_id,
399 void *user_data)
400{
401 PJ_ASSERT_RETURN(acc_id>=0 && acc_id<(int)PJ_ARRAY_SIZE(pjsua_var.acc),
402 PJ_EINVAL);
403 PJ_ASSERT_RETURN(pjsua_var.acc[acc_id].valid, PJ_EINVALIDOP);
404
405 PJSUA_LOCK();
406
407 pjsua_var.acc[acc_id].cfg.user_data = user_data;
408
409 PJSUA_UNLOCK();
410
411 return PJ_SUCCESS;
412}
413
414
415/*
416 * Retrieve arbitrary data associated with the account.
417 */
418PJ_DEF(void*) pjsua_acc_get_user_data(pjsua_acc_id acc_id)
419{
420 PJ_ASSERT_RETURN(acc_id>=0 && acc_id<(int)PJ_ARRAY_SIZE(pjsua_var.acc),
421 NULL);
422 PJ_ASSERT_RETURN(pjsua_var.acc[acc_id].valid, NULL);
423
424 return pjsua_var.acc[acc_id].cfg.user_data;
425}
426
427
428/*
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000429 * Delete account.
430 */
431PJ_DEF(pj_status_t) pjsua_acc_del(pjsua_acc_id acc_id)
432{
Benny Prijono093d3022006-09-24 00:07:11 +0000433 unsigned i;
434
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000435 PJ_ASSERT_RETURN(acc_id>=0 && acc_id<(int)PJ_ARRAY_SIZE(pjsua_var.acc),
436 PJ_EINVAL);
437 PJ_ASSERT_RETURN(pjsua_var.acc[acc_id].valid, PJ_EINVALIDOP);
438
439 PJSUA_LOCK();
440
441 /* Delete registration */
Benny Prijono922933b2007-01-21 16:23:56 +0000442 if (pjsua_var.acc[acc_id].regc != NULL) {
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000443 pjsua_acc_set_registration(acc_id, PJ_FALSE);
Benny Prijonoe68e99f2007-06-06 00:28:10 +0000444 if (pjsua_var.acc[acc_id].regc) {
445 pjsip_regc_destroy(pjsua_var.acc[acc_id].regc);
446 }
Benny Prijono922933b2007-01-21 16:23:56 +0000447 pjsua_var.acc[acc_id].regc = NULL;
448 }
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000449
450 /* Delete server presence subscription */
451 pjsua_pres_delete_acc(acc_id);
452
Benny Prijonoc91ed8d2008-07-13 12:24:55 +0000453 /* Release account pool */
454 if (pjsua_var.acc[acc_id].pool) {
455 pj_pool_release(pjsua_var.acc[acc_id].pool);
456 pjsua_var.acc[acc_id].pool = NULL;
457 }
458
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000459 /* Invalidate */
460 pjsua_var.acc[acc_id].valid = PJ_FALSE;
Benny Prijono978de6e2008-09-15 14:56:05 +0000461 pjsua_var.acc[acc_id].contact.slen = 0;
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000462
Benny Prijono093d3022006-09-24 00:07:11 +0000463 /* Remove from array */
464 for (i=0; i<pjsua_var.acc_cnt; ++i) {
465 if (pjsua_var.acc_ids[i] == acc_id)
466 break;
467 }
468 if (i != pjsua_var.acc_cnt) {
469 pj_array_erase(pjsua_var.acc_ids, sizeof(pjsua_var.acc_ids[0]),
470 pjsua_var.acc_cnt, i);
471 --pjsua_var.acc_cnt;
472 }
473
Benny Prijono62c5c5b2007-01-13 23:22:40 +0000474 /* Leave the calls intact, as I don't think calls need to
475 * access account once it's created
476 */
477
Benny Prijonofb2b3652007-06-28 07:15:03 +0000478 /* Update default account */
479 if (pjsua_var.default_acc == acc_id)
480 pjsua_var.default_acc = 0;
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000481
482 PJSUA_UNLOCK();
483
484 PJ_LOG(4,(THIS_FILE, "Account id %d deleted", acc_id));
485
486 return PJ_SUCCESS;
487}
488
489
490/*
491 * Modify account information.
492 */
493PJ_DEF(pj_status_t) pjsua_acc_modify( pjsua_acc_id acc_id,
494 const pjsua_acc_config *cfg)
495{
496 PJ_TODO(pjsua_acc_modify);
Benny Prijonoc570f2d2006-07-18 00:33:02 +0000497 PJ_UNUSED_ARG(acc_id);
498 PJ_UNUSED_ARG(cfg);
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000499 return PJ_EINVALIDOP;
500}
501
502
503/*
504 * Modify account's presence status to be advertised to remote/presence
505 * subscribers.
506 */
507PJ_DEF(pj_status_t) pjsua_acc_set_online_status( pjsua_acc_id acc_id,
508 pj_bool_t is_online)
509{
510 PJ_ASSERT_RETURN(acc_id>=0 && acc_id<(int)PJ_ARRAY_SIZE(pjsua_var.acc),
511 PJ_EINVAL);
512 PJ_ASSERT_RETURN(pjsua_var.acc[acc_id].valid, PJ_EINVALIDOP);
513
514 pjsua_var.acc[acc_id].online_status = is_online;
Benny Prijono4461c7d2007-08-25 13:36:15 +0000515 pj_bzero(&pjsua_var.acc[acc_id].rpid, sizeof(pjrpid_element));
516 pjsua_pres_update_acc(acc_id, PJ_FALSE);
517 return PJ_SUCCESS;
518}
519
520
521/*
522 * Set online status with extended information
523 */
524PJ_DEF(pj_status_t) pjsua_acc_set_online_status2( pjsua_acc_id acc_id,
525 pj_bool_t is_online,
526 const pjrpid_element *pr)
527{
528 PJ_ASSERT_RETURN(acc_id>=0 && acc_id<(int)PJ_ARRAY_SIZE(pjsua_var.acc),
529 PJ_EINVAL);
530 PJ_ASSERT_RETURN(pjsua_var.acc[acc_id].valid, PJ_EINVALIDOP);
531
Benny Prijonoc91ed8d2008-07-13 12:24:55 +0000532 PJSUA_LOCK();
Benny Prijono4461c7d2007-08-25 13:36:15 +0000533 pjsua_var.acc[acc_id].online_status = is_online;
Benny Prijonoc91ed8d2008-07-13 12:24:55 +0000534 pjrpid_element_dup(pjsua_var.acc[acc_id].pool, &pjsua_var.acc[acc_id].rpid, pr);
535 PJSUA_UNLOCK();
536
Benny Prijono4461c7d2007-08-25 13:36:15 +0000537 pjsua_pres_update_acc(acc_id, PJ_TRUE);
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000538 return PJ_SUCCESS;
539}
540
Benny Prijono7f630432008-09-24 16:52:41 +0000541/* Check if IP is private IP address */
542static pj_bool_t is_private_ip(const pj_str_t *addr)
543{
544 const pj_str_t private_net[] =
545 {
546 { "10.", 3 },
547 { "127.", 4 },
548 { "172.16.", 7 },
549 { "192.168.", 8 }
550 };
551 unsigned i;
552
553 for (i=0; i<PJ_ARRAY_SIZE(private_net); ++i) {
554 if (pj_strncmp(addr, &private_net[i], private_net[i].slen)==0)
555 return PJ_TRUE;
556 }
557
558 return PJ_FALSE;
559}
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000560
Benny Prijono15b02302007-09-27 14:07:07 +0000561/* Update NAT address from the REGISTER response */
562static pj_bool_t acc_check_nat_addr(pjsua_acc *acc,
563 struct pjsip_regc_cbparam *param)
564{
565 pjsip_transport *tp;
566 const pj_str_t *via_addr;
Benny Prijonoe8554ef2008-03-22 09:33:52 +0000567 pj_pool_t *pool;
Benny Prijono15b02302007-09-27 14:07:07 +0000568 int rport;
Benny Prijonoe8554ef2008-03-22 09:33:52 +0000569 pjsip_sip_uri *uri;
Benny Prijono15b02302007-09-27 14:07:07 +0000570 pjsip_via_hdr *via;
Benny Prijono7f630432008-09-24 16:52:41 +0000571 pj_str_t srv_ip;
Benny Prijono15b02302007-09-27 14:07:07 +0000572
573 tp = param->rdata->tp_info.transport;
574
575 /* Only update if account is configured to auto-update */
Benny Prijonoe8554ef2008-03-22 09:33:52 +0000576 if (acc->cfg.allow_contact_rewrite == PJ_FALSE)
Benny Prijono15b02302007-09-27 14:07:07 +0000577 return PJ_FALSE;
578
Benny Prijonoe8554ef2008-03-22 09:33:52 +0000579#if 0
580 // Always update
581 // See http://lists.pjsip.org/pipermail/pjsip_lists.pjsip.org/2008-March/002178.html
Benny Prijono15b02302007-09-27 14:07:07 +0000582
Benny Prijonoe8554ef2008-03-22 09:33:52 +0000583 /* For UDP, only update if STUN is enabled (for now).
584 * For TCP/TLS, always check.
585 */
586 if ((tp->key.type == PJSIP_TRANSPORT_UDP &&
587 (pjsua_var.ua_cfg.stun_domain.slen != 0 ||
588 (pjsua_var.ua_cfg.stun_host.slen != 0)) ||
589 (tp->key.type == PJSIP_TRANSPORT_TCP) ||
590 (tp->key.type == PJSIP_TRANSPORT_TLS))
Benny Prijono15b02302007-09-27 14:07:07 +0000591 {
Benny Prijonoe8554ef2008-03-22 09:33:52 +0000592 /* Yes we will check */
593 } else {
Benny Prijono15b02302007-09-27 14:07:07 +0000594 return PJ_FALSE;
595 }
Benny Prijonoe8554ef2008-03-22 09:33:52 +0000596#endif
Benny Prijono15b02302007-09-27 14:07:07 +0000597
598 /* Get the received and rport info */
599 via = param->rdata->msg_info.via;
600 if (via->rport_param < 1) {
601 /* Remote doesn't support rport */
602 rport = via->sent_by.port;
Benny Prijono24a21852008-04-14 04:04:30 +0000603 if (rport==0) {
604 pjsip_transport_type_e tp_type;
605 tp_type = (pjsip_transport_type_e) tp->key.type;
606 rport = pjsip_transport_get_default_port_for_type(tp_type);
607 }
Benny Prijono15b02302007-09-27 14:07:07 +0000608 } else
609 rport = via->rport_param;
610
611 if (via->recvd_param.slen != 0)
612 via_addr = &via->recvd_param;
613 else
614 via_addr = &via->sent_by.host;
615
Benny Prijonoe8554ef2008-03-22 09:33:52 +0000616 /* Compare received and rport with the URI in our registration */
617 pool = pjsua_pool_create("tmp", 512, 512);
618 uri = (pjsip_sip_uri*)
619 pjsip_parse_uri(pool, acc->contact.ptr, acc->contact.slen, 0);
620 pj_assert(uri != NULL);
Benny Prijono24a21852008-04-14 04:04:30 +0000621 uri = (pjsip_sip_uri*) pjsip_uri_get_uri(uri);
Benny Prijonoe8554ef2008-03-22 09:33:52 +0000622
Benny Prijono24a21852008-04-14 04:04:30 +0000623 if (uri->port == 0) {
624 pjsip_transport_type_e tp_type;
625 tp_type = (pjsip_transport_type_e) tp->key.type;
626 uri->port = pjsip_transport_get_default_port_for_type(tp_type);
627 }
Benny Prijonoe8554ef2008-03-22 09:33:52 +0000628
629 if (uri->port == rport &&
630 pj_stricmp(&uri->host, via_addr)==0)
Benny Prijono15b02302007-09-27 14:07:07 +0000631 {
632 /* Address doesn't change */
Benny Prijonoe8554ef2008-03-22 09:33:52 +0000633 pj_pool_release(pool);
Benny Prijono15b02302007-09-27 14:07:07 +0000634 return PJ_FALSE;
635 }
636
Benny Prijono7f630432008-09-24 16:52:41 +0000637 /* Get server IP */
638 srv_ip = pj_str(param->rdata->pkt_info.src_name);
639
Benny Prijono15b02302007-09-27 14:07:07 +0000640 /* At this point we've detected that the address as seen by registrar.
641 * has changed.
642 */
Benny Prijono7f630432008-09-24 16:52:41 +0000643
644 /* Do not switch if both Contact and server's IP address are
645 * public but response contains private IP. A NAT in the middle
646 * might have messed up with the SIP packets.
Benny Prijono247921b2008-09-26 22:06:11 +0000647 *
648 * This exception can be disabled by setting allow_contact_rewrite
649 * to 2. In this case, the switch will always be done whenever there
650 * is difference in the IP address in the response.
Benny Prijono7f630432008-09-24 16:52:41 +0000651 */
Benny Prijono247921b2008-09-26 22:06:11 +0000652 if (acc->cfg.allow_contact_rewrite != 2 && !is_private_ip(&uri->host) &&
653 !is_private_ip(&srv_ip) && is_private_ip(via_addr))
Benny Prijono7f630432008-09-24 16:52:41 +0000654 {
655 /* Don't switch */
656 pj_pool_release(pool);
657 return PJ_FALSE;
658 }
659
Benny Prijono15b02302007-09-27 14:07:07 +0000660 PJ_LOG(3,(THIS_FILE, "IP address change detected for account %d "
661 "(%.*s:%d --> %.*s:%d). Updating registration..",
662 acc->index,
Benny Prijonoe8554ef2008-03-22 09:33:52 +0000663 (int)uri->host.slen,
664 uri->host.ptr,
665 uri->port,
Benny Prijono15b02302007-09-27 14:07:07 +0000666 (int)via_addr->slen,
667 via_addr->ptr,
668 rport));
669
670 /* Unregister current contact */
671 pjsua_acc_set_registration(acc->index, PJ_FALSE);
672 if (acc->regc != NULL) {
673 pjsip_regc_destroy(acc->regc);
674 acc->regc = NULL;
Benny Prijonoddaaf6a2008-04-15 10:37:19 +0000675 acc->contact.slen = 0;
Benny Prijono15b02302007-09-27 14:07:07 +0000676 }
677
Benny Prijonoe8554ef2008-03-22 09:33:52 +0000678 /* Update account's Contact header */
679 {
680 char *tmp;
Benny Prijono8972bf02009-04-05 18:30:45 +0000681 const char *beginquote, *endquote;
Benny Prijonoe8554ef2008-03-22 09:33:52 +0000682 int len;
683
Benny Prijono8972bf02009-04-05 18:30:45 +0000684 /* Enclose IPv6 address in square brackets */
685 if (tp->key.type & PJSIP_TRANSPORT_IPV6) {
686 beginquote = "[";
687 endquote = "]";
688 } else {
689 beginquote = endquote = "";
690 }
691
Benny Prijono24a21852008-04-14 04:04:30 +0000692 tmp = (char*) pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
Benny Prijonoe8554ef2008-03-22 09:33:52 +0000693 len = pj_ansi_snprintf(tmp, PJSIP_MAX_URL_SIZE,
Benny Prijono8972bf02009-04-05 18:30:45 +0000694 "<sip:%.*s%s%s%.*s%s:%d;transport=%s%.*s>",
Benny Prijonoe8554ef2008-03-22 09:33:52 +0000695 (int)acc->user_part.slen,
696 acc->user_part.ptr,
Benny Prijono83088f32008-04-22 18:33:55 +0000697 (acc->user_part.slen? "@" : ""),
Benny Prijono8972bf02009-04-05 18:30:45 +0000698 beginquote,
Benny Prijonoe8554ef2008-03-22 09:33:52 +0000699 (int)via_addr->slen,
700 via_addr->ptr,
Benny Prijono8972bf02009-04-05 18:30:45 +0000701 endquote,
Benny Prijonoe8554ef2008-03-22 09:33:52 +0000702 rport,
Benny Prijono30fe4852008-12-10 16:54:16 +0000703 tp->type_name,
704 (int)acc->cfg.contact_params.slen,
705 acc->cfg.contact_params.ptr);
Benny Prijonoe8554ef2008-03-22 09:33:52 +0000706 if (len < 1) {
707 PJ_LOG(1,(THIS_FILE, "URI too long"));
708 pj_pool_release(pool);
709 return PJ_FALSE;
710 }
Benny Prijono3d9b4b62008-07-14 17:55:40 +0000711 pj_strdup2_with_null(acc->pool, &acc->contact, tmp);
Benny Prijonoe8554ef2008-03-22 09:33:52 +0000712 }
713
714 /* For UDP transport, if STUN is enabled then update the transport's
715 * published name as well.
716 */
717 if (tp->key.type==PJSIP_TRANSPORT_UDP &&
718 (pjsua_var.ua_cfg.stun_domain.slen != 0 ||
719 pjsua_var.ua_cfg.stun_host.slen != 0))
720 {
721 pj_strdup_with_null(tp->pool, &tp->local_name.host, via_addr);
722 tp->local_name.port = rport;
723 }
Benny Prijono15b02302007-09-27 14:07:07 +0000724
725 /* Perform new registration */
726 pjsua_acc_set_registration(acc->index, PJ_TRUE);
727
Benny Prijonoe8554ef2008-03-22 09:33:52 +0000728 pj_pool_release(pool);
729
Benny Prijono15b02302007-09-27 14:07:07 +0000730 return PJ_TRUE;
731}
732
Benny Prijonoa2a2d412007-10-18 05:54:02 +0000733/* Check and update Service-Route header */
734void update_service_route(pjsua_acc *acc, pjsip_rx_data *rdata)
735{
736 pjsip_generic_string_hdr *hsr = NULL;
737 pjsip_route_hdr *hr, *h;
738 const pj_str_t HNAME = { "Service-Route", 13 };
739 const pj_str_t HROUTE = { "Route", 5 };
740 pjsip_uri *uri[PJSUA_ACC_MAX_PROXIES];
Benny Prijonof020ab22007-10-18 15:28:33 +0000741 unsigned i, uri_cnt = 0, rcnt;
Benny Prijonoa2a2d412007-10-18 05:54:02 +0000742
743 /* Find and parse Service-Route headers */
744 for (;;) {
745 char saved;
746 int parsed_len;
747
748 /* Find Service-Route header */
749 hsr = (pjsip_generic_string_hdr*)
750 pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &HNAME, hsr);
751 if (!hsr)
752 break;
753
754 /* Parse as Route header since the syntax is similar. This may
755 * return more than one headers.
756 */
757 saved = hsr->hvalue.ptr[hsr->hvalue.slen];
758 hsr->hvalue.ptr[hsr->hvalue.slen] = '\0';
759 hr = (pjsip_route_hdr*)
760 pjsip_parse_hdr(rdata->tp_info.pool, &HROUTE, hsr->hvalue.ptr,
761 hsr->hvalue.slen, &parsed_len);
762 hsr->hvalue.ptr[hsr->hvalue.slen] = saved;
763
764 if (hr == NULL) {
765 /* Error */
766 PJ_LOG(1,(THIS_FILE, "Error parsing Service-Route header"));
767 return;
768 }
769
770 /* Save each URI in the result */
771 h = hr;
772 do {
773 if (!PJSIP_URI_SCHEME_IS_SIP(h->name_addr.uri) &&
774 !PJSIP_URI_SCHEME_IS_SIPS(h->name_addr.uri))
775 {
776 PJ_LOG(1,(THIS_FILE,"Error: non SIP URI in Service-Route: %.*s",
777 (int)hsr->hvalue.slen, hsr->hvalue.ptr));
778 return;
779 }
780
781 uri[uri_cnt++] = h->name_addr.uri;
782 h = h->next;
783 } while (h != hr && uri_cnt != PJ_ARRAY_SIZE(uri));
784
785 if (h != hr) {
786 PJ_LOG(1,(THIS_FILE, "Error: too many Service-Route headers"));
787 return;
788 }
789
790 /* Prepare to find next Service-Route header */
791 hsr = hsr->next;
792 if ((void*)hsr == (void*)&rdata->msg_info.msg->hdr)
793 break;
794 }
795
796 if (uri_cnt == 0)
797 return;
798
799 /*
800 * Update account's route set
801 */
802
803 /* First remove all routes which are not the outbound proxies */
Benny Prijonof020ab22007-10-18 15:28:33 +0000804 rcnt = pj_list_size(&acc->route_set);
Benny Prijono2568c742007-11-03 09:29:52 +0000805 if (rcnt != pjsua_var.ua_cfg.outbound_proxy_cnt + acc->cfg.proxy_cnt) {
806 for (i=pjsua_var.ua_cfg.outbound_proxy_cnt + acc->cfg.proxy_cnt,
807 hr=acc->route_set.prev;
Benny Prijonof020ab22007-10-18 15:28:33 +0000808 i<rcnt;
809 ++i)
810 {
811 pjsip_route_hdr *prev = hr->prev;
812 pj_list_erase(hr);
813 hr = prev;
814 }
815 }
Benny Prijonoa2a2d412007-10-18 05:54:02 +0000816
817 /* Then append the Service-Route URIs */
818 for (i=0; i<uri_cnt; ++i) {
Benny Prijonoc91ed8d2008-07-13 12:24:55 +0000819 hr = pjsip_route_hdr_create(acc->pool);
820 hr->name_addr.uri = (pjsip_uri*)pjsip_uri_clone(acc->pool, uri[i]);
Benny Prijonoa2a2d412007-10-18 05:54:02 +0000821 pj_list_push_back(&acc->route_set, hr);
822 }
823
824 /* Done */
825
826 PJ_LOG(4,(THIS_FILE, "Service-Route updated for acc %d with %d URI(s)",
827 acc->index, uri_cnt));
828}
829
Benny Prijonobddef2c2007-10-31 13:28:08 +0000830
831/* Keep alive timer callback */
832static void keep_alive_timer_cb(pj_timer_heap_t *th, pj_timer_entry *te)
833{
834 pjsua_acc *acc;
835 pjsip_tpselector tp_sel;
836 pj_time_val delay;
Benny Prijonodb4eb812007-12-09 05:30:47 +0000837 char addrtxt[PJ_INET6_ADDRSTRLEN];
Benny Prijonobddef2c2007-10-31 13:28:08 +0000838 pj_status_t status;
839
840 PJ_UNUSED_ARG(th);
841
842 PJSUA_LOCK();
843
844 te->id = PJ_FALSE;
845
846 acc = (pjsua_acc*) te->user_data;
847
848 /* Select the transport to send the packet */
849 pj_bzero(&tp_sel, sizeof(tp_sel));
850 tp_sel.type = PJSIP_TPSELECTOR_TRANSPORT;
851 tp_sel.u.transport = acc->ka_transport;
852
853 PJ_LOG(5,(THIS_FILE,
Benny Prijonodb4eb812007-12-09 05:30:47 +0000854 "Sending %d bytes keep-alive packet for acc %d to %s",
Benny Prijonobddef2c2007-10-31 13:28:08 +0000855 acc->cfg.ka_data.slen, acc->index,
Benny Prijonodb4eb812007-12-09 05:30:47 +0000856 pj_sockaddr_print(&acc->ka_target, addrtxt, sizeof(addrtxt),3)));
Benny Prijonobddef2c2007-10-31 13:28:08 +0000857
858 /* Send raw packet */
859 status = pjsip_tpmgr_send_raw(pjsip_endpt_get_tpmgr(pjsua_var.endpt),
860 PJSIP_TRANSPORT_UDP, &tp_sel,
861 NULL, acc->cfg.ka_data.ptr,
862 acc->cfg.ka_data.slen,
863 &acc->ka_target, acc->ka_target_len,
864 NULL, NULL);
865
866 if (status != PJ_SUCCESS && status != PJ_EPENDING) {
867 pjsua_perror(THIS_FILE, "Error sending keep-alive packet", status);
868 }
869
870 /* Reschedule next timer */
871 delay.sec = acc->cfg.ka_interval;
872 delay.msec = 0;
873 status = pjsip_endpt_schedule_timer(pjsua_var.endpt, te, &delay);
874 if (status == PJ_SUCCESS) {
875 te->id = PJ_TRUE;
876 } else {
877 pjsua_perror(THIS_FILE, "Error starting keep-alive timer", status);
878 }
879
880 PJSUA_UNLOCK();
881}
882
883
884/* Update keep-alive for the account */
885static void update_keep_alive(pjsua_acc *acc, pj_bool_t start,
886 struct pjsip_regc_cbparam *param)
887{
888 /* In all cases, stop keep-alive timer if it's running. */
889 if (acc->ka_timer.id) {
890 pjsip_endpt_cancel_timer(pjsua_var.endpt, &acc->ka_timer);
891 acc->ka_timer.id = PJ_FALSE;
892
893 pjsip_transport_dec_ref(acc->ka_transport);
894 acc->ka_transport = NULL;
895 }
896
897 if (start) {
898 pj_time_val delay;
899 pj_status_t status;
900
901 /* Only do keep-alive if:
Benny Prijonobddef2c2007-10-31 13:28:08 +0000902 * - ka_interval is not zero in the account, and
903 * - transport is UDP.
Benny Prijono7fff9f92008-04-04 10:50:21 +0000904 *
905 * Previously we only enabled keep-alive when STUN is enabled, since
906 * we thought that keep-alive is only needed in Internet situation.
907 * But it has been discovered that Windows Firewall on WinXP also
908 * needs to be kept-alive, otherwise incoming packets will be dropped.
909 * So because of this, now keep-alive is always enabled for UDP,
910 * regardless of whether STUN is enabled or not.
911 *
912 * Note that this applies only for UDP. For TCP/TLS, the keep-alive
913 * is done by the transport layer.
Benny Prijonobddef2c2007-10-31 13:28:08 +0000914 */
Benny Prijono7fff9f92008-04-04 10:50:21 +0000915 if (/*pjsua_var.stun_srv.ipv4.sin_family == 0 ||*/
Benny Prijonobddef2c2007-10-31 13:28:08 +0000916 acc->cfg.ka_interval == 0 ||
917 param->rdata->tp_info.transport->key.type != PJSIP_TRANSPORT_UDP)
918 {
919 /* Keep alive is not necessary */
920 return;
921 }
922
923 /* Save transport and destination address. */
924 acc->ka_transport = param->rdata->tp_info.transport;
925 pjsip_transport_add_ref(acc->ka_transport);
926 pj_memcpy(&acc->ka_target, &param->rdata->pkt_info.src_addr,
927 param->rdata->pkt_info.src_addr_len);
928 acc->ka_target_len = param->rdata->pkt_info.src_addr_len;
929
930 /* Setup and start the timer */
931 acc->ka_timer.cb = &keep_alive_timer_cb;
932 acc->ka_timer.user_data = (void*)acc;
933
934 delay.sec = acc->cfg.ka_interval;
935 delay.msec = 0;
936 status = pjsip_endpt_schedule_timer(pjsua_var.endpt, &acc->ka_timer,
937 &delay);
938 if (status == PJ_SUCCESS) {
939 acc->ka_timer.id = PJ_TRUE;
940 PJ_LOG(4,(THIS_FILE, "Keep-alive timer started for acc %d, "
941 "destination:%s:%d, interval:%ds",
942 acc->index,
943 param->rdata->pkt_info.src_name,
944 param->rdata->pkt_info.src_port,
945 acc->cfg.ka_interval));
946 } else {
947 acc->ka_timer.id = PJ_FALSE;
948 pjsip_transport_dec_ref(acc->ka_transport);
949 acc->ka_transport = NULL;
950 pjsua_perror(THIS_FILE, "Error starting keep-alive timer", status);
951 }
952 }
953}
954
955
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000956/*
957 * This callback is called by pjsip_regc when outgoing register
958 * request has completed.
959 */
960static void regc_cb(struct pjsip_regc_cbparam *param)
961{
962
Benny Prijonoa1e69682007-05-11 15:14:34 +0000963 pjsua_acc *acc = (pjsua_acc*) param->token;
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000964
Benny Prijono15b02302007-09-27 14:07:07 +0000965 if (param->regc != acc->regc)
966 return;
967
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000968 PJSUA_LOCK();
969
970 /*
971 * Print registration status.
972 */
973 if (param->status!=PJ_SUCCESS) {
974 pjsua_perror(THIS_FILE, "SIP registration error",
975 param->status);
976 pjsip_regc_destroy(acc->regc);
977 acc->regc = NULL;
Benny Prijonoddaaf6a2008-04-15 10:37:19 +0000978 acc->contact.slen = 0;
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000979
Benny Prijonobddef2c2007-10-31 13:28:08 +0000980 /* Stop keep-alive timer if any. */
981 update_keep_alive(acc, PJ_FALSE, NULL);
982
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000983 } else if (param->code < 0 || param->code >= 300) {
984 PJ_LOG(2, (THIS_FILE, "SIP registration failed, status=%d (%.*s)",
985 param->code,
986 (int)param->reason.slen, param->reason.ptr));
987 pjsip_regc_destroy(acc->regc);
988 acc->regc = NULL;
Benny Prijonoddaaf6a2008-04-15 10:37:19 +0000989 acc->contact.slen = 0;
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000990
Benny Prijonobddef2c2007-10-31 13:28:08 +0000991 /* Stop keep-alive timer if any. */
992 update_keep_alive(acc, PJ_FALSE, NULL);
993
Benny Prijonoeebe9af2006-06-13 22:57:13 +0000994 } else if (PJSIP_IS_STATUS_IN_CLASS(param->code, 200)) {
995
996 if (param->expiration < 1) {
997 pjsip_regc_destroy(acc->regc);
998 acc->regc = NULL;
Benny Prijonoddaaf6a2008-04-15 10:37:19 +0000999 acc->contact.slen = 0;
Benny Prijonobddef2c2007-10-31 13:28:08 +00001000
1001 /* Stop keep-alive timer if any. */
1002 update_keep_alive(acc, PJ_FALSE, NULL);
1003
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001004 PJ_LOG(3,(THIS_FILE, "%s: unregistration success",
1005 pjsua_var.acc[acc->index].cfg.id.ptr));
1006 } else {
Benny Prijono15b02302007-09-27 14:07:07 +00001007 /* Check NAT bound address */
1008 if (acc_check_nat_addr(acc, param)) {
1009 /* Update address, don't notify application yet */
1010 PJSUA_UNLOCK();
1011 return;
1012 }
1013
Benny Prijonoa2a2d412007-10-18 05:54:02 +00001014 /* Check and update Service-Route header */
1015 update_service_route(acc, param->rdata);
1016
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001017 PJ_LOG(3, (THIS_FILE,
1018 "%s: registration success, status=%d (%.*s), "
1019 "will re-register in %d seconds",
1020 pjsua_var.acc[acc->index].cfg.id.ptr,
1021 param->code,
1022 (int)param->reason.slen, param->reason.ptr,
1023 param->expiration));
Benny Prijono8b6834f2007-02-24 13:29:22 +00001024
Benny Prijonobddef2c2007-10-31 13:28:08 +00001025 /* Start keep-alive timer if necessary. */
1026 update_keep_alive(acc, PJ_TRUE, param);
1027
Benny Prijono8b6834f2007-02-24 13:29:22 +00001028 /* Send initial PUBLISH if it is enabled */
1029 if (acc->cfg.publish_enabled && acc->publish_sess==NULL)
1030 pjsua_pres_init_publish_acc(acc->index);
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001031 }
1032
1033 } else {
1034 PJ_LOG(4, (THIS_FILE, "SIP registration updated status=%d", param->code));
1035 }
1036
1037 acc->reg_last_err = param->status;
1038 acc->reg_last_code = param->code;
1039
1040 if (pjsua_var.ua_cfg.cb.on_reg_state)
1041 (*pjsua_var.ua_cfg.cb.on_reg_state)(acc->index);
1042
1043 PJSUA_UNLOCK();
1044}
1045
1046
1047/*
1048 * Initialize client registration.
1049 */
1050static pj_status_t pjsua_regc_init(int acc_id)
1051{
1052 pjsua_acc *acc;
Benny Prijonoe1a8bad2006-10-13 17:45:38 +00001053 pj_pool_t *pool;
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001054 pj_status_t status;
1055
Benny Prijono62c5c5b2007-01-13 23:22:40 +00001056 PJ_ASSERT_RETURN(pjsua_acc_is_valid(acc_id), PJ_EINVAL);
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001057 acc = &pjsua_var.acc[acc_id];
1058
1059 if (acc->cfg.reg_uri.slen == 0) {
1060 PJ_LOG(3,(THIS_FILE, "Registrar URI is not specified"));
1061 return PJ_SUCCESS;
1062 }
1063
Benny Prijonoe1a8bad2006-10-13 17:45:38 +00001064 /* Destroy existing session, if any */
1065 if (acc->regc) {
1066 pjsip_regc_destroy(acc->regc);
1067 acc->regc = NULL;
Benny Prijonoddaaf6a2008-04-15 10:37:19 +00001068 acc->contact.slen = 0;
Benny Prijonoe1a8bad2006-10-13 17:45:38 +00001069 }
1070
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001071 /* initialize SIP registration if registrar is configured */
1072
1073 status = pjsip_regc_create( pjsua_var.endpt,
1074 acc, &regc_cb, &acc->regc);
1075
1076 if (status != PJ_SUCCESS) {
1077 pjsua_perror(THIS_FILE, "Unable to create client registration",
1078 status);
1079 return status;
1080 }
1081
Benny Prijono38fb3ea2008-01-02 08:27:03 +00001082 pool = pjsua_pool_create("tmpregc", 512, 512);
Benny Prijonoe8554ef2008-03-22 09:33:52 +00001083
1084 if (acc->contact.slen == 0) {
1085 pj_str_t tmp_contact;
1086
1087 status = pjsua_acc_create_uac_contact( pool, &tmp_contact,
1088 acc_id, &acc->cfg.reg_uri);
1089 if (status != PJ_SUCCESS) {
1090 pjsua_perror(THIS_FILE, "Unable to generate suitable Contact header"
1091 " for registration",
1092 status);
1093 pjsip_regc_destroy(acc->regc);
1094 pj_pool_release(pool);
1095 acc->regc = NULL;
1096 return status;
1097 }
1098
Benny Prijonoc91ed8d2008-07-13 12:24:55 +00001099 pj_strdup_with_null(acc->pool, &acc->contact, &tmp_contact);
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001100 }
1101
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001102 status = pjsip_regc_init( acc->regc,
1103 &acc->cfg.reg_uri,
1104 &acc->cfg.id,
1105 &acc->cfg.id,
Benny Prijonoe8554ef2008-03-22 09:33:52 +00001106 1, &acc->contact,
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001107 acc->cfg.reg_timeout);
1108 if (status != PJ_SUCCESS) {
1109 pjsua_perror(THIS_FILE,
1110 "Client registration initialization error",
1111 status);
Benny Prijono19b29372007-12-05 04:08:40 +00001112 pjsip_regc_destroy(acc->regc);
Benny Prijono38fb3ea2008-01-02 08:27:03 +00001113 pj_pool_release(pool);
Benny Prijono19b29372007-12-05 04:08:40 +00001114 acc->regc = NULL;
Benny Prijonoddaaf6a2008-04-15 10:37:19 +00001115 acc->contact.slen = 0;
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001116 return status;
1117 }
1118
Benny Prijono62c5c5b2007-01-13 23:22:40 +00001119 /* If account is locked to specific transport, then set transport to
1120 * the client registration.
1121 */
1122 if (pjsua_var.acc[acc_id].cfg.transport_id != PJSUA_INVALID_ID) {
1123 pjsip_tpselector tp_sel;
1124
1125 pjsua_init_tpselector(pjsua_var.acc[acc_id].cfg.transport_id, &tp_sel);
1126 pjsip_regc_set_transport(acc->regc, &tp_sel);
1127 }
1128
1129
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001130 /* Set credentials
1131 */
1132 if (acc->cred_cnt) {
1133 pjsip_regc_set_credentials( acc->regc, acc->cred_cnt, acc->cred);
1134 }
1135
Benny Prijono48ab2b72007-11-08 09:24:30 +00001136 /* Set authentication preference */
1137 pjsip_regc_set_prefs(acc->regc, &acc->cfg.auth_pref);
1138
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001139 /* Set route-set
1140 */
1141 if (!pj_list_empty(&acc->route_set)) {
1142 pjsip_regc_set_route_set( acc->regc, &acc->route_set );
1143 }
1144
Benny Prijono8fc6de02006-11-11 21:25:55 +00001145 /* Add other request headers. */
1146 if (pjsua_var.ua_cfg.user_agent.slen) {
1147 pjsip_hdr hdr_list;
1148 const pj_str_t STR_USER_AGENT = { "User-Agent", 10 };
1149 pjsip_generic_string_hdr *h;
1150
Benny Prijono8fc6de02006-11-11 21:25:55 +00001151 pj_list_init(&hdr_list);
1152
1153 h = pjsip_generic_string_hdr_create(pool, &STR_USER_AGENT,
1154 &pjsua_var.ua_cfg.user_agent);
1155 pj_list_push_back(&hdr_list, (pjsip_hdr*)h);
1156
1157 pjsip_regc_add_headers(acc->regc, &hdr_list);
1158 }
1159
Benny Prijono38fb3ea2008-01-02 08:27:03 +00001160 pj_pool_release(pool);
1161
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001162 return PJ_SUCCESS;
1163}
1164
1165
1166/*
1167 * Update registration or perform unregistration.
1168 */
1169PJ_DEF(pj_status_t) pjsua_acc_set_registration( pjsua_acc_id acc_id,
1170 pj_bool_t renew)
1171{
1172 pj_status_t status = 0;
1173 pjsip_tx_data *tdata = 0;
1174
1175 PJ_ASSERT_RETURN(acc_id>=0 && acc_id<(int)PJ_ARRAY_SIZE(pjsua_var.acc),
1176 PJ_EINVAL);
1177 PJ_ASSERT_RETURN(pjsua_var.acc[acc_id].valid, PJ_EINVALIDOP);
1178
1179 PJSUA_LOCK();
1180
1181 if (renew) {
1182 if (pjsua_var.acc[acc_id].regc == NULL) {
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001183 status = pjsua_regc_init(acc_id);
1184 if (status != PJ_SUCCESS) {
1185 pjsua_perror(THIS_FILE, "Unable to create registration",
1186 status);
1187 goto on_return;
1188 }
1189 }
1190 if (!pjsua_var.acc[acc_id].regc) {
1191 status = PJ_EINVALIDOP;
1192 goto on_return;
1193 }
1194
1195 status = pjsip_regc_register(pjsua_var.acc[acc_id].regc, 1,
1196 &tdata);
1197
Benny Prijono28f673a2007-10-15 07:04:59 +00001198 if (0 && status == PJ_SUCCESS && pjsua_var.acc[acc_id].cred_cnt) {
1199 pjsua_acc *acc = &pjsua_var.acc[acc_id];
1200 pjsip_authorization_hdr *h;
1201 char *uri;
1202 int d;
1203
1204 uri = (char*) pj_pool_alloc(tdata->pool, acc->cfg.reg_uri.slen+10);
1205 d = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, tdata->msg->line.req.uri,
1206 uri, acc->cfg.reg_uri.slen+10);
1207 pj_assert(d > 0);
1208
1209 h = pjsip_authorization_hdr_create(tdata->pool);
1210 h->scheme = pj_str("Digest");
1211 h->credential.digest.username = acc->cred[0].username;
1212 h->credential.digest.realm = acc->srv_domain;
1213 h->credential.digest.uri = pj_str(uri);
1214 h->credential.digest.algorithm = pj_str("md5");
1215
1216 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)h);
1217 }
1218
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001219 } else {
1220 if (pjsua_var.acc[acc_id].regc == NULL) {
1221 PJ_LOG(3,(THIS_FILE, "Currently not registered"));
1222 status = PJ_EINVALIDOP;
1223 goto on_return;
1224 }
1225 status = pjsip_regc_unregister(pjsua_var.acc[acc_id].regc, &tdata);
1226 }
1227
Benny Prijono56315612006-07-18 14:39:40 +00001228 if (status == PJ_SUCCESS) {
Benny Prijono8fc6de02006-11-11 21:25:55 +00001229 //pjsua_process_msg_data(tdata, NULL);
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001230 status = pjsip_regc_send( pjsua_var.acc[acc_id].regc, tdata );
Benny Prijono56315612006-07-18 14:39:40 +00001231 }
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001232
1233 if (status != PJ_SUCCESS) {
1234 pjsua_perror(THIS_FILE, "Unable to create/send REGISTER",
1235 status);
1236 } else {
1237 PJ_LOG(3,(THIS_FILE, "%s sent",
1238 (renew? "Registration" : "Unregistration")));
1239 }
1240
1241on_return:
1242 PJSUA_UNLOCK();
1243 return status;
1244}
1245
1246
1247/*
1248 * Get account information.
1249 */
1250PJ_DEF(pj_status_t) pjsua_acc_get_info( pjsua_acc_id acc_id,
1251 pjsua_acc_info *info)
1252{
1253 pjsua_acc *acc = &pjsua_var.acc[acc_id];
1254 pjsua_acc_config *acc_cfg = &pjsua_var.acc[acc_id].cfg;
1255
1256 PJ_ASSERT_RETURN(info != NULL, PJ_EINVAL);
Benny Prijono62c5c5b2007-01-13 23:22:40 +00001257 PJ_ASSERT_RETURN(pjsua_acc_is_valid(acc_id), PJ_EINVAL);
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001258
Benny Prijonoac623b32006-07-03 15:19:31 +00001259 pj_bzero(info, sizeof(pjsua_acc_info));
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001260
1261 PJ_ASSERT_RETURN(acc_id>=0 && acc_id<(int)PJ_ARRAY_SIZE(pjsua_var.acc),
1262 PJ_EINVAL);
1263 PJ_ASSERT_RETURN(pjsua_var.acc[acc_id].valid, PJ_EINVALIDOP);
1264
1265 PJSUA_LOCK();
1266
1267 if (pjsua_var.acc[acc_id].valid == PJ_FALSE) {
1268 PJSUA_UNLOCK();
1269 return PJ_EINVALIDOP;
1270 }
1271
1272 info->id = acc_id;
1273 info->is_default = (pjsua_var.default_acc == acc_id);
1274 info->acc_uri = acc_cfg->id;
1275 info->has_registration = (acc->cfg.reg_uri.slen > 0);
1276 info->online_status = acc->online_status;
Benny Prijono4461c7d2007-08-25 13:36:15 +00001277 pj_memcpy(&info->rpid, &acc->rpid, sizeof(pjrpid_element));
1278 if (info->rpid.note.slen)
1279 info->online_status_text = info->rpid.note;
1280 else if (info->online_status)
1281 info->online_status_text = pj_str("Online");
1282 else
1283 info->online_status_text = pj_str("Offline");
1284
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001285 if (acc->reg_last_err) {
Benny Prijonoba5926a2007-05-02 11:29:37 +00001286 info->status = (pjsip_status_code) acc->reg_last_err;
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001287 pj_strerror(acc->reg_last_err, info->buf_, sizeof(info->buf_));
1288 info->status_text = pj_str(info->buf_);
1289 } else if (acc->reg_last_code) {
Benny Prijono6f979412006-06-15 12:25:46 +00001290 if (info->has_registration) {
Benny Prijonoba5926a2007-05-02 11:29:37 +00001291 info->status = (pjsip_status_code) acc->reg_last_code;
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001292 info->status_text = *pjsip_get_status_text(acc->reg_last_code);
1293 } else {
Benny Prijonoba5926a2007-05-02 11:29:37 +00001294 info->status = (pjsip_status_code) 0;
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001295 info->status_text = pj_str("not registered");
1296 }
1297 } else if (acc->cfg.reg_uri.slen) {
Benny Prijonoba5926a2007-05-02 11:29:37 +00001298 info->status = PJSIP_SC_TRYING;
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001299 info->status_text = pj_str("In Progress");
1300 } else {
Benny Prijonoba5926a2007-05-02 11:29:37 +00001301 info->status = (pjsip_status_code) 0;
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001302 info->status_text = pj_str("does not register");
1303 }
1304
1305 if (acc->regc) {
1306 pjsip_regc_info regc_info;
1307 pjsip_regc_get_info(acc->regc, &regc_info);
1308 info->expires = regc_info.next_reg;
1309 } else {
1310 info->expires = -1;
1311 }
1312
1313 PJSUA_UNLOCK();
1314
1315 return PJ_SUCCESS;
1316
1317}
1318
1319
1320/*
1321 * Enum accounts all account ids.
1322 */
1323PJ_DEF(pj_status_t) pjsua_enum_accs(pjsua_acc_id ids[],
1324 unsigned *count )
1325{
1326 unsigned i, c;
1327
1328 PJ_ASSERT_RETURN(ids && *count, PJ_EINVAL);
1329
1330 PJSUA_LOCK();
1331
1332 for (i=0, c=0; c<*count && i<PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
1333 if (!pjsua_var.acc[i].valid)
1334 continue;
1335 ids[c] = i;
1336 ++c;
1337 }
1338
1339 *count = c;
1340
1341 PJSUA_UNLOCK();
1342
1343 return PJ_SUCCESS;
1344}
1345
1346
1347/*
1348 * Enum accounts info.
1349 */
1350PJ_DEF(pj_status_t) pjsua_acc_enum_info( pjsua_acc_info info[],
1351 unsigned *count )
1352{
1353 unsigned i, c;
1354
1355 PJ_ASSERT_RETURN(info && *count, PJ_EINVAL);
1356
1357 PJSUA_LOCK();
1358
1359 for (i=0, c=0; c<*count && i<PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
1360 if (!pjsua_var.acc[i].valid)
1361 continue;
1362
1363 pjsua_acc_get_info(i, &info[c]);
1364 ++c;
1365 }
1366
1367 *count = c;
1368
1369 PJSUA_UNLOCK();
1370
1371 return PJ_SUCCESS;
1372}
1373
1374
1375/*
1376 * This is an internal function to find the most appropriate account to
1377 * used to reach to the specified URL.
1378 */
1379PJ_DEF(pjsua_acc_id) pjsua_acc_find_for_outgoing(const pj_str_t *url)
1380{
1381 pj_str_t tmp;
1382 pjsip_uri *uri;
1383 pjsip_sip_uri *sip_uri;
Benny Prijonoc91ed8d2008-07-13 12:24:55 +00001384 pj_pool_t *tmp_pool;
Benny Prijono093d3022006-09-24 00:07:11 +00001385 unsigned i;
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001386
1387 PJSUA_LOCK();
1388
Benny Prijonoc91ed8d2008-07-13 12:24:55 +00001389 tmp_pool = pjsua_pool_create("tmpacc10", 256, 256);
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001390
Benny Prijonoc91ed8d2008-07-13 12:24:55 +00001391 pj_strdup_with_null(tmp_pool, &tmp, url);
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001392
Benny Prijonoc91ed8d2008-07-13 12:24:55 +00001393 uri = pjsip_parse_uri(tmp_pool, tmp.ptr, tmp.slen, 0);
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001394 if (!uri) {
Benny Prijonoc91ed8d2008-07-13 12:24:55 +00001395 pj_pool_release(tmp_pool);
Benny Prijono093d3022006-09-24 00:07:11 +00001396 PJSUA_UNLOCK();
1397 return pjsua_var.default_acc;
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001398 }
1399
1400 if (!PJSIP_URI_SCHEME_IS_SIP(uri) &&
1401 !PJSIP_URI_SCHEME_IS_SIPS(uri))
1402 {
1403 /* Return the first account with proxy */
Benny Prijono093d3022006-09-24 00:07:11 +00001404 for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
1405 if (!pjsua_var.acc[i].valid)
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001406 continue;
Benny Prijono093d3022006-09-24 00:07:11 +00001407 if (!pj_list_empty(&pjsua_var.acc[i].route_set))
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001408 break;
1409 }
1410
Benny Prijono093d3022006-09-24 00:07:11 +00001411 if (i != PJ_ARRAY_SIZE(pjsua_var.acc)) {
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001412 /* Found rather matching account */
Benny Prijonoc91ed8d2008-07-13 12:24:55 +00001413 pj_pool_release(tmp_pool);
Benny Prijono093d3022006-09-24 00:07:11 +00001414 PJSUA_UNLOCK();
Benny Prijonoc91ed8d2008-07-13 12:24:55 +00001415 return i;
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001416 }
1417
1418 /* Not found, use default account */
Benny Prijonoc91ed8d2008-07-13 12:24:55 +00001419 pj_pool_release(tmp_pool);
Benny Prijono093d3022006-09-24 00:07:11 +00001420 PJSUA_UNLOCK();
1421 return pjsua_var.default_acc;
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001422 }
1423
Benny Prijonoa1e69682007-05-11 15:14:34 +00001424 sip_uri = (pjsip_sip_uri*) pjsip_uri_get_uri(uri);
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001425
Benny Prijonob4a17c92006-07-10 14:40:21 +00001426 /* Find matching domain AND port */
Benny Prijono093d3022006-09-24 00:07:11 +00001427 for (i=0; i<pjsua_var.acc_cnt; ++i) {
1428 unsigned acc_id = pjsua_var.acc_ids[i];
1429 if (pj_stricmp(&pjsua_var.acc[acc_id].srv_domain, &sip_uri->host)==0 &&
1430 pjsua_var.acc[acc_id].srv_port == sip_uri->port)
1431 {
Benny Prijonoc91ed8d2008-07-13 12:24:55 +00001432 pj_pool_release(tmp_pool);
Benny Prijono093d3022006-09-24 00:07:11 +00001433 PJSUA_UNLOCK();
1434 return acc_id;
Benny Prijono21b9ad92006-08-15 13:11:22 +00001435 }
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001436 }
1437
Benny Prijonob4a17c92006-07-10 14:40:21 +00001438 /* If no match, try to match the domain part only */
Benny Prijono093d3022006-09-24 00:07:11 +00001439 for (i=0; i<pjsua_var.acc_cnt; ++i) {
1440 unsigned acc_id = pjsua_var.acc_ids[i];
1441 if (pj_stricmp(&pjsua_var.acc[acc_id].srv_domain, &sip_uri->host)==0)
1442 {
Benny Prijonoc91ed8d2008-07-13 12:24:55 +00001443 pj_pool_release(tmp_pool);
Benny Prijono093d3022006-09-24 00:07:11 +00001444 PJSUA_UNLOCK();
1445 return acc_id;
Benny Prijonob4a17c92006-07-10 14:40:21 +00001446 }
1447 }
1448
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001449
Benny Prijono093d3022006-09-24 00:07:11 +00001450 /* Still no match, just use default account */
Benny Prijonoc91ed8d2008-07-13 12:24:55 +00001451 pj_pool_release(tmp_pool);
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001452 PJSUA_UNLOCK();
Benny Prijono093d3022006-09-24 00:07:11 +00001453 return pjsua_var.default_acc;
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001454}
1455
1456
1457/*
1458 * This is an internal function to find the most appropriate account to be
1459 * used to handle incoming calls.
1460 */
1461PJ_DEF(pjsua_acc_id) pjsua_acc_find_for_incoming(pjsip_rx_data *rdata)
1462{
1463 pjsip_uri *uri;
1464 pjsip_sip_uri *sip_uri;
Benny Prijono093d3022006-09-24 00:07:11 +00001465 unsigned i;
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001466
Benny Prijono371cf0a2007-06-19 00:35:37 +00001467 /* Check that there's at least one account configured */
1468 PJ_ASSERT_RETURN(pjsua_var.acc_cnt!=0, pjsua_var.default_acc);
1469
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001470 uri = rdata->msg_info.to->uri;
1471
1472 /* Just return default account if To URI is not SIP: */
1473 if (!PJSIP_URI_SCHEME_IS_SIP(uri) &&
1474 !PJSIP_URI_SCHEME_IS_SIPS(uri))
1475 {
1476 return pjsua_var.default_acc;
1477 }
1478
1479
1480 PJSUA_LOCK();
1481
1482 sip_uri = (pjsip_sip_uri*)pjsip_uri_get_uri(uri);
1483
1484 /* Find account which has matching username and domain. */
Benny Prijono093d3022006-09-24 00:07:11 +00001485 for (i=0; i < pjsua_var.acc_cnt; ++i) {
1486 unsigned acc_id = pjsua_var.acc_ids[i];
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001487 pjsua_acc *acc = &pjsua_var.acc[acc_id];
1488
Benny Prijono62c5c5b2007-01-13 23:22:40 +00001489 if (acc->valid && pj_stricmp(&acc->user_part, &sip_uri->user)==0 &&
Benny Prijonob4a17c92006-07-10 14:40:21 +00001490 pj_stricmp(&acc->srv_domain, &sip_uri->host)==0)
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001491 {
1492 /* Match ! */
1493 PJSUA_UNLOCK();
1494 return acc_id;
1495 }
1496 }
1497
Benny Prijono093d3022006-09-24 00:07:11 +00001498 /* No matching account, try match domain part only. */
1499 for (i=0; i < pjsua_var.acc_cnt; ++i) {
1500 unsigned acc_id = pjsua_var.acc_ids[i];
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001501 pjsua_acc *acc = &pjsua_var.acc[acc_id];
1502
Benny Prijono62c5c5b2007-01-13 23:22:40 +00001503 if (acc->valid && pj_stricmp(&acc->srv_domain, &sip_uri->host)==0) {
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001504 /* Match ! */
1505 PJSUA_UNLOCK();
1506 return acc_id;
1507 }
1508 }
1509
Benny Prijono62c5c5b2007-01-13 23:22:40 +00001510 /* No matching account, try match user part (and transport type) only. */
Benny Prijono093d3022006-09-24 00:07:11 +00001511 for (i=0; i < pjsua_var.acc_cnt; ++i) {
1512 unsigned acc_id = pjsua_var.acc_ids[i];
1513 pjsua_acc *acc = &pjsua_var.acc[acc_id];
1514
Benny Prijono62c5c5b2007-01-13 23:22:40 +00001515 if (acc->valid && pj_stricmp(&acc->user_part, &sip_uri->user)==0) {
1516
1517 if (acc->cfg.transport_id != PJSUA_INVALID_ID) {
1518 pjsip_transport_type_e type;
1519 type = pjsip_transport_get_type_from_name(&sip_uri->transport_param);
1520 if (type == PJSIP_TRANSPORT_UNSPECIFIED)
1521 type = PJSIP_TRANSPORT_UDP;
1522
1523 if (pjsua_var.tpdata[acc->cfg.transport_id].type != type)
1524 continue;
1525 }
1526
Benny Prijono093d3022006-09-24 00:07:11 +00001527 /* Match ! */
1528 PJSUA_UNLOCK();
1529 return acc_id;
1530 }
1531 }
1532
Benny Prijonoeebe9af2006-06-13 22:57:13 +00001533 /* Still no match, use default account */
1534 PJSUA_UNLOCK();
1535 return pjsua_var.default_acc;
1536}
1537
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001538
Benny Prijonofff245c2007-04-02 11:44:47 +00001539/*
1540 * Create arbitrary requests for this account.
1541 */
1542PJ_DEF(pj_status_t) pjsua_acc_create_request(pjsua_acc_id acc_id,
1543 const pjsip_method *method,
1544 const pj_str_t *target,
1545 pjsip_tx_data **p_tdata)
1546{
1547 pjsip_tx_data *tdata;
1548 pjsua_acc *acc;
1549 pjsip_route_hdr *r;
1550 pj_status_t status;
1551
1552 PJ_ASSERT_RETURN(method && target && p_tdata, PJ_EINVAL);
1553 PJ_ASSERT_RETURN(pjsua_acc_is_valid(acc_id), PJ_EINVAL);
1554
1555 acc = &pjsua_var.acc[acc_id];
1556
1557 status = pjsip_endpt_create_request(pjsua_var.endpt, method, target,
1558 &acc->cfg.id, target,
1559 NULL, NULL, -1, NULL, &tdata);
1560 if (status != PJ_SUCCESS) {
1561 pjsua_perror(THIS_FILE, "Unable to create request", status);
1562 return status;
1563 }
1564
1565 /* Copy routeset */
1566 r = acc->route_set.next;
1567 while (r != &acc->route_set) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00001568 pjsip_msg_add_hdr(tdata->msg,
1569 (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, r));
Benny Prijonofff245c2007-04-02 11:44:47 +00001570 r = r->next;
1571 }
1572
1573 /* Done */
1574 *p_tdata = tdata;
1575 return PJ_SUCCESS;
1576}
1577
1578
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001579PJ_DEF(pj_status_t) pjsua_acc_create_uac_contact( pj_pool_t *pool,
1580 pj_str_t *contact,
1581 pjsua_acc_id acc_id,
1582 const pj_str_t *suri)
1583{
1584 pjsua_acc *acc;
1585 pjsip_sip_uri *sip_uri;
1586 pj_status_t status;
1587 pjsip_transport_type_e tp_type = PJSIP_TRANSPORT_UNSPECIFIED;
1588 pj_str_t local_addr;
Benny Prijono62c5c5b2007-01-13 23:22:40 +00001589 pjsip_tpselector tp_sel;
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001590 unsigned flag;
1591 int secure;
1592 int local_port;
Benny Prijonod0bd4982007-12-02 15:40:52 +00001593 const char *beginquote, *endquote;
1594 char transport_param[32];
1595
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001596
Benny Prijono62c5c5b2007-01-13 23:22:40 +00001597 PJ_ASSERT_RETURN(pjsua_acc_is_valid(acc_id), PJ_EINVAL);
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001598 acc = &pjsua_var.acc[acc_id];
1599
Benny Prijonof75eceb2007-03-23 19:09:54 +00001600 /* If force_contact is configured, then use use it */
1601 if (acc->cfg.force_contact.slen) {
1602 *contact = acc->cfg.force_contact;
1603 return PJ_SUCCESS;
1604 }
1605
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001606 /* If route-set is configured for the account, then URI is the
1607 * first entry of the route-set.
1608 */
1609 if (!pj_list_empty(&acc->route_set)) {
Benny Prijono9c1528f2007-02-10 19:22:25 +00001610 sip_uri = (pjsip_sip_uri*)
1611 pjsip_uri_get_uri(acc->route_set.next->name_addr.uri);
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001612 } else {
1613 pj_str_t tmp;
1614 pjsip_uri *uri;
1615
1616 pj_strdup_with_null(pool, &tmp, suri);
1617
1618 uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0);
1619 if (uri == NULL)
1620 return PJSIP_EINVALIDURI;
1621
1622 /* For non-SIP scheme, route set should be configured */
1623 if (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri))
1624 return PJSIP_EINVALIDREQURI;
1625
Benny Prijono8c7a6172007-02-18 21:17:46 +00001626 sip_uri = (pjsip_sip_uri*)pjsip_uri_get_uri(uri);
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001627 }
1628
1629 /* Get transport type of the URI */
1630 if (PJSIP_URI_SCHEME_IS_SIPS(sip_uri))
1631 tp_type = PJSIP_TRANSPORT_TLS;
1632 else if (sip_uri->transport_param.slen == 0) {
1633 tp_type = PJSIP_TRANSPORT_UDP;
1634 } else
1635 tp_type = pjsip_transport_get_type_from_name(&sip_uri->transport_param);
1636
1637 if (tp_type == PJSIP_TRANSPORT_UNSPECIFIED)
1638 return PJSIP_EUNSUPTRANSPORT;
1639
Benny Prijonod0bd4982007-12-02 15:40:52 +00001640 /* If destination URI specifies IPv6, then set transport type
1641 * to use IPv6 as well.
1642 */
Benny Prijono19b29372007-12-05 04:08:40 +00001643 if (pj_strchr(&sip_uri->host, ':'))
Benny Prijonod0bd4982007-12-02 15:40:52 +00001644 tp_type = (pjsip_transport_type_e)(((int)tp_type) + PJSIP_TRANSPORT_IPV6);
1645
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001646 flag = pjsip_transport_get_flag_from_type(tp_type);
1647 secure = (flag & PJSIP_TRANSPORT_SECURE) != 0;
1648
Benny Prijono62c5c5b2007-01-13 23:22:40 +00001649 /* Init transport selector. */
1650 pjsua_init_tpselector(pjsua_var.acc[acc_id].cfg.transport_id, &tp_sel);
1651
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001652 /* Get local address suitable to send request from */
1653 status = pjsip_tpmgr_find_local_addr(pjsip_endpt_get_tpmgr(pjsua_var.endpt),
Benny Prijono62c5c5b2007-01-13 23:22:40 +00001654 pool, tp_type, &tp_sel,
1655 &local_addr, &local_port);
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001656 if (status != PJ_SUCCESS)
1657 return status;
1658
Benny Prijonod0bd4982007-12-02 15:40:52 +00001659 /* Enclose IPv6 address in square brackets */
1660 if (tp_type & PJSIP_TRANSPORT_IPV6) {
1661 beginquote = "[";
1662 endquote = "]";
1663 } else {
1664 beginquote = endquote = "";
1665 }
1666
1667 /* Don't add transport parameter if it's UDP */
Benny Prijono4c82c1e2008-10-16 08:14:51 +00001668 if (tp_type!=PJSIP_TRANSPORT_UDP && tp_type!=PJSIP_TRANSPORT_UDP6) {
Benny Prijonod0bd4982007-12-02 15:40:52 +00001669 pj_ansi_snprintf(transport_param, sizeof(transport_param),
1670 ";transport=%s",
1671 pjsip_transport_get_type_name(tp_type));
1672 } else {
1673 transport_param[0] = '\0';
1674 }
1675
1676
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001677 /* Create the contact header */
Benny Prijonoa1e69682007-05-11 15:14:34 +00001678 contact->ptr = (char*)pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001679 contact->slen = pj_ansi_snprintf(contact->ptr, PJSIP_MAX_URL_SIZE,
Benny Prijono30fe4852008-12-10 16:54:16 +00001680 "%.*s%s<%s:%.*s%s%s%.*s%s:%d%s%.*s>",
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001681 (int)acc->display.slen,
1682 acc->display.ptr,
1683 (acc->display.slen?" " : ""),
Benny Prijono8058a622007-06-08 04:37:05 +00001684 (secure ? PJSUA_SECURE_SCHEME : "sip"),
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001685 (int)acc->user_part.slen,
1686 acc->user_part.ptr,
1687 (acc->user_part.slen?"@":""),
Benny Prijonod0bd4982007-12-02 15:40:52 +00001688 beginquote,
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001689 (int)local_addr.slen,
1690 local_addr.ptr,
Benny Prijonod0bd4982007-12-02 15:40:52 +00001691 endquote,
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001692 local_port,
Benny Prijono30fe4852008-12-10 16:54:16 +00001693 transport_param,
1694 (int)acc->cfg.contact_params.slen,
1695 acc->cfg.contact_params.ptr);
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001696
1697 return PJ_SUCCESS;
1698}
1699
1700
1701
1702PJ_DEF(pj_status_t) pjsua_acc_create_uas_contact( pj_pool_t *pool,
1703 pj_str_t *contact,
1704 pjsua_acc_id acc_id,
1705 pjsip_rx_data *rdata )
1706{
1707 /*
1708 * Section 12.1.1, paragraph about using SIPS URI in Contact.
1709 * If the request that initiated the dialog contained a SIPS URI
1710 * in the Request-URI or in the top Record-Route header field value,
1711 * if there was any, or the Contact header field if there was no
1712 * Record-Route header field, the Contact header field in the response
1713 * MUST be a SIPS URI.
1714 */
1715 pjsua_acc *acc;
1716 pjsip_sip_uri *sip_uri;
1717 pj_status_t status;
1718 pjsip_transport_type_e tp_type = PJSIP_TRANSPORT_UNSPECIFIED;
1719 pj_str_t local_addr;
Benny Prijono62c5c5b2007-01-13 23:22:40 +00001720 pjsip_tpselector tp_sel;
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001721 unsigned flag;
1722 int secure;
1723 int local_port;
Benny Prijonod0bd4982007-12-02 15:40:52 +00001724 const char *beginquote, *endquote;
1725 char transport_param[32];
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001726
Benny Prijono62c5c5b2007-01-13 23:22:40 +00001727 PJ_ASSERT_RETURN(pjsua_acc_is_valid(acc_id), PJ_EINVAL);
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001728 acc = &pjsua_var.acc[acc_id];
1729
Benny Prijonof75eceb2007-03-23 19:09:54 +00001730 /* If force_contact is configured, then use use it */
1731 if (acc->cfg.force_contact.slen) {
1732 *contact = acc->cfg.force_contact;
1733 return PJ_SUCCESS;
1734 }
1735
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001736 /* If Record-Route is present, then URI is the top Record-Route. */
1737 if (rdata->msg_info.record_route) {
Benny Prijono9c1528f2007-02-10 19:22:25 +00001738 sip_uri = (pjsip_sip_uri*)
1739 pjsip_uri_get_uri(rdata->msg_info.record_route->name_addr.uri);
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001740 } else {
Benny Prijonoa330d452008-08-05 20:14:39 +00001741 pjsip_hdr *pos = NULL;
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001742 pjsip_contact_hdr *h_contact;
1743 pjsip_uri *uri = NULL;
1744
Benny Prijonoa330d452008-08-05 20:14:39 +00001745 /* Otherwise URI is Contact URI.
1746 * Iterate the Contact URI until we find sip: or sips: scheme.
1747 */
1748 do {
1749 h_contact = (pjsip_contact_hdr*)
1750 pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT,
1751 pos);
1752 if (h_contact) {
1753 uri = (pjsip_uri*) pjsip_uri_get_uri(h_contact->uri);
1754 if (!PJSIP_URI_SCHEME_IS_SIP(uri) &&
1755 !PJSIP_URI_SCHEME_IS_SIPS(uri))
1756 {
1757 pos = (pjsip_hdr*)h_contact->next;
1758 if (pos == &rdata->msg_info.msg->hdr)
1759 h_contact = NULL;
1760 } else {
1761 break;
1762 }
1763 }
1764 } while (h_contact);
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001765
1766
1767 /* Or if Contact URI is not present, take the remote URI from
1768 * the From URI.
1769 */
1770 if (uri == NULL)
Benny Prijonoa1e69682007-05-11 15:14:34 +00001771 uri = (pjsip_uri*) pjsip_uri_get_uri(rdata->msg_info.from->uri);
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001772
1773
1774 /* Can only do sip/sips scheme at present. */
1775 if (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri))
1776 return PJSIP_EINVALIDREQURI;
1777
Benny Prijono8c7a6172007-02-18 21:17:46 +00001778 sip_uri = (pjsip_sip_uri*)pjsip_uri_get_uri(uri);
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001779 }
1780
1781 /* Get transport type of the URI */
1782 if (PJSIP_URI_SCHEME_IS_SIPS(sip_uri))
1783 tp_type = PJSIP_TRANSPORT_TLS;
1784 else if (sip_uri->transport_param.slen == 0) {
1785 tp_type = PJSIP_TRANSPORT_UDP;
1786 } else
1787 tp_type = pjsip_transport_get_type_from_name(&sip_uri->transport_param);
Benny Prijonod0bd4982007-12-02 15:40:52 +00001788
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001789 if (tp_type == PJSIP_TRANSPORT_UNSPECIFIED)
1790 return PJSIP_EUNSUPTRANSPORT;
1791
Benny Prijonod0bd4982007-12-02 15:40:52 +00001792 /* If destination URI specifies IPv6, then set transport type
1793 * to use IPv6 as well.
1794 */
1795 if (pj_strchr(&sip_uri->host, ':'))
1796 tp_type = (pjsip_transport_type_e)(((int)tp_type) + PJSIP_TRANSPORT_IPV6);
1797
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001798 flag = pjsip_transport_get_flag_from_type(tp_type);
1799 secure = (flag & PJSIP_TRANSPORT_SECURE) != 0;
1800
Benny Prijono62c5c5b2007-01-13 23:22:40 +00001801 /* Init transport selector. */
1802 pjsua_init_tpselector(pjsua_var.acc[acc_id].cfg.transport_id, &tp_sel);
1803
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001804 /* Get local address suitable to send request from */
1805 status = pjsip_tpmgr_find_local_addr(pjsip_endpt_get_tpmgr(pjsua_var.endpt),
Benny Prijono62c5c5b2007-01-13 23:22:40 +00001806 pool, tp_type, &tp_sel,
1807 &local_addr, &local_port);
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001808 if (status != PJ_SUCCESS)
1809 return status;
1810
Benny Prijonod0bd4982007-12-02 15:40:52 +00001811 /* Enclose IPv6 address in square brackets */
1812 if (tp_type & PJSIP_TRANSPORT_IPV6) {
1813 beginquote = "[";
1814 endquote = "]";
1815 } else {
1816 beginquote = endquote = "";
1817 }
1818
1819 /* Don't add transport parameter if it's UDP */
Benny Prijono4c82c1e2008-10-16 08:14:51 +00001820 if (tp_type!=PJSIP_TRANSPORT_UDP && tp_type!=PJSIP_TRANSPORT_UDP6) {
Benny Prijonod0bd4982007-12-02 15:40:52 +00001821 pj_ansi_snprintf(transport_param, sizeof(transport_param),
1822 ";transport=%s",
1823 pjsip_transport_get_type_name(tp_type));
1824 } else {
1825 transport_param[0] = '\0';
1826 }
1827
1828
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001829 /* Create the contact header */
Benny Prijonoa1e69682007-05-11 15:14:34 +00001830 contact->ptr = (char*) pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001831 contact->slen = pj_ansi_snprintf(contact->ptr, PJSIP_MAX_URL_SIZE,
Benny Prijono30fe4852008-12-10 16:54:16 +00001832 "%.*s%s<%s:%.*s%s%s%.*s%s:%d%s%.*s>",
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001833 (int)acc->display.slen,
1834 acc->display.ptr,
1835 (acc->display.slen?" " : ""),
Benny Prijono8058a622007-06-08 04:37:05 +00001836 (secure ? PJSUA_SECURE_SCHEME : "sip"),
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001837 (int)acc->user_part.slen,
1838 acc->user_part.ptr,
1839 (acc->user_part.slen?"@":""),
Benny Prijonod0bd4982007-12-02 15:40:52 +00001840 beginquote,
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001841 (int)local_addr.slen,
1842 local_addr.ptr,
Benny Prijonod0bd4982007-12-02 15:40:52 +00001843 endquote,
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001844 local_port,
Benny Prijono30fe4852008-12-10 16:54:16 +00001845 transport_param,
1846 (int)acc->cfg.contact_params.slen,
1847 acc->cfg.contact_params.ptr);
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001848
1849 return PJ_SUCCESS;
1850}
1851
1852
Benny Prijono62c5c5b2007-01-13 23:22:40 +00001853PJ_DEF(pj_status_t) pjsua_acc_set_transport( pjsua_acc_id acc_id,
1854 pjsua_transport_id tp_id)
1855{
1856 pjsua_acc *acc;
1857
1858 PJ_ASSERT_RETURN(pjsua_acc_is_valid(acc_id), PJ_EINVAL);
1859 acc = &pjsua_var.acc[acc_id];
1860
Benny Prijonoa1e69682007-05-11 15:14:34 +00001861 PJ_ASSERT_RETURN(tp_id >= 0 && tp_id < (int)PJ_ARRAY_SIZE(pjsua_var.tpdata),
Benny Prijono62c5c5b2007-01-13 23:22:40 +00001862 PJ_EINVAL);
1863
1864 acc->cfg.transport_id = tp_id;
1865
1866 return PJ_SUCCESS;
1867}
Benny Prijonoc570f2d2006-07-18 00:33:02 +00001868