Ignore:
Timestamp:
Jun 8, 2016 3:17:45 AM (8 years ago)
Author:
nanang
Message:

Re #422: Added IPv6 support to PJNATH, changes:

  • Deprecated 'pj_ice_strans_cfg.af', if set, the value will be ignored, address family setting is now specified via transport setting, i.e: 'pj_ice_strans_cfg.stun_tp/turn_tp'.
  • Deprecated 'pj_ice_strans_cfg.stun/turn', for backward compatibility, this field value will be checked if 'pj_ice_strans_cfg.stun_tp_cnt/turn_tp_cnt' is set to zero.
  • Added 'pj_ice_strans_stun_cfg' & 'pj_ice_strans_stun_cfg' and the corresponding 'pj_ice_strans_stun/turn_cfg_default()'
  • Added 'pj_ice_strans_cfg.stun_tp/turn_tp' as replacement of 'pj_ice_strans_cfg.stun/turn', it is now an array so app can have multiple STUN/TURN transports.
  • Added macro PJ_ICE_MAX_STUN/TURN to specify maximum number of STUN/TURN transports in each ICE component in compile-time.
  • Miscellaneous: fixed socket number limit in concurrency test in pjnath-test, updated pjsua_media.c to use new 'pj_ice_strans_cfg' setting.
File:
1 edited

