Ignore:
Timestamp:
Mar 25, 2007 6:44:51 PM (17 years ago)
Author:
bennylp
Message:

ICE (work in progress): use single socket for all candidates in component, and implemented IP interface enumeration on Win32

File:
1 edited

Legend:

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

    r1101 r1104  
    2121#include <pj/addr_resolv.h> 
    2222#include <pj/assert.h> 
     23#include <pj/ip_helper.h> 
    2324#include <pj/log.h> 
    2425#include <pj/pool.h> 
     
    2930/* ICE callbacks */ 
    3031static void        on_ice_complete(pj_ice *ice, pj_status_t status); 
    31 static pj_status_t on_tx_pkt(pj_ice *ice,  
    32                              unsigned comp_id, unsigned cand_id, 
    33                              const void *pkt, pj_size_t size, 
    34                              const pj_sockaddr_t *dst_addr, 
    35                              unsigned dst_addr_len); 
    36 static void        on_rx_data(pj_ice *ice,  
     32static pj_status_t ice_tx_pkt(pj_ice *ice,  
    3733                              unsigned comp_id, unsigned cand_id, 
     34                              const void *pkt, pj_size_t size, 
     35                              const pj_sockaddr_t *dst_addr, 
     36                              unsigned dst_addr_len); 
     37static void        ice_rx_data(pj_ice *ice,  
     38                              unsigned comp_id,  
    3839                              void *pkt, pj_size_t size, 
    3940                              const pj_sockaddr_t *src_addr, 
     
    4546                             pj_ssize_t bytes_read); 
    4647 
    47 static void destroy_ice_interface(pj_ice_st_interface *is); 
     48static void destroy_component(pj_ice_st_comp *comp); 
    4849static void destroy_ice_st(pj_ice_st *ice_st, pj_status_t reason); 
    4950 
     
    8687 
    8788/*  
    88  * Create new interface (i.e. socket)  
    89  */ 
    90 static pj_status_t create_ice_interface(pj_ice_st *ice_st, 
    91                                         pj_ice_cand_type type, 
    92                                         unsigned comp_id, 
    93                                         pj_uint16_t local_pref, 
    94                                         const pj_sockaddr_in *addr, 
    95                                         pj_ice_st_interface **p_is) 
    96 { 
    97     pj_ioqueue_callback ioqueue_cb; 
    98     pj_ice_st_interface *is; 
    99     char foundation[32]; 
    100     int addr_len; 
    101     pj_status_t status; 
    102  
    103     is = PJ_POOL_ZALLOC_T(ice_st->pool, pj_ice_st_interface); 
    104     is->type = type; 
    105     is->comp_id = comp_id; 
    106     is->cand_id = -1; 
    107     is->sock = PJ_INVALID_SOCKET; 
    108     is->ice_st = ice_st; 
    109     is->local_pref = local_pref; 
    110  
    111     status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &is->sock); 
    112     if (status != PJ_SUCCESS) 
    113         return status; 
    114  
    115     /* Bind and get the local IP address */ 
    116     if (addr)  
    117         pj_memcpy(&is->base_addr, addr, sizeof(pj_sockaddr_in)); 
    118     else  
    119         pj_sockaddr_in_init(&is->base_addr.ipv4, NULL, 0); 
    120  
    121     status = pj_sock_bind(is->sock, &is->base_addr, sizeof(pj_sockaddr_in)); 
    122     if (status != PJ_SUCCESS) 
    123         goto on_error; 
    124  
    125     addr_len = sizeof(is->base_addr); 
    126     status = pj_sock_getsockname(is->sock, &is->base_addr, &addr_len); 
    127     if (status != PJ_SUCCESS) 
    128         goto on_error; 
    129  
    130     if (is->base_addr.ipv4.sin_addr.s_addr == 0) { 
    131         status = pj_gethostip(&is->base_addr.ipv4.sin_addr); 
    132         if (status != PJ_SUCCESS)  
    133             goto on_error; 
    134     } 
    135  
    136     /* Assign foundation */ 
    137     pj_ansi_snprintf(foundation, sizeof(foundation), "%c%x",  
    138                      get_type_prefix(type), 
    139                      (int)pj_ntohl(is->base_addr.ipv4.sin_addr.s_addr)); 
    140     pj_strdup2(ice_st->pool, &is->foundation, foundation); 
    141  
    142  
    143     /* Register to ioqueue */ 
    144     pj_bzero(&ioqueue_cb, sizeof(ioqueue_cb)); 
    145     ioqueue_cb.on_read_complete = &on_read_complete; 
    146     status = pj_ioqueue_register_sock(ice_st->pool, ice_st->stun_cfg.ioqueue,  
    147                                       is->sock, is, &ioqueue_cb, &is->key); 
    148     if (status != PJ_SUCCESS) 
    149         goto on_error; 
    150  
    151     pj_ioqueue_op_key_init(&is->read_op, sizeof(is->read_op)); 
    152     pj_ioqueue_op_key_init(&is->write_op, sizeof(is->write_op)); 
    153  
    154     /* Kick start reading the socket */ 
    155     on_read_complete(is->key, &is->read_op, 0); 
    156  
    157     /* Done */ 
    158     *p_is = is; 
    159     return PJ_SUCCESS; 
    160  
    161 on_error: 
    162     destroy_ice_interface(is); 
    163     return status; 
    164 } 
    165  
    166 /*  
    167  * This is callback called by ioqueue on incoming packet  
    168  */ 
    169 static void on_read_complete(pj_ioqueue_key_t *key,  
    170                              pj_ioqueue_op_key_t *op_key,  
    171                              pj_ssize_t bytes_read) 
    172 { 
    173     pj_ice_st_interface *is = (pj_ice_st_interface*)  
    174                               pj_ioqueue_get_user_data(key); 
    175     pj_ice_st *ice_st = is->ice_st; 
    176     pj_ssize_t pkt_size; 
    177     pj_status_t status; 
    178  
    179     if (bytes_read > 0) { 
    180  
    181         /* If we have an active ICE session, hand over all incoming 
    182          * packets to the ICE session. Otherwise just drop the packet. 
    183          */ 
    184         if (ice_st->ice) { 
    185             status = pj_ice_on_rx_pkt(ice_st->ice,  
    186                                       is->comp_id, is->cand_id, 
    187                                       is->pkt, bytes_read, 
    188                                       &is->src_addr, is->src_addr_len); 
    189         } else if (is->stun_sess) { 
    190             status = pj_stun_msg_check(is->pkt, bytes_read, PJ_STUN_IS_DATAGRAM); 
    191             if (status == PJ_SUCCESS) { 
    192                 status = pj_stun_session_on_rx_pkt(is->stun_sess, is->pkt,  
    193                                                    bytes_read,  
    194                                                    PJ_STUN_IS_DATAGRAM, NULL, 
    195                                                    &is->src_addr,  
    196                                                    is->src_addr_len); 
    197             } else { 
    198                 (*ice_st->cb.on_rx_data)(ice_st, is->comp_id, is->cand_id,  
    199                                          is->pkt, bytes_read,  
    200                                          &is->src_addr, is->src_addr_len); 
    201  
    202             } 
    203         } else { 
    204             (*ice_st->cb.on_rx_data)(ice_st, is->comp_id, is->cand_id,  
    205                                      is->pkt, bytes_read,  
    206                                      &is->src_addr, is->src_addr_len); 
    207         } 
    208  
    209     } else if (bytes_read < 0) { 
    210         ice_st_perror(is->ice_st, "ioqueue read callback error", -bytes_read); 
    211     } 
    212  
    213     /* Read next packet */ 
    214     pkt_size = sizeof(is->pkt); 
    215     is->src_addr_len = sizeof(is->src_addr); 
    216     status = pj_ioqueue_recvfrom(key, op_key, is->pkt, &pkt_size,  
    217                                  PJ_IOQUEUE_ALWAYS_ASYNC, 
    218                                  &is->src_addr, &is->src_addr_len); 
    219     if (status != PJ_SUCCESS && status != PJ_EPENDING) { 
    220         ice_st_perror(is->ice_st, "ioqueue recvfrom() error", status); 
    221     } 
    222 } 
    223  
    224 /*  
    225  * Destroy an interface  
    226  */ 
    227 static void destroy_ice_interface(pj_ice_st_interface *is) 
    228 { 
    229     if (is->stun_sess) { 
    230         pj_stun_session_destroy(is->stun_sess); 
    231         is->stun_sess = NULL; 
    232     } 
    233  
    234     if (is->key) { 
    235         pj_ioqueue_unregister(is->key); 
    236         is->key = NULL; 
    237         is->sock = PJ_INVALID_SOCKET; 
    238     } else if (is->sock != PJ_INVALID_SOCKET && is->sock != 0) { 
    239         pj_sock_close(is->sock); 
    240         is->sock = PJ_INVALID_SOCKET; 
    241     } 
    242 } 
    243  
    244 /*  
    24589 * Create ICE stream transport  
    24690 */ 
    24791PJ_DECL(pj_status_t) pj_ice_st_create(pj_stun_config *stun_cfg, 
    24892                                      const char *name, 
     93                                      unsigned comp_cnt, 
    24994                                      void *user_data, 
    25095                                      const pj_ice_st_cb *cb, 
     
    25499    pj_ice_st *ice_st; 
    255100 
    256     PJ_ASSERT_RETURN(stun_cfg && cb && p_ice_st, PJ_EINVAL); 
     101    PJ_ASSERT_RETURN(stun_cfg && comp_cnt && cb && p_ice_st, PJ_EINVAL); 
    257102    PJ_ASSERT_RETURN(stun_cfg->ioqueue && stun_cfg->timer_heap, PJ_EINVAL); 
    258103 
     
    266111    ice_st->user_data = user_data; 
    267112     
     113    ice_st->comp_cnt = comp_cnt; 
     114    ice_st->comp = (pj_ice_st_comp**) pj_pool_calloc(pool, comp_cnt,  
     115                                                     sizeof(void*)); 
     116 
    268117    pj_memcpy(&ice_st->cb, cb, sizeof(*cb)); 
    269118    pj_memcpy(&ice_st->stun_cfg, stun_cfg, sizeof(*stun_cfg)); 
    270119 
     120 
    271121    PJ_LOG(4,(ice_st->obj_name, "ICE stream transport created")); 
    272122 
     
    275125} 
    276126 
     127/* Destroy ICE */ 
    277128static void destroy_ice_st(pj_ice_st *ice_st, pj_status_t reason) 
    278129{ 
     
    291142    } 
    292143 
    293     /* Destroy all interfaces */ 
    294     for (i=0; i<ice_st->itf_cnt; ++i) { 
    295         destroy_ice_interface(ice_st->itfs[i]); 
    296         ice_st->itfs[i] = NULL; 
    297     } 
    298     ice_st->itf_cnt = 0; 
     144    /* Destroy all components */ 
     145    for (i=0; i<ice_st->comp_cnt; ++i) { 
     146        if (ice_st->comp[i]) { 
     147            destroy_component(ice_st->comp[i]); 
     148            ice_st->comp[i] = NULL; 
     149        } 
     150    } 
     151    ice_st->comp_cnt = 0; 
    299152 
    300153    /* Done */ 
     
    318171 * Resolve STUN server 
    319172 */ 
    320 PJ_DEF(pj_status_t) pj_ice_st_set_stun( pj_ice_st *ice_st, 
    321                                         pj_dns_resolver *resolver, 
    322                                         pj_bool_t enable_relay, 
    323                                         const pj_str_t *domain) 
     173PJ_DEF(pj_status_t) pj_ice_st_set_stun_domain(pj_ice_st *ice_st, 
     174                                              pj_dns_resolver *resolver, 
     175                                              const pj_str_t *domain) 
    324176{ 
    325177    /* Yeah, TODO */ 
    326178    PJ_UNUSED_ARG(ice_st); 
    327179    PJ_UNUSED_ARG(resolver); 
    328     PJ_UNUSED_ARG(enable_relay); 
    329180    PJ_UNUSED_ARG(domain); 
    330181    return -1; 
     
    334185 * Set STUN server address. 
    335186 */ 
    336 PJ_DEF(pj_status_t) pj_ice_st_set_stun_addr( pj_ice_st *ice_st, 
    337                                              pj_bool_t enable_relay, 
    338                                              const pj_sockaddr_in *srv_addr) 
    339 { 
    340  
    341     PJ_ASSERT_RETURN(ice_st && srv_addr, PJ_EINVAL); 
    342      
    343     ice_st->relay_enabled = enable_relay; 
    344     pj_strdup2(ice_st->pool, &ice_st->stun_domain, 
    345                pj_inet_ntoa(srv_addr->sin_addr)); 
    346     pj_memcpy(&ice_st->stun_srv, srv_addr, sizeof(pj_sockaddr_in)); 
     187PJ_DEF(pj_status_t) pj_ice_st_set_stun_srv( pj_ice_st *ice_st, 
     188                                            const pj_sockaddr_in *stun_srv, 
     189                                            const pj_sockaddr_in *turn_srv) 
     190{ 
     191    PJ_ASSERT_RETURN(ice_st, PJ_EINVAL); 
     192    /* Must not have pending resolver job */ 
     193    PJ_ASSERT_RETURN(ice_st->has_resolver_job==PJ_FALSE, PJ_EINVALIDOP); 
     194 
     195    if (stun_srv) { 
     196        pj_memcpy(&ice_st->stun_srv, stun_srv, sizeof(pj_sockaddr_in)); 
     197    } else { 
     198        pj_bzero(&ice_st->stun_srv, sizeof(pj_sockaddr_in)); 
     199    } 
     200 
     201    if (turn_srv) { 
     202        pj_memcpy(&ice_st->turn_srv, turn_srv, sizeof(pj_sockaddr_in)); 
     203    } else { 
     204        pj_bzero(&ice_st->turn_srv, sizeof(pj_sockaddr_in)); 
     205    } 
    347206 
    348207    return PJ_SUCCESS; 
    349208} 
    350209 
    351 /* 
    352  * Add new component. 
    353  */ 
    354 PJ_DEF(pj_status_t) pj_ice_st_add_comp(pj_ice_st *ice_st, 
    355                                        unsigned comp_id) 
    356 { 
    357     /* Verify arguments */ 
    358     PJ_ASSERT_RETURN(ice_st && comp_id, PJ_EINVAL); 
    359  
    360     /* Can only add component when we don't have active ICE session */ 
    361     PJ_ASSERT_RETURN(ice_st->ice == NULL, PJ_EBUSY); 
    362  
    363     /* Check that we don't have too many components */ 
    364     PJ_ASSERT_RETURN(ice_st->comp_cnt < PJ_ICE_MAX_COMP, PJ_ETOOMANY); 
    365  
    366     /* Component ID must be valid */ 
    367     PJ_ASSERT_RETURN(comp_id <= PJ_ICE_MAX_COMP, PJNATH_EICEINCOMPID); 
    368  
    369     /* First component ID must be 1, second must be 2, etc., and  
    370      * they must be registered in order. 
    371      */ 
    372     PJ_ASSERT_RETURN(ice_st->comps[comp_id-1] == ice_st->comp_cnt,  
    373                      PJNATH_EICEINCOMPID); 
    374  
    375     /* All in order, add the component. */ 
    376     ice_st->comps[ice_st->comp_cnt++] = comp_id; 
    377  
    378     return PJ_SUCCESS; 
    379 } 
    380  
    381 /* Add interface */ 
    382 static void add_interface(pj_ice_st *ice_st, pj_ice_st_interface *is, 
    383                           unsigned *p_itf_id) 
    384 { 
    385     unsigned itf_id; 
    386  
    387     itf_id = ice_st->itf_cnt++; 
    388     ice_st->itfs[itf_id] = is; 
    389  
    390     if (p_itf_id) 
    391         *p_itf_id = itf_id; 
    392 } 
    393  
    394 /* 
    395  * Add new host interface. 
    396  */ 
    397 PJ_DEF(pj_status_t) pj_ice_st_add_host_interface(pj_ice_st *ice_st, 
    398                                                  unsigned comp_id, 
    399                                                  pj_uint16_t local_pref, 
    400                                                  const pj_sockaddr_in *addr, 
    401                                                  unsigned *p_itf_id) 
    402 { 
    403     pj_ice_st_interface *is; 
     210 
     211/* Calculate foundation */ 
     212static pj_str_t calc_foundation(pj_pool_t *pool, 
     213                                pj_ice_cand_type type, 
     214                                const pj_in_addr *base_addr) 
     215{ 
     216    char foundation[32]; 
     217    pj_str_t result; 
     218 
     219    pj_ansi_snprintf(foundation, sizeof(foundation), "%c%x",  
     220                     get_type_prefix(type), 
     221                     (int)pj_ntohl(base_addr->s_addr)); 
     222    pj_strdup2(pool, &result, foundation); 
     223 
     224    return result; 
     225} 
     226 
     227/*  Create new component (i.e. socket)  */ 
     228static pj_status_t create_component(pj_ice_st *ice_st, 
     229                                    unsigned comp_id, 
     230                                    pj_uint32_t options, 
     231                                    const pj_sockaddr_in *addr, 
     232                                    pj_ice_st_comp **p_comp) 
     233{ 
     234    enum { MAX_RETRY=100, PORT_INC=2 }; 
     235    pj_ioqueue_callback ioqueue_cb; 
     236    pj_ice_st_comp *comp; 
     237    int retry, addr_len; 
    404238    pj_status_t status; 
    405239 
    406     /* Verify arguments */ 
    407     PJ_ASSERT_RETURN(ice_st && comp_id, PJ_EINVAL); 
    408  
    409     /* Check that component ID present */ 
    410     PJ_ASSERT_RETURN(comp_id <= ice_st->comp_cnt, PJNATH_EICEINCOMPID); 
    411  
    412     /* Can't add new interface while ICE is running */ 
    413     PJ_ASSERT_RETURN(ice_st->ice == NULL, PJ_EBUSY); 
    414  
    415     /* Create interface */ 
    416     status = create_ice_interface(ice_st, PJ_ICE_CAND_TYPE_HOST, comp_id, 
    417                                   local_pref, addr, &is); 
     240    comp = PJ_POOL_ZALLOC_T(ice_st->pool, pj_ice_st_comp); 
     241    comp->ice_st = ice_st; 
     242    comp->comp_id = comp_id; 
     243    comp->options = options; 
     244    comp->sock = PJ_INVALID_SOCKET; 
     245    comp->last_status = PJ_SUCCESS; 
     246 
     247    /* Create socket */ 
     248    status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &comp->sock); 
    418249    if (status != PJ_SUCCESS) 
    419250        return status; 
    420251 
    421     /* For host interface, the address is the base address */ 
    422     pj_memcpy(&is->addr, &is->base_addr, sizeof(is->addr)); 
    423  
    424     /* Store this interface */ 
    425     add_interface(ice_st, is, p_itf_id); 
    426  
    427     /* Set interface status to SUCCESS */ 
    428     is->status = PJ_SUCCESS; 
     252    /* Init address */ 
     253    if (addr)  
     254        pj_memcpy(&comp->local_addr, addr, sizeof(pj_sockaddr_in)); 
     255    else  
     256        pj_sockaddr_in_init(&comp->local_addr.ipv4, NULL, 0); 
     257 
     258    /* Retry binding socket */ 
     259    for (retry=0; retry<MAX_RETRY; ++retry) { 
     260        pj_uint16_t port; 
     261 
     262        status = pj_sock_bind(comp->sock, &comp->local_addr,  
     263                              sizeof(pj_sockaddr_in)); 
     264        if (status == PJ_SUCCESS) 
     265            break; 
     266 
     267        if (options & PJ_ICE_ST_OPT_NO_PORT_RETRY) 
     268            goto on_error; 
     269 
     270        port = pj_ntohs(comp->local_addr.ipv4.sin_port); 
     271        port += PORT_INC; 
     272        comp->local_addr.ipv4.sin_port = pj_htons(port); 
     273    } 
     274 
     275    /* Get the actual port where the socket is bound to. 
     276     * (don't care about the address, it will be retrieved later) 
     277     */ 
     278    addr_len = sizeof(comp->local_addr); 
     279    status = pj_sock_getsockname(comp->sock, &comp->local_addr, &addr_len); 
     280    if (status != PJ_SUCCESS) 
     281        goto on_error; 
     282 
     283    /* Register to ioqueue */ 
     284    pj_bzero(&ioqueue_cb, sizeof(ioqueue_cb)); 
     285    ioqueue_cb.on_read_complete = &on_read_complete; 
     286    status = pj_ioqueue_register_sock(ice_st->pool, ice_st->stun_cfg.ioqueue,  
     287                                      comp->sock, comp, &ioqueue_cb,  
     288                                      &comp->key); 
     289    if (status != PJ_SUCCESS) 
     290        goto on_error; 
     291 
     292    pj_ioqueue_op_key_init(&comp->read_op, sizeof(comp->read_op)); 
     293    pj_ioqueue_op_key_init(&comp->write_op, sizeof(comp->write_op)); 
     294 
     295    /* Kick start reading the socket */ 
     296    on_read_complete(comp->key, &comp->read_op, 0); 
     297 
     298    /* If the socket is bound to INADDR_ANY, then lookup all interfaces in 
     299     * the host and add them into cand_list. Otherwise if the socket is bound 
     300     * to a specific interface, then only add that specific interface to 
     301     * cand_list. 
     302     */ 
     303    if (comp->local_addr.ipv4.sin_addr.s_addr == 0) { 
     304        /* Socket is bound to INADDR_ANY */ 
     305        unsigned i, ifs_cnt; 
     306        pj_in_addr ifs[PJ_ICE_ST_MAX_ALIASES-2]; 
     307 
     308        /* Reset default candidate */ 
     309        comp->default_cand = -1; 
     310 
     311        /* Enum all IP interfaces in the host */ 
     312        ifs_cnt = PJ_ARRAY_SIZE(ifs); 
     313        status = pj_enum_ip_interface(&ifs_cnt, ifs); 
     314        if (status != PJ_SUCCESS) 
     315            goto on_error; 
     316 
     317        /* Set default IP interface as the base address */ 
     318        status = pj_gethostip(&comp->local_addr.ipv4.sin_addr); 
     319        if (status != PJ_SUCCESS) 
     320            return status; 
     321 
     322        /* Add candidate entry for each interface */ 
     323        for (i=0; i<ifs_cnt; ++i) { 
     324            pj_ice_st_cand *cand = &comp->cand_list[i]; 
     325 
     326            cand->type = PJ_ICE_CAND_TYPE_HOST; 
     327            cand->status = PJ_SUCCESS; 
     328            pj_memcpy(&cand->addr, &comp->local_addr, sizeof(pj_sockaddr_in)); 
     329            cand->addr.ipv4.sin_addr.s_addr = ifs[i].s_addr; 
     330            cand->cand_id = -1; 
     331            cand->local_pref = 65535; 
     332            cand->foundation = calc_foundation(ice_st->pool,  
     333                                             PJ_ICE_CAND_TYPE_HOST, 
     334                                             &cand->addr.ipv4.sin_addr); 
     335 
     336            /* If the IP address is equal to local address, assign it 
     337             * as default candidate. 
     338             */ 
     339            if (cand->addr.ipv4.sin_addr.s_addr == 
     340                comp->local_addr.ipv4.sin_addr.s_addr) 
     341            { 
     342                comp->default_cand = i; 
     343            } 
     344 
     345            PJ_LOG(5,(ice_st->obj_name,  
     346                      "Interface %s:%d added to component %d", 
     347                      pj_inet_ntoa(cand->addr.ipv4.sin_addr), 
     348                      (int)pj_ntohs(cand->addr.ipv4.sin_port), comp_id)); 
     349        } 
     350        comp->cand_cnt = ifs_cnt; 
     351 
     352 
     353    } else { 
     354        /* Socket is bound to specific address.  
     355         * In this case only add that address as a single entry in the 
     356         * cand_list table. 
     357         */ 
     358        pj_ice_st_cand *cand = &comp->cand_list[0]; 
     359 
     360        cand->type = PJ_ICE_CAND_TYPE_HOST; 
     361        cand->status = PJ_SUCCESS; 
     362        pj_memcpy(&cand->addr, &comp->local_addr, sizeof(pj_sockaddr_in)); 
     363        cand->cand_id = -1; 
     364        cand->local_pref = 65535; 
     365        cand->foundation = calc_foundation(ice_st->pool,  
     366                                         PJ_ICE_CAND_TYPE_HOST, 
     367                                         &cand->addr.ipv4.sin_addr); 
     368 
     369        comp->cand_cnt = 1; 
     370        comp->default_cand = 0; 
     371 
     372        PJ_LOG(5,(ice_st->obj_name,  
     373                  "Interface %s:%d added to component %d", 
     374                  pj_inet_ntoa(cand->addr.ipv4.sin_addr), 
     375                  (int)pj_ntohs(cand->addr.ipv4.sin_port), comp_id)); 
     376 
     377    } 
     378 
     379    /* Done */ 
     380    if (p_comp) 
     381        *p_comp = comp; 
    429382 
    430383    return PJ_SUCCESS; 
    431 } 
    432  
    433 /* 
    434  * Enumerate and add all host interfaces. 
    435  */ 
    436 PJ_DEF(pj_status_t) pj_ice_st_add_all_host_interfaces(pj_ice_st *ice_st, 
    437                                                       unsigned comp_id, 
    438                                                       unsigned port) 
    439 { 
    440     pj_sockaddr_in addr; 
     384 
     385on_error: 
     386    destroy_component(comp); 
     387    return status; 
     388} 
     389 
     390/*  
     391 * This is callback called by ioqueue on incoming packet  
     392 */ 
     393static void on_read_complete(pj_ioqueue_key_t *key,  
     394                             pj_ioqueue_op_key_t *op_key,  
     395                             pj_ssize_t bytes_read) 
     396{ 
     397    pj_ice_st_comp *comp = (pj_ice_st_comp*)  
     398                            pj_ioqueue_get_user_data(key); 
     399    pj_ice_st *ice_st = comp->ice_st; 
     400    pj_ssize_t pkt_size; 
    441401    pj_status_t status; 
    442402 
    443     /* Yeah, TODO. 
    444      * For now just add the default interface. 
    445      */ 
    446     pj_sockaddr_in_init(&addr, NULL, (pj_uint16_t)port); 
    447      
    448     status = pj_gethostip(&addr.sin_addr); 
    449     if (status != PJ_SUCCESS) 
    450         return status; 
    451  
    452     return pj_ice_st_add_host_interface(ice_st, comp_id, 65535, &addr, NULL); 
    453 } 
    454  
    455 /* 
    456  * Add STUN mapping interface. 
    457  */ 
    458 PJ_DEF(pj_status_t) pj_ice_st_add_stun_interface(pj_ice_st *ice_st, 
    459                                                  unsigned comp_id, 
    460                                                  unsigned local_port, 
    461                                                  unsigned *p_itf_id) 
    462 { 
    463     pj_ice_st_interface *is; 
    464     pj_sockaddr_in local_addr; 
     403    if (bytes_read > 0) { 
     404        /* 
     405         * Okay, we got a packet from the socket for the component. There is 
     406         * a bit of situation here, since this packet could be one of these: 
     407         * 
     408         * 1) this could be the response of STUN binding request sent by 
     409         *    this component to a) an initial request to get the STUN mapped 
     410         *    address of this component, or b) subsequent request to keep 
     411         *    the binding alive. 
     412         *  
     413         * 2) this could be a packet (STUN or not STUN) sent from the STUN 
     414         *    relay server. In this case, still there are few options to do 
     415         *    for this packet: a) process this locally if this packet is 
     416         *    related to TURN session management (e.g. Allocate response), 
     417         *    b) forward this packet to ICE if this is related to ICE 
     418         *    discovery process. 
     419         * 
     420         * 3) this could be a STUN request or response sent as part of ICE 
     421         *    discovery process. 
     422         * 
     423         * 4) this could be application's packet, e.g. when ICE processing 
     424         *    is done and agents start sending RTP/RTCP packets to each 
     425         *    other, or when ICE processing is not done and this ICE stream 
     426         *    transport decides to allow sending data. 
     427         * 
     428         * So far we don't have good solution for this. 
     429         * The process below is just a workaround. 
     430         */ 
     431        if (ice_st->ice) { 
     432            PJ_TODO(DISTINGUISH_BETWEEN_LOCAL_AND_RELAY); 
     433            status = pj_ice_on_rx_pkt(ice_st->ice, comp->comp_id,  
     434                                      comp->cand_list[0].cand_id, 
     435                                      comp->pkt, bytes_read, 
     436                                      &comp->src_addr, comp->src_addr_len); 
     437        } else if (comp->stun_sess) { 
     438            status = pj_stun_msg_check(comp->pkt, bytes_read,  
     439                                       PJ_STUN_IS_DATAGRAM); 
     440            if (status == PJ_SUCCESS) { 
     441                status = pj_stun_session_on_rx_pkt(comp->stun_sess, comp->pkt, 
     442                                                   bytes_read,  
     443                                                   PJ_STUN_IS_DATAGRAM, NULL, 
     444                                                   &comp->src_addr,  
     445                                                   comp->src_addr_len); 
     446            } else { 
     447                (*ice_st->cb.on_rx_data)(ice_st, comp->comp_id,  
     448                                         comp->pkt, bytes_read,  
     449                                         &comp->src_addr, comp->src_addr_len); 
     450 
     451            } 
     452        } else { 
     453            (*ice_st->cb.on_rx_data)(ice_st, comp->comp_id,  
     454                                     comp->pkt, bytes_read,  
     455                                     &comp->src_addr, comp->src_addr_len); 
     456        } 
     457 
     458    } else if (bytes_read < 0) { 
     459        ice_st_perror(comp->ice_st, "ioqueue read callback error",  
     460                      -bytes_read); 
     461    } 
     462 
     463    /* Read next packet */ 
     464    pkt_size = sizeof(comp->pkt); 
     465    comp->src_addr_len = sizeof(comp->src_addr); 
     466    status = pj_ioqueue_recvfrom(key, op_key, comp->pkt, &pkt_size,  
     467                                 PJ_IOQUEUE_ALWAYS_ASYNC, 
     468                                 &comp->src_addr, &comp->src_addr_len); 
     469    if (status != PJ_SUCCESS && status != PJ_EPENDING) { 
     470        ice_st_perror(comp->ice_st, "ioqueue recvfrom() error", status); 
     471    } 
     472} 
     473 
     474/*  
     475 * Destroy a component  
     476 */ 
     477static void destroy_component(pj_ice_st_comp *comp) 
     478{ 
     479    if (comp->stun_sess) { 
     480        pj_stun_session_destroy(comp->stun_sess); 
     481        comp->stun_sess = NULL; 
     482    } 
     483 
     484    if (comp->key) { 
     485        pj_ioqueue_unregister(comp->key); 
     486        comp->key = NULL; 
     487        comp->sock = PJ_INVALID_SOCKET; 
     488    } else if (comp->sock != PJ_INVALID_SOCKET && comp->sock != 0) { 
     489        pj_sock_close(comp->sock); 
     490        comp->sock = PJ_INVALID_SOCKET; 
     491    } 
     492} 
     493 
     494 
     495 
     496/* 
     497 * Add STUN mapping to a component. 
     498 */ 
     499static pj_status_t get_stun_mapped_addr(pj_ice_st *ice_st, 
     500                                        pj_ice_st_comp *comp) 
     501{ 
     502    pj_ice_st_cand *cand; 
    465503    pj_stun_session_cb sess_cb; 
    466504    pj_stun_tx_data *tdata; 
    467505    pj_status_t status; 
    468506 
    469     PJ_ASSERT_RETURN(ice_st && comp_id, PJ_EINVAL); 
     507    PJ_ASSERT_RETURN(ice_st && comp, PJ_EINVAL); 
    470508     
    471     /* STUN server must have been configured */ 
    472     PJ_ASSERT_RETURN(ice_st->stun_srv.sin_family != 0, PJ_EINVALIDOP); 
    473  
    474  
    475     /* Create interface */ 
    476     pj_sockaddr_in_init(&local_addr, NULL, (pj_uint16_t)local_port); 
    477     status = create_ice_interface(ice_st, PJ_ICE_CAND_TYPE_SRFLX, comp_id, 
    478                                   65535, &local_addr, &is); 
    479     if (status != PJ_SUCCESS) 
    480         return status; 
    481  
    482     /* Create STUN session */ 
     509    /* Bail out if STUN server is still being resolved */ 
     510    if (ice_st->has_resolver_job) 
     511        return PJ_EBUSY; 
     512 
     513    /* Just return (successfully) if STUN server is not configured */ 
     514    if (ice_st->stun_srv.sin_family == 0) 
     515        return PJ_SUCCESS; 
     516 
     517 
     518    /* Create STUN session for this component */ 
    483519    pj_bzero(&sess_cb, sizeof(sess_cb)); 
    484520    sess_cb.on_request_complete = &stun_on_request_complete; 
    485521    sess_cb.on_send_msg = &stun_on_send_msg; 
    486522    status = pj_stun_session_create(&ice_st->stun_cfg, ice_st->obj_name, 
    487                                     &sess_cb, PJ_FALSE, &is->stun_sess); 
     523                                    &sess_cb, PJ_FALSE, &comp->stun_sess); 
    488524    if (status != PJ_SUCCESS) 
    489         goto on_error; 
    490  
    491     /* Associate interface with STUN session */ 
    492     pj_stun_session_set_user_data(is->stun_sess, (void*)is); 
    493  
    494     /* Create and send STUN binding request */ 
    495     status = pj_stun_session_create_req(is->stun_sess,  
     525        return status; 
     526 
     527    /* Associate component with STUN session */ 
     528    pj_stun_session_set_user_data(comp->stun_sess, (void*)comp); 
     529 
     530    /* Create STUN binding request */ 
     531    status = pj_stun_session_create_req(comp->stun_sess,  
    496532                                        PJ_STUN_BINDING_REQUEST, &tdata); 
    497533    if (status != PJ_SUCCESS) 
    498         goto on_error; 
    499  
    500     status = pj_stun_session_send_msg(is->stun_sess, PJ_FALSE,  
     534        return status; 
     535 
     536    /* Attach alias instance to tdata */ 
     537    cand = &comp->cand_list[comp->cand_cnt]; 
     538    tdata->user_data = (void*)cand; 
     539 
     540    /* Send STUN binding request */ 
     541    status = pj_stun_session_send_msg(comp->stun_sess, PJ_FALSE,  
    501542                                      &ice_st->stun_srv,  
    502543                                      sizeof(pj_sockaddr_in), tdata); 
    503544    if (status != PJ_SUCCESS) 
    504         goto on_error; 
    505  
    506     /* Mark interface as pending */ 
    507     is->status = PJ_EPENDING; 
    508  
    509     add_interface(ice_st, is, p_itf_id); 
     545        return status; 
     546 
     547 
     548    /* Add new alias to this component */ 
     549    cand->type = PJ_ICE_CAND_TYPE_SRFLX; 
     550    cand->status = PJ_EPENDING; 
     551    cand->cand_id = -1; 
     552    cand->local_pref = 65535; 
     553    cand->foundation = calc_foundation(ice_st->pool, PJ_ICE_CAND_TYPE_SRFLX, 
     554                                       &comp->local_addr.ipv4.sin_addr); 
     555 
     556    ++comp->cand_cnt; 
     557 
     558    /* Add pending count for this component */ 
     559    comp->pending_cnt++; 
    510560 
    511561    return PJ_SUCCESS; 
    512  
    513 on_error: 
    514     destroy_ice_interface(is); 
    515     return status; 
    516 } 
    517  
    518 /* 
    519  * Add TURN mapping interface. 
    520  */ 
    521 PJ_DEF(pj_status_t) pj_ice_st_add_relay_interface(pj_ice_st *ice_st, 
    522                                                   unsigned comp_id, 
    523                                                   unsigned local_port, 
    524                                                   pj_bool_t notify, 
    525                                                   void *notify_data) 
    526 { 
    527     /* Yeah, TODO */ 
    528     PJ_UNUSED_ARG(ice_st); 
    529     PJ_UNUSED_ARG(comp_id); 
    530     PJ_UNUSED_ARG(local_port); 
    531     PJ_UNUSED_ARG(notify); 
    532     PJ_UNUSED_ARG(notify_data); 
    533     return -1; 
    534 } 
    535  
    536 PJ_DEF(pj_status_t) pj_ice_st_get_interfaces_status(pj_ice_st *ice_st) 
     562} 
     563 
     564 
     565/* 
     566 * Create the component. 
     567 */ 
     568PJ_DEF(pj_status_t) pj_ice_st_create_comp(pj_ice_st *ice_st, 
     569                                          unsigned comp_id, 
     570                                          pj_uint32_t options, 
     571                                          const pj_sockaddr_in *addr, 
     572                                          unsigned *p_itf_id) 
     573{ 
     574    pj_ice_st_comp *comp; 
     575    pj_status_t status; 
     576 
     577    /* Verify arguments */ 
     578    PJ_ASSERT_RETURN(ice_st && comp_id, PJ_EINVAL); 
     579 
     580    /* Check that component ID present */ 
     581    PJ_ASSERT_RETURN(comp_id <= ice_st->comp_cnt, PJNATH_EICEINCOMPID); 
     582 
     583    /* Can't add new component while ICE is running */ 
     584    PJ_ASSERT_RETURN(ice_st->ice == NULL, PJ_EBUSY); 
     585     
     586    /* Can't add new component while resolver is running */ 
     587    PJ_ASSERT_RETURN(ice_st->has_resolver_job == PJ_FALSE, PJ_EBUSY); 
     588 
     589 
     590    /* Create component */ 
     591    status = create_component(ice_st, comp_id, options, addr, &comp); 
     592    if (status != PJ_SUCCESS) 
     593        return status; 
     594 
     595    if ((options & PJ_ICE_ST_OPT_DISABLE_STUN) == 0) { 
     596        status = get_stun_mapped_addr(ice_st, comp); 
     597        if (status != PJ_SUCCESS) { 
     598            destroy_component(comp); 
     599            return status; 
     600        } 
     601    } 
     602 
     603    /* Store this component */ 
     604    if (p_itf_id) 
     605        *p_itf_id = ice_st->comp_cnt; 
     606 
     607    ice_st->comp[comp_id-1] = comp; 
     608 
     609    return PJ_SUCCESS; 
     610} 
     611 
     612 
     613PJ_DEF(pj_status_t) pj_ice_st_get_comps_status(pj_ice_st *ice_st) 
    537614{ 
    538615    unsigned i; 
    539616    pj_status_t worst = PJ_SUCCESS; 
    540617 
    541     for (i=0; i<ice_st->itf_cnt; ++i) { 
    542         pj_ice_st_interface *itf = ice_st->itfs[i]; 
    543  
    544         if (itf->status == PJ_SUCCESS) { 
     618    for (i=0; i<ice_st->comp_cnt; ++i) { 
     619        pj_ice_st_comp *comp = ice_st->comp[i]; 
     620 
     621        if (comp->last_status == PJ_SUCCESS) { 
    545622            /* okay */ 
    546         } else if (itf->status == PJ_EPENDING && worst==PJ_SUCCESS) { 
    547             worst = itf->status; 
    548         } else { 
    549             worst = itf->status; 
     623        } else if (comp->pending_cnt && worst==PJ_SUCCESS) { 
     624            worst = PJ_EPENDING; 
     625            break; 
     626        } else if (comp->last_status != PJ_SUCCESS) { 
     627            worst = comp->last_status; 
     628            break; 
    550629        } 
     630 
     631        if (worst != PJ_SUCCESS) 
     632            break; 
    551633    } 
    552634 
     
    574656    pj_bzero(&ice_cb, sizeof(ice_cb)); 
    575657    ice_cb.on_ice_complete = &on_ice_complete; 
    576     ice_cb.on_rx_data = &on_rx_data; 
    577     ice_cb.on_tx_pkt = &on_tx_pkt; 
     658    ice_cb.on_rx_data = &ice_rx_data; 
     659    ice_cb.on_tx_pkt = &ice_tx_pkt; 
    578660 
    579661    /* Create! */ 
     
    588670 
    589671    /* Add candidates */ 
    590     for (i=0; i<ice_st->itf_cnt; ++i) { 
    591         pj_ice_st_interface *is= ice_st->itfs[i]; 
    592         status = pj_ice_add_cand(ice_st->ice, is->comp_id, is->type,  
    593                                  is->local_pref, &is->foundation, 
    594                                  &is->addr, &is->base_addr, NULL,  
    595                                  sizeof(pj_sockaddr_in),  
    596                                  (unsigned*)&is->cand_id); 
    597         if (status != PJ_SUCCESS) 
    598             goto on_error; 
     672    for (i=0; i<ice_st->comp_cnt; ++i) { 
     673        unsigned j; 
     674        pj_ice_st_comp *comp= ice_st->comp[i]; 
     675 
     676        for (j=0; j<comp->cand_cnt; ++j) { 
     677            pj_ice_st_cand *cand = &comp->cand_list[j]; 
     678 
     679            /* Skip if candidate is not ready */ 
     680            if (cand->status != PJ_SUCCESS) { 
     681                PJ_LOG(5,(ice_st->obj_name,  
     682                          "Candidate %d in component %d is not added", 
     683                          j, i)); 
     684                continue; 
     685            } 
     686 
     687            status = pj_ice_add_cand(ice_st->ice, comp->comp_id, cand->type, 
     688                                     cand->local_pref, &cand->foundation, 
     689                                     &cand->addr, &comp->local_addr, NULL,  
     690                                     sizeof(pj_sockaddr_in),  
     691                                     (unsigned*)&cand->cand_id); 
     692            if (status != PJ_SUCCESS) 
     693                goto on_error; 
     694        } 
    599695    } 
    600696 
     
    602698 
    603699on_error: 
    604     for (i=0; i<ice_st->itf_cnt; ++i) { 
    605         ice_st->itfs[i]->cand_id = -1; 
    606     } 
    607     if (ice_st->ice) { 
    608         pj_ice_destroy(ice_st->ice); 
    609         ice_st->ice = NULL; 
    610     } 
     700    pj_ice_st_stop_ice(ice_st); 
    611701    return status; 
    612702} 
     
    654744        return status; 
    655745 
    656     return pj_ice_start_check(ice_st->ice); 
     746    status = pj_ice_start_check(ice_st->ice); 
     747    if (status != PJ_SUCCESS) { 
     748        pj_ice_st_stop_ice(ice_st); 
     749    } 
     750 
     751    return status; 
    657752} 
    658753 
     
    662757PJ_DECL(pj_status_t) pj_ice_st_stop_ice(pj_ice_st *ice_st) 
    663758{ 
     759    unsigned i; 
     760 
    664761    if (ice_st->ice) { 
    665762        pj_ice_destroy(ice_st->ice); 
     
    667764    } 
    668765 
     766    /* Invalidate all candidate Ids */ 
     767    for (i=0; i<ice_st->comp_cnt; ++i) { 
     768        unsigned j; 
     769        for (j=0; j<ice_st->comp[i]->cand_cnt; ++j) { 
     770            ice_st->comp[i]->cand_list[j].cand_id = -1; 
     771        } 
     772    } 
     773 
    669774    return PJ_SUCCESS; 
    670 } 
    671  
    672 /* 
    673  * Send data to peer agent. 
    674  */ 
    675 PJ_DEF(pj_status_t) pj_ice_st_send_data( pj_ice_st *ice_st, 
    676                                          unsigned comp_id, 
    677                                          const void *data, 
    678                                          pj_size_t data_len) 
    679 { 
    680     if (!ice_st->ice) 
    681         return PJNATH_ENOICE; 
    682  
    683     return pj_ice_send_data(ice_st->ice, comp_id, data, data_len); 
    684775} 
    685776 
     
    689780PJ_DEF(pj_status_t) pj_ice_st_sendto( pj_ice_st *ice_st, 
    690781                                      unsigned comp_id, 
    691                                       unsigned itf_id, 
    692782                                      const void *data, 
    693783                                      pj_size_t data_len, 
     
    696786{ 
    697787    pj_ssize_t pkt_size; 
    698     pj_ice_st_interface *is = ice_st->itfs[itf_id]; 
     788    pj_ice_st_comp *comp; 
    699789    pj_status_t status; 
    700790 
     791    PJ_ASSERT_RETURN(ice_st && comp_id && comp_id <= ice_st->comp_cnt && 
     792                     dst_addr && dst_addr_len, PJ_EINVAL); 
     793 
     794    comp = ice_st->comp[comp_id-1]; 
     795 
     796    /* If ICE is available, send data with ICE */ 
     797    if (ice_st->ice) { 
     798        return pj_ice_send_data(ice_st->ice, comp_id, data, data_len); 
     799    } 
     800 
     801    /* Otherwise send direcly with the socket */ 
    701802    pkt_size = data_len; 
    702     status = pj_ioqueue_sendto(is->key, &is->write_op,  
     803    status = pj_ioqueue_sendto(comp->key, &comp->write_op,  
    703804                               data, &pkt_size, 0, 
    704805                               dst_addr, dst_addr_len); 
     
    722823 * Callback called by ICE session when it wants to send outgoing packet. 
    723824 */ 
    724 static pj_status_t on_tx_pkt(pj_ice *ice,  
    725                              unsigned comp_id, unsigned cand_id, 
    726                              const void *pkt, pj_size_t size, 
    727                              const pj_sockaddr_t *dst_addr, 
    728                              unsigned dst_addr_len) 
     825static pj_status_t ice_tx_pkt(pj_ice *ice,  
     826                              unsigned comp_id, unsigned cand_id, 
     827                              const void *pkt, pj_size_t size, 
     828                              const pj_sockaddr_t *dst_addr, 
     829                              unsigned dst_addr_len) 
    729830{ 
    730831    pj_ice_st *ice_st = (pj_ice_st*)ice->user_data; 
    731     pj_ice_st_interface *is = NULL; 
    732     unsigned i; 
     832    pj_ice_st_comp *comp = NULL; 
    733833    pj_ssize_t pkt_size; 
    734834    pj_status_t status; 
    735835 
    736     PJ_UNUSED_ARG(comp_id); 
    737  
    738     for (i=0; i<ice_st->itf_cnt; ++i) { 
    739         if (ice_st->itfs[i]->cand_id == (int)cand_id) { 
    740             is = ice_st->itfs[i]; 
    741             break; 
    742         } 
    743     } 
    744     if (is == NULL) { 
    745         return PJNATH_EICEINCANDID; 
    746     } 
     836    PJ_TODO(TX_TO_RELAY); 
     837 
     838    PJ_ASSERT_RETURN(comp_id && comp_id <= ice_st->comp_cnt, PJ_EINVAL); 
     839    comp = ice_st->comp[comp_id-1]; 
    747840 
    748841    pkt_size = size; 
    749     status = pj_ioqueue_sendto(is->key, &is->write_op,  
     842    status = pj_ioqueue_sendto(comp->key, &comp->write_op,  
    750843                               pkt, &pkt_size, 0, 
    751844                               dst_addr, dst_addr_len); 
     
    757850 * Callback called by ICE session when it receives application data. 
    758851 */ 
    759 static void on_rx_data(pj_ice *ice,  
    760                        unsigned comp_id, unsigned cand_id, 
    761                        void *pkt, pj_size_t size, 
    762                        const pj_sockaddr_t *src_addr, 
    763                        unsigned src_addr_len) 
     852static void ice_rx_data(pj_ice *ice,  
     853                        unsigned comp_id,  
     854                        void *pkt, pj_size_t size, 
     855                        const pj_sockaddr_t *src_addr, 
     856                        unsigned src_addr_len) 
    764857{ 
    765858    pj_ice_st *ice_st = (pj_ice_st*)ice->user_data; 
    766859 
    767860    if (ice_st->cb.on_rx_data) { 
    768         (*ice_st->cb.on_rx_data)(ice_st, comp_id, cand_id,  
    769                                  pkt, size, src_addr, src_addr_len); 
     861        (*ice_st->cb.on_rx_data)(ice_st, comp_id, pkt, size,  
     862                                 src_addr, src_addr_len); 
    770863    } 
    771864} 
     
    780873                                    unsigned dst_addr_len) 
    781874{ 
    782     pj_ice_st_interface *is; 
     875    pj_ice_st_comp *comp; 
    783876    pj_ssize_t pkt_size; 
    784877    pj_status_t status; 
    785878 
    786     is = (pj_ice_st_interface*) pj_stun_session_get_user_data(sess); 
     879    comp = (pj_ice_st_comp*) pj_stun_session_get_user_data(sess); 
    787880    pkt_size = size; 
    788     status = pj_ioqueue_sendto(is->key, &is->write_op,  
     881    status = pj_ioqueue_sendto(comp->key, &comp->write_op,  
    789882                               pkt, &pkt_size, 0, 
    790883                               dst_addr, dst_addr_len); 
     
    802895                                     const pj_stun_msg *response) 
    803896{ 
    804     pj_ice_st_interface *is; 
     897    pj_ice_st_comp *comp; 
     898    pj_ice_st_cand *cand = NULL; 
    805899    pj_stun_xor_mapped_addr_attr *xa; 
    806900    pj_stun_mapped_addr_attr *ma; 
    807901    pj_sockaddr *mapped_addr; 
    808902 
    809     PJ_UNUSED_ARG(tdata); 
    810  
    811     is = (pj_ice_st_interface*) pj_stun_session_get_user_data(sess); 
     903    comp = (pj_ice_st_comp*) pj_stun_session_get_user_data(sess); 
     904    cand = (pj_ice_st_cand*) tdata->user_data; 
     905 
     906    /* Decrement pending count for this component */ 
     907    pj_assert(comp->pending_cnt > 0); 
     908    comp->pending_cnt--; 
     909 
    812910    if (status != PJ_SUCCESS) { 
    813         is->status = status; 
    814         ice_st_perror(is->ice_st, "STUN Binding request failed", is->status); 
     911        comp->last_status = cand->status = status; 
     912        ice_st_perror(comp->ice_st, "STUN Binding request failed",  
     913                      cand->status); 
    815914        return; 
    816915    } 
     
    826925        mapped_addr = &ma->sockaddr; 
    827926    else { 
    828         is->status = PJNATH_ESTUNNOMAPPEDADDR; 
    829         ice_st_perror(is->ice_st, "STUN Binding request failed", is->status); 
     927        cand->status = PJNATH_ESTUNNOMAPPEDADDR; 
     928        ice_st_perror(comp->ice_st, "STUN Binding request failed",  
     929                      cand->status); 
    830930        return; 
    831931    } 
    832932 
    833     PJ_LOG(4,(is->ice_st->obj_name,  
     933    PJ_LOG(4,(comp->ice_st->obj_name,  
    834934              "STUN mapped address: %s:%d", 
    835935              pj_inet_ntoa(mapped_addr->ipv4.sin_addr), 
    836936              (int)pj_ntohs(mapped_addr->ipv4.sin_port))); 
    837     pj_memcpy(&is->addr, mapped_addr, sizeof(pj_sockaddr_in)); 
    838     is->status = PJ_SUCCESS; 
    839  
    840 } 
    841  
     937    pj_memcpy(&cand->addr, mapped_addr, sizeof(pj_sockaddr_in)); 
     938    cand->status = PJ_SUCCESS; 
     939 
     940    /* Set this candidate as the default candidate */ 
     941    comp->default_cand = (cand - comp->cand_list); 
     942    comp->last_status = PJ_SUCCESS; 
     943} 
     944 
Note: See TracChangeset for help on using the changeset viewer.