- Timestamp:
- May 17, 2009 5:57:19 PM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/branches/projects/sipit24/pjnath/src/pjnath/ice_session.c
r2419 r2705 67 67 }; 68 68 69 typedef 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 69 83 /* Candidate type preference */ 70 84 static pj_uint8_t cand_type_prefs[4] = … … 119 133 120 134 /* Forward declarations */ 135 static void on_timer(pj_timer_heap_t *th, pj_timer_entry *te); 136 static void on_ice_complete(pj_ice_sess *ice, pj_status_t status); 121 137 static void destroy_ice(pj_ice_sess *ice, 122 138 pj_status_t reason); 123 139 static pj_status_t start_periodic_check(pj_timer_heap_t *th, 124 140 pj_timer_entry *te); 141 static void start_nominated_check(pj_ice_sess *ice); 125 142 static void periodic_timer(pj_timer_heap_t *th, 126 143 pj_timer_entry *te); … … 297 314 298 315 316 /* Init options with default values */ 317 PJ_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 299 325 /* 300 326 * Create ICE session. … … 327 353 ice->tie_breaker.u32.lo = pj_rand(); 328 354 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); 329 358 330 359 pj_ansi_snprintf(ice->obj_name, sizeof(ice->obj_name), … … 346 375 comp = &ice->comp[i]; 347 376 comp->valid_check = NULL; 377 comp->nominated_check = NULL; 348 378 349 379 status = init_comp(ice, i+1, comp); … … 390 420 391 421 /* 422 * Get the value of various options of the ICE session. 423 */ 424 PJ_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 */ 435 PJ_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 /* 392 445 * Destroy 393 446 */ … … 407 460 } 408 461 409 if (ice-> completion_timer.id) {462 if (ice->timer.id) { 410 463 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; 413 466 } 414 467 … … 1040 1093 } 1041 1094 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 */ 1096 static void on_timer(pj_timer_heap_t *th, pj_timer_entry *te) 1045 1097 { 1046 1098 pj_ice_sess *ice = (pj_ice_sess*) te->user_data; 1099 enum timer_time type = (enum timer_type)te->id; 1047 1100 1048 1101 PJ_UNUSED_ARG(th); 1049 1102 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 } 1054 1120 } 1055 1121 … … 1061 1127 ice->ice_status = status; 1062 1128 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 1063 1134 /* Log message */ 1064 1135 LOG4((ice->obj_name, "ICE process complete, status=%s", … … 1072 1143 pj_time_val delay = {0, 0}; 1073 1144 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; 1078 1146 pj_timer_heap_schedule(ice->stun_cfg.timer_heap, 1079 &ice->completion_timer, 1080 &delay); 1147 &ice->timer, &delay); 1081 1148 } 1082 1149 } … … 1088 1155 pj_ice_sess_check *check) 1089 1156 { 1157 pj_ice_sess_comp *comp; 1090 1158 unsigned i; 1091 1159 1092 1160 pj_assert(check->state >= PJ_ICE_SESS_CHECK_STATE_SUCCEEDED); 1161 1162 comp = find_comp(ice, check->lcand->comp_id); 1093 1163 1094 1164 /* 7.1.2.2.2. Updating Pair States … … 1105 1175 */ 1106 1176 if (check->err_code==PJ_SUCCESS) { 1177 1107 1178 for (i=0; i<ice->clist.count; ++i) { 1108 1179 pj_ice_sess_check *c = &ice->clist.checks[i]; … … 1113 1184 } 1114 1185 } 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 1115 1199 } 1116 1200 … … 1137 1221 */ 1138 1222 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);1145 1223 1146 1224 for (i=0; i<ice->clist.count; ++i) { … … 1182 1260 1183 1261 /* 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; 1186 1264 } 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; 1189 1267 } 1190 1268 } … … 1212 1290 */ 1213 1291 for (i=0; i<ice->comp_cnt; ++i) { 1214 if (ice->comp[i]. valid_check == NULL)1292 if (ice->comp[i].nominated_check == NULL) 1215 1293 break; 1216 1294 } … … 1259 1337 * If agent's role is controlled, check if all components have 1260 1338 * valid pair. If it does, this means the controlled agent has 1261 * finished the check list earlyand it's waiting for controlling1262 * agent to send a checkwith 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. 1263 1341 */ 1264 1342 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) 1274 1345 break; 1275 1346 } 1276 1347 1277 if ( comp_id <=ice->comp_cnt) {1348 if (i < ice->comp_cnt) { 1278 1349 /* This component ID doesn't have valid pair. 1279 1350 * Mark ICE as failed. … … 1285 1356 * We should wait until we receive nominated checks. 1286 1357 */ 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 } 1287 1378 return PJ_FALSE; 1288 1379 } 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; 1293 1456 } 1294 1457 … … 1296 1459 return PJ_FALSE; 1297 1460 } 1298 1299 1461 1300 1462 … … 1431 1593 } 1432 1594 1433 /* Perform check on the specified candidate pair */1595 /* Perform check on the specified candidate pair. */ 1434 1596 static pj_status_t perform_check(pj_ice_sess *ice, 1435 1597 pj_ice_sess_checklist *clist, 1436 unsigned check_id) 1598 unsigned check_id, 1599 pj_bool_t nominate) 1437 1600 { 1438 1601 pj_ice_sess_comp *comp; … … 1482 1645 */ 1483 1646 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 } 1487 1652 1488 1653 pj_stun_msg_add_uint64_attr(check->tdata->pool, check->tdata->msg, … … 1550 1715 1551 1716 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); 1553 1718 if (status != PJ_SUCCESS) { 1554 1719 pj_mutex_unlock(ice->mutex); … … 1569 1734 1570 1735 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); 1572 1737 if (status != PJ_SUCCESS) { 1573 1738 pj_mutex_unlock(ice->mutex); … … 1596 1761 } 1597 1762 1763 1764 /* Start sending connectivity check with USE-CANDIDATE */ 1765 static 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 } 1598 1806 1599 1807 /* Timer callback to perform periodic check */ … … 1642 1850 1643 1851 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; 1644 1856 1645 1857 /* The agent examines the check list for the first media stream (a … … 1827 2039 LOG4((ice->obj_name, "Resending check because of role conflict")); 1828 2040 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); 1830 2043 pj_mutex_unlock(ice->mutex); 1831 2044 return; … … 2313 2526 c->state == PJ_ICE_SESS_CHECK_STATE_WAITING) 2314 2527 { 2528 /* See if we shall nominate this check */ 2529 pj_bool_t nominate = (c->nominated || ice->is_nominating); 2530 2315 2531 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); 2317 2533 2318 2534 } else if (c->state == PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS) { … … 2362 2578 2363 2579 pj_ice_sess_check *c = &ice->clist.checks[ice->clist.count]; 2580 pj_bool_t nominate; 2364 2581 2365 2582 c->lcand = lcand; … … 2370 2587 c->err_code = PJ_SUCCESS; 2371 2588 2589 nominate = (c->nominated || ice->is_nominating); 2590 2372 2591 LOG4((ice->obj_name, "New triggered check added: %d", 2373 2592 ice->clist.count)); 2374 perform_check(ice, &ice->clist, ice->clist.count++ );2593 perform_check(ice, &ice->clist, ice->clist.count++, nominate); 2375 2594 2376 2595 } else {
Note: See TracChangeset
for help on using the changeset viewer.