Legend:

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

    r5282 r5339  
    4949}; 
    5050 
     51 
     52#define CREATE_TP_ID(type, idx)     (pj_uint8_t)((type << 6) | idx) 
     53#define GET_TP_TYPE(transport_id)   ((transport_id & 0xC0) >> 6) 
     54#define GET_TP_IDX(transport_id)    (transport_id & 0x3F) 
     55 
     56 
    5157/* Candidate's local preference values. This is mostly used to 
    5258 * specify preference among candidates with the same type. Since 
     
    149155    unsigned             comp_id;       /**< Component ID.              */ 
    150156 
    151     pj_stun_sock        *stun_sock;     /**< STUN transport.            */ 
    152     pj_turn_sock        *turn_sock;     /**< TURN relay transport.      */ 
    153     pj_bool_t            turn_log_off;  /**< TURN loggin off?           */ 
    154     unsigned             turn_err_cnt;  /**< TURN disconnected count.   */ 
     157    struct { 
     158        pj_stun_sock    *sock;          /**< STUN transport.            */ 
     159    } stun[PJ_ICE_MAX_STUN]; 
     160 
     161    struct { 
     162        pj_turn_sock    *sock;          /**< TURN relay transport.      */ 
     163        pj_bool_t        log_off;       /**< TURN loggin off?           */ 
     164        unsigned         err_cnt;       /**< TURN disconnected count.   */ 
     165    } turn[PJ_ICE_MAX_TURN]; 
    155166 
    156167    unsigned             cand_cnt;      /**< # of candidates/aliaes.    */ 
     
    188199 
    189200 
     201/** 
     202 * This structure describe user data for STUN/TURN sockets of the 
     203 * ICE stream transport. 
     204 */ 
     205typedef struct sock_user_data 
     206{ 
     207    pj_ice_strans_comp      *comp; 
     208    pj_uint8_t               transport_id; 
     209 
     210} sock_user_data; 
     211 
     212 
    190213/* Validate configuration */ 
    191214static pj_status_t pj_ice_strans_cfg_check_valid(const pj_ice_strans_cfg *cfg) 
     
    209232 
    210233    pj_stun_config_init(&cfg->stun_cfg, NULL, 0, NULL, NULL); 
    211     pj_stun_sock_cfg_default(&cfg->stun.cfg); 
    212     pj_turn_alloc_param_default(&cfg->turn.alloc_param); 
    213     pj_turn_sock_cfg_default(&cfg->turn.cfg); 
    214  
     234    pj_ice_strans_stun_cfg_default(&cfg->stun); 
     235    pj_ice_strans_turn_cfg_default(&cfg->turn); 
    215236    pj_ice_sess_options_default(&cfg->opt); 
     237} 
     238 
     239 
     240/* 
     241 * Initialize ICE STUN transport configuration with default values. 
     242 */ 
     243PJ_DEF(void) pj_ice_strans_stun_cfg_default(pj_ice_strans_stun_cfg *cfg) 
     244{ 
     245    pj_bzero(cfg, sizeof(*cfg)); 
    216246 
    217247    cfg->af = pj_AF_INET(); 
    218     cfg->stun.port = PJ_STUN_PORT; 
    219     cfg->turn.conn_type = PJ_TURN_TP_UDP; 
    220  
    221     cfg->stun.max_host_cands = 64; 
    222     cfg->stun.ignore_stun_error = PJ_FALSE; 
     248    cfg->port = PJ_STUN_PORT; 
     249    cfg->max_host_cands = 64; 
     250    cfg->ignore_stun_error = PJ_FALSE; 
     251    pj_stun_sock_cfg_default(&cfg->cfg); 
     252} 
     253 
     254 
     255/* 
     256 * Initialize ICE TURN transport configuration with default values. 
     257 */ 
     258PJ_DEF(void) pj_ice_strans_turn_cfg_default(pj_ice_strans_turn_cfg *cfg) 
     259{ 
     260    pj_bzero(cfg, sizeof(*cfg)); 
     261 
     262    cfg->af = pj_AF_INET(); 
     263    cfg->conn_type = PJ_TURN_TP_UDP; 
     264    pj_turn_alloc_param_default(&cfg->alloc_param); 
     265    pj_turn_sock_cfg_default(&cfg->cfg); 
    223266} 
    224267 
     
    231274                                     const pj_ice_strans_cfg *src) 
    232275{ 
     276    unsigned i; 
     277 
    233278    pj_memcpy(dst, src, sizeof(*src)); 
    234279 
    235280    if (src->stun.server.slen) 
    236281        pj_strdup(pool, &dst->stun.server, &src->stun.server); 
     282 
     283    for (i = 0; i < src->stun_tp_cnt; ++i) { 
     284        if (src->stun_tp[i].server.slen) 
     285            pj_strdup(pool, &dst->stun_tp[i].server, 
     286                      &src->stun_tp[i].server); 
     287    } 
     288 
    237289    if (src->turn.server.slen) 
    238290        pj_strdup(pool, &dst->turn.server, &src->turn.server); 
    239     pj_stun_auth_cred_dup(pool, &dst->turn.auth_cred, 
    240                           &src->turn.auth_cred); 
     291    pj_stun_auth_cred_dup(pool, &dst->turn.auth_cred, &src->turn.auth_cred); 
     292 
     293    for (i = 0; i < src->turn_tp_cnt; ++i) { 
     294        if (src->turn_tp[i].server.slen) 
     295            pj_strdup(pool, &dst->turn_tp[i].server, 
     296                      &src->turn_tp[i].server); 
     297        pj_stun_auth_cred_dup(pool, &dst->turn_tp[i].auth_cred, 
     298                              &src->turn_tp[i].auth_cred); 
     299    } 
    241300} 
    242301 
     
    246305 */ 
    247306static pj_status_t add_update_turn(pj_ice_strans *ice_st, 
    248                                    pj_ice_strans_comp *comp) 
    249 { 
     307                                   pj_ice_strans_comp *comp, 
     308                                   unsigned idx) 
     309{ 
     310    pj_ice_sess_cand *cand = NULL; 
     311    pj_ice_strans_turn_cfg *turn_cfg = &ice_st->cfg.turn_tp[idx]; 
     312    pj_turn_sock_cfg *sock_cfg  = &turn_cfg->cfg; 
     313    unsigned comp_idx = comp->comp_id - 1; 
    250314    pj_turn_sock_cb turn_sock_cb; 
    251     pj_ice_sess_cand *cand = NULL; 
     315    sock_user_data *data; 
    252316    unsigned i; 
     317    pj_uint8_t tp_id; 
    253318    pj_status_t status; 
    254319 
     320    /* Check if TURN transport is configured */ 
     321    if (turn_cfg->server.slen == 0) 
     322        return PJ_SUCCESS; 
     323 
    255324    /* Find relayed candidate in the component */ 
     325    tp_id = CREATE_TP_ID(TP_TURN, idx); 
    256326    for (i=0; i<comp->cand_cnt; ++i) { 
    257         if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_RELAYED) { 
     327        if (comp->cand_list[i].transport_id == tp_id) { 
    258328            cand = &comp->cand_list[i]; 
    259329            break; 
     
    287357 
    288358    /* Override with component specific QoS settings, if any */ 
    289     if (ice_st->cfg.comp[comp->comp_id-1].qos_type) { 
    290         ice_st->cfg.turn.cfg.qos_type = 
    291             ice_st->cfg.comp[comp->comp_id-1].qos_type; 
    292     } 
    293     if (ice_st->cfg.comp[comp->comp_id-1].qos_params.flags) { 
    294         pj_memcpy(&ice_st->cfg.turn.cfg.qos_params, 
    295                   &ice_st->cfg.comp[comp->comp_id-1].qos_params, 
    296                   sizeof(ice_st->cfg.turn.cfg.qos_params)); 
    297     } 
     359    if (ice_st->cfg.comp[comp_idx].qos_type) 
     360        sock_cfg->qos_type = ice_st->cfg.comp[comp_idx].qos_type; 
     361    if (ice_st->cfg.comp[comp_idx].qos_params.flags) 
     362        pj_memcpy(&sock_cfg->qos_params, 
     363                  &ice_st->cfg.comp[comp_idx].qos_params, 
     364                  sizeof(sock_cfg->qos_params)); 
    298365 
    299366    /* Override with component specific socket buffer size settings, if any */ 
    300     if (ice_st->cfg.comp[comp->comp_id-1].so_rcvbuf_size > 0) { 
    301         ice_st->cfg.turn.cfg.so_rcvbuf_size = 
    302             ice_st->cfg.comp[comp->comp_id-1].so_rcvbuf_size; 
    303     } 
    304     if (ice_st->cfg.comp[comp->comp_id-1].so_sndbuf_size > 0) { 
    305         ice_st->cfg.turn.cfg.so_sndbuf_size = 
    306             ice_st->cfg.comp[comp->comp_id-1].so_sndbuf_size; 
    307     } 
     367    if (ice_st->cfg.comp[comp_idx].so_rcvbuf_size > 0) 
     368        sock_cfg->so_rcvbuf_size = ice_st->cfg.comp[comp_idx].so_rcvbuf_size; 
     369    if (ice_st->cfg.comp[comp_idx].so_sndbuf_size > 0) 
     370        sock_cfg->so_sndbuf_size = ice_st->cfg.comp[comp_idx].so_sndbuf_size; 
     371 
     372    /* Add relayed candidate with pending status if there's no existing one */ 
     373    if (cand == NULL) { 
     374        cand = &comp->cand_list[comp->cand_cnt]; 
     375        cand->type = PJ_ICE_CAND_TYPE_RELAYED; 
     376        cand->status = PJ_EPENDING; 
     377        cand->local_pref = RELAY_PREF; 
     378        cand->transport_id = CREATE_TP_ID(TP_TURN, idx); 
     379        cand->comp_id = (pj_uint8_t) comp->comp_id; 
     380    } 
     381 
     382    /* Allocate and initialize TURN socket data */ 
     383    data = PJ_POOL_ZALLOC_T(ice_st->pool, sock_user_data); 
     384    data->comp = comp; 
     385    data->transport_id = cand->transport_id; 
    308386 
    309387    /* Create the TURN transport */ 
    310     status = pj_turn_sock_create(&ice_st->cfg.stun_cfg, ice_st->cfg.af, 
    311                                  ice_st->cfg.turn.conn_type, 
    312                                  &turn_sock_cb, &ice_st->cfg.turn.cfg, 
    313                                  comp, &comp->turn_sock); 
     388    status = pj_turn_sock_create(&ice_st->cfg.stun_cfg, turn_cfg->af, 
     389                                 turn_cfg->conn_type, 
     390                                 &turn_sock_cb, sock_cfg, 
     391                                 data, &comp->turn[idx].sock); 
    314392    if (status != PJ_SUCCESS) { 
    315393        return status; 
     
    320398 
    321399    /* Start allocation */ 
    322     status=pj_turn_sock_alloc(comp->turn_sock, 
    323                               &ice_st->cfg.turn.server, 
    324                               ice_st->cfg.turn.port, 
     400    status=pj_turn_sock_alloc(comp->turn[idx].sock, 
     401                              &turn_cfg->server, 
     402                              turn_cfg->port, 
    325403                              ice_st->cfg.resolver, 
    326                               &ice_st->cfg.turn.auth_cred, 
    327                               &ice_st->cfg.turn.alloc_param); 
     404                              &turn_cfg->auth_cred, 
     405                              &turn_cfg->alloc_param); 
    328406    if (status != PJ_SUCCESS) { 
    329407        ///sess_dec_ref(ice_st); 
     
    331409    } 
    332410 
    333     /* Add relayed candidate with pending status if there's no existing one */ 
    334     if (cand == NULL) { 
    335         cand = &comp->cand_list[comp->cand_cnt++]; 
    336         cand->type = PJ_ICE_CAND_TYPE_RELAYED; 
    337         cand->status = PJ_EPENDING; 
    338         cand->local_pref = RELAY_PREF; 
    339         cand->transport_id = TP_TURN; 
    340         cand->comp_id = (pj_uint8_t) comp->comp_id; 
    341     } 
     411    /* Commit the relayed candidate. */ 
     412    comp->cand_cnt++; 
    342413 
    343414    PJ_LOG(4,(ice_st->obj_name, 
     
    373444} 
    374445 
     446 
     447static pj_status_t add_stun_and_host(pj_ice_strans *ice_st, 
     448                                     pj_ice_strans_comp *comp, 
     449                                     unsigned idx) 
     450{ 
     451    pj_ice_sess_cand *cand; 
     452    pj_ice_strans_stun_cfg *stun_cfg = &ice_st->cfg.stun_tp[idx]; 
     453    pj_stun_sock_cfg *sock_cfg  = &stun_cfg->cfg; 
     454    unsigned comp_idx = comp->comp_id - 1; 
     455    pj_stun_sock_cb stun_sock_cb; 
     456    sock_user_data *data; 
     457    pj_status_t status; 
     458 
     459    /* Check if STUN transport or host candidate is configured */ 
     460    if (stun_cfg->server.slen == 0 && stun_cfg->max_host_cands == 0) 
     461        return PJ_SUCCESS; 
     462 
     463    /* Initialize STUN socket callback */ 
     464    pj_bzero(&stun_sock_cb, sizeof(stun_sock_cb)); 
     465    stun_sock_cb.on_rx_data = &stun_on_rx_data; 
     466    stun_sock_cb.on_status = &stun_on_status; 
     467    stun_sock_cb.on_data_sent = &stun_on_data_sent; 
     468 
     469    /* Override component specific QoS settings, if any */ 
     470    if (ice_st->cfg.comp[comp_idx].qos_type) { 
     471        sock_cfg->qos_type = ice_st->cfg.comp[comp_idx].qos_type; 
     472    } 
     473    if (ice_st->cfg.comp[comp_idx].qos_params.flags) { 
     474        pj_memcpy(&sock_cfg->qos_params, 
     475                  &ice_st->cfg.comp[comp_idx].qos_params, 
     476                  sizeof(sock_cfg->qos_params)); 
     477    } 
     478 
     479    /* Override component specific socket buffer size settings, if any */ 
     480    if (ice_st->cfg.comp[comp_idx].so_rcvbuf_size > 0) { 
     481        sock_cfg->so_rcvbuf_size = ice_st->cfg.comp[comp_idx].so_rcvbuf_size; 
     482    } 
     483    if (ice_st->cfg.comp[comp_idx].so_sndbuf_size > 0) { 
     484        sock_cfg->so_sndbuf_size = ice_st->cfg.comp[comp_idx].so_sndbuf_size; 
     485    } 
     486 
     487    /* Prepare srflx candidate with pending status. */ 
     488    cand = &comp->cand_list[comp->cand_cnt]; 
     489    cand->type = PJ_ICE_CAND_TYPE_SRFLX; 
     490    cand->status = PJ_EPENDING; 
     491    cand->local_pref = SRFLX_PREF; 
     492    cand->transport_id = CREATE_TP_ID(TP_STUN, idx); 
     493    cand->comp_id = (pj_uint8_t) comp->comp_id; 
     494 
     495    /* Allocate and initialize STUN socket data */ 
     496    data = PJ_POOL_ZALLOC_T(ice_st->pool, sock_user_data); 
     497    data->comp = comp; 
     498    data->transport_id = cand->transport_id; 
     499 
     500    /* Create the STUN transport */ 
     501    status = pj_stun_sock_create(&ice_st->cfg.stun_cfg, NULL, 
     502                                 stun_cfg->af, &stun_sock_cb, 
     503                                 sock_cfg, data, &comp->stun[idx].sock); 
     504    if (status != PJ_SUCCESS) 
     505        return status; 
     506 
     507    /* Start STUN Binding resolution and add srflx candidate 
     508     * only if server is set 
     509     */ 
     510    if (stun_cfg->server.slen) { 
     511        pj_stun_sock_info stun_sock_info; 
     512 
     513        /* Add pending job */ 
     514        ///sess_add_ref(ice_st); 
     515 
     516        PJ_LOG(4,(ice_st->obj_name, 
     517                  "Comp %d: srflx candidate starts Binding discovery", 
     518                  comp->comp_id)); 
     519 
     520        pj_log_push_indent(); 
     521 
     522        /* Start Binding resolution */ 
     523        status = pj_stun_sock_start(comp->stun[idx].sock, &stun_cfg->server, 
     524                                    stun_cfg->port, ice_st->cfg.resolver); 
     525        if (status != PJ_SUCCESS) { 
     526            ///sess_dec_ref(ice_st); 
     527            pj_log_pop_indent(); 
     528            return status; 
     529        } 
     530 
     531        /* Enumerate addresses */ 
     532        status = pj_stun_sock_get_info(comp->stun[idx].sock, &stun_sock_info); 
     533        if (status != PJ_SUCCESS) { 
     534            ///sess_dec_ref(ice_st); 
     535            pj_log_pop_indent(); 
     536            return status; 
     537        } 
     538 
     539        /* Update and commit the srflx candidate. */ 
     540        pj_sockaddr_cp(&cand->base_addr, &stun_sock_info.aliases[0]); 
     541        pj_sockaddr_cp(&cand->rel_addr, &cand->base_addr); 
     542        pj_ice_calc_foundation(ice_st->pool, &cand->foundation, 
     543                               cand->type, &cand->base_addr); 
     544        comp->cand_cnt++; 
     545 
     546        /* Set default candidate to srflx */ 
     547        comp->default_cand = (unsigned)(cand - comp->cand_list); 
     548 
     549        pj_log_pop_indent(); 
     550    } 
     551 
     552    /* Add local addresses to host candidates, unless max_host_cands 
     553     * is set to zero. 
     554     */ 
     555    if (stun_cfg->max_host_cands) { 
     556        pj_stun_sock_info stun_sock_info; 
     557        unsigned i; 
     558 
     559        /* Enumerate addresses */ 
     560        status = pj_stun_sock_get_info(comp->stun[idx].sock, &stun_sock_info); 
     561        if (status != PJ_SUCCESS) 
     562            return status; 
     563 
     564        for (i=0; i<stun_sock_info.alias_cnt && 
     565                  i<stun_cfg->max_host_cands; ++i) 
     566        { 
     567            unsigned j; 
     568            pj_bool_t cand_duplicate = PJ_FALSE; 
     569            char addrinfo[PJ_INET6_ADDRSTRLEN+10]; 
     570            const pj_sockaddr *addr = &stun_sock_info.aliases[i]; 
     571 
     572            /* Leave one candidate for relay */ 
     573            if (comp->cand_cnt >= PJ_ICE_ST_MAX_CAND-1) { 
     574                PJ_LOG(4,(ice_st->obj_name, "Too many host candidates")); 
     575                break; 
     576            } 
     577 
     578            /* Ignore loopback addresses if cfg->stun.loop_addr is unset */ 
     579            if (stun_cfg->loop_addr==PJ_FALSE) { 
     580                if (stun_cfg->af == pj_AF_INET() &&  
     581                    (pj_ntohl(addr->ipv4.sin_addr.s_addr)>>24)==127) 
     582                { 
     583                    continue; 
     584                } 
     585                else if (stun_cfg->af == pj_AF_INET6()) { 
     586                    pj_in6_addr in6addr = {0}; 
     587                    in6addr.s6_addr[15] = 1; 
     588                    if (pj_memcmp(&in6addr, &addr->ipv6.sin6_addr, 
     589                                  sizeof(in6addr))==0) 
     590                    { 
     591                        continue; 
     592                    } 
     593                } 
     594            } 
     595 
     596            cand = &comp->cand_list[comp->cand_cnt]; 
     597 
     598            cand->type = PJ_ICE_CAND_TYPE_HOST; 
     599            cand->status = PJ_SUCCESS; 
     600            cand->local_pref = HOST_PREF; 
     601            cand->transport_id = CREATE_TP_ID(TP_STUN, idx); 
     602            cand->comp_id = (pj_uint8_t) comp->comp_id; 
     603            pj_sockaddr_cp(&cand->addr, addr); 
     604            pj_sockaddr_cp(&cand->base_addr, addr); 
     605            pj_bzero(&cand->rel_addr, sizeof(cand->rel_addr)); 
     606             
     607            /* Check if not already in list */ 
     608            for (j=0; j<comp->cand_cnt; j++) { 
     609                if (ice_cand_equals(cand, &comp->cand_list[j])) { 
     610                    cand_duplicate = PJ_TRUE; 
     611                    break; 
     612                } 
     613            } 
     614 
     615            if (cand_duplicate) { 
     616                PJ_LOG(4, (ice_st->obj_name, 
     617                       "Comp %d: host candidate %s is a duplicate", 
     618                       comp->comp_id, pj_sockaddr_print(&cand->addr, addrinfo, 
     619                       sizeof(addrinfo), 3))); 
     620 
     621                pj_bzero(&cand->addr, sizeof(cand->addr)); 
     622                pj_bzero(&cand->base_addr, sizeof(cand->base_addr)); 
     623                continue; 
     624            } else { 
     625                comp->cand_cnt+=1; 
     626            } 
     627             
     628            pj_ice_calc_foundation(ice_st->pool, &cand->foundation, 
     629                                   cand->type, &cand->base_addr); 
     630 
     631            PJ_LOG(4,(ice_st->obj_name, 
     632                      "Comp %d: host candidate %s added", 
     633                      comp->comp_id, pj_sockaddr_print(&cand->addr, addrinfo, 
     634                                                      sizeof(addrinfo), 3))); 
     635        } 
     636    } 
     637 
     638    return PJ_SUCCESS; 
     639} 
     640 
     641 
    375642/* 
    376643 * Create the component. 
     
    379646{ 
    380647    pj_ice_strans_comp *comp = NULL; 
     648    unsigned i; 
    381649    pj_status_t status; 
    382650 
     
    398666 
    399667    /* Create STUN transport if configured */ 
    400     if (ice_st->cfg.stun.server.slen || ice_st->cfg.stun.max_host_cands) { 
    401         pj_stun_sock_cb stun_sock_cb; 
    402         pj_ice_sess_cand *cand; 
    403  
    404         pj_bzero(&stun_sock_cb, sizeof(stun_sock_cb)); 
    405         stun_sock_cb.on_rx_data = &stun_on_rx_data; 
    406         stun_sock_cb.on_status = &stun_on_status; 
    407         stun_sock_cb.on_data_sent = &stun_on_data_sent; 
    408  
    409         /* Override component specific QoS settings, if any */ 
    410         if (ice_st->cfg.comp[comp_id-1].qos_type) { 
    411             ice_st->cfg.stun.cfg.qos_type = 
    412                 ice_st->cfg.comp[comp_id-1].qos_type; 
    413         } 
    414         if (ice_st->cfg.comp[comp_id-1].qos_params.flags) { 
    415             pj_memcpy(&ice_st->cfg.stun.cfg.qos_params, 
    416                       &ice_st->cfg.comp[comp_id-1].qos_params, 
    417                       sizeof(ice_st->cfg.stun.cfg.qos_params)); 
    418         } 
    419  
    420         /* Override component specific socket buffer size settings, if any */ 
    421         if (ice_st->cfg.comp[comp_id-1].so_rcvbuf_size > 0) { 
    422             ice_st->cfg.stun.cfg.so_rcvbuf_size = 
    423                 ice_st->cfg.comp[comp_id-1].so_rcvbuf_size; 
    424         } 
    425         if (ice_st->cfg.comp[comp_id-1].so_sndbuf_size > 0) { 
    426             ice_st->cfg.stun.cfg.so_sndbuf_size = 
    427                 ice_st->cfg.comp[comp_id-1].so_sndbuf_size; 
    428         } 
    429  
    430         /* Create the STUN transport */ 
    431         status = pj_stun_sock_create(&ice_st->cfg.stun_cfg, NULL, 
    432                                      ice_st->cfg.af, &stun_sock_cb, 
    433                                      &ice_st->cfg.stun.cfg, 
    434                                      comp, &comp->stun_sock); 
     668    for (i=0; i<ice_st->cfg.stun_tp_cnt; ++i) { 
     669        status = add_stun_and_host(ice_st, comp, i); 
    435670        if (status != PJ_SUCCESS) 
    436671            return status; 
    437  
    438         /* Start STUN Binding resolution and add srflx candidate 
    439          * only if server is set 
    440          */ 
    441         if (ice_st->cfg.stun.server.slen) { 
    442             pj_stun_sock_info stun_sock_info; 
    443  
    444             /* Add pending job */ 
    445             ///sess_add_ref(ice_st); 
    446  
    447             PJ_LOG(4,(ice_st->obj_name, 
    448                       "Comp %d: srflx candidate starts Binding discovery", 
    449                       comp_id)); 
    450  
    451             pj_log_push_indent(); 
    452  
    453             /* Start Binding resolution */ 
    454             status = pj_stun_sock_start(comp->stun_sock, 
    455                                         &ice_st->cfg.stun.server, 
    456                                         ice_st->cfg.stun.port, 
    457                                         ice_st->cfg.resolver); 
    458             if (status != PJ_SUCCESS) { 
    459                 ///sess_dec_ref(ice_st); 
    460                 pj_log_pop_indent(); 
    461                 return status; 
    462             } 
    463  
    464             /* Enumerate addresses */ 
    465             status = pj_stun_sock_get_info(comp->stun_sock, &stun_sock_info); 
    466             if (status != PJ_SUCCESS) { 
    467                 ///sess_dec_ref(ice_st); 
    468                 pj_log_pop_indent(); 
    469                 return status; 
    470             } 
    471  
    472             /* Add srflx candidate with pending status. */ 
    473             cand = &comp->cand_list[comp->cand_cnt++]; 
    474             cand->type = PJ_ICE_CAND_TYPE_SRFLX; 
    475             cand->status = PJ_EPENDING; 
    476             cand->local_pref = SRFLX_PREF; 
    477             cand->transport_id = TP_STUN; 
    478             cand->comp_id = (pj_uint8_t) comp_id; 
    479             pj_sockaddr_cp(&cand->base_addr, &stun_sock_info.aliases[0]); 
    480             pj_sockaddr_cp(&cand->rel_addr, &cand->base_addr); 
    481             pj_ice_calc_foundation(ice_st->pool, &cand->foundation, 
    482                                    cand->type, &cand->base_addr); 
    483  
    484             /* Set default candidate to srflx */ 
    485             comp->default_cand = (unsigned)(cand - comp->cand_list); 
    486  
    487             pj_log_pop_indent(); 
    488         } 
    489  
    490         /* Add local addresses to host candidates, unless max_host_cands 
    491          * is set to zero. 
    492          */ 
    493         if (ice_st->cfg.stun.max_host_cands) { 
    494             pj_stun_sock_info stun_sock_info; 
    495             unsigned i; 
    496  
    497             /* Enumerate addresses */ 
    498             status = pj_stun_sock_get_info(comp->stun_sock, &stun_sock_info); 
    499             if (status != PJ_SUCCESS) 
    500                 return status; 
    501  
    502             for (i=0; i<stun_sock_info.alias_cnt && 
    503                       i<ice_st->cfg.stun.max_host_cands; ++i) 
    504             { 
    505                 unsigned j; 
    506                 pj_bool_t cand_duplicate = PJ_FALSE; 
    507                 char addrinfo[PJ_INET6_ADDRSTRLEN+10]; 
    508                 const pj_sockaddr *addr = &stun_sock_info.aliases[i]; 
    509  
    510                 /* Leave one candidate for relay */ 
    511                 if (comp->cand_cnt >= PJ_ICE_ST_MAX_CAND-1) { 
    512                     PJ_LOG(4,(ice_st->obj_name, "Too many host candidates")); 
    513                     break; 
    514                 } 
    515  
    516                 /* Ignore loopback addresses unless cfg->stun.loop_addr 
    517                  * is set 
    518                  */ 
    519                 if ((pj_ntohl(addr->ipv4.sin_addr.s_addr)>>24)==127) { 
    520                     if (ice_st->cfg.stun.loop_addr==PJ_FALSE) 
    521                         continue; 
    522                 } 
    523  
    524                 cand = &comp->cand_list[comp->cand_cnt]; 
    525  
    526                 cand->type = PJ_ICE_CAND_TYPE_HOST; 
    527                 cand->status = PJ_SUCCESS; 
    528                 cand->local_pref = HOST_PREF; 
    529                 cand->transport_id = TP_STUN; 
    530                 cand->comp_id = (pj_uint8_t) comp_id; 
    531                 pj_sockaddr_cp(&cand->addr, addr); 
    532                 pj_sockaddr_cp(&cand->base_addr, addr); 
    533                 pj_bzero(&cand->rel_addr, sizeof(cand->rel_addr)); 
    534              
    535                 /* Check if not already in list */ 
    536                 for (j=0; j<comp->cand_cnt; j++) { 
    537                     if (ice_cand_equals(cand, &comp->cand_list[j])) { 
    538                         cand_duplicate = PJ_TRUE; 
    539                         break; 
    540                     } 
    541                 } 
    542  
    543                 if (cand_duplicate) { 
    544                     PJ_LOG(4, (ice_st->obj_name, 
    545                            "Comp %d: host candidate %s is a duplicate", 
    546                            comp_id, pj_sockaddr_print(&cand->addr, addrinfo, 
    547                            sizeof(addrinfo), 3))); 
    548  
    549                     pj_bzero(&cand->addr, sizeof(cand->addr)); 
    550                     pj_bzero(&cand->base_addr, sizeof(cand->base_addr)); 
    551                     continue; 
    552                 } else { 
    553                     comp->cand_cnt+=1; 
    554                 } 
    555              
    556                 pj_ice_calc_foundation(ice_st->pool, &cand->foundation, 
    557                                        cand->type, &cand->base_addr); 
    558  
    559                 PJ_LOG(4,(ice_st->obj_name, 
    560                           "Comp %d: host candidate %s added", 
    561                           comp_id, pj_sockaddr_print(&cand->addr, addrinfo, 
    562                                                      sizeof(addrinfo), 3))); 
    563             } 
    564         } 
    565672    } 
    566673 
    567674    /* Create TURN relay if configured. */ 
    568     if (ice_st->cfg.turn.server.slen) { 
    569         add_update_turn(ice_st, comp); 
     675    for (i=0; i<ice_st->cfg.turn_tp_cnt; ++i) { 
     676        status = add_update_turn(ice_st, comp, i); 
     677        if (status != PJ_SUCCESS) 
     678            return status; 
    570679    } 
    571680 
     
    630739 
    631740    pj_ice_strans_cfg_copy(pool, &ice_st->cfg, cfg); 
    632     ice_st->cfg.stun.cfg.grp_lock = ice_st->grp_lock; 
    633     ice_st->cfg.turn.cfg.grp_lock = ice_st->grp_lock; 
     741 
     742    /* To maintain backward compatibility, check if old/deprecated setting is set 
     743     * and the new setting is not, copy the value to the new setting. 
     744     */ 
     745    if (cfg->stun_tp_cnt == 0 &&  
     746        (cfg->stun.server.slen || cfg->stun.max_host_cands)) 
     747    { 
     748        ice_st->cfg.stun_tp_cnt = 1; 
     749        ice_st->cfg.stun_tp[0] = ice_st->cfg.stun; 
     750    } 
     751    if (cfg->turn_tp_cnt == 0 && cfg->turn.server.slen) { 
     752        ice_st->cfg.turn_tp_cnt = 1; 
     753        ice_st->cfg.turn_tp[0] = ice_st->cfg.turn; 
     754    } 
     755 
     756    for (i=0; i<ice_st->cfg.stun_tp_cnt; ++i) 
     757        ice_st->cfg.stun_tp[i].cfg.grp_lock = ice_st->grp_lock; 
     758    for (i=0; i<ice_st->cfg.turn_tp_cnt; ++i) 
     759        ice_st->cfg.turn_tp[i].cfg.grp_lock = ice_st->grp_lock; 
    634760    pj_memcpy(&ice_st->cb, cb, sizeof(*cb)); 
    635761 
     
    709835    for (i=0; i<ice_st->comp_cnt; ++i) { 
    710836        if (ice_st->comp[i]) { 
    711             if (ice_st->comp[i]->stun_sock) { 
    712                 pj_stun_sock_destroy(ice_st->comp[i]->stun_sock); 
    713                 ice_st->comp[i]->stun_sock = NULL; 
     837            pj_ice_strans_comp *comp = ice_st->comp[i]; 
     838            unsigned j; 
     839            for (j = 0; j < ice_st->cfg.stun_tp_cnt; ++j) { 
     840                if (comp->stun[j].sock) { 
     841                    pj_stun_sock_destroy(comp->stun[j].sock); 
     842                    comp->stun[j].sock = NULL; 
     843                } 
    714844            } 
    715             if (ice_st->comp[i]->turn_sock) { 
    716                 pj_turn_sock_destroy(ice_st->comp[i]->turn_sock); 
    717                 ice_st->comp[i]->turn_sock = NULL; 
     845            for (j = 0; j < ice_st->cfg.turn_tp_cnt; ++j) { 
     846                if (comp->turn[j].sock) { 
     847                    pj_turn_sock_destroy(comp->turn[j].sock); 
     848                    comp->turn[j].sock = NULL; 
     849                } 
    718850            } 
    719851        } 
     
    9121044 
    9131045        /* Re-enable logging for Send/Data indications */ 
    914         if (comp->turn_sock) { 
     1046        if (ice_st->cfg.turn_tp_cnt) { 
    9151047            PJ_LOG(5,(ice_st->obj_name, 
    916                       "Disabling STUN Indication logging for " 
     1048                      "Enabling STUN Indication logging for " 
    9171049                      "component %d", i+1)); 
    918             pj_turn_sock_set_log(comp->turn_sock, 0xFFFF); 
    919             comp->turn_log_off = PJ_FALSE; 
     1050        } 
     1051        for (j = 0; j < ice_st->cfg.turn_tp_cnt; ++j) { 
     1052            if (comp->turn[j].sock) { 
     1053                pj_turn_sock_set_log(comp->turn[j].sock, 0xFFFF); 
     1054                comp->turn[j].log_off = PJ_FALSE; 
     1055            } 
    9201056        } 
    9211057 
     
    11231259                                             const pj_ice_sess_cand rem_cand[]) 
    11241260{ 
     1261    unsigned n; 
    11251262    pj_status_t status; 
    11261263 
     
    11381275 
    11391276    /* If we have TURN candidate, now is the time to create the permissions */ 
    1140     if (ice_st->comp[0]->turn_sock) { 
     1277    for (n = 0; n < ice_st->cfg.turn_tp_cnt; ++n) { 
    11411278        unsigned i; 
    11421279 
     
    11481285            /* Gather remote addresses for this component */ 
    11491286            for (j=0; j<rem_cand_cnt && count<PJ_ARRAY_SIZE(addrs); ++j) { 
    1150                 if (rem_cand[j].comp_id==i+1) { 
    1151                     pj_memcpy(&addrs[count++], &rem_cand[j].addr, 
    1152                               pj_sockaddr_get_len(&rem_cand[j].addr)); 
     1287                if (rem_cand[j].comp_id==i+1 && 
     1288                    rem_cand[j].addr.addr.sa_family== 
     1289                    ice_st->cfg.turn_tp[n].af) 
     1290                { 
     1291                    pj_sockaddr_cp(&addrs[count++], &rem_cand[j].addr); 
    11531292                } 
    11541293            } 
    11551294 
    11561295            if (count) { 
    1157                 status = pj_turn_sock_set_perm(comp->turn_sock, count, 
     1296                status = pj_turn_sock_set_perm(comp->turn[n].sock, count, 
    11581297                                               addrs, 0); 
    11591298                if (status != PJ_SUCCESS) { 
     
    12281367{ 
    12291368    pj_ice_strans_comp *comp; 
    1230     unsigned def_cand; 
     1369    pj_ice_sess_cand *def_cand; 
    12311370    pj_status_t status; 
    12321371 
     
    12371376 
    12381377    /* Check that default candidate for the component exists */ 
    1239     def_cand = comp->default_cand; 
    1240     if (def_cand >= comp->cand_cnt) 
     1378    if (comp->default_cand >= comp->cand_cnt) 
    12411379        return PJ_EINVALIDOP; 
    12421380 
     
    12621400     
    12631401    pj_grp_lock_release(ice_st->grp_lock); 
     1402 
     1403    def_cand = &comp->cand_list[comp->default_cand]; 
    12641404     
    1265     if (comp->cand_list[def_cand].status == PJ_SUCCESS) { 
    1266  
    1267         if (comp->cand_list[def_cand].type == PJ_ICE_CAND_TYPE_RELAYED) { 
     1405    if (def_cand->status == PJ_SUCCESS) { 
     1406        unsigned tp_idx = GET_TP_IDX(def_cand->transport_id); 
     1407 
     1408        if (def_cand->type == PJ_ICE_CAND_TYPE_RELAYED) { 
    12681409 
    12691410            enum { 
     
    12741415 
    12751416            /* https://trac.pjsip.org/repos/ticket/1316 */ 
    1276             if (comp->turn_sock == NULL) { 
     1417            if (comp->turn[tp_idx].sock == NULL) { 
    12771418                /* TURN socket error */ 
    12781419                return PJ_EINVALIDOP; 
    12791420            } 
    12801421 
    1281             if (!comp->turn_log_off) { 
     1422            if (!comp->turn[tp_idx].log_off) { 
    12821423                /* Disable logging for Send/Data indications */ 
    12831424                PJ_LOG(5,(ice_st->obj_name, 
    12841425                          "Disabling STUN Indication logging for " 
    12851426                          "component %d", comp->comp_id)); 
    1286                 pj_turn_sock_set_log(comp->turn_sock, msg_disable_ind); 
    1287                 comp->turn_log_off = PJ_TRUE; 
     1427                pj_turn_sock_set_log(comp->turn[tp_idx].sock, 
     1428                                     msg_disable_ind); 
     1429                comp->turn[tp_idx].log_off = PJ_TRUE; 
    12881430            } 
    12891431 
    1290             status = pj_turn_sock_sendto(comp->turn_sock, 
     1432            status = pj_turn_sock_sendto(comp->turn[tp_idx].sock, 
    12911433                                         (const pj_uint8_t*)data, 
    12921434                                         (unsigned)data_len, 
     
    12951437                    PJ_SUCCESS : status; 
    12961438        } else { 
    1297             status = pj_stun_sock_sendto(comp->stun_sock, NULL, data, 
     1439            status = pj_stun_sock_sendto(comp->stun[tp_idx].sock, NULL, data, 
    12981440                                         (unsigned)data_len, 0, dst_addr, 
    12991441                                         dst_addr_len); 
     
    13431485            for (i=0; i<ice_st->comp_cnt; ++i) { 
    13441486                const pj_ice_sess_check *check; 
     1487                pj_ice_strans_comp *comp = ice_st->comp[i]; 
    13451488 
    13461489                check = pj_ice_strans_get_valid_pair(ice_st, i+1); 
     
    13481491                    char lip[PJ_INET6_ADDRSTRLEN+10]; 
    13491492                    char rip[PJ_INET6_ADDRSTRLEN+10]; 
     1493                    unsigned tp_idx = GET_TP_IDX(check->lcand->transport_id); 
     1494                    unsigned tp_typ = GET_TP_TYPE(check->lcand->transport_id); 
    13501495 
    13511496                    pj_sockaddr_print(&check->lcand->addr, lip, 
     
    13541499                                      sizeof(rip), 3); 
    13551500 
    1356                     if (check->lcand->transport_id == TP_TURN) { 
     1501                    if (tp_typ == TP_TURN) { 
    13571502                        /* Activate channel binding for the remote address 
    13581503                         * for more efficient data transfer using TURN. 
    13591504                         */ 
    13601505                        status = pj_turn_sock_bind_channel( 
    1361                                         ice_st->comp[i]->turn_sock, 
     1506                                        comp->turn[tp_idx].sock, 
    13621507                                        &check->rcand->addr, 
    13631508                                        sizeof(check->rcand->addr)); 
     
    13671512                                  "Disabling STUN Indication logging for " 
    13681513                                  "component %d", i+1)); 
    1369                         pj_turn_sock_set_log(ice_st->comp[i]->turn_sock, 
     1514                        pj_turn_sock_set_log(comp->turn[tp_idx].sock, 
    13701515                                             msg_disable_ind); 
    1371                         ice_st->comp[i]->turn_log_off = PJ_TRUE; 
     1516                        comp->turn[tp_idx].log_off = PJ_TRUE; 
    13721517                    } 
    13731518 
     
    14171562    char daddr[PJ_INET6_ADDRSTRLEN]; 
    14181563#endif 
     1564    unsigned tp_idx = GET_TP_IDX(transport_id); 
     1565    unsigned tp_typ = GET_TP_TYPE(transport_id); 
    14191566 
    14201567    PJ_ASSERT_RETURN(comp_id && comp_id <= ice_st->comp_cnt, PJ_EINVAL); 
     
    14271574               pj_sockaddr_print(dst_addr, daddr, sizeof(addr), 0), 
    14281575               pj_sockaddr_get_port(dst_addr), 
    1429                transport_id)); 
    1430  
    1431     if (transport_id == TP_TURN) { 
    1432         if (comp->turn_sock) { 
    1433             status = pj_turn_sock_sendto(comp->turn_sock, 
     1576               tp_typ)); 
     1577 
     1578    if (tp_typ == TP_TURN) { 
     1579        if (comp->turn[tp_idx].sock) { 
     1580            status = pj_turn_sock_sendto(comp->turn[tp_idx].sock, 
    14341581                                         (const pj_uint8_t*)pkt, 
    14351582                                         (unsigned)size, 
     
    14381585            status = PJ_EINVALIDOP; 
    14391586        } 
    1440     } else if (transport_id == TP_STUN) { 
    1441         status = pj_stun_sock_sendto(comp->stun_sock, NULL, 
     1587    } else if (tp_typ == TP_STUN) { 
     1588        status = pj_stun_sock_sendto(comp->stun[tp_idx].sock, NULL, 
    14421589                                     pkt, (unsigned)size, 0, 
    14431590                                     dst_addr, dst_addr_len); 
     
    14791626                                 unsigned addr_len) 
    14801627{ 
     1628    sock_user_data *data; 
    14811629    pj_ice_strans_comp *comp; 
    14821630    pj_ice_strans *ice_st; 
    14831631    pj_status_t status; 
    14841632 
    1485     comp = (pj_ice_strans_comp*) pj_stun_sock_get_user_data(stun_sock); 
    1486     if (comp == NULL) { 
     1633    data = (sock_user_data*) pj_stun_sock_get_user_data(stun_sock); 
     1634    if (data == NULL) { 
    14871635        /* We have disassociated ourselves from the STUN socket */ 
    14881636        return PJ_FALSE; 
    14891637    } 
    14901638 
     1639    comp = data->comp; 
    14911640    ice_st = comp->ice_st; 
    14921641 
     
    15071656        /* Hand over the packet to ICE session */ 
    15081657        status = pj_ice_sess_on_rx_pkt(comp->ice_st->ice, comp->comp_id, 
    1509                                        TP_STUN, pkt, pkt_len, 
     1658                                       data->transport_id, 
     1659                                       pkt, pkt_len, 
    15101660                                       src_addr, addr_len); 
    15111661 
     
    15371687                                pj_status_t status) 
    15381688{ 
     1689    sock_user_data *data; 
    15391690    pj_ice_strans_comp *comp; 
    15401691    pj_ice_strans *ice_st; 
    15411692    pj_ice_sess_cand *cand = NULL; 
    15421693    unsigned i; 
     1694    int tp_idx; 
    15431695 
    15441696    pj_assert(status != PJ_EPENDING); 
    15451697 
    1546     comp = (pj_ice_strans_comp*) pj_stun_sock_get_user_data(stun_sock); 
     1698    data = (sock_user_data*) pj_stun_sock_get_user_data(stun_sock); 
     1699    comp = data->comp; 
    15471700    ice_st = comp->ice_st; 
    15481701 
     
    15541707    /* Find the srflx cancidate */ 
    15551708    for (i=0; i<comp->cand_cnt; ++i) { 
    1556         if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_SRFLX) { 
     1709        if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_SRFLX && 
     1710            comp->cand_list[i].transport_id == data->transport_id) 
     1711        { 
    15571712            cand = &comp->cand_list[i]; 
    15581713            break; 
     
    15701725    } 
    15711726 
     1727    tp_idx = GET_TP_IDX(data->transport_id); 
     1728 
    15721729    switch (op) { 
    15731730    case PJ_STUN_SOCK_DNS_OP: 
     
    15761733            if (cand) 
    15771734                cand->status = status; 
    1578             if (!ice_st->cfg.stun.ignore_stun_error) { 
     1735            if (!ice_st->cfg.stun_tp[tp_idx].ignore_stun_error) { 
    15791736                sess_fail(ice_st, PJ_ICE_STRANS_OP_INIT, 
    15801737                          "DNS resolution failed", status); 
     
    16561813            if (cand) 
    16571814                cand->status = status; 
    1658             if (!ice_st->cfg.stun.ignore_stun_error || comp->cand_cnt==1) { 
     1815            if (!ice_st->cfg.stun_tp[tp_idx].ignore_stun_error || 
     1816                comp->cand_cnt==1) 
     1817            { 
    16591818                sess_fail(ice_st, PJ_ICE_STRANS_OP_INIT, 
    16601819                          "STUN binding request failed", status); 
     
    16811840            pj_assert(cand != NULL); 
    16821841            cand->status = status; 
    1683             if (!ice_st->cfg.stun.ignore_stun_error) { 
     1842            if (!ice_st->cfg.stun_tp[tp_idx].ignore_stun_error) { 
    16841843                sess_fail(ice_st, PJ_ICE_STRANS_OP_INIT, 
    16851844                          "STUN keep-alive failed", status); 
     
    17021861{ 
    17031862    pj_ice_strans_comp *comp; 
     1863    sock_user_data *data; 
    17041864    pj_status_t status; 
    17051865 
    1706     comp = (pj_ice_strans_comp*) pj_turn_sock_get_user_data(turn_sock); 
    1707     if (comp == NULL) { 
     1866    data = (sock_user_data*) pj_turn_sock_get_user_data(turn_sock); 
     1867    if (data == NULL) { 
    17081868        /* We have disassociated ourselves from the TURN socket */ 
    17091869        return; 
    17101870    } 
     1871 
     1872    comp = data->comp; 
    17111873 
    17121874    pj_grp_lock_add_ref(comp->ice_st->grp_lock); 
     
    17271889        /* Hand over the packet to ICE */ 
    17281890        status = pj_ice_sess_on_rx_pkt(comp->ice_st->ice, comp->comp_id, 
    1729                                        TP_TURN, pkt, pkt_len, 
     1891                                       data->transport_id, pkt, pkt_len, 
    17301892                                       peer_addr, addr_len); 
    17311893 
     
    17461908{ 
    17471909    pj_ice_strans_comp *comp; 
    1748  
    1749     comp = (pj_ice_strans_comp*) pj_turn_sock_get_user_data(turn_sock); 
    1750     if (comp == NULL) { 
     1910    sock_user_data *data; 
     1911    int tp_idx; 
     1912 
     1913    data = (sock_user_data*) pj_turn_sock_get_user_data(turn_sock); 
     1914    if (data == NULL) { 
    17511915        /* Not interested in further state notification once the relay is 
    17521916         * disconnecting. 
     
    17541918        return; 
    17551919    } 
     1920 
     1921    comp = data->comp; 
     1922    tp_idx = GET_TP_IDX(data->transport_id); 
    17561923 
    17571924    PJ_LOG(5,(comp->ice_st->obj_name, "TURN client state changed %s --> %s", 
     
    17671934        unsigned i; 
    17681935 
    1769         comp->turn_err_cnt = 0; 
     1936        comp->turn[tp_idx].err_cnt = 0; 
    17701937 
    17711938        /* Get allocation info */ 
     
    17771944        /* Find relayed candidate in the component */ 
    17781945        for (i=0; i<comp->cand_cnt; ++i) { 
    1779             if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_RELAYED) { 
     1946            if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_RELAYED && 
     1947                comp->cand_list[i].transport_id == data->transport_id) 
     1948            { 
    17801949                cand = &comp->cand_list[i]; 
    17811950                break; 
     
    18091978        pj_turn_session_info info; 
    18101979 
    1811         ++comp->turn_err_cnt; 
     1980        ++comp->turn[tp_idx].err_cnt; 
    18121981 
    18131982        pj_turn_sock_get_info(turn_sock, &info); 
     
    18151984        /* Unregister ourself from the TURN relay */ 
    18161985        pj_turn_sock_set_user_data(turn_sock, NULL); 
    1817         comp->turn_sock = NULL; 
     1986        comp->turn[tp_idx].sock = NULL; 
    18181987 
    18191988        /* Set session to fail on error. last_status PJ_SUCCESS means normal 
     
    18251994                sess_fail(comp->ice_st, PJ_ICE_STRANS_OP_INIT, 
    18261995                          "TURN allocation failed", info.last_status); 
    1827             } else if (comp->turn_err_cnt > 1) { 
     1996            } else if (comp->turn[tp_idx].err_cnt > 1) { 
    18281997                sess_fail(comp->ice_st, PJ_ICE_STRANS_OP_KEEP_ALIVE, 
    18291998                          "TURN refresh failed", info.last_status); 
     
    18322001                          "Comp %d: TURN allocation failed, retrying", 
    18332002                          comp->comp_id)); 
    1834                 add_update_turn(comp->ice_st, comp); 
     2003                add_update_turn(comp->ice_st, comp, tp_idx); 
    18352004            } 
    18362005        } 
Note: See TracChangeset for help on using the changeset viewer.