Changeset 1152


Ignore:
Timestamp:
Apr 5, 2007 11:32:47 AM (17 years ago)
Author:
bennylp
Message:

ICE (work in progress): handle early check that is received before answer

Location:
pjproject/trunk
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/src/pjmedia/transport_ice.c

    r1140 r1152  
    465465                        (pj_uint16_t)sdp_med->desc.port); 
    466466 
    467     /* Find ice-ufrag attribute in session descriptor */ 
    468     attr = pjmedia_sdp_attr_find2(rem_sdp->attr_count, rem_sdp->attr, 
     467    /* Find ice-ufrag attribute in media descriptor */ 
     468    attr = pjmedia_sdp_attr_find2(sdp_med->attr_count, sdp_med->attr, 
    469469                                  "ice-ufrag", NULL); 
    470470    if (attr == NULL) { 
    471         /* Find in media descriptor */ 
    472         attr = pjmedia_sdp_attr_find2(sdp_med->attr_count, sdp_med->attr, 
     471        /* Find ice-ufrag attribute in session descriptor */ 
     472        attr = pjmedia_sdp_attr_find2(rem_sdp->attr_count, rem_sdp->attr, 
    473473                                      "ice-ufrag", NULL); 
    474474        if (attr == NULL) { 
     
    479479    uname = attr->value; 
    480480 
    481     /* Find ice-pwd attribute in session descriptor */ 
    482     attr = pjmedia_sdp_attr_find2(rem_sdp->attr_count, rem_sdp->attr, 
     481    /* Find ice-pwd attribute in media descriptor */ 
     482    attr = pjmedia_sdp_attr_find2(sdp_med->attr_count, sdp_med->attr, 
    483483                                  "ice-pwd", NULL); 
    484484    if (attr == NULL) { 
    485         /* Not found, find in media descriptor */ 
    486         attr = pjmedia_sdp_attr_find2(sdp_med->attr_count, sdp_med->attr, 
     485        /* Find ice-pwd attribute in session descriptor */ 
     486        attr = pjmedia_sdp_attr_find2(rem_sdp->attr_count, rem_sdp->attr, 
    487487                                      "ice-pwd", NULL); 
    488488        if (attr == NULL) { 
  • pjproject/trunk/pjnath/include/pjnath/config.h

    r1140 r1152  
    166166 
    167167/** 
     168 * According to ICE Section 8.2. Updating States, if an In-Progress pair in  
     169 * the check list is for the same component as a nominated pair, the agent  
     170 * SHOULD cease retransmissions for its check if its pair priority is lower 
     171 * than the lowest priority nominated pair for that component. 
     172 * 
     173 * If a higher priority check is In Progress, this rule would cause that 
     174 * check to be performed even when it most likely will fail. 
     175 * 
     176 * The macro here controls if ICE session should cancel all In Progress  
     177 * checks for the same component regardless of its priority. 
     178 * 
     179 * Default: 1 (yes, cancel all) 
     180 */ 
     181#ifndef PJ_ICE_CANCEL_ALL 
     182#   define PJ_ICE_CANCEL_ALL                        1 
     183#endif 
     184 
     185 
     186/** 
    168187 * Minimum interval value to be used for sending STUN keep-alive on the ICE 
    169188 * stream transport, in seconds. This minimum interval, plus a random value 
     
    196215 
    197216 
    198  
    199217/** 
    200218 * @} 
  • pjproject/trunk/pjnath/include/pjnath/ice_session.h

    r1141 r1152  
    420420 
    421421/** 
     422 * This structure represents an incoming check (an incoming Binding 
     423 * request message), and is mainly used to keep early checks in the 
     424 * list in the ICE session. An early check is a request received 
     425 * from remote when we haven't received SDP answer yet, therefore we 
     426 * can't perform triggered check. For such cases, keep the incoming 
     427 * request in a list, and we'll do triggered checks (simultaneously) 
     428 * as soon as we receive answer. 
     429 */ 
     430typedef struct pj_ice_rx_check 
     431{ 
     432    PJ_DECL_LIST_MEMBER(struct pj_ice_rx_check); 
     433 
     434    unsigned             comp_id;       /**< Component ID.              */ 
     435 
     436    pj_sockaddr          src_addr;      /**< Source address of request  */ 
     437    unsigned             src_addr_len;  /**< Length of src address.     */ 
     438 
     439    pj_bool_t            use_candidate; /**< USE-CANDIDATE is present?  */ 
     440    pj_uint32_t          priority;      /**< PRIORITY value in the req. */ 
     441    pj_stun_uint64_attr *role_attr;     /**< ICE-CONTROLLING/CONTROLLED */ 
     442 
     443} pj_ice_rx_check; 
     444 
     445 
     446/** 
    422447 * This structure describes the ICE session. For this version of PJNATH, 
    423448 * an ICE session corresponds to a single media stream (unlike the ICE 
     
    463488    unsigned             rcand_cnt;                 /**< # of remote cand.  */ 
    464489    pj_ice_sess_cand     rcand[PJ_ICE_MAX_CAND];    /**< Array of cand.     */ 
     490 
     491    /* List of eearly checks */ 
     492    pj_ice_rx_check      early_check;               /**< Early checks.      */ 
    465493 
    466494    /* Checklist */ 
  • pjproject/trunk/pjnath/include/pjnath/stun_session.h

    r1141 r1152  
    359359 
    360360/** 
     361 * Explicitly request retransmission of the request. Normally application 
     362 * doesn't need to do this, but this functionality is needed by ICE to 
     363 * speed up connectivity check completion. 
     364 * 
     365 * @param sess      The STUN session instance. 
     366 * @param tdata     The request message previously sent. 
     367 * 
     368 * @return          PJ_SUCCESS on success, or the appropriate error. 
     369 */ 
     370PJ_DECL(pj_status_t) pj_stun_session_retransmit_req(pj_stun_session *sess, 
     371                                                    pj_stun_tx_data *tdata); 
     372 
     373 
     374/** 
    361375 * Application must call this function to notify the STUN session about 
    362376 * the arrival of STUN packet. The STUN packet MUST have been checked 
  • pjproject/trunk/pjnath/include/pjnath/stun_transaction.h

    r1141 r1152  
    222222                                                 unsigned pkt_len); 
    223223 
     224/** 
     225 * Request to retransmit the request. Normally application should not need 
     226 * to call this function since retransmission would be handled internally, 
     227 * but this functionality is needed by ICE. 
     228 * 
     229 * @param tsx           The STUN client transaction instance. 
     230 * 
     231 * @return              PJ_SUCCESS on success or the appropriate error code. 
     232 */ 
     233PJ_DECL(pj_status_t) pj_stun_client_tsx_retransmit(pj_stun_client_tsx *tsx); 
    224234 
    225235 
  • pjproject/trunk/pjnath/src/pjnath/ice_session.c

    r1144 r1152  
    8181 
    8282 
     83/* The data that will be attached to the STUN session on each 
     84 * component. 
     85 */ 
    8386typedef struct stun_data 
    8487{ 
     
    8891} stun_data; 
    8992 
     93 
     94/* The data that will be attached to the timer to perform 
     95 * periodic check. 
     96 */ 
    9097typedef struct timer_data 
    9198{ 
     
    95102 
    96103 
    97  
     104/* Forward declarations */ 
    98105static void destroy_ice(pj_ice_sess *ice, 
    99106                        pj_status_t reason); 
     
    101108                                        pj_timer_entry *te); 
    102109static void periodic_timer(pj_timer_heap_t *th,  
    103                          pj_timer_entry *te); 
     110                          pj_timer_entry *te); 
     111static void handle_incoming_check(pj_ice_sess *ice, 
     112                                  const pj_ice_rx_check *rcheck); 
     113 
     114/* These are the callbacks registered to the STUN sessions */ 
    104115static pj_status_t on_stun_send_msg(pj_stun_session *sess, 
    105116                                    const void *pkt, 
     
    126137                                         unsigned src_addr_len); 
    127138 
     139/* These are the callbacks for performing STUN authentication */ 
    128140static pj_status_t stun_auth_get_auth(void *user_data, 
    129141                                      pj_pool_t *pool, 
     
    299311    } 
    300312 
     313    pj_list_init(&ice->early_check); 
    301314 
    302315    /* Done */ 
     
    483496         * or answer for a session in-progress, and the MESSAGE-INTEGRITY  
    484497         * is the output of a hash of the password and the STUN packet's  
    485          * contents.  
     498         * contents. 
    486499         */ 
    487         PJ_TODO(CHECK_USERNAME_FOR_INCOMING_STUN_REQUEST); 
     500        const char *pos; 
     501        pj_str_t ufrag; 
     502 
     503        pos = (const char*)pj_memchr(username->ptr, ':', username->slen); 
     504        if (pos == NULL) 
     505            return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNKNOWN_USERNAME); 
     506 
     507        ufrag.ptr = (char*)username->ptr; 
     508        ufrag.slen = (pos - username->ptr); 
     509 
     510        if (pj_strcmp(&ufrag, &ice->rx_ufrag) != 0) 
     511            return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNKNOWN_USERNAME); 
     512 
    488513        *data_type = 0; 
    489514        *data = ice->rx_pass; 
     
    921946     *  
    922947     * 1.  The agent changes the states for all other Frozen pairs for the 
    923      * same media stream and same foundation to Waiting.  Typically 
    924      * these other pairs will have different component IDs but not 
    925      * always. 
    926      */ 
    927  
    928  
    929     /* If there is at least one nominated pair in the valid list: 
    930      * - The agent MUST remove all Waiting and Frozen pairs in the check 
    931      *   list for the same component as the nominated pairs for that 
    932      *   media stream 
    933      * - If an In-Progress pair in the check list is for the same 
    934      *   component as a nominated pair, the agent SHOULD cease 
    935      *   retransmissions for its check if its pair priority is lower 
    936      *   than the lowest priority nominated pair for that component 
     948     *     same media stream and same foundation to Waiting.  Typically 
     949     *     these other pairs will have different component IDs but not 
     950     *     always. 
     951     */ 
     952    if (check->err_code==PJ_SUCCESS) { 
     953        for (i=0; i<ice->clist.count; ++i) { 
     954            pj_ice_sess_check *c = &ice->clist.checks[i]; 
     955            if (pj_strcmp(&c->lcand->foundation, &check->lcand->foundation)==0 
     956                 && c->state == PJ_ICE_SESS_CHECK_STATE_FROZEN) 
     957            { 
     958                check_set_state(ice, c, PJ_ICE_SESS_CHECK_STATE_WAITING, 0); 
     959            } 
     960        } 
     961    } 
     962 
     963    /* 8.2.  Updating States 
     964     *  
     965     * For both controlling and controlled agents, the state of ICE 
     966     * processing depends on the presence of nominated candidate pairs in 
     967     * the valid list and on the state of the check list: 
     968     * 
     969     * o  If there are no nominated pairs in the valid list for a media 
     970     *    stream and the state of the check list is Running, ICE processing 
     971     *    continues. 
     972     * 
     973     * o  If there is at least one nominated pair in the valid list: 
     974     * 
     975     *    - The agent MUST remove all Waiting and Frozen pairs in the check 
     976     *      list for the same component as the nominated pairs for that 
     977     *      media stream 
     978     * 
     979     *    - If an In-Progress pair in the check list is for the same 
     980     *      component as a nominated pair, the agent SHOULD cease 
     981     *      retransmissions for its check if its pair priority is lower 
     982     *      than the lowest priority nominated pair for that component 
    937983     */ 
    938984    if (check->err_code==PJ_SUCCESS && check->nominated) { 
     
    946992 
    947993        for (i=0; i<ice->clist.count; ++i) { 
     994 
    948995            pj_ice_sess_check *c = &ice->clist.checks[i]; 
     996 
    949997            if (c->lcand->comp_id == check->lcand->comp_id) { 
     998 
    950999                if (c->state < PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS) { 
     1000 
    9511001                    /* Just fail Frozen/Waiting check */ 
    9521002                    LOG5((ice->obj_name,  
     
    9571007                                    PJ_ECANCELLED); 
    9581008 
    959                 } else if (c->state == PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS) { 
     1009                } else if (c->state == PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS 
     1010                           && (PJ_ICE_CANCEL_ALL || 
     1011                                CMP_CHECK_PRIO(c, check) < 0)) { 
     1012 
    9601013                    /* State is IN_PROGRESS, cancel transaction */ 
    9611014                    if (c->tdata) { 
     
    9821035    } 
    9831036 
    984     /* Once there is at least one nominated pair in the valid list for 
    985      * every component of at least one media stream: 
    986      * - The agent MUST change the state of processing for its check 
    987      *   list for that media stream to Completed. 
    988      * - The agent MUST continue to respond to any checks it may still 
    989      *   receive for that media stream, and MUST perform triggered 
    990      *   checks if required by the processing of Section 7.2. 
    991      * - The agent MAY begin transmitting media for this media stream as 
    992      *   described in Section 11.1 
    993      */ 
    994     /* TODO */ 
    995  
    996     /* Once there is at least one nominated pair in the valid list for 
    997      * each component of each media stream: 
    998      * - The agent sets the state of ICE processing overall to 
    999      *   Completed. 
    1000      * - If an agent is controlling, it examines the highest priority 
    1001      *   nominated candidate pair for each component of each media 
    1002      *   stream.  If any of those candidate pairs differ from the 
    1003      *   default candidate pairs in the most recent offer/answer 
    1004      *   exchange, the controlling agent MUST generate an updated offer 
    1005      *   as described in Section 9.  If the controlling agent is using 
    1006      *   an aggressive nomination algorithm, this may result in several 
    1007      *   updated offers as the pairs selected for media change.  An 
    1008      *   agent MAY delay sending the offer for a brief interval (one 
    1009      *   second is RECOMMENDED) in order to allow the selected pairs to 
    1010      *   stabilize. 
    1011      */ 
    1012     /* TODO */ 
    1013  
     1037 
     1038    /* Still in 8.2.  Updating States 
     1039     *  
     1040     * o  Once there is at least one nominated pair in the valid list for 
     1041     *    every component of at least one media stream and the state of the 
     1042     *    check list is Running: 
     1043     *     
     1044     *    *  The agent MUST change the state of processing for its check 
     1045     *       list for that media stream to Completed. 
     1046     *     
     1047     *    *  The agent MUST continue to respond to any checks it may still 
     1048     *       receive for that media stream, and MUST perform triggered 
     1049     *       checks if required by the processing of Section 7.2. 
     1050     *     
     1051     *    *  The agent MAY begin transmitting media for this media stream as 
     1052     *       described in Section 11.1 
     1053     */ 
    10141054 
    10151055    /* See if all components have nominated pair. If they do, then mark 
     
    10251065        return PJ_TRUE; 
    10261066    } 
     1067 
     1068    /* Note: this is the stuffs that we don't do in 7.1.2.2.2, since our 
     1069     *       ICE session only supports one media stream for now: 
     1070     *  
     1071     * 7.1.2.2.2.  Updating Pair States 
     1072     * 
     1073     * 2.  If there is a pair in the valid list for every component of this 
     1074     *     media stream (where this is the actual number of components being 
     1075     *     used, in cases where the number of components signaled in the SDP 
     1076     *     differs from offerer to answerer), the success of this check may 
     1077     *     unfreeze checks for other media streams.  
     1078     */ 
     1079 
     1080    /* 7.1.2.3.  Check List and Timer State Updates 
     1081     * Regardless of whether the check was successful or failed, the 
     1082     * completion of the transaction may require updating of check list and 
     1083     * timer states. 
     1084     *  
     1085     * If all of the pairs in the check list are now either in the Failed or 
     1086     * Succeeded state, and there is not a pair in the valid list for each 
     1087     * component of the media stream, the state of the check list is set to 
     1088     * Failed.   
     1089     */ 
    10271090 
    10281091    /*  
     
    13661429} 
    13671430 
    1368 /* Start ICE check */ 
     1431 
     1432/* 
     1433 * Start ICE periodic check. This function will return immediately, and 
     1434 * application will be notified about the connectivity check status in 
     1435 * #pj_ice_sess_cb callback. 
     1436 */ 
    13691437PJ_DEF(pj_status_t) pj_ice_sess_start_check(pj_ice_sess *ice) 
    13701438{ 
     
    13721440    const pj_ice_sess_cand *cand0; 
    13731441    const pj_str_t *flist[PJ_ICE_MAX_CAND]; 
     1442    pj_ice_rx_check *rcheck; 
    13741443    unsigned i, flist_cnt = 0; 
    13751444 
     
    14291498    } 
    14301499 
     1500    /* First, perform all pending triggered checks, simultaneously. */ 
     1501    rcheck = ice->early_check.next; 
     1502    while (rcheck != &ice->early_check) { 
     1503        LOG4((ice->obj_name,  
     1504              "Performing delayed triggerred check for component %d", 
     1505              rcheck->comp_id)); 
     1506        handle_incoming_check(ice, rcheck); 
     1507        rcheck = rcheck->next; 
     1508    } 
     1509    pj_list_init(&ice->early_check); 
     1510 
    14311511    /* Start periodic check */ 
    14321512    return start_periodic_check(ice->stun_cfg.timer_heap, &clist->timer); 
     
    14921572 
    14931573        if (status==PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_ROLE_CONFLICT)) { 
     1574 
    14941575            /* Role conclict response. 
     1576             * 
    14951577             * 7.1.2.1.  Failure Cases: 
     1578             * 
    14961579             * If the request had contained the ICE-CONTROLLED attribute,  
    14971580             * the agent MUST switch to the controlling role if it has not 
     
    15181601            if (new_role != ice->role) { 
    15191602                LOG4((ice->obj_name,  
    1520                       "Changing role because of role conflict")); 
     1603                      "Changing role because of role conflict response")); 
    15211604                pj_ice_sess_change_role(ice, new_role); 
    15221605            } 
     
    15441627 
    15451628 
    1546     /* The agent MUST check that the source IP address and port of the 
     1629    /* 7.1.2.1.  Failure Cases 
     1630     * 
     1631     * The agent MUST check that the source IP address and port of the 
    15471632     * response equals the destination IP address and port that the Binding 
    15481633     * Request was sent to, and that the destination IP address and port of 
     
    15621647    } 
    15631648 
     1649    /* 7.1.2.2.  Success Cases 
     1650     *  
     1651     * A check is considered to be a success if all of the following are 
     1652     * true: 
     1653     *  
     1654     * o  the STUN transaction generated a success response 
     1655     *  
     1656     * o  the source IP address and port of the response equals the 
     1657     *    destination IP address and port that the Binding Request was sent 
     1658     *    to 
     1659     *  
     1660     * o  the destination IP address and port of the response match the 
     1661     *    source IP address and port that the Binding Request was sent from 
     1662     */ 
     1663 
     1664 
    15641665    LOG4((ice->obj_name,  
    15651666         "Check %s%s: connectivity check SUCCESS", 
     
    15881689    } 
    15891690 
    1590     /* If the transport address returned in XOR-MAPPED-ADDRESS does not match 
     1691    /* 7.1.2.2.1.  Discovering Peer Reflexive Candidates 
     1692     * If the transport address returned in XOR-MAPPED-ADDRESS does not match 
    15911693     * any of the local candidates that the agent knows about, the mapped  
    15921694     * address represents a new candidate - a peer reflexive candidate. 
     
    15991701                               &check->lcand->base_addr); 
    16001702 
    1601         /* According to: 7.1.2.2.1. Discovering Peer Reflexive Candidates: 
     1703        /* Still in 7.1.2.2.1.  Discovering Peer Reflexive Candidates 
    16021704         * Its priority is set equal to the value of the PRIORITY attribute 
    16031705         * in the Binding Request. 
     
    16281730    } 
    16291731 
     1732    /* 7.1.2.2.3.  Constructing a Valid Pair 
     1733     * Next, the agent constructs a candidate pair whose local candidate 
     1734     * equals the mapped address of the response, and whose remote candidate 
     1735     * equals the destination address to which the request was sent.     
     1736     */ 
     1737 
    16301738    /* Add pair to valid list */ 
     1739    pj_assert(ice->valid_list.count < PJ_ICE_MAX_CHECKS); 
    16311740    new_check = &ice->valid_list.checks[ice->valid_list.count++]; 
    16321741    new_check->lcand = lcand; 
     
    16411750 
    16421751 
    1643     /* Sets the state of the original pair that generated the check to  
    1644      * succeeded.  
     1752    /* 7.1.2.2.2.  Updating Pair States 
     1753     *  
     1754     * The agent sets the state of the pair that generated the check to 
     1755     * Succeeded.  The success of this check might also cause the state of 
     1756     * other checks to change as well. 
    16451757     */ 
    16461758    check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_SUCCEEDED,  
    16471759                    PJ_SUCCESS); 
    16481760 
    1649     /* Inform about check completion. 
     1761    /* Perform 7.1.2.2.2.  Updating Pair States. 
    16501762     * This may terminate ICE processing. 
    16511763     */ 
     
    16561768    } 
    16571769 
    1658     /* If the pair had a component ID of 1, the agent MUST change the 
    1659      * states for all other Frozen pairs for the same media stream and 
    1660      * same foundation, but different component IDs, to Waiting. 
    1661      */ 
    1662     if (lcand->comp_id == 1) { 
    1663         unsigned i; 
    1664         pj_bool_t unfrozen = PJ_FALSE; 
    1665  
    1666         for (i=0; i<clist->count; ++i)  { 
    1667             pj_ice_sess_check *c = &clist->checks[i]; 
    1668  
    1669             if (c->state == PJ_ICE_SESS_CHECK_STATE_FROZEN && 
    1670                 c->lcand->comp_id != lcand->comp_id && 
    1671                 pj_strcmp(&c->lcand->foundation, &lcand->foundation)==0) 
    1672             { 
    1673                 /* Unfreeze and start check */ 
    1674                 check_set_state(ice, c, PJ_ICE_SESS_CHECK_STATE_WAITING,  
    1675                                 PJ_SUCCESS); 
    1676                 unfrozen = PJ_TRUE; 
    1677             } 
    1678         } 
    1679  
    1680         if (unfrozen && clist->timer.id == PJ_FALSE) 
    1681             start_periodic_check(ice->stun_cfg.timer_heap, &clist->timer); 
    1682     }  
    1683  
    1684     /* If the pair had a component ID equal to the number of components 
    1685      * for the media stream (where this is the actual number of 
    1686      * components being used, in cases where the number of components 
    1687      * signaled in the SDP differs from offerer to answerer), the agent 
    1688      * MUST change the state for all other Frozen pairs for the first 
    1689      * component of different media streams (and thus in different check 
    1690      * lists) but the same foundation, to Waiting. 
    1691      */ 
    1692     else if (0) { 
    1693         PJ_TODO(UNFREEZE_OTHER_COMPONENT_ID); 
    1694     } 
    1695     /* If the pair has any other component ID, no other pairs can be 
    1696      * unfrozen. 
    1697      */ 
    1698     else { 
    1699         PJ_TODO(UNFREEZE_OTHER_COMPONENT_ID1); 
    1700     } 
    1701  
    17021770    pj_mutex_unlock(ice->mutex); 
    17031771} 
     1772 
    17041773 
    17051774/* This callback is called by the STUN session associated with a candidate 
     
    17151784    stun_data *sd; 
    17161785    pj_ice_sess *ice; 
    1717     pj_stun_priority_attr *ap; 
    1718     pj_stun_use_candidate_attr *uc; 
    1719     pj_ice_sess_comp *comp; 
    1720     pj_ice_sess_cand *lcand = NULL; 
    1721     pj_ice_sess_cand *rcand; 
    1722     unsigned i; 
     1786    pj_stun_priority_attr *prio_attr; 
     1787    pj_stun_use_candidate_attr *uc_attr; 
     1788    pj_stun_uint64_attr *role_attr; 
    17231789    pj_stun_tx_data *tdata; 
    1724     pj_bool_t is_relayed; 
     1790    pj_ice_rx_check *rcheck, tmp_rcheck; 
    17251791    pj_status_t status; 
    17261792 
     
    17431809    sd = (stun_data*) pj_stun_session_get_user_data(sess); 
    17441810    ice = sd->ice; 
    1745     comp = sd->comp; 
    17461811 
    17471812    pj_mutex_lock(ice->mutex); 
    17481813 
     1814    /* 
     1815     * Note: 
     1816     *  Be aware that when STUN request is received, we might not get 
     1817     *  SDP answer yet, so we might not have remote candidates and 
     1818     *  checklist yet. This case will be handled after we send 
     1819     *  a response. 
     1820     */ 
     1821 
    17491822    /* Get PRIORITY attribute */ 
    1750     ap = (pj_stun_priority_attr*) 
    1751          pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_PRIORITY, 0); 
    1752     if (ap == 0) { 
     1823    prio_attr = (pj_stun_priority_attr*) 
     1824                pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_PRIORITY, 0); 
     1825    if (prio_attr == NULL) { 
    17531826        LOG5((ice->obj_name, "Received Binding request with no PRIORITY")); 
    17541827        pj_mutex_unlock(ice->mutex); 
     
    17571830 
    17581831    /* Get USE-CANDIDATE attribute */ 
    1759     uc = (pj_stun_use_candidate_attr*) 
    1760          pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_USE_CANDIDATE, 0); 
    1761  
    1762     /* For simplicity, ignore incoming requests when we don't have remote 
    1763      * candidates yet. The peer agent should retransmit the STUN request 
    1764      * and we'll receive it again later. 
    1765      */ 
    1766     if (ice->rcand_cnt == 0) { 
    1767         pj_mutex_unlock(ice->mutex); 
    1768         return PJ_SUCCESS; 
    1769     } 
     1832    uc_attr = (pj_stun_use_candidate_attr*) 
     1833              pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_USE_CANDIDATE, 0); 
     1834 
     1835 
     1836    /* Get ICE-CONTROLLING or ICE-CONTROLLED */ 
     1837    role_attr = (pj_stun_uint64_attr*) 
     1838                pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_ICE_CONTROLLING, 0); 
     1839    if (role_attr == NULL) { 
     1840        role_attr = (pj_stun_uint64_attr*) 
     1841                    pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_ICE_CONTROLLED, 0); 
     1842    } 
     1843 
     1844    /* 7.2.1.1.  Detecting and Repairing Role Conflicts 
     1845     */ 
     1846    if (ice->role == PJ_ICE_SESS_ROLE_CONTROLLING && 
     1847        role_attr && role_attr->hdr.type == PJ_STUN_ATTR_ICE_CONTROLLING) 
     1848    { 
     1849        if (pj_cmp_timestamp(&ice->tie_breaker, &role_attr->value) < 0) { 
     1850            /* Switch role to controlled */ 
     1851            LOG4((ice->obj_name,  
     1852                  "Changing role because of ICE-CONTROLLING attribute")); 
     1853            pj_ice_sess_change_role(ice, PJ_ICE_SESS_ROLE_CONTROLLED); 
     1854        } else { 
     1855            /* Generate 487 response */ 
     1856            status = pj_stun_session_create_response(sess, msg,  
     1857                                                     PJ_STUN_SC_ROLE_CONFLICT, 
     1858                                                     NULL, &tdata); 
     1859            if (status == PJ_SUCCESS) { 
     1860                pj_stun_session_send_msg(sess, PJ_TRUE,  
     1861                                         src_addr, src_addr_len, tdata); 
     1862            } 
     1863            pj_mutex_unlock(ice->mutex); 
     1864            return PJ_SUCCESS; 
     1865        } 
     1866 
     1867    } else if (ice->role == PJ_ICE_SESS_ROLE_CONTROLLED && 
     1868               role_attr && role_attr->hdr.type == PJ_STUN_ATTR_ICE_CONTROLLED) 
     1869    { 
     1870        if (pj_cmp_timestamp(&ice->tie_breaker, &role_attr->value) < 0) { 
     1871            /* Generate 487 response */ 
     1872            status = pj_stun_session_create_response(sess, msg,  
     1873                                                     PJ_STUN_SC_ROLE_CONFLICT, 
     1874                                                     NULL, &tdata); 
     1875            if (status == PJ_SUCCESS) { 
     1876                pj_stun_session_send_msg(sess, PJ_TRUE,  
     1877                                         src_addr, src_addr_len, tdata); 
     1878            } 
     1879            pj_mutex_unlock(ice->mutex); 
     1880            return PJ_SUCCESS; 
     1881        } else { 
     1882            /* Switch role to controlled */ 
     1883            LOG4((ice->obj_name,  
     1884                  "Changing role because of ICE-CONTROLLED attribute")); 
     1885            pj_ice_sess_change_role(ice, PJ_ICE_SESS_ROLE_CONTROLLING); 
     1886        } 
     1887    } 
     1888 
    17701889 
    17711890    /*  
     
    17861905 
    17871906 
     1907    /*  
     1908     * Handling early check. 
     1909     * 
     1910     * It's possible that we receive this request before we receive SDP 
     1911     * answer. In this case, we can't perform trigger check since we 
     1912     * don't have checklist yet, so just save this check in a pending 
     1913     * triggered check array to be acted upon later. 
     1914     */ 
     1915    if (ice->rcand_cnt == 0) { 
     1916        rcheck = PJ_POOL_ZALLOC_T(ice->pool, pj_ice_rx_check); 
     1917    } else { 
     1918        rcheck = &tmp_rcheck; 
     1919    } 
     1920 
     1921    /* Init rcheck */ 
     1922    rcheck->comp_id = sd->comp_id; 
     1923    rcheck->src_addr_len = src_addr_len; 
     1924    pj_memcpy(&rcheck->src_addr, src_addr, src_addr_len); 
     1925    rcheck->use_candidate = (uc_attr != NULL); 
     1926    rcheck->priority = prio_attr->value; 
     1927    rcheck->role_attr = role_attr; 
     1928 
     1929    if (ice->rcand_cnt == 0) { 
     1930        /* We don't have answer yet, so keep this request for later */ 
     1931        LOG4((ice->obj_name, "Received an early check for comp %d", 
     1932              rcheck->comp_id)); 
     1933        pj_list_push_back(&ice->early_check, rcheck); 
     1934    } else { 
     1935        /* Handle this check */ 
     1936        handle_incoming_check(ice, rcheck); 
     1937    } 
     1938 
     1939    pj_mutex_unlock(ice->mutex); 
     1940    return PJ_SUCCESS; 
     1941} 
     1942 
     1943 
     1944/* Handle incoming Binding request and perform triggered check. 
     1945 * This function may be called by on_stun_rx_request(), or when 
     1946 * SDP answer is received and we have received early checks. 
     1947 */ 
     1948static void handle_incoming_check(pj_ice_sess *ice, 
     1949                                  const pj_ice_rx_check *rcheck) 
     1950{ 
     1951    pj_ice_sess_comp *comp; 
     1952    pj_ice_sess_cand *lcand = NULL; 
     1953    pj_ice_sess_cand *rcand; 
     1954    unsigned i; 
     1955    pj_bool_t is_relayed; 
     1956 
     1957    comp = find_comp(ice, rcheck->comp_id); 
     1958 
    17881959    /* Find remote candidate based on the source transport address of  
    17891960     * the request. 
    17901961     */ 
    17911962    for (i=0; i<ice->rcand_cnt; ++i) { 
    1792         if (sockaddr_cmp((const pj_sockaddr*)src_addr, &ice->rcand[i].addr)==0) 
     1963        if (sockaddr_cmp(&rcheck->src_addr, &ice->rcand[i].addr)==0) 
    17931964            break; 
    17941965    } 
    17951966 
    1796     /* If the source transport address of the request does not match any 
     1967    /* 7.2.1.3.  Learning Peer Reflexive Candidates 
     1968     * If the source transport address of the request does not match any 
    17971969     * existing remote candidates, it represents a new peer reflexive remote 
    17981970     * candidate. 
     
    18001972    if (i == ice->rcand_cnt) { 
    18011973        rcand = &ice->rcand[ice->rcand_cnt++]; 
    1802         rcand->comp_id = sd->comp_id; 
     1974        rcand->comp_id = rcheck->comp_id; 
    18031975        rcand->type = PJ_ICE_CAND_TYPE_PRFLX; 
    1804         rcand->prio = ap->value; 
    1805         pj_memcpy(&rcand->addr, src_addr, src_addr_len); 
     1976        rcand->prio = rcheck->priority; 
     1977        pj_memcpy(&rcand->addr, &rcheck->src_addr, rcheck->src_addr_len); 
    18061978 
    18071979        /* Foundation is random, unique from other foundation */ 
    1808         rcand->foundation.ptr = pj_pool_alloc(ice->pool, 32); 
    1809         rcand->foundation.slen = pj_ansi_snprintf(rcand->foundation.ptr, 32, 
     1980        rcand->foundation.ptr = pj_pool_alloc(ice->pool, 36); 
     1981        rcand->foundation.slen = pj_ansi_snprintf(rcand->foundation.ptr, 36, 
    18101982                                                  "f%p",  
    18111983                                                  rcand->foundation.ptr); 
     
    18432015    for (i=0; i<ice->clist.count; ++i) { 
    18442016        pj_ice_sess_check *c = &ice->clist.checks[i]; 
    1845         if (c->lcand->comp_id == sd->comp_id) { 
     2017        if (c->lcand->comp_id == rcheck->comp_id) { 
    18462018            lcand = c->lcand; 
    18472019            break; 
    18482020        } 
    18492021    } 
    1850     pj_assert(lcand != NULL); 
     2022    if (lcand == NULL) { 
     2023        /* Should not happen, but just in case remote is sending a 
     2024         * Binding request for a component which it doesn't have. 
     2025         */ 
     2026        LOG4((ice->obj_name,  
     2027             "Received Binding request but no local candidate is found!")); 
     2028        return; 
     2029    } 
    18512030#endif 
    18522031 
     
    18602039    is_relayed = PJ_FALSE; 
    18612040 
    1862     /* Now that we have local and remote candidate, check if we already 
     2041    /*  
     2042     * 7.2.1.4.  Triggered Checks 
     2043     * 
     2044     * Now that we have local and remote candidate, check if we already 
    18632045     * have this pair in our checklist. 
    18642046     */ 
     
    18882070         * Note: DO NOT overwrite nominated flag if one is already set. 
    18892071         */ 
    1890         c->nominated = ((uc != NULL) || c->nominated); 
     2072        c->nominated = ((rcheck->use_candidate) || c->nominated); 
    18912073 
    18922074        if (c->state == PJ_ICE_SESS_CHECK_STATE_FROZEN || 
     
    18972079 
    18982080        } else if (c->state == PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS) { 
    1899             /* Should retransmit here, but how?? 
    1900              * TODO 
     2081            /* Should retransmit immediately 
    19012082             */ 
    19022083            LOG5((ice->obj_name, "Triggered check for check %d not performed " 
    1903                                 "because it's in progress", i)); 
     2084                  "because it's in progress. Retransmitting", i)); 
     2085            pj_stun_session_retransmit_req(comp->stun_sess, c->tdata); 
     2086 
    19042087        } else if (c->state == PJ_ICE_SESS_CHECK_STATE_SUCCEEDED) { 
    19052088            /* Check complete for this component. 
     
    19132096            complete = on_check_complete(ice, c); 
    19142097            if (complete) { 
    1915                 pj_mutex_unlock(ice->mutex); 
    1916                 return PJ_SUCCESS; 
     2098                return; 
    19172099            } 
    19182100        } 
     
    19332115        c->prio = CALC_CHECK_PRIO(ice, lcand, rcand); 
    19342116        c->state = PJ_ICE_SESS_CHECK_STATE_WAITING; 
    1935         c->nominated = (uc != NULL); 
     2117        c->nominated = rcheck->use_candidate; 
    19362118        c->err_code = PJ_SUCCESS; 
    19372119 
     
    19442126             "TOO MANY CHECKS IN CHECKLIST!")); 
    19452127    } 
    1946  
    1947     pj_mutex_unlock(ice->mutex); 
    1948     return status; 
    19492128} 
    19502129 
  • pjproject/trunk/pjnath/src/pjnath/stun_msg_dump.c

    r1126 r1152  
    228228 
    229229    len = pj_ansi_snprintf(p, end-p,  
    230                            " Hdr: length=%d, magic=%08x, tsx_id=%08x %08x %08x\n" 
     230                           " Hdr: length=%d, magic=%08x, tsx_id=%08x%08x%08x\n" 
    231231                           " Attributes:\n", 
    232232                           msg->hdr.length, 
  • pjproject/trunk/pjnath/src/pjnath/stun_session.c

    r1151 r1152  
    711711    pj_mutex_unlock(sess->mutex); 
    712712    return PJ_SUCCESS; 
    713  
    714 } 
     713} 
     714 
     715/* 
     716 * Explicitly request retransmission of the request. 
     717 */ 
     718PJ_DEF(pj_status_t) pj_stun_session_retransmit_req(pj_stun_session *sess, 
     719                                                   pj_stun_tx_data *tdata) 
     720{ 
     721    pj_status_t status; 
     722 
     723    PJ_ASSERT_RETURN(sess && tdata, PJ_EINVAL); 
     724    PJ_ASSERT_RETURN(PJ_STUN_IS_REQUEST(tdata->msg->hdr.type), PJ_EINVAL); 
     725 
     726    pj_mutex_lock(sess->mutex); 
     727 
     728    status = pj_stun_client_tsx_retransmit(tdata->client_tsx); 
     729 
     730    pj_mutex_unlock(sess->mutex); 
     731 
     732    return status; 
     733} 
     734 
    715735 
    716736/* Send response */ 
  • pjproject/trunk/pjnath/src/pjnath/stun_transaction.c

    r1141 r1152  
    295295} 
    296296 
     297/* 
     298 * Request to retransmit the request. 
     299 */ 
     300PJ_DEF(pj_status_t) pj_stun_client_tsx_retransmit(pj_stun_client_tsx *tsx) 
     301{ 
     302    if (tsx->destroy_timer.id != 0) { 
     303        return PJ_SUCCESS; 
     304    } 
     305 
     306    if (tsx->retransmit_timer.id != 0) { 
     307        pj_timer_heap_cancel(tsx->cfg->timer_heap, &tsx->retransmit_timer); 
     308        tsx->retransmit_timer.id = 0; 
     309    } 
     310 
     311    return tsx_transmit_msg(tsx); 
     312} 
    297313 
    298314/* Timer callback to destroy transaction */ 
  • pjproject/trunk/pjnath/src/pjstun-client/client_main.c

    r1151 r1152  
    3030#define REQ_IP          NULL                /* IP address string */ 
    3131 
    32 #define OPTIONS         PJ_STUN_NO_AUTHENTICATE 
     32//#define OPTIONS               PJ_STUN_NO_AUTHENTICATE 
     33#define OPTIONS         0 
     34 
    3335 
    3436static struct global 
Note: See TracChangeset for help on using the changeset viewer.