blob: bd81727230a59c1f69dcb6b484ab635da8ecfa1d [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 <pjnath/ice_strans.h>
21#include <pjnath/errno.h>
22#include <pj/addr_resolv.h>
23#include <pj/array.h>
24#include <pj/assert.h>
25#include <pj/ip_helper.h>
26#include <pj/lock.h>
27#include <pj/log.h>
28#include <pj/os.h>
29#include <pj/pool.h>
30#include <pj/rand.h>
31#include <pj/string.h>
32#include <pj/compat/socket.h>
33
34#define ENABLE_TRACE 0
35
36#if defined(ENABLE_TRACE) && (ENABLE_TRACE != 0)
37# define TRACE_PKT(expr) PJ_LOG(5,expr)
38#else
39# define TRACE_PKT(expr)
40#endif
41
42
43/* Transport IDs */
44enum tp_type
45{
46 TP_NONE,
47 TP_STUN,
48 TP_TURN
49};
50
51/* Candidate's local preference values. This is mostly used to
52 * specify preference among candidates with the same type. Since
53 * we don't have the facility to specify that, we'll just set it
54 * all to the same value.
55 */
56#if PJNATH_ICE_PRIO_STD
57# define SRFLX_PREF 65535
58# define HOST_PREF 65535
59# define RELAY_PREF 65535
60#else
61# define SRFLX_PREF 0
62# define HOST_PREF 0
63# define RELAY_PREF 0
64#endif
65
66
67/* The candidate type preference when STUN candidate is used */
68static pj_uint8_t srflx_pref_table[PJ_ICE_CAND_TYPE_MAX] =
69{
70#if PJNATH_ICE_PRIO_STD
71 100, /**< PJ_ICE_HOST_PREF */
72 110, /**< PJ_ICE_SRFLX_PREF */
73 126, /**< PJ_ICE_PRFLX_PREF */
74 0 /**< PJ_ICE_RELAYED_PREF */
75#else
76 /* Keep it to 2 bits */
77 1, /**< PJ_ICE_HOST_PREF */
78 2, /**< PJ_ICE_SRFLX_PREF */
79 3, /**< PJ_ICE_PRFLX_PREF */
80 0 /**< PJ_ICE_RELAYED_PREF */
81#endif
82};
83
84
85/* ICE callbacks */
86static void on_ice_complete(pj_ice_sess *ice, pj_status_t status);
87static pj_status_t ice_tx_pkt(pj_ice_sess *ice,
88 unsigned comp_id,
89 unsigned transport_id,
90 const void *pkt, pj_size_t size,
91 const pj_sockaddr_t *dst_addr,
92 unsigned dst_addr_len);
93static void ice_rx_data(pj_ice_sess *ice,
94 unsigned comp_id,
95 unsigned transport_id,
96 void *pkt, pj_size_t size,
97 const pj_sockaddr_t *src_addr,
98 unsigned src_addr_len);
99
100
101/* STUN socket callbacks */
102/* Notification when incoming packet has been received. */
103static pj_bool_t stun_on_rx_data(pj_stun_sock *stun_sock,
104 void *pkt,
105 unsigned pkt_len,
106 const pj_sockaddr_t *src_addr,
107 unsigned addr_len);
108/* Notifification when asynchronous send operation has completed. */
109static pj_bool_t stun_on_data_sent(pj_stun_sock *stun_sock,
110 pj_ioqueue_op_key_t *send_key,
111 pj_ssize_t sent);
112/* Notification when the status of the STUN transport has changed. */
113static pj_bool_t stun_on_status(pj_stun_sock *stun_sock,
114 pj_stun_sock_op op,
115 pj_status_t status);
116
117
118/* TURN callbacks */
119static void turn_on_rx_data(pj_turn_sock *turn_sock,
120 void *pkt,
121 unsigned pkt_len,
122 const pj_sockaddr_t *peer_addr,
123 unsigned addr_len);
124static void turn_on_state(pj_turn_sock *turn_sock, pj_turn_state_t old_state,
125 pj_turn_state_t new_state);
126
127
128
129/* Forward decls */
130static void ice_st_on_destroy(void *obj);
131static void destroy_ice_st(pj_ice_strans *ice_st);
132#define ice_st_perror(ice_st,msg,rc) pjnath_perror(ice_st->obj_name,msg,rc)
133static void sess_init_update(pj_ice_strans *ice_st);
134
135/**
136 * This structure describes an ICE stream transport component. A component
137 * in ICE stream transport typically corresponds to a single socket created
138 * for this component, and bound to a specific transport address. This
139 * component may have multiple alias addresses, for example one alias
140 * address for each interfaces in multi-homed host, another for server
141 * reflexive alias, and another for relayed alias. For each transport
142 * address alias, an ICE stream transport candidate (#pj_ice_sess_cand) will
143 * be created, and these candidates will eventually registered to the ICE
144 * session.
145 */
146typedef struct pj_ice_strans_comp
147{
148 pj_ice_strans *ice_st; /**< ICE stream transport. */
149 unsigned comp_id; /**< Component ID. */
150
151 pj_stun_sock *stun_sock; /**< STUN transport. */
152 pj_turn_sock *turn_sock; /**< TURN relay transport. */
153 pj_bool_t turn_log_off; /**< TURN loggin off? */
154 unsigned turn_err_cnt; /**< TURN disconnected count. */
155
156 unsigned cand_cnt; /**< # of candidates/aliaes. */
157 pj_ice_sess_cand cand_list[PJ_ICE_ST_MAX_CAND]; /**< Cand array */
158
159 unsigned default_cand; /**< Default candidate. */
160
161} pj_ice_strans_comp;
162
163
164/**
165 * This structure represents the ICE stream transport.
166 */
167struct pj_ice_strans
168{
169 char *obj_name; /**< Log ID. */
170 pj_pool_t *pool; /**< Pool used by this object. */
171 void *user_data; /**< Application data. */
172 pj_ice_strans_cfg cfg; /**< Configuration. */
173 pj_ice_strans_cb cb; /**< Application callback. */
174 pj_grp_lock_t *grp_lock; /**< Group lock. */
175
176 pj_ice_strans_state state; /**< Session state. */
177 pj_ice_sess *ice; /**< ICE session. */
178 pj_time_val start_time;/**< Time when ICE was started */
179
180 unsigned comp_cnt; /**< Number of components. */
181 pj_ice_strans_comp **comp; /**< Components array. */
182
183 pj_timer_entry ka_timer; /**< STUN keep-alive timer. */
184
185 pj_bool_t destroy_req;/**< Destroy has been called? */
186 pj_bool_t cb_called; /**< Init error callback called?*/
187};
188
189
190/* Validate configuration */
191static pj_status_t pj_ice_strans_cfg_check_valid(const pj_ice_strans_cfg *cfg)
192{
193 pj_status_t status;
194
195 status = pj_stun_config_check_valid(&cfg->stun_cfg);
196 if (!status)
197 return status;
198
199 return PJ_SUCCESS;
200}
201
202
203/*
204 * Initialize ICE transport configuration with default values.
205 */
206PJ_DEF(void) pj_ice_strans_cfg_default(pj_ice_strans_cfg *cfg)
207{
208 pj_bzero(cfg, sizeof(*cfg));
209
210 pj_stun_config_init(&cfg->stun_cfg, NULL, 0, NULL, NULL);
211 pj_stun_sock_cfg_default(&cfg->stun.cfg);
212 pj_turn_alloc_param_default(&cfg->turn.alloc_param);
213 pj_turn_sock_cfg_default(&cfg->turn.cfg);
214
215 pj_ice_sess_options_default(&cfg->opt);
216
217 cfg->af = pj_AF_INET();
218 cfg->stun.port = PJ_STUN_PORT;
219 cfg->turn.conn_type = PJ_TURN_TP_UDP;
220
221 cfg->stun.max_host_cands = 64;
222 cfg->stun.ignore_stun_error = PJ_FALSE;
223}
224
225
226/*
227 * Copy configuration.
228 */
229PJ_DEF(void) pj_ice_strans_cfg_copy( pj_pool_t *pool,
230 pj_ice_strans_cfg *dst,
231 const pj_ice_strans_cfg *src)
232{
233 pj_memcpy(dst, src, sizeof(*src));
234
235 if (src->stun.server.slen)
236 pj_strdup(pool, &dst->stun.server, &src->stun.server);
237 if (src->turn.server.slen)
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
244/*
245 * Add or update TURN candidate.
246 */
247static pj_status_t add_update_turn(pj_ice_strans *ice_st,
248 pj_ice_strans_comp *comp)
249{
250 pj_turn_sock_cb turn_sock_cb;
251 pj_ice_sess_cand *cand = NULL;
252 unsigned i;
253 pj_status_t status;
254
255 /* Find relayed candidate in the component */
256 for (i=0; i<comp->cand_cnt; ++i) {
257 if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_RELAYED) {
258 cand = &comp->cand_list[i];
259 break;
260 }
261 }
262
263 /* If candidate is found, invalidate it first */
264 if (cand) {
265 cand->status = PJ_EPENDING;
266
267 /* Also if this component's default candidate is set to relay,
268 * move it temporarily to something else.
269 */
270 if ((int)comp->default_cand == cand - comp->cand_list) {
271 /* Init to something */
272 comp->default_cand = 0;
273 /* Use srflx candidate as the default, if any */
274 for (i=0; i<comp->cand_cnt; ++i) {
275 if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_SRFLX) {
276 comp->default_cand = i;
277 break;
278 }
279 }
280 }
281 }
282
283 /* Init TURN socket */
284 pj_bzero(&turn_sock_cb, sizeof(turn_sock_cb));
285 turn_sock_cb.on_rx_data = &turn_on_rx_data;
286 turn_sock_cb.on_state = &turn_on_state;
287
288 /* Override with component specific QoS settings, if any */
289 if (ice_st->cfg.comp[comp->comp_id-1].qos_type) {
290 ice_st->cfg.turn.cfg.qos_type =
291 ice_st->cfg.comp[comp->comp_id-1].qos_type;
292 }
293 if (ice_st->cfg.comp[comp->comp_id-1].qos_params.flags) {
294 pj_memcpy(&ice_st->cfg.turn.cfg.qos_params,
295 &ice_st->cfg.comp[comp->comp_id-1].qos_params,
296 sizeof(ice_st->cfg.turn.cfg.qos_params));
297 }
298
299 /* Override with component specific socket buffer size settings, if any */
300 if (ice_st->cfg.comp[comp->comp_id-1].so_rcvbuf_size > 0) {
301 ice_st->cfg.turn.cfg.so_rcvbuf_size =
302 ice_st->cfg.comp[comp->comp_id-1].so_rcvbuf_size;
303 }
304 if (ice_st->cfg.comp[comp->comp_id-1].so_sndbuf_size > 0) {
305 ice_st->cfg.turn.cfg.so_sndbuf_size =
306 ice_st->cfg.comp[comp->comp_id-1].so_sndbuf_size;
307 }
308
309 /* Create the TURN transport */
310 status = pj_turn_sock_create(&ice_st->cfg.stun_cfg, ice_st->cfg.af,
311 ice_st->cfg.turn.conn_type,
312 &turn_sock_cb, &ice_st->cfg.turn.cfg,
313 comp, &comp->turn_sock);
314 if (status != PJ_SUCCESS) {
315 return status;
316 }
317
318 /* Add pending job */
319 ///sess_add_ref(ice_st);
320
321 /* Start allocation */
322 status=pj_turn_sock_alloc(comp->turn_sock,
323 &ice_st->cfg.turn.server,
324 ice_st->cfg.turn.port,
325 ice_st->cfg.resolver,
326 &ice_st->cfg.turn.auth_cred,
327 &ice_st->cfg.turn.alloc_param);
328 if (status != PJ_SUCCESS) {
329 ///sess_dec_ref(ice_st);
330 return status;
331 }
332
333 /* Add relayed candidate with pending status if there's no existing one */
334 if (cand == NULL) {
335 cand = &comp->cand_list[comp->cand_cnt++];
336 cand->type = PJ_ICE_CAND_TYPE_RELAYED;
337 cand->status = PJ_EPENDING;
338 cand->local_pref = RELAY_PREF;
339 cand->transport_id = TP_TURN;
340 cand->comp_id = (pj_uint8_t) comp->comp_id;
341 }
342
343 PJ_LOG(4,(ice_st->obj_name,
344 "Comp %d: TURN relay candidate waiting for allocation",
345 comp->comp_id));
346
347 return PJ_SUCCESS;
348}
349
350
351/*
352 * Create the component.
353 */
354static pj_status_t create_comp(pj_ice_strans *ice_st, unsigned comp_id)
355{
356 pj_ice_strans_comp *comp = NULL;
357 pj_status_t status;
358
359 /* Verify arguments */
360 PJ_ASSERT_RETURN(ice_st && comp_id, PJ_EINVAL);
361
362 /* Check that component ID present */
363 PJ_ASSERT_RETURN(comp_id <= ice_st->comp_cnt, PJNATH_EICEINCOMPID);
364
365 /* Create component */
366 comp = PJ_POOL_ZALLOC_T(ice_st->pool, pj_ice_strans_comp);
367 comp->ice_st = ice_st;
368 comp->comp_id = comp_id;
369
370 ice_st->comp[comp_id-1] = comp;
371
372 /* Initialize default candidate */
373 comp->default_cand = 0;
374
375 /* Create STUN transport if configured */
376 if (ice_st->cfg.stun.server.slen || ice_st->cfg.stun.max_host_cands) {
377 pj_stun_sock_cb stun_sock_cb;
378 pj_ice_sess_cand *cand;
379
380 pj_bzero(&stun_sock_cb, sizeof(stun_sock_cb));
381 stun_sock_cb.on_rx_data = &stun_on_rx_data;
382 stun_sock_cb.on_status = &stun_on_status;
383 stun_sock_cb.on_data_sent = &stun_on_data_sent;
384
385 /* Override component specific QoS settings, if any */
386 if (ice_st->cfg.comp[comp_id-1].qos_type) {
387 ice_st->cfg.stun.cfg.qos_type =
388 ice_st->cfg.comp[comp_id-1].qos_type;
389 }
390 if (ice_st->cfg.comp[comp_id-1].qos_params.flags) {
391 pj_memcpy(&ice_st->cfg.stun.cfg.qos_params,
392 &ice_st->cfg.comp[comp_id-1].qos_params,
393 sizeof(ice_st->cfg.stun.cfg.qos_params));
394 }
395
396 /* Override component specific socket buffer size settings, if any */
397 if (ice_st->cfg.comp[comp_id-1].so_rcvbuf_size > 0) {
398 ice_st->cfg.stun.cfg.so_rcvbuf_size =
399 ice_st->cfg.comp[comp_id-1].so_rcvbuf_size;
400 }
401 if (ice_st->cfg.comp[comp_id-1].so_sndbuf_size > 0) {
402 ice_st->cfg.stun.cfg.so_sndbuf_size =
403 ice_st->cfg.comp[comp_id-1].so_sndbuf_size;
404 }
405
406 /* Create the STUN transport */
407 status = pj_stun_sock_create(&ice_st->cfg.stun_cfg, NULL,
408 ice_st->cfg.af, &stun_sock_cb,
409 &ice_st->cfg.stun.cfg,
410 comp, &comp->stun_sock);
411 if (status != PJ_SUCCESS)
412 return status;
413
414 /* Start STUN Binding resolution and add srflx candidate
415 * only if server is set
416 */
417 if (ice_st->cfg.stun.server.slen) {
418 pj_stun_sock_info stun_sock_info;
419
420 /* Add pending job */
421 ///sess_add_ref(ice_st);
422
423 PJ_LOG(4,(ice_st->obj_name,
424 "Comp %d: srflx candidate starts Binding discovery",
425 comp_id));
426
427 pj_log_push_indent();
428
429 /* Start Binding resolution */
430 status = pj_stun_sock_start(comp->stun_sock,
431 &ice_st->cfg.stun.server,
432 ice_st->cfg.stun.port,
433 ice_st->cfg.resolver);
434 if (status != PJ_SUCCESS) {
435 ///sess_dec_ref(ice_st);
436 pj_log_pop_indent();
437 return status;
438 }
439
440 /* Enumerate addresses */
441 status = pj_stun_sock_get_info(comp->stun_sock, &stun_sock_info);
442 if (status != PJ_SUCCESS) {
443 ///sess_dec_ref(ice_st);
444 pj_log_pop_indent();
445 return status;
446 }
447
448 /* Add srflx candidate with pending status. */
449 cand = &comp->cand_list[comp->cand_cnt++];
450 cand->type = PJ_ICE_CAND_TYPE_SRFLX;
451 cand->status = PJ_EPENDING;
452 cand->local_pref = SRFLX_PREF;
453 cand->transport_id = TP_STUN;
454 cand->comp_id = (pj_uint8_t) comp_id;
455 pj_sockaddr_cp(&cand->base_addr, &stun_sock_info.aliases[0]);
456 pj_sockaddr_cp(&cand->rel_addr, &cand->base_addr);
457 pj_ice_calc_foundation(ice_st->pool, &cand->foundation,
458 cand->type, &cand->base_addr);
459
460 /* Set default candidate to srflx */
461 comp->default_cand = (unsigned)(cand - comp->cand_list);
462
463 pj_log_pop_indent();
464 }
465
466 /* Add local addresses to host candidates, unless max_host_cands
467 * is set to zero.
468 */
469 if (ice_st->cfg.stun.max_host_cands) {
470 pj_stun_sock_info stun_sock_info;
471 unsigned i;
472
473 /* Enumerate addresses */
474 status = pj_stun_sock_get_info(comp->stun_sock, &stun_sock_info);
475 if (status != PJ_SUCCESS)
476 return status;
477
478 for (i=0; i<stun_sock_info.alias_cnt &&
479 i<ice_st->cfg.stun.max_host_cands; ++i)
480 {
481 char addrinfo[PJ_INET6_ADDRSTRLEN+10];
482 const pj_sockaddr *addr = &stun_sock_info.aliases[i];
483
484 /* Leave one candidate for relay */
485 if (comp->cand_cnt >= PJ_ICE_ST_MAX_CAND-1) {
486 PJ_LOG(4,(ice_st->obj_name, "Too many host candidates"));
487 break;
488 }
489
490 /* Ignore loopback addresses unless cfg->stun.loop_addr
491 * is set
492 */
493 if ((pj_ntohl(addr->ipv4.sin_addr.s_addr)>>24)==127) {
494 if (ice_st->cfg.stun.loop_addr==PJ_FALSE)
495 continue;
496 }
497
498 cand = &comp->cand_list[comp->cand_cnt++];
499
500 cand->type = PJ_ICE_CAND_TYPE_HOST;
501 cand->status = PJ_SUCCESS;
502 cand->local_pref = HOST_PREF;
503 cand->transport_id = TP_STUN;
504 cand->comp_id = (pj_uint8_t) comp_id;
505 pj_sockaddr_cp(&cand->addr, addr);
506 pj_sockaddr_cp(&cand->base_addr, addr);
507 pj_bzero(&cand->rel_addr, sizeof(cand->rel_addr));
508 pj_ice_calc_foundation(ice_st->pool, &cand->foundation,
509 cand->type, &cand->base_addr);
510
511 PJ_LOG(4,(ice_st->obj_name,
512 "Comp %d: host candidate %s added",
513 comp_id, pj_sockaddr_print(&cand->addr, addrinfo,
514 sizeof(addrinfo), 3)));
515 }
516 }
517 }
518
519 /* Create TURN relay if configured. */
520 if (ice_st->cfg.turn.server.slen) {
521 add_update_turn(ice_st, comp);
522 }
523
524 /* It's possible that we end up without any candidates */
525 if (comp->cand_cnt == 0) {
526 PJ_LOG(4,(ice_st->obj_name,
527 "Error: no candidate is created due to settings"));
528 return PJ_EINVAL;
529 }
530
531 return PJ_SUCCESS;
532}
533
534
535/*
536 * Create ICE stream transport
537 */
538PJ_DEF(pj_status_t) pj_ice_strans_create( const char *name,
539 const pj_ice_strans_cfg *cfg,
540 unsigned comp_cnt,
541 void *user_data,
542 const pj_ice_strans_cb *cb,
543 pj_ice_strans **p_ice_st)
544{
545 pj_pool_t *pool;
546 pj_ice_strans *ice_st;
547 unsigned i;
548 pj_status_t status;
549
550 status = pj_ice_strans_cfg_check_valid(cfg);
551 if (status != PJ_SUCCESS)
552 return status;
553
554 PJ_ASSERT_RETURN(comp_cnt && cb && p_ice_st &&
555 comp_cnt <= PJ_ICE_MAX_COMP , PJ_EINVAL);
556
557 if (name == NULL)
558 name = "ice%p";
559
560 pool = pj_pool_create(cfg->stun_cfg.pf, name, PJNATH_POOL_LEN_ICE_STRANS,
561 PJNATH_POOL_INC_ICE_STRANS, NULL);
562 ice_st = PJ_POOL_ZALLOC_T(pool, pj_ice_strans);
563 ice_st->pool = pool;
564 ice_st->obj_name = pool->obj_name;
565 ice_st->user_data = user_data;
566
567 PJ_LOG(4,(ice_st->obj_name,
568 "Creating ICE stream transport with %d component(s)",
569 comp_cnt));
570 pj_log_push_indent();
571
572 status = pj_grp_lock_create(pool, NULL, &ice_st->grp_lock);
573 if (status != PJ_SUCCESS) {
574 pj_pool_release(pool);
575 pj_log_pop_indent();
576 return status;
577 }
578
579 pj_grp_lock_add_ref(ice_st->grp_lock);
580 pj_grp_lock_add_handler(ice_st->grp_lock, pool, ice_st,
581 &ice_st_on_destroy);
582
583 pj_ice_strans_cfg_copy(pool, &ice_st->cfg, cfg);
584 ice_st->cfg.stun.cfg.grp_lock = ice_st->grp_lock;
585 ice_st->cfg.turn.cfg.grp_lock = ice_st->grp_lock;
586 pj_memcpy(&ice_st->cb, cb, sizeof(*cb));
587
588 ice_st->comp_cnt = comp_cnt;
589 ice_st->comp = (pj_ice_strans_comp**)
590 pj_pool_calloc(pool, comp_cnt, sizeof(pj_ice_strans_comp*));
591
592 /* Move state to candidate gathering */
593 ice_st->state = PJ_ICE_STRANS_STATE_INIT;
594
595 /* Acquire initialization mutex to prevent callback to be
596 * called before we finish initialization.
597 */
598 pj_grp_lock_acquire(ice_st->grp_lock);
599
600 for (i=0; i<comp_cnt; ++i) {
601 status = create_comp(ice_st, i+1);
602 if (status != PJ_SUCCESS) {
603 pj_grp_lock_release(ice_st->grp_lock);
604 destroy_ice_st(ice_st);
605 pj_log_pop_indent();
606 return status;
607 }
608 }
609
610 /* Done with initialization */
611 pj_grp_lock_release(ice_st->grp_lock);
612
613 PJ_LOG(4,(ice_st->obj_name, "ICE stream transport %p created", ice_st));
614
615 *p_ice_st = ice_st;
616
617 /* Check if all candidates are ready (this may call callback) */
618 sess_init_update(ice_st);
619
620 pj_log_pop_indent();
621
622 return PJ_SUCCESS;
623}
624
625/* REALLY destroy ICE */
626static void ice_st_on_destroy(void *obj)
627{
628 pj_ice_strans *ice_st = (pj_ice_strans*)obj;
629
630 PJ_LOG(4,(ice_st->obj_name, "ICE stream transport %p destroyed", obj));
631
632 /* Done */
633 pj_pool_release(ice_st->pool);
634}
635
636/* Destroy ICE */
637static void destroy_ice_st(pj_ice_strans *ice_st)
638{
639 unsigned i;
640
641 PJ_LOG(5,(ice_st->obj_name, "ICE stream transport %p destroy request..",
642 ice_st));
643 pj_log_push_indent();
644
645 pj_grp_lock_acquire(ice_st->grp_lock);
646
647 if (ice_st->destroy_req) {
648 pj_grp_lock_release(ice_st->grp_lock);
649 return;
650 }
651
652 ice_st->destroy_req = PJ_TRUE;
653
654 /* Destroy ICE if we have ICE */
655 if (ice_st->ice) {
656 pj_ice_sess_destroy(ice_st->ice);
657 ice_st->ice = NULL;
658 }
659
660 /* Destroy all components */
661 for (i=0; i<ice_st->comp_cnt; ++i) {
662 if (ice_st->comp[i]) {
663 if (ice_st->comp[i]->stun_sock) {
664 pj_stun_sock_destroy(ice_st->comp[i]->stun_sock);
665 ice_st->comp[i]->stun_sock = NULL;
666 }
667 if (ice_st->comp[i]->turn_sock) {
668 pj_turn_sock_destroy(ice_st->comp[i]->turn_sock);
669 ice_st->comp[i]->turn_sock = NULL;
670 }
671 }
672 }
673
674 pj_grp_lock_dec_ref(ice_st->grp_lock);
675 pj_grp_lock_release(ice_st->grp_lock);
676
677 pj_log_pop_indent();
678}
679
680/* Get ICE session state. */
681PJ_DEF(pj_ice_strans_state) pj_ice_strans_get_state(pj_ice_strans *ice_st)
682{
683 return ice_st->state;
684}
685
686/* State string */
687PJ_DEF(const char*) pj_ice_strans_state_name(pj_ice_strans_state state)
688{
689 const char *names[] = {
690 "Null",
691 "Candidate Gathering",
692 "Candidate Gathering Complete",
693 "Session Initialized",
694 "Negotiation In Progress",
695 "Negotiation Success",
696 "Negotiation Failed"
697 };
698
699 PJ_ASSERT_RETURN(state <= PJ_ICE_STRANS_STATE_FAILED, "???");
700 return names[state];
701}
702
703/* Notification about failure */
704static void sess_fail(pj_ice_strans *ice_st, pj_ice_strans_op op,
705 const char *title, pj_status_t status)
706{
707 char errmsg[PJ_ERR_MSG_SIZE];
708
709 pj_strerror(status, errmsg, sizeof(errmsg));
710 PJ_LOG(4,(ice_st->obj_name, "%s: %s", title, errmsg));
711 pj_log_push_indent();
712
713 if (op==PJ_ICE_STRANS_OP_INIT && ice_st->cb_called) {
714 pj_log_pop_indent();
715 return;
716 }
717
718 ice_st->cb_called = PJ_TRUE;
719
720 if (ice_st->cb.on_ice_complete)
721 (*ice_st->cb.on_ice_complete)(ice_st, op, status);
722
723 pj_log_pop_indent();
724}
725
726/* Update initialization status */
727static void sess_init_update(pj_ice_strans *ice_st)
728{
729 unsigned i;
730
731 /* Ignore if init callback has been called */
732 if (ice_st->cb_called)
733 return;
734
735 /* Notify application when all candidates have been gathered */
736 for (i=0; i<ice_st->comp_cnt; ++i) {
737 unsigned j;
738 pj_ice_strans_comp *comp = ice_st->comp[i];
739
740 for (j=0; j<comp->cand_cnt; ++j) {
741 pj_ice_sess_cand *cand = &comp->cand_list[j];
742
743 if (cand->status == PJ_EPENDING)
744 return;
745 }
746 }
747
748 /* All candidates have been gathered */
749 ice_st->cb_called = PJ_TRUE;
750 ice_st->state = PJ_ICE_STRANS_STATE_READY;
751 if (ice_st->cb.on_ice_complete)
752 (*ice_st->cb.on_ice_complete)(ice_st, PJ_ICE_STRANS_OP_INIT,
753 PJ_SUCCESS);
754}
755
756/*
757 * Destroy ICE stream transport.
758 */
759PJ_DEF(pj_status_t) pj_ice_strans_destroy(pj_ice_strans *ice_st)
760{
761 destroy_ice_st(ice_st);
762 return PJ_SUCCESS;
763}
764
765
766/*
767 * Get user data
768 */
769PJ_DEF(void*) pj_ice_strans_get_user_data(pj_ice_strans *ice_st)
770{
771 PJ_ASSERT_RETURN(ice_st, NULL);
772 return ice_st->user_data;
773}
774
775
776/*
777 * Get the value of various options of the ICE stream transport.
778 */
779PJ_DEF(pj_status_t) pj_ice_strans_get_options( pj_ice_strans *ice_st,
780 pj_ice_sess_options *opt)
781{
782 PJ_ASSERT_RETURN(ice_st && opt, PJ_EINVAL);
783 pj_memcpy(opt, &ice_st->cfg.opt, sizeof(*opt));
784 return PJ_SUCCESS;
785}
786
787/*
788 * Specify various options for this ICE stream transport.
789 */
790PJ_DEF(pj_status_t) pj_ice_strans_set_options(pj_ice_strans *ice_st,
791 const pj_ice_sess_options *opt)
792{
793 PJ_ASSERT_RETURN(ice_st && opt, PJ_EINVAL);
794 pj_memcpy(&ice_st->cfg.opt, opt, sizeof(*opt));
795 if (ice_st->ice)
796 pj_ice_sess_set_options(ice_st->ice, &ice_st->cfg.opt);
797 return PJ_SUCCESS;
798}
799
800/**
801 * Get the group lock for this ICE stream transport.
802 */
803PJ_DEF(pj_grp_lock_t *) pj_ice_strans_get_grp_lock(pj_ice_strans *ice_st)
804{
805 PJ_ASSERT_RETURN(ice_st, NULL);
806 return ice_st->grp_lock;
807}
808
809/*
810 * Create ICE!
811 */
812PJ_DEF(pj_status_t) pj_ice_strans_init_ice(pj_ice_strans *ice_st,
813 pj_ice_sess_role role,
814 const pj_str_t *local_ufrag,
815 const pj_str_t *local_passwd)
816{
817 pj_status_t status;
818 unsigned i;
819 pj_ice_sess_cb ice_cb;
820 //const pj_uint8_t srflx_prio[4] = { 100, 126, 110, 0 };
821
822 /* Check arguments */
823 PJ_ASSERT_RETURN(ice_st, PJ_EINVAL);
824 /* Must not have ICE */
825 PJ_ASSERT_RETURN(ice_st->ice == NULL, PJ_EINVALIDOP);
826 /* Components must have been created */
827 PJ_ASSERT_RETURN(ice_st->comp[0] != NULL, PJ_EINVALIDOP);
828
829 /* Init callback */
830 pj_bzero(&ice_cb, sizeof(ice_cb));
831 ice_cb.on_ice_complete = &on_ice_complete;
832 ice_cb.on_rx_data = &ice_rx_data;
833 ice_cb.on_tx_pkt = &ice_tx_pkt;
834
835 /* Create! */
836 status = pj_ice_sess_create(&ice_st->cfg.stun_cfg, ice_st->obj_name, role,
837 ice_st->comp_cnt, &ice_cb,
838 local_ufrag, local_passwd,
839 ice_st->grp_lock,
840 &ice_st->ice);
841 if (status != PJ_SUCCESS)
842 return status;
843
844 /* Associate user data */
845 ice_st->ice->user_data = (void*)ice_st;
846
847 /* Set options */
848 pj_ice_sess_set_options(ice_st->ice, &ice_st->cfg.opt);
849
850 /* If default candidate for components are SRFLX one, upload a custom
851 * type priority to ICE session so that SRFLX candidates will get
852 * checked first.
853 */
854 if (ice_st->comp[0]->default_cand >= 0 &&
855 ice_st->comp[0]->cand_list[ice_st->comp[0]->default_cand].type
856 == PJ_ICE_CAND_TYPE_SRFLX)
857 {
858 pj_ice_sess_set_prefs(ice_st->ice, srflx_pref_table);
859 }
860
861 /* Add components/candidates */
862 for (i=0; i<ice_st->comp_cnt; ++i) {
863 unsigned j;
864 pj_ice_strans_comp *comp = ice_st->comp[i];
865
866 /* Re-enable logging for Send/Data indications */
867 if (comp->turn_sock) {
868 PJ_LOG(5,(ice_st->obj_name,
869 "Disabling STUN Indication logging for "
870 "component %d", i+1));
871 pj_turn_sock_set_log(comp->turn_sock, 0xFFFF);
872 comp->turn_log_off = PJ_FALSE;
873 }
874
875 for (j=0; j<comp->cand_cnt; ++j) {
876 pj_ice_sess_cand *cand = &comp->cand_list[j];
877 unsigned ice_cand_id;
878
879 /* Skip if candidate is not ready */
880 if (cand->status != PJ_SUCCESS) {
881 PJ_LOG(5,(ice_st->obj_name,
882 "Candidate %d of comp %d is not added (pending)",
883 j, i));
884 continue;
885 }
886
887 /* Must have address */
888 pj_assert(pj_sockaddr_has_addr(&cand->addr));
889
890 /* Add the candidate */
891 status = pj_ice_sess_add_cand(ice_st->ice, comp->comp_id,
892 cand->transport_id, cand->type,
893 cand->local_pref,
894 &cand->foundation, &cand->addr,
895 &cand->base_addr, &cand->rel_addr,
896 pj_sockaddr_get_len(&cand->addr),
897 (unsigned*)&ice_cand_id);
898 if (status != PJ_SUCCESS)
899 goto on_error;
900 }
901 }
902
903 /* ICE session is ready for negotiation */
904 ice_st->state = PJ_ICE_STRANS_STATE_SESS_READY;
905
906 return PJ_SUCCESS;
907
908on_error:
909 pj_ice_strans_stop_ice(ice_st);
910 return status;
911}
912
913/*
914 * Check if the ICE stream transport has the ICE session created.
915 */
916PJ_DEF(pj_bool_t) pj_ice_strans_has_sess(pj_ice_strans *ice_st)
917{
918 PJ_ASSERT_RETURN(ice_st, PJ_FALSE);
919 return ice_st->ice != NULL;
920}
921
922/*
923 * Check if ICE negotiation is still running.
924 */
925PJ_DEF(pj_bool_t) pj_ice_strans_sess_is_running(pj_ice_strans *ice_st)
926{
927 return ice_st && ice_st->ice && ice_st->ice->rcand_cnt &&
928 !pj_ice_strans_sess_is_complete(ice_st);
929}
930
931
932/*
933 * Check if ICE negotiation has completed.
934 */
935PJ_DEF(pj_bool_t) pj_ice_strans_sess_is_complete(pj_ice_strans *ice_st)
936{
937 return ice_st && ice_st->ice && ice_st->ice->is_complete;
938}
939
940
941/*
942 * Get the current/running component count.
943 */
944PJ_DEF(unsigned) pj_ice_strans_get_running_comp_cnt(pj_ice_strans *ice_st)
945{
946 PJ_ASSERT_RETURN(ice_st, PJ_EINVAL);
947
948 if (ice_st->ice && ice_st->ice->rcand_cnt) {
949 return ice_st->ice->comp_cnt;
950 } else {
951 return ice_st->comp_cnt;
952 }
953}
954
955
956/*
957 * Get the ICE username fragment and password of the ICE session.
958 */
959PJ_DEF(pj_status_t) pj_ice_strans_get_ufrag_pwd( pj_ice_strans *ice_st,
960 pj_str_t *loc_ufrag,
961 pj_str_t *loc_pwd,
962 pj_str_t *rem_ufrag,
963 pj_str_t *rem_pwd)
964{
965 PJ_ASSERT_RETURN(ice_st && ice_st->ice, PJ_EINVALIDOP);
966
967 if (loc_ufrag) *loc_ufrag = ice_st->ice->rx_ufrag;
968 if (loc_pwd) *loc_pwd = ice_st->ice->rx_pass;
969
970 if (rem_ufrag || rem_pwd) {
971 PJ_ASSERT_RETURN(ice_st->ice->rcand_cnt != 0, PJ_EINVALIDOP);
972 if (rem_ufrag) *rem_ufrag = ice_st->ice->tx_ufrag;
973 if (rem_pwd) *rem_pwd = ice_st->ice->tx_pass;
974 }
975
976 return PJ_SUCCESS;
977}
978
979/*
980 * Get number of candidates
981 */
982PJ_DEF(unsigned) pj_ice_strans_get_cands_count(pj_ice_strans *ice_st,
983 unsigned comp_id)
984{
985 unsigned i, cnt;
986
987 PJ_ASSERT_RETURN(ice_st && ice_st->ice && comp_id &&
988 comp_id <= ice_st->comp_cnt, 0);
989
990 cnt = 0;
991 for (i=0; i<ice_st->ice->lcand_cnt; ++i) {
992 if (ice_st->ice->lcand[i].comp_id != comp_id)
993 continue;
994 ++cnt;
995 }
996
997 return cnt;
998}
999
1000/*
1001 * Enum candidates
1002 */
1003PJ_DEF(pj_status_t) pj_ice_strans_enum_cands(pj_ice_strans *ice_st,
1004 unsigned comp_id,
1005 unsigned *count,
1006 pj_ice_sess_cand cand[])
1007{
1008 unsigned i, cnt;
1009
1010 PJ_ASSERT_RETURN(ice_st && ice_st->ice && comp_id &&
1011 comp_id <= ice_st->comp_cnt && count && cand, PJ_EINVAL);
1012
1013 cnt = 0;
1014 for (i=0; i<ice_st->ice->lcand_cnt && cnt<*count; ++i) {
1015 if (ice_st->ice->lcand[i].comp_id != comp_id)
1016 continue;
1017 pj_memcpy(&cand[cnt], &ice_st->ice->lcand[i],
1018 sizeof(pj_ice_sess_cand));
1019 ++cnt;
1020 }
1021
1022 *count = cnt;
1023 return PJ_SUCCESS;
1024}
1025
1026/*
1027 * Get default candidate.
1028 */
1029PJ_DEF(pj_status_t) pj_ice_strans_get_def_cand( pj_ice_strans *ice_st,
1030 unsigned comp_id,
1031 pj_ice_sess_cand *cand)
1032{
1033 const pj_ice_sess_check *valid_pair;
1034
1035 PJ_ASSERT_RETURN(ice_st && comp_id && comp_id <= ice_st->comp_cnt &&
1036 cand, PJ_EINVAL);
1037
1038 valid_pair = pj_ice_strans_get_valid_pair(ice_st, comp_id);
1039 if (valid_pair) {
1040 pj_memcpy(cand, valid_pair->lcand, sizeof(pj_ice_sess_cand));
1041 } else {
1042 pj_ice_strans_comp *comp = ice_st->comp[comp_id - 1];
1043 pj_assert(comp->default_cand>=0 && comp->default_cand<comp->cand_cnt);
1044 pj_memcpy(cand, &comp->cand_list[comp->default_cand],
1045 sizeof(pj_ice_sess_cand));
1046 }
1047 return PJ_SUCCESS;
1048}
1049
1050/*
1051 * Get the current ICE role.
1052 */
1053PJ_DEF(pj_ice_sess_role) pj_ice_strans_get_role(pj_ice_strans *ice_st)
1054{
1055 PJ_ASSERT_RETURN(ice_st && ice_st->ice, PJ_ICE_SESS_ROLE_UNKNOWN);
1056 return ice_st->ice->role;
1057}
1058
1059/*
1060 * Change session role.
1061 */
1062PJ_DEF(pj_status_t) pj_ice_strans_change_role( pj_ice_strans *ice_st,
1063 pj_ice_sess_role new_role)
1064{
1065 PJ_ASSERT_RETURN(ice_st && ice_st->ice, PJ_EINVALIDOP);
1066 return pj_ice_sess_change_role(ice_st->ice, new_role);
1067}
1068
1069/*
1070 * Start ICE processing !
1071 */
1072PJ_DEF(pj_status_t) pj_ice_strans_start_ice( pj_ice_strans *ice_st,
1073 const pj_str_t *rem_ufrag,
1074 const pj_str_t *rem_passwd,
1075 unsigned rem_cand_cnt,
1076 const pj_ice_sess_cand rem_cand[])
1077{
1078 pj_status_t status;
1079
1080 PJ_ASSERT_RETURN(ice_st && rem_ufrag && rem_passwd &&
1081 rem_cand_cnt && rem_cand, PJ_EINVAL);
1082
1083 /* Mark start time */
1084 pj_gettimeofday(&ice_st->start_time);
1085
1086 /* Build check list */
1087 status = pj_ice_sess_create_check_list(ice_st->ice, rem_ufrag, rem_passwd,
1088 rem_cand_cnt, rem_cand);
1089 if (status != PJ_SUCCESS)
1090 return status;
1091
1092 /* If we have TURN candidate, now is the time to create the permissions */
1093 if (ice_st->comp[0]->turn_sock) {
1094 unsigned i;
1095
1096 for (i=0; i<ice_st->comp_cnt; ++i) {
1097 pj_ice_strans_comp *comp = ice_st->comp[i];
1098 pj_sockaddr addrs[PJ_ICE_ST_MAX_CAND];
1099 unsigned j, count=0;
1100
1101 /* Gather remote addresses for this component */
1102 for (j=0; j<rem_cand_cnt && count<PJ_ARRAY_SIZE(addrs); ++j) {
1103 if (rem_cand[j].comp_id==i+1) {
1104 pj_memcpy(&addrs[count++], &rem_cand[j].addr,
1105 pj_sockaddr_get_len(&rem_cand[j].addr));
1106 }
1107 }
1108
1109 if (count) {
1110 status = pj_turn_sock_set_perm(comp->turn_sock, count,
1111 addrs, 0);
1112 if (status != PJ_SUCCESS) {
1113 pj_ice_strans_stop_ice(ice_st);
1114 return status;
1115 }
1116 }
1117 }
1118 }
1119
1120 /* Start ICE negotiation! */
1121 status = pj_ice_sess_start_check(ice_st->ice);
1122 if (status != PJ_SUCCESS) {
1123 pj_ice_strans_stop_ice(ice_st);
1124 return status;
1125 }
1126
1127 ice_st->state = PJ_ICE_STRANS_STATE_NEGO;
1128 return status;
1129}
1130
1131/*
1132 * Get valid pair.
1133 */
1134PJ_DEF(const pj_ice_sess_check*)
1135pj_ice_strans_get_valid_pair(const pj_ice_strans *ice_st,
1136 unsigned comp_id)
1137{
1138 PJ_ASSERT_RETURN(ice_st && comp_id && comp_id <= ice_st->comp_cnt,
1139 NULL);
1140
1141 if (ice_st->ice == NULL)
1142 return NULL;
1143
1144 return ice_st->ice->comp[comp_id-1].valid_check;
1145}
1146
1147/*
1148 * Stop ICE!
1149 */
1150PJ_DEF(pj_status_t) pj_ice_strans_stop_ice(pj_ice_strans *ice_st)
1151{
1152 PJ_ASSERT_RETURN(ice_st, PJ_EINVAL);
1153
1154 if (ice_st->ice) {
1155 pj_ice_sess_destroy(ice_st->ice);
1156 ice_st->ice = NULL;
1157 }
1158
1159 ice_st->state = PJ_ICE_STRANS_STATE_INIT;
1160 return PJ_SUCCESS;
1161}
1162
1163/*
1164 * Application wants to send outgoing packet.
1165 */
1166PJ_DEF(pj_status_t) pj_ice_strans_sendto( pj_ice_strans *ice_st,
1167 unsigned comp_id,
1168 const void *data,
1169 pj_size_t data_len,
1170 const pj_sockaddr_t *dst_addr,
1171 int dst_addr_len)
1172{
1173 pj_ssize_t pkt_size;
1174 pj_ice_strans_comp *comp;
1175 unsigned def_cand;
1176 pj_status_t status;
1177
1178 PJ_ASSERT_RETURN(ice_st && comp_id && comp_id <= ice_st->comp_cnt &&
1179 dst_addr && dst_addr_len, PJ_EINVAL);
1180
1181 comp = ice_st->comp[comp_id-1];
1182
1183 /* Check that default candidate for the component exists */
1184 def_cand = comp->default_cand;
1185 if (def_cand >= comp->cand_cnt)
1186 return PJ_EINVALIDOP;
1187
1188 /* If ICE is available, send data with ICE, otherwise send with the
1189 * default candidate selected during initialization.
1190 *
1191 * https://trac.pjsip.org/repos/ticket/1416:
1192 * Once ICE has failed, also send data with the default candidate.
1193 */
1194 if (ice_st->ice && ice_st->state == PJ_ICE_STRANS_STATE_RUNNING) {
1195 if (comp->turn_sock) {
1196 pj_turn_sock_lock(comp->turn_sock);
1197 }
1198 status = pj_ice_sess_send_data(ice_st->ice, comp_id, data, data_len);
1199 if (comp->turn_sock) {
1200 pj_turn_sock_unlock(comp->turn_sock);
1201 }
1202 return status;
1203
1204 } else if (comp->cand_list[def_cand].status == PJ_SUCCESS) {
1205
1206 if (comp->cand_list[def_cand].type == PJ_ICE_CAND_TYPE_RELAYED) {
1207
1208 enum {
1209 msg_disable_ind = 0xFFFF &
1210 ~(PJ_STUN_SESS_LOG_TX_IND|
1211 PJ_STUN_SESS_LOG_RX_IND)
1212 };
1213
1214 /* https://trac.pjsip.org/repos/ticket/1316 */
1215 if (comp->turn_sock == NULL) {
1216 /* TURN socket error */
1217 return PJ_EINVALIDOP;
1218 }
1219
1220 if (!comp->turn_log_off) {
1221 /* Disable logging for Send/Data indications */
1222 PJ_LOG(5,(ice_st->obj_name,
1223 "Disabling STUN Indication logging for "
1224 "component %d", comp->comp_id));
1225 pj_turn_sock_set_log(comp->turn_sock, msg_disable_ind);
1226 comp->turn_log_off = PJ_TRUE;
1227 }
1228
1229 status = pj_turn_sock_sendto(comp->turn_sock,
1230 (const pj_uint8_t*)data,
1231 (unsigned)data_len,
1232 dst_addr, dst_addr_len);
1233 return (status==PJ_SUCCESS||status==PJ_EPENDING) ?
1234 PJ_SUCCESS : status;
1235 } else {
1236 pkt_size = data_len;
1237 status = pj_stun_sock_sendto(comp->stun_sock, NULL, data,
1238 (unsigned)data_len, 0, dst_addr,
1239 dst_addr_len);
1240 return (status==PJ_SUCCESS||status==PJ_EPENDING) ?
1241 PJ_SUCCESS : status;
1242 }
1243
1244 } else
1245 return PJ_EINVALIDOP;
1246}
1247
1248/*
1249 * Callback called by ICE session when ICE processing is complete, either
1250 * successfully or with failure.
1251 */
1252static void on_ice_complete(pj_ice_sess *ice, pj_status_t status)
1253{
1254 pj_ice_strans *ice_st = (pj_ice_strans*)ice->user_data;
1255 pj_time_val t;
1256 unsigned msec;
1257
1258 pj_grp_lock_add_ref(ice_st->grp_lock);
1259
1260 pj_gettimeofday(&t);
1261 PJ_TIME_VAL_SUB(t, ice_st->start_time);
1262 msec = PJ_TIME_VAL_MSEC(t);
1263
1264 if (ice_st->cb.on_ice_complete) {
1265 if (status != PJ_SUCCESS) {
1266 char errmsg[PJ_ERR_MSG_SIZE];
1267 pj_strerror(status, errmsg, sizeof(errmsg));
1268 PJ_LOG(4,(ice_st->obj_name,
1269 "ICE negotiation failed after %ds:%03d: %s",
1270 msec/1000, msec%1000, errmsg));
1271 } else {
1272 unsigned i;
1273 enum {
1274 msg_disable_ind = 0xFFFF &
1275 ~(PJ_STUN_SESS_LOG_TX_IND|
1276 PJ_STUN_SESS_LOG_RX_IND)
1277 };
1278
1279 PJ_LOG(4,(ice_st->obj_name,
1280 "ICE negotiation success after %ds:%03d",
1281 msec/1000, msec%1000));
1282
1283 for (i=0; i<ice_st->comp_cnt; ++i) {
1284 const pj_ice_sess_check *check;
1285
1286 check = pj_ice_strans_get_valid_pair(ice_st, i+1);
1287 if (check) {
1288 char lip[PJ_INET6_ADDRSTRLEN+10];
1289 char rip[PJ_INET6_ADDRSTRLEN+10];
1290
1291 pj_sockaddr_print(&check->lcand->addr, lip,
1292 sizeof(lip), 3);
1293 pj_sockaddr_print(&check->rcand->addr, rip,
1294 sizeof(rip), 3);
1295
1296 if (check->lcand->transport_id == TP_TURN) {
1297 /* Activate channel binding for the remote address
1298 * for more efficient data transfer using TURN.
1299 */
1300 status = pj_turn_sock_bind_channel(
1301 ice_st->comp[i]->turn_sock,
1302 &check->rcand->addr,
1303 sizeof(check->rcand->addr));
1304
1305 /* Disable logging for Send/Data indications */
1306 PJ_LOG(5,(ice_st->obj_name,
1307 "Disabling STUN Indication logging for "
1308 "component %d", i+1));
1309 pj_turn_sock_set_log(ice_st->comp[i]->turn_sock,
1310 msg_disable_ind);
1311 ice_st->comp[i]->turn_log_off = PJ_TRUE;
1312 }
1313
1314 PJ_LOG(4,(ice_st->obj_name, " Comp %d: "
1315 "sending from %s candidate %s to "
1316 "%s candidate %s",
1317 i+1,
1318 pj_ice_get_cand_type_name(check->lcand->type),
1319 lip,
1320 pj_ice_get_cand_type_name(check->rcand->type),
1321 rip));
1322
1323 } else {
1324 PJ_LOG(4,(ice_st->obj_name,
1325 "Comp %d: disabled", i+1));
1326 }
1327 }
1328 }
1329
1330 ice_st->state = (status==PJ_SUCCESS) ? PJ_ICE_STRANS_STATE_RUNNING :
1331 PJ_ICE_STRANS_STATE_FAILED;
1332
1333 pj_log_push_indent();
1334 (*ice_st->cb.on_ice_complete)(ice_st, PJ_ICE_STRANS_OP_NEGOTIATION,
1335 status);
1336 pj_log_pop_indent();
1337
1338 }
1339
1340 pj_grp_lock_dec_ref(ice_st->grp_lock);
1341}
1342
1343/*
1344 * Callback called by ICE session when it wants to send outgoing packet.
1345 */
1346static pj_status_t ice_tx_pkt(pj_ice_sess *ice,
1347 unsigned comp_id,
1348 unsigned transport_id,
1349 const void *pkt, pj_size_t size,
1350 const pj_sockaddr_t *dst_addr,
1351 unsigned dst_addr_len)
1352{
1353 pj_ice_strans *ice_st = (pj_ice_strans*)ice->user_data;
1354 pj_ice_strans_comp *comp;
1355 pj_status_t status;
1356#if defined(ENABLE_TRACE) && (ENABLE_TRACE != 0)
1357 char daddr[PJ_INET6_ADDRSTRLEN];
1358#endif
1359
1360 PJ_ASSERT_RETURN(comp_id && comp_id <= ice_st->comp_cnt, PJ_EINVAL);
1361
1362 comp = ice_st->comp[comp_id-1];
1363
1364 TRACE_PKT((comp->ice_st->obj_name,
1365 "Component %d TX packet to %s:%d with transport %d",
1366 comp_id,
1367 pj_sockaddr_print(dst_addr, daddr, sizeof(addr), 0),
1368 pj_sockaddr_get_port(dst_addr),
1369 transport_id));
1370
1371 if (transport_id == TP_TURN) {
1372 if (comp->turn_sock) {
1373 status = pj_turn_sock_sendto(comp->turn_sock,
1374 (const pj_uint8_t*)pkt,
1375 (unsigned)size,
1376 dst_addr, dst_addr_len);
1377 } else {
1378 status = PJ_EINVALIDOP;
1379 }
1380 } else if (transport_id == TP_STUN) {
1381 status = pj_stun_sock_sendto(comp->stun_sock, NULL,
1382 pkt, (unsigned)size, 0,
1383 dst_addr, dst_addr_len);
1384 } else {
1385 pj_assert(!"Invalid transport ID");
1386 status = PJ_EINVALIDOP;
1387 }
1388
1389 return (status==PJ_SUCCESS||status==PJ_EPENDING) ? PJ_SUCCESS : status;
1390}
1391
1392/*
1393 * Callback called by ICE session when it receives application data.
1394 */
1395static void ice_rx_data(pj_ice_sess *ice,
1396 unsigned comp_id,
1397 unsigned transport_id,
1398 void *pkt, pj_size_t size,
1399 const pj_sockaddr_t *src_addr,
1400 unsigned src_addr_len)
1401{
1402 pj_ice_strans *ice_st = (pj_ice_strans*)ice->user_data;
1403
1404 PJ_UNUSED_ARG(transport_id);
1405
1406 if (ice_st->cb.on_rx_data) {
1407 (*ice_st->cb.on_rx_data)(ice_st, comp_id, pkt, size,
1408 src_addr, src_addr_len);
1409 }
1410}
1411
1412/* Notification when incoming packet has been received from
1413 * the STUN socket.
1414 */
1415static pj_bool_t stun_on_rx_data(pj_stun_sock *stun_sock,
1416 void *pkt,
1417 unsigned pkt_len,
1418 const pj_sockaddr_t *src_addr,
1419 unsigned addr_len)
1420{
1421 pj_ice_strans_comp *comp;
1422 pj_ice_strans *ice_st;
1423 pj_status_t status;
1424
1425 comp = (pj_ice_strans_comp*) pj_stun_sock_get_user_data(stun_sock);
1426 if (comp == NULL) {
1427 /* We have disassociated ourselves from the STUN socket */
1428 return PJ_FALSE;
1429 }
1430
1431 ice_st = comp->ice_st;
1432
1433 pj_grp_lock_add_ref(ice_st->grp_lock);
1434
1435 if (ice_st->ice == NULL) {
1436 /* The ICE session is gone, but we're still receiving packets.
1437 * This could also happen if remote doesn't do ICE. So just
1438 * report this to application.
1439 */
1440 if (ice_st->cb.on_rx_data) {
1441 (*ice_st->cb.on_rx_data)(ice_st, comp->comp_id, pkt, pkt_len,
1442 src_addr, addr_len);
1443 }
1444
1445 } else {
1446
1447 /* Hand over the packet to ICE session */
1448 status = pj_ice_sess_on_rx_pkt(comp->ice_st->ice, comp->comp_id,
1449 TP_STUN, pkt, pkt_len,
1450 src_addr, addr_len);
1451
1452 if (status != PJ_SUCCESS) {
1453 ice_st_perror(comp->ice_st, "Error processing packet",
1454 status);
1455 }
1456 }
1457
1458 return pj_grp_lock_dec_ref(ice_st->grp_lock) ? PJ_FALSE : PJ_TRUE;
1459}
1460
1461/* Notifification when asynchronous send operation to the STUN socket
1462 * has completed.
1463 */
1464static pj_bool_t stun_on_data_sent(pj_stun_sock *stun_sock,
1465 pj_ioqueue_op_key_t *send_key,
1466 pj_ssize_t sent)
1467{
1468 PJ_UNUSED_ARG(stun_sock);
1469 PJ_UNUSED_ARG(send_key);
1470 PJ_UNUSED_ARG(sent);
1471 return PJ_TRUE;
1472}
1473
1474/* Notification when the status of the STUN transport has changed. */
1475static pj_bool_t stun_on_status(pj_stun_sock *stun_sock,
1476 pj_stun_sock_op op,
1477 pj_status_t status)
1478{
1479 pj_ice_strans_comp *comp;
1480 pj_ice_strans *ice_st;
1481 pj_ice_sess_cand *cand = NULL;
1482 unsigned i;
1483
1484 pj_assert(status != PJ_EPENDING);
1485
1486 comp = (pj_ice_strans_comp*) pj_stun_sock_get_user_data(stun_sock);
1487 ice_st = comp->ice_st;
1488
1489 pj_grp_lock_add_ref(ice_st->grp_lock);
1490
1491 /* Wait until initialization completes */
1492 pj_grp_lock_acquire(ice_st->grp_lock);
1493
1494 /* Find the srflx cancidate */
1495 for (i=0; i<comp->cand_cnt; ++i) {
1496 if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_SRFLX) {
1497 cand = &comp->cand_list[i];
1498 break;
1499 }
1500 }
1501
1502 pj_grp_lock_release(ice_st->grp_lock);
1503
1504 /* It is possible that we don't have srflx candidate even though this
1505 * callback is called. This could happen when we cancel adding srflx
1506 * candidate due to initialization error.
1507 */
1508 if (cand == NULL) {
1509 return pj_grp_lock_dec_ref(ice_st->grp_lock) ? PJ_FALSE : PJ_TRUE;
1510 }
1511
1512 switch (op) {
1513 case PJ_STUN_SOCK_DNS_OP:
1514 if (status != PJ_SUCCESS) {
1515 /* May not have cand, e.g. when error during init */
1516 if (cand)
1517 cand->status = status;
1518 if (!ice_st->cfg.stun.ignore_stun_error) {
1519 sess_fail(ice_st, PJ_ICE_STRANS_OP_INIT,
1520 "DNS resolution failed", status);
1521 } else {
1522 PJ_LOG(4,(ice_st->obj_name,
1523 "STUN error is ignored for comp %d",
1524 comp->comp_id));
1525 }
1526 }
1527 break;
1528 case PJ_STUN_SOCK_BINDING_OP:
1529 case PJ_STUN_SOCK_MAPPED_ADDR_CHANGE:
1530 if (status == PJ_SUCCESS) {
1531 pj_stun_sock_info info;
1532
1533 status = pj_stun_sock_get_info(stun_sock, &info);
1534 if (status == PJ_SUCCESS) {
1535 char ipaddr[PJ_INET6_ADDRSTRLEN+10];
1536 const char *op_name = (op==PJ_STUN_SOCK_BINDING_OP) ?
1537 "Binding discovery complete" :
1538 "srflx address changed";
1539 pj_bool_t dup = PJ_FALSE;
1540
1541 /* Eliminate the srflx candidate if the address is
1542 * equal to other (host) candidates.
1543 */
1544 for (i=0; i<comp->cand_cnt; ++i) {
1545 if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_HOST &&
1546 pj_sockaddr_cmp(&comp->cand_list[i].addr,
1547 &info.mapped_addr) == 0)
1548 {
1549 dup = PJ_TRUE;
1550 break;
1551 }
1552 }
1553
1554 if (dup) {
1555 /* Duplicate found, remove the srflx candidate */
1556 unsigned idx = (unsigned)(cand - comp->cand_list);
1557
1558 /* Update default candidate index */
1559 if (comp->default_cand > idx) {
1560 --comp->default_cand;
1561 } else if (comp->default_cand == idx) {
1562 comp->default_cand = 0;
1563 }
1564
1565 /* Remove srflx candidate */
1566 pj_array_erase(comp->cand_list, sizeof(comp->cand_list[0]),
1567 comp->cand_cnt, idx);
1568 --comp->cand_cnt;
1569 } else {
1570 /* Otherwise update the address */
1571 pj_sockaddr_cp(&cand->addr, &info.mapped_addr);
1572 cand->status = PJ_SUCCESS;
1573 }
1574
1575 PJ_LOG(4,(comp->ice_st->obj_name,
1576 "Comp %d: %s, "
1577 "srflx address is %s",
1578 comp->comp_id, op_name,
1579 pj_sockaddr_print(&info.mapped_addr, ipaddr,
1580 sizeof(ipaddr), 3)));
1581
1582 sess_init_update(ice_st);
1583 }
1584 }
1585
1586 if (status != PJ_SUCCESS) {
1587 /* May not have cand, e.g. when error during init */
1588 if (cand)
1589 cand->status = status;
1590 if (!ice_st->cfg.stun.ignore_stun_error || comp->cand_cnt==1) {
1591 sess_fail(ice_st, PJ_ICE_STRANS_OP_INIT,
1592 "STUN binding request failed", status);
1593 } else {
1594 PJ_LOG(4,(ice_st->obj_name,
1595 "STUN error is ignored for comp %d",
1596 comp->comp_id));
1597
1598 if (cand) {
1599 unsigned idx = (unsigned)(cand - comp->cand_list);
1600
1601 /* Update default candidate index */
1602 if (comp->default_cand == idx) {
1603 comp->default_cand = !idx;
1604 }
1605 }
1606
1607 sess_init_update(ice_st);
1608 }
1609 }
1610 break;
1611 case PJ_STUN_SOCK_KEEP_ALIVE_OP:
1612 if (status != PJ_SUCCESS) {
1613 pj_assert(cand != NULL);
1614 cand->status = status;
1615 if (!ice_st->cfg.stun.ignore_stun_error) {
1616 sess_fail(ice_st, PJ_ICE_STRANS_OP_INIT,
1617 "STUN keep-alive failed", status);
1618 } else {
1619 PJ_LOG(4,(ice_st->obj_name, "STUN error is ignored"));
1620 }
1621 }
1622 break;
1623 }
1624
1625 return pj_grp_lock_dec_ref(ice_st->grp_lock)? PJ_FALSE : PJ_TRUE;
1626}
1627
1628/* Callback when TURN socket has received a packet */
1629static void turn_on_rx_data(pj_turn_sock *turn_sock,
1630 void *pkt,
1631 unsigned pkt_len,
1632 const pj_sockaddr_t *peer_addr,
1633 unsigned addr_len)
1634{
1635 pj_ice_strans_comp *comp;
1636 pj_status_t status;
1637
1638 comp = (pj_ice_strans_comp*) pj_turn_sock_get_user_data(turn_sock);
1639 if (comp == NULL) {
1640 /* We have disassociated ourselves from the TURN socket */
1641 return;
1642 }
1643
1644 pj_grp_lock_add_ref(comp->ice_st->grp_lock);
1645
1646 if (comp->ice_st->ice == NULL) {
1647 /* The ICE session is gone, but we're still receiving packets.
1648 * This could also happen if remote doesn't do ICE and application
1649 * specifies TURN as the default address in SDP.
1650 * So in this case just give the packet to application.
1651 */
1652 if (comp->ice_st->cb.on_rx_data) {
1653 (*comp->ice_st->cb.on_rx_data)(comp->ice_st, comp->comp_id, pkt,
1654 pkt_len, peer_addr, addr_len);
1655 }
1656
1657 } else {
1658
1659 /* Hand over the packet to ICE */
1660 status = pj_ice_sess_on_rx_pkt(comp->ice_st->ice, comp->comp_id,
1661 TP_TURN, pkt, pkt_len,
1662 peer_addr, addr_len);
1663
1664 if (status != PJ_SUCCESS) {
1665 ice_st_perror(comp->ice_st,
1666 "Error processing packet from TURN relay",
1667 status);
1668 }
1669 }
1670
1671 pj_grp_lock_dec_ref(comp->ice_st->grp_lock);
1672}
1673
1674
1675/* Callback when TURN client state has changed */
1676static void turn_on_state(pj_turn_sock *turn_sock, pj_turn_state_t old_state,
1677 pj_turn_state_t new_state)
1678{
1679 pj_ice_strans_comp *comp;
1680
1681 comp = (pj_ice_strans_comp*) pj_turn_sock_get_user_data(turn_sock);
1682 if (comp == NULL) {
1683 /* Not interested in further state notification once the relay is
1684 * disconnecting.
1685 */
1686 return;
1687 }
1688
1689 PJ_LOG(5,(comp->ice_st->obj_name, "TURN client state changed %s --> %s",
1690 pj_turn_state_name(old_state), pj_turn_state_name(new_state)));
1691 pj_log_push_indent();
1692
1693 pj_grp_lock_add_ref(comp->ice_st->grp_lock);
1694
1695 if (new_state == PJ_TURN_STATE_READY) {
1696 pj_turn_session_info rel_info;
1697 char ipaddr[PJ_INET6_ADDRSTRLEN+8];
1698 pj_ice_sess_cand *cand = NULL;
1699 unsigned i;
1700
1701 comp->turn_err_cnt = 0;
1702
1703 /* Get allocation info */
1704 pj_turn_sock_get_info(turn_sock, &rel_info);
1705
1706 /* Wait until initialization completes */
1707 pj_grp_lock_acquire(comp->ice_st->grp_lock);
1708
1709 /* Find relayed candidate in the component */
1710 for (i=0; i<comp->cand_cnt; ++i) {
1711 if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_RELAYED) {
1712 cand = &comp->cand_list[i];
1713 break;
1714 }
1715 }
1716 pj_assert(cand != NULL);
1717
1718 pj_grp_lock_release(comp->ice_st->grp_lock);
1719
1720 /* Update candidate */
1721 pj_sockaddr_cp(&cand->addr, &rel_info.relay_addr);
1722 pj_sockaddr_cp(&cand->base_addr, &rel_info.relay_addr);
1723 pj_sockaddr_cp(&cand->rel_addr, &rel_info.mapped_addr);
1724 pj_ice_calc_foundation(comp->ice_st->pool, &cand->foundation,
1725 PJ_ICE_CAND_TYPE_RELAYED,
1726 &rel_info.relay_addr);
1727 cand->status = PJ_SUCCESS;
1728
1729 /* Set default candidate to relay */
1730 comp->default_cand = (unsigned)(cand - comp->cand_list);
1731
1732 PJ_LOG(4,(comp->ice_st->obj_name,
1733 "Comp %d: TURN allocation complete, relay address is %s",
1734 comp->comp_id,
1735 pj_sockaddr_print(&rel_info.relay_addr, ipaddr,
1736 sizeof(ipaddr), 3)));
1737
1738 sess_init_update(comp->ice_st);
1739
1740 } else if (new_state >= PJ_TURN_STATE_DEALLOCATING) {
1741 pj_turn_session_info info;
1742
1743 ++comp->turn_err_cnt;
1744
1745 pj_turn_sock_get_info(turn_sock, &info);
1746
1747 /* Unregister ourself from the TURN relay */
1748 pj_turn_sock_set_user_data(turn_sock, NULL);
1749 comp->turn_sock = NULL;
1750
1751 /* Set session to fail on error. last_status PJ_SUCCESS means normal
1752 * deallocation, which should not trigger sess_fail as it may have
1753 * been initiated by ICE destroy
1754 */
1755 if (info.last_status != PJ_SUCCESS) {
1756 if (comp->ice_st->state < PJ_ICE_STRANS_STATE_READY) {
1757 sess_fail(comp->ice_st, PJ_ICE_STRANS_OP_INIT,
1758 "TURN allocation failed", info.last_status);
1759 } else if (comp->turn_err_cnt > 1) {
1760 sess_fail(comp->ice_st, PJ_ICE_STRANS_OP_KEEP_ALIVE,
1761 "TURN refresh failed", info.last_status);
1762 } else {
1763 PJ_PERROR(4,(comp->ice_st->obj_name, info.last_status,
1764 "Comp %d: TURN allocation failed, retrying",
1765 comp->comp_id));
1766 add_update_turn(comp->ice_st, comp);
1767 }
1768 }
1769 }
1770
1771 pj_grp_lock_dec_ref(comp->ice_st->grp_lock);
1772
1773 pj_log_pop_indent();
1774}
1775