blob: bc0cc40638d4c05372d1bcae81b87266ce6bd355 [file] [log] [blame]
Alexandre Lision8af73cb2013-12-10 14:11:20 -05001/* $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_core.c"
25
26
27/* Internal prototypes */
28static void resolve_stun_entry(pjsua_stun_resolve *sess);
29
30
31/* PJSUA application instance. */
32struct pjsua_data pjsua_var;
33
34
35PJ_DEF(struct pjsua_data*) pjsua_get_var(void)
36{
37 return &pjsua_var;
38}
39
40
41/* Display error */
42PJ_DEF(void) pjsua_perror( const char *sender, const char *title,
43 pj_status_t status)
44{
45 char errmsg[PJ_ERR_MSG_SIZE];
46
47 pj_strerror(status, errmsg, sizeof(errmsg));
48 PJ_LOG(1,(sender, "%s: %s [status=%d]", title, errmsg, status));
49}
50
51
52static void init_data()
53{
54 unsigned i;
55
56 pj_bzero(&pjsua_var, sizeof(pjsua_var));
57
58 for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.acc); ++i)
59 pjsua_var.acc[i].index = i;
60
61 for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.tpdata); ++i)
62 pjsua_var.tpdata[i].index = i;
63
64 pjsua_var.stun_status = PJ_EUNKNOWN;
65 pjsua_var.nat_status = PJ_EPENDING;
66 pj_list_init(&pjsua_var.stun_res);
67 pj_list_init(&pjsua_var.outbound_proxy);
68
69 pjsua_config_default(&pjsua_var.ua_cfg);
70
71 for (i=0; i<PJSUA_MAX_VID_WINS; ++i) {
72 pjsua_vid_win_reset(i);
73 }
74}
75
76
77PJ_DEF(void) pjsua_logging_config_default(pjsua_logging_config *cfg)
78{
79 pj_bzero(cfg, sizeof(*cfg));
80
81 cfg->msg_logging = PJ_TRUE;
82 cfg->level = 5;
83 cfg->console_level = 4;
84 cfg->decor = PJ_LOG_HAS_SENDER | PJ_LOG_HAS_TIME |
85 PJ_LOG_HAS_MICRO_SEC | PJ_LOG_HAS_NEWLINE |
86 PJ_LOG_HAS_SPACE | PJ_LOG_HAS_THREAD_SWC |
87 PJ_LOG_HAS_INDENT;
88#if (defined(PJ_WIN32) && PJ_WIN32 != 0) || (defined(PJ_WIN64) && PJ_WIN64 != 0)
89 cfg->decor |= PJ_LOG_HAS_COLOR;
90#endif
91}
92
93PJ_DEF(void) pjsua_logging_config_dup(pj_pool_t *pool,
94 pjsua_logging_config *dst,
95 const pjsua_logging_config *src)
96{
97 pj_memcpy(dst, src, sizeof(*src));
98 pj_strdup_with_null(pool, &dst->log_filename, &src->log_filename);
99}
100
101PJ_DEF(void) pjsua_config_default(pjsua_config *cfg)
102{
103 pj_bzero(cfg, sizeof(*cfg));
104
105 cfg->max_calls = ((PJSUA_MAX_CALLS) < 4) ? (PJSUA_MAX_CALLS) : 4;
106 cfg->thread_cnt = 1;
107 cfg->nat_type_in_sdp = 1;
108 cfg->stun_ignore_failure = PJ_TRUE;
109 cfg->force_lr = PJ_TRUE;
110 cfg->enable_unsolicited_mwi = PJ_TRUE;
111 cfg->use_srtp = PJSUA_DEFAULT_USE_SRTP;
112 cfg->srtp_secure_signaling = PJSUA_DEFAULT_SRTP_SECURE_SIGNALING;
113 cfg->hangup_forked_call = PJ_TRUE;
114
115 cfg->use_timer = PJSUA_SIP_TIMER_OPTIONAL;
116 pjsip_timer_setting_default(&cfg->timer_setting);
117}
118
119PJ_DEF(void) pjsua_config_dup(pj_pool_t *pool,
120 pjsua_config *dst,
121 const pjsua_config *src)
122{
123 unsigned i;
124
125 pj_memcpy(dst, src, sizeof(*src));
126
127 for (i=0; i<src->outbound_proxy_cnt; ++i) {
128 pj_strdup_with_null(pool, &dst->outbound_proxy[i],
129 &src->outbound_proxy[i]);
130 }
131
132 for (i=0; i<src->cred_count; ++i) {
133 pjsip_cred_dup(pool, &dst->cred_info[i], &src->cred_info[i]);
134 }
135
136 pj_strdup_with_null(pool, &dst->user_agent, &src->user_agent);
137 pj_strdup_with_null(pool, &dst->stun_domain, &src->stun_domain);
138 pj_strdup_with_null(pool, &dst->stun_host, &src->stun_host);
139
140 for (i=0; i<src->stun_srv_cnt; ++i) {
141 pj_strdup_with_null(pool, &dst->stun_srv[i], &src->stun_srv[i]);
142 }
143}
144
145PJ_DEF(void) pjsua_msg_data_init(pjsua_msg_data *msg_data)
146{
147 pj_bzero(msg_data, sizeof(*msg_data));
148 pj_list_init(&msg_data->hdr_list);
149 pjsip_media_type_init(&msg_data->multipart_ctype, NULL, NULL);
150 pj_list_init(&msg_data->multipart_parts);
151}
152
153PJ_DEF(pjsua_msg_data*) pjsua_msg_data_clone(pj_pool_t *pool,
154 const pjsua_msg_data *rhs)
155{
156 pjsua_msg_data *msg_data;
157 const pjsip_hdr *hdr;
158 const pjsip_multipart_part *mpart;
159
160 PJ_ASSERT_RETURN(pool && rhs, NULL);
161
162 msg_data = PJ_POOL_ZALLOC_T(pool, pjsua_msg_data);
163 PJ_ASSERT_RETURN(msg_data != NULL, NULL);
164
165 pj_strdup(pool, &msg_data->target_uri, &rhs->target_uri);
166
167 pj_list_init(&msg_data->hdr_list);
168 hdr = rhs->hdr_list.next;
169 while (hdr != &rhs->hdr_list) {
170 pj_list_push_back(&msg_data->hdr_list, pjsip_hdr_clone(pool, hdr));
171 hdr = hdr->next;
172 }
173
174 pj_strdup(pool, &msg_data->content_type, &rhs->content_type);
175 pj_strdup(pool, &msg_data->msg_body, &rhs->msg_body);
176
177 pjsip_media_type_cp(pool, &msg_data->multipart_ctype,
178 &rhs->multipart_ctype);
179
180 pj_list_init(&msg_data->multipart_parts);
181 mpart = rhs->multipart_parts.next;
182 while (mpart != &rhs->multipart_parts) {
183 pj_list_push_back(&msg_data->multipart_parts,
184 pjsip_multipart_clone_part(pool, mpart));
185 mpart = mpart->next;
186 }
187
188 return msg_data;
189}
190
191PJ_DEF(void) pjsua_transport_config_default(pjsua_transport_config *cfg)
192{
193 pj_bzero(cfg, sizeof(*cfg));
194 pjsip_tls_setting_default(&cfg->tls_setting);
195}
196
197PJ_DEF(void) pjsua_transport_config_dup(pj_pool_t *pool,
198 pjsua_transport_config *dst,
199 const pjsua_transport_config *src)
200{
201 pj_memcpy(dst, src, sizeof(*src));
202 pj_strdup(pool, &dst->public_addr, &src->public_addr);
203 pj_strdup(pool, &dst->bound_addr, &src->bound_addr);
204}
205
206PJ_DEF(void) pjsua_ice_config_from_media_config( pj_pool_t *pool,
207 pjsua_ice_config *dst,
208 const pjsua_media_config *src)
209{
210 PJ_UNUSED_ARG(pool);
211
212 dst->enable_ice = src->enable_ice;
213 dst->ice_max_host_cands = src->ice_max_host_cands;
214 dst->ice_opt = src->ice_opt;
215 dst->ice_no_rtcp = src->ice_no_rtcp;
216 dst->ice_always_update = src->ice_always_update;
217}
218
219PJ_DEF(void) pjsua_ice_config_dup( pj_pool_t *pool,
220 pjsua_ice_config *dst,
221 const pjsua_ice_config *src)
222{
223 PJ_UNUSED_ARG(pool);
224 pj_memcpy(dst, src, sizeof(*src));
225}
226
227PJ_DEF(void) pjsua_turn_config_from_media_config(pj_pool_t *pool,
228 pjsua_turn_config *dst,
229 const pjsua_media_config *src)
230{
231 dst->enable_turn = src->enable_turn;
232 dst->turn_conn_type = src->turn_conn_type;
233 if (pool == NULL) {
234 dst->turn_server = src->turn_server;
235 dst->turn_auth_cred = src->turn_auth_cred;
236 } else {
237 if (pj_stricmp(&dst->turn_server, &src->turn_server))
238 pj_strdup(pool, &dst->turn_server, &src->turn_server);
239 pj_stun_auth_cred_dup(pool, &dst->turn_auth_cred,
240 &src->turn_auth_cred);
241 }
242}
243
244PJ_DEF(void) pjsua_turn_config_dup(pj_pool_t *pool,
245 pjsua_turn_config *dst,
246 const pjsua_turn_config *src)
247{
248 pj_memcpy(dst, src, sizeof(*src));
249 if (pool) {
250 pj_strdup(pool, &dst->turn_server, &src->turn_server);
251 pj_stun_auth_cred_dup(pool, &dst->turn_auth_cred,
252 &src->turn_auth_cred);
253 }
254}
255
256PJ_DEF(void) pjsua_acc_config_default(pjsua_acc_config *cfg)
257{
258 pjsua_media_config med_cfg;
259
260 pj_bzero(cfg, sizeof(*cfg));
261
262 cfg->reg_timeout = PJSUA_REG_INTERVAL;
263 cfg->reg_delay_before_refresh = PJSIP_REGISTER_CLIENT_DELAY_BEFORE_REFRESH;
264 cfg->unreg_timeout = PJSUA_UNREG_TIMEOUT;
265 pjsip_publishc_opt_default(&cfg->publish_opt);
266 cfg->unpublish_max_wait_time_msec = PJSUA_UNPUBLISH_MAX_WAIT_TIME_MSEC;
267 cfg->transport_id = PJSUA_INVALID_ID;
268 cfg->allow_contact_rewrite = PJ_TRUE;
269 cfg->allow_via_rewrite = PJ_TRUE;
270 cfg->require_100rel = pjsua_var.ua_cfg.require_100rel;
271 cfg->use_timer = pjsua_var.ua_cfg.use_timer;
272 cfg->timer_setting = pjsua_var.ua_cfg.timer_setting;
273 cfg->lock_codec = 1;
274 cfg->ka_interval = 15;
275 cfg->ka_data = pj_str("\r\n");
276 cfg->vid_cap_dev = PJMEDIA_VID_DEFAULT_CAPTURE_DEV;
277 cfg->vid_rend_dev = PJMEDIA_VID_DEFAULT_RENDER_DEV;
278#if PJMEDIA_HAS_VIDEO
279 pjmedia_vid_stream_rc_config_default(&cfg->vid_stream_rc_cfg);
280#endif
281 pjsua_transport_config_default(&cfg->rtp_cfg);
282
283 pjsua_media_config_default(&med_cfg);
284 pjsua_ice_config_from_media_config(NULL, &cfg->ice_cfg, &med_cfg);
285 pjsua_turn_config_from_media_config(NULL, &cfg->turn_cfg, &med_cfg);
286
287 cfg->use_srtp = pjsua_var.ua_cfg.use_srtp;
288 cfg->srtp_secure_signaling = pjsua_var.ua_cfg.srtp_secure_signaling;
289 cfg->srtp_optional_dup_offer = pjsua_var.ua_cfg.srtp_optional_dup_offer;
290 cfg->reg_retry_interval = PJSUA_REG_RETRY_INTERVAL;
291 cfg->contact_rewrite_method = PJSUA_CONTACT_REWRITE_METHOD;
292 cfg->use_rfc5626 = PJ_TRUE;
293 cfg->reg_use_proxy = PJSUA_REG_USE_OUTBOUND_PROXY |
294 PJSUA_REG_USE_ACC_PROXY;
295#if defined(PJMEDIA_STREAM_ENABLE_KA) && PJMEDIA_STREAM_ENABLE_KA!=0
296 cfg->use_stream_ka = (PJMEDIA_STREAM_ENABLE_KA != 0);
297#endif
298 pj_list_init(&cfg->reg_hdr_list);
299 pj_list_init(&cfg->sub_hdr_list);
300 cfg->call_hold_type = PJSUA_CALL_HOLD_TYPE_DEFAULT;
301 cfg->register_on_acc_add = PJ_TRUE;
302 cfg->mwi_expires = PJSIP_MWI_DEFAULT_EXPIRES;
303}
304
305PJ_DEF(void) pjsua_buddy_config_default(pjsua_buddy_config *cfg)
306{
307 pj_bzero(cfg, sizeof(*cfg));
308}
309
310PJ_DEF(void) pjsua_media_config_default(pjsua_media_config *cfg)
311{
312 const pj_sys_info *si = pj_get_sys_info();
313 pj_str_t dev_model = {"iPhone5", 7};
314
315 pj_bzero(cfg, sizeof(*cfg));
316
317 cfg->clock_rate = PJSUA_DEFAULT_CLOCK_RATE;
318 /* It is reported that there may be some media server resampling problem
319 * with iPhone 5 devices running iOS 7, so we set the sound device's
320 * clock rate to 44100 to avoid resampling.
321 */
322 if (pj_stristr(&si->machine, &dev_model) &&
323 ((si->os_ver & 0xFF000000) >> 24) >= 7)
324 {
325 cfg->snd_clock_rate = 44100;
326 } else {
327 cfg->snd_clock_rate = 0;
328 }
329 cfg->channel_count = 1;
330 cfg->audio_frame_ptime = PJSUA_DEFAULT_AUDIO_FRAME_PTIME;
331 cfg->max_media_ports = PJSUA_MAX_CONF_PORTS;
332 cfg->has_ioqueue = PJ_TRUE;
333 cfg->thread_cnt = 1;
334 cfg->quality = PJSUA_DEFAULT_CODEC_QUALITY;
335 cfg->ilbc_mode = PJSUA_DEFAULT_ILBC_MODE;
336 cfg->ec_tail_len = PJSUA_DEFAULT_EC_TAIL_LEN;
337 cfg->snd_rec_latency = PJMEDIA_SND_DEFAULT_REC_LATENCY;
338 cfg->snd_play_latency = PJMEDIA_SND_DEFAULT_PLAY_LATENCY;
339 cfg->jb_init = cfg->jb_min_pre = cfg->jb_max_pre = cfg->jb_max = -1;
340 cfg->snd_auto_close_time = 1;
341
342 cfg->ice_max_host_cands = -1;
343 cfg->ice_always_update = PJ_TRUE;
344 pj_ice_sess_options_default(&cfg->ice_opt);
345
346 cfg->turn_conn_type = PJ_TURN_TP_UDP;
347 cfg->vid_preview_enable_native = PJ_TRUE;
348}
349
350/*****************************************************************************
351 * This is a very simple PJSIP module, whose sole purpose is to display
352 * incoming and outgoing messages to log. This module will have priority
353 * higher than transport layer, which means:
354 *
355 * - incoming messages will come to this module first before reaching
356 * transaction layer.
357 *
358 * - outgoing messages will come to this module last, after the message
359 * has been 'printed' to contiguous buffer by transport layer and
360 * appropriate transport instance has been decided for this message.
361 *
362 */
363
364/* Notification on incoming messages */
365static pj_bool_t logging_on_rx_msg(pjsip_rx_data *rdata)
366{
367 PJ_LOG(4,(THIS_FILE, "RX %d bytes %s from %s %s:%d:\n"
368 "%.*s\n"
369 "--end msg--",
370 rdata->msg_info.len,
371 pjsip_rx_data_get_info(rdata),
372 rdata->tp_info.transport->type_name,
373 rdata->pkt_info.src_name,
374 rdata->pkt_info.src_port,
375 (int)rdata->msg_info.len,
376 rdata->msg_info.msg_buf));
377
378 /* Always return false, otherwise messages will not get processed! */
379 return PJ_FALSE;
380}
381
382/* Notification on outgoing messages */
383static pj_status_t logging_on_tx_msg(pjsip_tx_data *tdata)
384{
385
386 /* Important note:
387 * tp_info field is only valid after outgoing messages has passed
388 * transport layer. So don't try to access tp_info when the module
389 * has lower priority than transport layer.
390 */
391
392 PJ_LOG(4,(THIS_FILE, "TX %d bytes %s to %s %s:%d:\n"
393 "%.*s\n"
394 "--end msg--",
395 (tdata->buf.cur - tdata->buf.start),
396 pjsip_tx_data_get_info(tdata),
397 tdata->tp_info.transport->type_name,
398 tdata->tp_info.dst_name,
399 tdata->tp_info.dst_port,
400 (int)(tdata->buf.cur - tdata->buf.start),
401 tdata->buf.start));
402
403 /* Always return success, otherwise message will not get sent! */
404 return PJ_SUCCESS;
405}
406
407/* The module instance. */
408static pjsip_module pjsua_msg_logger =
409{
410 NULL, NULL, /* prev, next. */
411 { "mod-pjsua-log", 13 }, /* Name. */
412 -1, /* Id */
413 PJSIP_MOD_PRIORITY_TRANSPORT_LAYER-1,/* Priority */
414 NULL, /* load() */
415 NULL, /* start() */
416 NULL, /* stop() */
417 NULL, /* unload() */
418 &logging_on_rx_msg, /* on_rx_request() */
419 &logging_on_rx_msg, /* on_rx_response() */
420 &logging_on_tx_msg, /* on_tx_request. */
421 &logging_on_tx_msg, /* on_tx_response() */
422 NULL, /* on_tsx_state() */
423
424};
425
426
427/*****************************************************************************
428 * Another simple module to handle incoming OPTIONS request
429 */
430
431/* Notification on incoming request */
432static pj_bool_t options_on_rx_request(pjsip_rx_data *rdata)
433{
434 pjsip_tx_data *tdata;
435 pjsip_response_addr res_addr;
436 const pjsip_hdr *cap_hdr;
437 pj_status_t status;
438
439 /* Only want to handle OPTIONS requests */
440 if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method,
441 pjsip_get_options_method()) != 0)
442 {
443 return PJ_FALSE;
444 }
445
446 /* Don't want to handle if shutdown is in progress */
447 if (pjsua_var.thread_quit_flag) {
448 pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata,
449 PJSIP_SC_TEMPORARILY_UNAVAILABLE, NULL,
450 NULL, NULL);
451 return PJ_TRUE;
452 }
453
454 /* Create basic response. */
455 status = pjsip_endpt_create_response(pjsua_var.endpt, rdata, 200, NULL,
456 &tdata);
457 if (status != PJ_SUCCESS) {
458 pjsua_perror(THIS_FILE, "Unable to create OPTIONS response", status);
459 return PJ_TRUE;
460 }
461
462 /* Add Allow header */
463 cap_hdr = pjsip_endpt_get_capability(pjsua_var.endpt, PJSIP_H_ALLOW, NULL);
464 if (cap_hdr) {
465 pjsip_msg_add_hdr(tdata->msg,
466 (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, cap_hdr));
467 }
468
469 /* Add Accept header */
470 cap_hdr = pjsip_endpt_get_capability(pjsua_var.endpt, PJSIP_H_ACCEPT, NULL);
471 if (cap_hdr) {
472 pjsip_msg_add_hdr(tdata->msg,
473 (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, cap_hdr));
474 }
475
476 /* Add Supported header */
477 cap_hdr = pjsip_endpt_get_capability(pjsua_var.endpt, PJSIP_H_SUPPORTED, NULL);
478 if (cap_hdr) {
479 pjsip_msg_add_hdr(tdata->msg,
480 (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, cap_hdr));
481 }
482
483 /* Add Allow-Events header from the evsub module */
484 cap_hdr = pjsip_evsub_get_allow_events_hdr(NULL);
485 if (cap_hdr) {
486 pjsip_msg_add_hdr(tdata->msg,
487 (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, cap_hdr));
488 }
489
490 /* Add User-Agent header */
491 if (pjsua_var.ua_cfg.user_agent.slen) {
492 const pj_str_t USER_AGENT = { "User-Agent", 10};
493 pjsip_hdr *h;
494
495 h = (pjsip_hdr*) pjsip_generic_string_hdr_create(tdata->pool,
496 &USER_AGENT,
497 &pjsua_var.ua_cfg.user_agent);
498 pjsip_msg_add_hdr(tdata->msg, h);
499 }
500
501 /* Get media socket info, make sure transport is ready */
502#if DISABLED_FOR_TICKET_1185
503 if (pjsua_var.calls[0].med_tp) {
504 pjmedia_transport_info tpinfo;
505 pjmedia_sdp_session *sdp;
506
507 pjmedia_transport_info_init(&tpinfo);
508 pjmedia_transport_get_info(pjsua_var.calls[0].med_tp, &tpinfo);
509
510 /* Add SDP body, using call0's RTP address */
511 status = pjmedia_endpt_create_sdp(pjsua_var.med_endpt, tdata->pool, 1,
512 &tpinfo.sock_info, &sdp);
513 if (status == PJ_SUCCESS) {
514 pjsip_create_sdp_body(tdata->pool, sdp, &tdata->msg->body);
515 }
516 }
517#endif
518
519 /* Send response */
520 pjsip_get_response_addr(tdata->pool, rdata, &res_addr);
521 status = pjsip_endpt_send_response(pjsua_var.endpt, &res_addr, tdata, NULL, NULL);
522 if (status != PJ_SUCCESS)
523 pjsip_tx_data_dec_ref(tdata);
524
525 return PJ_TRUE;
526}
527
528
529/* The module instance. */
530static pjsip_module pjsua_options_handler =
531{
532 NULL, NULL, /* prev, next. */
533 { "mod-pjsua-options", 17 }, /* Name. */
534 -1, /* Id */
535 PJSIP_MOD_PRIORITY_APPLICATION, /* Priority */
536 NULL, /* load() */
537 NULL, /* start() */
538 NULL, /* stop() */
539 NULL, /* unload() */
540 &options_on_rx_request, /* on_rx_request() */
541 NULL, /* on_rx_response() */
542 NULL, /* on_tx_request. */
543 NULL, /* on_tx_response() */
544 NULL, /* on_tsx_state() */
545
546};
547
548
549/*****************************************************************************
550 * These two functions are the main callbacks registered to PJSIP stack
551 * to receive SIP request and response messages that are outside any
552 * dialogs and any transactions.
553 */
554
555/*
556 * Handler for receiving incoming requests.
557 *
558 * This handler serves multiple purposes:
559 * - it receives requests outside dialogs.
560 * - it receives requests inside dialogs, when the requests are
561 * unhandled by other dialog usages. Example of these
562 * requests are: MESSAGE.
563 */
564static pj_bool_t mod_pjsua_on_rx_request(pjsip_rx_data *rdata)
565{
566 pj_bool_t processed = PJ_FALSE;
567
568 PJSUA_LOCK();
569
570 if (rdata->msg_info.msg->line.req.method.id == PJSIP_INVITE_METHOD) {
571
572 processed = pjsua_call_on_incoming(rdata);
573 }
574
575 PJSUA_UNLOCK();
576
577 return processed;
578}
579
580
581/*
582 * Handler for receiving incoming responses.
583 *
584 * This handler serves multiple purposes:
585 * - it receives strayed responses (i.e. outside any dialog and
586 * outside any transactions).
587 * - it receives responses coming to a transaction, when pjsua
588 * module is set as transaction user for the transaction.
589 * - it receives responses inside a dialog, when these responses
590 * are unhandled by other dialog usages.
591 */
592static pj_bool_t mod_pjsua_on_rx_response(pjsip_rx_data *rdata)
593{
594 PJ_UNUSED_ARG(rdata);
595 return PJ_FALSE;
596}
597
598
599/*****************************************************************************
600 * Logging.
601 */
602
603/* Log callback */
604static void log_writer(int level, const char *buffer, int len)
605{
606 /* Write to file, stdout or application callback. */
607
608 if (pjsua_var.log_file) {
609 pj_ssize_t size = len;
610 pj_file_write(pjsua_var.log_file, buffer, &size);
611 /* This will slow things down considerably! Don't do it!
612 pj_file_flush(pjsua_var.log_file);
613 */
614 }
615
616 if (level <= (int)pjsua_var.log_cfg.console_level) {
617 if (pjsua_var.log_cfg.cb)
618 (*pjsua_var.log_cfg.cb)(level, buffer, len);
619 else
620 pj_log_write(level, buffer, len);
621 }
622}
623
624
625/*
626 * Application can call this function at any time (after pjsua_create(), of
627 * course) to change logging settings.
628 */
629PJ_DEF(pj_status_t) pjsua_reconfigure_logging(const pjsua_logging_config *cfg)
630{
631 pj_status_t status;
632
633 /* Save config. */
634 pjsua_logging_config_dup(pjsua_var.pool, &pjsua_var.log_cfg, cfg);
635
636 /* Redirect log function to ours */
637 pj_log_set_log_func( &log_writer );
638
639 /* Set decor */
640 pj_log_set_decor(pjsua_var.log_cfg.decor);
641
642 /* Set log level */
643 pj_log_set_level(pjsua_var.log_cfg.level);
644
645 /* Close existing file, if any */
646 if (pjsua_var.log_file) {
647 pj_file_close(pjsua_var.log_file);
648 pjsua_var.log_file = NULL;
649 }
650
651 /* If output log file is desired, create the file: */
652 if (pjsua_var.log_cfg.log_filename.slen) {
653 unsigned flags = PJ_O_WRONLY;
654 flags |= pjsua_var.log_cfg.log_file_flags;
655 status = pj_file_open(pjsua_var.pool,
656 pjsua_var.log_cfg.log_filename.ptr,
657 flags,
658 &pjsua_var.log_file);
659
660 if (status != PJ_SUCCESS) {
661 pjsua_perror(THIS_FILE, "Error creating log file", status);
662 return status;
663 }
664 }
665
666 /* Unregister msg logging if it's previously registered */
667 if (pjsua_msg_logger.id >= 0) {
668 pjsip_endpt_unregister_module(pjsua_var.endpt, &pjsua_msg_logger);
669 pjsua_msg_logger.id = -1;
670 }
671
672 /* Enable SIP message logging */
673 if (pjsua_var.log_cfg.msg_logging)
674 pjsip_endpt_register_module(pjsua_var.endpt, &pjsua_msg_logger);
675
676 return PJ_SUCCESS;
677}
678
679
680/*****************************************************************************
681 * PJSUA Base API.
682 */
683
684/* Worker thread function. */
685static int worker_thread(void *arg)
686{
687 enum { TIMEOUT = 10 };
688
689 PJ_UNUSED_ARG(arg);
690
691 while (!pjsua_var.thread_quit_flag) {
692 int count;
693
694 count = pjsua_handle_events(TIMEOUT);
695 if (count < 0)
696 pj_thread_sleep(TIMEOUT);
697 }
698
699 return 0;
700}
701
702
703/* Init random seed */
704static void init_random_seed(void)
705{
706 pj_sockaddr addr;
707 const pj_str_t *hostname;
708 pj_uint32_t pid;
709 pj_time_val t;
710 unsigned seed=0;
711
712 /* Add hostname */
713 hostname = pj_gethostname();
714 seed = pj_hash_calc(seed, hostname->ptr, (int)hostname->slen);
715
716 /* Add primary IP address */
717 if (pj_gethostip(pj_AF_INET(), &addr)==PJ_SUCCESS)
718 seed = pj_hash_calc(seed, &addr.ipv4.sin_addr, 4);
719
720 /* Get timeofday */
721 pj_gettimeofday(&t);
722 seed = pj_hash_calc(seed, &t, sizeof(t));
723
724 /* Add PID */
725 pid = pj_getpid();
726 seed = pj_hash_calc(seed, &pid, sizeof(pid));
727
728 /* Init random seed */
729 pj_srand(seed);
730}
731
732/*
733 * Instantiate pjsua application.
734 */
735PJ_DEF(pj_status_t) pjsua_create(void)
736{
737 pj_status_t status;
738
739 /* Init pjsua data */
740 init_data();
741
742 /* Set default logging settings */
743 pjsua_logging_config_default(&pjsua_var.log_cfg);
744
745 /* Init PJLIB: */
746 status = pj_init();
747 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
748
749 pj_log_push_indent();
750
751 /* Init random seed */
752 init_random_seed();
753
754 /* Init PJLIB-UTIL: */
755 status = pjlib_util_init();
756 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
757
758 /* Init PJNATH */
759 status = pjnath_init();
760 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
761
762 /* Set default sound device ID */
763 pjsua_var.cap_dev = PJMEDIA_AUD_DEFAULT_CAPTURE_DEV;
764 pjsua_var.play_dev = PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV;
765
766 /* Set default video device ID */
767 pjsua_var.vcap_dev = PJMEDIA_VID_DEFAULT_CAPTURE_DEV;
768 pjsua_var.vrdr_dev = PJMEDIA_VID_DEFAULT_RENDER_DEV;
769
770 /* Init caching pool. */
771 pj_caching_pool_init(&pjsua_var.cp, NULL, 0);
772
773 /* Create memory pool for application. */
774 pjsua_var.pool = pjsua_pool_create("pjsua", 1000, 1000);
775
776 PJ_ASSERT_RETURN(pjsua_var.pool, PJ_ENOMEM);
777
778 /* Create mutex */
779 status = pj_mutex_create_recursive(pjsua_var.pool, "pjsua",
780 &pjsua_var.mutex);
781 if (status != PJ_SUCCESS) {
782 pj_log_pop_indent();
783 pjsua_perror(THIS_FILE, "Unable to create mutex", status);
784 return status;
785 }
786
787 /* Must create SIP endpoint to initialize SIP parser. The parser
788 * is needed for example when application needs to call pjsua_verify_url().
789 */
790 status = pjsip_endpt_create(&pjsua_var.cp.factory,
791 pj_gethostname()->ptr,
792 &pjsua_var.endpt);
793 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
794
795 /* Init timer entry list */
796 pj_list_init(&pjsua_var.timer_list);
797
798 /* Create timer mutex */
799 status = pj_mutex_create_recursive(pjsua_var.pool, "pjsua_timer",
800 &pjsua_var.timer_mutex);
801 if (status != PJ_SUCCESS) {
802 pj_log_pop_indent();
803 pjsua_perror(THIS_FILE, "Unable to create mutex", status);
804 return status;
805 }
806
807 pjsua_set_state(PJSUA_STATE_CREATED);
808 pj_log_pop_indent();
809 return PJ_SUCCESS;
810}
811
812
813/*
814 * Initialize pjsua with the specified settings. All the settings are
815 * optional, and the default values will be used when the config is not
816 * specified.
817 */
818PJ_DEF(pj_status_t) pjsua_init( const pjsua_config *ua_cfg,
819 const pjsua_logging_config *log_cfg,
820 const pjsua_media_config *media_cfg)
821{
822 pjsua_config default_cfg;
823 pjsua_media_config default_media_cfg;
824 const pj_str_t STR_OPTIONS = { "OPTIONS", 7 };
825 pjsip_ua_init_param ua_init_param;
826 unsigned i;
827 pj_status_t status;
828
829 pj_log_push_indent();
830
831 /* Create default configurations when the config is not supplied */
832
833 if (ua_cfg == NULL) {
834 pjsua_config_default(&default_cfg);
835 ua_cfg = &default_cfg;
836 }
837
838 if (media_cfg == NULL) {
839 pjsua_media_config_default(&default_media_cfg);
840 media_cfg = &default_media_cfg;
841 }
842
843 /* Initialize logging first so that info/errors can be captured */
844 if (log_cfg) {
845 status = pjsua_reconfigure_logging(log_cfg);
846 if (status != PJ_SUCCESS)
847 goto on_error;
848 }
849
850#if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \
851 PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT != 0
852 if (!(pj_get_sys_info()->flags & PJ_SYS_HAS_IOS_BG)) {
853 PJ_LOG(5, (THIS_FILE, "Device does not support "
854 "background mode"));
855 pj_activesock_enable_iphone_os_bg(PJ_FALSE);
856 }
857#endif
858
859 /* If nameserver is configured, create DNS resolver instance and
860 * set it to be used by SIP resolver.
861 */
862 if (ua_cfg->nameserver_count) {
863#if PJSIP_HAS_RESOLVER
864 unsigned i;
865
866 /* Create DNS resolver */
867 status = pjsip_endpt_create_resolver(pjsua_var.endpt,
868 &pjsua_var.resolver);
869 if (status != PJ_SUCCESS) {
870 pjsua_perror(THIS_FILE, "Error creating resolver", status);
871 goto on_error;
872 }
873
874 /* Configure nameserver for the DNS resolver */
875 status = pj_dns_resolver_set_ns(pjsua_var.resolver,
876 ua_cfg->nameserver_count,
877 ua_cfg->nameserver, NULL);
878 if (status != PJ_SUCCESS) {
879 pjsua_perror(THIS_FILE, "Error setting nameserver", status);
880 goto on_error;
881 }
882
883 /* Set this DNS resolver to be used by the SIP resolver */
884 status = pjsip_endpt_set_resolver(pjsua_var.endpt, pjsua_var.resolver);
885 if (status != PJ_SUCCESS) {
886 pjsua_perror(THIS_FILE, "Error setting DNS resolver", status);
887 goto on_error;
888 }
889
890 /* Print nameservers */
891 for (i=0; i<ua_cfg->nameserver_count; ++i) {
892 PJ_LOG(4,(THIS_FILE, "Nameserver %.*s added",
893 (int)ua_cfg->nameserver[i].slen,
894 ua_cfg->nameserver[i].ptr));
895 }
896#else
897 PJ_LOG(2,(THIS_FILE,
898 "DNS resolver is disabled (PJSIP_HAS_RESOLVER==0)"));
899#endif
900 }
901
902 /* Init SIP UA: */
903
904 /* Initialize transaction layer: */
905 status = pjsip_tsx_layer_init_module(pjsua_var.endpt);
906 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
907
908
909 /* Initialize UA layer module: */
910 pj_bzero(&ua_init_param, sizeof(ua_init_param));
911 if (ua_cfg->hangup_forked_call) {
912 ua_init_param.on_dlg_forked = &on_dlg_forked;
913 }
914 status = pjsip_ua_init_module( pjsua_var.endpt, &ua_init_param);
915 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
916
917
918 /* Initialize Replaces support. */
919 status = pjsip_replaces_init_module( pjsua_var.endpt );
920 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
921
922 /* Initialize 100rel support */
923 status = pjsip_100rel_init_module(pjsua_var.endpt);
924 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
925
926 /* Initialize session timer support */
927 status = pjsip_timer_init_module(pjsua_var.endpt);
928 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
929
930 /* Initialize and register PJSUA application module. */
931 {
932 const pjsip_module mod_initializer =
933 {
934 NULL, NULL, /* prev, next. */
935 { "mod-pjsua", 9 }, /* Name. */
936 -1, /* Id */
937 PJSIP_MOD_PRIORITY_APPLICATION, /* Priority */
938 NULL, /* load() */
939 NULL, /* start() */
940 NULL, /* stop() */
941 NULL, /* unload() */
942 &mod_pjsua_on_rx_request, /* on_rx_request() */
943 &mod_pjsua_on_rx_response, /* on_rx_response() */
944 NULL, /* on_tx_request. */
945 NULL, /* on_tx_response() */
946 NULL, /* on_tsx_state() */
947 };
948
949 pjsua_var.mod = mod_initializer;
950
951 status = pjsip_endpt_register_module(pjsua_var.endpt, &pjsua_var.mod);
952 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
953 }
954
955 /* Parse outbound proxies */
956 for (i=0; i<ua_cfg->outbound_proxy_cnt; ++i) {
957 pj_str_t tmp;
958 pj_str_t hname = { "Route", 5};
959 pjsip_route_hdr *r;
960
961 pj_strdup_with_null(pjsua_var.pool, &tmp, &ua_cfg->outbound_proxy[i]);
962
963 r = (pjsip_route_hdr*)
964 pjsip_parse_hdr(pjsua_var.pool, &hname, tmp.ptr,
965 (unsigned)tmp.slen, NULL);
966 if (r == NULL) {
967 pjsua_perror(THIS_FILE, "Invalid outbound proxy URI",
968 PJSIP_EINVALIDURI);
969 status = PJSIP_EINVALIDURI;
970 goto on_error;
971 }
972
973 if (pjsua_var.ua_cfg.force_lr) {
974 pjsip_sip_uri *sip_url;
975 if (!PJSIP_URI_SCHEME_IS_SIP(r->name_addr.uri) &&
976 !PJSIP_URI_SCHEME_IS_SIPS(r->name_addr.uri))
977 {
978 status = PJSIP_EINVALIDSCHEME;
979 goto on_error;
980 }
981 sip_url = (pjsip_sip_uri*)r->name_addr.uri;
982 sip_url->lr_param = 1;
983 }
984
985 pj_list_push_back(&pjsua_var.outbound_proxy, r);
986 }
987
988
989 /* Initialize PJSUA call subsystem: */
990 status = pjsua_call_subsys_init(ua_cfg);
991 if (status != PJ_SUCCESS)
992 goto on_error;
993
994 /* Convert deprecated STUN settings */
995 if (pjsua_var.ua_cfg.stun_srv_cnt==0) {
996 if (pjsua_var.ua_cfg.stun_domain.slen) {
997 pjsua_var.ua_cfg.stun_srv[pjsua_var.ua_cfg.stun_srv_cnt++] =
998 pjsua_var.ua_cfg.stun_domain;
999 }
1000 if (pjsua_var.ua_cfg.stun_host.slen) {
1001 pjsua_var.ua_cfg.stun_srv[pjsua_var.ua_cfg.stun_srv_cnt++] =
1002 pjsua_var.ua_cfg.stun_host;
1003 }
1004 }
1005
1006 /* Start resolving STUN server */
1007 status = resolve_stun_server(PJ_FALSE);
1008 if (status != PJ_SUCCESS && status != PJ_EPENDING) {
1009 pjsua_perror(THIS_FILE, "Error resolving STUN server", status);
1010 goto on_error;
1011 }
1012
1013 /* Initialize PJSUA media subsystem */
1014 status = pjsua_media_subsys_init(media_cfg);
1015 if (status != PJ_SUCCESS)
1016 goto on_error;
1017
1018
1019 /* Init core SIMPLE module : */
1020 status = pjsip_evsub_init_module(pjsua_var.endpt);
1021 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
1022
1023
1024 /* Init presence module: */
1025 status = pjsip_pres_init_module( pjsua_var.endpt, pjsip_evsub_instance());
1026 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
1027
1028 /* Initialize MWI support */
1029 status = pjsip_mwi_init_module(pjsua_var.endpt, pjsip_evsub_instance());
1030
1031 /* Init PUBLISH module */
1032 pjsip_publishc_init_module(pjsua_var.endpt);
1033
1034 /* Init xfer/REFER module */
1035 status = pjsip_xfer_init_module( pjsua_var.endpt );
1036 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
1037
1038 /* Init pjsua presence handler: */
1039 status = pjsua_pres_init();
1040 if (status != PJ_SUCCESS)
1041 goto on_error;
1042
1043 /* Init out-of-dialog MESSAGE request handler. */
1044 status = pjsua_im_init();
1045 if (status != PJ_SUCCESS)
1046 goto on_error;
1047
1048 /* Register OPTIONS handler */
1049 pjsip_endpt_register_module(pjsua_var.endpt, &pjsua_options_handler);
1050
1051 /* Add OPTIONS in Allow header */
1052 pjsip_endpt_add_capability(pjsua_var.endpt, NULL, PJSIP_H_ALLOW,
1053 NULL, 1, &STR_OPTIONS);
1054
1055 /* Start worker thread if needed. */
1056 if (pjsua_var.ua_cfg.thread_cnt) {
1057 unsigned i;
1058
1059 if (pjsua_var.ua_cfg.thread_cnt > PJ_ARRAY_SIZE(pjsua_var.thread))
1060 pjsua_var.ua_cfg.thread_cnt = PJ_ARRAY_SIZE(pjsua_var.thread);
1061
1062 for (i=0; i<pjsua_var.ua_cfg.thread_cnt; ++i) {
1063 status = pj_thread_create(pjsua_var.pool, "pjsua", &worker_thread,
1064 NULL, 0, 0, &pjsua_var.thread[i]);
1065 if (status != PJ_SUCCESS)
1066 goto on_error;
1067 }
1068 PJ_LOG(4,(THIS_FILE, "%d SIP worker threads created",
1069 pjsua_var.ua_cfg.thread_cnt));
1070 } else {
1071 PJ_LOG(4,(THIS_FILE, "No SIP worker threads created"));
1072 }
1073
1074 /* Done! */
1075
1076 PJ_LOG(3,(THIS_FILE, "pjsua version %s for %s initialized",
1077 pj_get_version(), pj_get_sys_info()->info.ptr));
1078
1079 pjsua_set_state(PJSUA_STATE_INIT);
1080 pj_log_pop_indent();
1081 return PJ_SUCCESS;
1082
1083on_error:
1084 pjsua_destroy();
1085 pj_log_pop_indent();
1086 return status;
1087}
1088
1089
1090/* Sleep with polling */
1091static void busy_sleep(unsigned msec)
1092{
1093 pj_time_val timeout, now;
1094
1095 pj_gettickcount(&timeout);
1096 timeout.msec += msec;
1097 pj_time_val_normalize(&timeout);
1098
1099 do {
1100 int i;
1101 i = msec / 10;
1102 while (pjsua_handle_events(10) > 0 && i > 0)
1103 --i;
1104 pj_gettickcount(&now);
1105 } while (PJ_TIME_VAL_LT(now, timeout));
1106}
1107
1108static void stun_resolve_add_ref(pjsua_stun_resolve *sess)
1109{
1110 ++sess->ref_cnt;
1111}
1112
1113static void destroy_stun_resolve(pjsua_stun_resolve *sess)
1114{
1115 sess->destroy_flag = PJ_TRUE;
1116 if (sess->ref_cnt > 0)
1117 return;
1118
1119 PJSUA_LOCK();
1120 pj_list_erase(sess);
1121 PJSUA_UNLOCK();
1122
1123 pj_assert(sess->stun_sock==NULL);
1124 pj_pool_release(sess->pool);
1125}
1126
1127static void stun_resolve_dec_ref(pjsua_stun_resolve *sess)
1128{
1129 --sess->ref_cnt;
1130 if (sess->ref_cnt <= 0 && sess->destroy_flag)
1131 destroy_stun_resolve(sess);
1132}
1133
1134
1135/* This is the internal function to be called when STUN resolution
1136 * session (pj_stun_resolve) has completed.
1137 */
1138static void stun_resolve_complete(pjsua_stun_resolve *sess)
1139{
1140 pj_stun_resolve_result result;
1141
1142 if (sess->has_result)
1143 goto on_return;
1144
1145 pj_bzero(&result, sizeof(result));
1146 result.token = sess->token;
1147 result.status = sess->status;
1148 result.name = sess->srv[sess->idx];
1149 pj_memcpy(&result.addr, &sess->addr, sizeof(result.addr));
1150 sess->has_result = PJ_TRUE;
1151
1152 if (result.status == PJ_SUCCESS) {
1153 char addr[PJ_INET6_ADDRSTRLEN+10];
1154 pj_sockaddr_print(&result.addr, addr, sizeof(addr), 3);
1155 PJ_LOG(4,(THIS_FILE,
1156 "STUN resolution success, using %.*s, address is %s",
1157 (int)sess->srv[sess->idx].slen,
1158 sess->srv[sess->idx].ptr,
1159 addr));
1160 } else {
1161 char errmsg[PJ_ERR_MSG_SIZE];
1162 pj_strerror(result.status, errmsg, sizeof(errmsg));
1163 PJ_LOG(1,(THIS_FILE, "STUN resolution failed: %s", errmsg));
1164 }
1165
1166 stun_resolve_add_ref(sess);
1167 sess->cb(&result);
1168 stun_resolve_dec_ref(sess);
1169
1170on_return:
1171 if (!sess->blocking) {
1172 destroy_stun_resolve(sess);
1173 }
1174}
1175
1176/* This is the callback called by the STUN socket (pj_stun_sock)
1177 * to report it's state. We use this as part of testing the
1178 * STUN server.
1179 */
1180static pj_bool_t test_stun_on_status(pj_stun_sock *stun_sock,
1181 pj_stun_sock_op op,
1182 pj_status_t status)
1183{
1184 pjsua_stun_resolve *sess;
1185
1186 sess = (pjsua_stun_resolve*) pj_stun_sock_get_user_data(stun_sock);
1187 pj_assert(stun_sock == sess->stun_sock);
1188
1189 if (status != PJ_SUCCESS) {
1190 char errmsg[PJ_ERR_MSG_SIZE];
1191 pj_strerror(status, errmsg, sizeof(errmsg));
1192
1193 PJ_LOG(4,(THIS_FILE, "STUN resolution for %.*s failed: %s",
1194 (int)sess->srv[sess->idx].slen,
1195 sess->srv[sess->idx].ptr, errmsg));
1196
1197 sess->status = status;
1198
1199 pj_stun_sock_destroy(stun_sock);
1200 sess->stun_sock = NULL;
1201
1202 ++sess->idx;
1203 resolve_stun_entry(sess);
1204
1205 return PJ_FALSE;
1206
1207 } else if (op == PJ_STUN_SOCK_BINDING_OP) {
1208 pj_stun_sock_info ssi;
1209
1210 pj_stun_sock_get_info(stun_sock, &ssi);
1211 pj_memcpy(&sess->addr, &ssi.srv_addr, sizeof(sess->addr));
1212
1213 sess->status = PJ_SUCCESS;
1214 pj_stun_sock_destroy(stun_sock);
1215 sess->stun_sock = NULL;
1216
1217 stun_resolve_complete(sess);
1218
1219 return PJ_FALSE;
1220
1221 } else
1222 return PJ_TRUE;
1223
1224}
1225
1226/* This is an internal function to resolve and test current
1227 * server entry in pj_stun_resolve session. It is called by
1228 * pjsua_resolve_stun_servers() and test_stun_on_status() above
1229 */
1230static void resolve_stun_entry(pjsua_stun_resolve *sess)
1231{
1232 stun_resolve_add_ref(sess);
1233
1234 /* Loop while we have entry to try */
1235 for (; sess->idx < sess->count; ++sess->idx) {
1236 const int af = pj_AF_INET();
1237 char target[64];
1238 pj_str_t hostpart;
1239 pj_uint16_t port;
1240 pj_stun_sock_cb stun_sock_cb;
1241
1242 pj_assert(sess->idx < sess->count);
1243
1244 pj_ansi_snprintf(target, sizeof(target), "%.*s",
1245 (int)sess->srv[sess->idx].slen,
1246 sess->srv[sess->idx].ptr);
1247
1248 /* Parse the server entry into host:port */
1249 sess->status = pj_sockaddr_parse2(af, 0, &sess->srv[sess->idx],
1250 &hostpart, &port, NULL);
1251 if (sess->status != PJ_SUCCESS) {
1252 PJ_LOG(2,(THIS_FILE, "Invalid STUN server entry %s", target));
1253 continue;
1254 }
1255
1256 /* Use default port if not specified */
1257 if (port == 0)
1258 port = PJ_STUN_PORT;
1259
1260 pj_assert(sess->stun_sock == NULL);
1261
1262 PJ_LOG(4,(THIS_FILE, "Trying STUN server %s (%d of %d)..",
1263 target, sess->idx+1, sess->count));
1264
1265 /* Use STUN_sock to test this entry */
1266 pj_bzero(&stun_sock_cb, sizeof(stun_sock_cb));
1267 stun_sock_cb.on_status = &test_stun_on_status;
1268 sess->status = pj_stun_sock_create(&pjsua_var.stun_cfg, "stunresolve",
1269 pj_AF_INET(), &stun_sock_cb,
1270 NULL, sess, &sess->stun_sock);
1271 if (sess->status != PJ_SUCCESS) {
1272 char errmsg[PJ_ERR_MSG_SIZE];
1273 pj_strerror(sess->status, errmsg, sizeof(errmsg));
1274 PJ_LOG(4,(THIS_FILE,
1275 "Error creating STUN socket for %s: %s",
1276 target, errmsg));
1277
1278 continue;
1279 }
1280
1281 sess->status = pj_stun_sock_start(sess->stun_sock, &hostpart,
1282 port, pjsua_var.resolver);
1283 if (sess->status != PJ_SUCCESS) {
1284 char errmsg[PJ_ERR_MSG_SIZE];
1285 pj_strerror(sess->status, errmsg, sizeof(errmsg));
1286 PJ_LOG(4,(THIS_FILE,
1287 "Error starting STUN socket for %s: %s",
1288 target, errmsg));
1289
1290 if (sess->stun_sock) {
1291 pj_stun_sock_destroy(sess->stun_sock);
1292 sess->stun_sock = NULL;
1293 }
1294 continue;
1295 }
1296
1297 /* Done for now, testing will resume/complete asynchronously in
1298 * stun_sock_cb()
1299 */
1300 goto on_return;
1301 }
1302
1303 if (sess->idx >= sess->count) {
1304 /* No more entries to try */
1305 PJ_ASSERT_ON_FAIL(sess->status != PJ_SUCCESS,
1306 sess->status = PJ_EUNKNOWN);
1307 stun_resolve_complete(sess);
1308 }
1309
1310on_return:
1311 stun_resolve_dec_ref(sess);
1312}
1313
1314
1315/*
1316 * Resolve STUN server.
1317 */
1318PJ_DEF(pj_status_t) pjsua_resolve_stun_servers( unsigned count,
1319 pj_str_t srv[],
1320 pj_bool_t wait,
1321 void *token,
1322 pj_stun_resolve_cb cb)
1323{
1324 pj_pool_t *pool;
1325 pjsua_stun_resolve *sess;
1326 pj_status_t status;
1327 unsigned i;
1328
1329 PJ_ASSERT_RETURN(count && srv && cb, PJ_EINVAL);
1330
1331 pool = pjsua_pool_create("stunres", 256, 256);
1332 if (!pool)
1333 return PJ_ENOMEM;
1334
1335 sess = PJ_POOL_ZALLOC_T(pool, pjsua_stun_resolve);
1336 sess->pool = pool;
1337 sess->token = token;
1338 sess->cb = cb;
1339 sess->count = count;
1340 sess->blocking = wait;
1341 sess->status = PJ_EPENDING;
1342 sess->srv = (pj_str_t*) pj_pool_calloc(pool, count, sizeof(pj_str_t));
1343 for (i=0; i<count; ++i) {
1344 pj_strdup(pool, &sess->srv[i], &srv[i]);
1345 }
1346
1347 PJSUA_LOCK();
1348 pj_list_push_back(&pjsua_var.stun_res, sess);
1349 PJSUA_UNLOCK();
1350
1351 resolve_stun_entry(sess);
1352
1353 if (!wait)
1354 return PJ_SUCCESS;
1355
1356 while (sess->status == PJ_EPENDING) {
1357 pjsua_handle_events(50);
1358 }
1359
1360 status = sess->status;
1361 destroy_stun_resolve(sess);
1362
1363 return status;
1364}
1365
1366/*
1367 * Cancel pending STUN resolution.
1368 */
1369PJ_DEF(pj_status_t) pjsua_cancel_stun_resolution( void *token,
1370 pj_bool_t notify_cb)
1371{
1372 pjsua_stun_resolve *sess;
1373 unsigned cancelled_count = 0;
1374
1375 PJSUA_LOCK();
1376 sess = pjsua_var.stun_res.next;
1377 while (sess != &pjsua_var.stun_res) {
1378 pjsua_stun_resolve *next = sess->next;
1379
1380 if (sess->token == token) {
1381 if (notify_cb) {
1382 pj_stun_resolve_result result;
1383
1384 pj_bzero(&result, sizeof(result));
1385 result.token = token;
1386 result.status = PJ_ECANCELLED;
1387
1388 sess->cb(&result);
1389 }
1390
1391 destroy_stun_resolve(sess);
1392 ++cancelled_count;
1393 }
1394
1395 sess = next;
1396 }
1397 PJSUA_UNLOCK();
1398
1399 return cancelled_count ? PJ_SUCCESS : PJ_ENOTFOUND;
1400}
1401
1402static void internal_stun_resolve_cb(const pj_stun_resolve_result *result)
1403{
1404 pjsua_var.stun_status = result->status;
1405 if (result->status == PJ_SUCCESS) {
1406 pj_memcpy(&pjsua_var.stun_srv, &result->addr, sizeof(result->addr));
1407 }
1408}
1409
1410/*
1411 * Resolve STUN server.
1412 */
1413pj_status_t resolve_stun_server(pj_bool_t wait)
1414{
1415 if (pjsua_var.stun_status == PJ_EUNKNOWN) {
1416 pj_status_t status;
1417
1418 /* Initialize STUN configuration */
1419 pj_stun_config_init(&pjsua_var.stun_cfg, &pjsua_var.cp.factory, 0,
1420 pjsip_endpt_get_ioqueue(pjsua_var.endpt),
1421 pjsip_endpt_get_timer_heap(pjsua_var.endpt));
1422
1423 /* Start STUN server resolution */
1424 if (pjsua_var.ua_cfg.stun_srv_cnt) {
1425 pjsua_var.stun_status = PJ_EPENDING;
1426 status = pjsua_resolve_stun_servers(pjsua_var.ua_cfg.stun_srv_cnt,
1427 pjsua_var.ua_cfg.stun_srv,
1428 wait, NULL,
1429 &internal_stun_resolve_cb);
1430 if (wait || status != PJ_SUCCESS) {
1431 pjsua_var.stun_status = status;
1432 }
1433 } else {
1434 pjsua_var.stun_status = PJ_SUCCESS;
1435 }
1436
1437 } else if (pjsua_var.stun_status == PJ_EPENDING) {
1438 /* STUN server resolution has been started, wait for the
1439 * result.
1440 */
1441 if (wait) {
1442 while (pjsua_var.stun_status == PJ_EPENDING) {
1443 if (pjsua_var.thread[0] == NULL)
1444 pjsua_handle_events(10);
1445 else
1446 pj_thread_sleep(10);
1447 }
1448 }
1449 }
1450
1451 if (pjsua_var.stun_status != PJ_EPENDING &&
1452 pjsua_var.stun_status != PJ_SUCCESS &&
1453 pjsua_var.ua_cfg.stun_ignore_failure)
1454 {
1455 PJ_LOG(2,(THIS_FILE,
1456 "Ignoring STUN resolution failure (by setting)"));
1457 pjsua_var.stun_status = PJ_SUCCESS;
1458 }
1459
1460 return pjsua_var.stun_status;
1461}
1462
1463/*
1464 * Destroy pjsua.
1465 */
1466PJ_DEF(pj_status_t) pjsua_destroy2(unsigned flags)
1467{
1468 int i; /* Must be signed */
1469
1470 if (pjsua_var.endpt) {
1471 PJ_LOG(4,(THIS_FILE, "Shutting down, flags=%d...", flags));
1472 }
1473
1474 if (pjsua_var.state > PJSUA_STATE_NULL &&
1475 pjsua_var.state < PJSUA_STATE_CLOSING)
1476 {
1477 pjsua_set_state(PJSUA_STATE_CLOSING);
1478 }
1479
1480 /* Signal threads to quit: */
1481 pjsua_var.thread_quit_flag = 1;
1482
1483 /* Wait worker threads to quit: */
1484 for (i=0; i<(int)pjsua_var.ua_cfg.thread_cnt; ++i) {
1485 if (pjsua_var.thread[i]) {
1486 pj_status_t status;
1487 status = pj_thread_join(pjsua_var.thread[i]);
1488 if (status != PJ_SUCCESS) {
1489 PJ_PERROR(4,(THIS_FILE, status, "Error joining worker thread"));
1490 pj_thread_sleep(1000);
1491 }
1492 pj_thread_destroy(pjsua_var.thread[i]);
1493 pjsua_var.thread[i] = NULL;
1494 }
1495 }
1496
1497 if (pjsua_var.endpt) {
1498 unsigned max_wait;
1499
1500 pj_log_push_indent();
1501
1502 /* Terminate all calls. */
1503 if ((flags & PJSUA_DESTROY_NO_TX_MSG) == 0) {
1504 pjsua_call_hangup_all();
1505 }
1506
1507 /* Set all accounts to offline */
1508 for (i=0; i<(int)PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
1509 if (!pjsua_var.acc[i].valid)
1510 continue;
1511 pjsua_var.acc[i].online_status = PJ_FALSE;
1512 pj_bzero(&pjsua_var.acc[i].rpid, sizeof(pjrpid_element));
1513 }
1514
1515 /* Terminate all presence subscriptions. */
1516 pjsua_pres_shutdown(flags);
1517
1518 /* Destroy media (to shutdown media transports etc) */
1519 pjsua_media_subsys_destroy(flags);
1520
1521 /* Wait for sometime until all publish client sessions are done
1522 * (ticket #364)
1523 */
1524 /* First stage, get the maximum wait time */
1525 max_wait = 100;
1526 for (i=0; i<(int)PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
1527 if (!pjsua_var.acc[i].valid)
1528 continue;
1529 if (pjsua_var.acc[i].cfg.unpublish_max_wait_time_msec > max_wait)
1530 max_wait = pjsua_var.acc[i].cfg.unpublish_max_wait_time_msec;
1531 }
1532
1533 /* No waiting if RX is disabled */
1534 if (flags & PJSUA_DESTROY_NO_RX_MSG) {
1535 max_wait = 0;
1536 }
1537
1538 /* Second stage, wait for unpublications to complete */
1539 for (i=0; i<(int)(max_wait/50); ++i) {
1540 unsigned j;
1541 for (j=0; j<PJ_ARRAY_SIZE(pjsua_var.acc); ++j) {
1542 if (!pjsua_var.acc[j].valid)
1543 continue;
1544
1545 if (pjsua_var.acc[j].publish_sess)
1546 break;
1547 }
1548 if (j != PJ_ARRAY_SIZE(pjsua_var.acc))
1549 busy_sleep(50);
1550 else
1551 break;
1552 }
1553
1554 /* Third stage, forcefully destroy unfinished unpublications */
1555 for (i=0; i<(int)PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
1556 if (pjsua_var.acc[i].publish_sess) {
1557 pjsip_publishc_destroy(pjsua_var.acc[i].publish_sess);
1558 pjsua_var.acc[i].publish_sess = NULL;
1559 }
1560 }
1561
1562 /* Unregister all accounts */
1563 for (i=0; i<(int)PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
1564 if (!pjsua_var.acc[i].valid)
1565 continue;
1566
1567 if (pjsua_var.acc[i].regc && (flags & PJSUA_DESTROY_NO_TX_MSG)==0)
1568 {
1569 pjsua_acc_set_registration(i, PJ_FALSE);
1570 }
1571 }
1572
1573 /* Terminate any pending STUN resolution */
1574 if (!pj_list_empty(&pjsua_var.stun_res)) {
1575 pjsua_stun_resolve *sess = pjsua_var.stun_res.next;
1576 while (sess != &pjsua_var.stun_res) {
1577 pjsua_stun_resolve *next = sess->next;
1578 destroy_stun_resolve(sess);
1579 sess = next;
1580 }
1581 }
1582
1583 /* Wait until all unregistrations are done (ticket #364) */
1584 /* First stage, get the maximum wait time */
1585 max_wait = 100;
1586 for (i=0; i<(int)PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
1587 if (!pjsua_var.acc[i].valid)
1588 continue;
1589 if (pjsua_var.acc[i].cfg.unreg_timeout > max_wait)
1590 max_wait = pjsua_var.acc[i].cfg.unreg_timeout;
1591 }
1592
1593 /* No waiting if RX is disabled */
1594 if (flags & PJSUA_DESTROY_NO_RX_MSG) {
1595 max_wait = 0;
1596 }
1597
1598 /* Second stage, wait for unregistrations to complete */
1599 for (i=0; i<(int)(max_wait/50); ++i) {
1600 unsigned j;
1601 for (j=0; j<PJ_ARRAY_SIZE(pjsua_var.acc); ++j) {
1602 if (!pjsua_var.acc[j].valid)
1603 continue;
1604
1605 if (pjsua_var.acc[j].regc)
1606 break;
1607 }
1608 if (j != PJ_ARRAY_SIZE(pjsua_var.acc))
1609 busy_sleep(50);
1610 else
1611 break;
1612 }
1613 /* Note variable 'i' is used below */
1614
1615 /* Wait for some time to allow unregistration and ICE/TURN
1616 * transports shutdown to complete:
1617 */
1618 if (i < 20 && (flags & PJSUA_DESTROY_NO_RX_MSG) == 0) {
1619 busy_sleep(1000 - i*50);
1620 }
1621
1622 PJ_LOG(4,(THIS_FILE, "Destroying..."));
1623
1624 /* Must destroy endpoint first before destroying pools in
1625 * buddies or accounts, since shutting down transaction layer
1626 * may emit events which trigger some buddy or account callbacks
1627 * to be called.
1628 */
1629 pjsip_endpt_destroy(pjsua_var.endpt);
1630 pjsua_var.endpt = NULL;
1631
1632 /* Destroy pool in the buddy object */
1633 for (i=0; i<(int)PJ_ARRAY_SIZE(pjsua_var.buddy); ++i) {
1634 if (pjsua_var.buddy[i].pool) {
1635 pj_pool_release(pjsua_var.buddy[i].pool);
1636 pjsua_var.buddy[i].pool = NULL;
1637 }
1638 }
1639
1640 /* Destroy accounts */
1641 for (i=0; i<(int)PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
1642 if (pjsua_var.acc[i].pool) {
1643 pj_pool_release(pjsua_var.acc[i].pool);
1644 pjsua_var.acc[i].pool = NULL;
1645 }
1646 }
1647 }
1648
1649 /* Destroy mutex */
1650 if (pjsua_var.mutex) {
1651 pj_mutex_destroy(pjsua_var.mutex);
1652 pjsua_var.mutex = NULL;
1653 }
1654
1655 if (pjsua_var.timer_mutex) {
1656 pj_mutex_destroy(pjsua_var.timer_mutex);
1657 pjsua_var.timer_mutex = NULL;
1658 }
1659
1660 /* Destroy pool and pool factory. */
1661 if (pjsua_var.pool) {
1662 pj_pool_release(pjsua_var.pool);
1663 pjsua_var.pool = NULL;
1664 pj_caching_pool_destroy(&pjsua_var.cp);
1665
1666 pjsua_set_state(PJSUA_STATE_NULL);
1667
1668 PJ_LOG(4,(THIS_FILE, "PJSUA destroyed..."));
1669
1670 /* End logging */
1671 if (pjsua_var.log_file) {
1672 pj_file_close(pjsua_var.log_file);
1673 pjsua_var.log_file = NULL;
1674 }
1675
1676 pj_log_pop_indent();
1677
1678 /* Shutdown PJLIB */
1679 pj_shutdown();
1680 }
1681
1682 /* Clear pjsua_var */
1683 pj_bzero(&pjsua_var, sizeof(pjsua_var));
1684
1685 /* Done. */
1686 return PJ_SUCCESS;
1687}
1688
1689void pjsua_set_state(pjsua_state new_state)
1690{
1691 const char *state_name[] = {
1692 "NULL",
1693 "CREATED",
1694 "INIT",
1695 "STARTING",
1696 "RUNNING",
1697 "CLOSING"
1698 };
1699 pjsua_state old_state = pjsua_var.state;
1700
1701 pjsua_var.state = new_state;
1702 PJ_LOG(4,(THIS_FILE, "PJSUA state changed: %s --> %s",
1703 state_name[old_state], state_name[new_state]));
1704}
1705
1706/* Get state */
1707PJ_DEF(pjsua_state) pjsua_get_state(void)
1708{
1709 return pjsua_var.state;
1710}
1711
1712PJ_DEF(pj_status_t) pjsua_destroy(void)
1713{
1714 return pjsua_destroy2(0);
1715}
1716
1717
1718/**
1719 * Application is recommended to call this function after all initialization
1720 * is done, so that the library can do additional checking set up
1721 * additional
1722 *
1723 * @return PJ_SUCCESS on success, or the appropriate error code.
1724 */
1725PJ_DEF(pj_status_t) pjsua_start(void)
1726{
1727 pj_status_t status;
1728
1729 pjsua_set_state(PJSUA_STATE_STARTING);
1730 pj_log_push_indent();
1731
1732 status = pjsua_call_subsys_start();
1733 if (status != PJ_SUCCESS)
1734 goto on_return;
1735
1736 status = pjsua_media_subsys_start();
1737 if (status != PJ_SUCCESS)
1738 goto on_return;
1739
1740 status = pjsua_pres_start();
1741 if (status != PJ_SUCCESS)
1742 goto on_return;
1743
1744 pjsua_set_state(PJSUA_STATE_RUNNING);
1745
1746on_return:
1747 pj_log_pop_indent();
1748 return status;
1749}
1750
1751
1752/**
1753 * Poll pjsua for events, and if necessary block the caller thread for
1754 * the specified maximum interval (in miliseconds).
1755 */
1756PJ_DEF(int) pjsua_handle_events(unsigned msec_timeout)
1757{
1758#if defined(PJ_SYMBIAN) && PJ_SYMBIAN != 0
1759
1760 return pj_symbianos_poll(-1, msec_timeout);
1761
1762#else
1763
1764 unsigned count = 0;
1765 pj_time_val tv;
1766 pj_status_t status;
1767
1768 tv.sec = 0;
1769 tv.msec = msec_timeout;
1770 pj_time_val_normalize(&tv);
1771
1772 status = pjsip_endpt_handle_events2(pjsua_var.endpt, &tv, &count);
1773
1774 if (status != PJ_SUCCESS)
1775 return -status;
1776
1777 return count;
1778
1779#endif
1780}
1781
1782
1783/*
1784 * Create memory pool.
1785 */
1786PJ_DEF(pj_pool_t*) pjsua_pool_create( const char *name, pj_size_t init_size,
1787 pj_size_t increment)
1788{
1789 /* Pool factory is thread safe, no need to lock */
1790 return pj_pool_create(&pjsua_var.cp.factory, name, init_size, increment,
1791 NULL);
1792}
1793
1794
1795/*
1796 * Internal function to get SIP endpoint instance of pjsua, which is
1797 * needed for example to register module, create transports, etc.
1798 * Probably is only valid after #pjsua_init() is called.
1799 */
1800PJ_DEF(pjsip_endpoint*) pjsua_get_pjsip_endpt(void)
1801{
1802 return pjsua_var.endpt;
1803}
1804
1805/*
1806 * Internal function to get media endpoint instance.
1807 * Only valid after #pjsua_init() is called.
1808 */
1809PJ_DEF(pjmedia_endpt*) pjsua_get_pjmedia_endpt(void)
1810{
1811 return pjsua_var.med_endpt;
1812}
1813
1814/*
1815 * Internal function to get PJSUA pool factory.
1816 */
1817PJ_DEF(pj_pool_factory*) pjsua_get_pool_factory(void)
1818{
1819 return &pjsua_var.cp.factory;
1820}
1821
1822/*****************************************************************************
1823 * PJSUA SIP Transport API.
1824 */
1825
1826/*
1827 * Tools to get address string.
1828 */
1829static const char *addr_string(const pj_sockaddr_t *addr)
1830{
1831 static char str[128];
1832 str[0] = '\0';
1833 pj_inet_ntop(((const pj_sockaddr*)addr)->addr.sa_family,
1834 pj_sockaddr_get_addr(addr),
1835 str, sizeof(str));
1836 return str;
1837}
1838
1839void pjsua_acc_on_tp_state_changed(pjsip_transport *tp,
1840 pjsip_transport_state state,
1841 const pjsip_transport_state_info *info);
1842
1843/* Callback to receive transport state notifications */
1844static void on_tp_state_callback(pjsip_transport *tp,
1845 pjsip_transport_state state,
1846 const pjsip_transport_state_info *info)
1847{
1848 if (pjsua_var.ua_cfg.cb.on_transport_state) {
1849 (*pjsua_var.ua_cfg.cb.on_transport_state)(tp, state, info);
1850 }
1851 if (pjsua_var.old_tp_cb) {
1852 (*pjsua_var.old_tp_cb)(tp, state, info);
1853 }
1854 pjsua_acc_on_tp_state_changed(tp, state, info);
1855}
1856
1857/*
1858 * Create and initialize SIP socket (and possibly resolve public
1859 * address via STUN, depending on config).
1860 */
1861static pj_status_t create_sip_udp_sock(int af,
1862 const pjsua_transport_config *cfg,
1863 pj_sock_t *p_sock,
1864 pj_sockaddr *p_pub_addr)
1865{
1866 char stun_ip_addr[PJ_INET6_ADDRSTRLEN];
1867 unsigned port = cfg->port;
1868 pj_str_t stun_srv;
1869 pj_sock_t sock;
1870 pj_sockaddr bind_addr;
1871 pj_status_t status;
1872
1873 /* Make sure STUN server resolution has completed */
1874 status = resolve_stun_server(PJ_TRUE);
1875 if (status != PJ_SUCCESS) {
1876 pjsua_perror(THIS_FILE, "Error resolving STUN server", status);
1877 return status;
1878 }
1879
1880 /* Initialize bound address */
1881 if (cfg->bound_addr.slen) {
1882 status = pj_sockaddr_init(af, &bind_addr, &cfg->bound_addr,
1883 (pj_uint16_t)port);
1884 if (status != PJ_SUCCESS) {
1885 pjsua_perror(THIS_FILE,
1886 "Unable to resolve transport bound address",
1887 status);
1888 return status;
1889 }
1890 } else {
1891 pj_sockaddr_init(af, &bind_addr, NULL, (pj_uint16_t)port);
1892 }
1893
1894 /* Create socket */
1895 status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &sock);
1896 if (status != PJ_SUCCESS) {
1897 pjsua_perror(THIS_FILE, "socket() error", status);
1898 return status;
1899 }
1900
1901 /* Apply QoS, if specified */
1902 status = pj_sock_apply_qos2(sock, cfg->qos_type,
1903 &cfg->qos_params,
1904 2, THIS_FILE, "SIP UDP socket");
1905
1906 /* Bind socket */
1907 status = pj_sock_bind(sock, &bind_addr, pj_sockaddr_get_len(&bind_addr));
1908 if (status != PJ_SUCCESS) {
1909 pjsua_perror(THIS_FILE, "bind() error", status);
1910 pj_sock_close(sock);
1911 return status;
1912 }
1913
1914 /* If port is zero, get the bound port */
1915 if (port == 0) {
1916 pj_sockaddr bound_addr;
1917 int namelen = sizeof(bound_addr);
1918 status = pj_sock_getsockname(sock, &bound_addr, &namelen);
1919 if (status != PJ_SUCCESS) {
1920 pjsua_perror(THIS_FILE, "getsockname() error", status);
1921 pj_sock_close(sock);
1922 return status;
1923 }
1924
1925 port = pj_sockaddr_get_port(&bound_addr);
1926 }
1927
1928 if (pjsua_var.stun_srv.addr.sa_family != 0) {
1929 pj_ansi_strcpy(stun_ip_addr,pj_inet_ntoa(pjsua_var.stun_srv.ipv4.sin_addr));
1930 stun_srv = pj_str(stun_ip_addr);
1931 } else {
1932 stun_srv.slen = 0;
1933 }
1934
1935 /* Get the published address, either by STUN or by resolving
1936 * the name of local host.
1937 */
1938 if (pj_sockaddr_has_addr(p_pub_addr)) {
1939 /*
1940 * Public address is already specified, no need to resolve the
1941 * address, only set the port.
1942 */
1943 if (pj_sockaddr_get_port(p_pub_addr) == 0)
1944 pj_sockaddr_set_port(p_pub_addr, (pj_uint16_t)port);
1945
1946 } else if (stun_srv.slen) {
1947 pjstun_setting stun_opt;
1948
1949 /*
1950 * STUN is specified, resolve the address with STUN.
1951 */
1952 if (af != pj_AF_INET()) {
1953 pjsua_perror(THIS_FILE, "Cannot use STUN", PJ_EAFNOTSUP);
1954 pj_sock_close(sock);
1955 return PJ_EAFNOTSUP;
1956 }
1957
1958 pj_bzero(&stun_opt, sizeof(stun_opt));
1959 stun_opt.use_stun2 = pjsua_var.ua_cfg.stun_map_use_stun2;
1960 stun_opt.srv1 = stun_opt.srv2 = stun_srv;
1961 stun_opt.port1 = stun_opt.port2 =
1962 pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port);
1963 status = pjstun_get_mapped_addr2(&pjsua_var.cp.factory, &stun_opt,
1964 1, &sock, &p_pub_addr->ipv4);
1965 if (status != PJ_SUCCESS) {
1966 pjsua_perror(THIS_FILE, "Error contacting STUN server", status);
1967 pj_sock_close(sock);
1968 return status;
1969 }
1970
1971 } else {
1972 pj_bzero(p_pub_addr, sizeof(pj_sockaddr));
1973
1974 if (pj_sockaddr_has_addr(&bind_addr)) {
1975 pj_sockaddr_copy_addr(p_pub_addr, &bind_addr);
1976 } else {
1977 status = pj_gethostip(af, p_pub_addr);
1978 if (status != PJ_SUCCESS) {
1979 pjsua_perror(THIS_FILE, "Unable to get local host IP", status);
1980 pj_sock_close(sock);
1981 return status;
1982 }
1983 }
1984
1985 p_pub_addr->addr.sa_family = (pj_uint16_t)af;
1986 pj_sockaddr_set_port(p_pub_addr, (pj_uint16_t)port);
1987 }
1988
1989 *p_sock = sock;
1990
1991 PJ_LOG(4,(THIS_FILE, "SIP UDP socket reachable at %s:%d",
1992 addr_string(p_pub_addr),
1993 (int)pj_sockaddr_get_port(p_pub_addr)));
1994
1995 return PJ_SUCCESS;
1996}
1997
1998
1999/*
2000 * Create SIP transport.
2001 */
2002PJ_DEF(pj_status_t) pjsua_transport_create( pjsip_transport_type_e type,
2003 const pjsua_transport_config *cfg,
2004 pjsua_transport_id *p_id)
2005{
2006 pjsip_transport *tp;
2007 unsigned id;
2008 pj_status_t status;
2009
2010 PJSUA_LOCK();
2011
2012 /* Find empty transport slot */
2013 for (id=0; id < PJ_ARRAY_SIZE(pjsua_var.tpdata); ++id) {
2014 if (pjsua_var.tpdata[id].data.ptr == NULL)
2015 break;
2016 }
2017
2018 if (id == PJ_ARRAY_SIZE(pjsua_var.tpdata)) {
2019 status = PJ_ETOOMANY;
2020 pjsua_perror(THIS_FILE, "Error creating transport", status);
2021 goto on_return;
2022 }
2023
2024 /* Create the transport */
2025 if (type==PJSIP_TRANSPORT_UDP || type==PJSIP_TRANSPORT_UDP6) {
2026 /*
2027 * Create UDP transport (IPv4 or IPv6).
2028 */
2029 pjsua_transport_config config;
2030 char hostbuf[PJ_INET6_ADDRSTRLEN];
2031 pj_sock_t sock = PJ_INVALID_SOCKET;
2032 pj_sockaddr pub_addr;
2033 pjsip_host_port addr_name;
2034
2035 /* Supply default config if it's not specified */
2036 if (cfg == NULL) {
2037 pjsua_transport_config_default(&config);
2038 cfg = &config;
2039 }
2040
2041 /* Initialize the public address from the config, if any */
2042 pj_sockaddr_init(pjsip_transport_type_get_af(type), &pub_addr,
2043 NULL, (pj_uint16_t)cfg->port);
2044 if (cfg->public_addr.slen) {
2045 status = pj_sockaddr_set_str_addr(pjsip_transport_type_get_af(type),
2046 &pub_addr, &cfg->public_addr);
2047 if (status != PJ_SUCCESS) {
2048 pjsua_perror(THIS_FILE,
2049 "Unable to resolve transport public address",
2050 status);
2051 goto on_return;
2052 }
2053 }
2054
2055 /* Create the socket and possibly resolve the address with STUN
2056 * (only when public address is not specified).
2057 */
2058 status = create_sip_udp_sock(pjsip_transport_type_get_af(type),
2059 cfg, &sock, &pub_addr);
2060 if (status != PJ_SUCCESS)
2061 goto on_return;
2062
2063 pj_ansi_strcpy(hostbuf, addr_string(&pub_addr));
2064 addr_name.host = pj_str(hostbuf);
2065 addr_name.port = pj_sockaddr_get_port(&pub_addr);
2066
2067 /* Create UDP transport */
2068 status = pjsip_udp_transport_attach2(pjsua_var.endpt, type, sock,
2069 &addr_name, 1, &tp);
2070 if (status != PJ_SUCCESS) {
2071 pjsua_perror(THIS_FILE, "Error creating SIP UDP transport",
2072 status);
2073 pj_sock_close(sock);
2074 goto on_return;
2075 }
2076
2077
2078 /* Save the transport */
2079 pjsua_var.tpdata[id].type = type;
2080 pjsua_var.tpdata[id].local_name = tp->local_name;
2081 pjsua_var.tpdata[id].data.tp = tp;
2082
2083#if defined(PJ_HAS_TCP) && PJ_HAS_TCP!=0
2084
2085 } else if (type == PJSIP_TRANSPORT_TCP || type == PJSIP_TRANSPORT_TCP6) {
2086 /*
2087 * Create TCP transport.
2088 */
2089 pjsua_transport_config config;
2090 pjsip_tpfactory *tcp;
2091 pjsip_tcp_transport_cfg tcp_cfg;
2092 int af;
2093
2094 af = (type==PJSIP_TRANSPORT_TCP6) ? pj_AF_INET6() : pj_AF_INET();
2095 pjsip_tcp_transport_cfg_default(&tcp_cfg, af);
2096
2097 /* Supply default config if it's not specified */
2098 if (cfg == NULL) {
2099 pjsua_transport_config_default(&config);
2100 cfg = &config;
2101 }
2102
2103 /* Configure bind address */
2104 if (cfg->port)
2105 pj_sockaddr_set_port(&tcp_cfg.bind_addr, (pj_uint16_t)cfg->port);
2106
2107 if (cfg->bound_addr.slen) {
2108 status = pj_sockaddr_set_str_addr(tcp_cfg.af,
2109 &tcp_cfg.bind_addr,
2110 &cfg->bound_addr);
2111 if (status != PJ_SUCCESS) {
2112 pjsua_perror(THIS_FILE,
2113 "Unable to resolve transport bound address",
2114 status);
2115 goto on_return;
2116 }
2117 }
2118
2119 /* Set published name */
2120 if (cfg->public_addr.slen)
2121 tcp_cfg.addr_name.host = cfg->public_addr;
2122
2123 /* Copy the QoS settings */
2124 tcp_cfg.qos_type = cfg->qos_type;
2125 pj_memcpy(&tcp_cfg.qos_params, &cfg->qos_params,
2126 sizeof(cfg->qos_params));
2127
2128 /* Create the TCP transport */
2129 status = pjsip_tcp_transport_start3(pjsua_var.endpt, &tcp_cfg, &tcp);
2130
2131 if (status != PJ_SUCCESS) {
2132 pjsua_perror(THIS_FILE, "Error creating SIP TCP listener",
2133 status);
2134 goto on_return;
2135 }
2136
2137 /* Save the transport */
2138 pjsua_var.tpdata[id].type = type;
2139 pjsua_var.tpdata[id].local_name = tcp->addr_name;
2140 pjsua_var.tpdata[id].data.factory = tcp;
2141
2142#endif /* PJ_HAS_TCP */
2143
2144#if defined(PJSIP_HAS_TLS_TRANSPORT) && PJSIP_HAS_TLS_TRANSPORT!=0
2145 } else if (type == PJSIP_TRANSPORT_TLS || type == PJSIP_TRANSPORT_TLS6) {
2146 /*
2147 * Create TLS transport.
2148 */
2149 pjsua_transport_config config;
2150 pjsip_host_port a_name;
2151 pjsip_tpfactory *tls;
2152 pj_sockaddr local_addr;
2153 int af;
2154
2155 /* Supply default config if it's not specified */
2156 if (cfg == NULL) {
2157 pjsua_transport_config_default(&config);
2158 config.port = 5061;
2159 cfg = &config;
2160 }
2161
2162 /* Init local address */
2163 af = (type==PJSIP_TRANSPORT_TLS) ? pj_AF_INET() : pj_AF_INET6();
2164 pj_sockaddr_init(af, &local_addr, NULL, 0);
2165
2166 if (cfg->port)
2167 pj_sockaddr_set_port(&local_addr, (pj_uint16_t)cfg->port);
2168
2169 if (cfg->bound_addr.slen) {
2170 status = pj_sockaddr_set_str_addr(af, &local_addr,
2171 &cfg->bound_addr);
2172 if (status != PJ_SUCCESS) {
2173 pjsua_perror(THIS_FILE,
2174 "Unable to resolve transport bound address",
2175 status);
2176 goto on_return;
2177 }
2178 }
2179
2180 /* Init published name */
2181 pj_bzero(&a_name, sizeof(pjsip_host_port));
2182 if (cfg->public_addr.slen)
2183 a_name.host = cfg->public_addr;
2184
2185 status = pjsip_tls_transport_start2(pjsua_var.endpt,
2186 &cfg->tls_setting,
2187 &local_addr, &a_name, 1, &tls);
2188 if (status != PJ_SUCCESS) {
2189 pjsua_perror(THIS_FILE, "Error creating SIP TLS listener",
2190 status);
2191 goto on_return;
2192 }
2193
2194 /* Save the transport */
2195 pjsua_var.tpdata[id].type = type;
2196 pjsua_var.tpdata[id].local_name = tls->addr_name;
2197 pjsua_var.tpdata[id].data.factory = tls;
2198#endif
2199
2200 } else {
2201 status = PJSIP_EUNSUPTRANSPORT;
2202 pjsua_perror(THIS_FILE, "Error creating transport", status);
2203 goto on_return;
2204 }
2205
2206 /* Set transport state callback */
2207 {
2208 pjsip_tp_state_callback tpcb;
2209 pjsip_tpmgr *tpmgr;
2210
2211 tpmgr = pjsip_endpt_get_tpmgr(pjsua_var.endpt);
2212 tpcb = pjsip_tpmgr_get_state_cb(tpmgr);
2213
2214 if (tpcb != &on_tp_state_callback) {
2215 pjsua_var.old_tp_cb = tpcb;
2216 pjsip_tpmgr_set_state_cb(tpmgr, &on_tp_state_callback);
2217 }
2218 }
2219
2220 /* Return the ID */
2221 if (p_id) *p_id = id;
2222
2223 status = PJ_SUCCESS;
2224
2225on_return:
2226
2227 PJSUA_UNLOCK();
2228
2229 return status;
2230}
2231
2232
2233/*
2234 * Register transport that has been created by application.
2235 */
2236PJ_DEF(pj_status_t) pjsua_transport_register( pjsip_transport *tp,
2237 pjsua_transport_id *p_id)
2238{
2239 unsigned id;
2240
2241 PJSUA_LOCK();
2242
2243 /* Find empty transport slot */
2244 for (id=0; id < PJ_ARRAY_SIZE(pjsua_var.tpdata); ++id) {
2245 if (pjsua_var.tpdata[id].data.ptr == NULL)
2246 break;
2247 }
2248
2249 if (id == PJ_ARRAY_SIZE(pjsua_var.tpdata)) {
2250 pjsua_perror(THIS_FILE, "Error creating transport", PJ_ETOOMANY);
2251 PJSUA_UNLOCK();
2252 return PJ_ETOOMANY;
2253 }
2254
2255 /* Save the transport */
2256 pjsua_var.tpdata[id].type = (pjsip_transport_type_e) tp->key.type;
2257 pjsua_var.tpdata[id].local_name = tp->local_name;
2258 pjsua_var.tpdata[id].data.tp = tp;
2259
2260 /* Return the ID */
2261 if (p_id) *p_id = id;
2262
2263 PJSUA_UNLOCK();
2264
2265 return PJ_SUCCESS;
2266}
2267
2268
2269/*
2270 * Enumerate all transports currently created in the system.
2271 */
2272PJ_DEF(pj_status_t) pjsua_enum_transports( pjsua_transport_id id[],
2273 unsigned *p_count )
2274{
2275 unsigned i, count;
2276
2277 PJSUA_LOCK();
2278
2279 for (i=0, count=0; i<PJ_ARRAY_SIZE(pjsua_var.tpdata) && count<*p_count;
2280 ++i)
2281 {
2282 if (!pjsua_var.tpdata[i].data.ptr)
2283 continue;
2284
2285 id[count++] = i;
2286 }
2287
2288 *p_count = count;
2289
2290 PJSUA_UNLOCK();
2291
2292 return PJ_SUCCESS;
2293}
2294
2295
2296/*
2297 * Get information about transports.
2298 */
2299PJ_DEF(pj_status_t) pjsua_transport_get_info( pjsua_transport_id id,
2300 pjsua_transport_info *info)
2301{
2302 pjsua_transport_data *t = &pjsua_var.tpdata[id];
2303 pj_status_t status;
2304
2305 pj_bzero(info, sizeof(*info));
2306
2307 /* Make sure id is in range. */
2308 PJ_ASSERT_RETURN(id>=0 && id<(int)PJ_ARRAY_SIZE(pjsua_var.tpdata),
2309 PJ_EINVAL);
2310
2311 /* Make sure that transport exists */
2312 PJ_ASSERT_RETURN(pjsua_var.tpdata[id].data.ptr != NULL, PJ_EINVAL);
2313
2314 PJSUA_LOCK();
2315
2316 if (t->type == PJSIP_TRANSPORT_UDP) {
2317
2318 pjsip_transport *tp = t->data.tp;
2319
2320 if (tp == NULL) {
2321 PJSUA_UNLOCK();
2322 return PJ_EINVALIDOP;
2323 }
2324
2325 info->id = id;
2326 info->type = (pjsip_transport_type_e) tp->key.type;
2327 info->type_name = pj_str(tp->type_name);
2328 info->info = pj_str(tp->info);
2329 info->flag = tp->flag;
2330 info->addr_len = tp->addr_len;
2331 info->local_addr = tp->local_addr;
2332 info->local_name = tp->local_name;
2333 info->usage_count = pj_atomic_get(tp->ref_cnt);
2334
2335 status = PJ_SUCCESS;
2336
2337 } else if (t->type == PJSIP_TRANSPORT_TCP ||
2338 t->type == PJSIP_TRANSPORT_TLS)
2339 {
2340
2341 pjsip_tpfactory *factory = t->data.factory;
2342
2343 if (factory == NULL) {
2344 PJSUA_UNLOCK();
2345 return PJ_EINVALIDOP;
2346 }
2347
2348 info->id = id;
2349 info->type = t->type;
2350 info->type_name = (t->type==PJSIP_TRANSPORT_TCP)? pj_str("TCP"):
2351 pj_str("TLS");
2352 info->info = (t->type==PJSIP_TRANSPORT_TCP)? pj_str("TCP transport"):
2353 pj_str("TLS transport");
2354 info->flag = factory->flag;
2355 info->addr_len = sizeof(factory->local_addr);
2356 info->local_addr = factory->local_addr;
2357 info->local_name = factory->addr_name;
2358 info->usage_count = 0;
2359
2360 status = PJ_SUCCESS;
2361
2362 } else {
2363 pj_assert(!"Unsupported transport");
2364 status = PJ_EINVALIDOP;
2365 }
2366
2367
2368 PJSUA_UNLOCK();
2369
2370 return status;
2371}
2372
2373
2374/*
2375 * Disable a transport or re-enable it.
2376 */
2377PJ_DEF(pj_status_t) pjsua_transport_set_enable( pjsua_transport_id id,
2378 pj_bool_t enabled)
2379{
2380 /* Make sure id is in range. */
2381 PJ_ASSERT_RETURN(id>=0 && id<(int)PJ_ARRAY_SIZE(pjsua_var.tpdata),
2382 PJ_EINVAL);
2383
2384 /* Make sure that transport exists */
2385 PJ_ASSERT_RETURN(pjsua_var.tpdata[id].data.ptr != NULL, PJ_EINVAL);
2386
2387
2388 /* To be done!! */
2389 PJ_TODO(pjsua_transport_set_enable);
2390 PJ_UNUSED_ARG(enabled);
2391
2392 return PJ_EINVALIDOP;
2393}
2394
2395
2396/*
2397 * Close the transport.
2398 */
2399PJ_DEF(pj_status_t) pjsua_transport_close( pjsua_transport_id id,
2400 pj_bool_t force )
2401{
2402 pj_status_t status;
2403
2404 /* Make sure id is in range. */
2405 PJ_ASSERT_RETURN(id>=0 && id<(int)PJ_ARRAY_SIZE(pjsua_var.tpdata),
2406 PJ_EINVAL);
2407
2408 /* Make sure that transport exists */
2409 PJ_ASSERT_RETURN(pjsua_var.tpdata[id].data.ptr != NULL, PJ_EINVAL);
2410
2411 /* Note: destroy() may not work if there are objects still referencing
2412 * the transport.
2413 */
2414 if (force) {
2415 switch (pjsua_var.tpdata[id].type) {
2416 case PJSIP_TRANSPORT_UDP:
2417 status = pjsip_transport_shutdown(pjsua_var.tpdata[id].data.tp);
2418 if (status != PJ_SUCCESS)
2419 return status;
2420 status = pjsip_transport_destroy(pjsua_var.tpdata[id].data.tp);
2421 if (status != PJ_SUCCESS)
2422 return status;
2423 break;
2424
2425 case PJSIP_TRANSPORT_TLS:
2426 case PJSIP_TRANSPORT_TCP:
2427 /* This will close the TCP listener, but existing TCP/TLS
2428 * connections (if any) will still linger
2429 */
2430 status = (*pjsua_var.tpdata[id].data.factory->destroy)
2431 (pjsua_var.tpdata[id].data.factory);
2432 if (status != PJ_SUCCESS)
2433 return status;
2434
2435 break;
2436
2437 default:
2438 return PJ_EINVAL;
2439 }
2440
2441 } else {
2442 /* If force is not specified, transports will be closed at their
2443 * convenient time. However this will leak PJSUA-API transport
2444 * descriptors as PJSUA-API wouldn't know when exactly the
2445 * transport is closed thus it can't cleanup PJSUA transport
2446 * descriptor.
2447 */
2448 switch (pjsua_var.tpdata[id].type) {
2449 case PJSIP_TRANSPORT_UDP:
2450 return pjsip_transport_shutdown(pjsua_var.tpdata[id].data.tp);
2451 case PJSIP_TRANSPORT_TLS:
2452 case PJSIP_TRANSPORT_TCP:
2453 return (*pjsua_var.tpdata[id].data.factory->destroy)
2454 (pjsua_var.tpdata[id].data.factory);
2455 default:
2456 return PJ_EINVAL;
2457 }
2458 }
2459
2460 /* Cleanup pjsua data when force is applied */
2461 if (force) {
2462 pjsua_var.tpdata[id].type = PJSIP_TRANSPORT_UNSPECIFIED;
2463 pjsua_var.tpdata[id].data.ptr = NULL;
2464 }
2465
2466 return PJ_SUCCESS;
2467}
2468
2469
2470/*
2471 * Add additional headers etc in msg_data specified by application
2472 * when sending requests.
2473 */
2474void pjsua_process_msg_data(pjsip_tx_data *tdata,
2475 const pjsua_msg_data *msg_data)
2476{
2477 pj_bool_t allow_body;
2478 const pjsip_hdr *hdr;
2479
2480 /* Always add User-Agent */
2481 if (pjsua_var.ua_cfg.user_agent.slen &&
2482 tdata->msg->type == PJSIP_REQUEST_MSG)
2483 {
2484 const pj_str_t STR_USER_AGENT = { "User-Agent", 10 };
2485 pjsip_hdr *h;
2486 h = (pjsip_hdr*)pjsip_generic_string_hdr_create(tdata->pool,
2487 &STR_USER_AGENT,
2488 &pjsua_var.ua_cfg.user_agent);
2489 pjsip_msg_add_hdr(tdata->msg, h);
2490 }
2491
2492 if (!msg_data)
2493 return;
2494
2495 hdr = msg_data->hdr_list.next;
2496 while (hdr && hdr != &msg_data->hdr_list) {
2497 pjsip_hdr *new_hdr;
2498
2499 new_hdr = (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, hdr);
2500 pjsip_msg_add_hdr(tdata->msg, new_hdr);
2501
2502 hdr = hdr->next;
2503 }
2504
2505 allow_body = (tdata->msg->body == NULL);
2506
2507 if (allow_body && msg_data->content_type.slen && msg_data->msg_body.slen) {
2508 pjsip_media_type ctype;
2509 pjsip_msg_body *body;
2510
2511 pjsua_parse_media_type(tdata->pool, &msg_data->content_type, &ctype);
2512 body = pjsip_msg_body_create(tdata->pool, &ctype.type, &ctype.subtype,
2513 &msg_data->msg_body);
2514 tdata->msg->body = body;
2515 }
2516
2517 /* Multipart */
2518 if (!pj_list_empty(&msg_data->multipart_parts) &&
2519 msg_data->multipart_ctype.type.slen)
2520 {
2521 pjsip_msg_body *bodies;
2522 pjsip_multipart_part *part;
2523 pj_str_t *boundary = NULL;
2524
2525 bodies = pjsip_multipart_create(tdata->pool,
2526 &msg_data->multipart_ctype,
2527 boundary);
2528 part = msg_data->multipart_parts.next;
2529 while (part != &msg_data->multipart_parts) {
2530 pjsip_multipart_part *part_copy;
2531
2532 part_copy = pjsip_multipart_clone_part(tdata->pool, part);
2533 pjsip_multipart_add_part(tdata->pool, bodies, part_copy);
2534 part = part->next;
2535 }
2536
2537 if (tdata->msg->body) {
2538 part = pjsip_multipart_create_part(tdata->pool);
2539 part->body = tdata->msg->body;
2540 pjsip_multipart_add_part(tdata->pool, bodies, part);
2541
2542 tdata->msg->body = NULL;
2543 }
2544
2545 tdata->msg->body = bodies;
2546 }
2547}
2548
2549
2550/*
2551 * Add route_set to outgoing requests
2552 */
2553void pjsua_set_msg_route_set( pjsip_tx_data *tdata,
2554 const pjsip_route_hdr *route_set )
2555{
2556 const pjsip_route_hdr *r;
2557
2558 r = route_set->next;
2559 while (r != route_set) {
2560 pjsip_route_hdr *new_r;
2561
2562 new_r = (pjsip_route_hdr*) pjsip_hdr_clone(tdata->pool, r);
2563 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)new_r);
2564
2565 r = r->next;
2566 }
2567}
2568
2569
2570/*
2571 * Simple version of MIME type parsing (it doesn't support parameters)
2572 */
2573void pjsua_parse_media_type( pj_pool_t *pool,
2574 const pj_str_t *mime,
2575 pjsip_media_type *media_type)
2576{
2577 pj_str_t tmp;
2578 char *pos;
2579
2580 pj_bzero(media_type, sizeof(*media_type));
2581
2582 pj_strdup_with_null(pool, &tmp, mime);
2583
2584 pos = pj_strchr(&tmp, '/');
2585 if (pos) {
2586 media_type->type.ptr = tmp.ptr;
2587 media_type->type.slen = (pos-tmp.ptr);
2588 media_type->subtype.ptr = pos+1;
2589 media_type->subtype.slen = tmp.ptr+tmp.slen-pos-1;
2590 } else {
2591 media_type->type = tmp;
2592 }
2593}
2594
2595
2596/*
2597 * Internal function to init transport selector from transport id.
2598 */
2599void pjsua_init_tpselector(pjsua_transport_id tp_id,
2600 pjsip_tpselector *sel)
2601{
2602 pjsua_transport_data *tpdata;
2603 unsigned flag;
2604
2605 pj_bzero(sel, sizeof(*sel));
2606 if (tp_id == PJSUA_INVALID_ID)
2607 return;
2608
2609 pj_assert(tp_id >= 0 && tp_id < (int)PJ_ARRAY_SIZE(pjsua_var.tpdata));
2610 tpdata = &pjsua_var.tpdata[tp_id];
2611
2612 flag = pjsip_transport_get_flag_from_type(tpdata->type);
2613
2614 if (flag & PJSIP_TRANSPORT_DATAGRAM) {
2615 sel->type = PJSIP_TPSELECTOR_TRANSPORT;
2616 sel->u.transport = tpdata->data.tp;
2617 } else {
2618 sel->type = PJSIP_TPSELECTOR_LISTENER;
2619 sel->u.listener = tpdata->data.factory;
2620 }
2621}
2622
2623
2624/* Callback upon NAT detection completion */
2625static void nat_detect_cb(void *user_data,
2626 const pj_stun_nat_detect_result *res)
2627{
2628 PJ_UNUSED_ARG(user_data);
2629
2630 pjsua_var.nat_in_progress = PJ_FALSE;
2631 pjsua_var.nat_status = res->status;
2632 pjsua_var.nat_type = res->nat_type;
2633
2634 if (pjsua_var.ua_cfg.cb.on_nat_detect) {
2635 (*pjsua_var.ua_cfg.cb.on_nat_detect)(res);
2636 }
2637}
2638
2639
2640/*
2641 * Detect NAT type.
2642 */
2643PJ_DEF(pj_status_t) pjsua_detect_nat_type()
2644{
2645 pj_status_t status;
2646
2647 if (pjsua_var.nat_in_progress)
2648 return PJ_SUCCESS;
2649
2650 /* Make sure STUN server resolution has completed */
2651 status = resolve_stun_server(PJ_TRUE);
2652 if (status != PJ_SUCCESS) {
2653 pjsua_var.nat_status = status;
2654 pjsua_var.nat_type = PJ_STUN_NAT_TYPE_ERR_UNKNOWN;
2655 return status;
2656 }
2657
2658 /* Make sure we have STUN */
2659 if (pjsua_var.stun_srv.ipv4.sin_family == 0) {
2660 pjsua_var.nat_status = PJNATH_ESTUNINSERVER;
2661 return PJNATH_ESTUNINSERVER;
2662 }
2663
2664 status = pj_stun_detect_nat_type(&pjsua_var.stun_srv.ipv4,
2665 &pjsua_var.stun_cfg,
2666 NULL, &nat_detect_cb);
2667
2668 if (status != PJ_SUCCESS) {
2669 pjsua_var.nat_status = status;
2670 pjsua_var.nat_type = PJ_STUN_NAT_TYPE_ERR_UNKNOWN;
2671 return status;
2672 }
2673
2674 pjsua_var.nat_in_progress = PJ_TRUE;
2675
2676 return PJ_SUCCESS;
2677}
2678
2679
2680/*
2681 * Get NAT type.
2682 */
2683PJ_DEF(pj_status_t) pjsua_get_nat_type(pj_stun_nat_type *type)
2684{
2685 *type = pjsua_var.nat_type;
2686 return pjsua_var.nat_status;
2687}
2688
2689/*
2690 * Verify that valid url is given.
2691 */
2692PJ_DEF(pj_status_t) pjsua_verify_url(const char *c_url)
2693{
2694 pjsip_uri *p;
2695 pj_pool_t *pool;
2696 char *url;
2697 pj_size_t len = (c_url ? pj_ansi_strlen(c_url) : 0);
2698
2699 if (!len) return PJSIP_EINVALIDURI;
2700
2701 pool = pj_pool_create(&pjsua_var.cp.factory, "check%p", 1024, 0, NULL);
2702 if (!pool) return PJ_ENOMEM;
2703
2704 url = (char*) pj_pool_alloc(pool, len+1);
2705 pj_ansi_strcpy(url, c_url);
2706
2707 p = pjsip_parse_uri(pool, url, len, 0);
2708
2709 pj_pool_release(pool);
2710 return p ? 0 : PJSIP_EINVALIDURI;
2711}
2712
2713/*
2714 * Verify that valid SIP url is given.
2715 */
2716PJ_DEF(pj_status_t) pjsua_verify_sip_url(const char *c_url)
2717{
2718 pjsip_uri *p;
2719 pj_pool_t *pool;
2720 char *url;
2721 pj_size_t len = (c_url ? pj_ansi_strlen(c_url) : 0);
2722
2723 if (!len) return PJSIP_EINVALIDURI;
2724
2725 pool = pj_pool_create(&pjsua_var.cp.factory, "check%p", 1024, 0, NULL);
2726 if (!pool) return PJ_ENOMEM;
2727
2728 url = (char*) pj_pool_alloc(pool, len+1);
2729 pj_ansi_strcpy(url, c_url);
2730
2731 p = pjsip_parse_uri(pool, url, len, 0);
2732 if (!p || (pj_stricmp2(pjsip_uri_get_scheme(p), "sip") != 0 &&
2733 pj_stricmp2(pjsip_uri_get_scheme(p), "sips") != 0))
2734 {
2735 p = NULL;
2736 }
2737
2738 pj_pool_release(pool);
2739 return p ? 0 : PJSIP_EINVALIDURI;
2740}
2741
2742/*
2743 * Schedule a timer entry.
2744 */
2745#if PJ_TIMER_DEBUG
2746PJ_DEF(pj_status_t) pjsua_schedule_timer_dbg( pj_timer_entry *entry,
2747 const pj_time_val *delay,
2748 const char *src_file,
2749 int src_line)
2750{
2751 return pjsip_endpt_schedule_timer_dbg(pjsua_var.endpt, entry, delay,
2752 src_file, src_line);
2753}
2754#else
2755PJ_DEF(pj_status_t) pjsua_schedule_timer( pj_timer_entry *entry,
2756 const pj_time_val *delay)
2757{
2758 return pjsip_endpt_schedule_timer(pjsua_var.endpt, entry, delay);
2759}
2760#endif
2761
2762/* Timer callback */
2763static void timer_cb( pj_timer_heap_t *th,
2764 pj_timer_entry *entry)
2765{
2766 pjsua_timer_list *tmr = (pjsua_timer_list *)entry->user_data;
2767 void (*cb)(void *user_data) = tmr->cb;
2768 void *user_data = tmr->user_data;
2769
2770 PJ_UNUSED_ARG(th);
2771
2772 pj_mutex_lock(pjsua_var.timer_mutex);
2773 pj_list_push_back(&pjsua_var.timer_list, tmr);
2774 pj_mutex_unlock(pjsua_var.timer_mutex);
2775
2776 if (cb)
2777 (*cb)(user_data);
2778}
2779
2780/*
2781 * Schedule a timer callback.
2782 */
2783#if PJ_TIMER_DEBUG
2784PJ_DEF(pj_status_t) pjsua_schedule_timer2_dbg( void (*cb)(void *user_data),
2785 void *user_data,
2786 unsigned msec_delay,
2787 const char *src_file,
2788 int src_line)
2789#else
2790PJ_DEF(pj_status_t) pjsua_schedule_timer2( void (*cb)(void *user_data),
2791 void *user_data,
2792 unsigned msec_delay)
2793#endif
2794{
2795 pjsua_timer_list *tmr = NULL;
2796 pj_status_t status;
2797 pj_time_val delay;
2798
2799 pj_mutex_lock(pjsua_var.timer_mutex);
2800
2801 if (pj_list_empty(&pjsua_var.timer_list)) {
2802 tmr = PJ_POOL_ALLOC_T(pjsua_var.pool, pjsua_timer_list);
2803 } else {
2804 tmr = pjsua_var.timer_list.next;
2805 pj_list_erase(tmr);
2806 }
2807 pj_timer_entry_init(&tmr->entry, 0, tmr, timer_cb);
2808 tmr->cb = cb;
2809 tmr->user_data = user_data;
2810 delay.sec = 0;
2811 delay.msec = msec_delay;
2812
2813#if PJ_TIMER_DEBUG
2814 status = pjsip_endpt_schedule_timer_dbg(pjsua_var.endpt, &tmr->entry,
2815 &delay, src_file, src_line);
2816#else
2817 status = pjsip_endpt_schedule_timer(pjsua_var.endpt, &tmr->entry, &delay);
2818#endif
2819 if (status != PJ_SUCCESS) {
2820 pj_list_push_back(&pjsua_var.timer_list, tmr);
2821 }
2822
2823 pj_mutex_unlock(pjsua_var.timer_mutex);
2824
2825 return status;
2826}
2827
2828/*
2829 * Cancel the previously scheduled timer.
2830 *
2831 */
2832PJ_DEF(void) pjsua_cancel_timer(pj_timer_entry *entry)
2833{
2834 pjsip_endpt_cancel_timer(pjsua_var.endpt, entry);
2835}
2836
2837/**
2838 * Normalize route URI (check for ";lr" and append one if it doesn't
2839 * exist and pjsua_config.force_lr is set.
2840 */
2841pj_status_t normalize_route_uri(pj_pool_t *pool, pj_str_t *uri)
2842{
2843 pj_str_t tmp_uri;
2844 pj_pool_t *tmp_pool;
2845 pjsip_uri *uri_obj;
2846 pjsip_sip_uri *sip_uri;
2847
2848 tmp_pool = pjsua_pool_create("tmplr%p", 512, 512);
2849 if (!tmp_pool)
2850 return PJ_ENOMEM;
2851
2852 pj_strdup_with_null(tmp_pool, &tmp_uri, uri);
2853
2854 uri_obj = pjsip_parse_uri(tmp_pool, tmp_uri.ptr, tmp_uri.slen, 0);
2855 if (!uri_obj) {
2856 PJ_LOG(1,(THIS_FILE, "Invalid route URI: %.*s",
2857 (int)uri->slen, uri->ptr));
2858 pj_pool_release(tmp_pool);
2859 return PJSIP_EINVALIDURI;
2860 }
2861
2862 if (!PJSIP_URI_SCHEME_IS_SIP(uri_obj) &&
2863 !PJSIP_URI_SCHEME_IS_SIPS(uri_obj))
2864 {
2865 PJ_LOG(1,(THIS_FILE, "Route URI must be SIP URI: %.*s",
2866 (int)uri->slen, uri->ptr));
2867 pj_pool_release(tmp_pool);
2868 return PJSIP_EINVALIDSCHEME;
2869 }
2870
2871 sip_uri = (pjsip_sip_uri*) pjsip_uri_get_uri(uri_obj);
2872
2873 /* Done if force_lr is disabled or if lr parameter is present */
2874 if (!pjsua_var.ua_cfg.force_lr || sip_uri->lr_param) {
2875 pj_pool_release(tmp_pool);
2876 return PJ_SUCCESS;
2877 }
2878
2879 /* Set lr param */
2880 sip_uri->lr_param = 1;
2881
2882 /* Print the URI */
2883 tmp_uri.ptr = (char*) pj_pool_alloc(tmp_pool, PJSIP_MAX_URL_SIZE);
2884 tmp_uri.slen = pjsip_uri_print(PJSIP_URI_IN_ROUTING_HDR, uri_obj,
2885 tmp_uri.ptr, PJSIP_MAX_URL_SIZE);
2886 if (tmp_uri.slen < 1) {
2887 PJ_LOG(1,(THIS_FILE, "Route URI is too long: %.*s",
2888 (int)uri->slen, uri->ptr));
2889 pj_pool_release(tmp_pool);
2890 return PJSIP_EURITOOLONG;
2891 }
2892
2893 /* Clone the URI */
2894 pj_strdup_with_null(pool, uri, &tmp_uri);
2895
2896 pj_pool_release(tmp_pool);
2897 return PJ_SUCCESS;
2898}
2899
2900/*
2901 * This is a utility function to dump the stack states to log, using
2902 * verbosity level 3.
2903 */
2904PJ_DEF(void) pjsua_dump(pj_bool_t detail)
2905{
2906 unsigned old_decor;
2907 unsigned i;
2908
2909 PJ_LOG(3,(THIS_FILE, "Start dumping application states:"));
2910
2911 old_decor = pj_log_get_decor();
2912 pj_log_set_decor(old_decor & (PJ_LOG_HAS_NEWLINE | PJ_LOG_HAS_CR));
2913
2914 if (detail)
2915 pj_dump_config();
2916
2917 pjsip_endpt_dump(pjsua_get_pjsip_endpt(), detail);
2918
2919 pjmedia_endpt_dump(pjsua_get_pjmedia_endpt());
2920
2921 PJ_LOG(3,(THIS_FILE, "Dumping media transports:"));
2922 for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) {
2923 pjsua_call *call = &pjsua_var.calls[i];
2924 pjsua_acc_config *acc_cfg;
2925 pjmedia_transport *tp[PJSUA_MAX_CALL_MEDIA*2];
2926 unsigned tp_cnt = 0;
2927 unsigned j;
2928
2929 /* Collect media transports in this call */
2930 for (j = 0; j < call->med_cnt; ++j) {
2931 if (call->media[j].tp != NULL)
2932 tp[tp_cnt++] = call->media[j].tp;
2933 }
2934 for (j = 0; j < call->med_prov_cnt; ++j) {
2935 pjmedia_transport *med_tp = call->media_prov[j].tp;
2936 if (med_tp) {
2937 unsigned k;
2938 pj_bool_t used = PJ_FALSE;
2939 for (k = 0; k < tp_cnt; ++k) {
2940 if (med_tp == tp[k]) {
2941 used = PJ_TRUE;
2942 break;
2943 }
2944 }
2945 if (!used)
2946 tp[tp_cnt++] = med_tp;
2947 }
2948 }
2949
2950 acc_cfg = &pjsua_var.acc[call->acc_id].cfg;
2951
2952 /* Dump the media transports in this call */
2953 for (j = 0; j < tp_cnt; ++j) {
2954 pjmedia_transport_info tpinfo;
2955 char addr_buf[80];
2956
2957 pjmedia_transport_info_init(&tpinfo);
2958 pjmedia_transport_get_info(tp[j], &tpinfo);
2959 PJ_LOG(3,(THIS_FILE, " %s: %s",
2960 (acc_cfg->ice_cfg.enable_ice ? "ICE" : "UDP"),
2961 pj_sockaddr_print(&tpinfo.sock_info.rtp_addr_name,
2962 addr_buf,
2963 sizeof(addr_buf), 3)));
2964 }
2965 }
2966
2967 pjsip_tsx_layer_dump(detail);
2968 pjsip_ua_dump(detail);
2969
2970// Dumping complete call states may require a 'large' buffer
2971// (about 3KB per call session, including RTCP XR).
2972#if 0
2973 /* Dump all invite sessions: */
2974 PJ_LOG(3,(THIS_FILE, "Dumping invite sessions:"));
2975
2976 if (pjsua_call_get_count() == 0) {
2977
2978 PJ_LOG(3,(THIS_FILE, " - no sessions -"));
2979
2980 } else {
2981 unsigned i;
2982
2983 for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) {
2984 if (pjsua_call_is_active(i)) {
2985 /* Tricky logging, since call states log string tends to be
2986 * longer than PJ_LOG_MAX_SIZE.
2987 */
2988 char buf[1024 * 3];
2989 unsigned call_dump_len;
2990 unsigned part_len;
2991 unsigned part_idx;
2992 unsigned log_decor;
2993
2994 pjsua_call_dump(i, detail, buf, sizeof(buf), " ");
2995 call_dump_len = strlen(buf);
2996
2997 log_decor = pj_log_get_decor();
2998 pj_log_set_decor(log_decor & ~(PJ_LOG_HAS_NEWLINE |
2999 PJ_LOG_HAS_CR));
3000 PJ_LOG(3,(THIS_FILE, "\n"));
3001 pj_log_set_decor(0);
3002
3003 part_idx = 0;
3004 part_len = PJ_LOG_MAX_SIZE-80;
3005 while (part_idx < call_dump_len) {
3006 char p_orig, *p;
3007
3008 p = &buf[part_idx];
3009 if (part_idx + part_len > call_dump_len)
3010 part_len = call_dump_len - part_idx;
3011 p_orig = p[part_len];
3012 p[part_len] = '\0';
3013 PJ_LOG(3,(THIS_FILE, "%s", p));
3014 p[part_len] = p_orig;
3015 part_idx += part_len;
3016 }
3017 pj_log_set_decor(log_decor);
3018 }
3019 }
3020 }
3021#endif
3022
3023 /* Dump presence status */
3024 pjsua_pres_dump(detail);
3025
3026 pj_log_set_decor(old_decor);
3027 PJ_LOG(3,(THIS_FILE, "Dump complete"));
3028}
3029