- Timestamp:
- Mar 20, 2007 10:36:54 PM (18 years ago)
- Location:
- pjproject/trunk/pjnath
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjnath/include/pjnath/errno.h
r1080 r1089 46 46 #define PJNATH_ESTUNFINGERPRINT -1 47 47 #define PJNATH_ESTUNNOTRESPOND -1 48 #define PJNATH_ESTUNNOXORMAP -1 48 49 49 50 /** -
pjproject/trunk/pjnath/include/pjnath/ice.h
r1085 r1089 28 28 #include <pjlib-util/resolver.h> 29 29 #include <pj/sock.h> 30 #include <pj/timer.h> 31 30 32 31 33 PJ_BEGIN_DECL … … 68 70 #define PJ_ICE_MAX_COMP 8 69 71 #define PJ_ICE_MAX_CHECKS 32 72 #define PJ_ICE_TA_VAL 20 70 73 71 74 /** … … 74 77 typedef struct pj_ice_comp 75 78 { 76 unsigned comp_id; 77 pj_sock_t sock; 79 unsigned comp_id; 80 pj_sock_t sock; 81 pj_stun_session *stun_sess; 82 pj_sockaddr local_addr; 78 83 } pj_ice_comp; 79 84 … … 105 110 typedef struct pj_ice_check 106 111 { 107 unsigned cand_id; 108 pj_uint32_t comp_id; 109 pj_str_t foundation; 110 111 pj_uint64_t check_prio; 112 pj_ice_check_state check_state; 113 114 pj_ice_cand_type rem_type; 115 pj_str_t rem_foundation; 116 pj_uint32_t rem_prio; 117 pj_sockaddr rem_addr; 118 pj_sockaddr rem_base_addr; 112 pj_ice_cand *lcand; 113 pj_ice_cand *rcand; 114 115 pj_uint64_t prio; 116 pj_ice_check_state state; 117 pj_bool_t nominated; 118 pj_status_t err_code; 119 119 } pj_ice_check; 120 120 … … 132 132 unsigned count; 133 133 pj_ice_check checks[PJ_ICE_MAX_CHECKS]; 134 pj_timer_entry timer; 134 135 } pj_ice_checklist; 135 136 … … 176 177 pj_ice_role role; 177 178 pj_ice_state state; 178 179 179 pj_ice_cb cb; 180 181 pj_stun_config stun_cfg; 180 182 181 183 /* STUN credentials */ … … 206 208 pj_bool_t relay_enabled; 207 209 pj_sockaddr stun_srv; 208 209 /* STUN sessions */210 pj_stun_session *tx_sess;211 pj_stun_session *rx_sess;212 210 }; 213 211 214 212 215 PJ_DECL(pj_status_t) pj_ice_create(pj_stun_config * cfg,213 PJ_DECL(pj_status_t) pj_ice_create(pj_stun_config *stun_cfg, 216 214 const char *name, 217 215 pj_ice_role role, … … 257 255 PJ_DECL(unsigned) pj_ice_get_cand_cnt(pj_ice *ice); 258 256 PJ_DECL(pj_status_t) pj_ice_enum_cands(pj_ice *ice, 259 unsigned sort_by,260 257 unsigned *p_count, 261 258 unsigned cand_ids[]); 262 PJ_DECL(unsigned) pj_ice_get_default_cand(pj_ice *ice, 263 int *cand_id); 259 PJ_DECL(pj_status_t) pj_ice_get_default_cand(pj_ice *ice, 260 unsigned comp_id, 261 int *cand_id); 264 262 PJ_DECL(pj_status_t) pj_ice_get_cand(pj_ice *ice, 265 263 unsigned cand_id, … … 267 265 268 266 PJ_DECL(pj_status_t) pj_ice_create_check_list(pj_ice *ice, 269 pj_bool_t is_remote_offer,270 267 unsigned rem_cand_cnt, 271 268 const pj_ice_cand rem_cand[]); -
pjproject/trunk/pjnath/include/pjnath/stun_auth.h
r1080 r1089 156 156 157 157 /** 158 * Get the credential to be put in outgoing message. 159 * 160 * @param msg The outgoing message where the credential is 161 * to be applied. 162 * @param user_data The user data as specified in the credential. 163 * @param pool Pool where the callback can allocate memory 164 * to fill in the credential. 165 * @param realm On return, the callback may specify the realm 166 * if long term credential is desired, otherwise 167 * this string must be set to empty. 168 * @param username On return, the callback must fill in with the 169 * username. 170 * @param nonce On return, the callback may optionally fill in 171 * this argument with NONCE value if desired, 172 * otherwise this argument must be set to empty. 173 * @param data_type On return, the callback must set this argument 174 * with the type of password in the data argument. 175 * @param data On return, the callback must set this with 176 * the password, encoded according to data_type 177 * argument. 178 * 179 * @return The callback must return PJ_SUCCESS, otherwise 180 * the message transmission will be cancelled. 181 */ 182 pj_status_t (*get_cred)(const pj_stun_msg *msg, 183 void *user_data, 184 pj_pool_t *pool, 185 pj_str_t *realm, 186 pj_str_t *username, 187 pj_str_t *nonce, 188 int *data_type, 189 pj_str_t *data); 190 191 /** 158 192 * Get the password for the specified username. This function 159 193 * is also used to check whether the username is valid. 160 194 * 195 * @param msg The STUN message where the password will be 196 * applied to. 161 197 * @param user_data The user data as specified in the credential. 162 198 * @param realm The realm as specified in the message. … … 176 212 * username is not valid. 177 213 */ 178 pj_status_t (*get_password)(void *user_data, 214 pj_status_t (*get_password)(const pj_stun_msg *msg, 215 void *user_data, 179 216 const pj_str_t *realm, 180 217 const pj_str_t *username, … … 188 225 * PJ_FALSE, 438 (Stale Nonce) response will be created. 189 226 * 227 * @param msg The STUN message where the nonce was received. 190 228 * @param user_data The user data as specified in the credential. 191 229 * @param realm The realm as specified in the message. … … 196 234 * NONCE can be accepted. 197 235 */ 198 pj_bool_t (*verify_nonce)(void *user_data, 236 pj_bool_t (*verify_nonce)(const pj_stun_msg *msg, 237 void *user_data, 199 238 const pj_str_t *realm, 200 239 const pj_str_t *username, -
pjproject/trunk/pjnath/src/pjnath/ice.c
r1085 r1089 20 20 #include <pjnath/errno.h> 21 21 #include <pj/addr_resolv.h> 22 #include <pj/array.h> 22 23 #include <pj/assert.h> 23 24 #include <pj/log.h> … … 27 28 28 29 30 /* String names for candidate types */ 31 static const char *cand_type_names[] = 32 { 33 "Host", 34 "Server Reflexive", 35 "Peer Reflexive", 36 "Relayed" 37 38 }; 39 40 /* String names for pj_ice_check_state */ 29 41 static const char *check_state_name[] = 30 42 { … … 36 48 }; 37 49 50 static const char *clist_state_name[] = 51 { 52 "Idle", 53 "Running", 54 "Completed" 55 }; 56 57 const pj_str_t host_foundation = {"host", 4}; 58 const pj_str_t mapped_foundation = {"srfx", 4}; 59 const pj_str_t relayed_foundation = {"rlyd", 4}; 60 const pj_str_t peer_mapped_foundation = {"peer", 4}; 61 62 #define CHECK_NAME_LEN 128 63 #define LOG(expr) PJ_LOG(4,expr) 64 38 65 static void destroy_ice(pj_ice *ice, 39 66 pj_status_t reason); 40 67 static void ice_set_state(pj_ice *ice, 41 68 pj_ice_state new_state); 42 69 static pj_status_t start_periodic_check(pj_timer_heap_t *th, 70 pj_timer_entry *te); 43 71 static pj_status_t on_stun_send_msg(pj_stun_session *sess, 44 72 const void *pkt, … … 52 80 const pj_sockaddr_t *src_addr, 53 81 unsigned src_addr_len); 54 static void on_stun_request_complete(pj_stun_session *s ess,82 static void on_stun_request_complete(pj_stun_session *stun_sess, 55 83 pj_status_t status, 56 84 pj_stun_tx_data *tdata, … … 67 95 pj_str_t *realm, 68 96 pj_str_t *nonce); 69 static pj_status_t stun_auth_get_password(void *user_data, 97 static pj_status_t stun_auth_get_cred(const pj_stun_msg *msg, 98 void *user_data, 99 pj_pool_t *pool, 100 pj_str_t *realm, 101 pj_str_t *username, 102 pj_str_t *nonce, 103 int *data_type, 104 pj_str_t *data); 105 static pj_status_t stun_auth_get_password(const pj_stun_msg *msg, 106 void *user_data, 70 107 const pj_str_t *realm, 71 108 const pj_str_t *username, … … 73 110 int *data_type, 74 111 pj_str_t *data); 75 static pj_bool_t stun_auth_verify_nonce(void *user_data, 112 static pj_bool_t stun_auth_verify_nonce(const pj_stun_msg *msg, 113 void *user_data, 76 114 const pj_str_t *realm, 77 115 const pj_str_t *username, … … 79 117 80 118 81 PJ_DEF(pj_status_t) pj_ice_create(pj_stun_config * cfg,119 PJ_DEF(pj_status_t) pj_ice_create(pj_stun_config *stun_cfg, 82 120 const char *name, 83 121 pj_ice_role role, … … 89 127 pj_pool_t *pool; 90 128 pj_ice *ice; 91 pj_stun_session_cb sess_cb;92 pj_stun_auth_cred auth_cred;93 129 pj_status_t status; 94 130 95 PJ_ASSERT_RETURN( cfg && cb && p_ice, PJ_EINVAL);131 PJ_ASSERT_RETURN(stun_cfg && cb && p_ice, PJ_EINVAL); 96 132 PJ_ASSERT_RETURN(sock_type==PJ_SOCK_DGRAM || sock_type==PJ_SOCK_STREAM, 97 133 PJ_EINVAL); … … 100 136 name = "ice%p"; 101 137 102 pool = pj_pool_create( cfg->pf, name, 4000, 4000, NULL);138 pool = pj_pool_create(stun_cfg->pf, name, 4000, 4000, NULL); 103 139 ice = PJ_POOL_ZALLOC_T(pool, pj_ice); 104 140 ice->pool = pool; … … 118 154 119 155 pj_memcpy(&ice->cb, cb, sizeof(*cb)); 120 121 /* Init STUN callbacks */ 122 pj_bzero(&sess_cb, sizeof(sess_cb)); 123 sess_cb.on_request_complete = &on_stun_request_complete; 124 sess_cb.on_rx_indication = &on_stun_rx_indication; 125 sess_cb.on_rx_request = &on_stun_rx_request; 126 sess_cb.on_send_msg = &on_stun_send_msg; 127 128 /* Init STUN authentication credential */ 129 pj_bzero(&auth_cred, sizeof(auth_cred)); 130 auth_cred.type = PJ_STUN_AUTH_CRED_DYNAMIC; 131 auth_cred.data.dyn_cred.get_auth = &stun_auth_get_auth; 132 auth_cred.data.dyn_cred.get_password = &stun_auth_get_password; 133 auth_cred.data.dyn_cred.verify_nonce = &stun_auth_verify_nonce; 134 135 /* Create STUN session for outgoing requests */ 136 status = pj_stun_session_create(cfg, ice->obj_name, &sess_cb, PJ_FALSE, 137 &ice->tx_sess); 138 if (status != PJ_SUCCESS) { 139 destroy_ice(ice, status); 140 return status; 141 } 142 143 pj_stun_session_set_user_data(ice->tx_sess, ice); 144 auth_cred.data.dyn_cred.user_data = ice->tx_sess; 145 pj_stun_session_set_credential(ice->tx_sess, &auth_cred); 146 147 /* Create STUN session for incoming requests */ 148 status = pj_stun_session_create(cfg, ice->obj_name, &sess_cb, PJ_FALSE, 149 &ice->rx_sess); 150 if (status != PJ_SUCCESS) { 151 destroy_ice(ice, status); 152 return status; 153 } 154 155 pj_stun_session_set_user_data(ice->rx_sess, ice); 156 auth_cred.data.dyn_cred.user_data = ice->rx_sess; 157 pj_stun_session_set_credential(ice->rx_sess, &auth_cred); 156 pj_memcpy(&ice->stun_cfg, stun_cfg, sizeof(*stun_cfg)); 157 158 158 159 159 /* Done */ 160 160 *p_ice = ice; 161 161 162 PJ_LOG(4,(ice->obj_name, "ICE session created"));162 LOG((ice->obj_name, "ICE session created")); 163 163 164 164 return PJ_SUCCESS; … … 170 170 { 171 171 if (reason == PJ_SUCCESS) { 172 PJ_LOG(4,(ice->obj_name, "Destroying ICE session"));172 LOG((ice->obj_name, "Destroying ICE session")); 173 173 } 174 174 … … 318 318 319 319 320 320 321 PJ_DEF(pj_status_t) pj_ice_add_comp(pj_ice *ice, 321 322 unsigned comp_id, … … 345 346 } 346 347 348 typedef struct stun_data 349 { 350 pj_ice *ice; 351 unsigned comp_id; 352 pj_ice_comp *comp; 353 } stun_data; 354 347 355 348 356 PJ_DEF(pj_status_t) pj_ice_add_sock_comp( pj_ice *ice, … … 350 358 pj_sock_t sock) 351 359 { 360 pj_stun_session_cb sess_cb; 361 pj_ice_comp *comp; 362 pj_stun_auth_cred auth_cred; 363 stun_data *sd; 364 int addr_len; 365 pj_status_t status; 366 352 367 PJ_ASSERT_RETURN(ice && sock != PJ_INVALID_SOCKET, PJ_EINVAL); 353 368 PJ_ASSERT_RETURN(ice->comp_cnt < PJ_ARRAY_SIZE(ice->comp), PJ_ETOOMANY); 354 369 355 370 pj_mutex_lock(ice->mutex); 356 ice->comp[ice->comp_cnt].comp_id = comp_id; 357 ice->comp[ice->comp_cnt].sock = sock; 358 ++ice->comp_cnt; 371 372 comp = &ice->comp[ice->comp_cnt]; 373 comp->comp_id = comp_id; 374 comp->sock = sock; 375 376 addr_len = sizeof(comp->local_addr); 377 status = pj_sock_getsockname(sock, &comp->local_addr, &addr_len); 378 if (status != PJ_SUCCESS) { 379 pj_mutex_unlock(ice->mutex); 380 return status; 381 } 382 383 384 /* Init STUN callbacks */ 385 pj_bzero(&sess_cb, sizeof(sess_cb)); 386 sess_cb.on_request_complete = &on_stun_request_complete; 387 sess_cb.on_rx_indication = &on_stun_rx_indication; 388 sess_cb.on_rx_request = &on_stun_rx_request; 389 sess_cb.on_send_msg = &on_stun_send_msg; 390 391 /* Create STUN session for this component */ 392 status = pj_stun_session_create(&ice->stun_cfg, ice->obj_name, 393 &sess_cb, PJ_FALSE, 394 &comp->stun_sess); 395 if (status != PJ_SUCCESS) { 396 pj_mutex_unlock(ice->mutex); 397 return status; 398 } 399 400 /* Associate data with this STUN session */ 401 sd = PJ_POOL_ZALLOC_T(ice->pool, struct stun_data); 402 sd->ice = ice; 403 sd->comp_id = comp_id; 404 sd->comp = comp; 405 pj_stun_session_set_user_data(comp->stun_sess, sd); 406 407 /* Init STUN authentication credential */ 408 pj_bzero(&auth_cred, sizeof(auth_cred)); 409 auth_cred.type = PJ_STUN_AUTH_CRED_DYNAMIC; 410 auth_cred.data.dyn_cred.get_auth = &stun_auth_get_auth; 411 auth_cred.data.dyn_cred.get_cred = &stun_auth_get_cred; 412 auth_cred.data.dyn_cred.get_password = &stun_auth_get_password; 413 auth_cred.data.dyn_cred.verify_nonce = &stun_auth_verify_nonce; 414 auth_cred.data.dyn_cred.user_data = comp->stun_sess; 415 pj_stun_session_set_credential(comp->stun_sess, &auth_cred); 416 417 /* Done */ 418 ice->comp_cnt++; 359 419 pj_mutex_unlock(ice->mutex); 360 420 … … 378 438 379 439 380 static pj_status_t stun_auth_get_password(void *user_data, 440 /* Get credential to be sent with outgoing message */ 441 static pj_status_t stun_auth_get_cred(const pj_stun_msg *msg, 442 void *user_data, 443 pj_pool_t *pool, 444 pj_str_t *realm, 445 pj_str_t *username, 446 pj_str_t *nonce, 447 int *data_type, 448 pj_str_t *data) 449 { 450 pj_stun_session *sess = (pj_stun_session *)user_data; 451 stun_data *sd = (stun_data*) pj_stun_session_get_user_data(sess); 452 pj_ice *ice = sd->ice; 453 454 PJ_UNUSED_ARG(pool); 455 realm->slen = nonce->slen = 0; 456 457 if (PJ_STUN_IS_RESPONSE(msg->hdr.type) || 458 PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type)) 459 { 460 /* Outgoing responses need to have the same credential as 461 * incoming requests. 462 */ 463 *username = ice->rx_uname; 464 *data_type = 0; 465 *data = ice->rx_pass; 466 } 467 else { 468 *username = ice->tx_uname; 469 *data_type = 0; 470 *data = ice->tx_pass; 471 } 472 473 return PJ_SUCCESS; 474 } 475 476 /* Get password to be used to authenticate incoming message */ 477 static pj_status_t stun_auth_get_password(const pj_stun_msg *msg, 478 void *user_data, 381 479 const pj_str_t *realm, 382 480 const pj_str_t *username, … … 386 484 { 387 485 pj_stun_session *sess = (pj_stun_session *)user_data; 388 pj_ice *ice = (pj_ice*) pj_stun_session_get_user_data(sess); 486 stun_data *sd = (stun_data*) pj_stun_session_get_user_data(sess); 487 pj_ice *ice = sd->ice; 389 488 390 489 PJ_UNUSED_ARG(realm); 391 490 PJ_UNUSED_ARG(pool); 392 491 393 if (sess == ice->tx_sess) { 492 if (PJ_STUN_IS_RESPONSE(msg->hdr.type) || 493 PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type)) 494 { 495 /* Incoming response is authenticated with TX credential */ 394 496 /* Verify username */ 395 497 if (pj_strcmp(username, &ice->tx_uname) != 0) … … 397 499 *data_type = 0; 398 500 *data = ice->tx_pass; 501 399 502 } else { 503 /* Incoming request is authenticated with RX credential */ 400 504 /* The agent MUST accept a credential if the username consists 401 505 * of two values separated by a colon, where the first value is … … 408 512 *data_type = 0; 409 513 *data = ice->rx_pass; 410 } 411 412 return PJ_SUCCESS; 413 } 414 415 416 static pj_bool_t stun_auth_verify_nonce(void *user_data, 514 515 } 516 517 return PJ_SUCCESS; 518 } 519 520 521 static pj_bool_t stun_auth_verify_nonce(const pj_stun_msg *msg, 522 void *user_data, 417 523 const pj_str_t *realm, 418 524 const pj_str_t *username, … … 420 526 { 421 527 /* We don't use NONCE */ 528 PJ_UNUSED_ARG(msg); 422 529 PJ_UNUSED_ARG(user_data); 423 530 PJ_UNUSED_ARG(realm); … … 484 591 485 592 status = pj_ice_add_cand(ice, i, PJ_ICE_CAND_TYPE_HOST, 65535, 486 NULL, &addr, &addr, NULL,593 &host_foundation, &addr, &addr, NULL, 487 594 sizeof(pj_sockaddr_in), NULL); 488 595 if (status != PJ_SUCCESS) … … 493 600 } 494 601 495 static pj_status_t gather_mapped_cands(pj_ice *ice) 496 { 497 PJ_UNUSED_ARG(ice); 498 return PJ_ENOTSUP; 499 } 500 501 static pj_status_t gather_relayed_cands(pj_ice *ice) 502 { 503 PJ_UNUSED_ARG(ice); 504 return PJ_ENOTSUP; 505 } 602 /* Eliminate redundant candidates. */ 603 static void eliminate_redundant_cand(unsigned *cnt, 604 pj_ice_cand cand[]) 605 { 606 607 /* A candidate is redundant if its transport address equals another 608 * candidate, and its base equals the base of that other candidate. 609 * Note that two candidates can have the same transport address yet 610 * have different bases, and these would not be considered redundant. 611 */ 612 PJ_TODO(ELIMINATE_REDUNDANT_CANDIDATES); 613 PJ_UNUSED_ARG(cnt); 614 PJ_UNUSED_ARG(cand); 615 } 616 506 617 507 618 PJ_DEF(pj_status_t) pj_ice_start_gather(pj_ice *ice, … … 516 627 if (status != PJ_SUCCESS) 517 628 return status; 629 630 /* Eliminate redundant host candidates. */ 631 eliminate_redundant_cand(&ice->lcand_cnt, ice->lcand); 518 632 519 633 PJ_TODO(GATHER_MAPPED_AND_RELAYED_CANDIDATES); … … 556 670 pj_ice_cand *lcand; 557 671 pj_status_t status = PJ_SUCCESS; 672 char tmp[128]; 673 674 PJ_ASSERT_RETURN(ice && comp_id && type && local_pref && 675 foundation && addr && base_addr && addr_len, 676 PJ_EINVAL); 558 677 559 678 pj_mutex_lock(ice->mutex); … … 579 698 *p_cand_id = ice->lcand_cnt; 580 699 700 pj_ansi_strcpy(tmp, pj_inet_ntoa(lcand->addr.ipv4.sin_addr)); 701 LOG((ice->obj_name, 702 "Candidate %d added: comp_id=%d, type=%s, foundation=%.*s, " 703 "addr=%s:%d, base=%s:%d, prio=0x%x (%u)", 704 ice->lcand_cnt, 705 lcand->comp_id, 706 cand_type_names[lcand->type], 707 (int)lcand->foundation.slen, 708 lcand->foundation.ptr, 709 tmp, 710 (int)pj_ntohs(lcand->addr.ipv4.sin_port), 711 pj_inet_ntoa(lcand->base_addr.ipv4.sin_addr), 712 (int)pj_htons(lcand->base_addr.ipv4.sin_port), 713 lcand->prio, lcand->prio)); 714 581 715 ++ice->lcand_cnt; 582 716 … … 594 728 595 729 PJ_DEF(pj_status_t) pj_ice_enum_cands(pj_ice *ice, 596 unsigned sort_by,597 730 unsigned *p_count, 598 731 unsigned cand_ids[]) … … 600 733 unsigned i, count; 601 734 602 PJ_ UNUSED_ARG(sort_by);735 PJ_ASSERT_RETURN(ice && p_count && *p_count && cand_ids, PJ_EINVAL); 603 736 604 737 pj_mutex_lock(ice->mutex); … … 615 748 616 749 750 PJ_DEF(pj_status_t) pj_ice_get_default_cand(pj_ice *ice, 751 unsigned comp_id, 752 int *cand_id) 753 { 754 PJ_ASSERT_RETURN(ice && comp_id && cand_id, PJ_EINVAL); 755 756 pj_mutex_lock(ice->mutex); 757 758 /* First find in valid list if we have nominated pair */ 759 760 /* If there's no nominated pair, find relayed candidate */ 761 762 /* If there's no relayed candidate, find server reflexive candidate */ 763 764 /* Otherwise return host candidate */ 765 766 pj_assert(!"Not implemented yet"); 767 PJ_TODO(IMPLEMENT_GET_DEFAULT_CAND); 768 769 pj_mutex_unlock(ice->mutex); 770 771 return PJ_SUCCESS; 772 } 773 774 617 775 PJ_DEF(pj_status_t) pj_ice_get_cand(pj_ice *ice, 618 776 unsigned cand_id, … … 635 793 #endif 636 794 637 static pj_uint64_t CALC_CHECK_PRIO(pj_uint32_t O, pj_uint32_t A) 638 { 795 static pj_uint64_t CALC_CHECK_PRIO(const pj_ice *ice, 796 const pj_ice_cand *lcand, 797 const pj_ice_cand *rcand) 798 { 799 pj_uint32_t O, A; 800 801 if (ice->role == PJ_ICE_ROLE_CONTROLLING) { 802 O = lcand->prio; 803 A = rcand->prio; 804 } else { 805 O = rcand->prio; 806 A = lcand->prio; 807 } 808 639 809 return ((pj_uint64_t)1 << 32) * MIN(O, A) + 640 810 (pj_uint64_t)2 * MAX(O, A) + (O>A ? 1 : 0); … … 645 815 const pj_ice_check *check) 646 816 { 647 char local_addr[128]; 817 const pj_ice_cand *lcand = check->lcand; 818 const pj_ice_cand *rcand = check->rcand; 819 char laddr[CHECK_NAME_LEN]; 648 820 int len; 649 821 650 pj_ansi_strcpy(local_addr, 651 pj_inet_ntoa(ice->lcand[check->cand_id].addr.ipv4.sin_addr)); 652 653 len = pj_ansi_snprintf(buffer, bufsize, 654 "%s:%d-->%s:%d", 655 local_addr, 656 (int)pj_ntohs(ice->lcand[check->cand_id].addr.ipv4.sin_port), 657 pj_inet_ntoa(check->rem_addr.ipv4.sin_addr), 658 (int)pj_ntohs(check->rem_addr.ipv4.sin_port)); 822 pj_ansi_strcpy(laddr, pj_inet_ntoa(lcand->addr.ipv4.sin_addr)); 823 824 if (lcand->addr.addr.sa_family == PJ_AF_INET) { 825 len = pj_ansi_snprintf(buffer, bufsize, 826 "%s:%d-->%s:%d", 827 laddr, (int)pj_ntohs(lcand->addr.ipv4.sin_port), 828 pj_inet_ntoa(rcand->addr.ipv4.sin_addr), 829 (int)pj_ntohs(rcand->addr.ipv4.sin_port)); 830 } else { 831 len = pj_ansi_snprintf(buffer, bufsize, "IPv6->IPv6"); 832 } 833 834 659 835 if (len < 0) 660 836 len = 0; … … 671 847 { 672 848 unsigned i; 673 char buffer[ 128];674 675 PJ_LOG(4,(ice->obj_name, "%s", title));849 char buffer[CHECK_NAME_LEN]; 850 851 LOG((ice->obj_name, "%s", title)); 676 852 for (i=0; i<clist->count; ++i) { 677 853 const pj_ice_check *c = &clist->checks[i]; 678 PJ_LOG(4,(ice->obj_name, " %d: %s (prio=%u, state=%s)",679 680 c->check_prio, check_state_name[c->check_state]));854 LOG((ice->obj_name, " %d: %s (prio=%u, state=%s)", 855 i, dump_check(buffer, sizeof(buffer), ice, c), 856 c->prio, check_state_name[c->state])); 681 857 } 682 858 } … … 685 861 #endif 686 862 863 static void check_set_state(pj_ice *ice, pj_ice_check *check, 864 pj_ice_check_state st, 865 pj_status_t err_code) 866 { 867 char buf[CHECK_NAME_LEN]; 868 LOG((ice->obj_name, "Check %s: state changed from %s to %s", 869 dump_check(buf, sizeof(buf), ice, check), 870 check_state_name[check->state], 871 check_state_name[st])); 872 check->state = st; 873 check->err_code = err_code; 874 } 875 876 static void clist_set_state(pj_ice *ice, pj_ice_checklist *clist, 877 pj_ice_checklist_state st) 878 { 879 LOG((ice->obj_name, "Checklist: state changed from %s to %s", 880 clist_state_name[clist->state], 881 clist_state_name[st])); 882 clist->state = st; 883 } 884 687 885 static void sort_checklist(pj_ice_checklist *clist) 688 886 { … … 692 890 unsigned j, highest = i; 693 891 for (j=i+1; j<clist->count; ++j) { 694 if (clist->checks[j].check_prio > 695 clist->checks[highest].check_prio) 696 { 892 if (clist->checks[j].prio > clist->checks[highest].prio) { 697 893 highest = j; 698 894 } … … 710 906 } 711 907 908 909 enum 910 { 911 SOCKADDR_EQUAL = 0, 912 SOCKADDR_NOT_EQUAL = 1 913 }; 914 915 /* Utility: compare sockaddr. 916 * Returns 0 if equal. 917 */ 918 static int sockaddr_cmp(const pj_sockaddr *a1, const pj_sockaddr *a2) 919 { 920 if (a1->addr.sa_family != a2->addr.sa_family) 921 return SOCKADDR_NOT_EQUAL; 922 923 if (a1->addr.sa_family == PJ_AF_INET) { 924 return !(a1->ipv4.sin_addr.s_addr == a2->ipv4.sin_addr.s_addr && 925 a1->ipv4.sin_port == a2->ipv4.sin_port); 926 } else if (a1->addr.sa_family == PJ_AF_INET6) { 927 return pj_memcmp(&a1->ipv6, &a2->ipv6, sizeof(a1->ipv6)); 928 } else { 929 pj_assert(!"Invalid address family!"); 930 return SOCKADDR_NOT_EQUAL; 931 } 932 } 933 934 935 /* Prune checklist, this must have been done after the checklist 936 * is sorted. 937 */ 938 static void prune_checklist(pj_ice *ice, pj_ice_checklist *clist) 939 { 940 unsigned i; 941 942 /* Since an agent cannot send requests directly from a reflexive 943 * candidate, but only from its base, the agent next goes through the 944 * sorted list of candidate pairs. For each pair where the local 945 * candidate is server reflexive, the server reflexive candidate MUST be 946 * replaced by its base. Once this has been done, the agent MUST prune 947 * the list. This is done by removing a pair if its local and remote 948 * candidates are identical to the local and remote candidates of a pair 949 * higher up on the priority list. The result is a sequence of ordered 950 * candidate pairs, called the check list for that media stream. 951 */ 952 for (i=0; i<clist->count; ++i) { 953 pj_ice_cand *licand = clist->checks[i].lcand; 954 pj_ice_cand *ricand = clist->checks[i].rcand; 955 const pj_sockaddr *liaddr; 956 unsigned j; 957 958 if (licand->type == PJ_ICE_CAND_TYPE_MAPPED) 959 liaddr = &licand->base_addr; 960 else 961 liaddr = &licand->addr; 962 963 for (j=i+1; j<clist->count;) { 964 pj_ice_cand *ljcand = clist->checks[j].lcand; 965 pj_ice_cand *rjcand = clist->checks[j].rcand; 966 const pj_sockaddr *ljaddr; 967 968 if (ljcand->type == PJ_ICE_CAND_TYPE_MAPPED) 969 ljaddr = &licand->base_addr; 970 else 971 ljaddr = &licand->addr; 972 973 if (sockaddr_cmp(liaddr, ljaddr) == SOCKADDR_EQUAL && 974 sockaddr_cmp(&ricand->addr, &rjcand->addr) == SOCKADDR_EQUAL) 975 { 976 /* Found duplicate, remove it */ 977 char buf[CHECK_NAME_LEN]; 978 979 LOG((ice->obj_name, "Check %s pruned", 980 dump_check(buf, sizeof(buf), ice, &clist->checks[j]))); 981 982 pj_array_erase(clist->checks, sizeof(clist->checks[0]), 983 clist->count, j); 984 --clist->count; 985 986 } else { 987 ++j; 988 } 989 } 990 } 991 } 992 993 typedef struct timer_data 994 { 995 pj_ice *ice; 996 pj_ice_checklist *clist; 997 } timer_data; 998 712 999 PJ_DEF(pj_status_t) pj_ice_create_check_list(pj_ice *ice, 713 pj_bool_t is_remote_offer, 714 unsigned rem_cand_cnt, 715 const pj_ice_cand rem_cand[]) 1000 unsigned rcand_cnt, 1001 const pj_ice_cand rcand[]) 716 1002 { 717 1003 pj_ice_checklist *clist; 1004 timer_data *td; 718 1005 unsigned i, j; 719 1006 720 PJ_ASSERT_RETURN(ice && rem_cand_cnt && rem_cand, PJ_EINVAL); 721 PJ_ASSERT_RETURN(rem_cand_cnt < PJ_ICE_MAX_CAND, PJ_ETOOMANY); 1007 PJ_ASSERT_RETURN(ice && rcand_cnt && rcand, PJ_EINVAL); 1008 PJ_ASSERT_RETURN(rcand_cnt + ice->rcand_cnt <= PJ_ICE_MAX_CAND, 1009 PJ_ETOOMANY); 722 1010 723 1011 pj_mutex_lock(ice->mutex); … … 725 1013 /* Save remote candidates */ 726 1014 ice->rcand_cnt = 0; 727 for (i=0; i<r em_cand_cnt; ++i) {1015 for (i=0; i<rcand_cnt; ++i) { 728 1016 pj_ice_cand *cn = &ice->rcand[ice->rcand_cnt++]; 729 pj_memcpy(cn, &r em_cand[i], sizeof(pj_ice_cand));730 pj_strdup(ice->pool, &cn->foundation, &r em_cand[i].foundation);1017 pj_memcpy(cn, &rcand[i], sizeof(pj_ice_cand)); 1018 pj_strdup(ice->pool, &cn->foundation, &rcand[i].foundation); 731 1019 } 732 1020 … … 734 1022 clist = &ice->cklist; 735 1023 for (i=0; i<ice->lcand_cnt; ++i) { 736 for (j=0; j<rem_cand_cnt; ++j) { 737 738 pj_ice_check *c = &clist->checks[clist->count++]; 1024 for (j=0; j<ice->rcand_cnt; ++j) { 1025 1026 pj_ice_cand *lcand = &ice->lcand[i]; 1027 pj_ice_cand *rcand = &ice->rcand[j]; 1028 pj_ice_check *chk = &clist->checks[clist->count]; 1029 1030 if (clist->count > PJ_ICE_MAX_CHECKS) { 1031 pj_mutex_unlock(ice->mutex); 1032 return PJ_ETOOMANY; 1033 } else { 1034 clist->count++; 1035 } 739 1036 740 1037 /* A local candidate is paired with a remote candidate if … … 742 1039 * and have the same IP address version. 743 1040 */ 744 if ( ice->lcand[i].comp_id != rem_cand[j].comp_id ||745 pj_strcmp(&ice->lcand[i].foundation,&rem_cand[j].foundation)==0)1041 if (lcand->comp_id != rcand->comp_id || 1042 lcand->addr.addr.sa_family != rcand->addr.addr.sa_family) 746 1043 { 747 1044 continue; 748 1045 } 749 1046 750 c->cand_id = i; 751 c->comp_id = ice->lcand[i].comp_id; 752 c->foundation = ice->lcand[i].foundation; 753 754 if (is_remote_offer) { 755 c->check_prio = CALC_CHECK_PRIO(rem_cand[j].prio, 756 ice->lcand[i].prio); 757 } else { 758 c->check_prio = CALC_CHECK_PRIO(ice->lcand[i].prio, 759 rem_cand[j].prio); 760 } 761 762 c->rem_type = rem_cand[j].type; 763 pj_strdup(ice->pool, &c->rem_foundation, &rem_cand[j].foundation); 764 c->rem_prio = rem_cand[j].prio; 765 pj_memcpy(&c->rem_addr, &rem_cand[j].addr, 766 sizeof(rem_cand[j].addr)); 767 pj_memcpy(&c->rem_base_addr, &rem_cand[j].base_addr, 768 sizeof(rem_cand[j].addr)); 1047 1048 chk->lcand = lcand; 1049 chk->rcand = rcand; 1050 chk->state = PJ_ICE_CHECK_STATE_FROZEN; 1051 1052 chk->prio = CALC_CHECK_PRIO(ice, lcand, rcand); 769 1053 } 770 1054 } … … 774 1058 775 1059 /* Prune the checklist */ 776 for (i=0; i<clist->count; ++i) { 777 PJ_TODO(PRUNE_CHECKLIST); 778 } 1060 prune_checklist(ice, clist); 1061 1062 /* Init timer entry in the checklist. Initially the timer ID is FALSE 1063 * because timer is not running. 1064 */ 1065 clist->timer.id = PJ_FALSE; 1066 td = PJ_POOL_ZALLOC_T(ice->pool, timer_data); 1067 td->ice = ice; 1068 td->clist = clist; 1069 clist->timer.user_data = (void*)td; 1070 clist->timer.cb = &start_periodic_check; 1071 779 1072 780 1073 /* Log checklist */ … … 799 1092 { 800 1093 pj_stun_tx_data *tdata; 1094 pj_ice_comp *comp; 801 1095 struct req_data *rd; 802 1096 pj_ice_check *check; 1097 const pj_ice_cand *lcand; 1098 const pj_ice_cand *rcand; 803 1099 pj_uint32_t prio; 804 1100 char buffer[128]; … … 806 1102 807 1103 check = &clist->checks[check_id]; 808 809 PJ_LOG(5,(ice->obj_name, 810 "Sending connectivity check for check %d: %s", 811 check_id, dump_check(buffer, sizeof(buffer), ice, check))); 1104 lcand = check->lcand; 1105 rcand = check->rcand; 1106 comp = &ice->comp[lcand->comp_id]; 1107 1108 LOG((ice->obj_name, 1109 "Sending connectivity check for check %d: %s", 1110 check_id, dump_check(buffer, sizeof(buffer), ice, check))); 812 1111 813 1112 /* Create request */ 814 status = pj_stun_session_create_req( ice->tx_sess,1113 status = pj_stun_session_create_req(comp->stun_sess, 815 1114 PJ_STUN_BINDING_REQUEST, &tdata); 816 1115 if (status != PJ_SUCCESS) … … 827 1126 828 1127 /* Add PRIORITY */ 829 prio = CALC_CAND_PRIO(check->rem_type, 65535, check->comp_id); 1128 prio = CALC_CAND_PRIO(PJ_ICE_CAND_TYPE_PEER_MAPPED, 65535, 1129 lcand->comp_id); 830 1130 pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg, PJ_STUN_ATTR_PRIORITY, 831 1131 prio); … … 837 1137 } 838 1138 1139 /* Note that USERNAME and MESSAGE-INTEGRITY will be added by the 1140 * STUN session. 1141 */ 1142 839 1143 /* Initiate STUN transaction to send the request */ 840 status = pj_stun_session_send_msg( ice->tx_sess, PJ_FALSE,841 & check->rem_addr,1144 status = pj_stun_session_send_msg(comp->stun_sess, PJ_FALSE, 1145 &rcand->addr, 842 1146 sizeof(pj_sockaddr_in), tdata); 843 1147 if (status != PJ_SUCCESS) 844 1148 return status; 845 1149 846 check->check_state = PJ_ICE_CHECK_STATE_IN_PROGRESS; 847 return PJ_SUCCESS; 848 } 849 850 /* Start periodic check for the specified checklist */ 851 static pj_status_t start_periodic_check(pj_ice *ice, pj_ice_checklist *clist) 852 { 1150 check_set_state(ice, check, PJ_ICE_CHECK_STATE_IN_PROGRESS, PJ_SUCCESS); 1151 return PJ_SUCCESS; 1152 } 1153 1154 1155 /* Start periodic check for the specified checklist. 1156 * This callback is called by timer on every Ta (20msec by default) 1157 */ 1158 static pj_status_t start_periodic_check(pj_timer_heap_t *th, 1159 pj_timer_entry *te) 1160 { 1161 timer_data *td; 1162 pj_ice *ice; 1163 pj_ice_checklist *clist; 853 1164 unsigned i, start_count=0; 854 1165 pj_status_t status; 855 1166 856 /* Checklist state must be idle or completed */ 857 pj_assert(clist->state == PJ_ICE_CHECKLIST_ST_IDLE || 858 clist->state == PJ_ICE_CHECKLIST_ST_COMPLETED); 1167 td = (struct timer_data*) te->user_data; 1168 ice = td->ice; 1169 clist = td->clist; 1170 1171 pj_mutex_lock(ice->mutex); 1172 1173 /* Set timer ID to FALSE first */ 1174 te->id = PJ_FALSE; 859 1175 860 1176 /* Set checklist state to Running */ 861 clist->state = PJ_ICE_CHECKLIST_ST_RUNNING; 862 863 PJ_LOG(4,(ice->obj_name, "Starting checklist periodic check")); 864 865 /* Send STUN Binding request for checks in Waiting list */ 1177 clist_set_state(ice, clist, PJ_ICE_CHECKLIST_ST_RUNNING); 1178 1179 LOG((ice->obj_name, "Starting checklist periodic check")); 1180 1181 /* Send STUN Binding request for check with highest priority on 1182 * Waiting state. 1183 */ 866 1184 for (i=0; i<clist->count; ++i) { 867 1185 pj_ice_check *check = &clist->checks[i]; 868 1186 869 if (check-> check_state == PJ_ICE_CHECK_STATE_WAITING) {1187 if (check->state == PJ_ICE_CHECK_STATE_WAITING) { 870 1188 status = perform_check(ice, clist, i); 871 if (status != PJ_SUCCESS) 1189 if (status != PJ_SUCCESS) { 1190 pj_mutex_unlock(ice->mutex); 872 1191 return status; 1192 } 873 1193 874 1194 ++start_count; 1195 break; 875 1196 } 876 1197 } … … 883 1204 pj_ice_check *check = &clist->checks[i]; 884 1205 885 if (check-> check_state == PJ_ICE_CHECK_STATE_FROZEN) {1206 if (check->state == PJ_ICE_CHECK_STATE_FROZEN) { 886 1207 status = perform_check(ice, clist, i); 887 if (status != PJ_SUCCESS) 1208 if (status != PJ_SUCCESS) { 1209 pj_mutex_unlock(ice->mutex); 888 1210 return status; 1211 } 889 1212 890 1213 ++start_count; … … 898 1221 */ 899 1222 if (start_count==0) { 900 clist->state = PJ_ICE_CHECKLIST_ST_COMPLETED; 901 PJ_LOG(4,(ice->obj_name, "Checklist completed")); 902 } 903 1223 clist_set_state(ice, clist, PJ_ICE_CHECKLIST_ST_COMPLETED); 1224 1225 } else { 1226 /* Schedule for next timer */ 1227 pj_time_val timeout = {0, PJ_ICE_TA_VAL}; 1228 1229 te->id = PJ_TRUE; 1230 pj_time_val_normalize(&timeout); 1231 pj_timer_heap_schedule(th, te, &timeout); 1232 } 1233 1234 pj_mutex_unlock(ice->mutex); 904 1235 return PJ_SUCCESS; 905 1236 } … … 910 1241 { 911 1242 pj_ice_checklist *clist; 1243 const pj_ice_cand *cand0; 912 1244 unsigned i; 913 1245 914 1246 PJ_ASSERT_RETURN(ice, PJ_EINVAL); 1247 1248 LOG((ice->obj_name, "Starting ICE check..")); 915 1249 916 1250 clist = &ice->cklist; … … 920 1254 921 1255 /* Pickup the first pair and set the state to Waiting */ 922 clist->checks[0].check_state = PJ_ICE_CHECK_STATE_WAITING; 1256 clist->checks[0].state = PJ_ICE_CHECK_STATE_WAITING; 1257 cand0 = clist->checks[0].lcand; 923 1258 924 1259 /* Find all of the other pairs in that check list with the same … … 927 1262 */ 928 1263 for (i=1; i<clist->count; ++i) { 929 pj_ice_check *cki = &clist->checks[i];930 931 if (cki->comp_id != clist->checks[0].comp_id)932 continue; 933 934 if (pj_strcmp(&cki->foundation, &clist->checks[0].foundation)==0)935 continue;936 937 clist->checks[i].check_state = PJ_ICE_CHECK_STATE_WAITING;1264 const pj_ice_cand *cand1; 1265 1266 cand1 = clist->checks[i].lcand; 1267 1268 if (cand0->comp_id == cand1->comp_id && 1269 pj_strcmp(&cand0->foundation, &cand1->foundation)!=0) 1270 { 1271 clist->checks[i].state = PJ_ICE_CHECK_STATE_WAITING; 1272 } 938 1273 } 939 1274 940 1275 /* Start periodic check */ 941 return start_periodic_check(ice , clist);1276 return start_periodic_check(ice->stun_cfg.timer_heap, &clist->timer); 942 1277 } 943 1278 … … 956 1291 957 1292 958 static pj_status_t on_stun_rx_request(pj_stun_session *sess,959 const pj_uint8_t *pkt,960 unsigned pkt_len,961 const pj_stun_msg *msg,962 const pj_sockaddr_t *src_addr,963 unsigned src_addr_len)964 {965 pj_stun_tx_data *tdata;966 pj_status_t status;967 968 /* 7.2.1.2. Learning Peer Reflexive Candidates */969 PJ_TODO(LEARN_PEER_REFLEXIVE_CANDIDATES);970 971 /* Reject any requests except Binding request */972 if (msg->hdr.type != PJ_STUN_BINDING_REQUEST) {973 status = pj_stun_session_create_response(sess, msg,974 PJ_STUN_SC_BAD_REQUEST,975 NULL, &tdata);976 if (status != PJ_SUCCESS)977 return status;978 979 status = pj_stun_session_send_msg(sess, PJ_TRUE,980 src_addr, src_addr_len, tdata);981 return status;982 }983 984 status = pj_stun_session_create_response(sess, msg, 0, NULL, &tdata);985 if (status != PJ_SUCCESS)986 return status;987 988 status = pj_stun_msg_add_sockaddr_attr(tdata->pool, msg,989 PJ_STUN_ATTR_XOR_MAPPED_ADDR,990 PJ_TRUE, src_addr, src_addr_len);991 992 status = pj_stun_session_send_msg(sess, PJ_TRUE,993 src_addr, src_addr_len, tdata);994 995 /* 7.2.1.3. Triggered Checks:996 * Next, the agent constructs a pair whose local candidate is equal to997 * the transport address on which the STUN request was received, and a998 * remote candidate equal to the source transport address where the999 * request came from (which may be peer-reflexive remote candidate that1000 * was just learned).1001 */1002 1003 return status;1004 }1005 1006 1293 /* This callback is called when outgoing STUN request completed */ 1007 static void on_stun_request_complete(pj_stun_session *s ess,1294 static void on_stun_request_complete(pj_stun_session *stun_sess, 1008 1295 pj_status_t status, 1009 1296 pj_stun_tx_data *tdata, … … 1013 1300 pj_ice *ice; 1014 1301 pj_ice_check *check, *valid_check; 1302 const pj_ice_cand *lcand; 1303 const pj_ice_cand *rcand; 1015 1304 pj_ice_checklist *clist; 1016 char buffer[128]; 1305 pj_stun_xor_mapped_addr_attr *xaddr; 1306 char buffer[CHECK_NAME_LEN]; 1307 unsigned i; 1308 1309 PJ_UNUSED_ARG(stun_sess); 1017 1310 1018 1311 ice = rd->ice; … … 1020 1313 clist = rd->clist; 1021 1314 1022 PJ_LOG(5,(ice->obj_name, 1023 "Connectivity check %s for check %d: %s", 1024 (status==PJ_SUCCESS ? "SUCCESS" : "FAILED"), rd->ckid, 1025 dump_check(buffer, sizeof(buffer), ice, check))); 1315 pj_mutex_lock(ice->mutex); 1316 1317 lcand = check->lcand; 1318 rcand = check->rcand; 1319 1320 LOG((ice->obj_name, 1321 "Connectivity check %s for check %s", 1322 (status==PJ_SUCCESS ? "SUCCESS" : "FAILED"), 1323 dump_check(buffer, sizeof(buffer), ice, check))); 1026 1324 1027 1325 if (status != PJ_SUCCESS) { 1028 check->check_state = PJ_ICE_CHECK_STATE_FAILED; 1326 check_set_state(ice, check, PJ_ICE_CHECK_STATE_FAILED, status); 1327 pj_mutex_unlock(ice->mutex); 1029 1328 return; 1030 1329 } … … 1036 1335 * Request was sent from. 1037 1336 */ 1038 PJ_TODO(CHECK_ICE_RESPONSE_SOURCE_ADDRESS); 1039 1040 /* Get the STUN MAPPED-ADDRESS attribute. If the 1041 * transport address does not match any of the local candidates that the 1042 * agent knows about, the mapped address represents a new candidate - a 1043 * peer reflexive candidate 1044 */ 1045 PJ_TODO(CHECK_ICE_RESPONSE_SOURCE_ADDRESS2); 1337 PJ_TODO(ICE_CHECK_RESPONSE_SOURCE_ADDRESS); 1338 1339 /* Get the STUN MAPPED-ADDRESS attribute. */ 1340 xaddr = (pj_stun_xor_mapped_addr_attr*) 1341 pj_stun_msg_find_attr(response, PJ_STUN_ATTR_XOR_MAPPED_ADDR,0); 1342 if (!xaddr) { 1343 check_set_state(ice, check, PJ_ICE_CHECK_STATE_FAILED, 1344 PJNATH_ESTUNNOXORMAP); 1345 pj_mutex_unlock(ice->mutex); 1346 return; 1347 } 1348 1349 /* If the transport address returned in XOR-MAPPED-ADDRESS does not match 1350 * any of the local candidates that the agent knows about, the mapped 1351 * address represents a new candidate - a peer reflexive candidate. 1352 */ 1353 for (i=0; i<ice->lcand_cnt; ++i) { 1354 if (sockaddr_cmp(&xaddr->sockaddr, &ice->lcand[i].addr) == 0) { 1355 /* Match */ 1356 break; 1357 } 1358 } 1359 1360 if (i == ice->lcand_cnt) { 1361 unsigned cand_id; 1362 1363 /* Add new peer reflexive candidate */ 1364 status = pj_ice_add_cand(ice, lcand->comp_id, 1365 PJ_ICE_CAND_TYPE_PEER_MAPPED, 1366 65535, &peer_mapped_foundation, 1367 &xaddr->sockaddr, &lcand->base_addr, NULL, 1368 sizeof(pj_sockaddr_in), &cand_id); 1369 if (status != PJ_SUCCESS) { 1370 check_set_state(ice, check, PJ_ICE_CHECK_STATE_FAILED, status); 1371 pj_mutex_unlock(ice->mutex); 1372 return; 1373 } 1374 1375 /* Update local candidate */ 1376 lcand = &ice->lcand[cand_id]; 1377 } 1046 1378 1047 1379 /* Sets the state of the pair that generated the check to succeeded. */ 1048 check->check_state = PJ_ICE_CHECK_STATE_SUCCEEDED; 1380 check_set_state(ice, check, PJ_ICE_CHECK_STATE_SUCCEEDED, PJ_SUCCESS); 1381 1049 1382 1050 1383 /* This is a valid pair, so add this to the valid list */ 1051 1384 valid_check = &ice->valid_list.checks[ice->valid_list.count++]; 1052 pj_memcpy(valid_check, check, sizeof(*check)); 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; 1053 1393 1054 1394 /* Sort valid_list */ 1055 1395 sort_checklist(&ice->valid_list); 1056 1057 1396 1058 1397 /* If the pair had a component ID of 1, the agent MUST change the … … 1060 1399 * same foundation, but different component IDs, to Waiting. 1061 1400 */ 1062 if ( check->comp_id == 1) {1401 if (lcand->comp_id == 1) { 1063 1402 unsigned i; 1403 pj_bool_t unfrozen = PJ_FALSE; 1404 1064 1405 for (i=0; i<clist->count; ++i) { 1065 1406 pj_ice_check *c = &clist->checks[i]; 1066 1407 1067 if (c-> check_state == PJ_ICE_CHECK_STATE_FROZEN &&1068 c-> comp_id != check->comp_id &&1069 pj_strcmp(&c-> foundation, &check->foundation)==0)1408 if (c->state == PJ_ICE_CHECK_STATE_FROZEN && 1409 c->lcand->comp_id != lcand->comp_id && 1410 pj_strcmp(&c->lcand->foundation, &lcand->foundation)==0) 1070 1411 { 1071 1412 /* Unfreeze and start check */ 1072 PJ_LOG(5,(ice->obj_name, "Unfreezing check %d", i));1073 c->check_state = PJ_ICE_CHECK_STATE_WAITING;1074 perform_check(ice, clist, i);1413 check_set_state(ice, c, PJ_ICE_CHECK_STATE_WAITING, 1414 PJ_SUCCESS); 1415 unfrozen = PJ_TRUE; 1075 1416 } 1076 1417 } 1077 1418 1419 if (unfrozen && clist->timer.id == PJ_FALSE) 1420 start_periodic_check(ice->stun_cfg.timer_heap, &clist->timer); 1078 1421 } 1422 1079 1423 /* If the pair had a component ID equal to the number of components 1080 1424 * for the media stream (where this is the actual number of … … 1095 1439 } 1096 1440 1097 } 1441 pj_mutex_unlock(ice->mutex); 1442 } 1443 1444 1445 static pj_status_t on_stun_rx_request(pj_stun_session *sess, 1446 const pj_uint8_t *pkt, 1447 unsigned pkt_len, 1448 const pj_stun_msg *msg, 1449 const pj_sockaddr_t *src_addr, 1450 unsigned src_addr_len) 1451 { 1452 stun_data *sd; 1453 pj_ice *ice; 1454 pj_stun_priority_attr *ap; 1455 pj_ice_comp *comp; 1456 pj_ice_cand *lcand; 1457 pj_ice_cand *rcand; 1458 unsigned i; 1459 pj_stun_tx_data *tdata; 1460 pj_bool_t is_relayed; 1461 pj_status_t status; 1462 1463 PJ_UNUSED_ARG(pkt); 1464 PJ_UNUSED_ARG(pkt_len); 1465 1466 /* Only accepts Binding request */ 1467 if (msg->hdr.type != PJ_STUN_BINDING_REQUEST) { 1468 LOG((ice->obj_name, "Received non-Binding request, ignored")); 1469 return PJ_SUCCESS; 1470 } 1471 1472 sd = (stun_data*) pj_stun_session_get_user_data(sess); 1473 ice = sd->ice; 1474 comp = sd->comp; 1475 1476 pj_mutex_lock(ice->mutex); 1477 1478 /* Get PRIORITY attribute */ 1479 ap = (pj_stun_priority_attr*) 1480 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_PRIORITY, 0); 1481 if (ap == 0) { 1482 LOG((ice->obj_name, "Received Binding request with no PRIORITY")); 1483 pj_mutex_unlock(ice->mutex); 1484 return PJ_SUCCESS; 1485 } 1486 1487 /* For simplicity, ignore incoming requests when we don't have remote 1488 * candidates yet. The peer agent should retransmit the STUN request 1489 * and we'll receive it again later. 1490 */ 1491 if (ice->rcand_cnt == 0) { 1492 pj_mutex_unlock(ice->mutex); 1493 return PJ_SUCCESS; 1494 } 1495 1496 1497 /* Find remote candidate based on the source transport address of 1498 * the request. 1499 */ 1500 for (i=0; i<ice->rcand_cnt; ++i) { 1501 if (sockaddr_cmp((const pj_sockaddr*)src_addr, &ice->rcand[i].addr)==0) 1502 break; 1503 } 1504 1505 /* If the source transport address of the request does not match any 1506 * existing remote candidates, it represents a new peer reflexive remote 1507 * candidate. 1508 */ 1509 if (i == ice->rcand_cnt) { 1510 rcand = &ice->rcand[ice->rcand_cnt++]; 1511 rcand->comp_id = comp->comp_id; 1512 rcand->type = PJ_ICE_CAND_TYPE_PEER_MAPPED; 1513 rcand->prio = ap->value; 1514 pj_memcpy(&rcand->addr, src_addr, src_addr_len); 1515 1516 /* Foundation is random, unique from other foundation */ 1517 rcand->foundation.ptr = pj_pool_alloc(ice->pool, 32); 1518 rcand->foundation.slen = pj_ansi_snprintf(rcand->foundation.ptr, 32, 1519 "f%p", 1520 rcand->foundation.ptr); 1521 } else { 1522 /* Remote candidate found */ 1523 rcand = &ice->rcand[i]; 1524 } 1525 1526 /* 1527 * Create candidate pair for this request. 1528 */ 1529 /* First check if the source address is the source address of the 1530 * STUN relay, to determine if local candidate is relayed candidate. 1531 */ 1532 PJ_TODO(DETERMINE_IF_REQUEST_COMES_FROM_RELAYED_CANDIDATE); 1533 is_relayed = PJ_FALSE; 1534 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; 1551 } 1552 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 1581 pj_mutex_unlock(ice->mutex); 1582 return status; 1583 } 1584 1098 1585 1099 1586 static pj_status_t on_stun_rx_indication(pj_stun_session *sess, … … 1104 1591 unsigned src_addr_len) 1105 1592 { 1593 PJ_UNUSED_ARG(sess); 1594 PJ_UNUSED_ARG(pkt); 1595 PJ_UNUSED_ARG(pkt_len); 1596 PJ_UNUSED_ARG(msg); 1597 PJ_UNUSED_ARG(src_addr); 1598 PJ_UNUSED_ARG(src_addr_len); 1599 1106 1600 PJ_TODO(SUPPORT_RX_BIND_REQUEST_AS_INDICATION); 1601 1107 1602 return PJ_ENOTSUP; 1108 1603 } -
pjproject/trunk/pjnath/src/pjnath/stun_auth.c
r1080 r1089 186 186 int data_type = 0; 187 187 pj_status_t rc; 188 rc = cred->data.dyn_cred.get_password(cred->data.dyn_cred.user_data, 188 rc = cred->data.dyn_cred.get_password(msg, 189 cred->data.dyn_cred.user_data, 189 190 (arealm?&arealm->value:NULL), 190 191 &auser->value, pool, … … 270 271 271 272 if (cred->type == PJ_STUN_AUTH_CRED_DYNAMIC) { 272 ok=cred->data.dyn_cred.verify_nonce(cred->data.dyn_cred.user_data, 273 ok=cred->data.dyn_cred.verify_nonce(msg, 274 cred->data.dyn_cred.user_data, 273 275 (arealm?&arealm->value:NULL), 274 276 &auser->value, -
pjproject/trunk/pjnath/src/pjnath/stun_session.c
r1080 r1089 207 207 } 208 208 209 static pj_str_t *get_passwd(pj_stun_session *sess) 210 { 211 if (sess->cred == NULL) 209 static pj_str_t *get_passwd(pj_stun_session *sess, pj_pool_t *pool, 210 const pj_stun_msg *msg) 211 { 212 if (sess->cred == NULL) { 212 213 return NULL; 213 else if (sess->cred->type == PJ_STUN_AUTH_CRED_STATIC)214 } else if (sess->cred->type == PJ_STUN_AUTH_CRED_STATIC) { 214 215 return &sess->cred->data.static_cred.data; 215 else 216 } else if (sess->cred->type == PJ_STUN_AUTH_CRED_DYNAMIC) { 217 pj_str_t realm, username, nonce; 218 pj_str_t *password; 219 void *user_data = sess->cred->data.dyn_cred.user_data; 220 int data_type = 0; 221 pj_status_t status; 222 223 realm.slen = username.slen = nonce.slen = 0; 224 password = PJ_POOL_ZALLOC_T(pool, pj_str_t); 225 status = (*sess->cred->data.dyn_cred.get_cred)(msg, user_data, pool, 226 &realm, &username, 227 &nonce, &data_type, 228 password); 229 return password; 230 231 } else { 216 232 return NULL; 233 } 217 234 } 218 235 … … 222 239 { 223 240 pj_status_t status = 0; 241 pj_str_t realm, username, nonce, password; 242 int data_type = 0; 243 244 realm.slen = username.slen = nonce.slen = password.slen = 0; 224 245 225 246 /* The server SHOULD include a SERVER attribute in all responses */ … … 239 260 !PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type)) 240 261 { 241 const pj_str_t *username; 242 243 /* Create and add USERNAME attribute */ 244 username = &sess->cred->data.static_cred.username; 262 realm = sess->cred->data.static_cred.realm; 263 username = sess->cred->data.static_cred.username; 264 data_type = sess->cred->data.static_cred.data_type; 265 password = sess->cred->data.static_cred.data; 266 nonce = sess->cred->data.static_cred.nonce; 267 268 } else if (sess->cred && sess->cred->type == PJ_STUN_AUTH_CRED_DYNAMIC && 269 !PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type)) 270 { 271 void *user_data = sess->cred->data.dyn_cred.user_data; 272 273 status = (*sess->cred->data.dyn_cred.get_cred)(msg, user_data, pool, 274 &realm, &username, 275 &nonce, &data_type, 276 &password); 277 if (status != PJ_SUCCESS) 278 return status; 279 } 280 281 282 /* Create and add USERNAME attribute */ 283 status = pj_stun_msg_add_string_attr(pool, msg, 284 PJ_STUN_ATTR_USERNAME, 285 &username); 286 PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 287 288 /* Add REALM only when long term credential is used */ 289 if (realm.slen) { 245 290 status = pj_stun_msg_add_string_attr(pool, msg, 246 PJ_STUN_ATTR_USERNAME,247 username);291 PJ_STUN_ATTR_REALM, 292 &realm); 248 293 PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 249 250 /* Add REALM only when long term credential is used */ 251 if (sess->cred->data.static_cred.realm.slen) { 252 const pj_str_t *realm = &sess->cred->data.static_cred.realm; 253 status = pj_stun_msg_add_string_attr(pool, msg, 254 PJ_STUN_ATTR_REALM, 255 realm); 256 } 257 258 /* Add MESSAGE-INTEGRITY attribute */ 259 status = pj_stun_msg_add_msgint_attr(pool, msg); 260 PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 261 262 } 294 } 295 296 /* Add NONCE when desired */ 297 if (nonce.slen) { 298 status = pj_stun_msg_add_string_attr(pool, msg, 299 PJ_STUN_ATTR_NONCE, 300 &nonce); 301 } 302 303 /* Add MESSAGE-INTEGRITY attribute */ 304 status = pj_stun_msg_add_msgint_attr(pool, msg); 305 PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 306 263 307 264 308 /* Add FINGERPRINT attribute if necessary */ … … 543 587 /* Encode message */ 544 588 status = pj_stun_msg_encode(tdata->msg, tdata->pkt, tdata->max_len, 545 0, get_passwd(sess), &tdata->pkt_size); 589 0, get_passwd(sess, tdata->pool, tdata->msg), 590 &tdata->pkt_size); 546 591 if (status != PJ_SUCCESS) { 547 592 pj_stun_msg_destroy_tdata(sess, tdata); … … 640 685 pj_status_t status; 641 686 687 /* Apply options */ 688 if (!retransmission) { 689 status = apply_msg_options(sess, pool, response); 690 if (status != PJ_SUCCESS) 691 return status; 692 } 693 642 694 /* Alloc packet buffer */ 643 695 out_max_len = PJ_STUN_MAX_PKT_LEN; 644 696 out_pkt = pj_pool_alloc(pool, out_max_len); 645 697 646 /* Apply options */647 if (!retransmission) {648 apply_msg_options(sess, pool, response);649 }650 651 698 /* Encode */ 652 699 status = pj_stun_msg_encode(response, out_pkt, out_max_len, 0, 653 get_passwd(sess), &out_len); 700 get_passwd(sess, pool, response), 701 &out_len); 654 702 if (status != PJ_SUCCESS) { 655 703 LOG_ERR_(sess, "Error encoding message", status);
Note: See TracChangeset
for help on using the changeset viewer.