1 /* $Id$ */
2 /*
3 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5 *
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 enum
27 {
28 OUTBOUND_UNKNOWN, // status unknown
29 OUTBOUND_WANTED, // initiated in registration
30 OUTBOUND_ACTIVE, // got positive response from server
31 OUTBOUND_NA // not wanted or got negative response from server
32 };
33
34
35 static int get_ip_addr_ver(const pj_str_t *host);
36 static void schedule_reregistration(pjsua_acc *acc);
37 static void keep_alive_timer_cb(pj_timer_heap_t *th, pj_timer_entry *te);
38
39 /*
40 * Get number of current accounts.
41 */
pjsua_acc_get_count(void)42 PJ_DEF(unsigned) pjsua_acc_get_count(void)
43 {
44 return pjsua_var.acc_cnt;
45 }
46
47
48 /*
49 * Check if the specified account ID is valid.
50 */
pjsua_acc_is_valid(pjsua_acc_id acc_id)51 PJ_DEF(pj_bool_t) pjsua_acc_is_valid(pjsua_acc_id acc_id)
52 {
53 return acc_id>=0 && acc_id<(int)PJ_ARRAY_SIZE(pjsua_var.acc) &&
54 pjsua_var.acc[acc_id].valid;
55 }
56
57
58 /*
59 * Set default account
60 */
pjsua_acc_set_default(pjsua_acc_id acc_id)61 PJ_DEF(pj_status_t) pjsua_acc_set_default(pjsua_acc_id acc_id)
62 {
63 pjsua_var.default_acc = acc_id;
64 return PJ_SUCCESS;
65 }
66
67
68 /*
69 * Get default account.
70 */
pjsua_acc_get_default(void)71 PJ_DEF(pjsua_acc_id) pjsua_acc_get_default(void)
72 {
73 return pjsua_var.default_acc;
74 }
75
76
77 /*
78 * Copy account configuration.
79 */
pjsua_acc_config_dup(pj_pool_t * pool,pjsua_acc_config * dst,const pjsua_acc_config * src)80 PJ_DEF(void) pjsua_acc_config_dup( pj_pool_t *pool,
81 pjsua_acc_config *dst,
82 const pjsua_acc_config *src)
83 {
84 unsigned i;
85
86 pj_memcpy(dst, src, sizeof(pjsua_acc_config));
87
88 pj_strdup_with_null(pool, &dst->id, &src->id);
89 pj_strdup_with_null(pool, &dst->reg_uri, &src->reg_uri);
90 pj_strdup_with_null(pool, &dst->force_contact, &src->force_contact);
91 pj_strdup_with_null(pool, &dst->reg_contact_params,
92 &src->reg_contact_params);
93 pj_strdup_with_null(pool, &dst->contact_params, &src->contact_params);
94 pj_strdup_with_null(pool, &dst->contact_uri_params,
95 &src->contact_uri_params);
96 pj_strdup_with_null(pool, &dst->pidf_tuple_id, &src->pidf_tuple_id);
97 pj_strdup_with_null(pool, &dst->rfc5626_instance_id,
98 &src->rfc5626_instance_id);
99 pj_strdup_with_null(pool, &dst->rfc5626_reg_id, &src->rfc5626_reg_id);
100
101 dst->proxy_cnt = src->proxy_cnt;
102 for (i=0; i<src->proxy_cnt; ++i)
103 pj_strdup_with_null(pool, &dst->proxy[i], &src->proxy[i]);
104
105 dst->reg_timeout = src->reg_timeout;
106 dst->reg_delay_before_refresh = src->reg_delay_before_refresh;
107 dst->cred_count = src->cred_count;
108
109 for (i=0; i<src->cred_count; ++i) {
110 pjsip_cred_dup(pool, &dst->cred_info[i], &src->cred_info[i]);
111 }
112
113 pj_list_init(&dst->reg_hdr_list);
114 if (!pj_list_empty(&src->reg_hdr_list)) {
115 const pjsip_hdr *hdr;
116
117 hdr = src->reg_hdr_list.next;
118 while (hdr != &src->reg_hdr_list) {
119 pj_list_push_back(&dst->reg_hdr_list, pjsip_hdr_clone(pool, hdr));
120 hdr = hdr->next;
121 }
122 }
123
124 pj_list_init(&dst->sub_hdr_list);
125 if (!pj_list_empty(&src->sub_hdr_list)) {
126 const pjsip_hdr *hdr;
127
128 hdr = src->sub_hdr_list.next;
129 while (hdr != &src->sub_hdr_list) {
130 pj_list_push_back(&dst->sub_hdr_list, pjsip_hdr_clone(pool, hdr));
131 hdr = hdr->next;
132 }
133 }
134
135 pjsip_auth_clt_pref_dup(pool, &dst->auth_pref, &src->auth_pref);
136
137 pjsua_transport_config_dup(pool, &dst->rtp_cfg, &src->rtp_cfg);
138
139 pjsua_ice_config_dup(pool, &dst->ice_cfg, &src->ice_cfg);
140 pjsua_turn_config_dup(pool, &dst->turn_cfg, &src->turn_cfg);
141
142 pjsua_srtp_opt_dup(pool, &dst->srtp_opt, &src->srtp_opt, PJ_FALSE);
143
144 pj_strdup(pool, &dst->ka_data, &src->ka_data);
145
146 pjmedia_rtcp_fb_setting_dup(pool, &dst->rtcp_fb_cfg, &src->rtcp_fb_cfg);
147 }
148
149 /*
150 * Calculate CRC of proxy list.
151 */
calc_proxy_crc(const pj_str_t proxy[],pj_size_t cnt)152 static pj_uint32_t calc_proxy_crc(const pj_str_t proxy[], pj_size_t cnt)
153 {
154 pj_crc32_context ctx;
155 unsigned i;
156
157 pj_crc32_init(&ctx);
158 for (i=0; i<cnt; ++i) {
159 pj_crc32_update(&ctx, (pj_uint8_t*)proxy[i].ptr, proxy[i].slen);
160 }
161
162 return pj_crc32_final(&ctx);
163 }
164
165 /*
166 * Initialize outbound settings.
167 */
init_outbound_setting(pjsua_acc * acc)168 static void init_outbound_setting(pjsua_acc *acc)
169 {
170 pjsua_acc_config *acc_cfg = &acc->cfg;
171 if (acc_cfg->rfc5626_instance_id.slen == 0) {
172 const pj_str_t *hostname;
173 pj_uint32_t hval;
174 pj_size_t pos;
175 char instprm[] = ";+sip.instance=\"<urn:uuid:00000000-0000-0000-0000-0000CCDDEEFF>\"";
176
177 hostname = pj_gethostname();
178 pos = pj_ansi_strlen(instprm) - 10;
179 hval = pj_hash_calc(0, hostname->ptr, (unsigned)hostname->slen);
180 pj_val_to_hex_digit(((char*)&hval)[0], instprm + pos + 0);
181 pj_val_to_hex_digit(((char*)&hval)[1], instprm + pos + 2);
182 pj_val_to_hex_digit(((char*)&hval)[2], instprm + pos + 4);
183 pj_val_to_hex_digit(((char*)&hval)[3], instprm + pos + 6);
184
185 pj_strdup2(acc->pool, &acc->rfc5626_instprm, instprm);
186 } else {
187 const char *prmname = ";+sip.instance=\"";
188 pj_size_t len;
189
190 len = pj_ansi_strlen(prmname) + acc_cfg->rfc5626_instance_id.slen + 1;
191 acc->rfc5626_instprm.ptr = (char*)pj_pool_alloc(acc->pool, len + 1);
192 pj_ansi_snprintf(acc->rfc5626_instprm.ptr, len + 1,
193 "%s%.*s\"",
194 prmname,
195 (int)acc_cfg->rfc5626_instance_id.slen,
196 acc_cfg->rfc5626_instance_id.ptr);
197 acc->rfc5626_instprm.slen = len;
198 }
199
200 if (acc_cfg->rfc5626_reg_id.slen == 0) {
201 acc->rfc5626_regprm = pj_str(";reg-id=1");
202 } else {
203 const char *prmname = ";reg-id=";
204 pj_size_t len;
205
206 len = pj_ansi_strlen(prmname) + acc_cfg->rfc5626_reg_id.slen;
207 acc->rfc5626_regprm.ptr = (char*)pj_pool_alloc(acc->pool, len + 1);
208 pj_ansi_snprintf(acc->rfc5626_regprm.ptr, len + 1,
209 "%s%.*s\"",
210 prmname,
211 (int)acc_cfg->rfc5626_reg_id.slen,
212 acc_cfg->rfc5626_reg_id.ptr);
213 acc->rfc5626_regprm.slen = len;
214 }
215
216 acc->rfc5626_status = OUTBOUND_WANTED;
217 }
218
219 /*
220 * Initialize a new account (after configuration is set).
221 */
initialize_acc(unsigned acc_id)222 static pj_status_t initialize_acc(unsigned acc_id)
223 {
224 pjsua_acc_config *acc_cfg = &pjsua_var.acc[acc_id].cfg;
225 pjsua_acc *acc = &pjsua_var.acc[acc_id];
226 pjsip_name_addr *name_addr;
227 pjsip_sip_uri *sip_reg_uri;
228 pj_status_t status;
229 unsigned i;
230
231 /* Need to parse local_uri to get the elements: */
232
233 name_addr = (pjsip_name_addr*)
234 pjsip_parse_uri(acc->pool, acc_cfg->id.ptr,
235 acc_cfg->id.slen,
236 PJSIP_PARSE_URI_AS_NAMEADDR);
237 if (name_addr == NULL) {
238 pjsua_perror(THIS_FILE, "Invalid local URI",
239 PJSIP_EINVALIDURI);
240 return PJSIP_EINVALIDURI;
241 }
242
243 /* Local URI MUST be a SIP or SIPS: */
244 if (!PJSIP_URI_SCHEME_IS_SIP(name_addr) &&
245 !PJSIP_URI_SCHEME_IS_SIPS(name_addr))
246 {
247 acc->display = name_addr->display;
248 acc->user_part = name_addr->display;
249 acc->srv_domain = pj_str("");
250 acc->srv_port = 0;
251 } else {
252 pjsip_sip_uri *sip_uri;
253
254 /* Get the SIP URI object: */
255 sip_uri = (pjsip_sip_uri*) pjsip_uri_get_uri(name_addr);
256
257 /* Save the user and domain part. These will be used when finding an
258 * account for incoming requests.
259 */
260 acc->display = name_addr->display;
261 acc->user_part = sip_uri->user;
262 acc->srv_domain = sip_uri->host;
263 acc->srv_port = 0;
264
265 /* Escape user part (ticket #2010) */
266 if (acc->user_part.slen) {
267 const pjsip_parser_const_t *pconst;
268 char buf[PJSIP_MAX_URL_SIZE];
269 pj_str_t user_part;
270
271 pconst = pjsip_parser_const();
272 pj_strset(&user_part, buf, sizeof(buf));
273 pj_strncpy_escape(&user_part, &sip_uri->user, sizeof(buf),
274 &pconst->pjsip_USER_SPEC_LENIENT);
275 if (user_part.slen > acc->user_part.slen)
276 pj_strdup(acc->pool, &acc->user_part, &user_part);
277 }
278 }
279 acc->is_sips = PJSIP_URI_SCHEME_IS_SIPS(name_addr);
280
281
282 /* Parse registrar URI, if any */
283 if (acc_cfg->reg_uri.slen) {
284 pjsip_uri *reg_uri;
285
286 reg_uri = pjsip_parse_uri(acc->pool, acc_cfg->reg_uri.ptr,
287 acc_cfg->reg_uri.slen, 0);
288 if (reg_uri == NULL) {
289 pjsua_perror(THIS_FILE, "Invalid registrar URI",
290 PJSIP_EINVALIDURI);
291 return PJSIP_EINVALIDURI;
292 }
293
294 /* Registrar URI MUST be a SIP or SIPS: */
295 if (!PJSIP_URI_SCHEME_IS_SIP(reg_uri) &&
296 !PJSIP_URI_SCHEME_IS_SIPS(reg_uri))
297 {
298 pjsua_perror(THIS_FILE, "Invalid registar URI",
299 PJSIP_EINVALIDSCHEME);
300 return PJSIP_EINVALIDSCHEME;
301 }
302
303 sip_reg_uri = (pjsip_sip_uri*) pjsip_uri_get_uri(reg_uri);
304
305 } else {
306 sip_reg_uri = NULL;
307 }
308
309 if (sip_reg_uri) {
310 acc->srv_port = sip_reg_uri->port;
311 }
312
313 /* Create Contact header if not present. */
314 //if (acc_cfg->contact.slen == 0) {
315 // acc_cfg->contact = acc_cfg->id;
316 //}
317
318 /* Build account route-set from outbound proxies and route set from
319 * account configuration.
320 */
321 pj_list_init(&acc->route_set);
322
323 if (!pj_list_empty(&pjsua_var.outbound_proxy)) {
324 pjsip_route_hdr *r;
325
326 r = pjsua_var.outbound_proxy.next;
327 while (r != &pjsua_var.outbound_proxy) {
328 pj_list_push_back(&acc->route_set,
329 pjsip_hdr_shallow_clone(acc->pool, r));
330 r = r->next;
331 }
332 }
333
334 for (i=0; i<acc_cfg->proxy_cnt; ++i) {
335 pj_str_t hname = { "Route", 5};
336 pjsip_route_hdr *r;
337 pj_str_t tmp;
338
339 pj_strdup_with_null(acc->pool, &tmp, &acc_cfg->proxy[i]);
340 r = (pjsip_route_hdr*)
341 pjsip_parse_hdr(acc->pool, &hname, tmp.ptr, tmp.slen, NULL);
342 if (r == NULL) {
343 pjsua_perror(THIS_FILE, "Invalid URI in account route set",
344 PJ_EINVAL);
345 return PJ_EINVAL;
346 }
347 pj_list_push_back(&acc->route_set, r);
348 }
349
350 /* Concatenate credentials from account config and global config */
351 acc->cred_cnt = 0;
352 for (i=0; i<acc_cfg->cred_count; ++i) {
353 acc->cred[acc->cred_cnt++] = acc_cfg->cred_info[i];
354 }
355 for (i=0; i<pjsua_var.ua_cfg.cred_count &&
356 acc->cred_cnt < PJ_ARRAY_SIZE(acc->cred); ++i)
357 {
358 acc->cred[acc->cred_cnt++] = pjsua_var.ua_cfg.cred_info[i];
359 }
360
361 /* If account's ICE and TURN customization is not set, then
362 * initialize it with the settings from the global media config.
363 */
364 if (acc->cfg.ice_cfg_use == PJSUA_ICE_CONFIG_USE_DEFAULT) {
365 pjsua_ice_config_from_media_config(NULL, &acc->cfg.ice_cfg,
366 &pjsua_var.media_cfg);
367 }
368 if (acc->cfg.turn_cfg_use == PJSUA_TURN_CONFIG_USE_DEFAULT) {
369 pjsua_turn_config_from_media_config(NULL, &acc->cfg.turn_cfg,
370 &pjsua_var.media_cfg);
371 }
372
373 /* If ICE is enabled, add "+sip.ice" media feature tag in account's
374 * contact params.
375 */
376 #if PJSUA_ADD_ICE_TAGS
377 if (acc_cfg->ice_cfg.enable_ice) {
378 pj_ssize_t new_len;
379 pj_str_t new_prm;
380
381 new_len = acc_cfg->contact_params.slen + 10;
382 new_prm.ptr = (char*)pj_pool_alloc(acc->pool, new_len);
383 pj_strcpy(&new_prm, &acc_cfg->contact_params);
384 pj_strcat2(&new_prm, ";+sip.ice");
385 acc_cfg->contact_params = new_prm;
386 }
387 #endif
388
389 status = pjsua_pres_init_acc(acc_id);
390 if (status != PJ_SUCCESS)
391 return status;
392
393 /* If SIP outbound is enabled, generate instance and reg ID if they are
394 * not specified
395 */
396 if (acc_cfg->use_rfc5626) {
397 init_outbound_setting(acc);
398 }
399
400 /* Mark account as valid */
401 pjsua_var.acc[acc_id].valid = PJ_TRUE;
402
403 /* Insert account ID into account ID array, sorted by priority */
404 for (i=0; i<pjsua_var.acc_cnt; ++i) {
405 if ( pjsua_var.acc[pjsua_var.acc_ids[i]].cfg.priority <
406 pjsua_var.acc[acc_id].cfg.priority)
407 {
408 break;
409 }
410 }
411 pj_array_insert(pjsua_var.acc_ids, sizeof(pjsua_var.acc_ids[0]),
412 pjsua_var.acc_cnt, i, &acc_id);
413
414 if (acc_cfg->transport_id != PJSUA_INVALID_ID)
415 acc->tp_type = pjsua_var.tpdata[acc_cfg->transport_id].type;
416
417 acc->ip_change_op = PJSUA_IP_CHANGE_OP_NULL;
418
419 return PJ_SUCCESS;
420 }
421
422
423 /*
424 * Add a new account to pjsua.
425 */
pjsua_acc_add(const pjsua_acc_config * cfg,pj_bool_t is_default,pjsua_acc_id * p_acc_id)426 PJ_DEF(pj_status_t) pjsua_acc_add( const pjsua_acc_config *cfg,
427 pj_bool_t is_default,
428 pjsua_acc_id *p_acc_id)
429 {
430 pjsua_acc *acc;
431 unsigned i, id;
432 pj_status_t status = PJ_SUCCESS;
433
434 PJ_ASSERT_RETURN(cfg, PJ_EINVAL);
435 PJ_ASSERT_RETURN(pjsua_var.acc_cnt < PJ_ARRAY_SIZE(pjsua_var.acc),
436 PJ_ETOOMANY);
437
438 /* Must have a transport */
439 PJ_ASSERT_RETURN(pjsua_var.tpdata[0].data.ptr != NULL, PJ_EINVALIDOP);
440
441 PJ_LOG(4,(THIS_FILE, "Adding account: id=%.*s",
442 (int)cfg->id.slen, cfg->id.ptr));
443 pj_log_push_indent();
444
445 PJSUA_LOCK();
446
447 /* Find empty account id. */
448 for (id=0; id < PJ_ARRAY_SIZE(pjsua_var.acc); ++id) {
449 if (pjsua_var.acc[id].valid == PJ_FALSE)
450 break;
451 }
452
453 /* Expect to find a slot */
454 PJ_ASSERT_ON_FAIL( id < PJ_ARRAY_SIZE(pjsua_var.acc),
455 {PJSUA_UNLOCK(); return PJ_EBUG;});
456
457 acc = &pjsua_var.acc[id];
458
459 /* Create pool for this account. */
460 if (acc->pool)
461 pj_pool_reset(acc->pool);
462 else
463 acc->pool = pjsua_pool_create("acc%p", PJSUA_POOL_LEN_ACC,
464 PJSUA_POOL_INC_ACC);
465
466 /* Copy config */
467 pjsua_acc_config_dup(acc->pool, &pjsua_var.acc[id].cfg, cfg);
468
469 /* Normalize registration timeout and refresh delay */
470 if (pjsua_var.acc[id].cfg.reg_uri.slen) {
471 if (pjsua_var.acc[id].cfg.reg_timeout == 0) {
472 pjsua_var.acc[id].cfg.reg_timeout = PJSUA_REG_INTERVAL;
473 }
474 if (pjsua_var.acc[id].cfg.reg_delay_before_refresh == 0) {
475 pjsua_var.acc[id].cfg.reg_delay_before_refresh =
476 PJSIP_REGISTER_CLIENT_DELAY_BEFORE_REFRESH;
477 }
478 }
479
480 /* Check the route URI's and force loose route if required */
481 for (i=0; i<acc->cfg.proxy_cnt; ++i) {
482 status = normalize_route_uri(acc->pool, &acc->cfg.proxy[i]);
483 if (status != PJ_SUCCESS) {
484 PJSUA_UNLOCK();
485 pj_log_pop_indent();
486 return status;
487 }
488 }
489
490 /* Get CRC of account proxy setting */
491 acc->local_route_crc = calc_proxy_crc(acc->cfg.proxy, acc->cfg.proxy_cnt);
492
493 /* Get CRC of global outbound proxy setting */
494 acc->global_route_crc=calc_proxy_crc(pjsua_var.ua_cfg.outbound_proxy,
495 pjsua_var.ua_cfg.outbound_proxy_cnt);
496
497 status = initialize_acc(id);
498 if (status != PJ_SUCCESS) {
499 pjsua_perror(THIS_FILE, "Error adding account", status);
500 pj_pool_release(acc->pool);
501 acc->pool = NULL;
502 PJSUA_UNLOCK();
503 pj_log_pop_indent();
504 return status;
505 }
506
507 if (is_default)
508 pjsua_var.default_acc = id;
509
510 if (p_acc_id)
511 *p_acc_id = id;
512
513 pjsua_var.acc_cnt++;
514
515 PJSUA_UNLOCK();
516
517 PJ_LOG(4,(THIS_FILE, "Account %.*s added with id %d",
518 (int)cfg->id.slen, cfg->id.ptr, id));
519
520 /* If accounts has registration enabled, start registration */
521 if (pjsua_var.acc[id].cfg.reg_uri.slen) {
522 if (pjsua_var.acc[id].cfg.register_on_acc_add)
523 pjsua_acc_set_registration(id, PJ_TRUE);
524 } else {
525 /* Otherwise subscribe to MWI, if it's enabled */
526 if (pjsua_var.acc[id].cfg.mwi_enabled)
527 pjsua_start_mwi(id, PJ_TRUE);
528
529 /* Start publish too */
530 if (acc->cfg.publish_enabled)
531 pjsua_pres_init_publish_acc(id);
532 }
533
534 pj_log_pop_indent();
535 return PJ_SUCCESS;
536 }
537
538
539 /*
540 * Add local account
541 */
pjsua_acc_add_local(pjsua_transport_id tid,pj_bool_t is_default,pjsua_acc_id * p_acc_id)542 PJ_DEF(pj_status_t) pjsua_acc_add_local( pjsua_transport_id tid,
543 pj_bool_t is_default,
544 pjsua_acc_id *p_acc_id)
545 {
546 pjsua_acc_config cfg;
547 pjsua_transport_data *t = &pjsua_var.tpdata[tid];
548 char transport_param[32];
549 char uri[PJSIP_MAX_URL_SIZE];
550 char addr_buf[PJ_INET6_ADDRSTRLEN+10];
551 pjsua_acc_id acc_id;
552 pj_status_t status;
553
554 /* ID must be valid */
555 PJ_ASSERT_RETURN(tid>=0 && tid<(int)PJ_ARRAY_SIZE(pjsua_var.tpdata),
556 PJ_EINVAL);
557
558 /* Transport must be valid */
559 PJ_ASSERT_RETURN(t->data.ptr != NULL, PJ_EINVAL);
560
561 pjsua_acc_config_default(&cfg);
562
563 /* Lower the priority of local account */
564 --cfg.priority;
565
566 /* Don't add transport parameter if it's UDP */
567 if (t->type!=PJSIP_TRANSPORT_UDP && t->type!=PJSIP_TRANSPORT_UDP6) {
568 pj_ansi_snprintf(transport_param, sizeof(transport_param),
569 ";transport=%s",
570 pjsip_transport_get_type_name(t->type));
571 } else {
572 transport_param[0] = '\0';
573 }
574
575 /* Build URI for the account */
576 pj_ansi_snprintf(uri, PJSIP_MAX_URL_SIZE,
577 "<sip:%s%s>",
578 pj_addr_str_print(&t->local_name.host, t->local_name.port,
579 addr_buf, sizeof(addr_buf), 1),
580 transport_param);
581
582 cfg.id = pj_str(uri);
583 cfg.transport_id = tid;
584
585 status = pjsua_acc_add(&cfg, is_default, &acc_id);
586 if (status == PJ_SUCCESS) {
587 pjsua_var.acc[acc_id].tp_type = t->type;
588 if (p_acc_id)
589 *p_acc_id = acc_id;
590 }
591
592 return status;
593 }
594
595
596 /*
597 * Set arbitrary data to be associated with the account.
598 */
pjsua_acc_set_user_data(pjsua_acc_id acc_id,void * user_data)599 PJ_DEF(pj_status_t) pjsua_acc_set_user_data(pjsua_acc_id acc_id,
600 void *user_data)
601 {
602 PJ_ASSERT_RETURN(acc_id>=0 && acc_id<(int)PJ_ARRAY_SIZE(pjsua_var.acc),
603 PJ_EINVAL);
604 PJ_ASSERT_RETURN(pjsua_var.acc[acc_id].valid, PJ_EINVALIDOP);
605
606 PJSUA_LOCK();
607
608 pjsua_var.acc[acc_id].cfg.user_data = user_data;
609
610 PJSUA_UNLOCK();
611
612 return PJ_SUCCESS;
613 }
614
615
616 /*
617 * Retrieve arbitrary data associated with the account.
618 */
pjsua_acc_get_user_data(pjsua_acc_id acc_id)619 PJ_DEF(void*) pjsua_acc_get_user_data(pjsua_acc_id acc_id)
620 {
621 PJ_ASSERT_RETURN(acc_id>=0 && acc_id<(int)PJ_ARRAY_SIZE(pjsua_var.acc),
622 NULL);
623 PJ_ASSERT_RETURN(pjsua_var.acc[acc_id].valid, NULL);
624
625 return pjsua_var.acc[acc_id].cfg.user_data;
626 }
627
628
629 /*
630 * Delete account.
631 */
pjsua_acc_del(pjsua_acc_id acc_id)632 PJ_DEF(pj_status_t) pjsua_acc_del(pjsua_acc_id acc_id)
633 {
634 pjsua_acc *acc;
635 unsigned i;
636
637 PJ_ASSERT_RETURN(acc_id>=0 && acc_id<(int)PJ_ARRAY_SIZE(pjsua_var.acc),
638 PJ_EINVAL);
639 PJ_ASSERT_RETURN(pjsua_var.acc[acc_id].valid, PJ_EINVALIDOP);
640
641 PJ_LOG(4,(THIS_FILE, "Deleting account %d..", acc_id));
642 pj_log_push_indent();
643
644 PJSUA_LOCK();
645
646 acc = &pjsua_var.acc[acc_id];
647
648 /* Cancel keep-alive timer, if any */
649 if (acc->ka_timer.id) {
650 pjsip_endpt_cancel_timer(pjsua_var.endpt, &acc->ka_timer);
651 acc->ka_timer.id = PJ_FALSE;
652 }
653 if (acc->ka_transport) {
654 pjsip_transport_dec_ref(acc->ka_transport);
655 acc->ka_transport = NULL;
656 }
657
658 /* Cancel any re-registration timer */
659 if (acc->auto_rereg.timer.id) {
660 acc->auto_rereg.timer.id = PJ_FALSE;
661 pjsua_cancel_timer(&acc->auto_rereg.timer);
662 }
663
664 /* Delete registration */
665 if (acc->regc != NULL) {
666 pjsua_acc_set_registration(acc_id, PJ_FALSE);
667 if (acc->regc) {
668 pjsip_regc_destroy(acc->regc);
669 }
670 acc->regc = NULL;
671 }
672
673 /* Terminate mwi subscription */
674 if (acc->cfg.mwi_enabled) {
675 acc->cfg.mwi_enabled = PJ_FALSE;
676 pjsua_start_mwi(acc_id, PJ_FALSE);
677 }
678
679 /* Delete server presence subscription */
680 pjsua_pres_delete_acc(acc_id, 0);
681
682 /* Release account pool */
683 if (acc->pool) {
684 pj_pool_release(acc->pool);
685 acc->pool = NULL;
686 }
687
688 /* Invalidate */
689 acc->valid = PJ_FALSE;
690 acc->contact.slen = 0;
691 acc->reg_mapped_addr.slen = 0;
692 acc->rfc5626_status = OUTBOUND_UNKNOWN;
693 pj_bzero(&acc->via_addr, sizeof(acc->via_addr));
694 acc->via_tp = NULL;
695 acc->next_rtp_port = 0;
696 acc->ip_change_op = PJSUA_IP_CHANGE_OP_NULL;
697
698 /* Remove from array */
699 for (i=0; i<pjsua_var.acc_cnt; ++i) {
700 if (pjsua_var.acc_ids[i] == acc_id)
701 break;
702 }
703 if (i != pjsua_var.acc_cnt) {
704 pj_array_erase(pjsua_var.acc_ids, sizeof(pjsua_var.acc_ids[0]),
705 pjsua_var.acc_cnt, i);
706 --pjsua_var.acc_cnt;
707 }
708
709 /* Leave the calls intact, as I don't think calls need to
710 * access account once it's created
711 */
712
713 /* Update default account */
714 if (pjsua_var.default_acc == acc_id)
715 pjsua_var.default_acc = 0;
716
717 #if PJ_HAS_SSL_SOCK
718 pj_turn_sock_tls_cfg_wipe_keys(&acc->cfg.turn_cfg.turn_tls_setting);
719 #endif
720
721 PJSUA_UNLOCK();
722
723 PJ_LOG(4,(THIS_FILE, "Account id %d deleted", acc_id));
724
725 pj_log_pop_indent();
726 return PJ_SUCCESS;
727 }
728
729
730 /* Get config */
pjsua_acc_get_config(pjsua_acc_id acc_id,pj_pool_t * pool,pjsua_acc_config * acc_cfg)731 PJ_DEF(pj_status_t) pjsua_acc_get_config(pjsua_acc_id acc_id,
732 pj_pool_t *pool,
733 pjsua_acc_config *acc_cfg)
734 {
735 PJ_ASSERT_RETURN(acc_id>=0 && acc_id<(int)PJ_ARRAY_SIZE(pjsua_var.acc)
736 && pjsua_var.acc[acc_id].valid, PJ_EINVAL);
737 //this now would not work due to corrupt header list
738 //pj_memcpy(acc_cfg, &pjsua_var.acc[acc_id].cfg, sizeof(*acc_cfg));
739 pjsua_acc_config_dup(pool, acc_cfg, &pjsua_var.acc[acc_id].cfg);
740 return PJ_SUCCESS;
741 }
742
743 /* Compare two SIP headers. Return zero if equal */
pjsip_hdr_cmp(const pjsip_hdr * h1,const pjsip_hdr * h2)744 static int pjsip_hdr_cmp(const pjsip_hdr *h1, const pjsip_hdr *h2)
745 {
746 char buf1[PJSIP_MAX_URL_SIZE];
747 char buf2[PJSIP_MAX_URL_SIZE];
748 pj_str_t p1, p2;
749
750 p1.ptr = buf1;
751 p1.slen = 0;
752 p2.ptr = buf2;
753 p2.slen = 0;
754
755 p1.slen = pjsip_hdr_print_on((void*)h1, buf1, sizeof(buf1));
756 if (p1.slen < 0)
757 p1.slen = 0;
758 p2.slen = pjsip_hdr_print_on((void*)h2, buf2, sizeof(buf2));
759 if (p2.slen < 0)
760 p2.slen = 0;
761
762 return pj_strcmp(&p1, &p2);
763 }
764
765 /* Update SIP header list from another list. Return PJ_TRUE if
766 * the list has been updated */
update_hdr_list(pj_pool_t * pool,pjsip_hdr * dst,const pjsip_hdr * src)767 static pj_bool_t update_hdr_list(pj_pool_t *pool, pjsip_hdr *dst,
768 const pjsip_hdr *src)
769 {
770 pjsip_hdr *dst_i;
771 const pjsip_hdr *src_i;
772 pj_bool_t changed = PJ_FALSE;
773
774 /* Remove header that's no longer needed */
775 for (dst_i = dst->next; dst_i != dst; ) {
776 for (src_i = src->next; src_i != src; src_i = src_i->next) {
777 if (pjsip_hdr_cmp(dst_i, src_i) == 0)
778 break;
779 }
780 if (src_i == src) {
781 pjsip_hdr *next = dst_i->next;
782 pj_list_erase(dst_i);
783 changed = PJ_TRUE;
784 dst_i = next;
785 } else {
786 dst_i = dst_i->next;
787 }
788 }
789
790 /* Add new header */
791 for (src_i = src->next; src_i != src; src_i = src_i->next) {
792 for (dst_i = dst->next; dst_i != dst; dst_i = dst_i->next) {
793 if (pjsip_hdr_cmp(dst_i, src_i) == 0)
794 break;
795 }
796 if (dst_i == dst) {
797 dst_i = pjsip_hdr_clone(pool, src_i);
798 pj_list_push_back(dst, dst_i);
799 changed = PJ_TRUE;
800 }
801 }
802
803 return changed;
804 }
805
806 /*
807 * Modify account information.
808 */
pjsua_acc_modify(pjsua_acc_id acc_id,const pjsua_acc_config * cfg)809 PJ_DEF(pj_status_t) pjsua_acc_modify( pjsua_acc_id acc_id,
810 const pjsua_acc_config *cfg)
811 {
812 pjsua_acc *acc;
813 pjsip_name_addr *id_name_addr = NULL;
814 pjsip_sip_uri *id_sip_uri = NULL;
815 pjsip_sip_uri *reg_sip_uri = NULL;
816 pj_uint32_t local_route_crc, global_route_crc;
817 pjsip_route_hdr global_route;
818 pjsip_route_hdr local_route;
819 pj_str_t acc_proxy[PJSUA_ACC_MAX_PROXIES];
820 pj_bool_t update_reg = PJ_FALSE;
821 pj_bool_t unreg_first = PJ_FALSE;
822 pj_bool_t update_mwi = PJ_FALSE;
823 pj_status_t status = PJ_SUCCESS;
824
825 PJ_ASSERT_RETURN(acc_id>=0 && acc_id<(int)PJ_ARRAY_SIZE(pjsua_var.acc),
826 PJ_EINVAL);
827
828 PJ_LOG(4,(THIS_FILE, "Modifying account %d", acc_id));
829 pj_log_push_indent();
830
831 PJSUA_LOCK();
832
833 acc = &pjsua_var.acc[acc_id];
834 if (!acc->valid) {
835 status = PJ_EINVAL;
836 goto on_return;
837 }
838
839 /* == Validate first == */
840
841 /* Account id */
842 if (pj_strcmp(&acc->cfg.id, &cfg->id)) {
843 /* Need to parse id to get the elements: */
844 id_name_addr = (pjsip_name_addr*)
845 pjsip_parse_uri(acc->pool, cfg->id.ptr, cfg->id.slen,
846 PJSIP_PARSE_URI_AS_NAMEADDR);
847 if (id_name_addr == NULL) {
848 status = PJSIP_EINVALIDURI;
849 pjsua_perror(THIS_FILE, "Invalid local URI", status);
850 goto on_return;
851 }
852
853 /* URI MUST be a SIP or SIPS: */
854 if (!PJSIP_URI_SCHEME_IS_SIP(id_name_addr) &&
855 !PJSIP_URI_SCHEME_IS_SIPS(id_name_addr))
856 {
857 status = PJSIP_EINVALIDSCHEME;
858 pjsua_perror(THIS_FILE, "Invalid local URI", status);
859 goto on_return;
860 }
861
862 /* Get the SIP URI object: */
863 id_sip_uri = (pjsip_sip_uri*) pjsip_uri_get_uri(id_name_addr);
864 }
865
866 /* Registrar URI */
867 if (pj_strcmp(&acc->cfg.reg_uri, &cfg->reg_uri) && cfg->reg_uri.slen) {
868 pjsip_uri *reg_uri;
869
870 /* Need to parse reg_uri to get the elements: */
871 reg_uri = pjsip_parse_uri(acc->pool, cfg->reg_uri.ptr,
872 cfg->reg_uri.slen, 0);
873 if (reg_uri == NULL) {
874 status = PJSIP_EINVALIDURI;
875 pjsua_perror(THIS_FILE, "Invalid registrar URI", status);
876 goto on_return;
877 }
878
879 /* Registrar URI MUST be a SIP or SIPS: */
880 if (!PJSIP_URI_SCHEME_IS_SIP(reg_uri) &&
881 !PJSIP_URI_SCHEME_IS_SIPS(reg_uri))
882 {
883 status = PJSIP_EINVALIDSCHEME;
884 pjsua_perror(THIS_FILE, "Invalid registar URI", status);
885 goto on_return;
886 }
887
888 reg_sip_uri = (pjsip_sip_uri*) pjsip_uri_get_uri(reg_uri);
889 }
890
891 /* REGISTER header list */
892 if (update_hdr_list(acc->pool, &acc->cfg.reg_hdr_list, &cfg->reg_hdr_list)) {
893 update_reg = PJ_TRUE;
894 unreg_first = PJ_TRUE;
895 }
896
897 /* SUBSCRIBE header list */
898 update_hdr_list(acc->pool, &acc->cfg.sub_hdr_list, &cfg->sub_hdr_list);
899
900 /* Global outbound proxy */
901 global_route_crc = calc_proxy_crc(pjsua_var.ua_cfg.outbound_proxy,
902 pjsua_var.ua_cfg.outbound_proxy_cnt);
903 if (global_route_crc != acc->global_route_crc) {
904 pjsip_route_hdr *r;
905
906 /* Copy from global outbound proxies */
907 pj_list_init(&global_route);
908 r = pjsua_var.outbound_proxy.next;
909 while (r != &pjsua_var.outbound_proxy) {
910 pj_list_push_back(&global_route,
911 pjsip_hdr_shallow_clone(acc->pool, r));
912 r = r->next;
913 }
914 }
915
916 /* Account proxy */
917 local_route_crc = calc_proxy_crc(cfg->proxy, cfg->proxy_cnt);
918 if (local_route_crc != acc->local_route_crc) {
919 pjsip_route_hdr *r;
920 unsigned i;
921
922 /* Validate the local route and save it to temporary var */
923 pj_list_init(&local_route);
924 for (i=0; i<cfg->proxy_cnt; ++i) {
925 pj_str_t hname = { "Route", 5};
926
927 pj_strdup_with_null(acc->pool, &acc_proxy[i], &cfg->proxy[i]);
928 status = normalize_route_uri(acc->pool, &acc_proxy[i]);
929 if (status != PJ_SUCCESS)
930 goto on_return;
931 r = (pjsip_route_hdr*)
932 pjsip_parse_hdr(acc->pool, &hname, acc_proxy[i].ptr,
933 acc_proxy[i].slen, NULL);
934 if (r == NULL) {
935 status = PJSIP_EINVALIDURI;
936 pjsua_perror(THIS_FILE, "Invalid URI in account route set",
937 status);
938 goto on_return;
939 }
940
941 pj_list_push_back(&local_route, r);
942 }
943
944 /* Recalculate the CRC again after route URI normalization */
945 local_route_crc = calc_proxy_crc(acc_proxy, cfg->proxy_cnt);
946 }
947
948
949 /* == Apply the new config == */
950
951 /* Account ID. */
952 if (id_name_addr && id_sip_uri) {
953 pj_strdup_with_null(acc->pool, &acc->cfg.id, &cfg->id);
954 pj_strdup_with_null(acc->pool, &acc->display, &id_name_addr->display);
955 pj_strdup_with_null(acc->pool, &acc->user_part, &id_sip_uri->user);
956 pj_strdup_with_null(acc->pool, &acc->srv_domain, &id_sip_uri->host);
957 acc->srv_port = 0;
958 acc->is_sips = PJSIP_URI_SCHEME_IS_SIPS(id_name_addr);
959 update_reg = PJ_TRUE;
960 unreg_first = PJ_TRUE;
961 }
962
963 /* User data */
964 acc->cfg.user_data = cfg->user_data;
965
966 /* Priority */
967 if (acc->cfg.priority != cfg->priority) {
968 unsigned i;
969
970 acc->cfg.priority = cfg->priority;
971
972 /* Resort accounts priority */
973 for (i=0; i<pjsua_var.acc_cnt; ++i) {
974 if (pjsua_var.acc_ids[i] == acc_id)
975 break;
976 }
977 pj_assert(i < pjsua_var.acc_cnt);
978 pj_array_erase(pjsua_var.acc_ids, sizeof(acc_id),
979 pjsua_var.acc_cnt, i);
980 for (i=0; i<pjsua_var.acc_cnt; ++i) {
981 if (pjsua_var.acc[pjsua_var.acc_ids[i]].cfg.priority <
982 acc->cfg.priority)
983 {
984 break;
985 }
986 }
987 pj_array_insert(pjsua_var.acc_ids, sizeof(acc_id),
988 pjsua_var.acc_cnt, i, &acc_id);
989 }
990
991 /* MWI */
992 if (acc->cfg.mwi_enabled != cfg->mwi_enabled) {
993 acc->cfg.mwi_enabled = cfg->mwi_enabled;
994 update_mwi = PJ_TRUE;
995 }
996 if (acc->cfg.mwi_expires != cfg->mwi_expires && cfg->mwi_expires > 0) {
997 acc->cfg.mwi_expires = cfg->mwi_expires;
998 update_mwi = PJ_TRUE;
999 }
1000
1001 /* PIDF tuple ID */
1002 if (pj_strcmp(&acc->cfg.pidf_tuple_id, &cfg->pidf_tuple_id))
1003 pj_strdup_with_null(acc->pool, &acc->cfg.pidf_tuple_id,
1004 &cfg->pidf_tuple_id);
1005
1006 /* Publish */
1007 acc->cfg.publish_opt = cfg->publish_opt;
1008 acc->cfg.unpublish_max_wait_time_msec = cfg->unpublish_max_wait_time_msec;
1009 if (acc->cfg.publish_enabled != cfg->publish_enabled) {
1010 acc->cfg.publish_enabled = cfg->publish_enabled;
1011 if (!acc->cfg.publish_enabled)
1012 pjsua_pres_unpublish(acc, 0);
1013 else
1014 update_reg = PJ_TRUE;
1015 }
1016
1017 /* Force contact URI */
1018 if (pj_strcmp(&acc->cfg.force_contact, &cfg->force_contact)) {
1019 pj_strdup_with_null(acc->pool, &acc->cfg.force_contact,
1020 &cfg->force_contact);
1021 update_reg = PJ_TRUE;
1022 unreg_first = PJ_TRUE;
1023 }
1024
1025 /* Register contact params */
1026 if (pj_strcmp(&acc->cfg.reg_contact_params, &cfg->reg_contact_params)) {
1027 pj_strdup_with_null(acc->pool, &acc->cfg.reg_contact_params,
1028 &cfg->reg_contact_params);
1029 update_reg = PJ_TRUE;
1030 unreg_first = PJ_TRUE;
1031 }
1032
1033 /* Contact param */
1034 if (pj_strcmp(&acc->cfg.contact_params, &cfg->contact_params)) {
1035 pj_strdup_with_null(acc->pool, &acc->cfg.contact_params,
1036 &cfg->contact_params);
1037 update_reg = PJ_TRUE;
1038 unreg_first = PJ_TRUE;
1039 }
1040
1041 /* Contact URI params */
1042 if (pj_strcmp(&acc->cfg.contact_uri_params, &cfg->contact_uri_params)) {
1043 pj_strdup_with_null(acc->pool, &acc->cfg.contact_uri_params,
1044 &cfg->contact_uri_params);
1045 update_reg = PJ_TRUE;
1046 unreg_first = PJ_TRUE;
1047 }
1048
1049 /* Reliable provisional response */
1050 acc->cfg.require_100rel = cfg->require_100rel;
1051
1052 /* Session timer */
1053 acc->cfg.use_timer = cfg->use_timer;
1054 acc->cfg.timer_setting = cfg->timer_setting;
1055
1056 /* Transport */
1057 if (acc->cfg.transport_id != cfg->transport_id) {
1058 acc->cfg.transport_id = cfg->transport_id;
1059
1060 if (acc->cfg.transport_id != PJSUA_INVALID_ID)
1061 acc->tp_type = pjsua_var.tpdata[acc->cfg.transport_id].type;
1062 else
1063 acc->tp_type = PJSIP_TRANSPORT_UNSPECIFIED;
1064
1065 update_reg = PJ_TRUE;
1066 unreg_first = PJ_TRUE;
1067 }
1068
1069 /* Update keep-alive */
1070 if (acc->cfg.ka_interval != cfg->ka_interval ||
1071 pj_strcmp(&acc->cfg.ka_data, &cfg->ka_data))
1072 {
1073 pjsip_transport *ka_transport = acc->ka_transport;
1074
1075 if (acc->ka_timer.id) {
1076 pjsip_endpt_cancel_timer(pjsua_var.endpt, &acc->ka_timer);
1077 acc->ka_timer.id = PJ_FALSE;
1078 }
1079 if (acc->ka_transport) {
1080 pjsip_transport_dec_ref(acc->ka_transport);
1081 acc->ka_transport = NULL;
1082 }
1083
1084 acc->cfg.ka_interval = cfg->ka_interval;
1085
1086 if (cfg->ka_interval) {
1087 if (ka_transport) {
1088 /* Keep-alive has been running so we can just restart it */
1089 pj_time_val delay;
1090
1091 pjsip_transport_add_ref(ka_transport);
1092 acc->ka_transport = ka_transport;
1093
1094 acc->ka_timer.cb = &keep_alive_timer_cb;
1095 acc->ka_timer.user_data = (void*)acc;
1096
1097 delay.sec = acc->cfg.ka_interval;
1098 delay.msec = 0;
1099 status = pjsua_schedule_timer(&acc->ka_timer, &delay);
1100 if (status == PJ_SUCCESS) {
1101 acc->ka_timer.id = PJ_TRUE;
1102 } else {
1103 pjsip_transport_dec_ref(ka_transport);
1104 acc->ka_transport = NULL;
1105 pjsua_perror(THIS_FILE, "Error starting keep-alive timer",
1106 status);
1107 }
1108
1109 } else {
1110 /* Keep-alive has not been running, we need to (re)register
1111 * first.
1112 */
1113 update_reg = PJ_TRUE;
1114 }
1115 }
1116 }
1117
1118 if (pj_strcmp(&acc->cfg.ka_data, &cfg->ka_data))
1119 pj_strdup(acc->pool, &acc->cfg.ka_data, &cfg->ka_data);
1120 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
1121 acc->cfg.use_srtp = cfg->use_srtp;
1122 acc->cfg.srtp_secure_signaling = cfg->srtp_secure_signaling;
1123 acc->cfg.srtp_optional_dup_offer = cfg->srtp_optional_dup_offer;
1124 #endif
1125
1126 #if defined(PJMEDIA_STREAM_ENABLE_KA) && (PJMEDIA_STREAM_ENABLE_KA != 0)
1127 acc->cfg.use_stream_ka = cfg->use_stream_ka;
1128 #endif
1129
1130 /* Use of proxy */
1131 if (acc->cfg.reg_use_proxy != cfg->reg_use_proxy) {
1132 acc->cfg.reg_use_proxy = cfg->reg_use_proxy;
1133 update_reg = PJ_TRUE;
1134 unreg_first = PJ_TRUE;
1135 }
1136
1137 /* Global outbound proxy */
1138 if (global_route_crc != acc->global_route_crc) {
1139 unsigned i;
1140 pj_size_t rcnt;
1141
1142 /* Remove the outbound proxies from the route set */
1143 rcnt = pj_list_size(&acc->route_set);
1144 for (i=0; i < rcnt - acc->cfg.proxy_cnt; ++i) {
1145 pjsip_route_hdr *r = acc->route_set.next;
1146 pj_list_erase(r);
1147 }
1148
1149 /* Insert the outbound proxies to the beginning of route set */
1150 pj_list_merge_first(&acc->route_set, &global_route);
1151
1152 /* Update global route CRC */
1153 acc->global_route_crc = global_route_crc;
1154
1155 update_reg = PJ_TRUE;
1156 unreg_first = PJ_TRUE;
1157 }
1158
1159 /* Account proxy */
1160 if (local_route_crc != acc->local_route_crc) {
1161 unsigned i;
1162
1163 /* Remove the current account proxies from the route set */
1164 for (i=0; i < acc->cfg.proxy_cnt; ++i) {
1165 pjsip_route_hdr *r = acc->route_set.prev;
1166 pj_list_erase(r);
1167 }
1168
1169 /* Insert new proxy setting to the route set */
1170 pj_list_merge_last(&acc->route_set, &local_route);
1171
1172 /* Update the proxy setting */
1173 acc->cfg.proxy_cnt = cfg->proxy_cnt;
1174 for (i = 0; i < cfg->proxy_cnt; ++i)
1175 acc->cfg.proxy[i] = acc_proxy[i];
1176
1177 /* Update local route CRC */
1178 acc->local_route_crc = local_route_crc;
1179
1180 update_reg = PJ_TRUE;
1181 unreg_first = PJ_TRUE;
1182 }
1183
1184 /* Credential info */
1185 {
1186 unsigned i;
1187 pj_bool_t cred_changed = PJ_FALSE;
1188
1189 /* Selective update credential info. */
1190 for (i = 0; i < cfg->cred_count; ++i) {
1191 unsigned j;
1192 pjsip_cred_info ci;
1193
1194 /* Find if this credential is already listed */
1195 for (j = i; j < acc->cfg.cred_count; ++j) {
1196 if (pjsip_cred_info_cmp(&acc->cfg.cred_info[j],
1197 &cfg->cred_info[i]) == 0)
1198 {
1199 /* Found, but different index/position, swap */
1200 if (j != i) {
1201 ci = acc->cfg.cred_info[i];
1202 acc->cfg.cred_info[i] = acc->cfg.cred_info[j];
1203 acc->cfg.cred_info[j] = ci;
1204 }
1205 break;
1206 }
1207 }
1208
1209 /* Not found, insert this */
1210 if (j == acc->cfg.cred_count) {
1211 cred_changed = PJ_TRUE;
1212
1213 /* If account credential is full, discard the last one. */
1214 if (acc->cfg.cred_count == PJ_ARRAY_SIZE(acc->cfg.cred_info)) {
1215 pj_array_erase(acc->cfg.cred_info, sizeof(pjsip_cred_info),
1216 acc->cfg.cred_count, acc->cfg.cred_count-1);
1217 acc->cfg.cred_count--;
1218 }
1219
1220 /* Insert this */
1221 pjsip_cred_info_dup(acc->pool, &ci, &cfg->cred_info[i]);
1222 pj_array_insert(acc->cfg.cred_info, sizeof(pjsip_cred_info),
1223 acc->cfg.cred_count, i, &ci);
1224 }
1225 }
1226 acc->cfg.cred_count = cfg->cred_count;
1227
1228 /* Concatenate credentials from account config and global config */
1229 acc->cred_cnt = 0;
1230 for (i=0; i<acc->cfg.cred_count; ++i) {
1231 acc->cred[acc->cred_cnt++] = acc->cfg.cred_info[i];
1232 }
1233 for (i=0; i<pjsua_var.ua_cfg.cred_count &&
1234 acc->cred_cnt < PJ_ARRAY_SIZE(acc->cred); ++i)
1235 {
1236 acc->cred[acc->cred_cnt++] = pjsua_var.ua_cfg.cred_info[i];
1237 }
1238
1239 if (cred_changed) {
1240 update_reg = PJ_TRUE;
1241 unreg_first = PJ_TRUE;
1242 }
1243 }
1244
1245 /* Authentication preference */
1246 acc->cfg.auth_pref.initial_auth = cfg->auth_pref.initial_auth;
1247 if (pj_strcmp(&acc->cfg.auth_pref.algorithm, &cfg->auth_pref.algorithm)) {
1248 pj_strdup_with_null(acc->pool, &acc->cfg.auth_pref.algorithm,
1249 &cfg->auth_pref.algorithm);
1250 update_reg = PJ_TRUE;
1251 unreg_first = PJ_TRUE;
1252 }
1253
1254 /* Registration */
1255 if (acc->cfg.reg_timeout != cfg->reg_timeout) {
1256 acc->cfg.reg_timeout = cfg->reg_timeout;
1257 if (acc->regc != NULL)
1258 pjsip_regc_update_expires(acc->regc, acc->cfg.reg_timeout);
1259
1260 update_reg = PJ_TRUE;
1261 }
1262 acc->cfg.unreg_timeout = cfg->unreg_timeout;
1263 acc->cfg.allow_contact_rewrite = cfg->allow_contact_rewrite;
1264 acc->cfg.reg_retry_interval = cfg->reg_retry_interval;
1265 acc->cfg.reg_first_retry_interval = cfg->reg_first_retry_interval;
1266 acc->cfg.reg_retry_random_interval = cfg->reg_retry_random_interval;
1267 acc->cfg.drop_calls_on_reg_fail = cfg->drop_calls_on_reg_fail;
1268 acc->cfg.register_on_acc_add = cfg->register_on_acc_add;
1269 if (acc->cfg.reg_delay_before_refresh != cfg->reg_delay_before_refresh) {
1270 acc->cfg.reg_delay_before_refresh = cfg->reg_delay_before_refresh;
1271 if (acc->regc != NULL)
1272 pjsip_regc_set_delay_before_refresh(acc->regc,
1273 cfg->reg_delay_before_refresh);
1274 }
1275
1276 /* Allow via rewrite */
1277 if (acc->cfg.allow_via_rewrite != cfg->allow_via_rewrite) {
1278 if (acc->regc != NULL) {
1279 if (cfg->allow_via_rewrite) {
1280 pjsip_regc_set_via_sent_by(acc->regc, &acc->via_addr,
1281 acc->via_tp);
1282 } else
1283 pjsip_regc_set_via_sent_by(acc->regc, NULL, NULL);
1284 }
1285 if (acc->publish_sess != NULL) {
1286 if (cfg->allow_via_rewrite) {
1287 pjsip_publishc_set_via_sent_by(acc->publish_sess,
1288 &acc->via_addr, acc->via_tp);
1289 } else
1290 pjsip_publishc_set_via_sent_by(acc->publish_sess, NULL, NULL);
1291 }
1292 acc->cfg.allow_via_rewrite = cfg->allow_via_rewrite;
1293 }
1294
1295 /* Normalize registration timeout and refresh delay */
1296 if (acc->cfg.reg_uri.slen ) {
1297 if (acc->cfg.reg_timeout == 0) {
1298 acc->cfg.reg_timeout = PJSUA_REG_INTERVAL;
1299 }
1300 if (acc->cfg.reg_delay_before_refresh == 0) {
1301 acc->cfg.reg_delay_before_refresh =
1302 PJSIP_REGISTER_CLIENT_DELAY_BEFORE_REFRESH;
1303 }
1304 }
1305
1306 /* Registrar URI */
1307 if (pj_strcmp(&acc->cfg.reg_uri, &cfg->reg_uri)) {
1308 if (cfg->reg_uri.slen) {
1309 pj_strdup_with_null(acc->pool, &acc->cfg.reg_uri, &cfg->reg_uri);
1310 if (reg_sip_uri)
1311 acc->srv_port = reg_sip_uri->port;
1312 }
1313 update_reg = PJ_TRUE;
1314 unreg_first = PJ_TRUE;
1315 }
1316
1317 /* SIP outbound setting */
1318 if (acc->cfg.use_rfc5626 != cfg->use_rfc5626 ||
1319 pj_strcmp(&acc->cfg.rfc5626_instance_id, &cfg->rfc5626_instance_id) ||
1320 pj_strcmp(&acc->cfg.rfc5626_reg_id, &cfg->rfc5626_reg_id))
1321 {
1322 if (acc->cfg.use_rfc5626 != cfg->use_rfc5626)
1323 acc->cfg.use_rfc5626 = cfg->use_rfc5626;
1324
1325 if (pj_strcmp(&acc->cfg.rfc5626_instance_id,
1326 &cfg->rfc5626_instance_id))
1327 {
1328 pj_strdup_with_null(acc->pool, &acc->cfg.rfc5626_instance_id,
1329 &cfg->rfc5626_instance_id);
1330 }
1331 if (pj_strcmp(&acc->cfg.rfc5626_reg_id, &cfg->rfc5626_reg_id)) {
1332 pj_strdup_with_null(acc->pool, &acc->cfg.rfc5626_reg_id,
1333 &cfg->rfc5626_reg_id);
1334 }
1335 init_outbound_setting(acc);
1336 update_reg = PJ_TRUE;
1337 unreg_first = PJ_TRUE;
1338 }
1339
1340 /* Video settings */
1341 acc->cfg.vid_in_auto_show = cfg->vid_in_auto_show;
1342 acc->cfg.vid_out_auto_transmit = cfg->vid_out_auto_transmit;
1343 acc->cfg.vid_wnd_flags = cfg->vid_wnd_flags;
1344 acc->cfg.vid_cap_dev = cfg->vid_cap_dev;
1345 acc->cfg.vid_rend_dev = cfg->vid_rend_dev;
1346 acc->cfg.vid_stream_rc_cfg = cfg->vid_stream_rc_cfg;
1347
1348 /* Media settings */
1349 if (pj_stricmp(&acc->cfg.rtp_cfg.public_addr, &cfg->rtp_cfg.public_addr) ||
1350 pj_stricmp(&acc->cfg.rtp_cfg.bound_addr, &cfg->rtp_cfg.bound_addr))
1351 {
1352 pjsua_transport_config_dup(acc->pool, &acc->cfg.rtp_cfg,
1353 &cfg->rtp_cfg);
1354 } else {
1355 pj_str_t p_addr = acc->cfg.rtp_cfg.public_addr;
1356 pj_str_t b_addr = acc->cfg.rtp_cfg.bound_addr;
1357
1358 /* ..to save memory by not using the pool */
1359 acc->cfg.rtp_cfg = cfg->rtp_cfg;
1360 acc->cfg.rtp_cfg.public_addr = p_addr;
1361 acc->cfg.rtp_cfg.bound_addr = b_addr;
1362 }
1363
1364 acc->cfg.nat64_opt = cfg->nat64_opt;
1365 acc->cfg.ipv6_media_use = cfg->ipv6_media_use;
1366 acc->cfg.enable_rtcp_mux = cfg->enable_rtcp_mux;
1367 acc->cfg.lock_codec = cfg->lock_codec;
1368
1369 /* STUN and Media customization */
1370 if (acc->cfg.sip_stun_use != cfg->sip_stun_use) {
1371 acc->cfg.sip_stun_use = cfg->sip_stun_use;
1372 update_reg = PJ_TRUE;
1373 }
1374 acc->cfg.media_stun_use = cfg->media_stun_use;
1375
1376 /* ICE settings */
1377 acc->cfg.ice_cfg_use = cfg->ice_cfg_use;
1378 switch (acc->cfg.ice_cfg_use) {
1379 case PJSUA_ICE_CONFIG_USE_DEFAULT:
1380 /* Copy ICE settings from media settings so that we don't need to
1381 * check the media config if we look for ICE config.
1382 */
1383 pjsua_ice_config_from_media_config(NULL, &acc->cfg.ice_cfg,
1384 &pjsua_var.media_cfg);
1385 break;
1386 case PJSUA_ICE_CONFIG_USE_CUSTOM:
1387 pjsua_ice_config_dup(acc->pool, &acc->cfg.ice_cfg, &cfg->ice_cfg);
1388 break;
1389 }
1390
1391 /* TURN settings */
1392 acc->cfg.turn_cfg_use = cfg->turn_cfg_use;
1393 switch (acc->cfg.turn_cfg_use) {
1394 case PJSUA_TURN_CONFIG_USE_DEFAULT:
1395 /* Copy TURN settings from media settings so that we don't need to
1396 * check the media config if we look for TURN config.
1397 */
1398 pjsua_turn_config_from_media_config(NULL, &acc->cfg.turn_cfg,
1399 &pjsua_var.media_cfg);
1400 break;
1401 case PJSUA_TURN_CONFIG_USE_CUSTOM:
1402 pjsua_turn_config_dup(acc->pool, &acc->cfg.turn_cfg,
1403 &cfg->turn_cfg);
1404 break;
1405 }
1406
1407 acc->cfg.use_srtp = cfg->use_srtp;
1408
1409 /* Call hold type */
1410 acc->cfg.call_hold_type = cfg->call_hold_type;
1411
1412 /* Unregister first */
1413 if (unreg_first) {
1414 if (acc->regc) {
1415 status = pjsua_acc_set_registration(acc->index, PJ_FALSE);
1416 if (status != PJ_SUCCESS) {
1417 pjsua_perror(THIS_FILE, "Ignored failure in unregistering the "
1418 "old account setting in modifying account",
1419 status);
1420 /* Not really sure if we should return error */
1421 status = PJ_SUCCESS;
1422 }
1423 }
1424 if (acc->regc != NULL) {
1425 pjsip_regc_destroy(acc->regc);
1426 acc->regc = NULL;
1427 acc->contact.slen = 0;
1428 acc->reg_mapped_addr.slen = 0;
1429 acc->rfc5626_status = OUTBOUND_UNKNOWN;
1430 }
1431
1432 if (!cfg->reg_uri.slen) {
1433 /* Reg URI still needed, delay unset after sending unregister. */
1434 pj_bzero(&acc->cfg.reg_uri, sizeof(acc->cfg.reg_uri));
1435 }
1436 }
1437
1438 /* Update registration */
1439 if (update_reg) {
1440 /* If accounts has registration enabled, start registration */
1441 if (acc->cfg.reg_uri.slen) {
1442 status = pjsua_acc_set_registration(acc->index, PJ_TRUE);
1443 if (status != PJ_SUCCESS) {
1444 pjsua_perror(THIS_FILE, "Failed to register with new account "
1445 "setting in modifying account", status);
1446 goto on_return;
1447 }
1448 }
1449 }
1450
1451 /* Update MWI subscription */
1452 if (update_mwi) {
1453 status = pjsua_start_mwi(acc_id, PJ_TRUE);
1454 if (status != PJ_SUCCESS) {
1455 pjsua_perror(THIS_FILE, "Failed in starting MWI subscription for "
1456 "new account setting in modifying account", status);
1457 }
1458 }
1459
1460 /* IP Change config */
1461 acc->cfg.ip_change_cfg.shutdown_tp = cfg->ip_change_cfg.shutdown_tp;
1462 acc->cfg.ip_change_cfg.hangup_calls = cfg->ip_change_cfg.hangup_calls;
1463 acc->cfg.ip_change_cfg.reinvite_flags = cfg->ip_change_cfg.reinvite_flags;
1464
1465 /* SRTP setting */
1466 pjsua_srtp_opt_dup(acc->pool, &acc->cfg.srtp_opt, &cfg->srtp_opt,
1467 PJ_TRUE);
1468
1469 /* RTCP-FB config */
1470 pjmedia_rtcp_fb_setting_dup(acc->pool, &acc->cfg.rtcp_fb_cfg,
1471 &cfg->rtcp_fb_cfg);
1472
1473 on_return:
1474 PJSUA_UNLOCK();
1475 pj_log_pop_indent();
1476 return status;
1477 }
1478
1479
1480 /*
1481 * Modify account's presence status to be advertised to remote/presence
1482 * subscribers.
1483 */
pjsua_acc_set_online_status(pjsua_acc_id acc_id,pj_bool_t is_online)1484 PJ_DEF(pj_status_t) pjsua_acc_set_online_status( pjsua_acc_id acc_id,
1485 pj_bool_t is_online)
1486 {
1487 PJ_ASSERT_RETURN(acc_id>=0 && acc_id<(int)PJ_ARRAY_SIZE(pjsua_var.acc),
1488 PJ_EINVAL);
1489 PJ_ASSERT_RETURN(pjsua_var.acc[acc_id].valid, PJ_EINVALIDOP);
1490
1491 PJ_LOG(4,(THIS_FILE, "Acc %d: setting online status to %d..",
1492 acc_id, is_online));
1493 pj_log_push_indent();
1494
1495 pjsua_var.acc[acc_id].online_status = is_online;
1496 pj_bzero(&pjsua_var.acc[acc_id].rpid, sizeof(pjrpid_element));
1497 pjsua_pres_update_acc(acc_id, PJ_FALSE);
1498
1499 pj_log_pop_indent();
1500 return PJ_SUCCESS;
1501 }
1502
1503
1504 /*
1505 * Set online status with extended information
1506 */
pjsua_acc_set_online_status2(pjsua_acc_id acc_id,pj_bool_t is_online,const pjrpid_element * pr)1507 PJ_DEF(pj_status_t) pjsua_acc_set_online_status2( pjsua_acc_id acc_id,
1508 pj_bool_t is_online,
1509 const pjrpid_element *pr)
1510 {
1511 PJ_ASSERT_RETURN(acc_id>=0 && acc_id<(int)PJ_ARRAY_SIZE(pjsua_var.acc),
1512 PJ_EINVAL);
1513 PJ_ASSERT_RETURN(pjsua_var.acc[acc_id].valid, PJ_EINVALIDOP);
1514
1515 PJ_LOG(4,(THIS_FILE, "Acc %d: setting online status to %d..",
1516 acc_id, is_online));
1517 pj_log_push_indent();
1518
1519 PJSUA_LOCK();
1520 pjsua_var.acc[acc_id].online_status = is_online;
1521 pjrpid_element_dup(pjsua_var.acc[acc_id].pool, &pjsua_var.acc[acc_id].rpid, pr);
1522 PJSUA_UNLOCK();
1523
1524 pjsua_pres_update_acc(acc_id, PJ_TRUE);
1525 pj_log_pop_indent();
1526
1527 return PJ_SUCCESS;
1528 }
1529
1530 /* Create reg_contact, mainly for SIP outbound */
update_regc_contact(pjsua_acc * acc)1531 static void update_regc_contact(pjsua_acc *acc)
1532 {
1533 pjsua_acc_config *acc_cfg = &acc->cfg;
1534 pj_bool_t need_outbound = PJ_FALSE;
1535 const pj_str_t tcp_param = pj_str(";transport=tcp");
1536 const pj_str_t tls_param = pj_str(";transport=tls");
1537
1538 if (!acc_cfg->use_rfc5626)
1539 goto done;
1540
1541 /* Check if outbound has been requested and rejected */
1542 if (acc->rfc5626_status == OUTBOUND_NA)
1543 goto done;
1544
1545 if (pj_stristr(&acc->contact, &tcp_param)==NULL &&
1546 pj_stristr(&acc->contact, &tls_param)==NULL)
1547 {
1548 /* Currently we can only do SIP outbound for TCP
1549 * and TLS.
1550 */
1551 goto done;
1552 }
1553
1554 /* looks like we can use outbound */
1555 need_outbound = PJ_TRUE;
1556
1557 done:
1558 {
1559 pj_ssize_t len;
1560 pj_str_t reg_contact;
1561
1562 acc->rfc5626_status = OUTBOUND_WANTED;
1563 len = acc->contact.slen + acc->cfg.reg_contact_params.slen +
1564 (need_outbound?
1565 (acc->rfc5626_instprm.slen + acc->rfc5626_regprm.slen): 0);
1566 if (len > acc->contact.slen) {
1567 reg_contact.ptr = (char*) pj_pool_alloc(acc->pool, len);
1568
1569 pj_strcpy(®_contact, &acc->contact);
1570
1571 if (need_outbound) {
1572 acc->rfc5626_status = OUTBOUND_WANTED;
1573
1574 /* Need to use outbound, append the contact with
1575 * +sip.instance and reg-id parameters.
1576 */
1577 pj_strcat(®_contact, &acc->rfc5626_regprm);
1578 pj_strcat(®_contact, &acc->rfc5626_instprm);
1579 } else {
1580 acc->rfc5626_status = OUTBOUND_NA;
1581 }
1582
1583 pj_strcat(®_contact, &acc->cfg.reg_contact_params);
1584
1585 acc->reg_contact = reg_contact;
1586
1587 PJ_LOG(4,(THIS_FILE,
1588 "Contact for acc %d updated: %.*s",
1589 acc->index,
1590 (int)acc->reg_contact.slen,
1591 acc->reg_contact.ptr));
1592
1593 } else {
1594 /* Outbound is not needed/wanted for the account and there's
1595 * no custom registration Contact params. acc->reg_contact
1596 * is set to the same as acc->contact.
1597 */
1598 acc->reg_contact = acc->contact;
1599 acc->rfc5626_status = OUTBOUND_NA;
1600 }
1601 }
1602 }
1603
1604 /* Check if IP is private IP address */
is_private_ip(const pj_str_t * addr)1605 static pj_bool_t is_private_ip(const pj_str_t *addr)
1606 {
1607 const pj_str_t private_net[] =
1608 {
1609 { "10.", 3 },
1610 { "127.", 4 },
1611 { "172.16.", 7 }, { "172.17.", 7 }, { "172.18.", 7 }, { "172.19.", 7 },
1612 { "172.20.", 7 }, { "172.21.", 7 }, { "172.22.", 7 }, { "172.23.", 7 },
1613 { "172.24.", 7 }, { "172.25.", 7 }, { "172.26.", 7 }, { "172.27.", 7 },
1614 { "172.28.", 7 }, { "172.29.", 7 }, { "172.30.", 7 }, { "172.31.", 7 },
1615 { "192.168.", 8 }
1616 };
1617 unsigned i;
1618
1619 for (i=0; i<PJ_ARRAY_SIZE(private_net); ++i) {
1620 if (pj_strncmp(addr, &private_net[i], private_net[i].slen)==0)
1621 return PJ_TRUE;
1622 }
1623
1624 return PJ_FALSE;
1625 }
1626
1627 /* Update NAT address from the REGISTER response */
acc_check_nat_addr(pjsua_acc * acc,int contact_rewrite_method,struct pjsip_regc_cbparam * param)1628 static pj_bool_t acc_check_nat_addr(pjsua_acc *acc,
1629 int contact_rewrite_method,
1630 struct pjsip_regc_cbparam *param)
1631 {
1632 pjsip_transport *tp;
1633 const pj_str_t *via_addr;
1634 pj_pool_t *pool;
1635 int rport;
1636 pjsip_sip_uri *uri;
1637 pjsip_via_hdr *via;
1638 pj_sockaddr contact_addr;
1639 pj_sockaddr recv_addr = {{0}};
1640 pj_status_t status;
1641 pj_bool_t matched;
1642 pj_str_t srv_ip;
1643 pjsip_contact_hdr *contact_hdr;
1644 char host_addr_buf[PJ_INET6_ADDRSTRLEN+10];
1645 char via_addr_buf[PJ_INET6_ADDRSTRLEN+10];
1646 const pj_str_t STR_CONTACT = { "Contact", 7 };
1647
1648 tp = param->rdata->tp_info.transport;
1649
1650 /* Get the received and rport info */
1651 via = param->rdata->msg_info.via;
1652 if (via->rport_param < 1) {
1653 /* Remote doesn't support rport */
1654 rport = via->sent_by.port;
1655 if (rport==0) {
1656 pjsip_transport_type_e tp_type;
1657 tp_type = (pjsip_transport_type_e) tp->key.type;
1658 rport = pjsip_transport_get_default_port_for_type(tp_type);
1659 }
1660 } else
1661 rport = via->rport_param;
1662
1663 if (via->recvd_param.slen != 0)
1664 via_addr = &via->recvd_param;
1665 else
1666 via_addr = &via->sent_by.host;
1667
1668 /* If allow_via_rewrite is enabled, we save the Via "received" address
1669 * from the response, if either of the following condition is met:
1670 * - the Via "received" address differs from saved one (or we haven't
1671 * saved any yet)
1672 * - transport is different
1673 * - only the port has changed, AND either the received address is
1674 * public IP or allow_contact_rewrite is 2
1675 */
1676 if (acc->cfg.allow_via_rewrite &&
1677 (pj_strcmp(&acc->via_addr.host, via_addr) || acc->via_tp != tp ||
1678 (acc->via_addr.port != rport &&
1679 (!is_private_ip(via_addr) || acc->cfg.allow_contact_rewrite == 2))))
1680 {
1681 if (pj_strcmp(&acc->via_addr.host, via_addr))
1682 pj_strdup(acc->pool, &acc->via_addr.host, via_addr);
1683 acc->via_addr.port = rport;
1684 acc->via_tp = tp;
1685 pjsip_regc_set_via_sent_by(acc->regc, &acc->via_addr, acc->via_tp);
1686 if (acc->publish_sess != NULL) {
1687 pjsip_publishc_set_via_sent_by(acc->publish_sess,
1688 &acc->via_addr, acc->via_tp);
1689 }
1690 }
1691
1692 /* Save mapped address if needed */
1693 if (acc->cfg.allow_sdp_nat_rewrite &&
1694 pj_strcmp(&acc->reg_mapped_addr, via_addr))
1695 {
1696 pj_strdup(acc->pool, &acc->reg_mapped_addr, via_addr);
1697 }
1698
1699 /* Only update if account is configured to auto-update */
1700 if (acc->cfg.allow_contact_rewrite == PJ_FALSE)
1701 return PJ_FALSE;
1702
1703 /* If SIP outbound is active, no need to update */
1704 if (acc->rfc5626_status == OUTBOUND_ACTIVE) {
1705 PJ_LOG(4,(THIS_FILE, "Acc %d has SIP outbound active, no need to "
1706 "update registration Contact", acc->index));
1707 return PJ_FALSE;
1708 }
1709
1710 #if 0
1711 // Always update
1712 // See http://lists.pjsip.org/pipermail/pjsip_lists.pjsip.org/2008-March/002178.html
1713
1714 /* For UDP, only update if STUN is enabled (for now).
1715 * For TCP/TLS, always check.
1716 */
1717 if ((tp->key.type == PJSIP_TRANSPORT_UDP &&
1718 (pjsua_var.ua_cfg.stun_domain.slen != 0 ||
1719 (pjsua_var.ua_cfg.stun_host.slen != 0)) ||
1720 (tp->key.type == PJSIP_TRANSPORT_TCP) ||
1721 (tp->key.type == PJSIP_TRANSPORT_TLS))
1722 {
1723 /* Yes we will check */
1724 } else {
1725 return PJ_FALSE;
1726 }
1727 #endif
1728
1729 /* Compare received and rport with the URI in our registration */
1730 pool = pjsua_pool_create("tmp", 512, 512);
1731 contact_hdr = (pjsip_contact_hdr*)
1732 pjsip_parse_hdr(pool, &STR_CONTACT, acc->contact.ptr,
1733 acc->contact.slen, NULL);
1734 pj_assert(contact_hdr != NULL);
1735 uri = (pjsip_sip_uri*) contact_hdr->uri;
1736 pj_assert(uri != NULL);
1737 uri = (pjsip_sip_uri*) pjsip_uri_get_uri(uri);
1738
1739 if (uri->port == 0) {
1740 pjsip_transport_type_e tp_type;
1741 tp_type = (pjsip_transport_type_e) tp->key.type;
1742 uri->port = pjsip_transport_get_default_port_for_type(tp_type);
1743 }
1744
1745 /* Convert IP address strings into sockaddr for comparison.
1746 * (http://trac.pjsip.org/repos/ticket/863)
1747 */
1748 status = pj_sockaddr_parse(pj_AF_UNSPEC(), 0, &uri->host,
1749 &contact_addr);
1750 if (status == PJ_SUCCESS)
1751 status = pj_sockaddr_parse(pj_AF_UNSPEC(), 0, via_addr,
1752 &recv_addr);
1753 if (status == PJ_SUCCESS) {
1754 /* Compare the addresses as sockaddr according to the ticket above,
1755 * but only if they have the same family (ipv4 vs ipv4, or
1756 * ipv6 vs ipv6).
1757 * Checking for the same address family is currently disabled,
1758 * since it can be useful in cases such as when on NAT64,
1759 * in order to get the IPv4-mapped address from IPv6.
1760 */
1761 matched = //(contact_addr.addr.sa_family != recv_addr.addr.sa_family)||
1762 (uri->port == rport &&
1763 pj_sockaddr_cmp(&contact_addr, &recv_addr)==0);
1764 } else {
1765 /* Compare the addresses as string, as before */
1766 matched = (uri->port == rport &&
1767 pj_stricmp(&uri->host, via_addr)==0);
1768 }
1769
1770 if (matched) {
1771 /* Address doesn't change */
1772 pj_pool_release(pool);
1773 return PJ_FALSE;
1774 }
1775
1776 /* Get server IP */
1777 srv_ip = pj_str(param->rdata->pkt_info.src_name);
1778
1779 /* At this point we've detected that the address as seen by registrar.
1780 * has changed.
1781 */
1782
1783 /* Do not switch if both Contact and server's IP address are
1784 * public but response contains private IP. A NAT in the middle
1785 * might have messed up with the SIP packets. See:
1786 * http://trac.pjsip.org/repos/ticket/643
1787 *
1788 * This exception can be disabled by setting allow_contact_rewrite
1789 * to 2. In this case, the switch will always be done whenever there
1790 * is difference in the IP address in the response.
1791 */
1792 if (acc->cfg.allow_contact_rewrite != 2 && !is_private_ip(&uri->host) &&
1793 !is_private_ip(&srv_ip) && is_private_ip(via_addr))
1794 {
1795 /* Don't switch */
1796 pj_pool_release(pool);
1797 return PJ_FALSE;
1798 }
1799
1800 /* Also don't switch if only the port number part is different, and
1801 * the Via received address is private.
1802 * See http://trac.pjsip.org/repos/ticket/864
1803 */
1804 if (acc->cfg.allow_contact_rewrite != 2 &&
1805 pj_sockaddr_cmp(&contact_addr, &recv_addr)==0 &&
1806 is_private_ip(via_addr))
1807 {
1808 /* Don't switch */
1809 pj_pool_release(pool);
1810 return PJ_FALSE;
1811 }
1812 pj_addr_str_print(&uri->host, uri->port, host_addr_buf,
1813 sizeof(host_addr_buf), 1);
1814 pj_addr_str_print(via_addr, rport, via_addr_buf,
1815 sizeof(via_addr_buf), 1);
1816 PJ_LOG(3,(THIS_FILE, "IP address change detected for account %d "
1817 "(%s --> %s). Updating registration "
1818 "(using method %d)",
1819 acc->index, host_addr_buf, via_addr_buf,
1820 contact_rewrite_method));
1821
1822 pj_assert(contact_rewrite_method == PJSUA_CONTACT_REWRITE_UNREGISTER ||
1823 contact_rewrite_method == PJSUA_CONTACT_REWRITE_NO_UNREG ||
1824 contact_rewrite_method == PJSUA_CONTACT_REWRITE_ALWAYS_UPDATE);
1825
1826 if (contact_rewrite_method == PJSUA_CONTACT_REWRITE_UNREGISTER) {
1827 /* Unregister current contact */
1828 pjsua_acc_set_registration(acc->index, PJ_FALSE);
1829 if (acc->regc != NULL) {
1830 pjsip_regc_destroy(acc->regc);
1831 acc->regc = NULL;
1832 acc->contact.slen = 0;
1833 }
1834 }
1835
1836 /*
1837 * Build new Contact header
1838 */
1839 {
1840 const char *ob = ";ob";
1841 char *tmp;
1842 const char *beginquote, *endquote;
1843 char transport_param[32];
1844 int len;
1845 pj_bool_t secure;
1846
1847 secure = pjsip_transport_get_flag_from_type(tp->key.type) &
1848 PJSIP_TRANSPORT_SECURE;
1849
1850 /* Enclose IPv6 address in square brackets */
1851 if (tp->key.type & PJSIP_TRANSPORT_IPV6) {
1852 beginquote = "[";
1853 endquote = "]";
1854 } else {
1855 beginquote = endquote = "";
1856 }
1857
1858 /* Don't add transport parameter if it's UDP */
1859 if (tp->key.type != PJSIP_TRANSPORT_UDP &&
1860 tp->key.type != PJSIP_TRANSPORT_UDP6)
1861 {
1862 pj_ansi_snprintf(transport_param, sizeof(transport_param),
1863 ";transport=%s",
1864 pjsip_transport_get_type_name(
1865 (pjsip_transport_type_e)tp->key.type));
1866 } else {
1867 transport_param[0] = '\0';
1868 }
1869
1870 tmp = (char*) pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
1871 len = pj_ansi_snprintf(tmp, PJSIP_MAX_URL_SIZE,
1872 "<%s:%.*s%s%s%.*s%s:%d%s%.*s%s>%.*s",
1873 ((secure && acc->is_sips)? "sips" : "sip"),
1874 (int)acc->user_part.slen,
1875 acc->user_part.ptr,
1876 (acc->user_part.slen? "@" : ""),
1877 beginquote,
1878 (int)via_addr->slen,
1879 via_addr->ptr,
1880 endquote,
1881 rport,
1882 transport_param,
1883 (int)acc->cfg.contact_uri_params.slen,
1884 acc->cfg.contact_uri_params.ptr,
1885 (acc->cfg.use_rfc5626? ob: ""),
1886 (int)acc->cfg.contact_params.slen,
1887 acc->cfg.contact_params.ptr);
1888 if (len < 1 || len >= PJSIP_MAX_URL_SIZE) {
1889 PJ_LOG(1,(THIS_FILE, "URI too long"));
1890 pj_pool_release(pool);
1891 return PJ_FALSE;
1892 }
1893 pj_strdup2_with_null(acc->pool, &acc->contact, tmp);
1894
1895 update_regc_contact(acc);
1896
1897 /* Always update, by http://trac.pjsip.org/repos/ticket/864. */
1898 /* Since the Via address will now be overwritten to the correct
1899 * address by https://trac.pjsip.org/repos/ticket/1537, we do
1900 * not need to update the transport address.
1901 */
1902 /*
1903 pj_strdup_with_null(tp->pool, &tp->local_name.host, via_addr);
1904 tp->local_name.port = rport;
1905 */
1906
1907 }
1908
1909 if (contact_rewrite_method == PJSUA_CONTACT_REWRITE_NO_UNREG &&
1910 acc->regc != NULL)
1911 {
1912 pjsip_regc_update_contact(acc->regc, 1, &acc->reg_contact);
1913 }
1914
1915 /* Perform new registration */
1916 if (contact_rewrite_method < PJSUA_CONTACT_REWRITE_ALWAYS_UPDATE) {
1917 pjsua_acc_set_registration(acc->index, PJ_TRUE);
1918 }
1919
1920 pj_pool_release(pool);
1921
1922 return PJ_TRUE;
1923 }
1924
1925 /* Check and update Service-Route header */
update_service_route(pjsua_acc * acc,pjsip_rx_data * rdata)1926 static void update_service_route(pjsua_acc *acc, pjsip_rx_data *rdata)
1927 {
1928 pjsip_generic_string_hdr *hsr = NULL;
1929 pjsip_route_hdr *hr, *h;
1930 const pj_str_t HNAME = { "Service-Route", 13 };
1931 const pj_str_t HROUTE = { "Route", 5 };
1932 pjsip_uri *uri[PJSUA_ACC_MAX_PROXIES];
1933 unsigned i, uri_cnt = 0;
1934 pj_size_t rcnt;
1935
1936 /* Find and parse Service-Route headers */
1937 for (;;) {
1938 char saved;
1939 int parsed_len;
1940
1941 /* Find Service-Route header */
1942 hsr = (pjsip_generic_string_hdr*)
1943 pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &HNAME, hsr);
1944 if (!hsr)
1945 break;
1946
1947 /* Parse as Route header since the syntax is similar. This may
1948 * return more than one headers.
1949 */
1950 saved = hsr->hvalue.ptr[hsr->hvalue.slen];
1951 hsr->hvalue.ptr[hsr->hvalue.slen] = '\0';
1952 hr = (pjsip_route_hdr*)
1953 pjsip_parse_hdr(rdata->tp_info.pool, &HROUTE, hsr->hvalue.ptr,
1954 hsr->hvalue.slen, &parsed_len);
1955 hsr->hvalue.ptr[hsr->hvalue.slen] = saved;
1956
1957 if (hr == NULL) {
1958 /* Error */
1959 PJ_LOG(1,(THIS_FILE, "Error parsing Service-Route header"));
1960 return;
1961 }
1962
1963 /* Save each URI in the result */
1964 h = hr;
1965 do {
1966 if (!PJSIP_URI_SCHEME_IS_SIP(h->name_addr.uri) &&
1967 !PJSIP_URI_SCHEME_IS_SIPS(h->name_addr.uri))
1968 {
1969 PJ_LOG(1,(THIS_FILE,"Error: non SIP URI in Service-Route: %.*s",
1970 (int)hsr->hvalue.slen, hsr->hvalue.ptr));
1971 return;
1972 }
1973
1974 uri[uri_cnt++] = h->name_addr.uri;
1975 h = h->next;
1976 } while (h != hr && uri_cnt != PJ_ARRAY_SIZE(uri));
1977
1978 if (h != hr) {
1979 PJ_LOG(1,(THIS_FILE, "Error: too many Service-Route headers"));
1980 return;
1981 }
1982
1983 /* Prepare to find next Service-Route header */
1984 hsr = hsr->next;
1985 if ((void*)hsr == (void*)&rdata->msg_info.msg->hdr)
1986 break;
1987 }
1988
1989 if (uri_cnt == 0)
1990 return;
1991
1992 /*
1993 * Update account's route set
1994 */
1995
1996 /* First remove all routes which are not the outbound proxies */
1997 rcnt = pj_list_size(&acc->route_set);
1998 if (rcnt != pjsua_var.ua_cfg.outbound_proxy_cnt + acc->cfg.proxy_cnt) {
1999 for (i=pjsua_var.ua_cfg.outbound_proxy_cnt + acc->cfg.proxy_cnt,
2000 hr=acc->route_set.prev;
2001 i<rcnt;
2002 ++i)
2003 {
2004 pjsip_route_hdr *prev = hr->prev;
2005 pj_list_erase(hr);
2006 hr = prev;
2007 }
2008 }
2009
2010 /* Then append the Service-Route URIs */
2011 for (i=0; i<uri_cnt; ++i) {
2012 hr = pjsip_route_hdr_create(acc->pool);
2013 hr->name_addr.uri = (pjsip_uri*)pjsip_uri_clone(acc->pool, uri[i]);
2014 pj_list_push_back(&acc->route_set, hr);
2015 }
2016
2017 /* Done */
2018
2019 PJ_LOG(4,(THIS_FILE, "Service-Route updated for acc %d with %d URI(s)",
2020 acc->index, uri_cnt));
2021 }
2022
2023
2024 /* Keep alive timer callback */
keep_alive_timer_cb(pj_timer_heap_t * th,pj_timer_entry * te)2025 static void keep_alive_timer_cb(pj_timer_heap_t *th, pj_timer_entry *te)
2026 {
2027 pjsua_acc *acc;
2028 pjsip_tpselector tp_sel;
2029 pj_time_val delay;
2030 char addrtxt[PJ_INET6_ADDRSTRLEN];
2031 pj_status_t status;
2032
2033 PJ_UNUSED_ARG(th);
2034
2035 PJSUA_LOCK();
2036
2037 te->id = PJ_FALSE;
2038
2039 acc = (pjsua_acc*) te->user_data;
2040
2041 /* Check if the account is still active. It might have just been deleted
2042 * while the keep-alive timer was about to be called (race condition).
2043 */
2044 if (acc->ka_transport == NULL)
2045 goto on_return;
2046
2047 /* Select the transport to send the packet */
2048 pj_bzero(&tp_sel, sizeof(tp_sel));
2049 tp_sel.type = PJSIP_TPSELECTOR_TRANSPORT;
2050 tp_sel.u.transport = acc->ka_transport;
2051
2052 PJ_LOG(5,(THIS_FILE,
2053 "Sending %d bytes keep-alive packet for acc %d to %s",
2054 acc->cfg.ka_data.slen, acc->index,
2055 pj_sockaddr_print(&acc->ka_target, addrtxt, sizeof(addrtxt),3)));
2056
2057 /* Send raw packet */
2058 status = pjsip_tpmgr_send_raw(pjsip_endpt_get_tpmgr(pjsua_var.endpt),
2059 acc->ka_transport->key.type, &tp_sel,
2060 NULL, acc->cfg.ka_data.ptr,
2061 acc->cfg.ka_data.slen,
2062 &acc->ka_target, acc->ka_target_len,
2063 NULL, NULL);
2064
2065 if (status != PJ_SUCCESS && status != PJ_EPENDING) {
2066 pjsua_perror(THIS_FILE, "Error sending keep-alive packet", status);
2067 }
2068
2069 /* Check just in case keep-alive has been disabled. This shouldn't happen
2070 * though as when ka_interval is changed this timer should have been
2071 * cancelled.
2072 */
2073 if (acc->cfg.ka_interval == 0)
2074 goto on_return;
2075
2076 /* Reschedule next timer */
2077 delay.sec = acc->cfg.ka_interval;
2078 delay.msec = 0;
2079 status = pjsip_endpt_schedule_timer(pjsua_var.endpt, te, &delay);
2080 if (status == PJ_SUCCESS) {
2081 te->id = PJ_TRUE;
2082 } else {
2083 pjsua_perror(THIS_FILE, "Error starting keep-alive timer", status);
2084 }
2085
2086 on_return:
2087 PJSUA_UNLOCK();
2088 }
2089
2090
2091 /* Update keep-alive for the account */
update_keep_alive(pjsua_acc * acc,pj_bool_t start,struct pjsip_regc_cbparam * param)2092 static void update_keep_alive(pjsua_acc *acc, pj_bool_t start,
2093 struct pjsip_regc_cbparam *param)
2094 {
2095 /* In all cases, stop keep-alive timer if it's running. */
2096 if (acc->ka_timer.id) {
2097 pjsip_endpt_cancel_timer(pjsua_var.endpt, &acc->ka_timer);
2098 acc->ka_timer.id = PJ_FALSE;
2099
2100 if (acc->ka_transport) {
2101 pjsip_transport_dec_ref(acc->ka_transport);
2102 acc->ka_transport = NULL;
2103 }
2104 }
2105
2106 if (start) {
2107 pj_time_val delay;
2108 pj_status_t status;
2109
2110 /* Only do keep-alive if:
2111 * - ka_interval is not zero in the account, and
2112 * - transport is UDP.
2113 *
2114 * Previously we only enabled keep-alive when STUN is enabled, since
2115 * we thought that keep-alive is only needed in Internet situation.
2116 * But it has been discovered that Windows Firewall on WinXP also
2117 * needs to be kept-alive, otherwise incoming packets will be dropped.
2118 * So because of this, now keep-alive is always enabled for UDP,
2119 * regardless of whether STUN is enabled or not.
2120 *
2121 * Note that this applies only for UDP. For TCP/TLS, the keep-alive
2122 * is done by the transport layer.
2123 */
2124 if (/*pjsua_var.stun_srv.ipv4.sin_family == 0 ||*/
2125 acc->cfg.ka_interval == 0 ||
2126 (param->rdata->tp_info.transport->key.type &
2127 ~PJSIP_TRANSPORT_IPV6)!= PJSIP_TRANSPORT_UDP)
2128 {
2129 /* Keep alive is not necessary */
2130 return;
2131 }
2132
2133 /* Save transport and destination address. */
2134 acc->ka_transport = param->rdata->tp_info.transport;
2135 pjsip_transport_add_ref(acc->ka_transport);
2136
2137 /* https://trac.pjsip.org/repos/ticket/1607:
2138 * Calculate the destination address from the original request. Some
2139 * (broken) servers send the response using different source address
2140 * than the one that receives the request, which is forbidden by RFC
2141 * 3581.
2142 */
2143 {
2144 pjsip_transaction *tsx;
2145 pjsip_tx_data *req;
2146
2147 tsx = pjsip_rdata_get_tsx(param->rdata);
2148 PJ_ASSERT_ON_FAIL(tsx, return);
2149
2150 req = tsx->last_tx;
2151
2152 pj_memcpy(&acc->ka_target, &req->tp_info.dst_addr,
2153 req->tp_info.dst_addr_len);
2154 acc->ka_target_len = req->tp_info.dst_addr_len;
2155 }
2156
2157 /* Setup and start the timer */
2158 acc->ka_timer.cb = &keep_alive_timer_cb;
2159 acc->ka_timer.user_data = (void*)acc;
2160
2161 delay.sec = acc->cfg.ka_interval;
2162 delay.msec = 0;
2163 status = pjsip_endpt_schedule_timer(pjsua_var.endpt, &acc->ka_timer,
2164 &delay);
2165 if (status == PJ_SUCCESS) {
2166 char addr[PJ_INET6_ADDRSTRLEN+10];
2167 pj_str_t input_str = pj_str(param->rdata->pkt_info.src_name);
2168 acc->ka_timer.id = PJ_TRUE;
2169
2170 pj_addr_str_print(&input_str, param->rdata->pkt_info.src_port,
2171 addr, sizeof(addr), 1);
2172 PJ_LOG(4,(THIS_FILE, "Keep-alive timer started for acc %d, "
2173 "destination:%s, interval:%ds",
2174 acc->index, addr, acc->cfg.ka_interval));
2175 } else {
2176 acc->ka_timer.id = PJ_FALSE;
2177 pjsip_transport_dec_ref(acc->ka_transport);
2178 acc->ka_transport = NULL;
2179 pjsua_perror(THIS_FILE, "Error starting keep-alive timer", status);
2180 }
2181 }
2182 }
2183
2184
2185 /* Update the status of SIP outbound registration request */
update_rfc5626_status(pjsua_acc * acc,pjsip_rx_data * rdata)2186 static void update_rfc5626_status(pjsua_acc *acc, pjsip_rx_data *rdata)
2187 {
2188 pjsip_require_hdr *hreq;
2189 const pj_str_t STR_OUTBOUND = {"outbound", 8};
2190 unsigned i;
2191
2192 if (acc->rfc5626_status == OUTBOUND_UNKNOWN) {
2193 goto on_return;
2194 }
2195
2196 hreq = rdata->msg_info.require;
2197 if (!hreq) {
2198 acc->rfc5626_status = OUTBOUND_NA;
2199 goto on_return;
2200 }
2201
2202 for (i=0; i<hreq->count; ++i) {
2203 if (pj_stricmp(&hreq->values[i], &STR_OUTBOUND)==0) {
2204 acc->rfc5626_status = OUTBOUND_ACTIVE;
2205 goto on_return;
2206 }
2207 }
2208
2209 /* Server does not support outbound */
2210 acc->rfc5626_status = OUTBOUND_NA;
2211
2212 on_return:
2213 if (acc->rfc5626_status != OUTBOUND_ACTIVE) {
2214 acc->reg_contact = acc->contact;
2215 }
2216 PJ_LOG(4,(THIS_FILE, "SIP outbound status for acc %d is %s",
2217 acc->index, (acc->rfc5626_status==OUTBOUND_ACTIVE?
2218 "active": "not active")));
2219 }
2220
regc_tsx_cb(struct pjsip_regc_tsx_cb_param * param)2221 static void regc_tsx_cb(struct pjsip_regc_tsx_cb_param *param)
2222 {
2223 pjsua_acc *acc = (pjsua_acc*) param->cbparam.token;
2224
2225 PJSUA_LOCK();
2226
2227 if (param->cbparam.regc != acc->regc) {
2228 PJSUA_UNLOCK();
2229 return;
2230 }
2231
2232 pj_log_push_indent();
2233
2234 /* Check if we should do NAT bound address check for contact rewrite.
2235 * Note that '!contact_rewritten' check here is to avoid overriding
2236 * the current contact generated from last 2xx.
2237 */
2238 if (!acc->contact_rewritten &&
2239 (acc->cfg.contact_rewrite_method &
2240 PJSUA_CONTACT_REWRITE_ALWAYS_UPDATE) ==
2241 PJSUA_CONTACT_REWRITE_ALWAYS_UPDATE &&
2242 param->cbparam.code >= 400 &&
2243 param->cbparam.rdata)
2244 {
2245 if (acc_check_nat_addr(acc, PJSUA_CONTACT_REWRITE_ALWAYS_UPDATE,
2246 ¶m->cbparam))
2247 {
2248 param->contact_cnt = 1;
2249 param->contact[0] = acc->reg_contact;
2250
2251 /* Don't set 'contact_rewritten' to PJ_TRUE here to allow
2252 * further check of NAT bound address in 2xx response.
2253 */
2254 }
2255 }
2256
2257 PJSUA_UNLOCK();
2258 pj_log_pop_indent();
2259 }
2260
2261 /*
2262 * Timer callback to handle call on IP change process.
2263 */
handle_call_on_ip_change_cb(void * user_data)2264 static void handle_call_on_ip_change_cb(void *user_data)
2265 {
2266 pjsua_acc *acc = (pjsua_acc*)user_data;
2267 pjsua_acc_handle_call_on_ip_change(acc);
2268 }
2269
2270 /*
2271 * This callback is called by pjsip_regc when outgoing register
2272 * request has completed.
2273 */
regc_cb(struct pjsip_regc_cbparam * param)2274 static void regc_cb(struct pjsip_regc_cbparam *param)
2275 {
2276
2277 pjsua_acc *acc = (pjsua_acc*) param->token;
2278
2279 PJSUA_LOCK();
2280
2281 if (param->regc != acc->regc) {
2282 PJSUA_UNLOCK();
2283 return;
2284 }
2285
2286 pj_log_push_indent();
2287
2288 /*
2289 * Print registration status.
2290 */
2291 if (param->status!=PJ_SUCCESS) {
2292 pj_status_t status;
2293
2294 pjsua_perror(THIS_FILE, "SIP registration error",
2295 param->status);
2296
2297 if (param->status == PJSIP_EBUSY) {
2298 pj_log_pop_indent();
2299 PJSUA_UNLOCK();
2300 return;
2301 }
2302
2303 /* This callback is called without holding the registration's lock,
2304 * so there can be a race condition with another registration
2305 * process. Therefore, we must not forcefully try to destroy
2306 * the registration here.
2307 */
2308 status = pjsip_regc_destroy2(acc->regc, PJ_FALSE);
2309 if (status == PJ_SUCCESS) {
2310 acc->regc = NULL;
2311 acc->contact.slen = 0;
2312 acc->reg_mapped_addr.slen = 0;
2313 acc->rfc5626_status = OUTBOUND_UNKNOWN;
2314
2315 /* Stop keep-alive timer if any. */
2316 update_keep_alive(acc, PJ_FALSE, NULL);
2317 } else {
2318 /* Another registration is in progress. */
2319 pj_assert(status == PJ_EBUSY);
2320 pjsua_perror(THIS_FILE, "Deleting registration failed",
2321 status);
2322 }
2323
2324 } else if (param->code < 0 || param->code >= 300) {
2325 PJ_LOG(2, (THIS_FILE, "SIP registration failed, status=%d (%.*s)",
2326 param->code,
2327 (int)param->reason.slen, param->reason.ptr));
2328 pjsip_regc_destroy(acc->regc);
2329 acc->regc = NULL;
2330 acc->contact.slen = 0;
2331 acc->reg_mapped_addr.slen = 0;
2332 acc->rfc5626_status = OUTBOUND_UNKNOWN;
2333
2334 /* Stop keep-alive timer if any. */
2335 update_keep_alive(acc, PJ_FALSE, NULL);
2336
2337 } else if (PJSIP_IS_STATUS_IN_CLASS(param->code, 200)) {
2338
2339 /* Update auto registration flag */
2340 acc->auto_rereg.active = PJ_FALSE;
2341 acc->auto_rereg.attempt_cnt = 0;
2342
2343 if (param->expiration < 1) {
2344 pjsip_regc_destroy(acc->regc);
2345 acc->regc = NULL;
2346 acc->contact.slen = 0;
2347 acc->reg_mapped_addr.slen = 0;
2348 acc->rfc5626_status = OUTBOUND_UNKNOWN;
2349
2350 /* Reset pointer to registration transport */
2351 //acc->auto_rereg.reg_tp = NULL;
2352
2353 /* Stop keep-alive timer if any. */
2354 update_keep_alive(acc, PJ_FALSE, NULL);
2355
2356 PJ_LOG(3,(THIS_FILE, "%s: unregistration success",
2357 pjsua_var.acc[acc->index].cfg.id.ptr));
2358
2359 } else {
2360 /* Check and update SIP outbound status first, since the result
2361 * will determine if we should update re-registration
2362 */
2363 update_rfc5626_status(acc, param->rdata);
2364
2365 /* Check NAT bound address if it hasn't been done before */
2366 if (!acc->contact_rewritten &&
2367 acc_check_nat_addr(acc, (acc->cfg.contact_rewrite_method & 3),
2368 param))
2369 {
2370 PJSUA_UNLOCK();
2371 pj_log_pop_indent();
2372
2373 /* Avoid another check of NAT bound address */
2374 acc->contact_rewritten = PJ_TRUE;
2375 return;
2376 }
2377
2378 /* Check and update Service-Route header */
2379 update_service_route(acc, param->rdata);
2380
2381 #if PJSUA_REG_AUTO_REG_REFRESH
2382
2383 PJ_LOG(3, (THIS_FILE,
2384 "%s: registration success, status=%d (%.*s), "
2385 "will re-register in %d seconds",
2386 pjsua_var.acc[acc->index].cfg.id.ptr,
2387 param->code,
2388 (int)param->reason.slen, param->reason.ptr,
2389 param->expiration));
2390
2391 #else
2392
2393 PJ_LOG(3, (THIS_FILE,
2394 "%s: registration success, status=%d (%.*s), "
2395 "auto re-register disabled",
2396 pjsua_var.acc[acc->index].cfg.id.ptr,
2397 param->code,
2398 (int)param->reason.slen, param->reason.ptr));
2399
2400 #endif
2401 /* Start keep-alive timer if necessary. */
2402 update_keep_alive(acc, PJ_TRUE, param);
2403
2404 /* Send initial PUBLISH if it is enabled */
2405 if (acc->cfg.publish_enabled && acc->publish_sess==NULL)
2406 pjsua_pres_init_publish_acc(acc->index);
2407
2408 /* Subscribe to MWI, if it's enabled */
2409 if (acc->cfg.mwi_enabled)
2410 pjsua_start_mwi(acc->index, PJ_FALSE);
2411
2412 }
2413 } else {
2414 PJ_LOG(4, (THIS_FILE, "SIP registration updated status=%d", param->code));
2415 }
2416
2417 acc->reg_last_err = param->status;
2418 acc->reg_last_code = param->code;
2419
2420 /* Reaching this point means no contact rewrite, so reset the flag */
2421 acc->contact_rewritten = PJ_FALSE;
2422
2423 /* Check if we need to auto retry registration. Basically, registration
2424 * failure codes triggering auto-retry are those of temporal failures
2425 * considered to be recoverable in relatively short term.
2426 */
2427 if (acc->cfg.reg_retry_interval &&
2428 (param->code == PJSIP_SC_REQUEST_TIMEOUT ||
2429 param->code == PJSIP_SC_INTERNAL_SERVER_ERROR ||
2430 param->code == PJSIP_SC_BAD_GATEWAY ||
2431 param->code == PJSIP_SC_SERVICE_UNAVAILABLE ||
2432 param->code == PJSIP_SC_SERVER_TIMEOUT ||
2433 param->code == PJSIP_SC_TEMPORARILY_UNAVAILABLE ||
2434 PJSIP_IS_STATUS_IN_CLASS(param->code, 600))) /* Global failure */
2435 {
2436 schedule_reregistration(acc);
2437 }
2438
2439 /* Call the registration status callback */
2440
2441 if (pjsua_var.ua_cfg.cb.on_reg_state) {
2442 (*pjsua_var.ua_cfg.cb.on_reg_state)(acc->index);
2443 }
2444
2445 if (pjsua_var.ua_cfg.cb.on_reg_state2) {
2446 pjsua_reg_info reg_info;
2447 pjsip_regc_info rinfo;
2448
2449 pjsip_regc_get_info(param->regc, &rinfo);
2450 reg_info.cbparam = param;
2451 reg_info.regc = param->regc;
2452 reg_info.renew = !param->is_unreg;
2453 (*pjsua_var.ua_cfg.cb.on_reg_state2)(acc->index, ®_info);
2454 }
2455
2456 if (acc->ip_change_op == PJSUA_IP_CHANGE_OP_ACC_UPDATE_CONTACT) {
2457 if (pjsua_var.ua_cfg.cb.on_ip_change_progress) {
2458 pjsua_ip_change_op_info ip_chg_info;
2459 pjsip_regc_info rinfo;
2460
2461 pj_bzero(&ip_chg_info, sizeof(ip_chg_info));
2462 pjsip_regc_get_info(param->regc, &rinfo);
2463 ip_chg_info.acc_update_contact.acc_id = acc->index;
2464 ip_chg_info.acc_update_contact.code = param->code;
2465 ip_chg_info.acc_update_contact.is_register = !param->is_unreg;
2466 (*pjsua_var.ua_cfg.cb.on_ip_change_progress)(acc->ip_change_op,
2467 param->status,
2468 &ip_chg_info);
2469 }
2470
2471 if (PJSIP_IS_STATUS_IN_CLASS(param->code, 200)) {
2472 if (param->expiration < 1) {
2473 pj_status_t status;
2474 /* Send re-register. */
2475 PJ_LOG(3, (THIS_FILE, "%.*s: send registration triggered by IP"
2476 " change", pjsua_var.acc[acc->index].cfg.id.slen,
2477 pjsua_var.acc[acc->index].cfg.id.ptr));
2478
2479 status = pjsua_acc_set_registration(acc->index, PJ_TRUE);
2480 if ((status != PJ_SUCCESS) &&
2481 pjsua_var.ua_cfg.cb.on_ip_change_progress)
2482 {
2483 pjsua_ip_change_op_info ip_chg_info;
2484
2485 pj_bzero(&ip_chg_info, sizeof(ip_chg_info));
2486 ip_chg_info.acc_update_contact.acc_id = acc->index;
2487 ip_chg_info.acc_update_contact.is_register = PJ_TRUE;
2488 (*pjsua_var.ua_cfg.cb.on_ip_change_progress)(
2489 acc->ip_change_op,
2490 status,
2491 &ip_chg_info);
2492
2493 pjsua_acc_end_ip_change(acc);
2494 }
2495 } else {
2496 /* Avoid deadlock issue when sending BYE or Re-INVITE. */
2497 pjsua_schedule_timer2(&handle_call_on_ip_change_cb,
2498 (void*)acc, 0);
2499 }
2500 } else {
2501 pjsua_acc_end_ip_change(acc);
2502 }
2503 }
2504
2505 PJSUA_UNLOCK();
2506 pj_log_pop_indent();
2507 }
2508
2509
2510 /*
2511 * Initialize client registration.
2512 */
pjsua_regc_init(int acc_id)2513 static pj_status_t pjsua_regc_init(int acc_id)
2514 {
2515 pjsua_acc *acc;
2516 pj_pool_t *pool;
2517 pj_status_t status;
2518
2519 PJ_ASSERT_RETURN(pjsua_acc_is_valid(acc_id), PJ_EINVAL);
2520 acc = &pjsua_var.acc[acc_id];
2521
2522 if (acc->cfg.reg_uri.slen == 0) {
2523 PJ_LOG(3,(THIS_FILE, "Registrar URI is not specified"));
2524 return PJ_SUCCESS;
2525 }
2526
2527 /* Destroy existing session, if any */
2528 if (acc->regc) {
2529 pjsip_regc_destroy(acc->regc);
2530 acc->regc = NULL;
2531 acc->contact.slen = 0;
2532 acc->reg_mapped_addr.slen = 0;
2533 acc->rfc5626_status = OUTBOUND_UNKNOWN;
2534 }
2535
2536 /* initialize SIP registration if registrar is configured */
2537
2538 status = pjsip_regc_create( pjsua_var.endpt,
2539 acc, ®c_cb, &acc->regc);
2540
2541 if (status != PJ_SUCCESS) {
2542 pjsua_perror(THIS_FILE, "Unable to create client registration",
2543 status);
2544 return status;
2545 }
2546
2547 pool = pjsua_pool_create("tmpregc", 512, 512);
2548
2549 if (acc->contact.slen == 0) {
2550 pj_str_t tmp_contact;
2551
2552 status = pjsua_acc_create_uac_contact( pool, &tmp_contact,
2553 acc_id, &acc->cfg.reg_uri);
2554 if (status != PJ_SUCCESS) {
2555 pjsua_perror(THIS_FILE, "Unable to generate suitable Contact header"
2556 " for registration",
2557 status);
2558 pjsip_regc_destroy(acc->regc);
2559 pj_pool_release(pool);
2560 acc->regc = NULL;
2561 return status;
2562 }
2563
2564 pj_strdup_with_null(acc->pool, &acc->contact, &tmp_contact);
2565 update_regc_contact(acc);
2566 }
2567
2568 status = pjsip_regc_init( acc->regc,
2569 &acc->cfg.reg_uri,
2570 &acc->cfg.id,
2571 &acc->cfg.id,
2572 1, &acc->reg_contact,
2573 acc->cfg.reg_timeout);
2574 if (status != PJ_SUCCESS) {
2575 pjsua_perror(THIS_FILE,
2576 "Client registration initialization error",
2577 status);
2578 pjsip_regc_destroy(acc->regc);
2579 pj_pool_release(pool);
2580 acc->regc = NULL;
2581 acc->contact.slen = 0;
2582 acc->reg_mapped_addr.slen = 0;
2583 acc->rfc5626_status = OUTBOUND_UNKNOWN;
2584
2585 return status;
2586 }
2587
2588 pjsip_regc_set_reg_tsx_cb(acc->regc, regc_tsx_cb);
2589
2590 /* If account is locked to specific transport, then set transport to
2591 * the client registration.
2592 */
2593 if (pjsua_var.acc[acc_id].cfg.transport_id != PJSUA_INVALID_ID) {
2594 pjsip_tpselector tp_sel;
2595
2596 pjsua_init_tpselector(pjsua_var.acc[acc_id].cfg.transport_id, &tp_sel);
2597 pjsip_regc_set_transport(acc->regc, &tp_sel);
2598 }
2599
2600
2601 /* Set credentials
2602 */
2603 if (acc->cred_cnt) {
2604 pjsip_regc_set_credentials( acc->regc, acc->cred_cnt, acc->cred);
2605 }
2606
2607 /* Set delay before registration refresh */
2608 pjsip_regc_set_delay_before_refresh(acc->regc,
2609 acc->cfg.reg_delay_before_refresh);
2610
2611 /* Set authentication preference */
2612 pjsip_regc_set_prefs(acc->regc, &acc->cfg.auth_pref);
2613
2614 /* Set route-set
2615 */
2616 if (acc->cfg.reg_use_proxy) {
2617 pjsip_route_hdr route_set;
2618 const pjsip_route_hdr *r;
2619
2620 pj_list_init(&route_set);
2621
2622 if (acc->cfg.reg_use_proxy & PJSUA_REG_USE_OUTBOUND_PROXY) {
2623 r = pjsua_var.outbound_proxy.next;
2624 while (r != &pjsua_var.outbound_proxy) {
2625 pj_list_push_back(&route_set, pjsip_hdr_shallow_clone(pool, r));
2626 r = r->next;
2627 }
2628 }
2629
2630 if (acc->cfg.reg_use_proxy & PJSUA_REG_USE_ACC_PROXY &&
2631 acc->cfg.proxy_cnt)
2632 {
2633 int cnt = acc->cfg.proxy_cnt;
2634 pjsip_route_hdr *pos = route_set.prev;
2635 int i;
2636
2637 r = acc->route_set.prev;
2638 for (i=0; i<cnt; ++i) {
2639 pj_list_push_front(pos, pjsip_hdr_shallow_clone(pool, r));
2640 r = r->prev;
2641 }
2642 }
2643
2644 if (!pj_list_empty(&route_set))
2645 pjsip_regc_set_route_set( acc->regc, &route_set );
2646 }
2647
2648 /* Add custom request headers specified in the account config */
2649 pjsip_regc_add_headers(acc->regc, &acc->cfg.reg_hdr_list);
2650
2651 /* Add other request headers. */
2652 if (pjsua_var.ua_cfg.user_agent.slen) {
2653 pjsip_hdr hdr_list;
2654 const pj_str_t STR_USER_AGENT = { "User-Agent", 10 };
2655 pjsip_generic_string_hdr *h;
2656
2657 pj_list_init(&hdr_list);
2658
2659 h = pjsip_generic_string_hdr_create(pool, &STR_USER_AGENT,
2660 &pjsua_var.ua_cfg.user_agent);
2661 pj_list_push_back(&hdr_list, (pjsip_hdr*)h);
2662
2663 pjsip_regc_add_headers(acc->regc, &hdr_list);
2664 }
2665
2666 /* If SIP outbound is used, add "Supported: outbound, path header" */
2667 if (acc->rfc5626_status == OUTBOUND_WANTED ||
2668 acc->rfc5626_status == OUTBOUND_ACTIVE)
2669 {
2670 pjsip_hdr hdr_list;
2671 pjsip_supported_hdr *hsup;
2672
2673 pj_list_init(&hdr_list);
2674 hsup = pjsip_supported_hdr_create(pool);
2675 pj_list_push_back(&hdr_list, hsup);
2676
2677 hsup->count = 2;
2678 hsup->values[0] = pj_str("outbound");
2679 hsup->values[1] = pj_str("path");
2680
2681 pjsip_regc_add_headers(acc->regc, &hdr_list);
2682 }
2683
2684 pj_pool_release(pool);
2685
2686 return PJ_SUCCESS;
2687 }
2688
pjsua_sip_acc_is_using_ipv6(pjsua_acc_id acc_id)2689 pj_bool_t pjsua_sip_acc_is_using_ipv6(pjsua_acc_id acc_id)
2690 {
2691 pjsua_acc *acc = &pjsua_var.acc[acc_id];
2692
2693 return (acc->tp_type & PJSIP_TRANSPORT_IPV6) == PJSIP_TRANSPORT_IPV6;
2694 }
2695
pjsua_sip_acc_is_using_stun(pjsua_acc_id acc_id)2696 pj_bool_t pjsua_sip_acc_is_using_stun(pjsua_acc_id acc_id)
2697 {
2698 pjsua_acc *acc = &pjsua_var.acc[acc_id];
2699
2700 return acc->cfg.sip_stun_use != PJSUA_STUN_USE_DISABLED &&
2701 pjsua_var.ua_cfg.stun_srv_cnt != 0;
2702 }
2703
pjsua_media_acc_is_using_stun(pjsua_acc_id acc_id)2704 pj_bool_t pjsua_media_acc_is_using_stun(pjsua_acc_id acc_id)
2705 {
2706 pjsua_acc *acc = &pjsua_var.acc[acc_id];
2707
2708 return acc->cfg.media_stun_use != PJSUA_STUN_USE_DISABLED &&
2709 pjsua_var.ua_cfg.stun_srv_cnt != 0;
2710 }
2711
2712 /*
2713 * Update registration or perform unregistration.
2714 */
pjsua_acc_set_registration(pjsua_acc_id acc_id,pj_bool_t renew)2715 PJ_DEF(pj_status_t) pjsua_acc_set_registration( pjsua_acc_id acc_id,
2716 pj_bool_t renew)
2717 {
2718 pjsua_acc *acc;
2719 pj_status_t status = 0;
2720 pjsip_tx_data *tdata = 0;
2721
2722 PJ_ASSERT_RETURN(acc_id>=0 && acc_id<(int)PJ_ARRAY_SIZE(pjsua_var.acc),
2723 PJ_EINVAL);
2724 PJ_ASSERT_RETURN(pjsua_var.acc[acc_id].valid, PJ_EINVALIDOP);
2725
2726 PJ_LOG(4,(THIS_FILE, "Acc %d: setting %sregistration..",
2727 acc_id, (renew? "" : "un")));
2728 pj_log_push_indent();
2729
2730 PJSUA_LOCK();
2731
2732 acc = &pjsua_var.acc[acc_id];
2733
2734 /* Cancel any re-registration timer */
2735 if (pjsua_var.acc[acc_id].auto_rereg.timer.id) {
2736 pjsua_var.acc[acc_id].auto_rereg.timer.id = PJ_FALSE;
2737 pjsua_cancel_timer(&pjsua_var.acc[acc_id].auto_rereg.timer);
2738 }
2739
2740 /* Reset pointer to registration transport */
2741 // Do not reset this here, as if currently there is another registration
2742 // on progress, this registration will fail but transport pointer will
2743 // become NULL which will prevent transport to be destroyed immediately
2744 // after disconnected (which may cause iOS app getting killed (see #1482).
2745 //pjsua_var.acc[acc_id].auto_rereg.reg_tp = NULL;
2746
2747 if (renew) {
2748 if (pjsua_var.acc[acc_id].regc == NULL) {
2749 status = pjsua_regc_init(acc_id);
2750 if (status != PJ_SUCCESS) {
2751 pjsua_perror(THIS_FILE, "Unable to create registration",
2752 status);
2753 goto on_return;
2754 }
2755 }
2756 if (!pjsua_var.acc[acc_id].regc) {
2757 status = PJ_EINVALIDOP;
2758 goto on_return;
2759 }
2760
2761 status = pjsip_regc_register(pjsua_var.acc[acc_id].regc,
2762 PJSUA_REG_AUTO_REG_REFRESH,
2763 &tdata);
2764
2765 if (0 && status == PJ_SUCCESS && pjsua_var.acc[acc_id].cred_cnt) {
2766 pjsip_authorization_hdr *h;
2767 char *uri;
2768 int d;
2769
2770 uri = (char*) pj_pool_alloc(tdata->pool, acc->cfg.reg_uri.slen+10);
2771 d = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, tdata->msg->line.req.uri,
2772 uri, acc->cfg.reg_uri.slen+10);
2773 pj_assert(d > 0);
2774 PJ_UNUSED_ARG(d);
2775
2776 h = pjsip_authorization_hdr_create(tdata->pool);
2777 h->scheme = pj_str("Digest");
2778 h->credential.digest.username = acc->cred[0].username;
2779 h->credential.digest.realm = acc->srv_domain;
2780 h->credential.digest.uri = pj_str(uri);
2781 h->credential.digest.algorithm = pj_str("md5");
2782
2783 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)h);
2784 }
2785
2786 } else {
2787 if (pjsua_var.acc[acc_id].regc == NULL) {
2788 PJ_LOG(3,(THIS_FILE, "Currently not registered"));
2789 status = PJ_EINVALIDOP;
2790 goto on_return;
2791 }
2792
2793 pjsua_pres_unpublish(&pjsua_var.acc[acc_id], 0);
2794
2795 status = pjsip_regc_unregister(pjsua_var.acc[acc_id].regc, &tdata);
2796 }
2797
2798 if (status == PJ_SUCCESS) {
2799 pjsip_regc *regc = pjsua_var.acc[acc_id].regc;
2800
2801 if (pjsua_var.acc[acc_id].cfg.allow_via_rewrite &&
2802 pjsua_var.acc[acc_id].via_addr.host.slen > 0)
2803 {
2804 pjsip_regc_set_via_sent_by(pjsua_var.acc[acc_id].regc,
2805 &pjsua_var.acc[acc_id].via_addr,
2806 pjsua_var.acc[acc_id].via_tp);
2807 } else if (!pjsua_sip_acc_is_using_stun(acc_id)) {
2808 /* Choose local interface to use in Via if acc is not using
2809 * STUN
2810 */
2811 pjsua_acc_get_uac_addr(acc_id, tdata->pool,
2812 &acc->cfg.reg_uri,
2813 &tdata->via_addr,
2814 NULL, NULL,
2815 &tdata->via_tp);
2816 }
2817
2818 /* Increment ref counter and release PJSUA lock here, to avoid
2819 * deadlock while making sure that regc won't be destroyed.
2820 */
2821 pjsip_regc_add_ref(regc);
2822 PJSUA_UNLOCK();
2823
2824 //pjsua_process_msg_data(tdata, NULL);
2825 status = pjsip_regc_send( regc, tdata );
2826
2827 PJSUA_LOCK();
2828 if (pjsip_regc_dec_ref(regc) == PJ_EGONE) {
2829 /* regc has been deleted. */
2830 goto on_return;
2831 }
2832 }
2833
2834 /* Update pointer to registration transport */
2835 if (status == PJ_SUCCESS) {
2836 /* Variable auto_rereg.reg_tp is currently unused since it may differ
2837 * with the transport used by regc (for example, when a resolver is
2838 * employed). A more reliable way is to query the regc directly
2839 * when needed.
2840 */
2841 //pjsip_regc_info reg_info;
2842
2843 //pjsip_regc_get_info(pjsua_var.acc[acc_id].regc, ®_info);
2844 //pjsua_var.acc[acc_id].auto_rereg.reg_tp = reg_info.transport;
2845
2846 if (pjsua_var.ua_cfg.cb.on_reg_started) {
2847 (*pjsua_var.ua_cfg.cb.on_reg_started)(acc_id, renew);
2848 }
2849 if (pjsua_var.ua_cfg.cb.on_reg_started2) {
2850 pjsua_reg_info rinfo;
2851
2852 rinfo.cbparam = NULL;
2853 rinfo.regc = pjsua_var.acc[acc_id].regc;
2854 rinfo.renew = renew;
2855 (*pjsua_var.ua_cfg.cb.on_reg_started2)(acc_id, &rinfo);
2856 }
2857 }
2858
2859 if (status != PJ_SUCCESS) {
2860 pjsua_perror(THIS_FILE, "Unable to create/send REGISTER",
2861 status);
2862 } else {
2863 PJ_LOG(4,(THIS_FILE, "Acc %d: %s sent", acc_id,
2864 (renew? "Registration" : "Unregistration")));
2865 }
2866
2867 on_return:
2868 PJSUA_UNLOCK();
2869 pj_log_pop_indent();
2870 return status;
2871 }
2872
2873
2874 /*
2875 * Get account information.
2876 */
pjsua_acc_get_info(pjsua_acc_id acc_id,pjsua_acc_info * info)2877 PJ_DEF(pj_status_t) pjsua_acc_get_info( pjsua_acc_id acc_id,
2878 pjsua_acc_info *info)
2879 {
2880 pjsua_acc *acc = &pjsua_var.acc[acc_id];
2881 pjsua_acc_config *acc_cfg = &pjsua_var.acc[acc_id].cfg;
2882
2883 PJ_ASSERT_RETURN(info != NULL, PJ_EINVAL);
2884 PJ_ASSERT_RETURN(pjsua_acc_is_valid(acc_id), PJ_EINVAL);
2885
2886 pj_bzero(info, sizeof(pjsua_acc_info));
2887
2888 PJ_ASSERT_RETURN(acc_id>=0 && acc_id<(int)PJ_ARRAY_SIZE(pjsua_var.acc),
2889 PJ_EINVAL);
2890 PJ_ASSERT_RETURN(pjsua_var.acc[acc_id].valid, PJ_EINVALIDOP);
2891
2892 PJSUA_LOCK();
2893
2894 if (pjsua_var.acc[acc_id].valid == PJ_FALSE) {
2895 PJSUA_UNLOCK();
2896 return PJ_EINVALIDOP;
2897 }
2898
2899 info->id = acc_id;
2900 info->is_default = (pjsua_var.default_acc == acc_id);
2901 info->acc_uri = acc_cfg->id;
2902 info->has_registration = (acc->cfg.reg_uri.slen > 0);
2903 info->online_status = acc->online_status;
2904 pj_memcpy(&info->rpid, &acc->rpid, sizeof(pjrpid_element));
2905 if (info->rpid.note.slen)
2906 info->online_status_text = info->rpid.note;
2907 else if (info->online_status)
2908 info->online_status_text = pj_str("Online");
2909 else
2910 info->online_status_text = pj_str("Offline");
2911
2912 if (acc->reg_last_code) {
2913 if (info->has_registration) {
2914 info->status = (pjsip_status_code) acc->reg_last_code;
2915 info->status_text = *pjsip_get_status_text(acc->reg_last_code);
2916 if (acc->reg_last_err)
2917 info->reg_last_err = acc->reg_last_err;
2918 } else {
2919 info->status = (pjsip_status_code) 0;
2920 info->status_text = pj_str("not registered");
2921 }
2922 } else if (acc->cfg.reg_uri.slen) {
2923 info->status = PJSIP_SC_TRYING;
2924 info->status_text = pj_str("In Progress");
2925 } else {
2926 info->status = (pjsip_status_code) 0;
2927 info->status_text = pj_str("does not register");
2928 }
2929
2930 if (acc->regc) {
2931 pjsip_regc_info regc_info;
2932 pjsip_regc_get_info(acc->regc, ®c_info);
2933 info->expires = regc_info.next_reg;
2934 } else {
2935 info->expires = PJSIP_EXPIRES_NOT_SPECIFIED;
2936 }
2937
2938 PJSUA_UNLOCK();
2939
2940 return PJ_SUCCESS;
2941
2942 }
2943
2944
2945 /*
2946 * Enum accounts all account ids.
2947 */
pjsua_enum_accs(pjsua_acc_id ids[],unsigned * count)2948 PJ_DEF(pj_status_t) pjsua_enum_accs(pjsua_acc_id ids[],
2949 unsigned *count )
2950 {
2951 unsigned i, c;
2952
2953 PJ_ASSERT_RETURN(ids && *count, PJ_EINVAL);
2954
2955 PJSUA_LOCK();
2956
2957 for (i=0, c=0; c<*count && i<PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
2958 if (!pjsua_var.acc[i].valid)
2959 continue;
2960 ids[c] = i;
2961 ++c;
2962 }
2963
2964 *count = c;
2965
2966 PJSUA_UNLOCK();
2967
2968 return PJ_SUCCESS;
2969 }
2970
2971
2972 /*
2973 * Enum accounts info.
2974 */
pjsua_acc_enum_info(pjsua_acc_info info[],unsigned * count)2975 PJ_DEF(pj_status_t) pjsua_acc_enum_info( pjsua_acc_info info[],
2976 unsigned *count )
2977 {
2978 unsigned i, c;
2979
2980 PJ_ASSERT_RETURN(info && *count, PJ_EINVAL);
2981
2982 PJSUA_LOCK();
2983
2984 for (i=0, c=0; c<*count && i<PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
2985 if (!pjsua_var.acc[i].valid)
2986 continue;
2987
2988 pjsua_acc_get_info(i, &info[c]);
2989 ++c;
2990 }
2991
2992 *count = c;
2993
2994 PJSUA_UNLOCK();
2995
2996 return PJ_SUCCESS;
2997 }
2998
2999
3000 /*
3001 * This is an internal function to find the most appropriate account to
3002 * used to reach to the specified URL.
3003 */
pjsua_acc_find_for_outgoing(const pj_str_t * url)3004 PJ_DEF(pjsua_acc_id) pjsua_acc_find_for_outgoing(const pj_str_t *url)
3005 {
3006 pj_str_t tmp;
3007 pjsip_uri *uri;
3008 pjsip_sip_uri *sip_uri;
3009 pj_pool_t *tmp_pool;
3010 unsigned i;
3011
3012 PJSUA_LOCK();
3013
3014 tmp_pool = pjsua_pool_create("tmpacc10", 256, 256);
3015
3016 pj_strdup_with_null(tmp_pool, &tmp, url);
3017
3018 uri = pjsip_parse_uri(tmp_pool, tmp.ptr, tmp.slen, 0);
3019 if (!uri) {
3020 pj_pool_release(tmp_pool);
3021 PJSUA_UNLOCK();
3022 return pjsua_var.default_acc;
3023 }
3024
3025 if (!PJSIP_URI_SCHEME_IS_SIP(uri) &&
3026 !PJSIP_URI_SCHEME_IS_SIPS(uri))
3027 {
3028 /* Return the first account with proxy */
3029 for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
3030 if (!pjsua_var.acc[i].valid)
3031 continue;
3032 if (!pj_list_empty(&pjsua_var.acc[i].route_set))
3033 break;
3034 }
3035
3036 if (i != PJ_ARRAY_SIZE(pjsua_var.acc)) {
3037 /* Found rather matching account */
3038 pj_pool_release(tmp_pool);
3039 PJSUA_UNLOCK();
3040 return i;
3041 }
3042
3043 /* Not found, use default account */
3044 pj_pool_release(tmp_pool);
3045 PJSUA_UNLOCK();
3046 return pjsua_var.default_acc;
3047 }
3048
3049 sip_uri = (pjsip_sip_uri*) pjsip_uri_get_uri(uri);
3050
3051 /* Find matching domain AND port */
3052 for (i=0; i<pjsua_var.acc_cnt; ++i) {
3053 unsigned acc_id = pjsua_var.acc_ids[i];
3054 if (pj_stricmp(&pjsua_var.acc[acc_id].srv_domain, &sip_uri->host)==0 &&
3055 pjsua_var.acc[acc_id].srv_port == sip_uri->port)
3056 {
3057 pj_pool_release(tmp_pool);
3058 PJSUA_UNLOCK();
3059 return acc_id;
3060 }
3061 }
3062
3063 /* If no match, try to match the domain part only */
3064 for (i=0; i<pjsua_var.acc_cnt; ++i) {
3065 unsigned acc_id = pjsua_var.acc_ids[i];
3066 if (pj_stricmp(&pjsua_var.acc[acc_id].srv_domain, &sip_uri->host)==0)
3067 {
3068 pj_pool_release(tmp_pool);
3069 PJSUA_UNLOCK();
3070 return acc_id;
3071 }
3072 }
3073
3074
3075 /* Still no match, just use default account */
3076 pj_pool_release(tmp_pool);
3077 PJSUA_UNLOCK();
3078 return pjsua_var.default_acc;
3079 }
3080
3081
3082 /*
3083 * This is an internal function to find the most appropriate account to be
3084 * used to handle incoming calls.
3085 */
pjsua_acc_find_for_incoming(pjsip_rx_data * rdata)3086 PJ_DEF(pjsua_acc_id) pjsua_acc_find_for_incoming(pjsip_rx_data *rdata)
3087 {
3088 pjsip_uri *uri;
3089 pjsip_sip_uri *sip_uri;
3090 pjsua_acc_id id = PJSUA_INVALID_ID;
3091 int max_score;
3092 unsigned i;
3093
3094 if (pjsua_var.acc_cnt == 0) {
3095 PJ_LOG(2, (THIS_FILE, "No available account to handle %s",
3096 pjsip_rx_data_get_info(rdata)));
3097
3098 return PJSUA_INVALID_ID;
3099 }
3100
3101 uri = rdata->msg_info.to->uri;
3102
3103 PJSUA_LOCK();
3104
3105 /* Use Req URI if To URI is not SIP */
3106 if (!PJSIP_URI_SCHEME_IS_SIP(uri) &&
3107 !PJSIP_URI_SCHEME_IS_SIPS(uri))
3108 {
3109 if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG)
3110 uri = rdata->msg_info.msg->line.req.uri;
3111 else
3112 goto on_return;
3113 }
3114
3115 /* Just return default account if both To and Req URI are not SIP: */
3116 if (!PJSIP_URI_SCHEME_IS_SIP(uri) &&
3117 !PJSIP_URI_SCHEME_IS_SIPS(uri))
3118 {
3119 goto on_return;
3120 }
3121
3122 sip_uri = (pjsip_sip_uri*)pjsip_uri_get_uri(uri);
3123
3124 /* Select account by weighted score. Matching priority order is:
3125 * transport type (matched or not set), domain part, and user part.
3126 * Note that the transport type has higher priority as unmatched
3127 * transport type may cause failure in sending response.
3128 */
3129 max_score = 0;
3130 for (i=0; i < pjsua_var.acc_cnt; ++i) {
3131 unsigned acc_id = pjsua_var.acc_ids[i];
3132 pjsua_acc *acc = &pjsua_var.acc[acc_id];
3133 int score = 0;
3134
3135 if (!acc->valid)
3136 continue;
3137
3138 /* Match transport type */
3139 if (acc->tp_type == rdata->tp_info.transport->key.type ||
3140 acc->tp_type == PJSIP_TRANSPORT_UNSPECIFIED)
3141 {
3142 score |= 4;
3143 }
3144
3145 /* Match domain */
3146 if (pj_stricmp(&acc->srv_domain, &sip_uri->host)==0) {
3147 score |= 2;
3148 }
3149
3150 /* Match username */
3151 if (pj_stricmp(&acc->user_part, &sip_uri->user)==0) {
3152 score |= 1;
3153 }
3154
3155 if (score > max_score) {
3156 id = acc_id;
3157 max_score = score;
3158 }
3159 }
3160
3161 on_return:
3162 PJSUA_UNLOCK();
3163
3164 /* Still no match, use default account */
3165 if (id == PJSUA_INVALID_ID)
3166 id = pjsua_var.default_acc;
3167
3168 /* Invoke account find callback */
3169 if (pjsua_var.ua_cfg.cb.on_acc_find_for_incoming)
3170 (*pjsua_var.ua_cfg.cb.on_acc_find_for_incoming)(rdata, &id);
3171
3172 /* Verify if the specified account id is valid */
3173 if (!pjsua_acc_is_valid(id))
3174 id = pjsua_var.default_acc;
3175
3176 return id;
3177 }
3178
3179
3180 /*
3181 * Create arbitrary requests for this account.
3182 */
pjsua_acc_create_request(pjsua_acc_id acc_id,const pjsip_method * method,const pj_str_t * target,pjsip_tx_data ** p_tdata)3183 PJ_DEF(pj_status_t) pjsua_acc_create_request(pjsua_acc_id acc_id,
3184 const pjsip_method *method,
3185 const pj_str_t *target,
3186 pjsip_tx_data **p_tdata)
3187 {
3188 pjsip_tx_data *tdata;
3189 pjsua_acc *acc;
3190 pjsip_route_hdr *r;
3191 pj_status_t status;
3192
3193 PJ_ASSERT_RETURN(method && target && p_tdata, PJ_EINVAL);
3194 PJ_ASSERT_RETURN(pjsua_acc_is_valid(acc_id), PJ_EINVAL);
3195
3196 acc = &pjsua_var.acc[acc_id];
3197
3198 status = pjsip_endpt_create_request(pjsua_var.endpt, method, target,
3199 &acc->cfg.id, target,
3200 NULL, NULL, -1, NULL, &tdata);
3201 if (status != PJ_SUCCESS) {
3202 pjsua_perror(THIS_FILE, "Unable to create request", status);
3203 return status;
3204 }
3205
3206 /* Copy routeset */
3207 r = acc->route_set.next;
3208 while (r != &acc->route_set) {
3209 pjsip_msg_add_hdr(tdata->msg,
3210 (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, r));
3211 r = r->next;
3212 }
3213
3214 /* If account is locked to specific transport, then set that transport to
3215 * the transmit data.
3216 */
3217 if (pjsua_var.acc[acc_id].cfg.transport_id != PJSUA_INVALID_ID) {
3218 pjsip_tpselector tp_sel;
3219
3220 pjsua_init_tpselector(acc->cfg.transport_id, &tp_sel);
3221 pjsip_tx_data_set_transport(tdata, &tp_sel);
3222 }
3223
3224 /* If via_addr is set, use this address for the Via header. */
3225 if (pjsua_var.acc[acc_id].cfg.allow_via_rewrite &&
3226 pjsua_var.acc[acc_id].via_addr.host.slen > 0)
3227 {
3228 tdata->via_addr = pjsua_var.acc[acc_id].via_addr;
3229 tdata->via_tp = pjsua_var.acc[acc_id].via_tp;
3230 } else if (!pjsua_sip_acc_is_using_stun(acc_id)) {
3231 /* Choose local interface to use in Via if acc is not using
3232 * STUN
3233 */
3234 pjsua_acc_get_uac_addr(acc_id, tdata->pool,
3235 target,
3236 &tdata->via_addr,
3237 NULL, NULL,
3238 &tdata->via_tp);
3239 }
3240
3241 /* Done */
3242 *p_tdata = tdata;
3243 return PJ_SUCCESS;
3244 }
3245
3246 /*
3247 * Internal:
3248 * determine if an address is a valid IP address, and if it is,
3249 * return the IP version (4 or 6).
3250 */
get_ip_addr_ver(const pj_str_t * host)3251 static int get_ip_addr_ver(const pj_str_t *host)
3252 {
3253 pj_in_addr dummy;
3254 pj_in6_addr dummy6;
3255
3256 /* First check if this is an IPv4 address */
3257 if (pj_inet_pton(pj_AF_INET(), host, &dummy) == PJ_SUCCESS)
3258 return 4;
3259
3260 /* Then check if this is an IPv6 address */
3261 if (pj_inet_pton(pj_AF_INET6(), host, &dummy6) == PJ_SUCCESS)
3262 return 6;
3263
3264 /* Not an IP address */
3265 return 0;
3266 }
3267
3268 /* Get local transport address suitable to be used for Via or Contact address
3269 * to send request to the specified destination URI.
3270 */
pjsua_acc_get_uac_addr(pjsua_acc_id acc_id,pj_pool_t * pool,const pj_str_t * dst_uri,pjsip_host_port * addr,pjsip_transport_type_e * p_tp_type,int * secure,const void ** p_tp)3271 pj_status_t pjsua_acc_get_uac_addr(pjsua_acc_id acc_id,
3272 pj_pool_t *pool,
3273 const pj_str_t *dst_uri,
3274 pjsip_host_port *addr,
3275 pjsip_transport_type_e *p_tp_type,
3276 int *secure,
3277 const void **p_tp)
3278 {
3279 pjsua_acc *acc;
3280 pjsip_sip_uri *sip_uri;
3281 pj_status_t status;
3282 pjsip_transport_type_e tp_type = PJSIP_TRANSPORT_UNSPECIFIED;
3283 unsigned flag;
3284 pjsip_tpselector tp_sel;
3285 pjsip_tpmgr *tpmgr;
3286 pjsip_tpmgr_fla2_param tfla2_prm;
3287 pj_bool_t update_addr = PJ_TRUE;
3288
3289 PJ_ASSERT_RETURN(pjsua_acc_is_valid(acc_id), PJ_EINVAL);
3290 acc = &pjsua_var.acc[acc_id];
3291
3292 /* If route-set is configured for the account, then URI is the
3293 * first entry of the route-set.
3294 */
3295 if (!pj_list_empty(&acc->route_set)) {
3296 sip_uri = (pjsip_sip_uri*)
3297 pjsip_uri_get_uri(acc->route_set.next->name_addr.uri);
3298 } else {
3299 pj_str_t tmp;
3300 pjsip_uri *uri;
3301
3302 pj_strdup_with_null(pool, &tmp, dst_uri);
3303
3304 uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0);
3305 if (uri == NULL)
3306 return PJSIP_EINVALIDURI;
3307
3308 /* For non-SIP scheme, route set should be configured */
3309 if (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri))
3310 return PJSIP_ENOROUTESET;
3311
3312 sip_uri = (pjsip_sip_uri*)pjsip_uri_get_uri(uri);
3313 }
3314
3315 /* Get transport type of the URI */
3316 if (PJSIP_URI_SCHEME_IS_SIPS(sip_uri))
3317 tp_type = PJSIP_TRANSPORT_TLS;
3318 else if (sip_uri->transport_param.slen == 0) {
3319 tp_type = PJSIP_TRANSPORT_UDP;
3320 } else
3321 tp_type = pjsip_transport_get_type_from_name(&sip_uri->transport_param);
3322
3323 if (tp_type == PJSIP_TRANSPORT_UNSPECIFIED)
3324 return PJSIP_EUNSUPTRANSPORT;
3325
3326 /* If destination URI specifies IPv6 or account is configured to use IPv6,
3327 * then set transport type to use IPv6 as well.
3328 */
3329 if (pj_strchr(&sip_uri->host, ':') || pjsua_sip_acc_is_using_ipv6(acc_id))
3330 tp_type = (pjsip_transport_type_e)(((int)tp_type) |
3331 PJSIP_TRANSPORT_IPV6);
3332
3333 flag = pjsip_transport_get_flag_from_type(tp_type);
3334
3335 /* Init transport selector. */
3336 pjsua_init_tpselector(acc->cfg.transport_id, &tp_sel);
3337
3338 /* Get local address suitable to send request from */
3339 pjsip_tpmgr_fla2_param_default(&tfla2_prm);
3340 tfla2_prm.tp_type = tp_type;
3341 tfla2_prm.tp_sel = &tp_sel;
3342 tfla2_prm.dst_host = sip_uri->host;
3343 tfla2_prm.local_if = (!pjsua_sip_acc_is_using_stun(acc_id) ||
3344 (flag & PJSIP_TRANSPORT_RELIABLE));
3345
3346 tpmgr = pjsip_endpt_get_tpmgr(pjsua_var.endpt);
3347 status = pjsip_tpmgr_find_local_addr2(tpmgr, pool, &tfla2_prm);
3348 if (status != PJ_SUCCESS)
3349 return status;
3350
3351 /* Set this as default return value. This may be changed below. */
3352 addr->host = tfla2_prm.ret_addr;
3353 addr->port = tfla2_prm.ret_port;
3354
3355 /* If we are behind NAT64, use the Contact and Via address from
3356 * the UDP6 transport, which should be obtained from STUN.
3357 */
3358 if (acc->cfg.nat64_opt != PJSUA_NAT64_DISABLED) {
3359 pjsip_tpmgr_fla2_param tfla2_prm2 = tfla2_prm;
3360
3361 tfla2_prm2.tp_type = PJSIP_TRANSPORT_UDP6;
3362 tfla2_prm2.tp_sel = NULL;
3363 tfla2_prm2.local_if = (!pjsua_sip_acc_is_using_stun(acc_id));
3364 status = pjsip_tpmgr_find_local_addr2(tpmgr, pool, &tfla2_prm2);
3365 if (status == PJ_SUCCESS) {
3366 update_addr = PJ_FALSE;
3367 addr->host = tfla2_prm2.ret_addr;
3368 pj_strdup(acc->pool, &acc->via_addr.host, &addr->host);
3369 acc->via_addr.port = addr->port;
3370 acc->via_tp = (pjsip_transport *)tfla2_prm.ret_tp;
3371 }
3372 } else
3373 /* For UDP transport, check if we need to overwrite the address
3374 * with its bound address.
3375 */
3376 if ((flag & PJSIP_TRANSPORT_DATAGRAM) && tfla2_prm.local_if &&
3377 tfla2_prm.ret_tp)
3378 {
3379 int i;
3380
3381 for (i = 0; i < sizeof(pjsua_var.tpdata); i++) {
3382 if (tfla2_prm.ret_tp==(const void *)pjsua_var.tpdata[i].data.tp) {
3383 if (pjsua_var.tpdata[i].has_bound_addr) {
3384 pj_strdup(pool, &addr->host,
3385 &pjsua_var.tpdata[i].data.tp->local_name.host);
3386 addr->port = (pj_uint16_t)
3387 pjsua_var.tpdata[i].data.tp->local_name.port;
3388 }
3389 break;
3390 }
3391 }
3392 }
3393
3394 /* For TCP/TLS, acc may request to specify source port */
3395 if (acc->cfg.contact_use_src_port) {
3396 pjsip_host_info dinfo;
3397 pjsip_transport *tp = NULL;
3398 pj_addrinfo ai;
3399 pj_bool_t log_written = PJ_FALSE;
3400
3401 status = pjsip_get_dest_info((pjsip_uri*)sip_uri, NULL,
3402 pool, &dinfo);
3403
3404 if (status==PJ_SUCCESS && (dinfo.flag & PJSIP_TRANSPORT_RELIABLE)==0) {
3405 /* Not TCP or TLS. No need to do this */
3406 status = PJ_EINVALIDOP;
3407 log_written = PJ_TRUE;
3408 }
3409
3410 if (status==PJ_SUCCESS &&
3411 get_ip_addr_ver(&dinfo.addr.host)==0 &&
3412 pjsua_var.ua_cfg.nameserver_count)
3413 {
3414 /* If nameserver is configured, PJSIP will resolve destinations
3415 * by their DNS SRV record first. On the other hand, we will
3416 * resolve destination with DNS A record via pj_getaddrinfo().
3417 * They may yield different IP addresses, hence causing different
3418 * TCP/TLS connection to be created and hence different source
3419 * address.
3420 */
3421 PJ_LOG(4,(THIS_FILE, "Warning: cannot use source TCP/TLS socket"
3422 " address for Contact when nameserver is configured."));
3423 status = PJ_ENOTSUP;
3424 log_written = PJ_TRUE;
3425 }
3426
3427 if (status == PJ_SUCCESS) {
3428 unsigned cnt=1;
3429 int af = pj_AF_UNSPEC();
3430
3431 if (pjsua_sip_acc_is_using_ipv6(acc_id) ||
3432 (dinfo.type & PJSIP_TRANSPORT_IPV6))
3433 {
3434 af = pj_AF_INET6();
3435 }
3436 status = pj_getaddrinfo(af, &dinfo.addr.host, &cnt, &ai);
3437 if (cnt == 0) {
3438 status = PJ_ENOTSUP;
3439 } else if ((dinfo.type & PJSIP_TRANSPORT_IPV6)==0 &&
3440 ai.ai_addr.addr.sa_family == pj_AF_INET6())
3441 {
3442 /* Destination is a hostname and account is not bound to IPv6,
3443 * but hostname resolution reveals that it has IPv6 address,
3444 * so let's use IPv6 transport type.
3445 */
3446 dinfo.type |= PJSIP_TRANSPORT_IPV6;
3447 tp_type |= PJSIP_TRANSPORT_IPV6;
3448 }
3449 }
3450
3451 if (status == PJ_SUCCESS) {
3452 pjsip_tx_data tdata;
3453 int addr_len = pj_sockaddr_get_len(&ai.ai_addr);
3454 pj_uint16_t port = (pj_uint16_t)dinfo.addr.port;
3455
3456 /* Create a dummy tdata to inform remote host name to transport */
3457 pj_bzero(&tdata, sizeof(tdata));
3458 pj_strdup(pool, &tdata.dest_info.name, &dinfo.addr.host);
3459
3460 if (port==0) {
3461 port = (dinfo.flag & PJSIP_TRANSPORT_SECURE) ? 5061 : 5060;
3462 }
3463 pj_sockaddr_set_port(&ai.ai_addr, port);
3464 status = pjsip_endpt_acquire_transport2(pjsua_var.endpt,
3465 dinfo.type,
3466 &ai.ai_addr,
3467 addr_len,
3468 &tp_sel,
3469 &tdata, &tp);
3470 }
3471
3472 if (status == PJ_SUCCESS && (tp->local_name.port == 0 ||
3473 tp->local_name.host.slen==0 ||
3474 *tp->local_name.host.ptr=='0'))
3475 {
3476 /* Trap zero port or "0.0.0.0" address. */
3477 /* The TCP/TLS transport is still connecting and unfortunately
3478 * this OS doesn't report the bound local address in this state.
3479 */
3480 PJ_LOG(4,(THIS_FILE, "Unable to get transport local port "
3481 "for Contact address (OS doesn't support)"));
3482 status = PJ_ENOTSUP;
3483 log_written = PJ_TRUE;
3484 }
3485
3486 if (status == PJ_SUCCESS) {
3487 /* Got the local transport address, don't update if
3488 * we are on NAT64 and already obtained the address
3489 * from STUN above.
3490 */
3491 if (update_addr)
3492 pj_strdup(pool, &addr->host, &tp->local_name.host);
3493 addr->port = tp->local_name.port;
3494 }
3495
3496 if (tp) {
3497 /* Here the transport's ref counter WILL reach zero. But the
3498 * transport will NOT get destroyed because it should have an
3499 * idle timer.
3500 */
3501 pjsip_transport_dec_ref(tp);
3502 tp = NULL;
3503 }
3504
3505 if (status != PJ_SUCCESS && !log_written) {
3506 PJ_PERROR(4,(THIS_FILE, status, "Unable to use source local "
3507 "TCP socket address for Contact"));
3508 }
3509 status = PJ_SUCCESS;
3510 }
3511
3512 if (p_tp_type)
3513 *p_tp_type = tp_type;
3514
3515 if (secure) {
3516 *secure = (flag & PJSIP_TRANSPORT_SECURE) != 0;
3517 }
3518
3519 if (p_tp)
3520 *p_tp = tfla2_prm.ret_tp;
3521
3522 return PJ_SUCCESS;
3523 }
3524
3525
pjsua_acc_create_uac_contact(pj_pool_t * pool,pj_str_t * contact,pjsua_acc_id acc_id,const pj_str_t * suri)3526 PJ_DEF(pj_status_t) pjsua_acc_create_uac_contact( pj_pool_t *pool,
3527 pj_str_t *contact,
3528 pjsua_acc_id acc_id,
3529 const pj_str_t *suri)
3530 {
3531 pjsua_acc *acc;
3532 pj_status_t status;
3533 pjsip_transport_type_e tp_type;
3534 pjsip_host_port addr;
3535 int secure;
3536 const char *beginquote, *endquote;
3537 char transport_param[32];
3538 const char *ob = ";ob";
3539
3540
3541 PJ_ASSERT_RETURN(pjsua_acc_is_valid(acc_id), PJ_EINVAL);
3542 acc = &pjsua_var.acc[acc_id];
3543
3544 /* If force_contact is configured, then use use it */
3545 if (acc->cfg.force_contact.slen) {
3546 *contact = acc->cfg.force_contact;
3547 return PJ_SUCCESS;
3548 }
3549
3550 status = pjsua_acc_get_uac_addr(acc_id, pool, suri, &addr,
3551 &tp_type, &secure, NULL);
3552 if (status != PJ_SUCCESS)
3553 return status;
3554
3555 /* Enclose IPv6 address in square brackets */
3556 if (tp_type & PJSIP_TRANSPORT_IPV6) {
3557 beginquote = "[";
3558 endquote = "]";
3559 } else {
3560 beginquote = endquote = "";
3561 }
3562
3563 /* Don't add transport parameter if it's UDP */
3564 if (tp_type!=PJSIP_TRANSPORT_UDP && tp_type!=PJSIP_TRANSPORT_UDP6) {
3565 pj_ansi_snprintf(transport_param, sizeof(transport_param),
3566 ";transport=%s",
3567 pjsip_transport_get_type_name(tp_type));
3568 } else {
3569 transport_param[0] = '\0';
3570 }
3571
3572
3573 /* Create the contact header */
3574 contact->ptr = (char*)pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
3575 contact->slen = pj_ansi_snprintf(contact->ptr, PJSIP_MAX_URL_SIZE,
3576 "%s%.*s%s<%s:%.*s%s%s%.*s%s:%d%s%.*s%s>%.*s",
3577 (acc->display.slen?"\"" : ""),
3578 (int)acc->display.slen,
3579 acc->display.ptr,
3580 (acc->display.slen?"\" " : ""),
3581 ((secure && acc->is_sips)? "sips" : "sip"),
3582 (int)acc->user_part.slen,
3583 acc->user_part.ptr,
3584 (acc->user_part.slen?"@":""),
3585 beginquote,
3586 (int)addr.host.slen,
3587 addr.host.ptr,
3588 endquote,
3589 addr.port,
3590 transport_param,
3591 (int)acc->cfg.contact_uri_params.slen,
3592 acc->cfg.contact_uri_params.ptr,
3593 (acc->cfg.use_rfc5626? ob: ""),
3594 (int)acc->cfg.contact_params.slen,
3595 acc->cfg.contact_params.ptr);
3596 if (contact->slen < 1 || contact->slen >= (int)PJSIP_MAX_URL_SIZE)
3597 return PJ_ETOOSMALL;
3598 return PJ_SUCCESS;
3599 }
3600
3601
3602
pjsua_acc_create_uas_contact(pj_pool_t * pool,pj_str_t * contact,pjsua_acc_id acc_id,pjsip_rx_data * rdata)3603 PJ_DEF(pj_status_t) pjsua_acc_create_uas_contact( pj_pool_t *pool,
3604 pj_str_t *contact,
3605 pjsua_acc_id acc_id,
3606 pjsip_rx_data *rdata )
3607 {
3608 /*
3609 * Section 12.1.1, paragraph about using SIPS URI in Contact.
3610 * If the request that initiated the dialog contained a SIPS URI
3611 * in the Request-URI or in the top Record-Route header field value,
3612 * if there was any, or the Contact header field if there was no
3613 * Record-Route header field, the Contact header field in the response
3614 * MUST be a SIPS URI.
3615 */
3616 pjsua_acc *acc;
3617 pjsip_sip_uri *sip_uri;
3618 pj_status_t status;
3619 pjsip_transport_type_e tp_type = PJSIP_TRANSPORT_UNSPECIFIED;
3620 pj_str_t local_addr;
3621 pjsip_tpselector tp_sel;
3622 pjsip_tpmgr *tpmgr;
3623 pjsip_tpmgr_fla2_param tfla2_prm;
3624 unsigned flag;
3625 int secure;
3626 int local_port;
3627 const char *beginquote, *endquote;
3628 char transport_param[32];
3629
3630 PJ_ASSERT_RETURN(pjsua_acc_is_valid(acc_id), PJ_EINVAL);
3631 acc = &pjsua_var.acc[acc_id];
3632
3633 /* If force_contact is configured, then use use it */
3634 if (acc->cfg.force_contact.slen) {
3635 *contact = acc->cfg.force_contact;
3636 return PJ_SUCCESS;
3637 }
3638
3639 /* If Record-Route is present, then URI is the top Record-Route. */
3640 if (rdata->msg_info.record_route) {
3641 sip_uri = (pjsip_sip_uri*)
3642 pjsip_uri_get_uri(rdata->msg_info.record_route->name_addr.uri);
3643 } else {
3644 pjsip_hdr *pos = NULL;
3645 pjsip_contact_hdr *h_contact;
3646 pjsip_uri *uri = NULL;
3647
3648 /* Otherwise URI is Contact URI.
3649 * Iterate the Contact URI until we find sip: or sips: scheme.
3650 */
3651 do {
3652 h_contact = (pjsip_contact_hdr*)
3653 pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT,
3654 pos);
3655 if (h_contact) {
3656 if (h_contact->uri)
3657 uri = (pjsip_uri*) pjsip_uri_get_uri(h_contact->uri);
3658 else
3659 uri = NULL;
3660 if (!uri || (!PJSIP_URI_SCHEME_IS_SIP(uri) &&
3661 !PJSIP_URI_SCHEME_IS_SIPS(uri)))
3662 {
3663 pos = (pjsip_hdr*)h_contact->next;
3664 if (pos == &rdata->msg_info.msg->hdr)
3665 h_contact = NULL;
3666 } else {
3667 break;
3668 }
3669 }
3670 } while (h_contact);
3671
3672
3673 /* Or if Contact URI is not present, take the remote URI from
3674 * the From URI.
3675 */
3676 if (uri == NULL)
3677 uri = (pjsip_uri*) pjsip_uri_get_uri(rdata->msg_info.from->uri);
3678
3679
3680 /* Can only do sip/sips scheme at present. */
3681 if (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri))
3682 return PJSIP_EINVALIDREQURI;
3683
3684 sip_uri = (pjsip_sip_uri*)pjsip_uri_get_uri(uri);
3685 }
3686
3687 /* Get transport type of the URI */
3688 if (PJSIP_URI_SCHEME_IS_SIPS(sip_uri))
3689 tp_type = PJSIP_TRANSPORT_TLS;
3690 else if (sip_uri->transport_param.slen == 0) {
3691 tp_type = PJSIP_TRANSPORT_UDP;
3692 } else
3693 tp_type = pjsip_transport_get_type_from_name(&sip_uri->transport_param);
3694
3695 if (tp_type == PJSIP_TRANSPORT_UNSPECIFIED)
3696 return PJSIP_EUNSUPTRANSPORT;
3697
3698 /* If destination URI specifies IPv6 or account is configured to use IPv6
3699 * or the transport being used to receive data is an IPv6 transport,
3700 * then set transport type to use IPv6 as well.
3701 */
3702 if (pj_strchr(&sip_uri->host, ':') ||
3703 pjsua_sip_acc_is_using_ipv6(acc_id) ||
3704 (rdata->tp_info.transport->key.type & PJSIP_TRANSPORT_IPV6))
3705 {
3706 tp_type = (pjsip_transport_type_e)
3707 (((int)tp_type) | PJSIP_TRANSPORT_IPV6);
3708 }
3709
3710 flag = pjsip_transport_get_flag_from_type(tp_type);
3711 secure = (flag & PJSIP_TRANSPORT_SECURE) != 0;
3712
3713 /* Init transport selector. */
3714 pjsua_init_tpselector(pjsua_var.acc[acc_id].cfg.transport_id, &tp_sel);
3715
3716 /* Get local address suitable to send request from */
3717 pjsip_tpmgr_fla2_param_default(&tfla2_prm);
3718 tfla2_prm.tp_type = tp_type;
3719 tfla2_prm.tp_sel = &tp_sel;
3720 tfla2_prm.dst_host = sip_uri->host;
3721 tfla2_prm.local_if = (!pjsua_sip_acc_is_using_stun(acc_id) ||
3722 (flag & PJSIP_TRANSPORT_RELIABLE));
3723
3724 tpmgr = pjsip_endpt_get_tpmgr(pjsua_var.endpt);
3725 status = pjsip_tpmgr_find_local_addr2(tpmgr, pool, &tfla2_prm);
3726 if (status != PJ_SUCCESS)
3727 return status;
3728
3729 local_addr = tfla2_prm.ret_addr;
3730 local_port = tfla2_prm.ret_port;
3731
3732
3733 /* Enclose IPv6 address in square brackets */
3734 if (tp_type & PJSIP_TRANSPORT_IPV6) {
3735 beginquote = "[";
3736 endquote = "]";
3737 } else {
3738 beginquote = endquote = "";
3739 }
3740
3741 /* Don't add transport parameter if it's UDP */
3742 if (tp_type!=PJSIP_TRANSPORT_UDP && tp_type!=PJSIP_TRANSPORT_UDP6) {
3743 pj_ansi_snprintf(transport_param, sizeof(transport_param),
3744 ";transport=%s",
3745 pjsip_transport_get_type_name(tp_type));
3746 } else {
3747 transport_param[0] = '\0';
3748 }
3749
3750
3751 /* Create the contact header */
3752 contact->ptr = (char*) pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
3753 contact->slen = pj_ansi_snprintf(contact->ptr, PJSIP_MAX_URL_SIZE,
3754 "%s%.*s%s<%s:%.*s%s%s%.*s%s:%d%s%.*s>%.*s",
3755 (acc->display.slen?"\"" : ""),
3756 (int)acc->display.slen,
3757 acc->display.ptr,
3758 (acc->display.slen?"\" " : ""),
3759 ((secure && acc->is_sips)? "sips" : "sip"),
3760 (int)acc->user_part.slen,
3761 acc->user_part.ptr,
3762 (acc->user_part.slen?"@":""),
3763 beginquote,
3764 (int)local_addr.slen,
3765 local_addr.ptr,
3766 endquote,
3767 local_port,
3768 transport_param,
3769 (int)acc->cfg.contact_uri_params.slen,
3770 acc->cfg.contact_uri_params.ptr,
3771 (int)acc->cfg.contact_params.slen,
3772 acc->cfg.contact_params.ptr);
3773 if (contact->slen < 1 || contact->slen >= (int)PJSIP_MAX_URL_SIZE)
3774 return PJ_ETOOSMALL;
3775
3776 return PJ_SUCCESS;
3777 }
3778
3779
pjsua_acc_set_transport(pjsua_acc_id acc_id,pjsua_transport_id tp_id)3780 PJ_DEF(pj_status_t) pjsua_acc_set_transport( pjsua_acc_id acc_id,
3781 pjsua_transport_id tp_id)
3782 {
3783 pjsua_acc *acc;
3784
3785 PJ_ASSERT_RETURN(pjsua_acc_is_valid(acc_id), PJ_EINVAL);
3786 acc = &pjsua_var.acc[acc_id];
3787
3788 PJ_ASSERT_RETURN(tp_id >= 0 && tp_id < (int)PJ_ARRAY_SIZE(pjsua_var.tpdata),
3789 PJ_EINVAL);
3790
3791 acc->cfg.transport_id = tp_id;
3792 acc->tp_type = pjsua_var.tpdata[tp_id].type;
3793
3794 return PJ_SUCCESS;
3795 }
3796
3797
3798 /* Auto re-registration timeout callback */
auto_rereg_timer_cb(pj_timer_heap_t * th,pj_timer_entry * te)3799 static void auto_rereg_timer_cb(pj_timer_heap_t *th, pj_timer_entry *te)
3800 {
3801 pjsua_acc *acc;
3802 pj_status_t status;
3803
3804 PJ_UNUSED_ARG(th);
3805 acc = (pjsua_acc*) te->user_data;
3806 pj_assert(acc);
3807
3808 PJSUA_LOCK();
3809
3810 /* Check if the reregistration timer is still valid, e.g: while waiting
3811 * timeout timer application might have deleted the account or disabled
3812 * the auto-reregistration.
3813 */
3814 if (!acc->valid || !acc->auto_rereg.active ||
3815 acc->cfg.reg_retry_interval == 0)
3816 {
3817 goto on_return;
3818 }
3819
3820 /* Start re-registration */
3821 acc->auto_rereg.attempt_cnt++;
3822
3823 /* Generate new contact as the current contact may use a disconnected
3824 * transport. Only do this when outbound is not active and contact is not
3825 * rewritten (where the contact address may really be used by server to
3826 * contact the UA).
3827 */
3828 if (acc->rfc5626_status != OUTBOUND_ACTIVE && !acc->contact_rewritten) {
3829 pj_str_t tmp_contact;
3830 pj_pool_t *pool;
3831
3832 pool = pjsua_pool_create("tmpregc", 512, 512);
3833
3834 status = pjsua_acc_create_uac_contact(pool, &tmp_contact, acc->index,
3835 &acc->cfg.reg_uri);
3836 if (status != PJ_SUCCESS) {
3837 pjsua_perror(THIS_FILE,
3838 "Unable to generate suitable Contact header"
3839 " for re-registration", status);
3840 pj_pool_release(pool);
3841 schedule_reregistration(acc);
3842 goto on_return;
3843 }
3844
3845 if (pj_strcmp(&tmp_contact, &acc->contact)) {
3846 if (acc->contact.slen < tmp_contact.slen) {
3847 pj_strdup_with_null(acc->pool, &acc->contact, &tmp_contact);
3848 } else {
3849 pj_strcpy(&acc->contact, &tmp_contact);
3850 }
3851 update_regc_contact(acc);
3852 if (acc->regc)
3853 pjsip_regc_update_contact(acc->regc, 1, &acc->reg_contact);
3854 }
3855 pj_pool_release(pool);
3856 }
3857
3858 status = pjsua_acc_set_registration(acc->index, PJ_TRUE);
3859 if (status != PJ_SUCCESS)
3860 schedule_reregistration(acc);
3861
3862 on_return:
3863 PJSUA_UNLOCK();
3864 }
3865
3866
3867 /* Schedule reregistration for specified account. Note that the first
3868 * re-registration after a registration failure will be done immediately.
3869 * Also note that this function should be called within PJSUA mutex.
3870 */
schedule_reregistration(pjsua_acc * acc)3871 static void schedule_reregistration(pjsua_acc *acc)
3872 {
3873 pj_time_val delay;
3874
3875 pj_assert(acc);
3876
3877 /* Validate the account and re-registration feature status */
3878 if (!acc->valid || acc->cfg.reg_retry_interval == 0) {
3879 return;
3880 }
3881
3882 /* If configured, disconnect calls of this account after the first
3883 * reregistration attempt failed.
3884 */
3885 if (acc->cfg.drop_calls_on_reg_fail && acc->auto_rereg.attempt_cnt >= 1)
3886 {
3887 unsigned i, cnt;
3888
3889 for (i = 0, cnt = 0; i < pjsua_var.ua_cfg.max_calls; ++i) {
3890 if (pjsua_var.calls[i].acc_id == acc->index) {
3891 pjsua_call_hangup(i, 0, NULL, NULL);
3892 ++cnt;
3893 }
3894 }
3895
3896 if (cnt) {
3897 PJ_LOG(3, (THIS_FILE, "Disconnecting %d call(s) of account #%d "
3898 "after reregistration attempt failed",
3899 cnt, acc->index));
3900 }
3901 }
3902
3903 /* Cancel any re-registration timer */
3904 if (acc->auto_rereg.timer.id) {
3905 acc->auto_rereg.timer.id = PJ_FALSE;
3906 pjsua_cancel_timer(&acc->auto_rereg.timer);
3907 }
3908
3909 /* Update re-registration flag */
3910 acc->auto_rereg.active = PJ_TRUE;
3911
3912 /* Set up timer for reregistration */
3913 acc->auto_rereg.timer.cb = &auto_rereg_timer_cb;
3914 acc->auto_rereg.timer.user_data = acc;
3915
3916 /* Reregistration attempt. The first attempt will be done immediately. */
3917 delay.sec = acc->auto_rereg.attempt_cnt? acc->cfg.reg_retry_interval :
3918 acc->cfg.reg_first_retry_interval;
3919 delay.msec = 0;
3920
3921 /* Randomize interval by +/- reg_retry_random_interval, if configured */
3922 if (acc->cfg.reg_retry_random_interval) {
3923 long rand_ms = acc->cfg.reg_retry_random_interval * 1000;
3924 if (delay.sec >= (long)acc->cfg.reg_retry_random_interval) {
3925 delay.msec = -rand_ms + (pj_rand() % (rand_ms * 2));
3926 } else {
3927 delay.sec = 0;
3928 delay.msec = (pj_rand() % (delay.sec * 1000 + rand_ms));
3929 }
3930 }
3931 pj_time_val_normalize(&delay);
3932
3933 PJ_LOG(4,(THIS_FILE,
3934 "Scheduling re-registration retry for acc %d in %u seconds..",
3935 acc->index, delay.sec));
3936
3937 acc->auto_rereg.timer.id = PJ_TRUE;
3938 if (pjsua_schedule_timer(&acc->auto_rereg.timer, &delay) != PJ_SUCCESS)
3939 acc->auto_rereg.timer.id = PJ_FALSE;
3940 }
3941
3942
3943 /* Internal function to perform auto-reregistration on transport
3944 * connection/disconnection events.
3945 */
pjsua_acc_on_tp_state_changed(pjsip_transport * tp,pjsip_transport_state state,const pjsip_transport_state_info * info)3946 void pjsua_acc_on_tp_state_changed(pjsip_transport *tp,
3947 pjsip_transport_state state,
3948 const pjsip_transport_state_info *info)
3949 {
3950 unsigned i;
3951
3952 PJ_UNUSED_ARG(info);
3953
3954 /* Only care for transport disconnection events */
3955 if (state != PJSIP_TP_STATE_DISCONNECTED)
3956 return;
3957
3958 PJ_LOG(4,(THIS_FILE, "Disconnected notification for transport %s",
3959 tp->obj_name));
3960 pj_log_push_indent();
3961
3962 /* Shutdown this transport, to make sure that the transport manager
3963 * will create a new transport for reconnection.
3964 */
3965 pjsip_transport_shutdown(tp);
3966
3967 PJSUA_LOCK();
3968
3969 /* Enumerate accounts using this transport and perform actions
3970 * based on the transport state.
3971 */
3972 for (i = 0; i < PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
3973 pjsua_acc *acc = &pjsua_var.acc[i];
3974
3975 /* Skip if this account is not valid. */
3976 if (!acc->valid)
3977 continue;
3978
3979 /* Reset Account's via transport and via address */
3980 if (acc->via_tp == (void*)tp) {
3981 pj_bzero(&acc->via_addr, sizeof(acc->via_addr));
3982 acc->via_tp = NULL;
3983
3984 /* Also reset regc's Via addr */
3985 if (acc->regc)
3986 pjsip_regc_set_via_sent_by(acc->regc, NULL, NULL);
3987 }
3988
3989 /* Release transport immediately if regc is using it
3990 * See https://trac.pjsip.org/repos/ticket/1481
3991 */
3992 if (acc->regc) {
3993 pjsip_regc_info reg_info;
3994
3995 pjsip_regc_get_info(acc->regc, ®_info);
3996 if (reg_info.transport != tp)
3997 continue;
3998
3999 pjsip_regc_release_transport(pjsua_var.acc[i].regc);
4000
4001 if (pjsua_var.acc[i].ip_change_op ==
4002 PJSUA_IP_CHANGE_OP_ACC_SHUTDOWN_TP)
4003 {
4004 /* Before progressing to next step, report here. */
4005 if (pjsua_var.ua_cfg.cb.on_ip_change_progress) {
4006 pjsua_ip_change_op_info ch_info;
4007
4008 pj_bzero(&ch_info, sizeof(ch_info));
4009 ch_info.acc_shutdown_tp.acc_id = acc->index;
4010
4011 pjsua_var.ua_cfg.cb.on_ip_change_progress(
4012 acc->ip_change_op,
4013 PJ_SUCCESS,
4014 &ch_info);
4015 }
4016
4017 if (acc->cfg.allow_contact_rewrite) {
4018 pjsua_acc_update_contact_on_ip_change(acc);
4019 } else {
4020 pjsua_acc_handle_call_on_ip_change(acc);
4021 }
4022 } else if (acc->cfg.reg_retry_interval) {
4023 /* Schedule reregistration for this account */
4024 schedule_reregistration(acc);
4025 }
4026 }
4027 }
4028
4029 PJSUA_UNLOCK();
4030 pj_log_pop_indent();
4031 }
4032
4033
4034 /*
4035 * Internal function to update contact on ip change process.
4036 */
pjsua_acc_update_contact_on_ip_change(pjsua_acc * acc)4037 pj_status_t pjsua_acc_update_contact_on_ip_change(pjsua_acc *acc)
4038 {
4039 pj_status_t status;
4040 pj_bool_t need_unreg = ((acc->cfg.contact_rewrite_method &
4041 PJSUA_CONTACT_REWRITE_UNREGISTER) != 0);
4042
4043 acc->ip_change_op = PJSUA_IP_CHANGE_OP_ACC_UPDATE_CONTACT;
4044
4045 PJ_LOG(3, (THIS_FILE, "%.*s: send %sregistration triggered "
4046 "by IP change", acc->cfg.id.slen,
4047 acc->cfg.id.ptr, (need_unreg ? "un-" : "")));
4048
4049 status = pjsua_acc_set_registration(acc->index, !need_unreg);
4050
4051 if ((status != PJ_SUCCESS) && (pjsua_var.ua_cfg.cb.on_ip_change_progress)
4052 && (acc->ip_change_op == PJSUA_IP_CHANGE_OP_ACC_UPDATE_CONTACT))
4053 {
4054 /* If update contact fails, notification might already been triggered
4055 * from registration callback.
4056 */
4057 pjsua_ip_change_op_info info;
4058
4059 pj_bzero(&info, sizeof(info));
4060 info.acc_update_contact.acc_id = acc->index;
4061 info.acc_update_contact.is_register = !need_unreg;
4062
4063 pjsua_var.ua_cfg.cb.on_ip_change_progress(acc->ip_change_op,
4064 status,
4065 &info);
4066
4067 pjsua_acc_end_ip_change(acc);
4068 }
4069 return status;
4070 }
4071
4072
4073 /*
4074 * Internal function to handle call on ip change process.
4075 */
pjsua_acc_handle_call_on_ip_change(pjsua_acc * acc)4076 pj_status_t pjsua_acc_handle_call_on_ip_change(pjsua_acc *acc)
4077 {
4078 pj_status_t status = PJ_SUCCESS;
4079 unsigned i = 0;
4080
4081 PJSUA_LOCK();
4082 if (acc->cfg.ip_change_cfg.hangup_calls ||
4083 acc->cfg.ip_change_cfg.reinvite_flags)
4084 {
4085 for (i = 0; i < (int)pjsua_var.ua_cfg.max_calls; ++i) {
4086 pjsua_call_info call_info;
4087 pjsua_call_get_info(i, &call_info);
4088
4089 if (pjsua_var.calls[i].acc_id != acc->index)
4090 {
4091 continue;
4092 }
4093
4094 if ((acc->cfg.ip_change_cfg.hangup_calls) &&
4095 (call_info.state >= PJSIP_INV_STATE_EARLY))
4096 {
4097 acc->ip_change_op = PJSUA_IP_CHANGE_OP_ACC_HANGUP_CALLS;
4098 PJ_LOG(3, (THIS_FILE, "call to %.*s: hangup "
4099 "triggered by IP change",
4100 (int)call_info.remote_info.slen,
4101 call_info.remote_info.ptr));
4102
4103 status = pjsua_call_hangup(i, PJSIP_SC_GONE, NULL, NULL);
4104
4105 if (pjsua_var.ua_cfg.cb.on_ip_change_progress) {
4106 pjsua_ip_change_op_info info;
4107
4108 pj_bzero(&info, sizeof(info));
4109 info.acc_hangup_calls.acc_id = acc->index;
4110 info.acc_hangup_calls.call_id = call_info.id;
4111
4112 pjsua_var.ua_cfg.cb.on_ip_change_progress(
4113 acc->ip_change_op,
4114 status,
4115 &info);
4116 }
4117 } else if ((acc->cfg.ip_change_cfg.reinvite_flags) &&
4118 (call_info.state == PJSIP_INV_STATE_CONFIRMED))
4119 {
4120 acc->ip_change_op = PJSUA_IP_CHANGE_OP_ACC_REINVITE_CALLS;
4121
4122 pjsua_call_cleanup_flag(&call_info.setting);
4123 call_info.setting.flag |=
4124 acc->cfg.ip_change_cfg.reinvite_flags;
4125
4126 PJ_LOG(3, (THIS_FILE, "call to %.*s: send "
4127 "re-INVITE with flags 0x%x triggered "
4128 "by IP change (IP change flag: 0x%x)",
4129 call_info.remote_info.slen,
4130 call_info.remote_info.ptr,
4131 call_info.setting.flag,
4132 acc->cfg.ip_change_cfg.reinvite_flags));
4133
4134 status = pjsua_call_reinvite(i, call_info.setting.flag, NULL);
4135
4136 if (pjsua_var.ua_cfg.cb.on_ip_change_progress) {
4137 pjsua_ip_change_op_info info;
4138
4139 pj_bzero(&info, sizeof(info));
4140 info.acc_reinvite_calls.acc_id = acc->index;
4141 info.acc_reinvite_calls.call_id = call_info.id;
4142
4143 pjsua_var.ua_cfg.cb.on_ip_change_progress(
4144 acc->ip_change_op,
4145 status,
4146 &info);
4147 }
4148
4149 }
4150 }
4151 }
4152 pjsua_acc_end_ip_change(acc);
4153 PJSUA_UNLOCK();
4154 return status;
4155 }
4156
pjsua_acc_end_ip_change(pjsua_acc * acc)4157 void pjsua_acc_end_ip_change(pjsua_acc *acc)
4158 {
4159 int i = 0;
4160 pj_bool_t all_done = PJ_TRUE;
4161
4162 PJSUA_LOCK();
4163 if (acc && acc->ip_change_op < PJSUA_IP_CHANGE_OP_COMPLETED) {
4164 PJ_LOG(3, (THIS_FILE, "IP address change handling for acc %d "
4165 "completed", acc->index));
4166 acc->ip_change_op = PJSUA_IP_CHANGE_OP_COMPLETED;
4167 if (pjsua_var.acc_cnt) {
4168 for (; i < (int)PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
4169 if (pjsua_var.acc[i].valid &&
4170 pjsua_var.acc[i].ip_change_op !=
4171 PJSUA_IP_CHANGE_OP_COMPLETED)
4172 {
4173 all_done = PJ_FALSE;
4174 break;
4175 }
4176 }
4177 }
4178 }
4179 if (all_done && pjsua_var.ua_cfg.cb.on_ip_change_progress) {
4180 PJ_LOG(3, (THIS_FILE, "IP address change handling completed"));
4181 pjsua_var.ua_cfg.cb.on_ip_change_progress(
4182 PJSUA_IP_CHANGE_OP_COMPLETED,
4183 PJ_SUCCESS,
4184 NULL);
4185 }
4186 PJSUA_UNLOCK();
4187 }
4188