Ignore:
Timestamp:
Jun 6, 2008 2:47:10 PM (16 years ago)
Author:
bennylp
Message:

Major major modifications related to ticket #485 (support for TURN-07):

  • Added STUN socket transport pj_stun_sock
  • Integration of TURN-07 to ICE
  • Major refactoring in ICE stream transport to make it simpler
  • Major modification (i.e. API change) in almost everywhere else
  • Much more elaborate STUN, TURN, and ICE tests in pjnath-test
File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjnath/src/pjnath/ice_strans.c

    r1913 r1988  
    2020#include <pjnath/errno.h> 
    2121#include <pj/addr_resolv.h> 
     22#include <pj/array.h> 
    2223#include <pj/assert.h> 
    2324#include <pj/ip_helper.h> 
    2425#include <pj/log.h> 
     26#include <pj/os.h> 
    2527#include <pj/pool.h> 
    2628#include <pj/rand.h> 
     
    3638 
    3739 
     40/* Transport IDs */ 
     41enum tp_type 
     42{ 
     43    TP_NONE, 
     44    TP_STUN, 
     45    TP_TURN 
     46}; 
     47 
     48/* Candidate preference default values */ 
     49#define SRFLX_PREF  65535 
     50#define HOST_PREF   65530 
     51#define RELAY_PREF  65525 
     52 
    3853 
    3954/* ICE callbacks */ 
     
    4156static pj_status_t ice_tx_pkt(pj_ice_sess *ice,  
    4257                              unsigned comp_id, 
     58                              unsigned transport_id, 
    4359                              const void *pkt, pj_size_t size, 
    4460                              const pj_sockaddr_t *dst_addr, 
    4561                              unsigned dst_addr_len); 
    4662static void        ice_rx_data(pj_ice_sess *ice,  
    47                               unsigned comp_id,  
    48                               void *pkt, pj_size_t size, 
    49                               const pj_sockaddr_t *src_addr, 
    50                               unsigned src_addr_len); 
    51  
    52 /* Ioqueue callback */ 
    53 static void on_read_complete(pj_ioqueue_key_t *key,  
    54                              pj_ioqueue_op_key_t *op_key,  
    55                              pj_ssize_t bytes_read); 
    56  
    57 static void destroy_component(pj_ice_strans_comp *comp); 
    58 static void destroy_ice_st(pj_ice_strans *ice_st, pj_status_t reason); 
    59  
    60  
    61 /* STUN session callback */ 
    62 static pj_status_t stun_on_send_msg(pj_stun_session *sess, 
    63                                     void *token, 
    64                                     const void *pkt, 
    65                                     pj_size_t pkt_size, 
    66                                     const pj_sockaddr_t *dst_addr, 
    67                                     unsigned addr_len); 
    68 static void stun_on_request_complete(pj_stun_session *sess, 
    69                                      pj_status_t status, 
    70                                      void *token, 
    71                                      pj_stun_tx_data *tdata, 
    72                                      const pj_stun_msg *response, 
    73                                      const pj_sockaddr_t *src_addr, 
    74                                      unsigned src_addr_len); 
    75  
    76 /* Keep-alive timer */ 
    77 static void start_ka_timer(pj_ice_strans *ice_st); 
    78 static void stop_ka_timer(pj_ice_strans *ice_st); 
    79  
    80 /* Utility: print error */ 
     63                               unsigned comp_id,  
     64                               unsigned transport_id, 
     65                               void *pkt, pj_size_t size, 
     66                               const pj_sockaddr_t *src_addr, 
     67                               unsigned src_addr_len); 
     68 
     69 
     70/* STUN socket callbacks */ 
     71/* Notification when incoming packet has been received. */ 
     72static pj_bool_t stun_on_rx_data(pj_stun_sock *stun_sock, 
     73                                 void *pkt, 
     74                                 unsigned pkt_len, 
     75                                 const pj_sockaddr_t *src_addr, 
     76                                 unsigned addr_len); 
     77/* Notifification when asynchronous send operation has completed. */ 
     78static pj_bool_t stun_on_data_sent(pj_stun_sock *stun_sock, 
     79                                   pj_ioqueue_op_key_t *send_key, 
     80                                   pj_ssize_t sent); 
     81/* Notification when the status of the STUN transport has changed. */ 
     82static pj_bool_t stun_on_status(pj_stun_sock *stun_sock,  
     83                                pj_stun_sock_op op, 
     84                                pj_status_t status); 
     85 
     86 
     87/* TURN callbacks */ 
     88static void turn_on_rx_data(pj_turn_sock *turn_sock, 
     89                            void *pkt, 
     90                            unsigned pkt_len, 
     91                            const pj_sockaddr_t *peer_addr, 
     92                            unsigned addr_len); 
     93static void turn_on_state(pj_turn_sock *turn_sock, pj_turn_state_t old_state, 
     94                          pj_turn_state_t new_state); 
     95 
     96 
     97 
     98/* Forward decls */ 
     99static void destroy_ice_st(pj_ice_strans *ice_st); 
    81100#define ice_st_perror(ice_st,msg,rc) pjnath_perror(ice_st->obj_name,msg,rc) 
     101static void sess_init_update(pj_ice_strans *ice_st); 
     102 
     103static void sess_add_ref(pj_ice_strans *ice_st); 
     104static pj_bool_t sess_dec_ref(pj_ice_strans *ice_st); 
     105 
     106/** 
     107 * This structure describes an ICE stream transport component. A component 
     108 * in ICE stream transport typically corresponds to a single socket created 
     109 * for this component, and bound to a specific transport address. This 
     110 * component may have multiple alias addresses, for example one alias  
     111 * address for each interfaces in multi-homed host, another for server 
     112 * reflexive alias, and another for relayed alias. For each transport 
     113 * address alias, an ICE stream transport candidate (#pj_ice_sess_cand) will 
     114 * be created, and these candidates will eventually registered to the ICE 
     115 * session. 
     116 */ 
     117typedef struct pj_ice_strans_comp 
     118{ 
     119    pj_ice_strans       *ice_st;        /**< ICE stream transport.      */ 
     120    unsigned             comp_id;       /**< Component ID.              */ 
     121 
     122    pj_stun_sock        *stun_sock;     /**< STUN transport.            */ 
     123    pj_turn_sock        *turn_sock;     /**< TURN relay transport.      */ 
     124 
     125    unsigned             cand_cnt;      /**< # of candidates/aliaes.    */ 
     126    pj_ice_sess_cand     cand_list[PJ_ICE_ST_MAX_CAND]; /**< Cand array */ 
     127 
     128    unsigned             default_cand;  /**< Default candidate.         */ 
     129 
     130} pj_ice_strans_comp; 
     131 
     132 
     133/** 
     134 * This structure represents the ICE stream transport. 
     135 */ 
     136struct pj_ice_strans 
     137{ 
     138    char                    *obj_name;  /**< Log ID.                    */ 
     139    pj_pool_t               *pool;      /**< Pool used by this object.  */ 
     140    void                    *user_data; /**< Application data.          */ 
     141    pj_ice_strans_cfg        cfg;       /**< Configuration.             */ 
     142    pj_ice_strans_cb         cb;        /**< Application callback.      */ 
     143 
     144    pj_ice_sess             *ice;       /**< ICE session.               */ 
     145    pj_time_val              start_time;/**< Time when ICE was started  */ 
     146 
     147    unsigned                 comp_cnt;  /**< Number of components.      */ 
     148    pj_ice_strans_comp     **comp;      /**< Components array.          */ 
     149 
     150    pj_timer_entry           ka_timer;  /**< STUN keep-alive timer.     */ 
     151 
     152    pj_atomic_t             *busy_cnt;  /**< To prevent destroy         */ 
     153    pj_bool_t                destroy_req;/**< Destroy has been called?  */ 
     154    pj_bool_t                cb_called; /**< Init error callback called?*/ 
     155}; 
     156 
     157 
     158/* Validate configuration */ 
     159static pj_status_t pj_ice_strans_cfg_check_valid(const pj_ice_strans_cfg *cfg) 
     160{ 
     161    pj_status_t status; 
     162 
     163    status = pj_stun_config_check_valid(&cfg->stun_cfg); 
     164    if (!status) 
     165        return status; 
     166 
     167    return PJ_SUCCESS; 
     168} 
     169 
     170 
     171/* 
     172 * Initialize ICE transport configuration with default values. 
     173 */ 
     174PJ_DEF(void) pj_ice_strans_cfg_default(pj_ice_strans_cfg *cfg) 
     175{ 
     176    pj_bzero(cfg, sizeof(*cfg)); 
     177 
     178    pj_stun_config_init(&cfg->stun_cfg, NULL, 0, NULL, NULL); 
     179    pj_stun_sock_cfg_default(&cfg->stun.cfg); 
     180    pj_turn_alloc_param_default(&cfg->turn.alloc_param); 
     181 
     182    cfg->af = pj_AF_INET(); 
     183    cfg->stun.port = PJ_STUN_PORT; 
     184    cfg->turn.conn_type = PJ_TURN_TP_UDP; 
     185} 
     186 
     187 
     188/* 
     189 * Copy configuration. 
     190 */ 
     191PJ_DEF(void) pj_ice_strans_cfg_copy( pj_pool_t *pool, 
     192                                     pj_ice_strans_cfg *dst, 
     193                                     const pj_ice_strans_cfg *src) 
     194{ 
     195    pj_memcpy(dst, src, sizeof(*src)); 
     196 
     197    if (src->stun.server.slen) 
     198        pj_strdup(pool, &dst->stun.server, &src->stun.server); 
     199    if (src->turn.server.slen) 
     200        pj_strdup(pool, &dst->turn.server, &src->turn.server); 
     201    pj_stun_auth_cred_dup(pool, &dst->turn.auth_cred, 
     202                          &src->turn.auth_cred); 
     203} 
     204 
     205/* 
     206 * Create the component. 
     207 */ 
     208static pj_status_t create_comp(pj_ice_strans *ice_st, unsigned comp_id) 
     209{ 
     210    pj_ice_strans_comp *comp = NULL; 
     211    pj_status_t status; 
     212 
     213    /* Verify arguments */ 
     214    PJ_ASSERT_RETURN(ice_st && comp_id, PJ_EINVAL); 
     215 
     216    /* Check that component ID present */ 
     217    PJ_ASSERT_RETURN(comp_id <= ice_st->comp_cnt, PJNATH_EICEINCOMPID); 
     218 
     219    /* Create component */ 
     220    comp = PJ_POOL_ZALLOC_T(ice_st->pool, pj_ice_strans_comp); 
     221    comp->ice_st = ice_st; 
     222    comp->comp_id = comp_id; 
     223 
     224    ice_st->comp[comp_id-1] = comp; 
     225 
     226    /* Initialize default candidate */ 
     227    comp->default_cand = 0; 
     228 
     229    /* Create STUN transport if configured */ 
     230    if (ice_st->cfg.stun.server.slen || !ice_st->cfg.stun.no_host_cands) { 
     231        pj_stun_sock_cb stun_sock_cb; 
     232        pj_ice_sess_cand *cand; 
     233 
     234        pj_bzero(&stun_sock_cb, sizeof(stun_sock_cb)); 
     235        stun_sock_cb.on_rx_data = &stun_on_rx_data; 
     236        stun_sock_cb.on_status = &stun_on_status; 
     237        stun_sock_cb.on_data_sent = &stun_on_data_sent; 
     238         
     239        /* Create the STUN transport */ 
     240        status = pj_stun_sock_create(&ice_st->cfg.stun_cfg, NULL, 
     241                                     ice_st->cfg.af, &stun_sock_cb, 
     242                                     &ice_st->cfg.stun.cfg, 
     243                                     comp, &comp->stun_sock); 
     244        if (status != PJ_SUCCESS) 
     245            return status; 
     246 
     247        /* Start STUN Binding resolution and add srflx candidate  
     248         * only if server is set  
     249         */ 
     250        if (ice_st->cfg.stun.server.slen) { 
     251            pj_stun_sock_info stun_sock_info; 
     252 
     253            /* Add pending job */ 
     254            ///sess_add_ref(ice_st); 
     255 
     256            /* Start Binding resolution */ 
     257            status = pj_stun_sock_start(comp->stun_sock,  
     258                                        &ice_st->cfg.stun.server, 
     259                                        ice_st->cfg.stun.port,  
     260                                        ice_st->cfg.resolver); 
     261            if (status != PJ_SUCCESS) { 
     262                ///sess_dec_ref(ice_st); 
     263                return status; 
     264            } 
     265 
     266            /* Enumerate addresses */ 
     267            status = pj_stun_sock_get_info(comp->stun_sock, &stun_sock_info); 
     268            if (status != PJ_SUCCESS) { 
     269                ///sess_dec_ref(ice_st); 
     270                return status; 
     271            } 
     272 
     273            /* Add srflx candidate with pending status */ 
     274            cand = &comp->cand_list[comp->cand_cnt++]; 
     275            cand->type = PJ_ICE_CAND_TYPE_SRFLX; 
     276            cand->status = PJ_EPENDING; 
     277            cand->local_pref = SRFLX_PREF; 
     278            cand->transport_id = TP_STUN; 
     279            cand->comp_id = (pj_uint8_t) comp_id; 
     280            pj_sockaddr_cp(&cand->base_addr, &stun_sock_info.aliases[0]); 
     281            pj_sockaddr_cp(&cand->rel_addr, &cand->base_addr); 
     282            pj_ice_calc_foundation(ice_st->pool, &cand->foundation, 
     283                                   cand->type, &cand->base_addr); 
     284            PJ_LOG(4,(ice_st->obj_name,  
     285                      "Comp %d: srflx candidate starts Binding discovery", 
     286                      comp_id)); 
     287 
     288            /* Set default candidate to srflx */ 
     289            comp->default_cand = cand - comp->cand_list; 
     290        } 
     291 
     292        /* Add local addresses to host candidates, unless no_host_cands 
     293         * flag is set. 
     294         */ 
     295        if (ice_st->cfg.stun.no_host_cands == PJ_FALSE) { 
     296            pj_stun_sock_info stun_sock_info; 
     297            unsigned i; 
     298 
     299            /* Enumerate addresses */ 
     300            status = pj_stun_sock_get_info(comp->stun_sock, &stun_sock_info); 
     301            if (status != PJ_SUCCESS) 
     302                return status; 
     303 
     304            for (i=0; i<stun_sock_info.alias_cnt; ++i) { 
     305                char addrinfo[PJ_INET6_ADDRSTRLEN+10]; 
     306                const pj_sockaddr *addr = &stun_sock_info.aliases[i]; 
     307 
     308                /* Leave one candidate for relay */ 
     309                if (comp->cand_cnt >= PJ_ICE_ST_MAX_CAND-1) { 
     310                    PJ_LOG(4,(ice_st->obj_name, "Too many host candidates")); 
     311                    break; 
     312                } 
     313 
     314                /* Ignore loopback addresses unless cfg->stun.loop_addr  
     315                 * is set  
     316                 */ 
     317                if ((pj_ntohl(addr->ipv4.sin_addr.s_addr)>>24)==127) { 
     318                    if (ice_st->cfg.stun.loop_addr==PJ_FALSE) 
     319                        continue; 
     320                } 
     321 
     322                cand = &comp->cand_list[comp->cand_cnt++]; 
     323 
     324                cand->type = PJ_ICE_CAND_TYPE_HOST; 
     325                cand->status = PJ_SUCCESS; 
     326                cand->local_pref = HOST_PREF; 
     327                cand->transport_id = TP_STUN; 
     328                cand->comp_id = (pj_uint8_t) comp_id; 
     329                pj_sockaddr_cp(&cand->addr, addr); 
     330                pj_sockaddr_cp(&cand->base_addr, addr); 
     331                pj_bzero(&cand->rel_addr, sizeof(cand->rel_addr)); 
     332                pj_ice_calc_foundation(ice_st->pool, &cand->foundation, 
     333                                       cand->type, &cand->base_addr); 
     334 
     335                PJ_LOG(4,(ice_st->obj_name,  
     336                          "Comp %d: host candidate %s added", 
     337                          comp_id, pj_sockaddr_print(&cand->addr, addrinfo, 
     338                                                     sizeof(addrinfo), 3))); 
     339            } 
     340        } 
     341    } 
     342 
     343    /* Create TURN relay if configured. */ 
     344    if (ice_st->cfg.turn.server.slen) { 
     345        pj_turn_sock_cb turn_sock_cb; 
     346        pj_ice_sess_cand *cand; 
     347 
     348        /* Init TURN socket */ 
     349        pj_bzero(&turn_sock_cb, sizeof(turn_sock_cb)); 
     350        turn_sock_cb.on_rx_data = &turn_on_rx_data; 
     351        turn_sock_cb.on_state = &turn_on_state; 
     352 
     353        status = pj_turn_sock_create(&ice_st->cfg.stun_cfg, ice_st->cfg.af, 
     354                                     ice_st->cfg.turn.conn_type, 
     355                                     &turn_sock_cb, 0, comp,  
     356                                     &comp->turn_sock); 
     357        if (status != PJ_SUCCESS) { 
     358            return status; 
     359        } 
     360 
     361        /* Add pending job */ 
     362        ///sess_add_ref(ice_st); 
     363 
     364        /* Start allocation */ 
     365        status=pj_turn_sock_alloc(comp->turn_sock,   
     366                                  &ice_st->cfg.turn.server, 
     367                                  ice_st->cfg.turn.port, 
     368                                  ice_st->cfg.resolver,  
     369                                  &ice_st->cfg.turn.auth_cred,  
     370                                  &ice_st->cfg.turn.alloc_param); 
     371        if (status != PJ_SUCCESS) { 
     372            ///sess_dec_ref(ice_st); 
     373            return status; 
     374        } 
     375 
     376        /* Add relayed candidate with pending status */ 
     377        cand = &comp->cand_list[comp->cand_cnt++]; 
     378        cand->type = PJ_ICE_CAND_TYPE_RELAYED; 
     379        cand->status = PJ_EPENDING; 
     380        cand->local_pref = RELAY_PREF; 
     381        cand->transport_id = TP_TURN; 
     382        cand->comp_id = (pj_uint8_t) comp_id; 
     383 
     384        PJ_LOG(4,(ice_st->obj_name,  
     385                      "Comp %d: TURN relay candidate waiting for allocation", 
     386                      comp_id)); 
     387 
     388        /* Set default candidate to relay */ 
     389        comp->default_cand = cand - comp->cand_list; 
     390    } 
     391 
     392    return PJ_SUCCESS; 
     393} 
     394 
    82395 
    83396/*  
    84397 * Create ICE stream transport  
    85398 */ 
    86 PJ_DEF(pj_status_t) pj_ice_strans_create( pj_stun_config *stun_cfg, 
    87                                           const char *name, 
     399PJ_DEF(pj_status_t) pj_ice_strans_create( const char *name, 
     400                                          const pj_ice_strans_cfg *cfg, 
    88401                                          unsigned comp_cnt, 
    89402                                          void *user_data, 
     
    93406    pj_pool_t *pool; 
    94407    pj_ice_strans *ice_st; 
    95  
    96     PJ_ASSERT_RETURN(stun_cfg && comp_cnt && cb && p_ice_st, PJ_EINVAL); 
    97     PJ_ASSERT_RETURN(stun_cfg->ioqueue && stun_cfg->timer_heap, PJ_EINVAL); 
     408    unsigned i; 
     409    pj_status_t status; 
     410 
     411    status = pj_ice_strans_cfg_check_valid(cfg); 
     412    if (status != PJ_SUCCESS) 
     413        return status; 
     414 
     415    PJ_ASSERT_RETURN(comp_cnt && cb && p_ice_st, PJ_EINVAL); 
    98416 
    99417    if (name == NULL) 
    100         name = "icstr%p"; 
    101  
    102     pool = pj_pool_create(stun_cfg->pf, name, PJNATH_POOL_LEN_ICE_STRANS,  
     418        name = "ice%p"; 
     419 
     420    pool = pj_pool_create(cfg->stun_cfg.pf, name, PJNATH_POOL_LEN_ICE_STRANS, 
    103421                          PJNATH_POOL_INC_ICE_STRANS, NULL); 
    104422    ice_st = PJ_POOL_ZALLOC_T(pool, pj_ice_strans); 
    105423    ice_st->pool = pool; 
    106     pj_memcpy(ice_st->obj_name, pool->obj_name, PJ_MAX_OBJ_NAME); 
     424    ice_st->obj_name = pool->obj_name; 
    107425    ice_st->user_data = user_data; 
     426 
     427    PJ_LOG(4,(ice_st->obj_name,  
     428              "Creating ICE stream transport with %d component(s)", 
     429              comp_cnt)); 
     430 
     431    pj_ice_strans_cfg_copy(pool, &ice_st->cfg, cfg); 
     432    pj_memcpy(&ice_st->cb, cb, sizeof(*cb)); 
    108433     
     434    status = pj_atomic_create(pool, 0, &ice_st->busy_cnt); 
     435    if (status != PJ_SUCCESS) { 
     436        destroy_ice_st(ice_st); 
     437        return status; 
     438    } 
     439 
    109440    ice_st->comp_cnt = comp_cnt; 
    110     ice_st->comp = (pj_ice_strans_comp**) pj_pool_calloc(pool, comp_cnt,  
    111                                                      sizeof(void*)); 
    112  
    113     pj_memcpy(&ice_st->cb, cb, sizeof(*cb)); 
    114     pj_memcpy(&ice_st->stun_cfg, stun_cfg, sizeof(*stun_cfg)); 
    115  
     441    ice_st->comp = (pj_ice_strans_comp**)  
     442                   pj_pool_calloc(pool, comp_cnt, sizeof(pj_ice_strans_comp*)); 
     443 
     444    for (i=0; i<comp_cnt; ++i) { 
     445        status = create_comp(ice_st, i+1); 
     446        if (status != PJ_SUCCESS) { 
     447            destroy_ice_st(ice_st); 
     448            return status; 
     449        } 
     450    } 
     451 
     452    /* Check if all candidates are ready (this may call callback) */ 
     453    sess_init_update(ice_st); 
    116454 
    117455    PJ_LOG(4,(ice_st->obj_name, "ICE stream transport created")); 
     
    122460 
    123461/* Destroy ICE */ 
    124 static void destroy_ice_st(pj_ice_strans *ice_st, pj_status_t reason) 
     462static void destroy_ice_st(pj_ice_strans *ice_st) 
    125463{ 
    126464    unsigned i; 
    127     char obj_name[PJ_MAX_OBJ_NAME]; 
    128  
    129     if (reason == PJ_SUCCESS) { 
    130         pj_memcpy(obj_name, ice_st->obj_name, PJ_MAX_OBJ_NAME); 
    131         PJ_LOG(4,(obj_name, "ICE stream transport shutting down")); 
    132     } 
    133  
    134     /* Kill keep-alive timer, if any */ 
    135     stop_ka_timer(ice_st); 
    136465 
    137466    /* Destroy ICE if we have ICE */ 
     
    144473    for (i=0; i<ice_st->comp_cnt; ++i) { 
    145474        if (ice_st->comp[i]) { 
    146             destroy_component(ice_st->comp[i]); 
    147             ice_st->comp[i] = NULL; 
     475            if (ice_st->comp[i]->stun_sock) { 
     476                pj_stun_sock_set_user_data(ice_st->comp[i]->stun_sock, NULL); 
     477                pj_stun_sock_destroy(ice_st->comp[i]->stun_sock); 
     478                ice_st->comp[i]->stun_sock = NULL; 
     479            } 
     480            if (ice_st->comp[i]->turn_sock) { 
     481                pj_turn_sock_set_user_data(ice_st->comp[i]->turn_sock, NULL); 
     482                pj_turn_sock_destroy(ice_st->comp[i]->turn_sock); 
     483                ice_st->comp[i]->turn_sock = NULL; 
     484            } 
    148485        } 
    149486    } 
    150487    ice_st->comp_cnt = 0; 
     488 
     489    /* Destroy reference counter */ 
     490    if (ice_st->busy_cnt) { 
     491        pj_assert(pj_atomic_get(ice_st->busy_cnt)==0); 
     492        pj_atomic_destroy(ice_st->busy_cnt); 
     493        ice_st->busy_cnt = NULL; 
     494    } 
    151495 
    152496    /* Done */ 
    153497    pj_pool_release(ice_st->pool); 
    154  
    155     if (reason == PJ_SUCCESS) { 
    156         PJ_LOG(4,(obj_name, "ICE stream transport destroyed")); 
    157     } 
     498} 
     499 
     500/* Notification about failure */ 
     501static void sess_fail(pj_ice_strans *ice_st, pj_ice_strans_op op, 
     502                      const char *title, pj_status_t status) 
     503{ 
     504    char errmsg[PJ_ERR_MSG_SIZE]; 
     505 
     506    pj_strerror(status, errmsg, sizeof(errmsg)); 
     507    PJ_LOG(4,(ice_st->obj_name, "%s: %s", title, errmsg)); 
     508 
     509    if (op==PJ_ICE_STRANS_OP_INIT && ice_st->cb_called) 
     510        return; 
     511 
     512    ice_st->cb_called = PJ_TRUE; 
     513 
     514    if (ice_st->cb.on_ice_complete) 
     515        (*ice_st->cb.on_ice_complete)(ice_st, op, status); 
     516} 
     517 
     518/* Update initialization status */ 
     519static void sess_init_update(pj_ice_strans *ice_st) 
     520{ 
     521    unsigned i; 
     522 
     523    /* Ignore if init callback has been called */ 
     524    if (ice_st->cb_called) 
     525        return; 
     526 
     527    /* Notify application when all candidates have been gathered */ 
     528    for (i=0; i<ice_st->comp_cnt; ++i) { 
     529        unsigned j; 
     530        pj_ice_strans_comp *comp = ice_st->comp[i]; 
     531 
     532        for (j=0; j<comp->cand_cnt; ++j) { 
     533            pj_ice_sess_cand *cand = &comp->cand_list[j]; 
     534 
     535            if (cand->status == PJ_EPENDING) 
     536                return; 
     537        } 
     538    } 
     539 
     540    /* All candidates have been gathered */ 
     541    ice_st->cb_called = PJ_TRUE; 
     542    if (ice_st->cb.on_ice_complete) 
     543        (*ice_st->cb.on_ice_complete)(ice_st, PJ_ICE_STRANS_OP_INIT,  
     544                                      PJ_SUCCESS); 
    158545} 
    159546 
     
    163550PJ_DEF(pj_status_t) pj_ice_strans_destroy(pj_ice_strans *ice_st) 
    164551{ 
    165     destroy_ice_st(ice_st, PJ_SUCCESS); 
     552    char obj_name[PJ_MAX_OBJ_NAME]; 
     553 
     554    PJ_ASSERT_RETURN(ice_st, PJ_EINVAL); 
     555 
     556    ice_st->destroy_req = PJ_TRUE; 
     557    if (pj_atomic_get(ice_st->busy_cnt) > 0) { 
     558        PJ_LOG(5,(ice_st->obj_name,  
     559                  "ICE strans object is busy, will destroy later")); 
     560        return PJ_EPENDING; 
     561    } 
     562     
     563    pj_memcpy(obj_name, ice_st->obj_name, PJ_MAX_OBJ_NAME); 
     564    destroy_ice_st(ice_st); 
     565 
     566    PJ_LOG(4,(obj_name, "ICE stream transport destroyed")); 
    166567    return PJ_SUCCESS; 
    167568} 
    168569 
    169 /* 
    170  * Resolve STUN server 
    171  */ 
    172 PJ_DEF(pj_status_t) pj_ice_strans_set_stun_domain(pj_ice_strans *ice_st, 
    173                                                   pj_dns_resolver *resolver, 
    174                                                   const pj_str_t *domain) 
    175 { 
    176     /* Yeah, TODO */ 
    177     PJ_UNUSED_ARG(ice_st); 
    178     PJ_UNUSED_ARG(resolver); 
    179     PJ_UNUSED_ARG(domain); 
    180     return -1; 
    181 } 
    182  
    183 /* 
    184  * Set STUN server address. 
    185  */ 
    186 PJ_DEF(pj_status_t) pj_ice_strans_set_stun_srv( pj_ice_strans *ice_st, 
    187                                                 const pj_sockaddr_in *stun_srv, 
    188                                                 const pj_sockaddr_in *turn_srv) 
    189 { 
    190     PJ_ASSERT_RETURN(ice_st, PJ_EINVAL); 
    191     /* Must not have pending resolver job */ 
    192     PJ_ASSERT_RETURN(ice_st->has_rjob==PJ_FALSE, PJ_EINVALIDOP); 
    193  
    194     if (stun_srv) { 
    195         pj_memcpy(&ice_st->stun_srv, stun_srv, sizeof(pj_sockaddr_in)); 
     570 
     571/* 
     572 * Increment busy counter. 
     573 */ 
     574static void sess_add_ref(pj_ice_strans *ice_st) 
     575{ 
     576    pj_atomic_inc(ice_st->busy_cnt); 
     577} 
     578 
     579/* 
     580 * Decrement busy counter. If the counter has reached zero and destroy 
     581 * has been requested, destroy the object and return FALSE. 
     582 */ 
     583static pj_bool_t sess_dec_ref(pj_ice_strans *ice_st) 
     584{ 
     585    int count = pj_atomic_dec_and_get(ice_st->busy_cnt); 
     586    pj_assert(count >= 0); 
     587    if (count==0 && ice_st->destroy_req) { 
     588        pj_ice_strans_destroy(ice_st); 
     589        return PJ_FALSE; 
    196590    } else { 
    197         pj_bzero(&ice_st->stun_srv, sizeof(pj_sockaddr_in)); 
    198     } 
    199  
    200     if (turn_srv) { 
    201         pj_memcpy(&ice_st->turn_srv, turn_srv, sizeof(pj_sockaddr_in)); 
    202     } else { 
    203         pj_bzero(&ice_st->turn_srv, sizeof(pj_sockaddr_in)); 
    204     } 
    205  
    206     return PJ_SUCCESS; 
    207 } 
    208  
    209 /* Add new candidate */ 
    210 static pj_status_t add_cand( pj_ice_strans *ice_st, 
    211                              pj_ice_strans_comp *comp, 
    212                              unsigned comp_id, 
    213                              pj_ice_cand_type type, 
    214                              pj_uint16_t local_pref, 
    215                              const pj_sockaddr_in *addr, 
    216                              pj_bool_t set_default) 
    217 { 
    218     pj_ice_strans_cand *cand; 
    219     unsigned i; 
    220  
    221     PJ_ASSERT_RETURN(ice_st && comp && addr, PJ_EINVAL); 
    222     PJ_ASSERT_RETURN(comp->cand_cnt < PJ_ICE_ST_MAX_CAND, PJ_ETOOMANY); 
    223  
    224     /* Check that we don't have candidate with the same 
    225      * address. 
    226      */ 
    227     for (i=0; i<comp->cand_cnt; ++i) { 
    228         if (pj_memcmp(addr, &comp->cand_list[i].addr,  
    229                       sizeof(pj_sockaddr_in))==0) 
    230         { 
    231             /* Duplicate */ 
    232             PJ_LOG(5,(ice_st->obj_name, "Duplicate candidate not added")); 
    233             return PJ_SUCCESS; 
    234         } 
    235     } 
    236  
    237     cand = &comp->cand_list[comp->cand_cnt]; 
    238  
    239     pj_bzero(cand, sizeof(*cand)); 
    240     cand->type = type; 
    241     cand->status = PJ_SUCCESS; 
    242     pj_memcpy(&cand->addr, addr, sizeof(pj_sockaddr_in)); 
    243     cand->ice_cand_id = -1; 
    244     cand->local_pref = local_pref; 
    245     pj_ice_calc_foundation(ice_st->pool, &cand->foundation, type,  
    246                            &comp->local_addr); 
    247  
    248     if (set_default)  
    249         comp->default_cand = comp->cand_cnt; 
    250  
    251     PJ_LOG(5,(ice_st->obj_name,  
    252               "Candidate %s:%d (type=%s) added to component %d", 
    253               pj_inet_ntoa(addr->sin_addr), 
    254               (int)pj_ntohs(addr->sin_port),  
    255               pj_ice_get_cand_type_name(type), 
    256               comp_id)); 
    257      
    258     comp->cand_cnt++; 
    259     return PJ_SUCCESS; 
    260 } 
    261  
    262 /*  Create new component (i.e. socket)  */ 
    263 static pj_status_t create_component(pj_ice_strans *ice_st, 
    264                                     unsigned comp_id, 
    265                                     pj_uint32_t options, 
    266                                     const pj_sockaddr_in *addr, 
    267                                     pj_ice_strans_comp **p_comp) 
    268 { 
    269     enum { MAX_RETRY=100, PORT_INC=2 }; 
    270     pj_ioqueue_callback ioqueue_cb; 
    271     pj_ice_strans_comp *comp; 
    272     int retry, addr_len; 
    273     struct { 
    274         pj_uint32_t a1, a2, a3; 
    275     } tsx_id; 
    276     pj_status_t status; 
    277  
    278     comp = PJ_POOL_ZALLOC_T(ice_st->pool, pj_ice_strans_comp); 
    279     comp->ice_st = ice_st; 
    280     comp->comp_id = comp_id; 
    281     comp->options = options; 
    282     comp->sock = PJ_INVALID_SOCKET; 
    283     comp->last_status = PJ_SUCCESS; 
    284  
    285     /* Create transaction ID for STUN keep alives */ 
    286     tsx_id.a1 = 0; 
    287     tsx_id.a2 = comp_id; 
    288     tsx_id.a3 = (pj_uint32_t) (unsigned long) ice_st; 
    289     pj_memcpy(comp->ka_tsx_id, &tsx_id, sizeof(comp->ka_tsx_id)); 
    290  
    291     /* Create socket */ 
    292     status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &comp->sock); 
    293     if (status != PJ_SUCCESS) 
    294         return status; 
    295  
    296     /* Init address */ 
    297     if (addr)  
    298         pj_memcpy(&comp->local_addr, addr, sizeof(pj_sockaddr_in)); 
    299     else  
    300         pj_sockaddr_in_init(&comp->local_addr.ipv4, NULL, 0); 
    301  
    302     /* Retry binding socket */ 
    303     for (retry=0; retry<MAX_RETRY; ++retry) { 
    304         pj_uint16_t port; 
    305  
    306         status = pj_sock_bind(comp->sock, &comp->local_addr,  
    307                               sizeof(pj_sockaddr_in)); 
    308         if (status == PJ_SUCCESS) 
    309             break; 
    310  
    311         if (options & PJ_ICE_ST_OPT_NO_PORT_RETRY) 
    312             goto on_error; 
    313  
    314         port = pj_ntohs(comp->local_addr.ipv4.sin_port); 
    315         port += PORT_INC; 
    316         comp->local_addr.ipv4.sin_port = pj_htons(port); 
    317     } 
    318  
    319     /* Get the actual port where the socket is bound to. 
    320      * (don't care about the address, it will be retrieved later) 
    321      */ 
    322     addr_len = sizeof(comp->local_addr); 
    323     status = pj_sock_getsockname(comp->sock, &comp->local_addr, &addr_len); 
    324     if (status != PJ_SUCCESS) 
    325         goto on_error; 
    326  
    327     /* Register to ioqueue */ 
    328     pj_bzero(&ioqueue_cb, sizeof(ioqueue_cb)); 
    329     ioqueue_cb.on_read_complete = &on_read_complete; 
    330     status = pj_ioqueue_register_sock(ice_st->pool, ice_st->stun_cfg.ioqueue,  
    331                                       comp->sock, comp, &ioqueue_cb,  
    332                                       &comp->key); 
    333     if (status != PJ_SUCCESS) 
    334         goto on_error; 
    335  
    336     /* Disable concurrency */ 
    337     status = pj_ioqueue_set_concurrency(comp->key, PJ_FALSE); 
    338     if (status != PJ_SUCCESS) 
    339         goto on_error; 
    340  
    341     pj_ioqueue_op_key_init(&comp->read_op, sizeof(comp->read_op)); 
    342     pj_ioqueue_op_key_init(&comp->write_op, sizeof(comp->write_op)); 
    343  
    344     /* Kick start reading the socket */ 
    345     on_read_complete(comp->key, &comp->read_op, 0); 
    346  
    347     /* If the socket is bound to INADDR_ANY, then lookup all interfaces in 
    348      * the host and add them into cand_list. Otherwise if the socket is bound 
    349      * to a specific interface, then only add that specific interface to 
    350      * cand_list. 
    351      */ 
    352     if (((options & PJ_ICE_ST_OPT_DONT_ADD_CAND)==0) && 
    353         comp->local_addr.ipv4.sin_addr.s_addr == 0)  
    354     { 
    355         /* Socket is bound to INADDR_ANY */ 
    356         unsigned i, ifs_cnt; 
    357         pj_sockaddr ifs[PJ_ICE_ST_MAX_CAND-2]; 
    358  
    359         /* Reset default candidate */ 
    360         comp->default_cand = -1; 
    361  
    362         /* Enum all IP interfaces in the host */ 
    363         ifs_cnt = PJ_ARRAY_SIZE(ifs); 
    364         status = pj_enum_ip_interface(pj_AF_INET(), &ifs_cnt, ifs); 
    365         if (status != PJ_SUCCESS) 
    366             goto on_error; 
    367  
    368         /* Set default IP interface as the base address */ 
    369         status = pj_gethostip(pj_AF_INET(), &comp->local_addr); 
    370         if (status != PJ_SUCCESS) 
    371             goto on_error; 
    372  
    373         /* Add candidate entry for each interface */ 
    374         for (i=0; i<ifs_cnt; ++i) { 
    375             pj_sockaddr_in cand_addr; 
    376             pj_bool_t set_default; 
    377             pj_uint16_t local_pref; 
    378  
    379             /* Ignore 127.0.0.0/24 address */ 
    380             if ((pj_ntohl(ifs[i].ipv4.sin_addr.s_addr) >> 24)==127) 
    381                 continue; 
    382  
    383             pj_memcpy(&cand_addr, &comp->local_addr, sizeof(pj_sockaddr_in)); 
    384             cand_addr.sin_addr.s_addr = ifs[i].ipv4.sin_addr.s_addr; 
    385  
    386  
    387             /* If the IP address is equal to local address, assign it 
    388              * as default candidate. 
    389              */ 
    390             if (ifs[i].ipv4.sin_addr.s_addr == comp->local_addr.ipv4.sin_addr.s_addr) { 
    391                 set_default = PJ_TRUE; 
    392                 local_pref = 65535; 
    393             } else { 
    394                 set_default = PJ_FALSE; 
    395                 local_pref = 0; 
    396             } 
    397  
    398             status = add_cand(ice_st, comp, comp_id,  
    399                               PJ_ICE_CAND_TYPE_HOST,  
    400                               local_pref, &cand_addr, set_default); 
    401             if (status != PJ_SUCCESS) 
    402                 goto on_error; 
    403         } 
    404  
    405  
    406     } else if ((options & PJ_ICE_ST_OPT_DONT_ADD_CAND)==0) { 
    407         /* Socket is bound to specific address.  
    408          * In this case only add that address as a single entry in the 
    409          * cand_list table. 
    410          */ 
    411         status = add_cand(ice_st, comp, comp_id,  
    412                           PJ_ICE_CAND_TYPE_HOST,  
    413                           65535, &comp->local_addr.ipv4, 
    414                           PJ_TRUE); 
    415         if (status != PJ_SUCCESS) 
    416             goto on_error; 
    417  
    418     } else if (options & PJ_ICE_ST_OPT_DONT_ADD_CAND) { 
    419         /* If application doesn't want to add candidate, just fix local_addr 
    420          * in case its value is zero. 
    421          */ 
    422         if (comp->local_addr.ipv4.sin_addr.s_addr == 0) { 
    423             status = pj_gethostip(pj_AF_INET(), &comp->local_addr); 
    424             if (status != PJ_SUCCESS) 
    425                 return status; 
    426         } 
    427     } 
    428  
    429  
    430     /* Done */ 
    431     if (p_comp) 
    432         *p_comp = comp; 
    433  
    434     return PJ_SUCCESS; 
    435  
    436 on_error: 
    437     destroy_component(comp); 
    438     return status; 
    439 } 
    440  
    441 /*  
    442  * This is callback called by ioqueue on incoming packet  
    443  */ 
    444 static void on_read_complete(pj_ioqueue_key_t *key,  
    445                              pj_ioqueue_op_key_t *op_key,  
    446                              pj_ssize_t bytes_read) 
    447 { 
    448     pj_ice_strans_comp *comp = (pj_ice_strans_comp*)  
    449                             pj_ioqueue_get_user_data(key); 
    450     pj_ice_strans *ice_st = comp->ice_st; 
    451     pj_ssize_t pkt_size; 
    452     enum { RETRY = 10 }; 
    453     unsigned retry; 
    454     pj_status_t status; 
    455  
    456     if (bytes_read > 0) { 
    457         /* 
    458          * Okay, we got a packet from the socket for the component. There is 
    459          * a bit of situation here, since this packet could be one of these: 
    460          * 
    461          * 1) this could be the response of STUN binding request sent by 
    462          *    this component to a) an initial request to get the STUN mapped 
    463          *    address of this component, or b) subsequent request to keep 
    464          *    the binding alive. 
    465          *  
    466          * 2) this could be a packet (STUN or not STUN) sent from the STUN 
    467          *    relay server. In this case, still there are few options to do 
    468          *    for this packet: a) process this locally if this packet is 
    469          *    related to TURN session management (e.g. Allocate response), 
    470          *    b) forward this packet to ICE if this is related to ICE 
    471          *    discovery process. 
    472          * 
    473          * 3) this could be a STUN request or response sent as part of ICE 
    474          *    discovery process. 
    475          * 
    476          * 4) this could be application's packet, e.g. when ICE processing 
    477          *    is done and agents start sending RTP/RTCP packets to each 
    478          *    other, or when ICE processing is not done and this ICE stream 
    479          *    transport decides to allow sending data. 
    480          * 
    481          * So far we don't have good solution for this. 
    482          * The process below is just a workaround. 
    483          */ 
    484         status = pj_stun_msg_check(comp->pkt, bytes_read,  
    485                                    PJ_STUN_IS_DATAGRAM); 
    486  
    487         if (status == PJ_SUCCESS) { 
    488             if (comp->stun_sess && 
    489                 PJ_STUN_IS_RESPONSE(((pj_stun_msg_hdr*)comp->pkt)->type) && 
    490                 pj_memcmp(comp->pkt+8, comp->ka_tsx_id, 12) == 0)  
    491             { 
    492                 status = pj_stun_session_on_rx_pkt(comp->stun_sess, comp->pkt, 
    493                                                    bytes_read,  
    494                                                    PJ_STUN_IS_DATAGRAM, NULL, 
    495                                                    NULL, &comp->src_addr,  
    496                                                    comp->src_addr_len); 
    497             } else if (ice_st->ice) { 
    498                 PJ_TODO(DISTINGUISH_BETWEEN_LOCAL_AND_RELAY); 
    499  
    500                 TRACE_PKT((comp->ice_st->obj_name,  
    501                           "Component %d RX packet from %s:%d", 
    502                           comp->comp_id, 
    503                           pj_inet_ntoa(comp->src_addr.ipv4.sin_addr), 
    504                           (int)pj_ntohs(comp->src_addr.ipv4.sin_port))); 
    505  
    506                 status = pj_ice_sess_on_rx_pkt(ice_st->ice, comp->comp_id,  
    507                                                comp->pkt, bytes_read, 
    508                                                &comp->src_addr,  
    509                                                comp->src_addr_len); 
    510             } else { 
    511                 /* This must have been a very late STUN reponse, 
    512                  * or an early STUN Binding Request when our local 
    513                  * ICE has not been created yet. */ 
    514             } 
    515         } else { 
    516             (*ice_st->cb.on_rx_data)(ice_st, comp->comp_id,  
    517                                      comp->pkt, bytes_read,  
    518                                      &comp->src_addr, comp->src_addr_len); 
    519         } 
    520  
    521     } else if (bytes_read < 0) { 
    522         ice_st_perror(comp->ice_st, "ioqueue read callback error",  
    523                       -bytes_read); 
    524     } 
    525  
    526     /* Read next packet */ 
    527     for (retry=0; retry<RETRY;) { 
    528         pkt_size = sizeof(comp->pkt); 
    529         comp->src_addr_len = sizeof(comp->src_addr); 
    530         status = pj_ioqueue_recvfrom(key, op_key, comp->pkt, &pkt_size,  
    531                                      PJ_IOQUEUE_ALWAYS_ASYNC, 
    532                                      &comp->src_addr, &comp->src_addr_len); 
    533         if (status == PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK) || 
    534             status == PJ_STATUS_FROM_OS(OSERR_EINPROGRESS) ||  
    535             status == PJ_STATUS_FROM_OS(OSERR_ECONNRESET)) 
    536         { 
    537             ice_st_perror(comp->ice_st, "ioqueue recvfrom() error", status); 
    538             ++retry; 
    539             continue; 
    540         } else if (status != PJ_SUCCESS && status != PJ_EPENDING) { 
    541             retry += 2; 
    542             ice_st_perror(comp->ice_st, "ioqueue recvfrom() error", status); 
    543         } else { 
    544             break; 
    545         } 
    546     } 
    547 } 
    548  
    549 /*  
    550  * Destroy a component  
    551  */ 
    552 static void destroy_component(pj_ice_strans_comp *comp) 
    553 { 
    554     if (comp->stun_sess) { 
    555         pj_stun_session_destroy(comp->stun_sess); 
    556         comp->stun_sess = NULL; 
    557     } 
    558  
    559     if (comp->key) { 
    560         pj_ioqueue_unregister(comp->key); 
    561         comp->key = NULL; 
    562         comp->sock = PJ_INVALID_SOCKET; 
    563     } else if (comp->sock != PJ_INVALID_SOCKET && comp->sock != 0) { 
    564         pj_sock_close(comp->sock); 
    565         comp->sock = PJ_INVALID_SOCKET; 
    566     } 
    567 } 
    568  
    569  
    570 /* STUN keep-alive timer callback */ 
    571 static void ka_timer_cb(pj_timer_heap_t *th, pj_timer_entry *te) 
    572 { 
    573     pj_ice_strans *ice_st = (pj_ice_strans*)te->user_data; 
    574     unsigned i; 
    575     pj_status_t status; 
    576  
    577     PJ_UNUSED_ARG(th); 
    578  
    579     ice_st->ka_timer.id = PJ_FALSE; 
    580  
    581     for (i=0; i<ice_st->comp_cnt; ++i) { 
    582         pj_ice_strans_comp *comp = ice_st->comp[i]; 
    583         pj_stun_tx_data *tdata; 
    584         unsigned j; 
    585  
    586         /* Does this component have STUN server reflexive candidate? */ 
    587         for (j=0; j<comp->cand_cnt; ++j) { 
    588             if (comp->cand_list[j].type == PJ_ICE_CAND_TYPE_SRFLX) 
    589                 break; 
    590         } 
    591         if (j == comp->cand_cnt) 
    592             continue; 
    593  
    594         /* Create STUN binding request */ 
    595         status = pj_stun_session_create_req(comp->stun_sess, 
    596                                             PJ_STUN_BINDING_REQUEST,  
    597                                             PJ_STUN_MAGIC, 
    598                                             comp->ka_tsx_id, &tdata); 
    599         if (status != PJ_SUCCESS) 
    600             continue; 
    601  
    602         /* tdata->user_data is NULL for keep-alive */ 
    603         //tdata->user_data = NULL; 
    604  
    605         ++comp->pending_cnt; 
    606  
    607  
    608         /* Send STUN binding request */ 
    609         PJ_LOG(5,(ice_st->obj_name, "Sending STUN keep-alive from %s;%d", 
    610                   pj_inet_ntoa(comp->local_addr.ipv4.sin_addr), 
    611                   pj_ntohs(comp->local_addr.ipv4.sin_port))); 
    612         status = pj_stun_session_send_msg(comp->stun_sess, &comp->cand_list[j], 
    613                                           PJ_FALSE, PJ_TRUE, &ice_st->stun_srv, 
    614                                           sizeof(pj_sockaddr_in), tdata); 
    615         if (status != PJ_SUCCESS) { 
    616             --comp->pending_cnt; 
    617         } 
    618     } 
    619  
    620     /* Start next timer */ 
    621     start_ka_timer(ice_st); 
    622 } 
    623  
    624 /* Start STUN keep-alive timer */ 
    625 static void start_ka_timer(pj_ice_strans *ice_st) 
    626 { 
    627     pj_time_val delay; 
    628  
    629     /* Skip if timer is already running */ 
    630     if (ice_st->ka_timer.id != PJ_FALSE) 
    631         return; 
    632  
    633     delay.sec = PJ_ICE_ST_KEEP_ALIVE_MIN; 
    634     delay.msec = pj_rand() % (PJ_ICE_ST_KEEP_ALIVE_MAX_RAND * 1000); 
    635     pj_time_val_normalize(&delay); 
    636  
    637     ice_st->ka_timer.cb = &ka_timer_cb; 
    638     ice_st->ka_timer.user_data = ice_st; 
    639      
    640     if (pj_timer_heap_schedule(ice_st->stun_cfg.timer_heap,  
    641                                &ice_st->ka_timer, &delay)==PJ_SUCCESS) 
    642     { 
    643         ice_st->ka_timer.id = PJ_TRUE; 
    644     } 
    645 } 
    646  
    647  
    648 /* Stop STUN keep-alive timer */ 
    649 static void stop_ka_timer(pj_ice_strans *ice_st) 
    650 { 
    651     /* Skip if timer is already stop */ 
    652     if (ice_st->ka_timer.id == PJ_FALSE) 
    653         return; 
    654  
    655     pj_timer_heap_cancel(ice_st->stun_cfg.timer_heap, &ice_st->ka_timer); 
    656     ice_st->ka_timer.id = PJ_FALSE; 
    657 } 
    658  
    659  
    660 /* 
    661  * Add STUN mapping to a component. 
    662  */ 
    663 static pj_status_t get_stun_mapped_addr(pj_ice_strans *ice_st, 
    664                                         pj_ice_strans_comp *comp) 
    665 { 
    666     pj_ice_strans_cand *cand; 
    667     pj_stun_session_cb sess_cb; 
    668     pj_stun_tx_data *tdata; 
    669     pj_status_t status; 
    670  
    671     PJ_ASSERT_RETURN(ice_st && comp, PJ_EINVAL); 
    672      
    673     /* Bail out if STUN server is still being resolved */ 
    674     if (ice_st->has_rjob) 
    675         return PJ_EBUSY; 
    676  
    677     /* Just return (successfully) if STUN server is not configured */ 
    678     if (ice_st->stun_srv.sin_family == 0) 
    679         return PJ_SUCCESS; 
    680  
    681  
    682     /* Create STUN session for this component */ 
    683     pj_bzero(&sess_cb, sizeof(sess_cb)); 
    684     sess_cb.on_request_complete = &stun_on_request_complete; 
    685     sess_cb.on_send_msg = &stun_on_send_msg; 
    686     status = pj_stun_session_create(&ice_st->stun_cfg, ice_st->obj_name, 
    687                                     &sess_cb, PJ_FALSE, &comp->stun_sess); 
    688     if (status != PJ_SUCCESS) 
    689         return status; 
    690  
    691     /* Associate component with STUN session */ 
    692     pj_stun_session_set_user_data(comp->stun_sess, (void*)comp); 
    693  
    694     /* Create STUN binding request */ 
    695     status = pj_stun_session_create_req(comp->stun_sess,  
    696                                         PJ_STUN_BINDING_REQUEST,  
    697                                         PJ_STUN_MAGIC, 
    698                                         comp->ka_tsx_id,  
    699                                         &tdata); 
    700     if (status != PJ_SUCCESS) 
    701         return status; 
    702  
    703     /* Will be attached to tdata in send_msg() */ 
    704     cand = &comp->cand_list[comp->cand_cnt]; 
    705  
    706     /* Add pending count first, since stun_on_request_complete() 
    707      * may be called before this function completes 
    708      */ 
    709     comp->pending_cnt++; 
    710  
    711     /* Add new alias to this component */ 
    712     cand->type = PJ_ICE_CAND_TYPE_SRFLX; 
    713     cand->status = PJ_EPENDING; 
    714     cand->ice_cand_id = -1; 
    715     cand->local_pref = 65535; 
    716     pj_ice_calc_foundation(ice_st->pool, &cand->foundation,  
    717                            PJ_ICE_CAND_TYPE_SRFLX, &comp->local_addr); 
    718  
    719     ++comp->cand_cnt; 
    720  
    721     /* Send STUN binding request */ 
    722     status = pj_stun_session_send_msg(comp->stun_sess, (void*)cand, PJ_FALSE,  
    723                                       PJ_TRUE, &ice_st->stun_srv,  
    724                                       sizeof(pj_sockaddr_in), tdata); 
    725     if (status != PJ_SUCCESS) { 
    726         --comp->pending_cnt; 
    727         --comp->cand_cnt; 
    728         return status; 
    729     } 
    730  
    731     return PJ_SUCCESS; 
    732 } 
    733  
    734  
    735 /* 
    736  * Create the component. 
    737  */ 
    738 PJ_DEF(pj_status_t) pj_ice_strans_create_comp(pj_ice_strans *ice_st, 
    739                                               unsigned comp_id, 
    740                                               pj_uint32_t options, 
    741                                               const pj_sockaddr_in *addr) 
    742 { 
    743     pj_ice_strans_comp *comp = NULL; 
    744     pj_status_t status; 
    745  
    746     /* Verify arguments */ 
    747     PJ_ASSERT_RETURN(ice_st && comp_id, PJ_EINVAL); 
    748  
    749     /* Check that component ID present */ 
    750     PJ_ASSERT_RETURN(comp_id <= ice_st->comp_cnt, PJNATH_EICEINCOMPID); 
    751  
    752     /* Can't add new component while ICE is running */ 
    753     PJ_ASSERT_RETURN(ice_st->ice == NULL, PJ_EBUSY); 
    754      
    755     /* Can't add new component while resolver is running */ 
    756     PJ_ASSERT_RETURN(ice_st->has_rjob == PJ_FALSE, PJ_EBUSY); 
    757  
    758  
    759     /* Create component */ 
    760     status = create_component(ice_st, comp_id, options, addr, &comp); 
    761     if (status != PJ_SUCCESS) 
    762         return status; 
    763  
    764     if ((options & PJ_ICE_ST_OPT_DISABLE_STUN) == 0) { 
    765         status = get_stun_mapped_addr(ice_st, comp); 
    766         if (status != PJ_SUCCESS) { 
    767             destroy_component(comp); 
    768             return status; 
    769         } 
    770     } 
    771  
    772     /* Store this component */ 
    773     ice_st->comp[comp_id-1] = comp; 
    774  
    775     return PJ_SUCCESS; 
    776 } 
    777  
    778  
    779 PJ_DEF(pj_status_t) pj_ice_strans_add_cand( pj_ice_strans *ice_st, 
    780                                             unsigned comp_id, 
    781                                             pj_ice_cand_type type, 
    782                                             pj_uint16_t local_pref, 
    783                                             const pj_sockaddr_in *addr, 
    784                                             pj_bool_t set_default) 
    785 { 
    786     pj_ice_strans_comp *comp; 
    787  
    788  
    789     PJ_ASSERT_RETURN(ice_st && comp_id && addr, PJ_EINVAL); 
    790     PJ_ASSERT_RETURN(comp_id <= ice_st->comp_cnt, PJ_EINVAL); 
    791     PJ_ASSERT_RETURN(ice_st->comp[comp_id-1] != NULL, PJ_EINVALIDOP); 
    792  
    793     comp = ice_st->comp[comp_id-1]; 
    794     return add_cand(ice_st, comp, comp_id, type, local_pref, addr,  
    795                     set_default); 
    796 } 
    797  
    798  
    799 PJ_DEF(pj_status_t) pj_ice_strans_get_comps_status(pj_ice_strans *ice_st) 
    800 { 
    801     unsigned i; 
    802     pj_status_t worst = PJ_SUCCESS; 
    803  
    804     for (i=0; i<ice_st->comp_cnt; ++i) { 
    805         pj_ice_strans_comp *comp = ice_st->comp[i]; 
    806  
    807         if (comp->last_status == PJ_SUCCESS) { 
    808             /* okay */ 
    809         } else if (comp->pending_cnt && worst==PJ_SUCCESS) { 
    810             worst = PJ_EPENDING; 
    811             break; 
    812         } else if (comp->last_status != PJ_SUCCESS) { 
    813             worst = comp->last_status; 
    814             break; 
    815         } 
    816  
    817         if (worst != PJ_SUCCESS) 
    818             break; 
    819     } 
    820  
    821     return worst; 
    822 } 
     591        return PJ_TRUE; 
     592    } 
     593} 
     594 
     595/* 
     596 * Get user data 
     597 */ 
     598PJ_DEF(void*) pj_ice_strans_get_user_data(pj_ice_strans *ice_st) 
     599{ 
     600    PJ_ASSERT_RETURN(ice_st, NULL); 
     601    return ice_st->user_data; 
     602} 
     603 
    823604 
    824605/* 
     
    833614    unsigned i; 
    834615    pj_ice_sess_cb ice_cb; 
    835     const pj_uint8_t srflx_prio[4] = { 100, 126, 110, 0 }; 
     616    //const pj_uint8_t srflx_prio[4] = { 100, 126, 110, 0 }; 
    836617 
    837618    /* Check arguments */ 
     
    849630 
    850631    /* Create! */ 
    851     status = pj_ice_sess_create(&ice_st->stun_cfg, ice_st->obj_name, role, 
     632    status = pj_ice_sess_create(&ice_st->cfg.stun_cfg, ice_st->obj_name, role, 
    852633                                ice_st->comp_cnt, &ice_cb,  
    853634                                local_ufrag, local_passwd, &ice_st->ice); 
     
    858639    ice_st->ice->user_data = (void*)ice_st; 
    859640 
     641#if 0 
    860642    /* If default candidate for components are SRFLX one, upload a custom 
    861643     * type priority to ICE session so that SRFLX candidates will get 
     
    868650        pj_ice_sess_set_prefs(ice_st->ice, srflx_prio); 
    869651    } 
    870  
    871  
    872     /* Add candidates */ 
     652#endif 
     653 
     654    /* Add components/candidates */ 
    873655    for (i=0; i<ice_st->comp_cnt; ++i) { 
    874656        unsigned j; 
    875         pj_ice_strans_comp *comp= ice_st->comp[i]; 
     657        pj_ice_strans_comp *comp = ice_st->comp[i]; 
     658 
     659        /* Re-enable logging for Send/Data indications */ 
     660        if (comp->turn_sock) { 
     661            PJ_LOG(5,(ice_st->obj_name,  
     662                      "Disabling STUN Indication logging for " 
     663                      "component %d", i+1)); 
     664            pj_turn_sock_set_log(comp->turn_sock, 0xFFFF); 
     665        } 
    876666 
    877667        for (j=0; j<comp->cand_cnt; ++j) { 
    878             pj_ice_strans_cand *cand = &comp->cand_list[j]; 
     668            pj_ice_sess_cand *cand = &comp->cand_list[j]; 
     669            unsigned ice_cand_id; 
    879670 
    880671            /* Skip if candidate is not ready */ 
    881672            if (cand->status != PJ_SUCCESS) { 
    882673                PJ_LOG(5,(ice_st->obj_name,  
    883                           "Candidate %d in component %d is not added", 
     674                          "Candidate %d of comp %d is not added (pending)", 
    884675                          j, i)); 
    885676                continue; 
    886677            } 
    887678 
     679            /* Must have address */ 
     680            pj_assert(pj_sockaddr_has_addr(&cand->addr)); 
     681 
     682            /* Add the candidate */ 
    888683            status = pj_ice_sess_add_cand(ice_st->ice, comp->comp_id,  
    889                                           cand->type, cand->local_pref,  
     684                                          cand->transport_id, cand->type,  
     685                                          cand->local_pref,  
    890686                                          &cand->foundation, &cand->addr,  
    891                                           &comp->local_addr, NULL,  
    892                                           sizeof(pj_sockaddr_in),  
    893                                           (unsigned*)&cand->ice_cand_id); 
     687                                          &cand->base_addr,  &cand->rel_addr, 
     688                                          pj_sockaddr_get_len(&cand->addr), 
     689                                          (unsigned*)&ice_cand_id); 
    894690            if (status != PJ_SUCCESS) 
    895691                goto on_error; 
     
    908704 */ 
    909705PJ_DEF(pj_status_t) pj_ice_strans_enum_cands(pj_ice_strans *ice_st, 
    910                                          unsigned *count, 
    911                                          pj_ice_sess_cand cand[]) 
     706                                             unsigned comp_id, 
     707                                             unsigned *count, 
     708                                             pj_ice_sess_cand cand[]) 
    912709{ 
    913710    unsigned i, cnt; 
    914     pj_ice_sess_cand *pcand; 
    915  
    916     PJ_ASSERT_RETURN(ice_st && count && cand, PJ_EINVAL); 
    917     PJ_ASSERT_RETURN(ice_st->ice, PJ_EINVALIDOP); 
    918  
    919     cnt = ice_st->ice->lcand_cnt; 
     711    pj_ice_strans_comp *comp; 
     712 
     713    PJ_ASSERT_RETURN(ice_st && comp_id && comp_id <= ice_st->comp_cnt && 
     714                     count && cand, PJ_EINVAL); 
     715 
     716    comp = ice_st->comp[comp_id - 1]; 
     717    cnt = comp->cand_cnt; 
    920718    cnt = (cnt > *count) ? *count : cnt; 
    921     *count = 0; 
    922719 
    923720    for (i=0; i<cnt; ++i) { 
    924         pcand = &ice_st->ice->lcand[i]; 
    925         pj_memcpy(&cand[i], pcand, sizeof(pj_ice_sess_cand)); 
     721        pj_memcpy(&cand[i], &comp->cand_list[i], sizeof(pj_ice_sess_cand)); 
    926722    } 
    927723 
    928724    *count = cnt; 
    929725    return PJ_SUCCESS; 
     726} 
     727 
     728/* 
     729 * Get default candidate. 
     730 */ 
     731PJ_DEF(pj_status_t) pj_ice_strans_get_def_cand( pj_ice_strans *ice_st, 
     732                                                unsigned comp_id, 
     733                                                pj_ice_sess_cand *cand) 
     734{ 
     735    const pj_ice_sess_check *valid_pair; 
     736 
     737    PJ_ASSERT_RETURN(ice_st && comp_id && comp_id <= ice_st->comp_cnt && 
     738                      cand, PJ_EINVAL); 
     739 
     740    valid_pair = pj_ice_strans_get_valid_pair(ice_st, comp_id); 
     741    if (valid_pair) { 
     742        pj_memcpy(cand, valid_pair->lcand, sizeof(pj_ice_sess_cand)); 
     743    } else { 
     744        pj_ice_strans_comp *comp = ice_st->comp[comp_id - 1]; 
     745        pj_assert(comp->default_cand>=0 && comp->default_cand<comp->cand_cnt); 
     746        pj_memcpy(cand, &comp->cand_list[comp->default_cand],  
     747                  sizeof(pj_ice_sess_cand)); 
     748    } 
     749    return PJ_SUCCESS; 
     750} 
     751 
     752/* 
     753 * Get the current ICE role. 
     754 */ 
     755PJ_DEF(pj_ice_sess_role) pj_ice_strans_get_role(pj_ice_strans *ice_st) 
     756{ 
     757    PJ_ASSERT_RETURN(ice_st && ice_st->ice, PJ_ICE_SESS_ROLE_UNKNOWN); 
     758    return ice_st->ice->role; 
     759} 
     760 
     761/* 
     762 * Change session role. 
     763 */ 
     764PJ_DEF(pj_status_t) pj_ice_strans_change_role( pj_ice_strans *ice_st, 
     765                                               pj_ice_sess_role new_role) 
     766{ 
     767    PJ_ASSERT_RETURN(ice_st && ice_st->ice, PJ_EINVALIDOP); 
     768    return pj_ice_sess_change_role(ice_st->ice, new_role); 
    930769} 
    931770 
     
    941780    pj_status_t status; 
    942781 
     782    PJ_ASSERT_RETURN(ice_st && rem_ufrag && rem_passwd && 
     783                     rem_cand_cnt && rem_cand, PJ_EINVAL); 
     784 
     785    /* Mark start time */ 
     786    pj_gettimeofday(&ice_st->start_time); 
     787 
     788    /* Build check list */ 
    943789    status = pj_ice_sess_create_check_list(ice_st->ice, rem_ufrag, rem_passwd, 
    944790                                           rem_cand_cnt, rem_cand); 
     
    946792        return status; 
    947793 
     794    /* Start ICE negotiation! */ 
    948795    status = pj_ice_sess_start_check(ice_st->ice); 
    949796    if (status != PJ_SUCCESS) { 
     
    955802 
    956803/* 
     804 * Get valid pair. 
     805 */ 
     806PJ_DEF(const pj_ice_sess_check*)  
     807pj_ice_strans_get_valid_pair(const pj_ice_strans *ice_st, 
     808                             unsigned comp_id) 
     809{ 
     810    PJ_ASSERT_RETURN(ice_st && comp_id && comp_id <= ice_st->comp_cnt, 
     811                     NULL); 
     812     
     813    if (ice_st->ice == NULL) 
     814        return NULL; 
     815     
     816    return ice_st->ice->comp[comp_id-1].valid_check; 
     817} 
     818 
     819/* 
    957820 * Stop ICE! 
    958821 */ 
    959822PJ_DEF(pj_status_t) pj_ice_strans_stop_ice(pj_ice_strans *ice_st) 
    960823{ 
    961     unsigned i; 
    962  
    963824    if (ice_st->ice) { 
    964825        pj_ice_sess_destroy(ice_st->ice); 
     
    966827    } 
    967828 
    968     /* Invalidate all candidate Ids */ 
    969     for (i=0; i<ice_st->comp_cnt; ++i) { 
    970         unsigned j; 
    971         for (j=0; j<ice_st->comp[i]->cand_cnt; ++j) { 
    972             ice_st->comp[i]->cand_list[j].ice_cand_id = -1; 
    973         } 
    974     } 
    975  
    976829    return PJ_SUCCESS; 
    977830} 
    978831 
    979832/* 
    980  * Send packet using non-ICE means (e.g. when ICE was not negotiated). 
     833 * Application wants to send outgoing packet. 
    981834 */ 
    982835PJ_DEF(pj_status_t) pj_ice_strans_sendto( pj_ice_strans *ice_st, 
     
    998851    /* If ICE is available, send data with ICE */ 
    999852    if (ice_st->ice) { 
    1000         return pj_ice_sess_send_data(ice_st->ice, comp_id, data, data_len); 
    1001     } 
    1002  
    1003     /* Otherwise send direcly with the socket. This is for compatibility 
    1004      * with remote that doesn't support ICE. 
    1005      */ 
    1006     pkt_size = data_len; 
    1007     status = pj_ioqueue_sendto(comp->key, &comp->write_op,  
    1008                                data, &pkt_size, 0, 
    1009                                dst_addr, dst_addr_len); 
    1010      
    1011     return (status==PJ_SUCCESS||status==PJ_EPENDING) ? PJ_SUCCESS : status; 
     853        if (comp->turn_sock) { 
     854            pj_turn_sock_lock(comp->turn_sock); 
     855        } 
     856        status = pj_ice_sess_send_data(ice_st->ice, comp_id, data, data_len); 
     857        if (comp->turn_sock) { 
     858            pj_turn_sock_unlock(comp->turn_sock); 
     859        } 
     860        return status; 
     861 
     862    } else if (comp->stun_sock) { 
     863 
     864        pkt_size = data_len; 
     865        status = pj_stun_sock_sendto(comp->stun_sock, NULL, data, data_len, 
     866                                     0, dst_addr, dst_addr_len); 
     867        return (status==PJ_SUCCESS||status==PJ_EPENDING) ? PJ_SUCCESS : status; 
     868 
     869    } else 
     870        return PJ_EINVALIDOP; 
    1012871} 
    1013872 
     
    1019878{ 
    1020879    pj_ice_strans *ice_st = (pj_ice_strans*)ice->user_data; 
     880    pj_time_val t; 
     881    unsigned msec; 
     882 
     883    sess_add_ref(ice_st); 
     884 
     885    pj_gettimeofday(&t); 
     886    PJ_TIME_VAL_SUB(t, ice_st->start_time); 
     887    msec = PJ_TIME_VAL_MSEC(t); 
     888 
    1021889    if (ice_st->cb.on_ice_complete) { 
    1022         (*ice_st->cb.on_ice_complete)(ice_st, status); 
    1023     } 
     890        if (status != PJ_SUCCESS) { 
     891            char errmsg[PJ_ERR_MSG_SIZE]; 
     892            pj_strerror(status, errmsg, sizeof(errmsg)); 
     893            PJ_LOG(4,(ice_st->obj_name,  
     894                      "ICE negotiation failed after %ds:%03d: %s",  
     895                      msec/1000, msec%1000, errmsg)); 
     896        } else { 
     897            unsigned i; 
     898            enum { 
     899                msg_disable_ind = 0xFFFF & 
     900                                  ~(PJ_STUN_SESS_LOG_TX_IND| 
     901                                    PJ_STUN_SESS_LOG_RX_IND) 
     902            }; 
     903 
     904            PJ_LOG(4,(ice_st->obj_name,  
     905                      "ICE negotiation success after %ds:%03d", 
     906                      msec/1000, msec%1000)); 
     907 
     908            for (i=0; i<ice_st->comp_cnt; ++i) { 
     909                const pj_ice_sess_check *check; 
     910 
     911                check = pj_ice_strans_get_valid_pair(ice_st, i+1); 
     912                if (check) { 
     913                    char lip[PJ_INET6_ADDRSTRLEN+10]; 
     914                    char rip[PJ_INET6_ADDRSTRLEN+10]; 
     915 
     916                    pj_sockaddr_print(&check->lcand->addr, lip,  
     917                                      sizeof(lip), 3); 
     918                    pj_sockaddr_print(&check->rcand->addr, rip,  
     919                                      sizeof(rip), 3); 
     920 
     921                    if (check->lcand->transport_id == TP_TURN) { 
     922                        /* Disable logging for Send/Data indications */ 
     923                        PJ_LOG(5,(ice_st->obj_name,  
     924                                  "Disabling STUN Indication logging for " 
     925                                  "component %d", i+1)); 
     926                        pj_turn_sock_set_log(ice_st->comp[i]->turn_sock, 
     927                                             msg_disable_ind); 
     928                    } 
     929 
     930                    PJ_LOG(4,(ice_st->obj_name, " Comp %d: " 
     931                              "sending from %s candidate %s to " 
     932                              "%s candidate %s", 
     933                              i+1,  
     934                              pj_ice_get_cand_type_name(check->lcand->type), 
     935                              lip, 
     936                              pj_ice_get_cand_type_name(check->rcand->type), 
     937                              rip)); 
     938                               
     939                } else { 
     940                    PJ_LOG(4,(ice_st->obj_name,  
     941                              "Comp %d: disabled", i+1)); 
     942                } 
     943            } 
     944        } 
     945 
     946        (*ice_st->cb.on_ice_complete)(ice_st, PJ_ICE_STRANS_OP_NEGOTIATION,  
     947                                      status); 
     948 
     949         
     950    } 
     951 
     952    sess_dec_ref(ice_st); 
    1024953} 
    1025954 
     
    1029958static pj_status_t ice_tx_pkt(pj_ice_sess *ice,  
    1030959                              unsigned comp_id,  
     960                              unsigned transport_id, 
    1031961                              const void *pkt, pj_size_t size, 
    1032962                              const pj_sockaddr_t *dst_addr, 
     
    1034964{ 
    1035965    pj_ice_strans *ice_st = (pj_ice_strans*)ice->user_data; 
    1036     pj_ice_strans_comp *comp = NULL; 
    1037     pj_ssize_t pkt_size; 
     966    pj_ice_strans_comp *comp; 
    1038967    pj_status_t status; 
    1039968 
    1040     PJ_TODO(TX_TO_RELAY); 
    1041  
    1042969    PJ_ASSERT_RETURN(comp_id && comp_id <= ice_st->comp_cnt, PJ_EINVAL); 
     970 
    1043971    comp = ice_st->comp[comp_id-1]; 
    1044972 
    1045973    TRACE_PKT((comp->ice_st->obj_name,  
    1046               "Component %d TX packet to %s:%d", 
    1047               comp_id, 
     974              "Component %d TX packet to %s:%d with transport %d", 
     975              comp_id,  
    1048976              pj_inet_ntoa(((pj_sockaddr_in*)dst_addr)->sin_addr), 
    1049               (int)pj_ntohs(((pj_sockaddr_in*)dst_addr)->sin_port))); 
    1050  
    1051     pkt_size = size; 
    1052     status = pj_ioqueue_sendto(comp->key, &comp->write_op,  
    1053                                pkt, &pkt_size, 0, 
    1054                                dst_addr, dst_addr_len); 
     977              (int)pj_ntohs(((pj_sockaddr_in*)dst_addr)->sin_port), 
     978              transport_id)); 
     979 
     980    if (transport_id == TP_TURN) { 
     981        if (comp->turn_sock) { 
     982            status = pj_turn_sock_sendto(comp->turn_sock,  
     983                                         (const pj_uint8_t*)pkt, size, 
     984                                         dst_addr, dst_addr_len); 
     985        } else { 
     986            status = PJ_EINVALIDOP; 
     987        } 
     988    } else if (transport_id == TP_STUN) { 
     989        status = pj_stun_sock_sendto(comp->stun_sock, NULL,  
     990                                     pkt, size, 0, 
     991                                     dst_addr, dst_addr_len); 
     992    } else { 
     993        pj_assert(!"Invalid transport ID"); 
     994        status = PJ_EINVALIDOP; 
     995    } 
    1055996     
    1056997    return (status==PJ_SUCCESS||status==PJ_EPENDING) ? PJ_SUCCESS : status; 
     
    10621003static void ice_rx_data(pj_ice_sess *ice,  
    10631004                        unsigned comp_id,  
     1005                        unsigned transport_id, 
    10641006                        void *pkt, pj_size_t size, 
    10651007                        const pj_sockaddr_t *src_addr, 
     
    10681010    pj_ice_strans *ice_st = (pj_ice_strans*)ice->user_data; 
    10691011 
     1012    PJ_UNUSED_ARG(transport_id); 
     1013 
    10701014    if (ice_st->cb.on_rx_data) { 
    10711015        (*ice_st->cb.on_rx_data)(ice_st, comp_id, pkt, size,  
     
    10741018} 
    10751019 
    1076 /* 
    1077  * Callback called by STUN session to send outgoing packet. 
    1078  */ 
    1079 static pj_status_t stun_on_send_msg(pj_stun_session *sess, 
    1080                                     void *token, 
    1081                                     const void *pkt, 
    1082                                     pj_size_t size, 
    1083                                     const pj_sockaddr_t *dst_addr, 
    1084                                     unsigned dst_addr_len) 
     1020/* Notification when incoming packet has been received from 
     1021 * the STUN socket.  
     1022 */ 
     1023static pj_bool_t stun_on_rx_data(pj_stun_sock *stun_sock, 
     1024                                 void *pkt, 
     1025                                 unsigned pkt_len, 
     1026                                 const pj_sockaddr_t *src_addr, 
     1027                                 unsigned addr_len) 
    10851028{ 
    10861029    pj_ice_strans_comp *comp; 
    1087     pj_ssize_t pkt_size; 
     1030    pj_ice_strans *ice_st; 
    10881031    pj_status_t status; 
    10891032 
    1090     PJ_UNUSED_ARG(token); 
    1091  
    1092     comp = (pj_ice_strans_comp*) pj_stun_session_get_user_data(sess); 
    1093     pkt_size = size; 
    1094     status = pj_ioqueue_sendto(comp->key, &comp->write_op,  
    1095                                pkt, &pkt_size, 0, 
    1096                                dst_addr, dst_addr_len); 
    1097      
    1098     return (status==PJ_SUCCESS||status==PJ_EPENDING) ? PJ_SUCCESS : status; 
    1099 } 
    1100  
    1101 /* 
    1102  * Callback sent by STUN session when outgoing STUN request has 
    1103  * completed. 
    1104  */ 
    1105 static void stun_on_request_complete(pj_stun_session *sess, 
    1106                                      pj_status_t status, 
    1107                                      void *token, 
    1108                                      pj_stun_tx_data *tdata, 
    1109                                      const pj_stun_msg *response, 
    1110                                      const pj_sockaddr_t *src_addr, 
    1111                                      unsigned src_addr_len) 
     1033    comp = (pj_ice_strans_comp*) pj_stun_sock_get_user_data(stun_sock); 
     1034    ice_st = comp->ice_st; 
     1035 
     1036    sess_add_ref(ice_st); 
     1037 
     1038    if (ice_st->ice == NULL) { 
     1039        /* The ICE session is gone, but we're still receiving packets. 
     1040         * This could also happen if remote doesn't do ICE. So just 
     1041         * report this to application. 
     1042         */ 
     1043        if (ice_st->cb.on_rx_data) { 
     1044            (*ice_st->cb.on_rx_data)(ice_st, comp->comp_id, pkt, pkt_len,  
     1045                                     src_addr, addr_len); 
     1046        } 
     1047 
     1048    } else { 
     1049 
     1050        /* Hand over the packet to ICE session */ 
     1051        status = pj_ice_sess_on_rx_pkt(comp->ice_st->ice, comp->comp_id,  
     1052                                       TP_STUN, pkt, pkt_len, 
     1053                                       src_addr, addr_len); 
     1054 
     1055        if (status != PJ_SUCCESS) { 
     1056            ice_st_perror(comp->ice_st, "Error processing packet",  
     1057                          status); 
     1058        } 
     1059    } 
     1060 
     1061    return sess_dec_ref(ice_st); 
     1062} 
     1063 
     1064/* Notifification when asynchronous send operation to the STUN socket 
     1065 * has completed.  
     1066 */ 
     1067static pj_bool_t stun_on_data_sent(pj_stun_sock *stun_sock, 
     1068                                   pj_ioqueue_op_key_t *send_key, 
     1069                                   pj_ssize_t sent) 
     1070{ 
     1071    PJ_UNUSED_ARG(stun_sock); 
     1072    PJ_UNUSED_ARG(send_key); 
     1073    PJ_UNUSED_ARG(sent); 
     1074    return PJ_TRUE; 
     1075} 
     1076 
     1077/* Notification when the status of the STUN transport has changed. */ 
     1078static pj_bool_t stun_on_status(pj_stun_sock *stun_sock,  
     1079                                pj_stun_sock_op op, 
     1080                                pj_status_t status) 
    11121081{ 
    11131082    pj_ice_strans_comp *comp; 
    1114     pj_ice_strans_cand *cand = NULL; 
    1115     pj_stun_xor_mapped_addr_attr *xa; 
    1116     pj_stun_mapped_addr_attr *ma; 
    1117     pj_sockaddr *mapped_addr; 
    1118     char ip[20]; 
    1119  
    1120     comp = (pj_ice_strans_comp*) pj_stun_session_get_user_data(sess); 
    1121     cand = (pj_ice_strans_cand*) token; 
    1122  
    1123     PJ_UNUSED_ARG(token); 
    1124     PJ_UNUSED_ARG(tdata); 
    1125     PJ_UNUSED_ARG(src_addr); 
    1126     PJ_UNUSED_ARG(src_addr_len); 
    1127  
    1128     if (cand == NULL) { 
    1129         /* This is keep-alive */ 
     1083    pj_ice_strans *ice_st; 
     1084    pj_ice_sess_cand *cand = NULL; 
     1085    unsigned i; 
     1086 
     1087    comp = (pj_ice_strans_comp*) pj_stun_sock_get_user_data(stun_sock); 
     1088    ice_st = comp->ice_st; 
     1089 
     1090    sess_add_ref(ice_st); 
     1091 
     1092    /* Find the srflx cancidate */ 
     1093    for (i=0; i<comp->cand_cnt; ++i) { 
     1094        if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_SRFLX) { 
     1095            cand = &comp->cand_list[i]; 
     1096            break; 
     1097        } 
     1098    } 
     1099 
     1100    pj_assert(status != PJ_EPENDING); 
     1101 
     1102    switch (op) { 
     1103    case PJ_STUN_SOCK_DNS_OP: 
    11301104        if (status != PJ_SUCCESS) { 
    1131             ice_st_perror(comp->ice_st, "STUN keep-alive request failed", 
     1105            /* May not have cand, e.g. when error during init */ 
     1106            if (cand) 
     1107                cand->status = status; 
     1108            sess_fail(ice_st, PJ_ICE_STRANS_OP_INIT, "DNS resolution failed",  
     1109                      status); 
     1110        } 
     1111        break; 
     1112    case PJ_STUN_SOCK_BINDING_OP: 
     1113        if (status == PJ_SUCCESS) { 
     1114            pj_stun_sock_info info; 
     1115 
     1116            status = pj_stun_sock_get_info(stun_sock, &info); 
     1117            if (status == PJ_SUCCESS) { 
     1118                char ipaddr[PJ_INET6_ADDRSTRLEN+10]; 
     1119                pj_bool_t dup = PJ_FALSE; 
     1120 
     1121                /* Eliminate the srflx candidate if the address is 
     1122                 * equal to other (host) candidates. 
     1123                 */ 
     1124                for (i=0; i<comp->cand_cnt; ++i) { 
     1125                    if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_HOST && 
     1126                        pj_sockaddr_cmp(&comp->cand_list[i].addr, 
     1127                                        &info.mapped_addr) == 0) 
     1128                    { 
     1129                        dup = PJ_TRUE; 
     1130                        break; 
     1131                    } 
     1132                } 
     1133 
     1134                if (dup) { 
     1135                    /* Duplicate found, remove the srflx candidate */ 
     1136                    pj_array_erase(comp->cand_list, sizeof(comp->cand_list[0]), 
     1137                                   comp->cand_cnt, cand - comp->cand_list); 
     1138                    --comp->cand_cnt; 
     1139                } else { 
     1140                    /* Otherwise update the address */ 
     1141                    pj_sockaddr_cp(&cand->addr, &info.mapped_addr); 
     1142                    cand->status = PJ_SUCCESS; 
     1143                } 
     1144 
     1145                PJ_LOG(4,(comp->ice_st->obj_name,  
     1146                          "Comp %d: Binding discovery complete, " 
     1147                          "srflx address is %s", 
     1148                          comp->comp_id,  
     1149                          pj_sockaddr_print(&info.mapped_addr, ipaddr,  
     1150                                             sizeof(ipaddr), 3))); 
     1151 
     1152                sess_init_update(ice_st); 
     1153            } 
     1154        } 
     1155 
     1156        if (status != PJ_SUCCESS) { 
     1157            /* May not have cand, e.g. when error during init */ 
     1158            if (cand) 
     1159                cand->status = status; 
     1160            sess_fail(ice_st, PJ_ICE_STRANS_OP_INIT,  
     1161                      "STUN binding request failed", status); 
     1162        } 
     1163        break; 
     1164    case PJ_STUN_SOCK_KEEP_ALIVE_OP: 
     1165        if (status != PJ_SUCCESS) { 
     1166            pj_assert(cand != NULL); 
     1167            cand->status = status; 
     1168            sess_fail(ice_st, PJ_ICE_STRANS_OP_INIT,  
     1169                      "STUN keep-alive failed", status); 
     1170        } 
     1171        break; 
     1172    } 
     1173 
     1174    return sess_dec_ref(ice_st); 
     1175} 
     1176 
     1177/* Callback when TURN socket has received a packet */ 
     1178static void turn_on_rx_data(pj_turn_sock *turn_sock, 
     1179                            void *pkt, 
     1180                            unsigned pkt_len, 
     1181                            const pj_sockaddr_t *peer_addr, 
     1182                            unsigned addr_len) 
     1183{ 
     1184    pj_ice_strans_comp *comp; 
     1185    pj_status_t status; 
     1186 
     1187    comp = (pj_ice_strans_comp*) pj_turn_sock_get_user_data(turn_sock); 
     1188    if (comp == NULL) { 
     1189        /* We have disassociated ourselves from the TURN socket */ 
     1190        return; 
     1191    } 
     1192 
     1193    sess_add_ref(comp->ice_st); 
     1194 
     1195    if (comp->ice_st->ice == NULL) { 
     1196        /* The ICE session is gone, but we're still receiving packets. 
     1197         * This could also happen if remote doesn't do ICE and application 
     1198         * specifies TURN as the default address in SDP. 
     1199         * So in this case just give the packet to application. 
     1200         */ 
     1201        if (comp->ice_st->cb.on_rx_data) { 
     1202            (*comp->ice_st->cb.on_rx_data)(comp->ice_st, comp->comp_id, pkt, 
     1203                                           pkt_len, peer_addr, addr_len); 
     1204        } 
     1205 
     1206    } else { 
     1207 
     1208        /* Hand over the packet to ICE */ 
     1209        status = pj_ice_sess_on_rx_pkt(comp->ice_st->ice, comp->comp_id, 
     1210                                       TP_TURN, pkt, pkt_len, 
     1211                                       peer_addr, addr_len); 
     1212 
     1213        if (status != PJ_SUCCESS) { 
     1214            ice_st_perror(comp->ice_st,  
     1215                          "Error processing packet from TURN relay",  
    11321216                          status); 
    11331217        } 
     1218    } 
     1219 
     1220    sess_dec_ref(comp->ice_st); 
     1221} 
     1222 
     1223 
     1224/* Callback when TURN client state has changed */ 
     1225static void turn_on_state(pj_turn_sock *turn_sock, pj_turn_state_t old_state, 
     1226                          pj_turn_state_t new_state) 
     1227{ 
     1228    pj_ice_strans_comp *comp; 
     1229 
     1230    comp = (pj_ice_strans_comp*) pj_turn_sock_get_user_data(turn_sock); 
     1231    if (comp == NULL) { 
     1232        /* Not interested in further state notification once the relay is 
     1233         * disconnecting. 
     1234         */ 
    11341235        return; 
    11351236    } 
    11361237 
    1137     /* Decrement pending count for this component */ 
    1138     pj_assert(comp->pending_cnt > 0); 
    1139     comp->pending_cnt--; 
    1140  
    1141     if (status == PJNATH_ESTUNTIMEDOUT) { 
     1238    PJ_LOG(5,(comp->ice_st->obj_name, "TURN client state changed %s --> %s", 
     1239              pj_turn_state_name(old_state), pj_turn_state_name(new_state))); 
     1240 
     1241    sess_add_ref(comp->ice_st); 
     1242 
     1243    if (new_state == PJ_TURN_STATE_READY) { 
     1244        pj_turn_session_info rel_info; 
     1245        char ipaddr[PJ_INET6_ADDRSTRLEN+8]; 
     1246        pj_ice_sess_cand *cand = NULL; 
     1247        unsigned i; 
     1248 
     1249        /* Get allocation info */ 
     1250        pj_turn_sock_get_info(turn_sock, &rel_info); 
     1251 
     1252        /* Find relayed candidate in the component */ 
     1253        for (i=0; i<comp->cand_cnt; ++i) { 
     1254            if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_RELAYED) { 
     1255                cand = &comp->cand_list[i]; 
     1256                break; 
     1257            } 
     1258        } 
     1259        pj_assert(cand != NULL); 
     1260 
     1261        /* Update candidate */ 
     1262        pj_sockaddr_cp(&cand->addr, &rel_info.relay_addr); 
     1263        pj_sockaddr_cp(&cand->base_addr, &rel_info.relay_addr); 
     1264        pj_sockaddr_cp(&cand->rel_addr, &rel_info.mapped_addr); 
     1265        pj_ice_calc_foundation(comp->ice_st->pool, &cand->foundation,  
     1266                               PJ_ICE_CAND_TYPE_RELAYED,  
     1267                               &rel_info.relay_addr); 
     1268        cand->status = PJ_SUCCESS; 
    11421269 
    11431270        PJ_LOG(4,(comp->ice_st->obj_name,  
    1144                   "STUN Binding request has timed-out, will retry " 
    1145                   "again alter")); 
    1146  
    1147         /* Restart keep-alive timer */ 
    1148         start_ka_timer(comp->ice_st); 
    1149         return; 
    1150  
    1151     } else if (status != PJ_SUCCESS) { 
    1152         comp->last_status = cand->status = status; 
    1153         ice_st_perror(comp->ice_st, "STUN Binding request failed",  
    1154                       cand->status); 
    1155         return; 
    1156     } 
    1157  
    1158     xa = (pj_stun_xor_mapped_addr_attr*) 
    1159          pj_stun_msg_find_attr(response, PJ_STUN_ATTR_XOR_MAPPED_ADDR, 0); 
    1160     ma = (pj_stun_mapped_addr_attr*) 
    1161          pj_stun_msg_find_attr(response, PJ_STUN_ATTR_MAPPED_ADDR, 0); 
    1162  
    1163     if (xa) 
    1164         mapped_addr = &xa->sockaddr; 
    1165     else if (ma) 
    1166         mapped_addr = &ma->sockaddr; 
    1167     else { 
    1168         cand->status = PJNATH_ESTUNNOMAPPEDADDR; 
    1169         ice_st_perror(comp->ice_st, "STUN Binding request failed",  
    1170                       cand->status); 
    1171         return; 
    1172     } 
    1173  
    1174     /* Save IP address for logging */ 
    1175     pj_ansi_strcpy(ip, pj_inet_ntoa(comp->local_addr.ipv4.sin_addr)); 
    1176  
    1177     /* Ignore response if it reports the same address */ 
    1178     if (comp->local_addr.ipv4.sin_addr.s_addr == mapped_addr->ipv4.sin_addr.s_addr && 
    1179         comp->local_addr.ipv4.sin_port == mapped_addr->ipv4.sin_port) 
    1180     { 
    1181         PJ_LOG(4,(comp->ice_st->obj_name,  
    1182                   "Candidate %s:%d is directly connected to Internet, " 
    1183                   "STUN mapped address is ignored", 
    1184                   ip, pj_ntohs(comp->local_addr.ipv4.sin_port))); 
    1185         return; 
    1186     } 
    1187  
    1188     PJ_LOG(5,(comp->ice_st->obj_name,  
    1189               "STUN mapped address for %s:%d is %s:%d", 
    1190               ip, (int)pj_ntohs(comp->local_addr.ipv4.sin_port), 
    1191               pj_inet_ntoa(mapped_addr->ipv4.sin_addr), 
    1192               (int)pj_ntohs(mapped_addr->ipv4.sin_port))); 
    1193     pj_memcpy(&cand->addr, mapped_addr, sizeof(pj_sockaddr_in)); 
    1194     cand->status = PJ_SUCCESS; 
    1195  
    1196     /* Set this candidate as the default candidate */ 
    1197     comp->default_cand = (cand - comp->cand_list); 
    1198     comp->last_status = PJ_SUCCESS; 
    1199  
    1200     /* We have STUN, so we must start the keep-alive timer */ 
    1201     start_ka_timer(comp->ice_st); 
    1202  
    1203     /* Notify app that STUN address has changed. */ 
    1204     if (comp->ice_st->cb.on_addr_change) 
    1205         (*comp->ice_st->cb.on_addr_change)(comp->ice_st, comp->comp_id,  
    1206                                            (cand - comp->cand_list)); 
    1207 } 
    1208  
     1271                  "Comp %d: TURN allocation complete, relay address is %s", 
     1272                  comp->comp_id,  
     1273                  pj_sockaddr_print(&rel_info.relay_addr, ipaddr,  
     1274                                     sizeof(ipaddr), 3))); 
     1275 
     1276        sess_init_update(comp->ice_st); 
     1277 
     1278    } else if (new_state >= PJ_TURN_STATE_DEALLOCATING) { 
     1279        pj_turn_session_info info; 
     1280 
     1281        pj_turn_sock_get_info(turn_sock, &info); 
     1282 
     1283        /* Unregister ourself from the TURN relay */ 
     1284        pj_turn_sock_set_user_data(turn_sock, NULL); 
     1285        comp->turn_sock = NULL; 
     1286 
     1287        /* Set session to fail if we're still initializing */ 
     1288        if (old_state < PJ_TURN_STATE_READY) { 
     1289            sess_fail(comp->ice_st, PJ_ICE_STRANS_OP_INIT, 
     1290                      "TURN relay failed", info.last_status); 
     1291        } 
     1292    } 
     1293 
     1294    sess_dec_ref(comp->ice_st); 
     1295} 
     1296 
Note: See TracChangeset for help on using the changeset viewer.