Ignore:
Timestamp:
Mar 21, 2007 1:24:02 PM (17 years ago)
Author:
bennylp
Message:

ICE complete, ready for testing

File:
1 edited

Legend:

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

    r1091 r1092  
    6060const pj_str_t peer_mapped_foundation = {"peer", 4}; 
    6161 
    62 #define CHECK_NAME_LEN  128 
    63 #define LOG(expr)       PJ_LOG(4,expr) 
     62#define CHECK_NAME_LEN      128 
     63#define LOG(expr)           PJ_LOG(4,expr) 
     64#define GET_LCAND_ID(cand)  (cand - ice->lcand) 
     65#define GET_CHECK_ID(chk)   (chk - ice->clist.checks) 
     66 
     67 
     68typedef struct stun_data 
     69{ 
     70    pj_ice      *ice; 
     71    unsigned     comp_id; 
     72    pj_ice_comp *comp; 
     73} stun_data; 
     74 
     75typedef struct timer_data 
     76{ 
     77    pj_ice              *ice; 
     78    pj_ice_checklist    *clist; 
     79} timer_data; 
     80 
     81 
    6482 
    6583static void destroy_ice(pj_ice *ice, 
     
    125143    pj_pool_t *pool; 
    126144    pj_ice *ice; 
     145    unsigned i; 
    127146    pj_status_t status; 
    128147 
     
    154173    pj_memcpy(&ice->stun_cfg, stun_cfg, sizeof(*stun_cfg)); 
    155174 
     175    for (i=0; i<PJ_ICE_MAX_COMP; ++i) { 
     176        ice->comp[i].nominated_check_id = -1; 
     177    } 
    156178 
    157179    /* Done */ 
    158180    *p_ice = ice; 
    159181 
    160     LOG((ice->obj_name, "ICE session created")); 
     182    LOG((ice->obj_name, "ICE media stream created")); 
    161183 
    162184    return PJ_SUCCESS; 
     
    185207        pj_timer_heap_cancel(ice->stun_cfg.timer_heap, &ice->clist.timer); 
    186208        ice->clist.timer.id = PJ_FALSE; 
    187     } 
    188  
    189     if (ice->resv_q) { 
    190         pj_dns_resolver_cancel_query(ice->resv_q, PJ_FALSE); 
    191         ice->resv_q = NULL; 
    192209    } 
    193210 
     
    212229 
    213230 
    214 static void resolver_cb(void *user_data, 
    215                         pj_status_t status, 
    216                         pj_dns_parsed_packet *response) 
    217 { 
    218     pj_assert(!"Not implemented yet!"); 
    219     PJ_UNUSED_ARG(user_data); 
    220     PJ_UNUSED_ARG(status); 
    221     PJ_UNUSED_ARG(response); 
    222 } 
    223  
    224 PJ_DEF(pj_status_t) pj_ice_set_srv(pj_ice *ice, 
    225                                    pj_bool_t enable_relay, 
    226                                    pj_dns_resolver *resolver, 
    227                                    const pj_str_t *domain) 
    228 { 
    229     char namebuf[128]; 
    230     char *tp_name; 
    231     pj_str_t name; 
    232     pj_status_t status; 
    233  
    234  
    235     /* Not implemented yet! */ 
    236     return PJ_ENOTSUP; 
    237  
    238  
    239     PJ_ASSERT_RETURN(ice && resolver && domain, PJ_EINVAL); 
    240  
    241     /* Must not have a running resolver. This is because we couldn't 
    242      * safely cancel the query (there is a race condition situation 
    243      * between the callback acquiring the mutex and this function 
    244      * acquiring the mutex) 
    245      */ 
    246     PJ_ASSERT_RETURN(ice->resv_q==NULL, PJ_EBUSY); 
    247  
    248     pj_mutex_lock(ice->mutex); 
    249  
    250     /* Reset resolver and server addresses */ 
    251     ice->relay_enabled = enable_relay; 
    252     ice->resv = resolver; 
    253     pj_bzero(&ice->stun_srv, sizeof(ice->stun_srv)); 
    254  
    255     /* Build SRV record name */ 
    256     if (ice->sock_type == PJ_SOCK_DGRAM) { 
    257         tp_name = "_udp"; 
    258     } else if (ice->sock_type == PJ_SOCK_STREAM) { 
    259         tp_name = "_tcp"; 
    260     } else { 
    261         pj_assert(!"Invalid sock_type"); 
    262         pj_mutex_unlock(ice->mutex); 
    263         return PJ_EBUG; 
    264     } 
    265  
    266     if (enable_relay) { 
    267         name.ptr = namebuf; 
    268         name.slen = pj_ansi_snprintf(namebuf, sizeof(namebuf), 
    269                                      "_stun-relay.%s.%.*s", 
    270                                      tp_name, 
    271                                      (int)domain->slen, 
    272                                      domain->ptr); 
    273     } else { 
    274         name.ptr = namebuf; 
    275         name.slen = pj_ansi_snprintf(namebuf, sizeof(namebuf), 
    276                                      "_stun.%s.%.*s", 
    277                                      tp_name, 
    278                                      (int)domain->slen, 
    279                                      domain->ptr); 
    280     } 
    281  
    282     if (name.slen < 1 || name.slen >= sizeof(namebuf)) { 
    283         pj_mutex_unlock(ice->mutex); 
    284         return PJ_ENAMETOOLONG; 
    285     } 
    286  
    287     /* Start DNS query */ 
    288     status = pj_dns_resolver_start_query(ice->resv, &name,  
    289                                          PJ_DNS_TYPE_SRV, 0,  
    290                                          &resolver_cb,  
    291                                          ice, &ice->resv_q); 
    292     if (status != PJ_SUCCESS) { 
    293         pj_mutex_unlock(ice->mutex); 
    294         return status; 
    295     } 
    296  
    297     pj_mutex_unlock(ice->mutex); 
    298  
    299     return PJ_SUCCESS; 
    300 } 
    301  
    302  
    303 PJ_DEF(pj_status_t) pj_ice_set_srv_addr(pj_ice *ice, 
    304                                         pj_bool_t enable_relay, 
    305                                         const pj_sockaddr_t *srv_addr, 
    306                                         unsigned addr_len) 
    307 { 
    308     PJ_ASSERT_RETURN(ice && srv_addr, PJ_EINVAL); 
    309     /* Must not have a running resolver. This is because we couldn't 
    310      * safely cancel the query (there is a race condition situation 
    311      * between the callback acquiring the mutex and this function 
    312      * acquiring the mutex) 
    313      */ 
    314     PJ_ASSERT_RETURN(ice->resv_q==NULL, PJ_EBUSY); 
    315  
    316     pj_mutex_lock(ice->mutex); 
    317  
    318     ice->relay_enabled = enable_relay; 
    319     pj_memcpy(&ice->stun_srv, srv_addr, addr_len); 
    320  
    321     pj_mutex_unlock(ice->mutex); 
    322  
    323     return PJ_SUCCESS; 
    324  
    325 } 
    326  
     231static pj_ice_comp *find_comp(const pj_ice *ice, unsigned comp_id) 
     232{ 
     233    unsigned i; 
     234    for (i=0; i<ice->comp_cnt; ++i) { 
     235        if (ice->comp[i].comp_id == comp_id) 
     236            return (pj_ice_comp*) &ice->comp[i]; 
     237    } 
     238 
     239    return NULL; 
     240} 
    327241 
    328242 
     
    332246                                    unsigned addr_len) 
    333247{ 
    334     pj_status_t status; 
    335     pj_sock_t sock; 
    336  
    337     PJ_ASSERT_RETURN(ice && local_addr && addr_len, PJ_EINVAL); 
    338  
    339     status = pj_sock_socket(ice->af, ice->sock_type, 0, &sock); 
    340     if (status != PJ_SUCCESS) 
    341         return status; 
    342  
    343     status = pj_sock_bind(sock, local_addr, addr_len); 
    344     if (status != PJ_SUCCESS) 
    345         return status; 
    346  
    347     status = pj_ice_add_sock_comp(ice, comp_id, sock); 
    348     if (status != PJ_SUCCESS) { 
    349         pj_sock_close(sock); 
    350         return status; 
    351     } 
    352  
    353     return PJ_SUCCESS; 
    354 } 
    355  
    356 typedef struct stun_data 
    357 { 
    358     pj_ice      *ice; 
    359     unsigned     comp_id; 
    360     pj_ice_comp *comp; 
    361 } stun_data; 
    362  
    363  
    364 PJ_DEF(pj_status_t) pj_ice_add_sock_comp( pj_ice *ice, 
    365                                           unsigned comp_id, 
    366                                           pj_sock_t sock) 
    367 { 
    368248    pj_stun_session_cb sess_cb; 
    369249    pj_ice_comp *comp; 
    370250    pj_stun_auth_cred auth_cred; 
    371251    stun_data *sd; 
    372     int addr_len; 
    373252    pj_status_t status; 
    374253 
    375     PJ_ASSERT_RETURN(ice && sock != PJ_INVALID_SOCKET, PJ_EINVAL); 
     254    PJ_ASSERT_RETURN(ice && local_addr && addr_len, PJ_EINVAL); 
    376255    PJ_ASSERT_RETURN(ice->comp_cnt < PJ_ARRAY_SIZE(ice->comp), PJ_ETOOMANY); 
     256    PJ_ASSERT_RETURN(find_comp(ice, comp_id) == NULL, PJ_EEXISTS); 
    377257 
    378258    pj_mutex_lock(ice->mutex); 
     
    380260    comp = &ice->comp[ice->comp_cnt]; 
    381261    comp->comp_id = comp_id; 
    382     comp->sock = sock; 
    383  
    384     addr_len = sizeof(comp->local_addr); 
    385     status = pj_sock_getsockname(sock, &comp->local_addr, &addr_len); 
    386     if (status != PJ_SUCCESS) { 
    387         pj_mutex_unlock(ice->mutex); 
    388         return status; 
    389     } 
    390  
     262    comp->nominated_check_id = -1; 
     263    pj_memcpy(&comp->local_addr, local_addr, addr_len); 
    391264 
    392265    /* Init STUN callbacks */ 
     
    429302    return PJ_SUCCESS; 
    430303} 
    431  
    432304 
    433305static pj_status_t stun_auth_get_auth(void *user_data, 
     
    577449 
    578450 
    579 static pj_status_t gather_host_cands(pj_ice *ice) 
    580 { 
    581     unsigned i; 
    582     pj_status_t status; 
    583  
    584     for (i=0; i<ice->comp_cnt; ++i) { 
    585         pj_ice_comp *comp = &ice->comp[i]; 
    586         pj_sockaddr addr; 
    587         int addr_len; 
    588  
    589         addr_len = sizeof(addr); 
    590         status = pj_sock_getsockname(comp->sock, &addr, &addr_len); 
    591         if (status != PJ_SUCCESS) 
    592             return status; 
    593  
    594         if (addr.ipv4.sin_addr.s_addr == 0) { 
    595             status = pj_gethostip(&addr.ipv4.sin_addr); 
    596             if (status != PJ_SUCCESS) 
    597                 return status; 
    598         } 
    599  
    600         status = pj_ice_add_cand(ice, i, PJ_ICE_CAND_TYPE_HOST, 65535, 
    601                                  &host_foundation, &addr, &addr, NULL, 
    602                                  sizeof(pj_sockaddr_in), NULL); 
    603         if (status != PJ_SUCCESS) 
    604             return status; 
    605     } 
    606  
    607     return PJ_SUCCESS; 
    608 } 
    609  
    610 /* Eliminate redundant candidates. */ 
    611 static void eliminate_redundant_cand(unsigned *cnt, 
    612                                      pj_ice_cand cand[]) 
    613 { 
    614  
    615     /* A candidate is redundant if its transport address equals another  
    616      * candidate, and its base equals the base of that other candidate. 
    617      * Note that two candidates can have the same transport address yet 
    618      * have different bases, and these would not be considered redundant. 
    619      */ 
    620     PJ_TODO(ELIMINATE_REDUNDANT_CANDIDATES); 
    621     PJ_UNUSED_ARG(cnt); 
    622     PJ_UNUSED_ARG(cand); 
    623 } 
    624  
    625  
    626 PJ_DEF(pj_status_t) pj_ice_start_gather(pj_ice *ice, 
    627                                         unsigned flags) 
    628 { 
    629     pj_status_t status; 
    630  
    631     PJ_UNUSED_ARG(flags); 
    632  
    633     /* Gather host candidate */ 
    634     status = gather_host_cands(ice); 
    635     if (status != PJ_SUCCESS) 
    636         return status; 
    637  
    638     /* Eliminate redundant host candidates. */ 
    639     eliminate_redundant_cand(&ice->lcand_cnt, ice->lcand); 
    640  
    641     PJ_TODO(GATHER_MAPPED_AND_RELAYED_CANDIDATES); 
    642  
    643     return PJ_SUCCESS; 
    644 } 
    645  
    646  
    647451static pj_uint32_t CALC_CAND_PRIO(pj_ice_cand_type type, 
    648452                                  pj_uint32_t local_pref, 
     
    652456    { 
    653457        PJ_ICE_HOST_PREF, 
    654         PJ_ICE_MAPPED_PREF, 
    655         PJ_ICE_PEER_MAPPED_PREF, 
     458        PJ_ICE_SRFLX_PREF, 
     459        PJ_ICE_PRFLX_PREF, 
    656460        PJ_ICE_RELAYED_PREF 
    657461    }; 
     
    758562                                            int *cand_id) 
    759563{ 
     564    unsigned i; 
     565 
    760566    PJ_ASSERT_RETURN(ice && comp_id && cand_id, PJ_EINVAL); 
    761567 
     568    *cand_id = -1; 
     569 
    762570    pj_mutex_lock(ice->mutex); 
    763571 
    764572    /* First find in valid list if we have nominated pair */ 
     573    for (i=0; i<ice->valid_cnt; ++i) { 
     574        pj_ice_cand *lcand; 
     575         
     576        lcand = ice->clist.checks[ice->valid_list[i]].lcand; 
     577        if (lcand->comp_id==comp_id) { 
     578            *cand_id = GET_LCAND_ID(lcand); 
     579            pj_mutex_unlock(ice->mutex); 
     580            return PJ_SUCCESS; 
     581        } 
     582    } 
    765583 
    766584    /* If there's no nominated pair, find relayed candidate */ 
     585    for (i=0; i<ice->lcand_cnt; ++i) { 
     586        pj_ice_cand *lcand = &ice->lcand[i]; 
     587        if (lcand->comp_id==comp_id && 
     588            lcand->type == PJ_ICE_CAND_TYPE_RELAYED)  
     589        { 
     590            *cand_id = GET_LCAND_ID(lcand); 
     591            pj_mutex_unlock(ice->mutex); 
     592            return PJ_SUCCESS; 
     593        } 
     594    } 
    767595 
    768596    /* If there's no relayed candidate, find server reflexive candidate */ 
     597    for (i=0; i<ice->lcand_cnt; ++i) { 
     598        pj_ice_cand *lcand = &ice->lcand[i]; 
     599        if (lcand->comp_id==comp_id && 
     600            lcand->type == PJ_ICE_CAND_TYPE_SRFLX)  
     601        { 
     602            *cand_id = GET_LCAND_ID(lcand); 
     603            pj_mutex_unlock(ice->mutex); 
     604            return PJ_SUCCESS; 
     605        } 
     606    } 
    769607 
    770608    /* Otherwise return host candidate */ 
    771  
    772     pj_assert(!"Not implemented yet"); 
    773     PJ_TODO(IMPLEMENT_GET_DEFAULT_CAND); 
    774  
     609    for (i=0; i<ice->lcand_cnt; ++i) { 
     610        pj_ice_cand *lcand = &ice->lcand[i]; 
     611        if (lcand->comp_id==comp_id && 
     612            lcand->type == PJ_ICE_CAND_TYPE_HOST)  
     613        { 
     614            *cand_id = GET_LCAND_ID(lcand); 
     615            pj_mutex_unlock(ice->mutex); 
     616            return PJ_SUCCESS; 
     617        } 
     618    } 
     619 
     620    /* Still no candidate is found! :( */ 
    775621    pj_mutex_unlock(ice->mutex); 
    776622 
    777     return PJ_SUCCESS; 
     623    pj_assert(!"Should have a candidate by now"); 
     624    return PJ_EICENOCAND; 
    778625} 
    779626 
     
    987834        unsigned j; 
    988835 
    989         if (licand->type == PJ_ICE_CAND_TYPE_MAPPED) 
     836        if (licand->type == PJ_ICE_CAND_TYPE_SRFLX) 
    990837            liaddr = &licand->base_addr; 
    991838        else 
     
    997844            const pj_sockaddr *ljaddr; 
    998845 
    999             if (ljcand->type == PJ_ICE_CAND_TYPE_MAPPED) 
     846            if (ljcand->type == PJ_ICE_CAND_TYPE_SRFLX) 
    1000847                ljaddr = &licand->base_addr; 
    1001848            else 
     
    1025872static void on_ice_complete(pj_ice *ice, pj_status_t status) 
    1026873{ 
     874    if (!ice->is_complete) { 
     875 
     876        ice->is_complete = PJ_TRUE; 
     877        ice->ice_status = status; 
     878 
     879        /* Call callback */ 
     880        (*ice->cb.on_ice_complete)(ice, status); 
     881    } 
    1027882} 
    1028883 
     
    1033888{ 
    1034889    unsigned i; 
     890 
     891    pj_assert(check->state >= PJ_ICE_CHECK_STATE_SUCCEEDED); 
    1035892 
    1036893    /* If there is at least one nominated pair in the valid list: 
     
    1043900     *   than the lowest priority nominated pair for that component 
    1044901     */ 
    1045     if (check->nominated) { 
     902    if (check->err_code==PJ_SUCCESS && check->nominated) { 
     903        pj_ice_comp *comp; 
     904 
    1046905        for (i=0; i<ice->clist.count; ++i) { 
    1047906            pj_ice_check *c = &ice->clist.checks[i]; 
     
    1053912                                PJ_ECANCELLED); 
    1054913            } 
     914        } 
     915 
     916        /* Update the nominated check for the component */ 
     917        comp = find_comp(ice, check->lcand->comp_id); 
     918        if (comp->nominated_check_id < 0) { 
     919            comp->nominated_check_id = GET_CHECK_ID(check); 
     920        } else { 
     921            pj_ice_check *nom_check; 
     922            nom_check = &ice->clist.checks[comp->nominated_check_id]; 
     923            if (nom_check->prio < check->prio) 
     924                comp->nominated_check_id = GET_CHECK_ID(check); 
    1055925        } 
    1056926    } 
     
    1125995 
    1126996 
    1127  
    1128  
    1129 typedef struct timer_data 
    1130 { 
    1131     pj_ice              *ice; 
    1132     pj_ice_checklist    *clist; 
    1133 } timer_data; 
    1134  
    1135997PJ_DEF(pj_status_t) pj_ice_create_check_list(pj_ice *ice, 
    1136998                                             unsigned rcand_cnt, 
     
    12621124 
    12631125    /* Add PRIORITY */ 
    1264     prio = CALC_CAND_PRIO(PJ_ICE_CAND_TYPE_PEER_MAPPED, 65535,  
     1126    prio = CALC_CAND_PRIO(PJ_ICE_CAND_TYPE_PRFLX, 65535,  
    12651127                          lcand->comp_id); 
    12661128    pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg, PJ_STUN_ATTR_PRIORITY, 
     
    14231285                                    unsigned addr_len) 
    14241286{ 
    1425     pj_ice *ice = (pj_ice*) pj_stun_session_get_user_data(sess); 
    1426     return (*ice->cb.on_send_pkt)(ice, pkt, pkt_size, dst_addr, addr_len); 
     1287    stun_data *sd = (stun_data*) pj_stun_session_get_user_data(sess); 
     1288    return (*sd->ice->cb.on_tx_pkt)(sd->ice, sd->comp_id,  
     1289                                    pkt, pkt_size,  
     1290                                    dst_addr, addr_len); 
    14271291} 
    14281292 
     
    15001364        /* Add new peer reflexive candidate */ 
    15011365        status = pj_ice_add_cand(ice, lcand->comp_id,  
    1502                                  PJ_ICE_CAND_TYPE_PEER_MAPPED, 
     1366                                 PJ_ICE_CAND_TYPE_PRFLX, 
    15031367                                 65535, &peer_mapped_foundation, 
    15041368                                 &xaddr->sockaddr, &lcand->base_addr, NULL, 
     
    16791543        rcand = &ice->rcand[ice->rcand_cnt++]; 
    16801544        rcand->comp_id = comp->comp_id; 
    1681         rcand->type = PJ_ICE_CAND_TYPE_PEER_MAPPED; 
     1545        rcand->type = PJ_ICE_CAND_TYPE_PRFLX; 
    16821546        rcand->prio = ap->value; 
    16831547        pj_memcpy(&rcand->addr, src_addr, src_addr_len); 
     
    18241688} 
    18251689 
     1690 
     1691PJ_DEF(pj_status_t) pj_ice_send_data( pj_ice *ice, 
     1692                                      unsigned comp_id, 
     1693                                      const void *data, 
     1694                                      pj_size_t data_len) 
     1695{ 
     1696    pj_status_t status = PJ_SUCCESS; 
     1697    pj_ice_comp *comp; 
     1698    pj_ice_check *check; 
     1699 
     1700    PJ_ASSERT_RETURN(ice, PJ_EINVAL); 
     1701     
     1702    pj_mutex_lock(ice->mutex); 
     1703 
     1704    comp = find_comp(ice, comp_id); 
     1705    if (comp == NULL) { 
     1706        status = PJ_EICEINCOMPID; 
     1707        goto on_return; 
     1708    } 
     1709 
     1710    if (comp->nominated_check_id == -1) { 
     1711        status = PJ_EICEINPROGRESS; 
     1712        goto on_return; 
     1713    } 
     1714 
     1715    check = &ice->clist.checks[comp->nominated_check_id]; 
     1716 
     1717    status = (*ice->cb.on_tx_pkt)(ice, comp_id, data, data_len,  
     1718                                  &check->rcand->addr,  
     1719                                  sizeof(pj_sockaddr_in)); 
     1720 
     1721on_return: 
     1722    pj_mutex_unlock(ice->mutex); 
     1723    return status; 
     1724} 
     1725 
     1726 
     1727PJ_DEF(pj_status_t) pj_ice_on_rx_pkt( pj_ice *ice, 
     1728                                      unsigned comp_id, 
     1729                                      void *pkt, 
     1730                                      pj_size_t pkt_size, 
     1731                                      const pj_sockaddr_t *src_addr, 
     1732                                      int src_addr_len) 
     1733{ 
     1734    pj_status_t status = PJ_SUCCESS; 
     1735    pj_ice_comp *comp; 
     1736    pj_bool_t is_stun; 
     1737 
     1738    PJ_ASSERT_RETURN(ice, PJ_EINVAL); 
     1739 
     1740    pj_mutex_lock(ice->mutex); 
     1741 
     1742    comp = find_comp(ice, comp_id); 
     1743    if (comp == NULL) { 
     1744        status = PJ_EICEINCOMPID; 
     1745        goto on_return; 
     1746    } 
     1747 
     1748    is_stun = pj_stun_msg_check(pkt, pkt_size, PJ_STUN_IS_DATAGRAM); 
     1749    if (is_stun) { 
     1750        status = pj_stun_session_on_rx_pkt(comp->stun_sess, pkt, pkt_size, 
     1751                                           PJ_STUN_IS_DATAGRAM, 
     1752                                           NULL, src_addr, src_addr_len); 
     1753    } else { 
     1754        status = (*ice->cb.on_rx_data)(ice, comp_id, pkt, pkt_size,  
     1755                                       src_addr, src_addr_len); 
     1756    } 
     1757     
     1758 
     1759on_return: 
     1760    pj_mutex_unlock(ice->mutex); 
     1761    return status; 
     1762} 
     1763 
     1764 
Note: See TracChangeset for help on using the changeset viewer.