- Timestamp:
- Mar 21, 2007 9:12:22 AM (18 years ago)
- Location:
- pjproject/trunk/pjnath
- Files:
-
- 4 edited
- 2 moved
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjnath/build/pjnath.dsp
r1085 r1090 100 100 # Begin Source File 101 101 102 SOURCE=..\src\pjnath\stun_endpoint.c103 # End Source File104 # Begin Source File105 106 102 SOURCE=..\src\pjnath\stun_msg.c 107 103 # End Source File … … 113 109 114 110 SOURCE=..\src\pjnath\stun_session.c 111 # End Source File 112 # Begin Source File 113 114 SOURCE=..\src\pjnath\stun_setting.c 115 115 # End Source File 116 116 # Begin Source File … … 148 148 # Begin Source File 149 149 150 SOURCE=..\include\pjnath\stun_endpoint.h151 # End Source File152 # Begin Source File153 154 150 SOURCE=..\include\pjnath\stun_msg.h 155 151 # End Source File … … 157 153 158 154 SOURCE=..\include\pjnath\stun_session.h 155 # End Source File 156 # Begin Source File 157 158 SOURCE=..\include\pjnath\stun_setting.h 159 159 # End Source File 160 160 # Begin Source File -
pjproject/trunk/pjnath/include/pjnath.h
r1080 r1090 21 21 #include <pjnath/errno.h> 22 22 #include <pjnath/stun_auth.h> 23 #include <pjnath/stun_ endpoint.h>23 #include <pjnath/stun_setting.h> 24 24 #include <pjnath/stun_msg.h> 25 25 #include <pjnath/stun_session.h> -
pjproject/trunk/pjnath/include/pjnath/ice.h
r1089 r1090 148 148 149 149 150 typedef enum pj_ice_state151 {152 PJ_ICE_STATE_INIT,153 PJ_ICE_STATE_GATHERING,154 PJ_ICE_STATE_CAND_COMPLETE,155 PJ_ICE_STATE_CHECKING,156 PJ_ICE_STATE_COMPLETE,157 PJ_ICE_STATE_RESV_ERROR158 } pj_ice_state;159 160 150 typedef enum pj_ice_role 161 151 { … … 176 166 int sock_type; 177 167 pj_ice_role role; 178 pj_ice_state state;179 168 pj_ice_cb cb; 180 169 … … 199 188 pj_ice_cand rcand[PJ_ICE_MAX_CAND]; 200 189 201 /* Checklists */ 202 pj_ice_checklist cklist; 203 pj_ice_checklist valid_list; 190 /* Checklist */ 191 pj_ice_checklist clist; 192 193 /* Valid list */ 194 unsigned valid_cnt; 195 unsigned valid_list[PJ_ICE_MAX_CHECKS]; 204 196 205 197 /* STUN servers */ -
pjproject/trunk/pjnath/include/pjnath/stun_setting.h
r1089 r1090 33 33 /* **************************************************************************/ 34 34 /** 35 * @defgroup PJNATH_STUN_ ENDPOINT STUN Endpoint36 * @brief Management of incoming and outgoing STUN transactions.35 * @defgroup PJNATH_STUN_SETTING STUN Settings 36 * @brief STUN settings. 37 37 * @ingroup PJNATH_STUN 38 38 * @{ … … 40 40 41 41 /** 42 * Opaque declaration for STUN endpoint. STUN endpoint manages client and 43 * server STUN transactions, and it needs to be initialized before application 44 * can send or receive STUN messages. 42 * Opaque declaration for STUN setting. 45 43 */ 46 44 typedef struct pj_stun_config … … 92 90 93 91 /** 94 * Create a STUN endpoint instance.92 * Initialize STUN config. 95 93 */ 96 PJ_DECL(pj_status_t) pj_stun_config_create(pj_pool_factory *factory, 97 unsigned options, 98 pj_ioqueue_t *ioqueue, 99 pj_timer_heap_t *timer_heap, 100 pj_stun_config **p_endpt); 94 PJ_INLINE(void) pj_stun_config_init(pj_stun_config *cfg, 95 pj_pool_factory *factory, 96 unsigned options, 97 pj_ioqueue_t *ioqueue, 98 pj_timer_heap_t *timer_heap) 99 { 100 pj_bzero(cfg, sizeof(*cfg)); 101 101 102 /** 103 * Destroy STUN endpoint instance. 104 */ 105 PJ_DECL(pj_status_t) pj_stun_config_destroy(pj_stun_config *endpt); 102 cfg->pf = factory; 103 cfg->options = options; 104 cfg->ioqueue = ioqueue; 105 cfg->timer_heap = timer_heap; 106 cfg->rto_msec = PJ_STUN_RTO_VALUE; 107 cfg->res_cache_msec = 10000; 108 } 106 109 107 110 -
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; -
pjproject/trunk/pjnath/src/pjnath/stun_setting.c
r1089 r1090 22 22 #include <pj/pool.h> 23 23 24 25 /*26 * Create a STUN endpoint instance.27 */28 PJ_DEF(pj_status_t) pj_stun_config_create( pj_pool_factory *factory,29 unsigned options,30 pj_ioqueue_t *ioqueue,31 pj_timer_heap_t *timer_heap,32 pj_stun_config **p_endpt)33 {34 pj_pool_t *pool;35 pj_stun_config *endpt;36 37 PJ_ASSERT_RETURN(factory && p_endpt, PJ_EINVAL);38 39 pool = pj_pool_create(factory, "stunendpt", 1000, 1000, NULL);40 if (!pool)41 return PJ_ENOMEM;42 43 endpt = PJ_POOL_ZALLOC_T(pool, pj_stun_config);44 endpt->pool = pool;45 endpt->pf = factory;46 endpt->options = options;47 endpt->ioqueue = ioqueue;48 endpt->timer_heap = timer_heap;49 endpt->rto_msec = PJ_STUN_RTO_VALUE;50 endpt->res_cache_msec = 10000;51 52 *p_endpt = endpt;53 54 return PJ_SUCCESS;55 }56 57 58 /*59 * Destroy STUN endpoint instance.60 */61 PJ_DEF(pj_status_t) pj_stun_config_destroy(pj_stun_config *endpt)62 {63 PJ_ASSERT_RETURN(endpt, PJ_EINVAL);64 65 pj_pool_release(endpt->pool);66 67 return PJ_SUCCESS;68 }69
Note: See TracChangeset
for help on using the changeset viewer.