~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.0.1/pjnath/src/pjnath/ice_strans.c

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (1.1.11)
  • mto: This revision was merged to the branch mainline in revision 24.
  • Revision ID: package-import@ubuntu.com-20140128182336-3xenud1kbnwmf3mz
* New upstream release 
  - Fixes "New Upstream Release" (Closes: #735846)
  - Fixes "Ringtone does not stop" (Closes: #727164)
  - Fixes "[sflphone-kde] crash on startup" (Closes: #718178)
  - Fixes "sflphone GUI crashes when call is hung up" (Closes: #736583)
* Build-Depends: ensure GnuTLS 2.6
  - libucommon-dev (>= 6.0.7-1.1), libccrtp-dev (>= 2.0.6-3)
  - Fixes "FTBFS Build-Depends libgnutls{26,28}-dev" (Closes: #722040)
* Fix "boost 1.49 is going away" unversioned Build-Depends: (Closes: #736746)
* Add Build-Depends: libsndfile-dev, nepomuk-core-dev

Show diffs side-by-side

added added

removed removed

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