Changeset 1091 for pjproject/trunk
- Timestamp:
- Mar 21, 2007 9:31:01 AM (18 years ago)
- Location:
- pjproject/trunk/pjnath
- Files:
-
- 1 deleted
- 12 edited
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjnath/build/pjnath.dsp
r1090 r1091 112 112 # Begin Source File 113 113 114 SOURCE=..\src\pjnath\stun_setting.c115 # End Source File116 # Begin Source File117 118 114 SOURCE=..\src\pjnath\stun_transaction.c 119 115 # End Source File … … 144 140 # Begin Source File 145 141 142 SOURCE=..\include\pjnath\stun_config.h 143 # End Source File 144 # Begin Source File 145 146 146 SOURCE=..\include\pjnath\stun_doc.h 147 147 # End Source File … … 153 153 154 154 SOURCE=..\include\pjnath\stun_session.h 155 # End Source File156 # Begin Source File157 158 SOURCE=..\include\pjnath\stun_setting.h159 155 # End Source File 160 156 # Begin Source File -
pjproject/trunk/pjnath/build/pjstun_client.dsp
r1062 r1091 43 43 # PROP Target_Dir "" 44 44 # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c 45 # ADD CPP /nologo /MD /W3 /GX /O2 /I "../include" /I "../../pjlib/include" / D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /YX /FD /c45 # ADD CPP /nologo /MD /W3 /GX /O2 /I "../include" /I "../../pjlib/include" /I "../../pjlib-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /YX /FD /c 46 46 # ADD BASE RSC /l 0x409 /d "NDEBUG" 47 47 # ADD RSC /l 0x409 /d "NDEBUG" … … 67 67 # PROP Target_Dir "" 68 68 # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c 69 # ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../include" /I "../../pjlib/include" / D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /YX /FD /GZ /c69 # ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../include" /I "../../pjlib/include" /I "../../pjlib-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /YX /FD /GZ /c 70 70 # ADD BASE RSC /l 0x409 /d "_DEBUG" 71 71 # ADD RSC /l 0x409 /d "_DEBUG" -
pjproject/trunk/pjnath/build/pjstun_srv_test.dsp
r1062 r1091 43 43 # PROP Target_Dir "" 44 44 # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c 45 # ADD CPP /nologo /MD /W4 /GX /O2 /I "../include" /I "../../pjlib/include" / D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /YX /FD /c45 # ADD CPP /nologo /MD /W4 /GX /O2 /I "../include" /I "../../pjlib/include" /I "../../pjlib-util/include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /YX /FD /c 46 46 # ADD BASE RSC /l 0x409 /d "NDEBUG" 47 47 # ADD RSC /l 0x409 /d "NDEBUG" … … 67 67 # PROP Target_Dir "" 68 68 # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c 69 # ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "../include" /I "../../pjlib/include" / D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /YX /FD /GZ /c69 # ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "../include" /I "../../pjlib/include" /I "../../pjlib-util/include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /YX /FD /GZ /c 70 70 # ADD BASE RSC /l 0x409 /d "_DEBUG" 71 71 # ADD RSC /l 0x409 /d "_DEBUG" -
pjproject/trunk/pjnath/include/pjnath.h
r1090 r1091 21 21 #include <pjnath/errno.h> 22 22 #include <pjnath/stun_auth.h> 23 #include <pjnath/stun_ setting.h>23 #include <pjnath/stun_config.h> 24 24 #include <pjnath/stun_msg.h> 25 25 #include <pjnath/stun_session.h> -
pjproject/trunk/pjnath/include/pjnath/stun_config.h
r1090 r1091 26 26 27 27 #include <pjnath/stun_msg.h> 28 #include <pj/string.h> 28 29 29 30 … … 33 34 /* **************************************************************************/ 34 35 /** 35 * @defgroup PJNATH_STUN_ SETTING STUN Settings36 * @brief STUN settings.36 * @defgroup PJNATH_STUN_CONFIG STUN Config 37 * @brief STUN config 37 38 * @ingroup PJNATH_STUN 38 39 * @{ … … 40 41 41 42 /** 42 * Opaque declaration for STUN setting.43 * STUN configuration. 43 44 */ 44 45 typedef struct pj_stun_config 45 46 { 46 47 /** 47 * Pool factory to be used by the STUN endpoint and all objects created 48 * that use this STUN endpoint. 48 * Pool factory to be used. 49 49 */ 50 50 pj_pool_factory *pf; 51 51 52 52 /** 53 * Ioqueue used by this endpoint.53 * Ioqueue. 54 54 */ 55 55 pj_ioqueue_t *ioqueue; 56 56 57 57 /** 58 * Timer heap instance used by this endpoint.58 * Timer heap instance. 59 59 */ 60 60 pj_timer_heap_t *timer_heap; 61 62 /**63 * Internal pool used by this endpoint. This shouldn't be used by64 * application.65 */66 pj_pool_t *pool;67 61 68 62 /** -
pjproject/trunk/pjnath/include/pjnath/stun_session.h
r1085 r1091 22 22 #include <pjnath/stun_msg.h> 23 23 #include <pjnath/stun_auth.h> 24 #include <pjnath/stun_ endpoint.h>24 #include <pjnath/stun_config.h> 25 25 #include <pjnath/stun_transaction.h> 26 26 #include <pj/list.h> -
pjproject/trunk/pjnath/include/pjnath/stun_transaction.h
r1080 r1091 26 26 27 27 #include <pjnath/stun_msg.h> 28 #include <pjnath/stun_ endpoint.h>28 #include <pjnath/stun_config.h> 29 29 30 30 -
pjproject/trunk/pjnath/src/pjnath/ice.c
r1090 r1091 212 212 213 213 214 static void resolver_cb(void *user_data, 215 pj_status_t status, 216 pj_dns_parsed_packet *response) 217 { 218 pj_assert(!"Not implemented yet!"); 219 PJ_UNUSED_ARG(user_data); 220 PJ_UNUSED_ARG(status); 221 PJ_UNUSED_ARG(response); 222 } 223 224 PJ_DEF(pj_status_t) pj_ice_set_srv(pj_ice *ice, 225 pj_bool_t enable_relay, 226 pj_dns_resolver *resolver, 227 const pj_str_t *domain) 228 { 229 char namebuf[128]; 230 char *tp_name; 231 pj_str_t name; 232 pj_status_t status; 233 234 235 /* Not implemented yet! */ 236 return PJ_ENOTSUP; 237 238 239 PJ_ASSERT_RETURN(ice && resolver && domain, PJ_EINVAL); 240 241 /* Must not have a running resolver. This is because we couldn't 242 * safely cancel the query (there is a race condition situation 243 * between the callback acquiring the mutex and this function 244 * acquiring the mutex) 245 */ 246 PJ_ASSERT_RETURN(ice->resv_q==NULL, PJ_EBUSY); 247 248 pj_mutex_lock(ice->mutex); 249 250 /* Reset resolver and server addresses */ 251 ice->relay_enabled = enable_relay; 252 ice->resv = resolver; 253 pj_bzero(&ice->stun_srv, sizeof(ice->stun_srv)); 254 255 /* Build SRV record name */ 256 if (ice->sock_type == PJ_SOCK_DGRAM) { 257 tp_name = "_udp"; 258 } else if (ice->sock_type == PJ_SOCK_STREAM) { 259 tp_name = "_tcp"; 260 } else { 261 pj_assert(!"Invalid sock_type"); 262 pj_mutex_unlock(ice->mutex); 263 return PJ_EBUG; 264 } 265 266 if (enable_relay) { 267 name.ptr = namebuf; 268 name.slen = pj_ansi_snprintf(namebuf, sizeof(namebuf), 269 "_stun-relay.%s.%.*s", 270 tp_name, 271 (int)domain->slen, 272 domain->ptr); 273 } else { 274 name.ptr = namebuf; 275 name.slen = pj_ansi_snprintf(namebuf, sizeof(namebuf), 276 "_stun.%s.%.*s", 277 tp_name, 278 (int)domain->slen, 279 domain->ptr); 280 } 281 282 if (name.slen < 1 || name.slen >= sizeof(namebuf)) { 283 pj_mutex_unlock(ice->mutex); 284 return PJ_ENAMETOOLONG; 285 } 286 287 /* Start DNS query */ 288 status = pj_dns_resolver_start_query(ice->resv, &name, 289 PJ_DNS_TYPE_SRV, 0, 290 &resolver_cb, 291 ice, &ice->resv_q); 292 if (status != PJ_SUCCESS) { 293 pj_mutex_unlock(ice->mutex); 294 return status; 295 } 296 297 pj_mutex_unlock(ice->mutex); 298 299 return PJ_SUCCESS; 300 } 301 302 303 PJ_DEF(pj_status_t) pj_ice_set_srv_addr(pj_ice *ice, 304 pj_bool_t enable_relay, 305 const pj_sockaddr_t *srv_addr, 306 unsigned addr_len) 307 { 308 PJ_ASSERT_RETURN(ice && srv_addr, PJ_EINVAL); 309 /* Must not have a running resolver. This is because we couldn't 310 * safely cancel the query (there is a race condition situation 311 * between the callback acquiring the mutex and this function 312 * acquiring the mutex) 313 */ 314 PJ_ASSERT_RETURN(ice->resv_q==NULL, PJ_EBUSY); 315 316 pj_mutex_lock(ice->mutex); 317 318 ice->relay_enabled = enable_relay; 319 pj_memcpy(&ice->stun_srv, srv_addr, addr_len); 320 321 pj_mutex_unlock(ice->mutex); 322 323 return PJ_SUCCESS; 324 325 } 326 327 328 329 PJ_DEF(pj_status_t) pj_ice_add_comp(pj_ice *ice, 330 unsigned comp_id, 331 const pj_sockaddr_t *local_addr, 332 unsigned addr_len) 333 { 334 pj_status_t status; 335 pj_sock_t sock; 336 337 PJ_ASSERT_RETURN(ice && local_addr && addr_len, PJ_EINVAL); 338 339 status = pj_sock_socket(ice->af, ice->sock_type, 0, &sock); 340 if (status != PJ_SUCCESS) 341 return status; 342 343 status = pj_sock_bind(sock, local_addr, addr_len); 344 if (status != PJ_SUCCESS) 345 return status; 346 347 status = pj_ice_add_sock_comp(ice, comp_id, sock); 348 if (status != PJ_SUCCESS) { 349 pj_sock_close(sock); 350 return status; 351 } 352 353 return PJ_SUCCESS; 354 } 355 356 typedef struct stun_data 357 { 358 pj_ice *ice; 359 unsigned comp_id; 360 pj_ice_comp *comp; 361 } stun_data; 362 363 364 PJ_DEF(pj_status_t) pj_ice_add_sock_comp( pj_ice *ice, 365 unsigned comp_id, 366 pj_sock_t sock) 367 { 368 pj_stun_session_cb sess_cb; 369 pj_ice_comp *comp; 370 pj_stun_auth_cred auth_cred; 371 stun_data *sd; 372 int addr_len; 373 pj_status_t status; 374 375 PJ_ASSERT_RETURN(ice && sock != PJ_INVALID_SOCKET, PJ_EINVAL); 376 PJ_ASSERT_RETURN(ice->comp_cnt < PJ_ARRAY_SIZE(ice->comp), PJ_ETOOMANY); 377 378 pj_mutex_lock(ice->mutex); 379 380 comp = &ice->comp[ice->comp_cnt]; 381 comp->comp_id = comp_id; 382 comp->sock = sock; 383 384 addr_len = sizeof(comp->local_addr); 385 status = pj_sock_getsockname(sock, &comp->local_addr, &addr_len); 386 if (status != PJ_SUCCESS) { 387 pj_mutex_unlock(ice->mutex); 388 return status; 389 } 390 391 392 /* Init STUN callbacks */ 393 pj_bzero(&sess_cb, sizeof(sess_cb)); 394 sess_cb.on_request_complete = &on_stun_request_complete; 395 sess_cb.on_rx_indication = &on_stun_rx_indication; 396 sess_cb.on_rx_request = &on_stun_rx_request; 397 sess_cb.on_send_msg = &on_stun_send_msg; 398 399 /* Create STUN session for this component */ 400 status = pj_stun_session_create(&ice->stun_cfg, ice->obj_name, 401 &sess_cb, PJ_FALSE, 402 &comp->stun_sess); 403 if (status != PJ_SUCCESS) { 404 pj_mutex_unlock(ice->mutex); 405 return status; 406 } 407 408 /* Associate data with this STUN session */ 409 sd = PJ_POOL_ZALLOC_T(ice->pool, struct stun_data); 410 sd->ice = ice; 411 sd->comp_id = comp_id; 412 sd->comp = comp; 413 pj_stun_session_set_user_data(comp->stun_sess, sd); 414 415 /* Init STUN authentication credential */ 416 pj_bzero(&auth_cred, sizeof(auth_cred)); 417 auth_cred.type = PJ_STUN_AUTH_CRED_DYNAMIC; 418 auth_cred.data.dyn_cred.get_auth = &stun_auth_get_auth; 419 auth_cred.data.dyn_cred.get_cred = &stun_auth_get_cred; 420 auth_cred.data.dyn_cred.get_password = &stun_auth_get_password; 421 auth_cred.data.dyn_cred.verify_nonce = &stun_auth_verify_nonce; 422 auth_cred.data.dyn_cred.user_data = comp->stun_sess; 423 pj_stun_session_set_credential(comp->stun_sess, &auth_cred); 424 425 /* Done */ 426 ice->comp_cnt++; 427 pj_mutex_unlock(ice->mutex); 428 429 return PJ_SUCCESS; 430 } 431 432 433 static pj_status_t stun_auth_get_auth(void *user_data, 434 pj_pool_t *pool, 435 pj_str_t *realm, 436 pj_str_t *nonce) 437 { 438 PJ_UNUSED_ARG(user_data); 439 PJ_UNUSED_ARG(pool); 440 441 realm->slen = 0; 442 nonce->slen = 0; 443 444 return PJ_SUCCESS; 445 } 446 447 448 /* Get credential to be sent with outgoing message */ 449 static pj_status_t stun_auth_get_cred(const pj_stun_msg *msg, 450 void *user_data, 451 pj_pool_t *pool, 452 pj_str_t *realm, 453 pj_str_t *username, 454 pj_str_t *nonce, 455 int *data_type, 456 pj_str_t *data) 457 { 458 pj_stun_session *sess = (pj_stun_session *)user_data; 459 stun_data *sd = (stun_data*) pj_stun_session_get_user_data(sess); 460 pj_ice *ice = sd->ice; 461 462 PJ_UNUSED_ARG(pool); 463 realm->slen = nonce->slen = 0; 464 465 if (PJ_STUN_IS_RESPONSE(msg->hdr.type) || 466 PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type)) 467 { 468 /* Outgoing responses need to have the same credential as 469 * incoming requests. 470 */ 471 *username = ice->rx_uname; 472 *data_type = 0; 473 *data = ice->rx_pass; 474 } 475 else { 476 *username = ice->tx_uname; 477 *data_type = 0; 478 *data = ice->tx_pass; 479 } 480 481 return PJ_SUCCESS; 482 } 483 484 /* Get password to be used to authenticate incoming message */ 485 static pj_status_t stun_auth_get_password(const pj_stun_msg *msg, 486 void *user_data, 487 const pj_str_t *realm, 488 const pj_str_t *username, 489 pj_pool_t *pool, 490 int *data_type, 491 pj_str_t *data) 492 { 493 pj_stun_session *sess = (pj_stun_session *)user_data; 494 stun_data *sd = (stun_data*) pj_stun_session_get_user_data(sess); 495 pj_ice *ice = sd->ice; 496 497 PJ_UNUSED_ARG(realm); 498 PJ_UNUSED_ARG(pool); 499 500 if (PJ_STUN_IS_RESPONSE(msg->hdr.type) || 501 PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type)) 502 { 503 /* Incoming response is authenticated with TX credential */ 504 /* Verify username */ 505 if (pj_strcmp(username, &ice->tx_uname) != 0) 506 return -1; 507 *data_type = 0; 508 *data = ice->tx_pass; 509 510 } else { 511 /* Incoming request is authenticated with RX credential */ 512 /* The agent MUST accept a credential if the username consists 513 * of two values separated by a colon, where the first value is 514 * equal to the username fragment generated by the agent in an offer 515 * or answer for a session in-progress, and the MESSAGE-INTEGRITY 516 * is the output of a hash of the password and the STUN packet's 517 * contents. 518 */ 519 PJ_TODO(CHECK_USERNAME_FOR_INCOMING_STUN_REQUEST); 520 *data_type = 0; 521 *data = ice->rx_pass; 522 523 } 524 525 return PJ_SUCCESS; 526 } 527 528 529 static pj_bool_t stun_auth_verify_nonce(const pj_stun_msg *msg, 530 void *user_data, 531 const pj_str_t *realm, 532 const pj_str_t *username, 533 const pj_str_t *nonce) 534 { 535 /* We don't use NONCE */ 536 PJ_UNUSED_ARG(msg); 537 PJ_UNUSED_ARG(user_data); 538 PJ_UNUSED_ARG(realm); 539 PJ_UNUSED_ARG(username); 540 PJ_UNUSED_ARG(nonce); 541 return PJ_TRUE; 542 } 543 544 545 PJ_DEF(pj_status_t) pj_ice_set_credentials(pj_ice *ice, 546 const pj_str_t *local_ufrag, 547 const pj_str_t *local_pass, 548 const pj_str_t *remote_ufrag, 549 const pj_str_t *remote_pass) 550 { 551 char buf[128]; 552 pj_str_t username; 553 554 username.ptr = buf; 555 556 PJ_ASSERT_RETURN(ice && local_ufrag && local_pass && 557 remote_ufrag && remote_pass, PJ_EINVAL); 558 PJ_ASSERT_RETURN(local_ufrag->slen + remote_ufrag->slen < 559 sizeof(buf), PJ_ENAMETOOLONG); 560 561 pj_strcpy(&username, remote_ufrag); 562 pj_strcat2(&username, ":"); 563 pj_strcat(&username, local_ufrag); 564 565 pj_strdup(ice->pool, &ice->tx_uname, &username); 566 pj_strdup(ice->pool, &ice->tx_pass, remote_pass); 567 568 pj_strcpy(&username, local_ufrag); 569 pj_strcat2(&username, ":"); 570 pj_strcat(&username, remote_ufrag); 571 572 pj_strdup(ice->pool, &ice->rx_uname, &username); 573 pj_strdup(ice->pool, &ice->rx_pass, local_pass); 574 575 return PJ_SUCCESS; 576 } 577 578 579 static pj_status_t gather_host_cands(pj_ice *ice) 580 { 581 unsigned i; 582 pj_status_t status; 583 584 for (i=0; i<ice->comp_cnt; ++i) { 585 pj_ice_comp *comp = &ice->comp[i]; 586 pj_sockaddr addr; 587 int addr_len; 588 589 addr_len = sizeof(addr); 590 status = pj_sock_getsockname(comp->sock, &addr, &addr_len); 591 if (status != PJ_SUCCESS) 592 return status; 593 594 if (addr.ipv4.sin_addr.s_addr == 0) { 595 status = pj_gethostip(&addr.ipv4.sin_addr); 596 if (status != PJ_SUCCESS) 597 return status; 598 } 599 600 status = pj_ice_add_cand(ice, i, PJ_ICE_CAND_TYPE_HOST, 65535, 601 &host_foundation, &addr, &addr, NULL, 602 sizeof(pj_sockaddr_in), NULL); 603 if (status != PJ_SUCCESS) 604 return status; 605 } 606 607 return PJ_SUCCESS; 608 } 609 610 /* Eliminate redundant candidates. */ 611 static void eliminate_redundant_cand(unsigned *cnt, 612 pj_ice_cand cand[]) 613 { 614 615 /* A candidate is redundant if its transport address equals another 616 * candidate, and its base equals the base of that other candidate. 617 * Note that two candidates can have the same transport address yet 618 * have different bases, and these would not be considered redundant. 619 */ 620 PJ_TODO(ELIMINATE_REDUNDANT_CANDIDATES); 621 PJ_UNUSED_ARG(cnt); 622 PJ_UNUSED_ARG(cand); 623 } 624 625 626 PJ_DEF(pj_status_t) pj_ice_start_gather(pj_ice *ice, 627 unsigned flags) 628 { 629 pj_status_t status; 630 631 PJ_UNUSED_ARG(flags); 632 633 /* Gather host candidate */ 634 status = gather_host_cands(ice); 635 if (status != PJ_SUCCESS) 636 return status; 637 638 /* Eliminate redundant host candidates. */ 639 eliminate_redundant_cand(&ice->lcand_cnt, ice->lcand); 640 641 PJ_TODO(GATHER_MAPPED_AND_RELAYED_CANDIDATES); 642 643 return PJ_SUCCESS; 644 } 645 646 647 static pj_uint32_t CALC_CAND_PRIO(pj_ice_cand_type type, 648 pj_uint32_t local_pref, 649 pj_uint32_t comp_id) 650 { 651 static pj_uint32_t type_pref[] = 652 { 653 PJ_ICE_HOST_PREF, 654 PJ_ICE_MAPPED_PREF, 655 PJ_ICE_PEER_MAPPED_PREF, 656 PJ_ICE_RELAYED_PREF 657 }; 658 659 return ((1 << 24) * type_pref[type]) + 660 ((1 << 8) * local_pref) + 661 (256 - comp_id); 662 } 663 664 665 PJ_DEF(pj_status_t) pj_ice_add_cand(pj_ice *ice, 666 unsigned comp_id, 667 pj_ice_cand_type type, 668 pj_uint16_t local_pref, 669 const pj_str_t *foundation, 670 const pj_sockaddr_t *addr, 671 const pj_sockaddr_t *base_addr, 672 const pj_sockaddr_t *srv_addr, 673 int addr_len, 674 unsigned *p_cand_id) 675 { 676 pj_ice_cand *lcand; 677 pj_status_t status = PJ_SUCCESS; 678 char tmp[128]; 679 680 PJ_ASSERT_RETURN(ice && comp_id && type && local_pref && 681 foundation && addr && base_addr && addr_len, 682 PJ_EINVAL); 683 684 pj_mutex_lock(ice->mutex); 685 686 if (ice->lcand_cnt >= PJ_ARRAY_SIZE(ice->lcand)) { 687 status = PJ_ETOOMANY; 688 goto on_error; 689 } 690 691 lcand = &ice->lcand[ice->lcand_cnt]; 692 lcand->comp_id = comp_id; 693 lcand->type = type; 694 pj_strdup(ice->pool, &lcand->foundation, foundation); 695 lcand->prio = CALC_CAND_PRIO(type, local_pref, lcand->comp_id); 696 pj_memcpy(&lcand->addr, addr, addr_len); 697 pj_memcpy(&lcand->base_addr, base_addr, addr_len); 698 if (srv_addr) 699 pj_memcpy(&lcand->srv_addr, srv_addr, addr_len); 700 else 701 pj_bzero(&lcand->srv_addr, sizeof(lcand->srv_addr)); 702 703 if (p_cand_id) 704 *p_cand_id = ice->lcand_cnt; 705 706 pj_ansi_strcpy(tmp, pj_inet_ntoa(lcand->addr.ipv4.sin_addr)); 707 LOG((ice->obj_name, 708 "Candidate %d added: comp_id=%d, type=%s, foundation=%.*s, " 709 "addr=%s:%d, base=%s:%d, prio=0x%x (%u)", 710 ice->lcand_cnt, 711 lcand->comp_id, 712 cand_type_names[lcand->type], 713 (int)lcand->foundation.slen, 714 lcand->foundation.ptr, 715 tmp, 716 (int)pj_ntohs(lcand->addr.ipv4.sin_port), 717 pj_inet_ntoa(lcand->base_addr.ipv4.sin_addr), 718 (int)pj_htons(lcand->base_addr.ipv4.sin_port), 719 lcand->prio, lcand->prio)); 720 721 ++ice->lcand_cnt; 722 723 on_error: 724 pj_mutex_unlock(ice->mutex); 725 return status; 726 } 727 728 729 PJ_DEF(unsigned) pj_ice_get_cand_cnt(pj_ice *ice) 730 { 731 return ice->lcand_cnt; 732 } 733 734 735 PJ_DEF(pj_status_t) pj_ice_enum_cands(pj_ice *ice, 736 unsigned *p_count, 737 unsigned cand_ids[]) 738 { 739 unsigned i, count; 740 741 PJ_ASSERT_RETURN(ice && p_count && *p_count && cand_ids, PJ_EINVAL); 742 743 pj_mutex_lock(ice->mutex); 744 745 count = (*p_count < ice->lcand_cnt) ? *p_count : ice->lcand_cnt; 746 for (i=0; i<count; ++i) 747 cand_ids[i] = i; 748 749 *p_count = count; 750 pj_mutex_unlock(ice->mutex); 751 752 return PJ_SUCCESS; 753 } 754 755 756 PJ_DEF(pj_status_t) pj_ice_get_default_cand(pj_ice *ice, 757 unsigned comp_id, 758 int *cand_id) 759 { 760 PJ_ASSERT_RETURN(ice && comp_id && cand_id, PJ_EINVAL); 761 762 pj_mutex_lock(ice->mutex); 763 764 /* First find in valid list if we have nominated pair */ 765 766 /* If there's no nominated pair, find relayed candidate */ 767 768 /* If there's no relayed candidate, find server reflexive candidate */ 769 770 /* Otherwise return host candidate */ 771 772 pj_assert(!"Not implemented yet"); 773 PJ_TODO(IMPLEMENT_GET_DEFAULT_CAND); 774 775 pj_mutex_unlock(ice->mutex); 776 777 return PJ_SUCCESS; 778 } 779 780 781 PJ_DEF(pj_status_t) pj_ice_get_cand(pj_ice *ice, 782 unsigned cand_id, 783 pj_ice_cand **p_cand) 784 { 785 PJ_ASSERT_RETURN(ice && p_cand, PJ_EINVAL); 786 PJ_ASSERT_RETURN(cand_id <= ice->lcand_cnt, PJ_EINVAL); 787 788 *p_cand = &ice->lcand[cand_id]; 789 790 return PJ_SUCCESS; 791 } 792 793 #ifndef MIN 794 # define MIN(a,b) (a < b ? a : b) 795 #endif 796 797 #ifndef MAX 798 # define MAX(a,b) (a > b ? a : b) 799 #endif 800 801 static pj_uint64_t CALC_CHECK_PRIO(const pj_ice *ice, 802 const pj_ice_cand *lcand, 803 const pj_ice_cand *rcand) 804 { 805 pj_uint32_t O, A; 806 807 if (ice->role == PJ_ICE_ROLE_CONTROLLING) { 808 O = lcand->prio; 809 A = rcand->prio; 810 } else { 811 O = rcand->prio; 812 A = lcand->prio; 813 } 814 815 return ((pj_uint64_t)1 << 32) * MIN(O, A) + 816 (pj_uint64_t)2 * MAX(O, A) + (O>A ? 1 : 0); 817 } 818 819 static const char *dump_check(char *buffer, unsigned bufsize, 820 const pj_ice_check *check) 821 { 822 const pj_ice_cand *lcand = check->lcand; 823 const pj_ice_cand *rcand = check->rcand; 824 char laddr[CHECK_NAME_LEN]; 825 int len; 826 827 pj_ansi_strcpy(laddr, pj_inet_ntoa(lcand->addr.ipv4.sin_addr)); 828 829 if (lcand->addr.addr.sa_family == PJ_AF_INET) { 830 len = pj_ansi_snprintf(buffer, bufsize, 831 "%s:%d-->%s:%d", 832 laddr, (int)pj_ntohs(lcand->addr.ipv4.sin_port), 833 pj_inet_ntoa(rcand->addr.ipv4.sin_addr), 834 (int)pj_ntohs(rcand->addr.ipv4.sin_port)); 835 } else { 836 len = pj_ansi_snprintf(buffer, bufsize, "IPv6->IPv6"); 837 } 838 839 840 if (len < 0) 841 len = 0; 842 else if (len >= (int)bufsize) 843 len = bufsize - 1; 844 845 buffer[len] = '\0'; 846 return buffer; 847 } 848 849 #if PJ_LOG_MAX_LEVEL >= 4 850 static void dump_checklist(const char *title, const pj_ice *ice, 851 const pj_ice_checklist *clist) 852 { 853 unsigned i; 854 char buffer[CHECK_NAME_LEN]; 855 856 LOG((ice->obj_name, "%s", title)); 857 for (i=0; i<clist->count; ++i) { 858 const pj_ice_check *c = &clist->checks[i]; 859 LOG((ice->obj_name, " %d: %s (prio=%u, state=%s)", 860 i, dump_check(buffer, sizeof(buffer), c), 861 c->prio, check_state_name[c->state])); 862 } 863 } 864 #else 865 #define dump_checklist(ice, clist) 866 #endif 867 868 static void check_set_state(pj_ice *ice, pj_ice_check *check, 869 pj_ice_check_state st, 870 pj_status_t err_code) 871 { 872 char buf[CHECK_NAME_LEN]; 873 LOG((ice->obj_name, "Check %s: state changed from %s to %s", 874 dump_check(buf, sizeof(buf), check), 875 check_state_name[check->state], 876 check_state_name[st])); 877 check->state = st; 878 check->err_code = err_code; 879 } 880 881 static void clist_set_state(pj_ice *ice, pj_ice_checklist *clist, 882 pj_ice_checklist_state st) 883 { 884 LOG((ice->obj_name, "Checklist: state changed from %s to %s", 885 clist_state_name[clist->state], 886 clist_state_name[st])); 887 clist->state = st; 888 } 889 890 /* Sort checklist based on priority */ 891 static void sort_checklist(pj_ice_checklist *clist) 892 { 893 unsigned i; 894 895 for (i=0; i<clist->count-1; ++i) { 896 unsigned j, highest = i; 897 for (j=i+1; j<clist->count; ++j) { 898 if (clist->checks[j].prio > clist->checks[highest].prio) { 899 highest = j; 900 } 901 } 902 903 if (highest != i) { 904 pj_ice_check tmp; 905 906 pj_memcpy(&tmp, &clist->checks[i], sizeof(pj_ice_check)); 907 pj_memcpy(&clist->checks[i], &clist->checks[highest], 908 sizeof(pj_ice_check)); 909 pj_memcpy(&clist->checks[highest], &tmp, sizeof(pj_ice_check)); 910 } 911 } 912 } 913 914 /* Sort valid list based on priority */ 915 static void sort_valid_list(pj_ice *ice) 916 { 917 unsigned i; 918 919 for (i=0; i<ice->valid_cnt-1; ++i) { 920 unsigned j, highest = i; 921 pj_ice_check *ci = &ice->clist.checks[ice->valid_list[i]]; 922 923 for (j=i+1; j<ice->valid_cnt; ++j) { 924 pj_ice_check *cj = &ice->clist.checks[ice->valid_list[j]]; 925 926 if (cj->prio > ci->prio) { 927 highest = j; 928 } 929 } 930 931 if (highest != i) { 932 unsigned tmp = ice->valid_list[i]; 933 ice->valid_list[i] = ice->valid_list[j]; 934 ice->valid_list[j] = tmp; 935 } 936 } 937 } 938 939 940 enum 941 { 942 SOCKADDR_EQUAL = 0, 943 SOCKADDR_NOT_EQUAL = 1 944 }; 945 946 /* Utility: compare sockaddr. 947 * Returns 0 if equal. 948 */ 949 static int sockaddr_cmp(const pj_sockaddr *a1, const pj_sockaddr *a2) 950 { 951 if (a1->addr.sa_family != a2->addr.sa_family) 952 return SOCKADDR_NOT_EQUAL; 953 954 if (a1->addr.sa_family == PJ_AF_INET) { 955 return !(a1->ipv4.sin_addr.s_addr == a2->ipv4.sin_addr.s_addr && 956 a1->ipv4.sin_port == a2->ipv4.sin_port); 957 } else if (a1->addr.sa_family == PJ_AF_INET6) { 958 return pj_memcmp(&a1->ipv6, &a2->ipv6, sizeof(a1->ipv6)); 959 } else { 960 pj_assert(!"Invalid address family!"); 961 return SOCKADDR_NOT_EQUAL; 962 } 963 } 964 965 966 /* Prune checklist, this must have been done after the checklist 967 * is sorted. 968 */ 969 static void prune_checklist(pj_ice *ice, pj_ice_checklist *clist) 970 { 971 unsigned i; 972 973 /* Since an agent cannot send requests directly from a reflexive 974 * candidate, but only from its base, the agent next goes through the 975 * sorted list of candidate pairs. For each pair where the local 976 * candidate is server reflexive, the server reflexive candidate MUST be 977 * replaced by its base. Once this has been done, the agent MUST prune 978 * the list. This is done by removing a pair if its local and remote 979 * candidates are identical to the local and remote candidates of a pair 980 * higher up on the priority list. The result is a sequence of ordered 981 * candidate pairs, called the check list for that media stream. 982 */ 983 for (i=0; i<clist->count; ++i) { 984 pj_ice_cand *licand = clist->checks[i].lcand; 985 pj_ice_cand *ricand = clist->checks[i].rcand; 986 const pj_sockaddr *liaddr; 987 unsigned j; 988 989 if (licand->type == PJ_ICE_CAND_TYPE_MAPPED) 990 liaddr = &licand->base_addr; 991 else 992 liaddr = &licand->addr; 993 994 for (j=i+1; j<clist->count;) { 995 pj_ice_cand *ljcand = clist->checks[j].lcand; 996 pj_ice_cand *rjcand = clist->checks[j].rcand; 997 const pj_sockaddr *ljaddr; 998 999 if (ljcand->type == PJ_ICE_CAND_TYPE_MAPPED) 1000 ljaddr = &licand->base_addr; 1001 else 1002 ljaddr = &licand->addr; 1003 1004 if (sockaddr_cmp(liaddr, ljaddr) == SOCKADDR_EQUAL && 1005 sockaddr_cmp(&ricand->addr, &rjcand->addr) == SOCKADDR_EQUAL) 1006 { 1007 /* Found duplicate, remove it */ 1008 char buf[CHECK_NAME_LEN]; 1009 1010 LOG((ice->obj_name, "Check %s pruned", 1011 dump_check(buf, sizeof(buf), &clist->checks[j]))); 1012 1013 pj_array_erase(clist->checks, sizeof(clist->checks[0]), 1014 clist->count, j); 1015 --clist->count; 1016 1017 } else { 1018 ++j; 1019 } 1020 } 1021 } 1022 } 1023 214 1024 /* This function is called when ICE processing completes */ 215 1025 static void on_ice_complete(pj_ice *ice, pj_status_t status) … … 235 1045 if (check->nominated) { 236 1046 for (i=0; i<ice->clist.count; ++i) { 237 pj_ice_check *c ;1047 pj_ice_check *c = &ice->clist.checks[i]; 238 1048 if (c->lcand->comp_id == check->lcand->comp_id && 239 1049 (c->state==PJ_ICE_CHECK_STATE_FROZEN || 240 c->state==PJ_ICE_CHECK_STATE_WAITING) 1050 c->state==PJ_ICE_CHECK_STATE_WAITING)) 241 1051 { 242 1052 check_set_state(ice, check, PJ_ICE_CHECK_STATE_FAILED, … … 281 1091 */ 282 1092 for (i=0; i<ice->valid_cnt; ++i) { 283 pj_ice_check *c = ice->clist.checks[ice->valid_list[i]];1093 pj_ice_check *c = &ice->clist.checks[ice->valid_list[i]]; 284 1094 if (c->lcand->comp_id == 1) 285 1095 break; … … 314 1124 315 1125 316 static void resolver_cb(void *user_data, 317 pj_status_t status, 318 pj_dns_parsed_packet *response) 319 { 320 pj_assert(!"Not implemented yet!"); 321 PJ_UNUSED_ARG(user_data); 322 PJ_UNUSED_ARG(status); 323 PJ_UNUSED_ARG(response); 324 } 325 326 PJ_DEF(pj_status_t) pj_ice_set_srv(pj_ice *ice, 327 pj_bool_t enable_relay, 328 pj_dns_resolver *resolver, 329 const pj_str_t *domain) 330 { 331 char namebuf[128]; 332 char *tp_name; 333 pj_str_t name; 334 pj_status_t status; 335 336 337 /* Not implemented yet! */ 338 return PJ_ENOTSUP; 339 340 341 PJ_ASSERT_RETURN(ice && resolver && domain, PJ_EINVAL); 342 343 /* Must not have a running resolver. This is because we couldn't 344 * safely cancel the query (there is a race condition situation 345 * between the callback acquiring the mutex and this function 346 * acquiring the mutex) 347 */ 348 PJ_ASSERT_RETURN(ice->resv_q==NULL, PJ_EBUSY); 349 350 pj_mutex_lock(ice->mutex); 351 352 /* Reset resolver and server addresses */ 353 ice->relay_enabled = enable_relay; 354 ice->resv = resolver; 355 pj_bzero(&ice->stun_srv, sizeof(ice->stun_srv)); 356 357 /* Build SRV record name */ 358 if (ice->sock_type == PJ_SOCK_DGRAM) { 359 tp_name = "_udp"; 360 } else if (ice->sock_type == PJ_SOCK_STREAM) { 361 tp_name = "_tcp"; 362 } else { 363 pj_assert(!"Invalid sock_type"); 364 pj_mutex_unlock(ice->mutex); 365 return PJ_EBUG; 366 } 367 368 if (enable_relay) { 369 name.ptr = namebuf; 370 name.slen = pj_ansi_snprintf(namebuf, sizeof(namebuf), 371 "_stun-relay.%s.%.*s", 372 tp_name, 373 (int)domain->slen, 374 domain->ptr); 375 } else { 376 name.ptr = namebuf; 377 name.slen = pj_ansi_snprintf(namebuf, sizeof(namebuf), 378 "_stun.%s.%.*s", 379 tp_name, 380 (int)domain->slen, 381 domain->ptr); 382 } 383 384 if (name.slen < 1 || name.slen >= sizeof(namebuf)) { 385 pj_mutex_unlock(ice->mutex); 386 return PJ_ENAMETOOLONG; 387 } 388 389 /* Start DNS query */ 390 status = pj_dns_resolver_start_query(ice->resv, &name, 391 PJ_DNS_TYPE_SRV, 0, 392 &resolver_cb, 393 ice, &ice->resv_q); 394 if (status != PJ_SUCCESS) { 395 pj_mutex_unlock(ice->mutex); 396 return status; 397 } 398 399 pj_mutex_unlock(ice->mutex); 400 401 return PJ_SUCCESS; 402 } 403 404 405 PJ_DEF(pj_status_t) pj_ice_set_srv_addr(pj_ice *ice, 406 pj_bool_t enable_relay, 407 const pj_sockaddr_t *srv_addr, 408 unsigned addr_len) 409 { 410 PJ_ASSERT_RETURN(ice && srv_addr, PJ_EINVAL); 411 /* Must not have a running resolver. This is because we couldn't 412 * safely cancel the query (there is a race condition situation 413 * between the callback acquiring the mutex and this function 414 * acquiring the mutex) 415 */ 416 PJ_ASSERT_RETURN(ice->resv_q==NULL, PJ_EBUSY); 417 418 pj_mutex_lock(ice->mutex); 419 420 ice->relay_enabled = enable_relay; 421 pj_memcpy(&ice->stun_srv, srv_addr, addr_len); 422 423 pj_mutex_unlock(ice->mutex); 424 425 return PJ_SUCCESS; 426 427 } 428 429 430 431 PJ_DEF(pj_status_t) pj_ice_add_comp(pj_ice *ice, 432 unsigned comp_id, 433 const pj_sockaddr_t *local_addr, 434 unsigned addr_len) 435 { 436 pj_status_t status; 437 pj_sock_t sock; 438 439 PJ_ASSERT_RETURN(ice && local_addr && addr_len, PJ_EINVAL); 440 441 status = pj_sock_socket(ice->af, ice->sock_type, 0, &sock); 442 if (status != PJ_SUCCESS) 443 return status; 444 445 status = pj_sock_bind(sock, local_addr, addr_len); 446 if (status != PJ_SUCCESS) 447 return status; 448 449 status = pj_ice_add_sock_comp(ice, comp_id, sock); 450 if (status != PJ_SUCCESS) { 451 pj_sock_close(sock); 452 return status; 453 } 454 455 return PJ_SUCCESS; 456 } 457 458 typedef struct stun_data 459 { 460 pj_ice *ice; 461 unsigned comp_id; 462 pj_ice_comp *comp; 463 } stun_data; 464 465 466 PJ_DEF(pj_status_t) pj_ice_add_sock_comp( pj_ice *ice, 467 unsigned comp_id, 468 pj_sock_t sock) 469 { 470 pj_stun_session_cb sess_cb; 471 pj_ice_comp *comp; 472 pj_stun_auth_cred auth_cred; 473 stun_data *sd; 474 int addr_len; 475 pj_status_t status; 476 477 PJ_ASSERT_RETURN(ice && sock != PJ_INVALID_SOCKET, PJ_EINVAL); 478 PJ_ASSERT_RETURN(ice->comp_cnt < PJ_ARRAY_SIZE(ice->comp), PJ_ETOOMANY); 479 480 pj_mutex_lock(ice->mutex); 481 482 comp = &ice->comp[ice->comp_cnt]; 483 comp->comp_id = comp_id; 484 comp->sock = sock; 485 486 addr_len = sizeof(comp->local_addr); 487 status = pj_sock_getsockname(sock, &comp->local_addr, &addr_len); 488 if (status != PJ_SUCCESS) { 489 pj_mutex_unlock(ice->mutex); 490 return status; 491 } 492 493 494 /* Init STUN callbacks */ 495 pj_bzero(&sess_cb, sizeof(sess_cb)); 496 sess_cb.on_request_complete = &on_stun_request_complete; 497 sess_cb.on_rx_indication = &on_stun_rx_indication; 498 sess_cb.on_rx_request = &on_stun_rx_request; 499 sess_cb.on_send_msg = &on_stun_send_msg; 500 501 /* Create STUN session for this component */ 502 status = pj_stun_session_create(&ice->stun_cfg, ice->obj_name, 503 &sess_cb, PJ_FALSE, 504 &comp->stun_sess); 505 if (status != PJ_SUCCESS) { 506 pj_mutex_unlock(ice->mutex); 507 return status; 508 } 509 510 /* Associate data with this STUN session */ 511 sd = PJ_POOL_ZALLOC_T(ice->pool, struct stun_data); 512 sd->ice = ice; 513 sd->comp_id = comp_id; 514 sd->comp = comp; 515 pj_stun_session_set_user_data(comp->stun_sess, sd); 516 517 /* Init STUN authentication credential */ 518 pj_bzero(&auth_cred, sizeof(auth_cred)); 519 auth_cred.type = PJ_STUN_AUTH_CRED_DYNAMIC; 520 auth_cred.data.dyn_cred.get_auth = &stun_auth_get_auth; 521 auth_cred.data.dyn_cred.get_cred = &stun_auth_get_cred; 522 auth_cred.data.dyn_cred.get_password = &stun_auth_get_password; 523 auth_cred.data.dyn_cred.verify_nonce = &stun_auth_verify_nonce; 524 auth_cred.data.dyn_cred.user_data = comp->stun_sess; 525 pj_stun_session_set_credential(comp->stun_sess, &auth_cred); 526 527 /* Done */ 528 ice->comp_cnt++; 529 pj_mutex_unlock(ice->mutex); 530 531 return PJ_SUCCESS; 532 } 533 534 535 static pj_status_t stun_auth_get_auth(void *user_data, 536 pj_pool_t *pool, 537 pj_str_t *realm, 538 pj_str_t *nonce) 539 { 540 PJ_UNUSED_ARG(user_data); 541 PJ_UNUSED_ARG(pool); 542 543 realm->slen = 0; 544 nonce->slen = 0; 545 546 return PJ_SUCCESS; 547 } 548 549 550 /* Get credential to be sent with outgoing message */ 551 static pj_status_t stun_auth_get_cred(const pj_stun_msg *msg, 552 void *user_data, 553 pj_pool_t *pool, 554 pj_str_t *realm, 555 pj_str_t *username, 556 pj_str_t *nonce, 557 int *data_type, 558 pj_str_t *data) 559 { 560 pj_stun_session *sess = (pj_stun_session *)user_data; 561 stun_data *sd = (stun_data*) pj_stun_session_get_user_data(sess); 562 pj_ice *ice = sd->ice; 563 564 PJ_UNUSED_ARG(pool); 565 realm->slen = nonce->slen = 0; 566 567 if (PJ_STUN_IS_RESPONSE(msg->hdr.type) || 568 PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type)) 569 { 570 /* Outgoing responses need to have the same credential as 571 * incoming requests. 572 */ 573 *username = ice->rx_uname; 574 *data_type = 0; 575 *data = ice->rx_pass; 576 } 577 else { 578 *username = ice->tx_uname; 579 *data_type = 0; 580 *data = ice->tx_pass; 581 } 582 583 return PJ_SUCCESS; 584 } 585 586 /* Get password to be used to authenticate incoming message */ 587 static pj_status_t stun_auth_get_password(const pj_stun_msg *msg, 588 void *user_data, 589 const pj_str_t *realm, 590 const pj_str_t *username, 591 pj_pool_t *pool, 592 int *data_type, 593 pj_str_t *data) 594 { 595 pj_stun_session *sess = (pj_stun_session *)user_data; 596 stun_data *sd = (stun_data*) pj_stun_session_get_user_data(sess); 597 pj_ice *ice = sd->ice; 598 599 PJ_UNUSED_ARG(realm); 600 PJ_UNUSED_ARG(pool); 601 602 if (PJ_STUN_IS_RESPONSE(msg->hdr.type) || 603 PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type)) 604 { 605 /* Incoming response is authenticated with TX credential */ 606 /* Verify username */ 607 if (pj_strcmp(username, &ice->tx_uname) != 0) 608 return -1; 609 *data_type = 0; 610 *data = ice->tx_pass; 611 612 } else { 613 /* Incoming request is authenticated with RX credential */ 614 /* The agent MUST accept a credential if the username consists 615 * of two values separated by a colon, where the first value is 616 * equal to the username fragment generated by the agent in an offer 617 * or answer for a session in-progress, and the MESSAGE-INTEGRITY 618 * is the output of a hash of the password and the STUN packet's 619 * contents. 620 */ 621 PJ_TODO(CHECK_USERNAME_FOR_INCOMING_STUN_REQUEST); 622 *data_type = 0; 623 *data = ice->rx_pass; 624 625 } 626 627 return PJ_SUCCESS; 628 } 629 630 631 static pj_bool_t stun_auth_verify_nonce(const pj_stun_msg *msg, 632 void *user_data, 633 const pj_str_t *realm, 634 const pj_str_t *username, 635 const pj_str_t *nonce) 636 { 637 /* We don't use NONCE */ 638 PJ_UNUSED_ARG(msg); 639 PJ_UNUSED_ARG(user_data); 640 PJ_UNUSED_ARG(realm); 641 PJ_UNUSED_ARG(username); 642 PJ_UNUSED_ARG(nonce); 643 return PJ_TRUE; 644 } 645 646 647 PJ_DEF(pj_status_t) pj_ice_set_credentials(pj_ice *ice, 648 const pj_str_t *local_ufrag, 649 const pj_str_t *local_pass, 650 const pj_str_t *remote_ufrag, 651 const pj_str_t *remote_pass) 652 { 653 char buf[128]; 654 pj_str_t username; 655 656 username.ptr = buf; 657 658 PJ_ASSERT_RETURN(ice && local_ufrag && local_pass && 659 remote_ufrag && remote_pass, PJ_EINVAL); 660 PJ_ASSERT_RETURN(local_ufrag->slen + remote_ufrag->slen < 661 sizeof(buf), PJ_ENAMETOOLONG); 662 663 pj_strcpy(&username, remote_ufrag); 664 pj_strcat2(&username, ":"); 665 pj_strcat(&username, local_ufrag); 666 667 pj_strdup(ice->pool, &ice->tx_uname, &username); 668 pj_strdup(ice->pool, &ice->tx_pass, remote_pass); 669 670 pj_strcpy(&username, local_ufrag); 671 pj_strcat2(&username, ":"); 672 pj_strcat(&username, remote_ufrag); 673 674 pj_strdup(ice->pool, &ice->rx_uname, &username); 675 pj_strdup(ice->pool, &ice->rx_pass, local_pass); 676 677 return PJ_SUCCESS; 678 } 679 680 681 static pj_status_t gather_host_cands(pj_ice *ice) 682 { 683 unsigned i; 684 pj_status_t status; 685 686 for (i=0; i<ice->comp_cnt; ++i) { 687 pj_ice_comp *comp = &ice->comp[i]; 688 pj_sockaddr addr; 689 int addr_len; 690 691 addr_len = sizeof(addr); 692 status = pj_sock_getsockname(comp->sock, &addr, &addr_len); 693 if (status != PJ_SUCCESS) 694 return status; 695 696 if (addr.ipv4.sin_addr.s_addr == 0) { 697 status = pj_gethostip(&addr.ipv4.sin_addr); 698 if (status != PJ_SUCCESS) 699 return status; 700 } 701 702 status = pj_ice_add_cand(ice, i, PJ_ICE_CAND_TYPE_HOST, 65535, 703 &host_foundation, &addr, &addr, NULL, 704 sizeof(pj_sockaddr_in), NULL); 705 if (status != PJ_SUCCESS) 706 return status; 707 } 708 709 return PJ_SUCCESS; 710 } 711 712 /* Eliminate redundant candidates. */ 713 static void eliminate_redundant_cand(unsigned *cnt, 714 pj_ice_cand cand[]) 715 { 716 717 /* A candidate is redundant if its transport address equals another 718 * candidate, and its base equals the base of that other candidate. 719 * Note that two candidates can have the same transport address yet 720 * have different bases, and these would not be considered redundant. 721 */ 722 PJ_TODO(ELIMINATE_REDUNDANT_CANDIDATES); 723 PJ_UNUSED_ARG(cnt); 724 PJ_UNUSED_ARG(cand); 725 } 726 727 728 PJ_DEF(pj_status_t) pj_ice_start_gather(pj_ice *ice, 729 unsigned flags) 730 { 731 pj_status_t status; 732 733 PJ_UNUSED_ARG(flags); 734 735 /* Gather host candidate */ 736 status = gather_host_cands(ice); 737 if (status != PJ_SUCCESS) 738 return status; 739 740 /* Eliminate redundant host candidates. */ 741 eliminate_redundant_cand(&ice->lcand_cnt, ice->lcand); 742 743 PJ_TODO(GATHER_MAPPED_AND_RELAYED_CANDIDATES); 744 745 return PJ_SUCCESS; 746 } 747 748 749 static pj_uint32_t CALC_CAND_PRIO(pj_ice_cand_type type, 750 pj_uint32_t local_pref, 751 pj_uint32_t comp_id) 752 { 753 static pj_uint32_t type_pref[] = 754 { 755 PJ_ICE_HOST_PREF, 756 PJ_ICE_MAPPED_PREF, 757 PJ_ICE_PEER_MAPPED_PREF, 758 PJ_ICE_RELAYED_PREF 759 }; 760 761 return ((1 << 24) * type_pref[type]) + 762 ((1 << 8) * local_pref) + 763 (256 - comp_id); 764 } 765 766 767 PJ_DEF(pj_status_t) pj_ice_add_cand(pj_ice *ice, 768 unsigned comp_id, 769 pj_ice_cand_type type, 770 pj_uint16_t local_pref, 771 const pj_str_t *foundation, 772 const pj_sockaddr_t *addr, 773 const pj_sockaddr_t *base_addr, 774 const pj_sockaddr_t *srv_addr, 775 int addr_len, 776 unsigned *p_cand_id) 777 { 778 pj_ice_cand *lcand; 779 pj_status_t status = PJ_SUCCESS; 780 char tmp[128]; 781 782 PJ_ASSERT_RETURN(ice && comp_id && type && local_pref && 783 foundation && addr && base_addr && addr_len, 784 PJ_EINVAL); 785 786 pj_mutex_lock(ice->mutex); 787 788 if (ice->lcand_cnt >= PJ_ARRAY_SIZE(ice->lcand)) { 789 status = PJ_ETOOMANY; 790 goto on_error; 791 } 792 793 lcand = &ice->lcand[ice->lcand_cnt]; 794 lcand->comp_id = comp_id; 795 lcand->type = type; 796 pj_strdup(ice->pool, &lcand->foundation, foundation); 797 lcand->prio = CALC_CAND_PRIO(type, local_pref, lcand->comp_id); 798 pj_memcpy(&lcand->addr, addr, addr_len); 799 pj_memcpy(&lcand->base_addr, base_addr, addr_len); 800 if (srv_addr) 801 pj_memcpy(&lcand->srv_addr, srv_addr, addr_len); 802 else 803 pj_bzero(&lcand->srv_addr, sizeof(lcand->srv_addr)); 804 805 if (p_cand_id) 806 *p_cand_id = ice->lcand_cnt; 807 808 pj_ansi_strcpy(tmp, pj_inet_ntoa(lcand->addr.ipv4.sin_addr)); 809 LOG((ice->obj_name, 810 "Candidate %d added: comp_id=%d, type=%s, foundation=%.*s, " 811 "addr=%s:%d, base=%s:%d, prio=0x%x (%u)", 812 ice->lcand_cnt, 813 lcand->comp_id, 814 cand_type_names[lcand->type], 815 (int)lcand->foundation.slen, 816 lcand->foundation.ptr, 817 tmp, 818 (int)pj_ntohs(lcand->addr.ipv4.sin_port), 819 pj_inet_ntoa(lcand->base_addr.ipv4.sin_addr), 820 (int)pj_htons(lcand->base_addr.ipv4.sin_port), 821 lcand->prio, lcand->prio)); 822 823 ++ice->lcand_cnt; 824 825 on_error: 826 pj_mutex_unlock(ice->mutex); 827 return status; 828 } 829 830 831 PJ_DEF(unsigned) pj_ice_get_cand_cnt(pj_ice *ice) 832 { 833 return ice->lcand_cnt; 834 } 835 836 837 PJ_DEF(pj_status_t) pj_ice_enum_cands(pj_ice *ice, 838 unsigned *p_count, 839 unsigned cand_ids[]) 840 { 841 unsigned i, count; 842 843 PJ_ASSERT_RETURN(ice && p_count && *p_count && cand_ids, PJ_EINVAL); 844 845 pj_mutex_lock(ice->mutex); 846 847 count = (*p_count < ice->lcand_cnt) ? *p_count : ice->lcand_cnt; 848 for (i=0; i<count; ++i) 849 cand_ids[i] = i; 850 851 *p_count = count; 852 pj_mutex_unlock(ice->mutex); 853 854 return PJ_SUCCESS; 855 } 856 857 858 PJ_DEF(pj_status_t) pj_ice_get_default_cand(pj_ice *ice, 859 unsigned comp_id, 860 int *cand_id) 861 { 862 PJ_ASSERT_RETURN(ice && comp_id && cand_id, PJ_EINVAL); 863 864 pj_mutex_lock(ice->mutex); 865 866 /* First find in valid list if we have nominated pair */ 867 868 /* If there's no nominated pair, find relayed candidate */ 869 870 /* If there's no relayed candidate, find server reflexive candidate */ 871 872 /* Otherwise return host candidate */ 873 874 pj_assert(!"Not implemented yet"); 875 PJ_TODO(IMPLEMENT_GET_DEFAULT_CAND); 876 877 pj_mutex_unlock(ice->mutex); 878 879 return PJ_SUCCESS; 880 } 881 882 883 PJ_DEF(pj_status_t) pj_ice_get_cand(pj_ice *ice, 884 unsigned cand_id, 885 pj_ice_cand **p_cand) 886 { 887 PJ_ASSERT_RETURN(ice && p_cand, PJ_EINVAL); 888 PJ_ASSERT_RETURN(cand_id <= ice->lcand_cnt, PJ_EINVAL); 889 890 *p_cand = &ice->lcand[cand_id]; 891 892 return PJ_SUCCESS; 893 } 894 895 #ifndef MIN 896 # define MIN(a,b) (a < b ? a : b) 897 #endif 898 899 #ifndef MAX 900 # define MAX(a,b) (a > b ? a : b) 901 #endif 902 903 static pj_uint64_t CALC_CHECK_PRIO(const pj_ice *ice, 904 const pj_ice_cand *lcand, 905 const pj_ice_cand *rcand) 906 { 907 pj_uint32_t O, A; 908 909 if (ice->role == PJ_ICE_ROLE_CONTROLLING) { 910 O = lcand->prio; 911 A = rcand->prio; 912 } else { 913 O = rcand->prio; 914 A = lcand->prio; 915 } 916 917 return ((pj_uint64_t)1 << 32) * MIN(O, A) + 918 (pj_uint64_t)2 * MAX(O, A) + (O>A ? 1 : 0); 919 } 920 921 static const char *dump_check(char *buffer, unsigned bufsize, 922 const pj_ice *ice, 923 const pj_ice_check *check) 924 { 925 const pj_ice_cand *lcand = check->lcand; 926 const pj_ice_cand *rcand = check->rcand; 927 char laddr[CHECK_NAME_LEN]; 928 int len; 929 930 pj_ansi_strcpy(laddr, pj_inet_ntoa(lcand->addr.ipv4.sin_addr)); 931 932 if (lcand->addr.addr.sa_family == PJ_AF_INET) { 933 len = pj_ansi_snprintf(buffer, bufsize, 934 "%s:%d-->%s:%d", 935 laddr, (int)pj_ntohs(lcand->addr.ipv4.sin_port), 936 pj_inet_ntoa(rcand->addr.ipv4.sin_addr), 937 (int)pj_ntohs(rcand->addr.ipv4.sin_port)); 938 } else { 939 len = pj_ansi_snprintf(buffer, bufsize, "IPv6->IPv6"); 940 } 941 942 943 if (len < 0) 944 len = 0; 945 else if (len >= (int)bufsize) 946 len = bufsize - 1; 947 948 buffer[len] = '\0'; 949 return buffer; 950 } 951 952 #if PJ_LOG_MAX_LEVEL >= 4 953 static void dump_checklist(const char *title, const pj_ice *ice, 954 const pj_ice_checklist *clist) 955 { 956 unsigned i; 957 char buffer[CHECK_NAME_LEN]; 958 959 LOG((ice->obj_name, "%s", title)); 960 for (i=0; i<clist->count; ++i) { 961 const pj_ice_check *c = &clist->checks[i]; 962 LOG((ice->obj_name, " %d: %s (prio=%u, state=%s)", 963 i, dump_check(buffer, sizeof(buffer), ice, c), 964 c->prio, check_state_name[c->state])); 965 } 966 } 967 #else 968 #define dump_checklist(ice, clist) 969 #endif 970 971 static void check_set_state(pj_ice *ice, pj_ice_check *check, 972 pj_ice_check_state st, 973 pj_status_t err_code) 974 { 975 char buf[CHECK_NAME_LEN]; 976 LOG((ice->obj_name, "Check %s: state changed from %s to %s", 977 dump_check(buf, sizeof(buf), ice, check), 978 check_state_name[check->state], 979 check_state_name[st])); 980 check->state = st; 981 check->err_code = err_code; 982 } 983 984 static void clist_set_state(pj_ice *ice, pj_ice_checklist *clist, 985 pj_ice_checklist_state st) 986 { 987 LOG((ice->obj_name, "Checklist: state changed from %s to %s", 988 clist_state_name[clist->state], 989 clist_state_name[st])); 990 clist->state = st; 991 } 992 993 /* Sort checklist based on priority */ 994 static void sort_checklist(pj_ice_checklist *clist) 995 { 996 unsigned i; 997 998 for (i=0; i<clist->count-1; ++i) { 999 unsigned j, highest = i; 1000 for (j=i+1; j<clist->count; ++j) { 1001 if (clist->checks[j].prio > clist->checks[highest].prio) { 1002 highest = j; 1003 } 1004 } 1005 1006 if (highest != i) { 1007 pj_ice_check tmp; 1008 1009 pj_memcpy(&tmp, &clist->checks[i], sizeof(pj_ice_check)); 1010 pj_memcpy(&clist->checks[i], &clist->checks[highest], 1011 sizeof(pj_ice_check)); 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; 1038 } 1039 } 1040 } 1041 1042 1043 enum 1044 { 1045 SOCKADDR_EQUAL = 0, 1046 SOCKADDR_NOT_EQUAL = 1 1047 }; 1048 1049 /* Utility: compare sockaddr. 1050 * Returns 0 if equal. 1051 */ 1052 static int sockaddr_cmp(const pj_sockaddr *a1, const pj_sockaddr *a2) 1053 { 1054 if (a1->addr.sa_family != a2->addr.sa_family) 1055 return SOCKADDR_NOT_EQUAL; 1056 1057 if (a1->addr.sa_family == PJ_AF_INET) { 1058 return !(a1->ipv4.sin_addr.s_addr == a2->ipv4.sin_addr.s_addr && 1059 a1->ipv4.sin_port == a2->ipv4.sin_port); 1060 } else if (a1->addr.sa_family == PJ_AF_INET6) { 1061 return pj_memcmp(&a1->ipv6, &a2->ipv6, sizeof(a1->ipv6)); 1062 } else { 1063 pj_assert(!"Invalid address family!"); 1064 return SOCKADDR_NOT_EQUAL; 1065 } 1066 } 1067 1068 1069 /* Prune checklist, this must have been done after the checklist 1070 * is sorted. 1071 */ 1072 static void prune_checklist(pj_ice *ice, pj_ice_checklist *clist) 1073 { 1074 unsigned i; 1075 1076 /* Since an agent cannot send requests directly from a reflexive 1077 * candidate, but only from its base, the agent next goes through the 1078 * sorted list of candidate pairs. For each pair where the local 1079 * candidate is server reflexive, the server reflexive candidate MUST be 1080 * replaced by its base. Once this has been done, the agent MUST prune 1081 * the list. This is done by removing a pair if its local and remote 1082 * candidates are identical to the local and remote candidates of a pair 1083 * higher up on the priority list. The result is a sequence of ordered 1084 * candidate pairs, called the check list for that media stream. 1085 */ 1086 for (i=0; i<clist->count; ++i) { 1087 pj_ice_cand *licand = clist->checks[i].lcand; 1088 pj_ice_cand *ricand = clist->checks[i].rcand; 1089 const pj_sockaddr *liaddr; 1090 unsigned j; 1091 1092 if (licand->type == PJ_ICE_CAND_TYPE_MAPPED) 1093 liaddr = &licand->base_addr; 1094 else 1095 liaddr = &licand->addr; 1096 1097 for (j=i+1; j<clist->count;) { 1098 pj_ice_cand *ljcand = clist->checks[j].lcand; 1099 pj_ice_cand *rjcand = clist->checks[j].rcand; 1100 const pj_sockaddr *ljaddr; 1101 1102 if (ljcand->type == PJ_ICE_CAND_TYPE_MAPPED) 1103 ljaddr = &licand->base_addr; 1104 else 1105 ljaddr = &licand->addr; 1106 1107 if (sockaddr_cmp(liaddr, ljaddr) == SOCKADDR_EQUAL && 1108 sockaddr_cmp(&ricand->addr, &rjcand->addr) == SOCKADDR_EQUAL) 1109 { 1110 /* Found duplicate, remove it */ 1111 char buf[CHECK_NAME_LEN]; 1112 1113 LOG((ice->obj_name, "Check %s pruned", 1114 dump_check(buf, sizeof(buf), ice, &clist->checks[j]))); 1115 1116 pj_array_erase(clist->checks, sizeof(clist->checks[0]), 1117 clist->count, j); 1118 --clist->count; 1119 1120 } else { 1121 ++j; 1122 } 1123 } 1124 } 1125 } 1126 1127 1126 1128 1127 1129 typedef struct timer_data … … 1242 1244 LOG((ice->obj_name, 1243 1245 "Sending connectivity check for check %d: %s", 1244 check_id, dump_check(buffer, sizeof(buffer), ice,check)));1246 check_id, dump_check(buffer, sizeof(buffer), check))); 1245 1247 1246 1248 /* Create request */ … … 1434 1436 struct req_data *rd = (struct req_data*) tdata->user_data; 1435 1437 pj_ice *ice; 1436 pj_ice_check *check , *valid_check;1438 pj_ice_check *check; 1437 1439 const pj_ice_cand *lcand; 1438 1440 const pj_ice_cand *rcand; … … 1456 1458 "Connectivity check %s for check %s", 1457 1459 (status==PJ_SUCCESS ? "SUCCESS" : "FAILED"), 1458 dump_check(buffer, sizeof(buffer), ice,check)));1460 dump_check(buffer, sizeof(buffer), check))); 1459 1461 1460 1462 if (status != PJ_SUCCESS) { -
pjproject/trunk/pjnath/src/pjstun-client/client_main.c
r1080 r1091 33 33 static struct global 34 34 { 35 pj_stun_ endpoint *endpt;35 pj_stun_config stun_config; 36 36 pj_pool_t *pool; 37 37 pj_caching_pool cp; … … 105 105 PJ_STUN_ATTR_RELAY_ADDR, 0); 106 106 if (ar) { 107 pj_memcpy(&g.relay_addr, &ar-> addr.ipv4,107 pj_memcpy(&g.relay_addr, &ar->sockaddr.ipv4, 108 108 sizeof(pj_sockaddr_in)); 109 109 PJ_LOG(3,(THIS_FILE, "Relay address is %s:%d", … … 209 209 pj_assert(status == PJ_SUCCESS); 210 210 211 status = pj_stun_endpoint_create(&g.cp.factory, 0, NULL, g.th, &g.endpt);211 pj_stun_config_init(&g.stun_config, &g.cp.factory, 0, NULL, g.th); 212 212 pj_assert(status == PJ_SUCCESS); 213 213 … … 236 236 stun_cb.on_request_complete = &on_request_complete; 237 237 238 status = pj_stun_session_create( g.endpt, NULL, &stun_cb,238 status = pj_stun_session_create(&g.stun_config, NULL, &stun_cb, 239 239 o.use_fingerprint!=0, &g.sess); 240 240 pj_assert(status == PJ_SUCCESS); … … 282 282 if (g.sess) 283 283 pj_stun_session_destroy(g.sess); 284 if (g.endpt)285 pj_stun_endpoint_destroy(g.endpt);286 284 if (g.sock != PJ_INVALID_SOCKET) 287 285 pj_sock_close(g.sock); -
pjproject/trunk/pjnath/src/pjstun-srv-test/bind_usage.c
r1080 r1091 86 86 sess_cb.on_send_msg = &sess_on_send_msg; 87 87 sess_cb.on_rx_request = &sess_on_rx_request; 88 status = pj_stun_session_create( si->cfg, "bind%p", &sess_cb, PJ_FALSE,89 &bu->session);88 status = pj_stun_session_create(&si->stun_cfg, "bind%p", &sess_cb, 89 PJ_FALSE, &bu->session); 90 90 if (status != PJ_SUCCESS) { 91 91 pj_stun_usage_destroy(bu->usage); -
pjproject/trunk/pjnath/src/pjstun-srv-test/server.c
r1080 r1091 84 84 goto on_error; 85 85 86 status = pj_stun_config_create(srv->si.pf, 0, srv->si.ioqueue, 87 srv->si.timer_heap, &srv->si.cfg); 88 if (status != PJ_SUCCESS) 89 goto on_error; 86 pj_stun_config_init(&srv->si.stun_cfg, srv->si.pf, 0, srv->si.ioqueue, 87 srv->si.timer_heap); 90 88 91 89 srv->si.thread_cnt = thread_cnt; … … 175 173 } 176 174 177 pj_stun_config_destroy(srv->si.cfg);178 175 pj_timer_heap_destroy(srv->si.timer_heap); 179 176 pj_ioqueue_destroy(srv->si.ioqueue); -
pjproject/trunk/pjnath/src/pjstun-srv-test/server.h
r1080 r1091 32 32 { 33 33 pj_pool_factory *pf; 34 pj_stun_config *cfg;34 pj_stun_config stun_cfg; 35 35 pj_ioqueue_t *ioqueue; 36 36 pj_timer_heap_t *timer_heap; -
pjproject/trunk/pjnath/src/pjstun-srv-test/turn_usage.c
r1080 r1091 166 166 tu->type = type; 167 167 tu->pf = si->pf; 168 tu->cfg = si->cfg;168 tu->cfg = &si->stun_cfg; 169 169 tu->ioqueue = si->ioqueue; 170 170 tu->timer_heap = si->timer_heap; … … 198 198 sess_cb.on_send_msg = &tu_sess_on_send_msg; 199 199 sess_cb.on_rx_request = &tu_sess_on_rx_request; 200 status = pj_stun_session_create( si->cfg, "turns%p", &sess_cb, PJ_FALSE,201 &tu->default_session);200 status = pj_stun_session_create(&si->stun_cfg, "turns%p", &sess_cb, 201 PJ_FALSE, &tu->default_session); 202 202 if (status != PJ_SUCCESS) { 203 203 pj_stun_usage_destroy(tu->usage); … … 934 934 935 935 /* Process REQUESTED-IP attribute */ 936 if (a_rip && a_rip-> addr.addr.sa_family != PJ_AF_INET) {936 if (a_rip && a_rip->sockaddr.addr.sa_family != PJ_AF_INET) { 937 937 client_respond(client, msg, PJ_STUN_SC_INVALID_IP_ADDR, NULL, 938 938 src_addr, src_addr_len); … … 940 940 941 941 } else if (a_rip) { 942 req_addr.sin_addr.s_addr = a_rip-> addr.ipv4.sin_addr.s_addr;942 req_addr.sin_addr.s_addr = a_rip->sockaddr.ipv4.sin_addr.s_addr; 943 943 } 944 944 … … 1107 1107 client->active_peer = NULL; 1108 1108 1109 } else if (a_raddr-> addr.addr.sa_family != PJ_AF_INET) {1109 } else if (a_raddr->sockaddr.addr.sa_family != PJ_AF_INET) { 1110 1110 /* Bad request (not IPv4) */ 1111 1111 client_respond(client, msg, PJ_STUN_SC_BAD_REQUEST, NULL, … … 1126 1126 1127 1127 /* Add a new peer/permission if we don't have one for this address */ 1128 peer = client_get_peer(client, &a_raddr-> addr.ipv4, &hval);1128 peer = client_get_peer(client, &a_raddr->sockaddr.ipv4, &hval); 1129 1129 if (peer==NULL) { 1130 peer = client_add_peer(client, &a_raddr-> addr.ipv4, hval);1130 peer = client_add_peer(client, &a_raddr->sockaddr.ipv4, hval); 1131 1131 } 1132 1132 … … 1173 1173 return PJ_SUCCESS; 1174 1174 1175 } else if (a_raddr-> addr.addr.sa_family != PJ_AF_INET) {1175 } else if (a_raddr->sockaddr.addr.sa_family != PJ_AF_INET) { 1176 1176 /* REMOTE-ADDRESS present but not IPv4, discard packet */ 1177 1177 return PJ_SUCCESS; … … 1196 1196 1197 1197 /* Add to peer table if necessary */ 1198 if (client_get_peer(client, &a_raddr-> addr.ipv4, &hval)==NULL)1199 client_add_peer(client, &a_raddr-> addr.ipv4, hval);1198 if (client_get_peer(client, &a_raddr->sockaddr.ipv4, &hval)==NULL) 1199 client_add_peer(client, &a_raddr->sockaddr.ipv4, hval); 1200 1200 1201 1201 /* Send the packet */ 1202 1202 pj_ioqueue_sendto(client->key, &client->pkt_write_key, 1203 1203 data, &datalen, 0, 1204 &a_raddr-> addr.ipv4, sizeof(a_raddr->addr.ipv4));1204 &a_raddr->sockaddr.ipv4, sizeof(pj_sockaddr_in)); 1205 1205 1206 1206 return PJ_SUCCESS;
Note: See TracChangeset
for help on using the changeset viewer.