Changeset 1090 for pjproject/trunk/pjnath/src/pjnath/ice.c
- Timestamp:
- Mar 21, 2007 9:12:22 AM (17 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjnath/src/pjnath/ice.c
r1089 r1090 65 65 static void destroy_ice(pj_ice *ice, 66 66 pj_status_t reason); 67 static void ice_set_state(pj_ice *ice,68 pj_ice_state new_state);69 67 static pj_status_t start_periodic_check(pj_timer_heap_t *th, 70 68 pj_timer_entry *te); … … 169 167 pj_status_t reason) 170 168 { 169 unsigned i; 170 171 171 if (reason == PJ_SUCCESS) { 172 172 LOG((ice->obj_name, "Destroying ICE session")); 173 } 174 175 for (i=0; i<ice->comp_cnt; ++i) { 176 pj_ice_comp *comp = &ice->comp[i]; 177 178 if (comp->stun_sess) { 179 pj_stun_session_destroy(comp->stun_sess); 180 comp->stun_sess = NULL; 181 } 182 } 183 184 if (ice->clist.timer.id) { 185 pj_timer_heap_cancel(ice->stun_cfg.timer_heap, &ice->clist.timer); 186 ice->clist.timer.id = PJ_FALSE; 173 187 } 174 188 … … 198 212 199 213 200 static void ice_set_state(pj_ice *ice, 201 pj_ice_state new_state) 202 { 203 ice->state = new_state; 204 } 214 /* This function is called when ICE processing completes */ 215 static void on_ice_complete(pj_ice *ice, pj_status_t status) 216 { 217 } 218 219 220 /* This function is called when one check completes */ 221 static pj_bool_t on_check_complete(pj_ice *ice, 222 pj_ice_check *check) 223 { 224 unsigned i; 225 226 /* If there is at least one nominated pair in the valid list: 227 * - The agent MUST remove all Waiting and Frozen pairs in the check 228 * list for the same component as the nominated pairs for that 229 * media stream 230 * - If an In-Progress pair in the check list is for the same 231 * component as a nominated pair, the agent SHOULD cease 232 * retransmissions for its check if its pair priority is lower 233 * than the lowest priority nominated pair for that component 234 */ 235 if (check->nominated) { 236 for (i=0; i<ice->clist.count; ++i) { 237 pj_ice_check *c; 238 if (c->lcand->comp_id == check->lcand->comp_id && 239 (c->state==PJ_ICE_CHECK_STATE_FROZEN || 240 c->state==PJ_ICE_CHECK_STATE_WAITING) 241 { 242 check_set_state(ice, check, PJ_ICE_CHECK_STATE_FAILED, 243 PJ_ECANCELLED); 244 } 245 } 246 } 247 248 /* Once there is at least one nominated pair in the valid list for 249 * every component of at least one media stream: 250 * - The agent MUST change the state of processing for its check 251 * list for that media stream to Completed. 252 * - The agent MUST continue to respond to any checks it may still 253 * receive for that media stream, and MUST perform triggered 254 * checks if required by the processing of Section 7.2. 255 * - The agent MAY begin transmitting media for this media stream as 256 * described in Section 11.1 257 */ 258 /* TODO */ 259 260 /* Once there is at least one nominated pair in the valid list for 261 * each component of each media stream: 262 * - The agent sets the state of ICE processing overall to 263 * Completed. 264 * - If an agent is controlling, it examines the highest priority 265 * nominated candidate pair for each component of each media 266 * stream. If any of those candidate pairs differ from the 267 * default candidate pairs in the most recent offer/answer 268 * exchange, the controlling agent MUST generate an updated offer 269 * as described in Section 9. If the controlling agent is using 270 * an aggressive nomination algorithm, this may result in several 271 * updated offers as the pairs selected for media change. An 272 * agent MAY delay sending the offer for a brief interval (one 273 * second is RECOMMENDED) in order to allow the selected pairs to 274 * stabilize. 275 */ 276 /* TODO */ 277 278 279 /* For now, just see if we have a valid pair in component 1 and 280 * just terminate ICE. 281 */ 282 for (i=0; i<ice->valid_cnt; ++i) { 283 pj_ice_check *c = ice->clist.checks[ice->valid_list[i]]; 284 if (c->lcand->comp_id == 1) 285 break; 286 } 287 288 if (i != ice->valid_cnt) { 289 /* ICE succeeded */ 290 on_ice_complete(ice, PJ_SUCCESS); 291 return PJ_TRUE; 292 } 293 294 /* We don't have valid pair for component 1. 295 * See if we have performed all checks in the checklist. If we do, 296 * then mark ICE processing as failed. 297 */ 298 for (i=0; i<ice->clist.count; ++i) { 299 pj_ice_check *c = &ice->clist.checks[i]; 300 if (c->state < PJ_ICE_CHECK_STATE_SUCCEEDED) { 301 break; 302 } 303 } 304 305 if (i == ice->clist.count) { 306 /* All checks have completed */ 307 on_ice_complete(ice, -1); 308 return PJ_TRUE; 309 } 310 311 /* We still have checks to perform */ 312 return PJ_FALSE; 313 } 314 205 315 206 316 static void resolver_cb(void *user_data, … … 633 743 PJ_TODO(GATHER_MAPPED_AND_RELAYED_CANDIDATES); 634 744 635 ice_set_state(ice, PJ_ICE_STATE_CAND_COMPLETE);636 637 745 return PJ_SUCCESS; 638 746 } … … 883 991 } 884 992 993 /* Sort checklist based on priority */ 885 994 static void sort_checklist(pj_ice_checklist *clist) 886 995 { … … 902 1011 sizeof(pj_ice_check)); 903 1012 pj_memcpy(&clist->checks[highest], &tmp, sizeof(pj_ice_check)); 1013 } 1014 } 1015 } 1016 1017 /* Sort valid list based on priority */ 1018 static void sort_valid_list(pj_ice *ice) 1019 { 1020 unsigned i; 1021 1022 for (i=0; i<ice->valid_cnt-1; ++i) { 1023 unsigned j, highest = i; 1024 pj_ice_check *ci = ice->clist.checks[ice->valid_list[i]]; 1025 1026 for (j=i+1; j<ice->valid_cnt; ++j) { 1027 pj_ice_check *cj = ice->clist.checks[ice->valid_list[j]]; 1028 1029 if (cj->prio > ci->prio) { 1030 highest = j; 1031 } 1032 } 1033 1034 if (highest != i) { 1035 unsigned tmp = ice->valid_list[i]; 1036 ice->valid_list[i] = ice->valid_list[j]; 1037 ice->valid_list[j] = tmp; 904 1038 } 905 1039 } … … 1020 1154 1021 1155 /* Generate checklist */ 1022 clist = &ice->c klist;1156 clist = &ice->clist; 1023 1157 for (i=0; i<ice->lcand_cnt; ++i) { 1024 1158 for (j=0; j<ice->rcand_cnt; ++j) { … … 1131 1265 prio); 1132 1266 1133 /* Add USE-CANDIDATE */1267 /* Add USE-CANDIDATE and set this check to nominated */ 1134 1268 if (ice->role == PJ_ICE_ROLE_CONTROLLING) { 1135 1269 pj_stun_msg_add_empty_attr(tdata->pool, tdata->msg, 1136 1270 PJ_STUN_ATTR_USE_CANDIDATE); 1271 check->nominated = PJ_TRUE; 1137 1272 } 1138 1273 … … 1248 1383 LOG((ice->obj_name, "Starting ICE check..")); 1249 1384 1250 clist = &ice->c klist;1385 clist = &ice->clist; 1251 1386 1252 1387 if (clist->count == 0) … … 1380 1515 check_set_state(ice, check, PJ_ICE_CHECK_STATE_SUCCEEDED, PJ_SUCCESS); 1381 1516 1382 1383 1517 /* This is a valid pair, so add this to the valid list */ 1384 valid_check = &ice->valid_list.checks[ice->valid_list.count++]; 1385 valid_check->lcand = lcand; 1386 valid_check->rcand = rcand; 1387 valid_check->prio = CALC_CHECK_PRIO(ice, lcand, rcand); 1388 valid_check->state = PJ_ICE_CHECK_STATE_SUCCEEDED; 1389 valid_check->nominated = (pj_stun_msg_find_attr(tdata->msg, 1390 PJ_STUN_ATTR_USE_CANDIDATE, 1391 0) != NULL); 1392 valid_check->err_code = PJ_SUCCESS; 1518 ice->valid_list[ice->valid_cnt++] = rd->ckid; 1393 1519 1394 1520 /* Sort valid_list */ 1395 sort_checklist(&ice->valid_list); 1521 sort_valid_list(ice); 1522 1523 /* Inform about check completion. 1524 * This may terminate ICE processing. 1525 */ 1526 if (on_check_complete(ice, check)) { 1527 /* ICE complete! */ 1528 pj_mutex_unlock(ice->mutex); 1529 return; 1530 } 1396 1531 1397 1532 /* If the pair had a component ID of 1, the agent MUST change the … … 1453 1588 pj_ice *ice; 1454 1589 pj_stun_priority_attr *ap; 1590 pj_stun_use_candidate_attr *uc; 1455 1591 pj_ice_comp *comp; 1456 1592 pj_ice_cand *lcand; … … 1464 1600 PJ_UNUSED_ARG(pkt_len); 1465 1601 1466 /* Only acceptsBinding request */1602 /* Reject any requests except Binding request */ 1467 1603 if (msg->hdr.type != PJ_STUN_BINDING_REQUEST) { 1468 LOG((ice->obj_name, "Received non-Binding request, ignored")); 1469 return PJ_SUCCESS; 1470 } 1604 pj_str_t err_msg = pj_str("Expecting Binding Request only"); 1605 status = pj_stun_session_create_response(sess, msg, 1606 PJ_STUN_SC_BAD_REQUEST, 1607 &err_msg, &tdata); 1608 if (status != PJ_SUCCESS) { 1609 return status; 1610 } 1611 1612 status = pj_stun_session_send_msg(sess, PJ_TRUE, 1613 src_addr, src_addr_len, tdata); 1614 1615 return status; 1616 } 1617 1471 1618 1472 1619 sd = (stun_data*) pj_stun_session_get_user_data(sess); … … 1485 1632 } 1486 1633 1634 /* Get USE-CANDIDATE attribute */ 1635 uc = (pj_stun_use_candidate_attr*) 1636 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_USE_CANDIDATE, 0); 1637 1487 1638 /* For simplicity, ignore incoming requests when we don't have remote 1488 1639 * candidates yet. The peer agent should retransmit the STUN request … … 1493 1644 return PJ_SUCCESS; 1494 1645 } 1646 1647 /* 1648 * First send response to this request 1649 */ 1650 status = pj_stun_session_create_response(sess, msg, 0, NULL, &tdata); 1651 if (status != PJ_SUCCESS) { 1652 pj_mutex_unlock(ice->mutex); 1653 return status; 1654 } 1655 1656 status = pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg, 1657 PJ_STUN_ATTR_XOR_MAPPED_ADDR, 1658 PJ_TRUE, src_addr, src_addr_len); 1659 1660 status = pj_stun_session_send_msg(sess, PJ_TRUE, 1661 src_addr, src_addr_len, tdata); 1495 1662 1496 1663 … … 1533 1700 is_relayed = PJ_FALSE; 1534 1701 1535 /* Next find local candidate */ 1536 /* Just pick up 1537 1538 1539 1540 /* 7.2.1.2. Learning Peer Reflexive Candidates */ 1541 PJ_TODO(LEARN_PEER_REFLEXIVE_CANDIDATES); 1542 1543 /* Reject any requests except Binding request */ 1544 if (msg->hdr.type != PJ_STUN_BINDING_REQUEST) { 1545 status = pj_stun_session_create_response(sess, msg, 1546 PJ_STUN_SC_BAD_REQUEST, 1547 NULL, &tdata); 1548 if (status != PJ_SUCCESS) { 1549 pj_mutex_unlock(ice->mutex); 1550 return status; 1702 /* Next find local candidate, by first finding a check in the checklist 1703 * which base address is equal to the local address. 1704 */ 1705 for (i=0; i<ice->clist.count; ++i) { 1706 pj_ice_check *c = &ice->clist.checks[i]; 1707 if (sockaddr_cmp(&c->lcand->base_addr, &comp->local_addr)==0) 1708 break; 1709 } 1710 1711 /* MUST find a local candidate! */ 1712 pj_assert(i != ice->clist.count); 1713 if (i == ice->clist.count) { 1714 pj_mutex_unlock(ice->mutex); 1715 LOG((ice->obj_name, "Error: unable to find local candidate for " 1716 "incoming request")); 1717 return PJ_SUCCESS; 1718 } 1719 1720 lcand = ice->clist.checks[i].lcand; 1721 1722 /* Now that we have local and remote candidate, check if we already 1723 * have this pair in our checklist. 1724 */ 1725 for (i=0; i<ice->clist.count; ++i) { 1726 pj_ice_check *c = &ice->clist.checks[i]; 1727 if (c->lcand == lcand && c->rcand == rcand) 1728 break; 1729 } 1730 1731 /* If the pair is already on the check list: 1732 * - If the state of that pair is Waiting or Frozen, its state is 1733 * changed to In-Progress and a check for that pair is performed 1734 * immediately. This is called a triggered check. 1735 * 1736 * - If the state of that pair is In-Progress, the agent SHOULD 1737 * generate an immediate retransmit of the Binding Request for the 1738 * check in progress. This is to facilitate rapid completion of 1739 * ICE when both agents are behind NAT. 1740 * 1741 * - If the state of that pair is Failed or Succeeded, no triggered 1742 * check is sent. 1743 */ 1744 if (i != ice->clist.count) { 1745 pj_ice_check *c = &ice->clist.checks[i]; 1746 1747 /* If USE-CANDIDATE is present, set nominated flag */ 1748 c->nominated = (uc != NULL); 1749 1750 if (c->state == PJ_ICE_CHECK_STATE_FROZEN || 1751 c->state == PJ_ICE_CHECK_STATE_WAITING) 1752 { 1753 LOG((ice->obj_name, "Performing triggered check for check %d",i)); 1754 perform_check(ice, &ice->clist, i); 1755 1756 } else if (c->state == PJ_ICE_CHECK_STATE_IN_PROGRESS) { 1757 /* Should retransmit here, but how?? 1758 * TODO 1759 */ 1760 } else if (c->state == PJ_ICE_CHECK_STATE_SUCCEEDED) { 1761 /* Check complete for this component. 1762 * Note this may end ICE process. 1763 */ 1764 pj_bool_t complete; 1765 1766 complete = on_check_complete(ice, c); 1767 if (complete) { 1768 pj_mutex_unlock(ice->mutex); 1769 return PJ_SUCCESS; 1770 } 1551 1771 } 1552 1772 1553 status = pj_stun_session_send_msg(sess, PJ_TRUE, 1554 src_addr, src_addr_len, tdata); 1555 1556 pj_mutex_unlock(ice->mutex); 1557 return status; 1558 } 1559 1560 status = pj_stun_session_create_response(sess, msg, 0, NULL, &tdata); 1561 if (status != PJ_SUCCESS) { 1562 pj_mutex_unlock(ice->mutex); 1563 return status; 1564 } 1565 1566 status = pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg, 1567 PJ_STUN_ATTR_XOR_MAPPED_ADDR, 1568 PJ_TRUE, src_addr, src_addr_len); 1569 1570 status = pj_stun_session_send_msg(sess, PJ_TRUE, 1571 src_addr, src_addr_len, tdata); 1572 1573 /* 7.2.1.3. Triggered Checks: 1574 * Next, the agent constructs a pair whose local candidate is equal to 1575 * the transport address on which the STUN request was received, and a 1576 * remote candidate equal to the source transport address where the 1577 * request came from (which may be peer-reflexive remote candidate that 1578 * was just learned). 1579 */ 1580 1773 } 1774 /* If the pair is not already on the check list: 1775 * - The pair is inserted into the check list based on its priority. 1776 * - Its state is set to In-Progress 1777 * - A triggered check for that pair is performed immediately. 1778 */ 1779 /* Note: only do this if we don't have too many checks in checklist */ 1780 else if (ice->clist.count < PJ_ICE_MAX_CHECKS) { 1781 1782 pj_ice_check *c = &ice->clist.checks[ice->clist.count]; 1783 1784 c->lcand = lcand; 1785 c->rcand = rcand; 1786 c->prio = CALC_CHECK_PRIO(ice, lcand, rcand); 1787 c->state = PJ_ICE_CHECK_STATE_WAITING; 1788 c->nominated = (uc != NULL); 1789 c->err_code = PJ_SUCCESS; 1790 1791 LOG((ice->obj_name, "New triggered check added: %d", 1792 ice->clist.count)); 1793 perform_check(ice, &ice->clist, ice->clist.count++); 1794 1795 } else { 1796 LOG((ice->obj_name, "Error: unable to perform triggered check: " 1797 "TOO MANY CHECKS IN CHECKLIST!")); 1798 } 1799 1581 1800 pj_mutex_unlock(ice->mutex); 1582 1801 return status;
Note: See TracChangeset
for help on using the changeset viewer.