Ignore:
Timestamp:
May 17, 2009 5:57:19 PM (15 years ago)
Author:
bennylp
Message:

Ticket #851: initial code to support regular nomination in ICE:

  • Added option to change nomination strategy in ICE strans and session. Default is still aggressive.
  • Added option to control nomination timer
  • Renamed no_host_cand to max_host_cands in ICE config
  • Updated icedemo
  • Also added timer for controlled agent to wait for nomination from controlling agent
File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/branches/projects/sipit24/pjnath/src/pjnath/ice_session.c

    r2419 r2705  
    6767}; 
    6868 
     69typedef enum timer_type 
     70{ 
     71    TIMER_NONE,                 /**< Timer not active                   */ 
     72    TIMER_COMPLETION_CALLBACK,  /**< Call on_ice_complete() callback    */ 
     73    TIMER_CONTROLLED_WAIT_NOM,  /**< Controlled agent is waiting for  
     74                                     controlling agent to send connectivity 
     75                                     check with nominated flag after it has 
     76                                     valid check for every components.  */ 
     77    TIMER_START_NOMINATED_CHECK,/**< Controlling agent start connectivity 
     78                                     checks with USE-CANDIDATE flag.    */ 
     79                                         
     80 
     81}; 
     82 
    6983/* Candidate type preference */ 
    7084static pj_uint8_t cand_type_prefs[4] = 
     
    119133 
    120134/* Forward declarations */ 
     135static void on_timer(pj_timer_heap_t *th, pj_timer_entry *te); 
     136static void on_ice_complete(pj_ice_sess *ice, pj_status_t status); 
    121137static void destroy_ice(pj_ice_sess *ice, 
    122138                        pj_status_t reason); 
    123139static pj_status_t start_periodic_check(pj_timer_heap_t *th,  
    124140                                        pj_timer_entry *te); 
     141static void start_nominated_check(pj_ice_sess *ice); 
    125142static void periodic_timer(pj_timer_heap_t *th,  
    126143                          pj_timer_entry *te); 
     
    297314 
    298315 
     316/* Init options with default values */ 
     317PJ_DEF(void) pj_ice_sess_options_default(pj_ice_sess_options *opt) 
     318{ 
     319    opt->aggressive = PJ_TRUE; 
     320    opt->nominated_check_delay = PJ_ICE_NOMINATED_CHECK_DELAY; 
     321    opt->controlled_agent_want_nom_timeout =  
     322        ICE_CONTROLLED_AGENT_WAIT_NOMINATION_TIMEOUT; 
     323} 
     324 
    299325/* 
    300326 * Create ICE session. 
     
    327353    ice->tie_breaker.u32.lo = pj_rand(); 
    328354    ice->prefs = cand_type_prefs; 
     355    pj_ice_sess_options_default(&ice->opt); 
     356 
     357    pj_timer_entry_init(&ice->timer, TIMER_NONE, (void*)ice, &on_timer); 
    329358 
    330359    pj_ansi_snprintf(ice->obj_name, sizeof(ice->obj_name), 
     
    346375        comp = &ice->comp[i]; 
    347376        comp->valid_check = NULL; 
     377        comp->nominated_check = NULL; 
    348378 
    349379        status = init_comp(ice, i+1, comp); 
     
    390420 
    391421/* 
     422 * Get the value of various options of the ICE session. 
     423 */ 
     424PJ_DEF(pj_status_t) pj_ice_sess_get_options(pj_ice_sess *ice, 
     425                                            pj_ice_sess_options *opt) 
     426{ 
     427    PJ_ASSERT_RETURN(ice, PJ_EINVAL); 
     428    pj_memcpy(opt, &ice->opt, sizeof(*opt)); 
     429    return PJ_SUCCESS; 
     430} 
     431 
     432/* 
     433 * Specify various options for this ICE session. 
     434 */ 
     435PJ_DEF(pj_status_t) pj_ice_sess_set_options(pj_ice_sess *ice, 
     436                                            const pj_ice_sess_options *opt) 
     437{ 
     438    PJ_ASSERT_RETURN(ice && opt, PJ_EINVAL); 
     439    pj_memcpy(&ice->opt, opt, sizeof(*opt)); 
     440    return PJ_SUCCESS; 
     441} 
     442 
     443 
     444/* 
    392445 * Destroy 
    393446 */ 
     
    407460    } 
    408461 
    409     if (ice->completion_timer.id) { 
     462    if (ice->timer.id) { 
    410463        pj_timer_heap_cancel(ice->stun_cfg.timer_heap,  
    411                              &ice->completion_timer); 
    412         ice->completion_timer.id = PJ_FALSE; 
     464                             &ice->timer); 
     465        ice->timer.id = PJ_FALSE; 
    413466    } 
    414467 
     
    10401093} 
    10411094 
    1042 /* Timer callback to call on_ice_complete() callback */ 
    1043 static void on_completion_timer(pj_timer_heap_t *th,  
    1044                                 pj_timer_entry *te) 
     1095/* Timer callback */ 
     1096static void on_timer(pj_timer_heap_t *th, pj_timer_entry *te) 
    10451097{ 
    10461098    pj_ice_sess *ice = (pj_ice_sess*) te->user_data; 
     1099    enum timer_time type = (enum timer_type)te->id; 
    10471100 
    10481101    PJ_UNUSED_ARG(th); 
    10491102 
    1050     te->id = PJ_FALSE; 
    1051  
    1052     if (ice->cb.on_ice_complete) 
    1053         (*ice->cb.on_ice_complete)(ice, ice->ice_status); 
     1103    te->id = TIMER_NONE; 
     1104 
     1105    switch (type) { 
     1106    case TIMER_CONTROLLED_WAIT_NOM: 
     1107        LOG4((ice->obj_name,  
     1108              "Controlled agent timed-out in waiting for the controlling " 
     1109              "agent to send nominated check. Setting state to fail now..")); 
     1110        on_ice_complete(ice, PJNATH_EICENOMTIMEOUT); 
     1111        break; 
     1112    case TIMER_COMPLETION_CALLBACK: 
     1113        if (ice->cb.on_ice_complete) 
     1114            (*ice->cb.on_ice_complete)(ice, ice->ice_status); 
     1115        break; 
     1116    case TIMER_START_NOMINATED_CHECK: 
     1117        start_nominated_check(ice); 
     1118        break; 
     1119    } 
    10541120} 
    10551121 
     
    10611127        ice->ice_status = status; 
    10621128     
     1129        if (ice->timer.id != TIMER_NONE) { 
     1130            pj_timer_heap_cancel(ice->stun_cfg.timer_heap, &ice->timer); 
     1131            ice->timer.id = TIMER_NONE; 
     1132        } 
     1133 
    10631134        /* Log message */ 
    10641135        LOG4((ice->obj_name, "ICE process complete, status=%s",  
     
    10721143            pj_time_val delay = {0, 0}; 
    10731144 
    1074             ice->completion_timer.cb = &on_completion_timer; 
    1075             ice->completion_timer.user_data = (void*) ice; 
    1076             ice->completion_timer.id = PJ_TRUE; 
    1077  
     1145            ice->timer.id = TIMER_COMPLETION_CALLBACK; 
    10781146            pj_timer_heap_schedule(ice->stun_cfg.timer_heap,  
    1079                                    &ice->completion_timer, 
    1080                                    &delay); 
     1147                                   &ice->timer, &delay); 
    10811148        } 
    10821149    } 
     
    10881155                                   pj_ice_sess_check *check) 
    10891156{ 
     1157    pj_ice_sess_comp *comp; 
    10901158    unsigned i; 
    10911159 
    10921160    pj_assert(check->state >= PJ_ICE_SESS_CHECK_STATE_SUCCEEDED); 
     1161 
     1162    comp = find_comp(ice, check->lcand->comp_id); 
    10931163 
    10941164    /* 7.1.2.2.2.  Updating Pair States 
     
    11051175     */ 
    11061176    if (check->err_code==PJ_SUCCESS) { 
     1177 
    11071178        for (i=0; i<ice->clist.count; ++i) { 
    11081179            pj_ice_sess_check *c = &ice->clist.checks[i]; 
     
    11131184            } 
    11141185        } 
     1186 
     1187        /* Update valid check */ 
     1188        if (comp->valid_check == NULL) { 
     1189            comp->valid_check = check; 
     1190        } else { 
     1191            if (CMP_CHECK_PRIO(comp->valid_check, check) < 0) 
     1192                comp->valid_check = check; 
     1193        } 
     1194 
     1195        LOG5((ice->obj_name, "Check %d is successful%s", 
     1196             GET_CHECK_ID(&ice->clist, check), 
     1197             (check->nominated ? "  and nominated" : ""))); 
     1198 
    11151199    } 
    11161200 
     
    11371221     */ 
    11381222    if (check->err_code==PJ_SUCCESS && check->nominated) { 
    1139         pj_ice_sess_comp *comp; 
    1140  
    1141         LOG5((ice->obj_name, "Check %d is successful and nominated", 
    1142              GET_CHECK_ID(&ice->clist, check))); 
    1143  
    1144         comp = find_comp(ice, check->lcand->comp_id); 
    11451223 
    11461224        for (i=0; i<ice->clist.count; ++i) { 
     
    11821260 
    11831261        /* Update the nominated check for the component */ 
    1184         if (comp->valid_check == NULL) { 
    1185             comp->valid_check = check; 
     1262        if (comp->nominated_check == NULL) { 
     1263            comp->nominated_check = check; 
    11861264        } else { 
    1187             if (CMP_CHECK_PRIO(comp->valid_check, check) < 0) 
    1188                 comp->valid_check = check; 
     1265            if (CMP_CHECK_PRIO(comp->nominated_check, check) < 0) 
     1266                comp->nominated_check = check; 
    11891267        } 
    11901268    } 
     
    12121290     */ 
    12131291    for (i=0; i<ice->comp_cnt; ++i) { 
    1214         if (ice->comp[i].valid_check == NULL) 
     1292        if (ice->comp[i].nominated_check == NULL) 
    12151293            break; 
    12161294    } 
     
    12591337         * If agent's role is controlled, check if all components have 
    12601338         * valid pair. If it does, this means the controlled agent has 
    1261          * finished the check list early and it's waiting for controlling 
    1262          * agent to send a check with USE-CANDIDATE flag set. 
     1339         * finished the check list and it's waiting for controlling 
     1340         * agent to send checks with USE-CANDIDATE flag set. 
    12631341         */ 
    12641342        if (ice->role == PJ_ICE_SESS_ROLE_CONTROLLED) { 
    1265             unsigned comp_id; 
    1266             for (comp_id=1; comp_id <= ice->comp_cnt; ++comp_id) { 
    1267                 unsigned j; 
    1268                 for (j=0; j<ice->valid_list.count; ++j) { 
    1269                     pj_ice_sess_check *vc = &ice->valid_list.checks[j]; 
    1270                     if (vc->lcand->comp_id == comp_id) 
    1271                         break; 
    1272                 } 
    1273                 if (j == ice->valid_list.count) 
     1343            for (i=0; i < ice->comp_cnt; ++i) { 
     1344                if (ice->comp[i].valid_check == NULL) 
    12741345                    break; 
    12751346            } 
    12761347 
    1277             if (comp_id <= ice->comp_cnt) { 
     1348            if (i < ice->comp_cnt) { 
    12781349                /* This component ID doesn't have valid pair. 
    12791350                 * Mark ICE as failed.  
     
    12851356                 * We should wait until we receive nominated checks. 
    12861357                 */ 
     1358                if (ice->timer.id == TIMER_NONE && 
     1359                    ice->opt.controlled_agent_want_nom_timeout >= 0)  
     1360                { 
     1361                    pj_time_val delay; 
     1362 
     1363                    delay.sec = 0; 
     1364                    delay.msec = ice->opt.controlled_agent_want_nom_timeout; 
     1365                    pj_time_val_normalize(&delay); 
     1366 
     1367                    ice->timer.id = TIMER_CONTROLLED_WAIT_NOM; 
     1368                    pj_timer_heap_schedule(ice->stun_cfg.timer_heap,  
     1369                                           &ice->timer, 
     1370                                           &delay); 
     1371 
     1372                    LOG5((ice->obj_name,  
     1373                          "All checks have completed. Controlled agent now " 
     1374                          "waits for nomination from controlling agent " 
     1375                          "(timeout=%d msec)", 
     1376                          ice->opt.controlled_agent_want_nom_timeout)); 
     1377                } 
    12871378                return PJ_FALSE; 
    12881379            } 
    1289         } 
    1290  
    1291         on_ice_complete(ice, PJNATH_EICEFAILED); 
    1292         return PJ_TRUE; 
     1380 
     1381            /* Unreached */ 
     1382 
     1383        } else if (ice->is_nominating) { 
     1384            /* We are controlling agent and all checks have completed but 
     1385             * there's at least one component without nominated pair (or 
     1386             * more likely we don't have any nominated pairs at all). 
     1387             */ 
     1388            on_ice_complete(ice, PJNATH_EICEFAILED); 
     1389            return PJ_TRUE; 
     1390 
     1391        } else { 
     1392            /* We are controlling agent and all checks have completed. If 
     1393             * we have valid list for every component, then move on to 
     1394             * sending nominated check, otherwise we have failed. 
     1395             */ 
     1396            for (i=0; i<ice->comp_cnt; ++i) { 
     1397                if (ice->comp[i].valid_check == NULL) 
     1398                    break; 
     1399            } 
     1400 
     1401            if (i < ice->comp_cnt) { 
     1402                /* At least one component doesn't have a valid check. Mark 
     1403                 * ICE as failed. 
     1404                 */ 
     1405                on_ice_complete(ice, PJNATH_EICEFAILED); 
     1406                return PJ_TRUE; 
     1407            } 
     1408 
     1409            /* Now it's time to send connectivity check with nomination  
     1410             * flag set. 
     1411             */ 
     1412            LOG5((ice->obj_name,  
     1413                  "All checks have completed, starting nominated checks now")); 
     1414            start_nominated_check(ice); 
     1415            return PJ_FALSE; 
     1416        } 
     1417    } 
     1418 
     1419    /* If this connectivity check has been successful, scan all components 
     1420     * and see if they have a valid pair, if we are controlling and we haven't 
     1421     * started our nominated check yet. 
     1422     */ 
     1423    if (check->err_code == PJ_SUCCESS &&  
     1424        ice->role==PJ_ICE_SESS_ROLE_CONTROLLING && 
     1425        !ice->is_nominating && 
     1426        ice->timer.id == TIMER_NONE)  
     1427    { 
     1428        pj_time_val delay; 
     1429 
     1430        for (i=0; i<ice->comp_cnt; ++i) { 
     1431            if (ice->comp[i].valid_check == NULL) 
     1432                break; 
     1433        } 
     1434 
     1435        if (i < ice->comp_cnt) { 
     1436            /* Some components still don't have valid pair, continue 
     1437             * processing. 
     1438             */ 
     1439            return PJ_FALSE; 
     1440        } 
     1441 
     1442        LOG5((ice->obj_name,  
     1443              "Scheduling nominated check in %d ms", 
     1444              ice->opt.nominated_check_delay)); 
     1445 
     1446        /* All components have valid pair. Let connectivity checks run for 
     1447         * a little bit more time, then start our nominated check. 
     1448         */ 
     1449        delay.sec = 0; 
     1450        delay.msec = ice->opt.nominated_check_delay; 
     1451        pj_time_val_normalize(&delay); 
     1452 
     1453        ice->timer.id = TIMER_START_NOMINATED_CHECK; 
     1454        pj_timer_heap_schedule(ice->stun_cfg.timer_heap, &ice->timer, &delay); 
     1455        return PJ_FALSE; 
    12931456    } 
    12941457 
     
    12961459    return PJ_FALSE; 
    12971460} 
    1298  
    12991461 
    13001462 
     
    14311593} 
    14321594 
    1433 /* Perform check on the specified candidate pair */ 
     1595/* Perform check on the specified candidate pair. */ 
    14341596static pj_status_t perform_check(pj_ice_sess *ice,  
    14351597                                 pj_ice_sess_checklist *clist, 
    1436                                  unsigned check_id) 
     1598                                 unsigned check_id, 
     1599                                 pj_bool_t nominate) 
    14371600{ 
    14381601    pj_ice_sess_comp *comp; 
     
    14821645     */ 
    14831646    if (ice->role == PJ_ICE_SESS_ROLE_CONTROLLING) { 
    1484         pj_stun_msg_add_empty_attr(check->tdata->pool, check->tdata->msg,  
    1485                                    PJ_STUN_ATTR_USE_CANDIDATE); 
    1486         check->nominated = PJ_TRUE; 
     1647        if (nominate) { 
     1648            pj_stun_msg_add_empty_attr(check->tdata->pool, check->tdata->msg, 
     1649                                       PJ_STUN_ATTR_USE_CANDIDATE); 
     1650            check->nominated = PJ_TRUE; 
     1651        } 
    14871652 
    14881653        pj_stun_msg_add_uint64_attr(check->tdata->pool, check->tdata->msg,  
     
    15501715 
    15511716        if (check->state == PJ_ICE_SESS_CHECK_STATE_WAITING) { 
    1552             status = perform_check(ice, clist, i); 
     1717            status = perform_check(ice, clist, i, ice->is_nominating); 
    15531718            if (status != PJ_SUCCESS) { 
    15541719                pj_mutex_unlock(ice->mutex); 
     
    15691734 
    15701735            if (check->state == PJ_ICE_SESS_CHECK_STATE_FROZEN) { 
    1571                 status = perform_check(ice, clist, i); 
     1736                status = perform_check(ice, clist, i, ice->is_nominating); 
    15721737                if (status != PJ_SUCCESS) { 
    15731738                    pj_mutex_unlock(ice->mutex); 
     
    15961761} 
    15971762 
     1763 
     1764/* Start sending connectivity check with USE-CANDIDATE */ 
     1765static void start_nominated_check(pj_ice_sess *ice) 
     1766{ 
     1767    pj_time_val delay; 
     1768    unsigned i; 
     1769    pj_status_t status; 
     1770 
     1771    LOG4((ice->obj_name, "Starting nominated check..")); 
     1772 
     1773    pj_assert(ice->is_nominating == PJ_FALSE); 
     1774 
     1775    /* Stop our timer if it's active */ 
     1776    if (ice->timer.id == TIMER_START_NOMINATED_CHECK) { 
     1777        pj_timer_heap_cancel(ice->stun_cfg.timer_heap, &ice->timer); 
     1778        ice->timer.id = TIMER_NONE; 
     1779    } 
     1780 
     1781    /* For each component, set the check state of valid check with 
     1782     * highest priority to Waiting (it should have Success state now). 
     1783     */ 
     1784    for (i=0; i<ice->comp_cnt; ++i) { 
     1785        pj_assert(ice->comp[i].nominated_check == NULL); 
     1786        pj_assert(ice->comp[i].valid_check->err_code == PJ_SUCCESS); 
     1787 
     1788        ice->comp[i].valid_check->state = PJ_ICE_SESS_CHECK_STATE_FROZEN; 
     1789        check_set_state(ice, ice->comp[i].valid_check,  
     1790                        PJ_ICE_SESS_CHECK_STATE_WAITING, PJ_SUCCESS); 
     1791    } 
     1792 
     1793    /* And (re)start the periodic check */ 
     1794    if (!ice->clist.timer.id) { 
     1795        ice->clist.timer.id = PJ_TRUE; 
     1796        delay.sec = delay.msec = 0; 
     1797        status = pj_timer_heap_schedule(ice->stun_cfg.timer_heap,  
     1798                                        &ice->clist.timer, &delay); 
     1799        if (status != PJ_SUCCESS) { 
     1800            ice->clist.timer.id = PJ_FALSE; 
     1801        } 
     1802    } 
     1803 
     1804    ice->is_nominating = PJ_TRUE; 
     1805} 
    15981806 
    15991807/* Timer callback to perform periodic check */ 
     
    16421850 
    16431851    LOG4((ice->obj_name, "Starting ICE check..")); 
     1852 
     1853    /* If we are using aggressive nomination, set the is_nominating state */ 
     1854    if (ice->opt.aggressive) 
     1855        ice->is_nominating = PJ_TRUE; 
    16441856 
    16451857    /* The agent examines the check list for the first media stream (a 
     
    18272039            LOG4((ice->obj_name, "Resending check because of role conflict")); 
    18282040            check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_WAITING, 0); 
    1829             perform_check(ice, clist, msg_data->data.req.ckid); 
     2041            perform_check(ice, clist, msg_data->data.req.ckid,  
     2042                          check->nominated); 
    18302043            pj_mutex_unlock(ice->mutex); 
    18312044            return; 
     
    23132526            c->state == PJ_ICE_SESS_CHECK_STATE_WAITING) 
    23142527        { 
     2528            /* See if we shall nominate this check */ 
     2529            pj_bool_t nominate = (c->nominated || ice->is_nominating); 
     2530 
    23152531            LOG5((ice->obj_name, "Performing triggered check for check %d",i)); 
    2316             perform_check(ice, &ice->clist, i); 
     2532            perform_check(ice, &ice->clist, i, nominate); 
    23172533 
    23182534        } else if (c->state == PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS) { 
     
    23622578 
    23632579        pj_ice_sess_check *c = &ice->clist.checks[ice->clist.count]; 
     2580        pj_bool_t nominate; 
    23642581 
    23652582        c->lcand = lcand; 
     
    23702587        c->err_code = PJ_SUCCESS; 
    23712588 
     2589        nominate = (c->nominated || ice->is_nominating); 
     2590 
    23722591        LOG4((ice->obj_name, "New triggered check added: %d",  
    23732592             ice->clist.count)); 
    2374         perform_check(ice, &ice->clist, ice->clist.count++); 
     2593        perform_check(ice, &ice->clist, ice->clist.count++, nominate); 
    23752594 
    23762595    } else { 
Note: See TracChangeset for help on using the changeset viewer.