blob: 95ca95717370525856c01dab020cd7debea61bf8 [file] [log] [blame]
Tristan Matthews0a329cc2013-07-17 13:20:14 -04001/* $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[4] =
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 * Create ICE!
802 */
803PJ_DEF(pj_status_t) pj_ice_strans_init_ice(pj_ice_strans *ice_st,
804 pj_ice_sess_role role,
805 const pj_str_t *local_ufrag,
806 const pj_str_t *local_passwd)
807{
808 pj_status_t status;
809 unsigned i;
810 pj_ice_sess_cb ice_cb;
811 //const pj_uint8_t srflx_prio[4] = { 100, 126, 110, 0 };
812
813 /* Check arguments */
814 PJ_ASSERT_RETURN(ice_st, PJ_EINVAL);
815 /* Must not have ICE */
816 PJ_ASSERT_RETURN(ice_st->ice == NULL, PJ_EINVALIDOP);
817 /* Components must have been created */
818 PJ_ASSERT_RETURN(ice_st->comp[0] != NULL, PJ_EINVALIDOP);
819
820 /* Init callback */
821 pj_bzero(&ice_cb, sizeof(ice_cb));
822 ice_cb.on_ice_complete = &on_ice_complete;
823 ice_cb.on_rx_data = &ice_rx_data;
824 ice_cb.on_tx_pkt = &ice_tx_pkt;
825
826 /* Create! */
827 status = pj_ice_sess_create(&ice_st->cfg.stun_cfg, ice_st->obj_name, role,
828 ice_st->comp_cnt, &ice_cb,
829 local_ufrag, local_passwd,
830 ice_st->grp_lock,
831 &ice_st->ice);
832 if (status != PJ_SUCCESS)
833 return status;
834
835 /* Associate user data */
836 ice_st->ice->user_data = (void*)ice_st;
837
838 /* Set options */
839 pj_ice_sess_set_options(ice_st->ice, &ice_st->cfg.opt);
840
841 /* If default candidate for components are SRFLX one, upload a custom
842 * type priority to ICE session so that SRFLX candidates will get
843 * checked first.
844 */
845 if (ice_st->comp[0]->default_cand >= 0 &&
846 ice_st->comp[0]->cand_list[ice_st->comp[0]->default_cand].type
847 == PJ_ICE_CAND_TYPE_SRFLX)
848 {
849 pj_ice_sess_set_prefs(ice_st->ice, srflx_pref_table);
850 }
851
852 /* Add components/candidates */
853 for (i=0; i<ice_st->comp_cnt; ++i) {
854 unsigned j;
855 pj_ice_strans_comp *comp = ice_st->comp[i];
856
857 /* Re-enable logging for Send/Data indications */
858 if (comp->turn_sock) {
859 PJ_LOG(5,(ice_st->obj_name,
860 "Disabling STUN Indication logging for "
861 "component %d", i+1));
862 pj_turn_sock_set_log(comp->turn_sock, 0xFFFF);
863 comp->turn_log_off = PJ_FALSE;
864 }
865
866 for (j=0; j<comp->cand_cnt; ++j) {
867 pj_ice_sess_cand *cand = &comp->cand_list[j];
868 unsigned ice_cand_id;
869
870 /* Skip if candidate is not ready */
871 if (cand->status != PJ_SUCCESS) {
872 PJ_LOG(5,(ice_st->obj_name,
873 "Candidate %d of comp %d is not added (pending)",
874 j, i));
875 continue;
876 }
877
878 /* Must have address */
879 pj_assert(pj_sockaddr_has_addr(&cand->addr));
880
881 /* Add the candidate */
882 status = pj_ice_sess_add_cand(ice_st->ice, comp->comp_id,
883 cand->transport_id, cand->type,
884 cand->local_pref,
885 &cand->foundation, &cand->addr,
886 &cand->base_addr, &cand->rel_addr,
887 pj_sockaddr_get_len(&cand->addr),
888 (unsigned*)&ice_cand_id);
889 if (status != PJ_SUCCESS)
890 goto on_error;
891 }
892 }
893
894 /* ICE session is ready for negotiation */
895 ice_st->state = PJ_ICE_STRANS_STATE_SESS_READY;
896
897 return PJ_SUCCESS;
898
899on_error:
900 pj_ice_strans_stop_ice(ice_st);
901 return status;
902}
903
904/*
905 * Check if the ICE stream transport has the ICE session created.
906 */
907PJ_DEF(pj_bool_t) pj_ice_strans_has_sess(pj_ice_strans *ice_st)
908{
909 PJ_ASSERT_RETURN(ice_st, PJ_FALSE);
910 return ice_st->ice != NULL;
911}
912
913/*
914 * Check if ICE negotiation is still running.
915 */
916PJ_DEF(pj_bool_t) pj_ice_strans_sess_is_running(pj_ice_strans *ice_st)
917{
918 return ice_st && ice_st->ice && ice_st->ice->rcand_cnt &&
919 !pj_ice_strans_sess_is_complete(ice_st);
920}
921
922
923/*
924 * Check if ICE negotiation has completed.
925 */
926PJ_DEF(pj_bool_t) pj_ice_strans_sess_is_complete(pj_ice_strans *ice_st)
927{
928 return ice_st && ice_st->ice && ice_st->ice->is_complete;
929}
930
931
932/*
933 * Get the current/running component count.
934 */
935PJ_DEF(unsigned) pj_ice_strans_get_running_comp_cnt(pj_ice_strans *ice_st)
936{
937 PJ_ASSERT_RETURN(ice_st, PJ_EINVAL);
938
939 if (ice_st->ice && ice_st->ice->rcand_cnt) {
940 return ice_st->ice->comp_cnt;
941 } else {
942 return ice_st->comp_cnt;
943 }
944}
945
946
947/*
948 * Get the ICE username fragment and password of the ICE session.
949 */
950PJ_DEF(pj_status_t) pj_ice_strans_get_ufrag_pwd( pj_ice_strans *ice_st,
951 pj_str_t *loc_ufrag,
952 pj_str_t *loc_pwd,
953 pj_str_t *rem_ufrag,
954 pj_str_t *rem_pwd)
955{
956 PJ_ASSERT_RETURN(ice_st && ice_st->ice, PJ_EINVALIDOP);
957
958 if (loc_ufrag) *loc_ufrag = ice_st->ice->rx_ufrag;
959 if (loc_pwd) *loc_pwd = ice_st->ice->rx_pass;
960
961 if (rem_ufrag || rem_pwd) {
962 PJ_ASSERT_RETURN(ice_st->ice->rcand_cnt != 0, PJ_EINVALIDOP);
963 if (rem_ufrag) *rem_ufrag = ice_st->ice->tx_ufrag;
964 if (rem_pwd) *rem_pwd = ice_st->ice->tx_pass;
965 }
966
967 return PJ_SUCCESS;
968}
969
970/*
971 * Get number of candidates
972 */
973PJ_DEF(unsigned) pj_ice_strans_get_cands_count(pj_ice_strans *ice_st,
974 unsigned comp_id)
975{
976 unsigned i, cnt;
977
978 PJ_ASSERT_RETURN(ice_st && ice_st->ice && comp_id &&
979 comp_id <= ice_st->comp_cnt, 0);
980
981 cnt = 0;
982 for (i=0; i<ice_st->ice->lcand_cnt; ++i) {
983 if (ice_st->ice->lcand[i].comp_id != comp_id)
984 continue;
985 ++cnt;
986 }
987
988 return cnt;
989}
990
991/*
992 * Enum candidates
993 */
994PJ_DEF(pj_status_t) pj_ice_strans_enum_cands(pj_ice_strans *ice_st,
995 unsigned comp_id,
996 unsigned *count,
997 pj_ice_sess_cand cand[])
998{
999 unsigned i, cnt;
1000
1001 PJ_ASSERT_RETURN(ice_st && ice_st->ice && comp_id &&
1002 comp_id <= ice_st->comp_cnt && count && cand, PJ_EINVAL);
1003
1004 cnt = 0;
1005 for (i=0; i<ice_st->ice->lcand_cnt && cnt<*count; ++i) {
1006 if (ice_st->ice->lcand[i].comp_id != comp_id)
1007 continue;
1008 pj_memcpy(&cand[cnt], &ice_st->ice->lcand[i],
1009 sizeof(pj_ice_sess_cand));
1010 ++cnt;
1011 }
1012
1013 *count = cnt;
1014 return PJ_SUCCESS;
1015}
1016
1017/*
1018 * Get default candidate.
1019 */
1020PJ_DEF(pj_status_t) pj_ice_strans_get_def_cand( pj_ice_strans *ice_st,
1021 unsigned comp_id,
1022 pj_ice_sess_cand *cand)
1023{
1024 const pj_ice_sess_check *valid_pair;
1025
1026 PJ_ASSERT_RETURN(ice_st && comp_id && comp_id <= ice_st->comp_cnt &&
1027 cand, PJ_EINVAL);
1028
1029 valid_pair = pj_ice_strans_get_valid_pair(ice_st, comp_id);
1030 if (valid_pair) {
1031 pj_memcpy(cand, valid_pair->lcand, sizeof(pj_ice_sess_cand));
1032 } else {
1033 pj_ice_strans_comp *comp = ice_st->comp[comp_id - 1];
1034 pj_assert(comp->default_cand>=0 && comp->default_cand<comp->cand_cnt);
1035 pj_memcpy(cand, &comp->cand_list[comp->default_cand],
1036 sizeof(pj_ice_sess_cand));
1037 }
1038 return PJ_SUCCESS;
1039}
1040
1041/*
1042 * Get the current ICE role.
1043 */
1044PJ_DEF(pj_ice_sess_role) pj_ice_strans_get_role(pj_ice_strans *ice_st)
1045{
1046 PJ_ASSERT_RETURN(ice_st && ice_st->ice, PJ_ICE_SESS_ROLE_UNKNOWN);
1047 return ice_st->ice->role;
1048}
1049
1050/*
1051 * Change session role.
1052 */
1053PJ_DEF(pj_status_t) pj_ice_strans_change_role( pj_ice_strans *ice_st,
1054 pj_ice_sess_role new_role)
1055{
1056 PJ_ASSERT_RETURN(ice_st && ice_st->ice, PJ_EINVALIDOP);
1057 return pj_ice_sess_change_role(ice_st->ice, new_role);
1058}
1059
1060/*
1061 * Start ICE processing !
1062 */
1063PJ_DEF(pj_status_t) pj_ice_strans_start_ice( pj_ice_strans *ice_st,
1064 const pj_str_t *rem_ufrag,
1065 const pj_str_t *rem_passwd,
1066 unsigned rem_cand_cnt,
1067 const pj_ice_sess_cand rem_cand[])
1068{
1069 pj_status_t status;
1070
1071 PJ_ASSERT_RETURN(ice_st && rem_ufrag && rem_passwd &&
1072 rem_cand_cnt && rem_cand, PJ_EINVAL);
1073
1074 /* Mark start time */
1075 pj_gettimeofday(&ice_st->start_time);
1076
1077 /* Build check list */
1078 status = pj_ice_sess_create_check_list(ice_st->ice, rem_ufrag, rem_passwd,
1079 rem_cand_cnt, rem_cand);
1080 if (status != PJ_SUCCESS)
1081 return status;
1082
1083 /* If we have TURN candidate, now is the time to create the permissions */
1084 if (ice_st->comp[0]->turn_sock) {
1085 unsigned i;
1086
1087 for (i=0; i<ice_st->comp_cnt; ++i) {
1088 pj_ice_strans_comp *comp = ice_st->comp[i];
1089 pj_sockaddr addrs[PJ_ICE_ST_MAX_CAND];
1090 unsigned j, count=0;
1091
1092 /* Gather remote addresses for this component */
1093 for (j=0; j<rem_cand_cnt && count<PJ_ARRAY_SIZE(addrs); ++j) {
1094 if (rem_cand[j].comp_id==i+1) {
1095 pj_memcpy(&addrs[count++], &rem_cand[j].addr,
1096 pj_sockaddr_get_len(&rem_cand[j].addr));
1097 }
1098 }
1099
1100 if (count) {
1101 status = pj_turn_sock_set_perm(comp->turn_sock, count,
1102 addrs, 0);
1103 if (status != PJ_SUCCESS) {
1104 pj_ice_strans_stop_ice(ice_st);
1105 return status;
1106 }
1107 }
1108 }
1109 }
1110
1111 /* Start ICE negotiation! */
1112 status = pj_ice_sess_start_check(ice_st->ice);
1113 if (status != PJ_SUCCESS) {
1114 pj_ice_strans_stop_ice(ice_st);
1115 return status;
1116 }
1117
1118 ice_st->state = PJ_ICE_STRANS_STATE_NEGO;
1119 return status;
1120}
1121
1122/*
1123 * Get valid pair.
1124 */
1125PJ_DEF(const pj_ice_sess_check*)
1126pj_ice_strans_get_valid_pair(const pj_ice_strans *ice_st,
1127 unsigned comp_id)
1128{
1129 PJ_ASSERT_RETURN(ice_st && comp_id && comp_id <= ice_st->comp_cnt,
1130 NULL);
1131
1132 if (ice_st->ice == NULL)
1133 return NULL;
1134
1135 return ice_st->ice->comp[comp_id-1].valid_check;
1136}
1137
1138/*
1139 * Stop ICE!
1140 */
1141PJ_DEF(pj_status_t) pj_ice_strans_stop_ice(pj_ice_strans *ice_st)
1142{
1143 PJ_ASSERT_RETURN(ice_st, PJ_EINVAL);
1144
1145 if (ice_st->ice) {
1146 pj_ice_sess_destroy(ice_st->ice);
1147 ice_st->ice = NULL;
1148 }
1149
1150 ice_st->state = PJ_ICE_STRANS_STATE_INIT;
1151 return PJ_SUCCESS;
1152}
1153
1154/*
1155 * Application wants to send outgoing packet.
1156 */
1157PJ_DEF(pj_status_t) pj_ice_strans_sendto( pj_ice_strans *ice_st,
1158 unsigned comp_id,
1159 const void *data,
1160 pj_size_t data_len,
1161 const pj_sockaddr_t *dst_addr,
1162 int dst_addr_len)
1163{
1164 pj_ssize_t pkt_size;
1165 pj_ice_strans_comp *comp;
1166 unsigned def_cand;
1167 pj_status_t status;
1168
1169 PJ_ASSERT_RETURN(ice_st && comp_id && comp_id <= ice_st->comp_cnt &&
1170 dst_addr && dst_addr_len, PJ_EINVAL);
1171
1172 comp = ice_st->comp[comp_id-1];
1173
1174 /* Check that default candidate for the component exists */
1175 def_cand = comp->default_cand;
1176 if (def_cand >= comp->cand_cnt)
1177 return PJ_EINVALIDOP;
1178
1179 /* If ICE is available, send data with ICE, otherwise send with the
1180 * default candidate selected during initialization.
1181 *
1182 * https://trac.pjsip.org/repos/ticket/1416:
1183 * Once ICE has failed, also send data with the default candidate.
1184 */
1185 if (ice_st->ice && ice_st->state < PJ_ICE_STRANS_STATE_FAILED) {
1186 if (comp->turn_sock) {
1187 pj_turn_sock_lock(comp->turn_sock);
1188 }
1189 status = pj_ice_sess_send_data(ice_st->ice, comp_id, data, data_len);
1190 if (comp->turn_sock) {
1191 pj_turn_sock_unlock(comp->turn_sock);
1192 }
1193 return status;
1194
1195 } else if (comp->cand_list[def_cand].status == PJ_SUCCESS) {
1196
1197 if (comp->cand_list[def_cand].type == PJ_ICE_CAND_TYPE_RELAYED) {
1198
1199 enum {
1200 msg_disable_ind = 0xFFFF &
1201 ~(PJ_STUN_SESS_LOG_TX_IND|
1202 PJ_STUN_SESS_LOG_RX_IND)
1203 };
1204
1205 /* https://trac.pjsip.org/repos/ticket/1316 */
1206 if (comp->turn_sock == NULL) {
1207 /* TURN socket error */
1208 return PJ_EINVALIDOP;
1209 }
1210
1211 if (!comp->turn_log_off) {
1212 /* Disable logging for Send/Data indications */
1213 PJ_LOG(5,(ice_st->obj_name,
1214 "Disabling STUN Indication logging for "
1215 "component %d", comp->comp_id));
1216 pj_turn_sock_set_log(comp->turn_sock, msg_disable_ind);
1217 comp->turn_log_off = PJ_TRUE;
1218 }
1219
1220 status = pj_turn_sock_sendto(comp->turn_sock,
1221 (const pj_uint8_t*)data,
1222 (unsigned)data_len,
1223 dst_addr, dst_addr_len);
1224 return (status==PJ_SUCCESS||status==PJ_EPENDING) ?
1225 PJ_SUCCESS : status;
1226 } else {
1227 pkt_size = data_len;
1228 status = pj_stun_sock_sendto(comp->stun_sock, NULL, data,
1229 (unsigned)data_len, 0, dst_addr,
1230 dst_addr_len);
1231 return (status==PJ_SUCCESS||status==PJ_EPENDING) ?
1232 PJ_SUCCESS : status;
1233 }
1234
1235 } else
1236 return PJ_EINVALIDOP;
1237}
1238
1239/*
1240 * Callback called by ICE session when ICE processing is complete, either
1241 * successfully or with failure.
1242 */
1243static void on_ice_complete(pj_ice_sess *ice, pj_status_t status)
1244{
1245 pj_ice_strans *ice_st = (pj_ice_strans*)ice->user_data;
1246 pj_time_val t;
1247 unsigned msec;
1248
1249 pj_grp_lock_add_ref(ice_st->grp_lock);
1250
1251 pj_gettimeofday(&t);
1252 PJ_TIME_VAL_SUB(t, ice_st->start_time);
1253 msec = PJ_TIME_VAL_MSEC(t);
1254
1255 if (ice_st->cb.on_ice_complete) {
1256 if (status != PJ_SUCCESS) {
1257 char errmsg[PJ_ERR_MSG_SIZE];
1258 pj_strerror(status, errmsg, sizeof(errmsg));
1259 PJ_LOG(4,(ice_st->obj_name,
1260 "ICE negotiation failed after %ds:%03d: %s",
1261 msec/1000, msec%1000, errmsg));
1262 } else {
1263 unsigned i;
1264 enum {
1265 msg_disable_ind = 0xFFFF &
1266 ~(PJ_STUN_SESS_LOG_TX_IND|
1267 PJ_STUN_SESS_LOG_RX_IND)
1268 };
1269
1270 PJ_LOG(4,(ice_st->obj_name,
1271 "ICE negotiation success after %ds:%03d",
1272 msec/1000, msec%1000));
1273
1274 for (i=0; i<ice_st->comp_cnt; ++i) {
1275 const pj_ice_sess_check *check;
1276
1277 check = pj_ice_strans_get_valid_pair(ice_st, i+1);
1278 if (check) {
1279 char lip[PJ_INET6_ADDRSTRLEN+10];
1280 char rip[PJ_INET6_ADDRSTRLEN+10];
1281
1282 pj_sockaddr_print(&check->lcand->addr, lip,
1283 sizeof(lip), 3);
1284 pj_sockaddr_print(&check->rcand->addr, rip,
1285 sizeof(rip), 3);
1286
1287 if (check->lcand->transport_id == TP_TURN) {
1288 /* Activate channel binding for the remote address
1289 * for more efficient data transfer using TURN.
1290 */
1291 status = pj_turn_sock_bind_channel(
1292 ice_st->comp[i]->turn_sock,
1293 &check->rcand->addr,
1294 sizeof(check->rcand->addr));
1295
1296 /* Disable logging for Send/Data indications */
1297 PJ_LOG(5,(ice_st->obj_name,
1298 "Disabling STUN Indication logging for "
1299 "component %d", i+1));
1300 pj_turn_sock_set_log(ice_st->comp[i]->turn_sock,
1301 msg_disable_ind);
1302 ice_st->comp[i]->turn_log_off = PJ_TRUE;
1303 }
1304
1305 PJ_LOG(4,(ice_st->obj_name, " Comp %d: "
1306 "sending from %s candidate %s to "
1307 "%s candidate %s",
1308 i+1,
1309 pj_ice_get_cand_type_name(check->lcand->type),
1310 lip,
1311 pj_ice_get_cand_type_name(check->rcand->type),
1312 rip));
1313
1314 } else {
1315 PJ_LOG(4,(ice_st->obj_name,
1316 "Comp %d: disabled", i+1));
1317 }
1318 }
1319 }
1320
1321 ice_st->state = (status==PJ_SUCCESS) ? PJ_ICE_STRANS_STATE_RUNNING :
1322 PJ_ICE_STRANS_STATE_FAILED;
1323
1324 pj_log_push_indent();
1325 (*ice_st->cb.on_ice_complete)(ice_st, PJ_ICE_STRANS_OP_NEGOTIATION,
1326 status);
1327 pj_log_pop_indent();
1328
1329 }
1330
1331 pj_grp_lock_dec_ref(ice_st->grp_lock);
1332}
1333
1334/*
1335 * Callback called by ICE session when it wants to send outgoing packet.
1336 */
1337static pj_status_t ice_tx_pkt(pj_ice_sess *ice,
1338 unsigned comp_id,
1339 unsigned transport_id,
1340 const void *pkt, pj_size_t size,
1341 const pj_sockaddr_t *dst_addr,
1342 unsigned dst_addr_len)
1343{
1344 pj_ice_strans *ice_st = (pj_ice_strans*)ice->user_data;
1345 pj_ice_strans_comp *comp;
1346 pj_status_t status;
1347#if defined(ENABLE_TRACE) && (ENABLE_TRACE != 0)
1348 char daddr[PJ_INET6_ADDRSTRLEN];
1349#endif
1350
1351 PJ_ASSERT_RETURN(comp_id && comp_id <= ice_st->comp_cnt, PJ_EINVAL);
1352
1353 comp = ice_st->comp[comp_id-1];
1354
1355 TRACE_PKT((comp->ice_st->obj_name,
1356 "Component %d TX packet to %s:%d with transport %d",
1357 comp_id,
1358 pj_sockaddr_print(dst_addr, daddr, sizeof(addr), 0),
1359 pj_sockaddr_get_port(dst_addr),
1360 transport_id));
1361
1362 if (transport_id == TP_TURN) {
1363 if (comp->turn_sock) {
1364 status = pj_turn_sock_sendto(comp->turn_sock,
1365 (const pj_uint8_t*)pkt,
1366 (unsigned)size,
1367 dst_addr, dst_addr_len);
1368 } else {
1369 status = PJ_EINVALIDOP;
1370 }
1371 } else if (transport_id == TP_STUN) {
1372 status = pj_stun_sock_sendto(comp->stun_sock, NULL,
1373 pkt, (unsigned)size, 0,
1374 dst_addr, dst_addr_len);
1375 } else {
1376 pj_assert(!"Invalid transport ID");
1377 status = PJ_EINVALIDOP;
1378 }
1379
1380 return (status==PJ_SUCCESS||status==PJ_EPENDING) ? PJ_SUCCESS : status;
1381}
1382
1383/*
1384 * Callback called by ICE session when it receives application data.
1385 */
1386static void ice_rx_data(pj_ice_sess *ice,
1387 unsigned comp_id,
1388 unsigned transport_id,
1389 void *pkt, pj_size_t size,
1390 const pj_sockaddr_t *src_addr,
1391 unsigned src_addr_len)
1392{
1393 pj_ice_strans *ice_st = (pj_ice_strans*)ice->user_data;
1394
1395 PJ_UNUSED_ARG(transport_id);
1396
1397 if (ice_st->cb.on_rx_data) {
1398 (*ice_st->cb.on_rx_data)(ice_st, comp_id, pkt, size,
1399 src_addr, src_addr_len);
1400 }
1401}
1402
1403/* Notification when incoming packet has been received from
1404 * the STUN socket.
1405 */
1406static pj_bool_t stun_on_rx_data(pj_stun_sock *stun_sock,
1407 void *pkt,
1408 unsigned pkt_len,
1409 const pj_sockaddr_t *src_addr,
1410 unsigned addr_len)
1411{
1412 pj_ice_strans_comp *comp;
1413 pj_ice_strans *ice_st;
1414 pj_status_t status;
1415
1416 comp = (pj_ice_strans_comp*) pj_stun_sock_get_user_data(stun_sock);
1417 if (comp == NULL) {
1418 /* We have disassociated ourselves from the STUN socket */
1419 return PJ_FALSE;
1420 }
1421
1422 ice_st = comp->ice_st;
1423
1424 pj_grp_lock_add_ref(ice_st->grp_lock);
1425
1426 if (ice_st->ice == NULL) {
1427 /* The ICE session is gone, but we're still receiving packets.
1428 * This could also happen if remote doesn't do ICE. So just
1429 * report this to application.
1430 */
1431 if (ice_st->cb.on_rx_data) {
1432 (*ice_st->cb.on_rx_data)(ice_st, comp->comp_id, pkt, pkt_len,
1433 src_addr, addr_len);
1434 }
1435
1436 } else {
1437
1438 /* Hand over the packet to ICE session */
1439 status = pj_ice_sess_on_rx_pkt(comp->ice_st->ice, comp->comp_id,
1440 TP_STUN, pkt, pkt_len,
1441 src_addr, addr_len);
1442
1443 if (status != PJ_SUCCESS) {
1444 ice_st_perror(comp->ice_st, "Error processing packet",
1445 status);
1446 }
1447 }
1448
1449 return pj_grp_lock_dec_ref(ice_st->grp_lock) ? PJ_FALSE : PJ_TRUE;
1450}
1451
1452/* Notifification when asynchronous send operation to the STUN socket
1453 * has completed.
1454 */
1455static pj_bool_t stun_on_data_sent(pj_stun_sock *stun_sock,
1456 pj_ioqueue_op_key_t *send_key,
1457 pj_ssize_t sent)
1458{
1459 PJ_UNUSED_ARG(stun_sock);
1460 PJ_UNUSED_ARG(send_key);
1461 PJ_UNUSED_ARG(sent);
1462 return PJ_TRUE;
1463}
1464
1465/* Notification when the status of the STUN transport has changed. */
1466static pj_bool_t stun_on_status(pj_stun_sock *stun_sock,
1467 pj_stun_sock_op op,
1468 pj_status_t status)
1469{
1470 pj_ice_strans_comp *comp;
1471 pj_ice_strans *ice_st;
1472 pj_ice_sess_cand *cand = NULL;
1473 unsigned i;
1474
1475 pj_assert(status != PJ_EPENDING);
1476
1477 comp = (pj_ice_strans_comp*) pj_stun_sock_get_user_data(stun_sock);
1478 ice_st = comp->ice_st;
1479
1480 pj_grp_lock_add_ref(ice_st->grp_lock);
1481
1482 /* Wait until initialization completes */
1483 pj_grp_lock_acquire(ice_st->grp_lock);
1484
1485 /* Find the srflx cancidate */
1486 for (i=0; i<comp->cand_cnt; ++i) {
1487 if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_SRFLX) {
1488 cand = &comp->cand_list[i];
1489 break;
1490 }
1491 }
1492
1493 pj_grp_lock_release(ice_st->grp_lock);
1494
1495 /* It is possible that we don't have srflx candidate even though this
1496 * callback is called. This could happen when we cancel adding srflx
1497 * candidate due to initialization error.
1498 */
1499 if (cand == NULL) {
1500 return pj_grp_lock_dec_ref(ice_st->grp_lock) ? PJ_FALSE : PJ_TRUE;
1501 }
1502
1503 switch (op) {
1504 case PJ_STUN_SOCK_DNS_OP:
1505 if (status != PJ_SUCCESS) {
1506 /* May not have cand, e.g. when error during init */
1507 if (cand)
1508 cand->status = status;
1509 if (!ice_st->cfg.stun.ignore_stun_error) {
1510 sess_fail(ice_st, PJ_ICE_STRANS_OP_INIT,
1511 "DNS resolution failed", status);
1512 } else {
1513 PJ_LOG(4,(ice_st->obj_name,
1514 "STUN error is ignored for comp %d",
1515 comp->comp_id));
1516 }
1517 }
1518 break;
1519 case PJ_STUN_SOCK_BINDING_OP:
1520 case PJ_STUN_SOCK_MAPPED_ADDR_CHANGE:
1521 if (status == PJ_SUCCESS) {
1522 pj_stun_sock_info info;
1523
1524 status = pj_stun_sock_get_info(stun_sock, &info);
1525 if (status == PJ_SUCCESS) {
1526 char ipaddr[PJ_INET6_ADDRSTRLEN+10];
1527 const char *op_name = (op==PJ_STUN_SOCK_BINDING_OP) ?
1528 "Binding discovery complete" :
1529 "srflx address changed";
1530 pj_bool_t dup = PJ_FALSE;
1531
1532 /* Eliminate the srflx candidate if the address is
1533 * equal to other (host) candidates.
1534 */
1535 for (i=0; i<comp->cand_cnt; ++i) {
1536 if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_HOST &&
1537 pj_sockaddr_cmp(&comp->cand_list[i].addr,
1538 &info.mapped_addr) == 0)
1539 {
1540 dup = PJ_TRUE;
1541 break;
1542 }
1543 }
1544
1545 if (dup) {
1546 /* Duplicate found, remove the srflx candidate */
1547 unsigned idx = (unsigned)(cand - comp->cand_list);
1548
1549 /* Update default candidate index */
1550 if (comp->default_cand > idx) {
1551 --comp->default_cand;
1552 } else if (comp->default_cand == idx) {
1553 comp->default_cand = 0;
1554 }
1555
1556 /* Remove srflx candidate */
1557 pj_array_erase(comp->cand_list, sizeof(comp->cand_list[0]),
1558 comp->cand_cnt, idx);
1559 --comp->cand_cnt;
1560 } else {
1561 /* Otherwise update the address */
1562 pj_sockaddr_cp(&cand->addr, &info.mapped_addr);
1563 cand->status = PJ_SUCCESS;
1564 }
1565
1566 PJ_LOG(4,(comp->ice_st->obj_name,
1567 "Comp %d: %s, "
1568 "srflx address is %s",
1569 comp->comp_id, op_name,
1570 pj_sockaddr_print(&info.mapped_addr, ipaddr,
1571 sizeof(ipaddr), 3)));
1572
1573 sess_init_update(ice_st);
1574 }
1575 }
1576
1577 if (status != PJ_SUCCESS) {
1578 /* May not have cand, e.g. when error during init */
1579 if (cand)
1580 cand->status = status;
1581 if (!ice_st->cfg.stun.ignore_stun_error || comp->cand_cnt==1) {
1582 sess_fail(ice_st, PJ_ICE_STRANS_OP_INIT,
1583 "STUN binding request failed", status);
1584 } else {
1585 PJ_LOG(4,(ice_st->obj_name,
1586 "STUN error is ignored for comp %d",
1587 comp->comp_id));
1588
1589 if (cand) {
1590 unsigned idx = (unsigned)(cand - comp->cand_list);
1591
1592 /* Update default candidate index */
1593 if (comp->default_cand == idx) {
1594 comp->default_cand = !idx;
1595 }
1596 }
1597
1598 sess_init_update(ice_st);
1599 }
1600 }
1601 break;
1602 case PJ_STUN_SOCK_KEEP_ALIVE_OP:
1603 if (status != PJ_SUCCESS) {
1604 pj_assert(cand != NULL);
1605 cand->status = status;
1606 if (!ice_st->cfg.stun.ignore_stun_error) {
1607 sess_fail(ice_st, PJ_ICE_STRANS_OP_INIT,
1608 "STUN keep-alive failed", status);
1609 } else {
1610 PJ_LOG(4,(ice_st->obj_name, "STUN error is ignored"));
1611 }
1612 }
1613 break;
1614 }
1615
1616 return pj_grp_lock_dec_ref(ice_st->grp_lock)? PJ_FALSE : PJ_TRUE;
1617}
1618
1619/* Callback when TURN socket has received a packet */
1620static void turn_on_rx_data(pj_turn_sock *turn_sock,
1621 void *pkt,
1622 unsigned pkt_len,
1623 const pj_sockaddr_t *peer_addr,
1624 unsigned addr_len)
1625{
1626 pj_ice_strans_comp *comp;
1627 pj_status_t status;
1628
1629 comp = (pj_ice_strans_comp*) pj_turn_sock_get_user_data(turn_sock);
1630 if (comp == NULL) {
1631 /* We have disassociated ourselves from the TURN socket */
1632 return;
1633 }
1634
1635 pj_grp_lock_add_ref(comp->ice_st->grp_lock);
1636
1637 if (comp->ice_st->ice == NULL) {
1638 /* The ICE session is gone, but we're still receiving packets.
1639 * This could also happen if remote doesn't do ICE and application
1640 * specifies TURN as the default address in SDP.
1641 * So in this case just give the packet to application.
1642 */
1643 if (comp->ice_st->cb.on_rx_data) {
1644 (*comp->ice_st->cb.on_rx_data)(comp->ice_st, comp->comp_id, pkt,
1645 pkt_len, peer_addr, addr_len);
1646 }
1647
1648 } else {
1649
1650 /* Hand over the packet to ICE */
1651 status = pj_ice_sess_on_rx_pkt(comp->ice_st->ice, comp->comp_id,
1652 TP_TURN, pkt, pkt_len,
1653 peer_addr, addr_len);
1654
1655 if (status != PJ_SUCCESS) {
1656 ice_st_perror(comp->ice_st,
1657 "Error processing packet from TURN relay",
1658 status);
1659 }
1660 }
1661
1662 pj_grp_lock_dec_ref(comp->ice_st->grp_lock);
1663}
1664
1665
1666/* Callback when TURN client state has changed */
1667static void turn_on_state(pj_turn_sock *turn_sock, pj_turn_state_t old_state,
1668 pj_turn_state_t new_state)
1669{
1670 pj_ice_strans_comp *comp;
1671
1672 comp = (pj_ice_strans_comp*) pj_turn_sock_get_user_data(turn_sock);
1673 if (comp == NULL) {
1674 /* Not interested in further state notification once the relay is
1675 * disconnecting.
1676 */
1677 return;
1678 }
1679
1680 PJ_LOG(5,(comp->ice_st->obj_name, "TURN client state changed %s --> %s",
1681 pj_turn_state_name(old_state), pj_turn_state_name(new_state)));
1682 pj_log_push_indent();
1683
1684 pj_grp_lock_add_ref(comp->ice_st->grp_lock);
1685
1686 if (new_state == PJ_TURN_STATE_READY) {
1687 pj_turn_session_info rel_info;
1688 char ipaddr[PJ_INET6_ADDRSTRLEN+8];
1689 pj_ice_sess_cand *cand = NULL;
1690 unsigned i;
1691
1692 comp->turn_err_cnt = 0;
1693
1694 /* Get allocation info */
1695 pj_turn_sock_get_info(turn_sock, &rel_info);
1696
1697 /* Wait until initialization completes */
1698 pj_grp_lock_acquire(comp->ice_st->grp_lock);
1699
1700 /* Find relayed candidate in the component */
1701 for (i=0; i<comp->cand_cnt; ++i) {
1702 if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_RELAYED) {
1703 cand = &comp->cand_list[i];
1704 break;
1705 }
1706 }
1707 pj_assert(cand != NULL);
1708
1709 pj_grp_lock_release(comp->ice_st->grp_lock);
1710
1711 /* Update candidate */
1712 pj_sockaddr_cp(&cand->addr, &rel_info.relay_addr);
1713 pj_sockaddr_cp(&cand->base_addr, &rel_info.relay_addr);
1714 pj_sockaddr_cp(&cand->rel_addr, &rel_info.mapped_addr);
1715 pj_ice_calc_foundation(comp->ice_st->pool, &cand->foundation,
1716 PJ_ICE_CAND_TYPE_RELAYED,
1717 &rel_info.relay_addr);
1718 cand->status = PJ_SUCCESS;
1719
1720 /* Set default candidate to relay */
1721 comp->default_cand = (unsigned)(cand - comp->cand_list);
1722
1723 PJ_LOG(4,(comp->ice_st->obj_name,
1724 "Comp %d: TURN allocation complete, relay address is %s",
1725 comp->comp_id,
1726 pj_sockaddr_print(&rel_info.relay_addr, ipaddr,
1727 sizeof(ipaddr), 3)));
1728
1729 sess_init_update(comp->ice_st);
1730
1731 } else if (new_state >= PJ_TURN_STATE_DEALLOCATING) {
1732 pj_turn_session_info info;
1733
1734 ++comp->turn_err_cnt;
1735
1736 pj_turn_sock_get_info(turn_sock, &info);
1737
1738 /* Unregister ourself from the TURN relay */
1739 pj_turn_sock_set_user_data(turn_sock, NULL);
1740 comp->turn_sock = NULL;
1741
1742 /* Set session to fail on error. last_status PJ_SUCCESS means normal
1743 * deallocation, which should not trigger sess_fail as it may have
1744 * been initiated by ICE destroy
1745 */
1746 if (info.last_status != PJ_SUCCESS) {
1747 if (comp->ice_st->state < PJ_ICE_STRANS_STATE_READY) {
1748 sess_fail(comp->ice_st, PJ_ICE_STRANS_OP_INIT,
1749 "TURN allocation failed", info.last_status);
1750 } else if (comp->turn_err_cnt > 1) {
1751 sess_fail(comp->ice_st, PJ_ICE_STRANS_OP_KEEP_ALIVE,
1752 "TURN refresh failed", info.last_status);
1753 } else {
1754 PJ_PERROR(4,(comp->ice_st->obj_name, info.last_status,
1755 "Comp %d: TURN allocation failed, retrying",
1756 comp->comp_id));
1757 add_update_turn(comp->ice_st, comp);
1758 }
1759 }
1760 }
1761
1762 pj_grp_lock_dec_ref(comp->ice_st->grp_lock);
1763
1764 pj_log_pop_indent();
1765}
1766