Changeset 4360 for pjproject/trunk/pjnath/src/pjnath/stun_session.c
- Timestamp:
- Feb 21, 2013 11:26:35 AM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjnath/src/pjnath/stun_session.c
r4352 r4360 26 26 pj_stun_config *cfg; 27 27 pj_pool_t *pool; 28 pj_lock_t *lock; 29 pj_bool_t delete_lock; 28 pj_grp_lock_t *grp_lock; 30 29 pj_stun_session_cb cb; 31 30 void *user_data; 32 33 pj_atomic_t *busy; 34 pj_bool_t destroy_request; 31 pj_bool_t is_destroying; 35 32 36 33 pj_bool_t use_fingerprint; … … 56 53 57 54 #define SNAME(s_) ((s_)->pool->obj_name) 58 59 #if PJ_LOG_MAX_LEVEL >= 5 55 #define THIS_FILE "stun_session.c" 56 57 #if 1 60 58 # define TRACE_(expr) PJ_LOG(5,expr) 61 59 #else … … 63 61 #endif 64 62 65 #define LOG_ERR_(sess,title,rc) pjnath_perror(sess->pool->obj_name,title,rc)63 #define LOG_ERR_(sess,title,rc) PJ_PERROR(3,(sess->pool->obj_name,rc,title)) 66 64 67 65 #define TDATA_POOL_SIZE PJNATH_POOL_LEN_STUN_TDATA … … 78 76 pj_size_t pkt_size); 79 77 static void stun_tsx_on_destroy(pj_stun_client_tsx *tsx); 78 static void stun_sess_on_destroy(void *comp); 80 79 81 80 static pj_stun_tsx_cb tsx_cb = … … 149 148 150 149 tdata = (pj_stun_tx_data*) pj_stun_client_tsx_get_data(tsx); 151 tsx_erase(tdata->sess, tdata); 152 153 pj_stun_client_tsx_destroy(tsx); 154 pj_pool_release(tdata->pool); 150 pj_stun_client_tsx_stop(tsx); 151 if (tdata) { 152 tsx_erase(tdata->sess, tdata); 153 pj_pool_release(tdata->pool); 154 } 155 156 TRACE_((THIS_FILE, "STUN transaction %p destroyed", tsx)); 155 157 } 156 158 157 159 static void destroy_tdata(pj_stun_tx_data *tdata, pj_bool_t force) 158 160 { 161 TRACE_((THIS_FILE, "tdata %p destroy request, force=%d, tsx=%p", tdata, 162 force, tdata->client_tsx)); 163 159 164 if (tdata->res_timer.id != PJ_FALSE) { 160 pj_timer_heap_cancel(tdata->sess->cfg->timer_heap, 161 &tdata->res_timer); 162 tdata->res_timer.id = PJ_FALSE; 165 pj_timer_heap_cancel_if_active(tdata->sess->cfg->timer_heap, 166 &tdata->res_timer, PJ_FALSE); 163 167 pj_list_erase(tdata); 164 168 } 165 169 166 170 if (force) { 171 pj_list_erase(tdata); 167 172 if (tdata->client_tsx) { 168 tsx_erase(tdata->sess, tdata);169 pj_stun_client_tsx_ destroy(tdata->client_tsx);173 pj_stun_client_tsx_stop(tdata->client_tsx); 174 pj_stun_client_tsx_set_data(tdata->client_tsx, NULL); 170 175 } 171 176 pj_pool_release(tdata->pool); … … 173 178 } else { 174 179 if (tdata->client_tsx) { 175 pj_time_val delay = {2, 0}; 180 /* "Probably" this is to absorb retransmission */ 181 pj_time_val delay = {0, 300}; 176 182 pj_stun_client_tsx_schedule_destroy(tdata->client_tsx, &delay); 177 183 … … 207 213 208 214 pj_list_erase(tdata); 209 pj_stun_msg_destroy_tdata(tdata->sess, tdata);215 destroy_tdata(tdata, PJ_FALSE); 210 216 } 211 217 … … 420 426 421 427 /* Lock the session and prevent user from destroying us in the callback */ 422 pj_atomic_inc(sess->busy); 423 pj_lock_acquire(sess->lock); 428 pj_grp_lock_acquire(sess->grp_lock); 429 if (sess->is_destroying) { 430 pj_stun_msg_destroy_tdata(sess, tdata); 431 pj_grp_lock_release(sess->grp_lock); 432 return; 433 } 424 434 425 435 /* Handle authentication challenge */ … … 435 445 * from the pending list too. 436 446 */ 437 pj_stun_msg_destroy_tdata(sess, tdata); 447 if (status == PJNATH_ESTUNTIMEDOUT) 448 destroy_tdata(tdata, PJ_TRUE); 449 else 450 destroy_tdata(tdata, PJ_FALSE); 438 451 tdata = NULL; 439 452 440 pj_lock_release(sess->lock); 441 442 if (pj_atomic_dec_and_get(sess->busy)==0 && sess->destroy_request) { 443 pj_stun_session_destroy(sess); 444 return; 445 } 453 pj_grp_lock_release(sess->grp_lock); 446 454 } 447 455 … … 458 466 459 467 /* Lock the session and prevent user from destroying us in the callback */ 460 pj_atomic_inc(sess->busy); 461 pj_lock_acquire(sess->lock); 468 pj_grp_lock_acquire(sess->grp_lock); 462 469 470 if (sess->is_destroying) { 471 /* Stray timer */ 472 pj_grp_lock_release(sess->grp_lock); 473 return PJ_EINVALIDOP; 474 } 475 463 476 status = sess->cb.on_send_msg(tdata->sess, tdata->token, stun_pkt, 464 477 pkt_size, tdata->dst_addr, 465 478 tdata->addr_len); 466 pj_lock_release(sess->lock); 467 468 if (pj_atomic_dec_and_get(sess->busy)==0 && sess->destroy_request) { 469 pj_stun_session_destroy(sess); 470 return PJNATH_ESTUNDESTROYED; 471 } else { 472 return status; 473 } 479 if (pj_grp_lock_release(sess->grp_lock)) 480 return PJ_EGONE; 481 482 return status; 474 483 } 475 484 … … 480 489 const pj_stun_session_cb *cb, 481 490 pj_bool_t fingerprint, 491 pj_grp_lock_t *grp_lock, 482 492 pj_stun_session **p_sess) 483 493 { … … 502 512 sess->log_flag = 0xFFFF; 503 513 514 if (grp_lock) { 515 sess->grp_lock = grp_lock; 516 } else { 517 status = pj_grp_lock_create(pool, NULL, &sess->grp_lock); 518 if (status != PJ_SUCCESS) { 519 pj_pool_release(pool); 520 return status; 521 } 522 } 523 524 pj_grp_lock_add_ref(sess->grp_lock); 525 pj_grp_lock_add_handler(sess->grp_lock, pool, sess, 526 &stun_sess_on_destroy); 527 504 528 pj_stun_session_set_software_name(sess, &cfg->software_name); 505 529 506 sess->rx_pool = pj_pool_create(sess->cfg->pf, name, 507 PJNATH_POOL_LEN_STUN_TDATA, 530 sess->rx_pool = pj_pool_create(sess->cfg->pf, name, 531 PJNATH_POOL_LEN_STUN_TDATA, 508 532 PJNATH_POOL_INC_STUN_TDATA, NULL); 509 533 … … 511 535 pj_list_init(&sess->cached_response_list); 512 536 513 status = pj_lock_create_recursive_mutex(pool, name, &sess->lock);514 if (status != PJ_SUCCESS) {515 pj_pool_release(pool);516 return status;517 }518 sess->delete_lock = PJ_TRUE;519 520 status = pj_atomic_create(pool, 0, &sess->busy);521 if (status != PJ_SUCCESS) {522 pj_lock_destroy(sess->lock);523 pj_pool_release(pool);524 return status;525 }526 527 537 *p_sess = sess; 528 538 … … 530 540 } 531 541 532 PJ_DEF(pj_status_t) pj_stun_session_destroy(pj_stun_session *sess) 533 { 534 PJ_ASSERT_RETURN(sess, PJ_EINVAL); 535 536 pj_lock_acquire(sess->lock); 537 538 /* Can't destroy if we're in a callback */ 539 sess->destroy_request = PJ_TRUE; 540 if (pj_atomic_get(sess->busy)) { 541 pj_lock_release(sess->lock); 542 return PJ_EPENDING; 543 } 542 static void stun_sess_on_destroy(void *comp) 543 { 544 pj_stun_session *sess = (pj_stun_session*)comp; 544 545 545 546 while (!pj_list_empty(&sess->pending_request_list)) { … … 552 553 destroy_tdata(tdata, PJ_TRUE); 553 554 } 554 pj_lock_release(sess->lock);555 556 if (sess->delete_lock) {557 pj_lock_destroy(sess->lock);558 }559 555 560 556 if (sess->rx_pool) { … … 565 561 pj_pool_release(sess->pool); 566 562 563 TRACE_((THIS_FILE, "STUN session %p destroyed", sess)); 564 } 565 566 PJ_DEF(pj_status_t) pj_stun_session_destroy(pj_stun_session *sess) 567 { 568 pj_stun_tx_data *tdata; 569 570 PJ_ASSERT_RETURN(sess, PJ_EINVAL); 571 572 TRACE_((SNAME(sess), "STUN session %p destroy request, ref_cnt=%d", 573 sess, pj_grp_lock_get_ref(sess->grp_lock))); 574 575 pj_grp_lock_acquire(sess->grp_lock); 576 577 if (sess->is_destroying) { 578 /* Prevent from decrementing the ref counter more than once */ 579 pj_grp_lock_release(sess->grp_lock); 580 return PJ_EINVALIDOP; 581 } 582 583 sess->is_destroying = PJ_TRUE; 584 585 /* We need to stop transactions and cached response because they are 586 * holding the group lock's reference counter while retransmitting. 587 */ 588 tdata = sess->pending_request_list.next; 589 while (tdata != &sess->pending_request_list) { 590 if (tdata->client_tsx) 591 pj_stun_client_tsx_stop(tdata->client_tsx); 592 tdata = tdata->next; 593 } 594 595 tdata = sess->cached_response_list.next; 596 while (tdata != &sess->cached_response_list) { 597 pj_timer_heap_cancel_if_active(tdata->sess->cfg->timer_heap, 598 &tdata->res_timer, PJ_FALSE); 599 tdata = tdata->next; 600 } 601 602 pj_grp_lock_dec_ref(sess->grp_lock); 603 pj_grp_lock_release(sess->grp_lock); 567 604 return PJ_SUCCESS; 568 605 } … … 573 610 { 574 611 PJ_ASSERT_RETURN(sess, PJ_EINVAL); 575 pj_ lock_acquire(sess->lock);612 pj_grp_lock_acquire(sess->grp_lock); 576 613 sess->user_data = user_data; 577 pj_ lock_release(sess->lock);614 pj_grp_lock_release(sess->grp_lock); 578 615 return PJ_SUCCESS; 579 616 } … … 585 622 } 586 623 587 PJ_DEF(pj_status_t) pj_stun_session_set_lock( pj_stun_session *sess,588 pj_lock_t *lock,589 pj_bool_t auto_del)590 {591 pj_lock_t *old_lock = sess->lock;592 pj_bool_t old_del;593 594 PJ_ASSERT_RETURN(sess && lock, PJ_EINVAL);595 596 pj_lock_acquire(old_lock);597 sess->lock = lock;598 old_del = sess->delete_lock;599 sess->delete_lock = auto_del;600 pj_lock_release(old_lock);601 602 if (old_lock)603 pj_lock_destroy(old_lock);604 605 return PJ_SUCCESS;606 }607 608 624 PJ_DEF(pj_status_t) pj_stun_session_set_software_name(pj_stun_session *sess, 609 625 const pj_str_t *sw) 610 626 { 611 627 PJ_ASSERT_RETURN(sess, PJ_EINVAL); 628 pj_grp_lock_acquire(sess->grp_lock); 612 629 if (sw && sw->slen) 613 630 pj_strdup(sess->pool, &sess->srv_name, sw); 614 631 else 615 632 sess->srv_name.slen = 0; 633 pj_grp_lock_release(sess->grp_lock); 616 634 return PJ_SUCCESS; 617 635 } … … 623 641 PJ_ASSERT_RETURN(sess, PJ_EINVAL); 624 642 643 pj_grp_lock_acquire(sess->grp_lock); 625 644 sess->auth_type = auth_type; 626 645 if (cred) { … … 630 649 pj_bzero(&sess->cred, sizeof(sess->cred)); 631 650 } 651 pj_grp_lock_release(sess->grp_lock); 632 652 633 653 return PJ_SUCCESS; … … 706 726 PJ_ASSERT_RETURN(sess && p_tdata, PJ_EINVAL); 707 727 728 pj_grp_lock_acquire(sess->grp_lock); 729 if (sess->is_destroying) { 730 pj_grp_lock_release(sess->grp_lock); 731 return PJ_EINVALIDOP; 732 } 733 708 734 status = create_tdata(sess, &tdata); 709 735 if (status != PJ_SUCCESS) 710 return status;736 goto on_error; 711 737 712 738 /* Create STUN message */ 713 739 status = pj_stun_msg_create(tdata->pool, method, magic, 714 740 tsx_id, &tdata->msg); 715 if (status != PJ_SUCCESS) { 716 pj_pool_release(tdata->pool); 717 return status; 718 } 741 if (status != PJ_SUCCESS) 742 goto on_error; 719 743 720 744 /* copy the request's transaction ID as the transaction key. */ … … 732 756 /* MUST put authentication in request */ 733 757 status = get_auth(sess, tdata); 734 if (status != PJ_SUCCESS) { 735 pj_pool_release(tdata->pool); 736 return status; 737 } 758 if (status != PJ_SUCCESS) 759 goto on_error; 738 760 739 761 } else if (sess->auth_type == PJ_STUN_AUTH_LONG_TERM) { … … 743 765 if (sess->next_nonce.slen != 0) { 744 766 status = get_auth(sess, tdata); 745 if (status != PJ_SUCCESS) { 746 pj_pool_release(tdata->pool); 747 return status; 748 } 767 if (status != PJ_SUCCESS) 768 goto on_error; 749 769 tdata->auth_info.nonce = sess->next_nonce; 750 770 tdata->auth_info.realm = sess->server_realm; … … 753 773 } else { 754 774 pj_assert(!"Invalid authentication type"); 775 status = PJ_EBUG; 776 goto on_error; 777 } 778 779 *p_tdata = tdata; 780 pj_grp_lock_release(sess->grp_lock); 781 return PJ_SUCCESS; 782 783 on_error: 784 if (tdata) 755 785 pj_pool_release(tdata->pool); 756 return PJ_EBUG; 757 } 758 759 *p_tdata = tdata; 760 return PJ_SUCCESS; 786 pj_grp_lock_release(sess->grp_lock); 787 return status; 761 788 } 762 789 … … 770 797 PJ_ASSERT_RETURN(sess && p_tdata, PJ_EINVAL); 771 798 799 pj_grp_lock_acquire(sess->grp_lock); 800 if (sess->is_destroying) { 801 pj_grp_lock_release(sess->grp_lock); 802 return PJ_EINVALIDOP; 803 } 804 772 805 status = create_tdata(sess, &tdata); 773 if (status != PJ_SUCCESS) 806 if (status != PJ_SUCCESS) { 807 pj_grp_lock_release(sess->grp_lock); 774 808 return status; 809 } 775 810 776 811 /* Create STUN message */ … … 780 815 if (status != PJ_SUCCESS) { 781 816 pj_pool_release(tdata->pool); 817 pj_grp_lock_release(sess->grp_lock); 782 818 return status; 783 819 } 784 820 785 821 *p_tdata = tdata; 822 823 pj_grp_lock_release(sess->grp_lock); 786 824 return PJ_SUCCESS; 787 825 } … … 799 837 pj_stun_tx_data *tdata = NULL; 800 838 839 pj_grp_lock_acquire(sess->grp_lock); 840 if (sess->is_destroying) { 841 pj_grp_lock_release(sess->grp_lock); 842 return PJ_EINVALIDOP; 843 } 844 801 845 status = create_tdata(sess, &tdata); 802 if (status != PJ_SUCCESS) 846 if (status != PJ_SUCCESS) { 847 pj_grp_lock_release(sess->grp_lock); 803 848 return status; 849 } 804 850 805 851 /* Create STUN response message */ … … 808 854 if (status != PJ_SUCCESS) { 809 855 pj_pool_release(tdata->pool); 856 pj_grp_lock_release(sess->grp_lock); 810 857 return status; 811 858 } … … 821 868 822 869 *p_tdata = tdata; 870 871 pj_grp_lock_release(sess->grp_lock); 823 872 824 873 return PJ_SUCCESS; … … 868 917 PJ_ASSERT_RETURN(sess && addr_len && server && tdata, PJ_EINVAL); 869 918 919 /* Lock the session and prevent user from destroying us in the callback */ 920 pj_grp_lock_acquire(sess->grp_lock); 921 if (sess->is_destroying) { 922 pj_grp_lock_release(sess->grp_lock); 923 return PJ_EINVALIDOP; 924 } 925 870 926 pj_log_push_indent(); 871 927 … … 876 932 tdata->token = token; 877 933 tdata->retransmit = retransmit; 878 879 /* Lock the session and prevent user from destroying us in the callback */880 pj_atomic_inc(sess->busy);881 pj_lock_acquire(sess->lock);882 934 883 935 /* Apply options */ … … 910 962 911 963 /* Create STUN client transaction */ 912 status = pj_stun_client_tsx_create(sess->cfg, tdata->pool, 964 status = pj_stun_client_tsx_create(sess->cfg, tdata->pool, 965 sess->grp_lock, 913 966 &tsx_cb, &tdata->client_tsx); 914 967 PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); … … 940 993 941 994 pj_memset(&tdata->res_timer, 0, sizeof(tdata->res_timer)); 942 pj_timer_entry_init(&tdata->res_timer, PJ_ TRUE, tdata,995 pj_timer_entry_init(&tdata->res_timer, PJ_FALSE, tdata, 943 996 &on_cache_timeout); 944 997 … … 946 999 timeout.msec = sess->cfg->res_cache_msec % 1000; 947 1000 948 status = pj_timer_heap_schedule(sess->cfg->timer_heap, 949 &tdata->res_timer, 950 &timeout); 1001 status = pj_timer_heap_schedule_w_grp_lock(sess->cfg->timer_heap, 1002 &tdata->res_timer, 1003 &timeout, PJ_TRUE, 1004 sess->grp_lock); 951 1005 if (status != PJ_SUCCESS) { 952 tdata->res_timer.id = PJ_FALSE;953 1006 pj_stun_msg_destroy_tdata(sess, tdata); 954 1007 LOG_ERR_(sess, "Error scheduling response timer", status); … … 976 1029 977 1030 on_return: 978 pj_lock_release(sess->lock);979 980 1031 pj_log_pop_indent(); 981 1032 982 /* Check if application has called destroy() in the callback */ 983 if (pj_atomic_dec_and_get(sess->busy)==0 && sess->destroy_request) { 984 pj_stun_session_destroy(sess); 985 return PJNATH_ESTUNDESTROYED; 986 } 1033 if (pj_grp_lock_release(sess->grp_lock)) 1034 return PJ_EGONE; 987 1035 988 1036 return status; … … 1006 1054 pj_stun_tx_data *tdata; 1007 1055 1056 pj_grp_lock_acquire(sess->grp_lock); 1057 if (sess->is_destroying) { 1058 pj_grp_lock_release(sess->grp_lock); 1059 return PJ_EINVALIDOP; 1060 } 1061 1008 1062 status = pj_stun_session_create_res(sess, rdata, code, 1009 1063 (errmsg?pj_cstr(&reason,errmsg):NULL), 1010 1064 &tdata); 1011 if (status != PJ_SUCCESS) 1065 if (status != PJ_SUCCESS) { 1066 pj_grp_lock_release(sess->grp_lock); 1012 1067 return status; 1013 1014 return pj_stun_session_send_msg(sess, token, cache, PJ_FALSE, 1015 dst_addr, addr_len, tdata); 1068 } 1069 1070 status = pj_stun_session_send_msg(sess, token, cache, PJ_FALSE, 1071 dst_addr, addr_len, tdata); 1072 1073 pj_grp_lock_release(sess->grp_lock); 1074 return status; 1016 1075 } 1017 1076 … … 1030 1089 1031 1090 /* Lock the session and prevent user from destroying us in the callback */ 1032 pj_atomic_inc(sess->busy); 1033 pj_lock_acquire(sess->lock); 1091 pj_grp_lock_acquire(sess->grp_lock); 1092 if (sess->is_destroying) { 1093 pj_grp_lock_release(sess->grp_lock); 1094 return PJ_EINVALIDOP; 1095 } 1034 1096 1035 1097 if (notify) { … … 1041 1103 pj_stun_msg_destroy_tdata(sess, tdata); 1042 1104 1043 pj_lock_release(sess->lock); 1044 1045 if (pj_atomic_dec_and_get(sess->busy)==0 && sess->destroy_request) { 1046 pj_stun_session_destroy(sess); 1047 return PJNATH_ESTUNDESTROYED; 1048 } 1105 pj_grp_lock_release(sess->grp_lock); 1049 1106 1050 1107 return PJ_SUCCESS; … … 1064 1121 1065 1122 /* Lock the session and prevent user from destroying us in the callback */ 1066 pj_atomic_inc(sess->busy); 1067 pj_lock_acquire(sess->lock); 1123 pj_grp_lock_acquire(sess->grp_lock); 1124 if (sess->is_destroying) { 1125 pj_grp_lock_release(sess->grp_lock); 1126 return PJ_EINVALIDOP; 1127 } 1068 1128 1069 1129 status = pj_stun_client_tsx_retransmit(tdata->client_tsx, mod_count); 1070 1130 1071 pj_lock_release(sess->lock); 1072 1073 if (pj_atomic_dec_and_get(sess->busy)==0 && sess->destroy_request) { 1074 pj_stun_session_destroy(sess); 1075 return PJNATH_ESTUNDESTROYED; 1076 } 1131 pj_grp_lock_release(sess->grp_lock); 1077 1132 1078 1133 return status; … … 1362 1417 PJ_ASSERT_RETURN(sess && packet && pkt_size, PJ_EINVAL); 1363 1418 1419 /* Lock the session and prevent user from destroying us in the callback */ 1420 pj_grp_lock_acquire(sess->grp_lock); 1421 1422 if (sess->is_destroying) { 1423 pj_grp_lock_release(sess->grp_lock); 1424 return PJ_EINVALIDOP; 1425 } 1426 1364 1427 pj_log_push_indent(); 1365 1366 /* Lock the session and prevent user from destroying us in the callback */1367 pj_atomic_inc(sess->busy);1368 pj_lock_acquire(sess->lock);1369 1428 1370 1429 /* Reset pool */ … … 1419 1478 1420 1479 on_return: 1421 pj_lock_release(sess->lock);1422 1423 1480 pj_log_pop_indent(); 1424 1481 1425 /* If we've received destroy request while we're on the callback, 1426 * destroy the session now. 1427 */ 1428 if (pj_atomic_dec_and_get(sess->busy)==0 && sess->destroy_request) { 1429 pj_stun_session_destroy(sess); 1430 return PJNATH_ESTUNDESTROYED; 1431 } 1482 if (pj_grp_lock_release(sess->grp_lock)) 1483 return PJ_EGONE; 1432 1484 1433 1485 return status;
Note: See TracChangeset
for help on using the changeset viewer.