- Timestamp:
- Mar 12, 2008 8:52:16 PM (17 years ago)
- Location:
- pjproject/trunk/pjnath
- Files:
-
- 2 added
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjnath/include/pjnath/errno.h
r1501 r1862 51 51 /** 52 52 * @hideinitializer 53 * Invalid STUN message 54 */ 55 #define PJNATH_EINSTUNMSG (PJNATH_ERRNO_START+1) /* 370001 */ 56 /** 57 * @hideinitializer 53 58 * Invalid STUN message length. 54 59 */ 55 #define PJNATH_EINSTUNMSGLEN (PJNATH_ERRNO_START+ 1) /* 370001*/60 #define PJNATH_EINSTUNMSGLEN (PJNATH_ERRNO_START+2) /* 370002 */ 56 61 /** 57 62 * @hideinitializer 58 63 * Invalid or unexpected STUN message type 59 64 */ 60 #define PJNATH_EINSTUNMSGTYPE (PJNATH_ERRNO_START+ 2) /* 370002*/65 #define PJNATH_EINSTUNMSGTYPE (PJNATH_ERRNO_START+3) /* 370003 */ 61 66 /** 62 67 * @hideinitializer 63 68 * STUN transaction has timed out 64 69 */ 65 #define PJNATH_ESTUNTIMEDOUT (PJNATH_ERRNO_START+3) /* 370003 */ 66 70 #define PJNATH_ESTUNTIMEDOUT (PJNATH_ERRNO_START+4) /* 370004 */ 67 71 68 72 … … 174 178 175 179 180 /************************************************************ 181 * TURN ERROR CODES 182 ***********************************************************/ 183 /** 184 * @hideinitializer 185 * Invalid or unsupported TURN transport. 186 */ 187 #define PJNATH_ETURNINTP (PJNATH_ERRNO_START+120) /* 370120 */ 188 189 190 176 191 /** 177 192 * @} -
pjproject/trunk/pjnath/include/pjnath/stun_session.h
r1852 r1862 113 113 * response may contain non-NULL value if the 114 114 * response contains STUN ERROR-CODE attribute. 115 * @param requestThe original STUN request.115 * @param tdata The original STUN request. 116 116 * @param response The response message, on successful transaction, 117 117 * or otherwise MAY BE NULL if status is not success. … … 223 223 */ 224 224 PJ_DECL(void*) pj_stun_session_get_user_data(pj_stun_session *sess); 225 226 /** 227 * Change the lock object used by the STUN session. By default, the STUN 228 * session uses a mutex to protect its internal data. If application already 229 * protects access to STUN session with higher layer lock, it may disable 230 * the mutex protection in the STUN session by changing the STUN session 231 * lock to a NULL mutex. 232 * 233 * @param sess The STUN session instance. 234 * @param lock New lock instance to be used by the STUN session. 235 * @param auto_del Specify whether STUN session should destroy this 236 * lock instance when it's destroyed. 237 */ 238 PJ_DECL(pj_status_t) pj_stun_session_set_lock(pj_stun_session *sess, 239 pj_lock_t *lock, 240 pj_bool_t auto_del); 225 241 226 242 /** -
pjproject/trunk/pjnath/include/pjnath/turn_session.h
r1854 r1862 49 49 #define PJ_TURN_NO_TIMEOUT ((long)0x7FFFFFFF) 50 50 #define PJ_TURN_MAX_PKT_LEN 3000 51 #define PJ_TURN_PERM_TIMEOUT 300 52 #define PJ_TURN_CHANNEL_TIMEOUT 600 53 54 55 /** Transport types */ 56 enum { 51 #define PJ_TURN_PERM_TIMEOUT 300 /* Must be greater than REFRESH_SEC_BEFORE */ 52 #define PJ_TURN_CHANNEL_TIMEOUT 600 /* Must be greater than REFRESH_SEC_BEFORE */ 53 #define PJ_TURN_REFRESH_SEC_BEFORE 60 54 #define PJ_TURN_KEEP_ALIVE_SEC 15 55 #define PJ_TURN_PEER_HTABLE_SIZE 8 56 57 58 /** TURN transport types */ 59 typedef enum pj_turn_tp_type 60 { 57 61 PJ_TURN_TP_UDP = 16, /**< UDP. */ 58 PJ_TURN_TP_TCP = 6 /**< TCP. */ 59 }; 62 PJ_TURN_TP_TCP = 6, /**< TCP. */ 63 PJ_TURN_TP_TLS = 256 /**< TLS. */ 64 } pj_turn_tp_type; 65 66 67 /** TURN session state */ 68 typedef enum pj_turn_state_t 69 { 70 /** 71 * TURN session has just been created. 72 */ 73 PJ_TURN_STATE_NULL, 74 75 /** 76 * TURN server has been configured and now is being resolved via 77 * DNS SRV resolution. 78 */ 79 PJ_TURN_STATE_RESOLVING, 80 81 /** 82 * TURN server has been resolved. If there is pending allocation to 83 * be done, it will be invoked immediately. 84 */ 85 PJ_TURN_STATE_RESOLVED, 86 87 /** 88 * TURN session has issued ALLOCATE request and is waiting for response 89 * from the TURN server. 90 */ 91 PJ_TURN_STATE_ALLOCATING, 92 93 /** 94 * TURN session has successfully allocated relay resoruce and now is 95 * ready to be used. 96 */ 97 PJ_TURN_STATE_READY, 98 99 /** 100 * TURN session has issued deallocate request and is waiting for a 101 * response from the TURN server. 102 */ 103 PJ_TURN_STATE_DEALLOCATING, 104 105 /** 106 * Deallocate response has been received. Normally the session will 107 * proceed to DESTROYING state immediately. 108 */ 109 PJ_TURN_STATE_DEALLOCATED, 110 111 /** 112 * TURN session is being destroyed. 113 */ 114 PJ_TURN_STATE_DESTROYING 115 116 } pj_turn_state_t; 117 60 118 61 119 /* ChannelData header */ … … 74 132 { 75 133 /** 76 * Callback to send outgoing packet. This callback is mandatory. 134 * This callback will be called by the TURN session whenever it 135 * needs to send outgoing message. Since the TURN session doesn't 136 * have a socket on its own, this callback must be implemented. 77 137 */ 78 138 pj_status_t (*on_send_pkt)(pj_turn_session *sess, … … 83 143 84 144 /** 85 * Notification when allocation completes, either successfully or 86 * with failure. 87 */ 88 void (*on_allocate_complete)(pj_turn_session *sess, 89 pj_status_t status); 90 91 /** 92 * Notification when data is received. 145 * Notification when peer address has been bound successfully to 146 * a channel number. 147 * 148 * This callback is optional. 149 */ 150 void (*on_channel_bound)(pj_turn_session *sess, 151 const pj_sockaddr_t *peer_addr, 152 unsigned addr_len, 153 unsigned ch_num); 154 155 /** 156 * Notification when incoming data has been received, either through 157 * Data indication or ChannelData message from the TURN server. 158 * 159 * This callback is optional. 93 160 */ 94 161 void (*on_rx_data)(pj_turn_session *sess, … … 99 166 100 167 /** 101 * Notification when session has been destroyed. 102 */ 103 void (*on_destroyed)(pj_turn_session *sess); 168 * Notification when TURN session state has changed. Application should 169 * implement this callback at least to know that the TURN session is 170 * going to be destroyed. 171 */ 172 void (*on_state)(pj_turn_session *sess, pj_turn_state_t old_state, 173 pj_turn_state_t new_state); 104 174 105 175 } pj_turn_session_cb; … … 113 183 int bandwidth; 114 184 int lifetime; 185 int ka_interval; 115 186 } pj_turn_alloc_param; 116 187 … … 121 192 typedef struct pj_turn_session_info 122 193 { 194 /** 195 * The relay address 196 */ 197 pj_sockaddr relay_addr; 198 199 /** 200 * The TURN server address for informational purpose. 201 */ 123 202 pj_sockaddr server; 203 124 204 } pj_turn_session_info; 125 205 126 206 127 207 /** 208 * Get TURN state name. 209 */ 210 PJ_DECL(const char*) pj_turn_state_name(pj_turn_state_t state); 211 212 213 /** 128 214 * Create TURN client session. 129 215 */ 130 216 PJ_DECL(pj_status_t) pj_turn_session_create(pj_stun_config *cfg, 217 const char *name, 218 int af, 219 pj_turn_tp_type conn_type, 131 220 const pj_turn_session_cb *cb, 221 void *user_data, 222 unsigned options, 132 223 pj_turn_session **p_sess); 133 224 … … 138 229 PJ_DECL(pj_status_t) pj_turn_session_destroy(pj_turn_session *sess); 139 230 231 232 /** 233 * Re-assign user data. 234 */ 235 PJ_DECL(pj_status_t) pj_turn_session_set_user_data(pj_turn_session *sess, 236 void *user_data); 237 238 /** 239 * Retrieve user data. 240 */ 241 PJ_DECL(void*) pj_turn_session_get_user_data(pj_turn_session *sess); 140 242 141 243 /** … … 144 246 PJ_DECL(pj_status_t) pj_turn_session_set_server(pj_turn_session *sess, 145 247 const pj_str_t *domain, 146 const pj_str_t *res_name,147 248 int default_port, 148 249 pj_dns_resolver *resolver); -
pjproject/trunk/pjnath/src/pjnath/errno.c
r1501 r1862 36 36 { 37 37 /* STUN related error codes */ 38 PJ_BUILD_ERR( PJNATH_EINSTUNMSG, "Invalid STUN message"), 38 39 PJ_BUILD_ERR( PJNATH_EINSTUNMSGLEN, "Invalid STUN message length"), 39 40 PJ_BUILD_ERR( PJNATH_EINSTUNMSGTYPE, "Invalid or unexpected STUN message type"), … … 62 63 PJ_BUILD_ERR( PJNATH_EICEINCANDSDP, "Invalid SDP \"candidate\" attribute"), 63 64 PJ_BUILD_ERR( PJNATH_EICENOHOSTCAND, "No host candidate associated with srflx"), 65 66 /* TURN related errors */ 67 PJ_BUILD_ERR( PJNATH_ETURNINTP, "Invalid/unsupported transport"), 64 68 65 69 }; -
pjproject/trunk/pjnath/src/pjnath/stun_session.c
r1852 r1862 24 24 pj_stun_config *cfg; 25 25 pj_pool_t *pool; 26 pj_mutex_t *mutex; 26 pj_lock_t *lock; 27 pj_bool_t delete_lock; 27 28 pj_stun_session_cb cb; 28 29 void *user_data; … … 403 404 pj_list_init(&sess->cached_response_list); 404 405 405 status = pj_ mutex_create_recursive(pool, name, &sess->mutex);406 status = pj_lock_create_recursive_mutex(pool, name, &sess->lock); 406 407 if (status != PJ_SUCCESS) { 407 408 pj_pool_release(pool); 408 409 return status; 409 410 } 411 sess->delete_lock = PJ_TRUE; 410 412 411 413 *p_sess = sess; … … 418 420 PJ_ASSERT_RETURN(sess, PJ_EINVAL); 419 421 420 pj_ mutex_lock(sess->mutex);422 pj_lock_acquire(sess->lock); 421 423 while (!pj_list_empty(&sess->pending_request_list)) { 422 424 pj_stun_tx_data *tdata = sess->pending_request_list.next; … … 427 429 destroy_tdata(tdata); 428 430 } 429 pj_mutex_unlock(sess->mutex); 430 431 pj_mutex_destroy(sess->mutex); 431 pj_lock_release(sess->lock); 432 433 if (sess->delete_lock) { 434 pj_lock_destroy(sess->lock); 435 } 436 432 437 pj_pool_release(sess->pool); 433 438 … … 440 445 { 441 446 PJ_ASSERT_RETURN(sess, PJ_EINVAL); 442 pj_ mutex_lock(sess->mutex);447 pj_lock_acquire(sess->lock); 443 448 sess->user_data = user_data; 444 pj_ mutex_unlock(sess->mutex);449 pj_lock_release(sess->lock); 445 450 return PJ_SUCCESS; 446 451 } … … 450 455 PJ_ASSERT_RETURN(sess, NULL); 451 456 return sess->user_data; 457 } 458 459 PJ_DEF(pj_status_t) pj_stun_session_set_lock( pj_stun_session *sess, 460 pj_lock_t *lock, 461 pj_bool_t auto_del) 462 { 463 pj_lock_t *old_lock = sess->lock; 464 pj_bool_t old_del; 465 466 PJ_ASSERT_RETURN(sess && lock, PJ_EINVAL); 467 468 pj_lock_acquire(old_lock); 469 sess->lock = lock; 470 old_del = sess->delete_lock; 471 sess->delete_lock = auto_del; 472 pj_lock_release(old_lock); 473 474 if (old_lock) 475 pj_lock_destroy(old_lock); 476 477 return PJ_SUCCESS; 452 478 } 453 479 … … 603 629 604 630 /* Start locking the session now */ 605 pj_ mutex_lock(sess->mutex);631 pj_lock_acquire(sess->lock); 606 632 607 633 /* Apply options */ … … 609 635 if (status != PJ_SUCCESS) { 610 636 pj_stun_msg_destroy_tdata(sess, tdata); 611 pj_ mutex_unlock(sess->mutex);637 pj_lock_release(sess->lock); 612 638 LOG_ERR_(sess, "Error applying options", status); 613 639 return status; … … 617 643 if (status != PJ_SUCCESS) { 618 644 pj_stun_msg_destroy_tdata(sess, tdata); 619 pj_ mutex_unlock(sess->mutex);645 pj_lock_release(sess->lock); 620 646 LOG_ERR_(sess, "Error getting creadential's key", status); 621 647 return status; … … 629 655 if (status != PJ_SUCCESS) { 630 656 pj_stun_msg_destroy_tdata(sess, tdata); 631 pj_ mutex_unlock(sess->mutex);657 pj_lock_release(sess->lock); 632 658 LOG_ERR_(sess, "STUN encode() error", status); 633 659 return status; … … 657 683 if (status != PJ_SUCCESS && status != PJ_EPENDING) { 658 684 pj_stun_msg_destroy_tdata(sess, tdata); 659 pj_ mutex_unlock(sess->mutex);685 pj_lock_release(sess->lock); 660 686 LOG_ERR_(sess, "Error sending STUN request", status); 661 687 return status; … … 685 711 if (status != PJ_SUCCESS) { 686 712 pj_stun_msg_destroy_tdata(sess, tdata); 687 pj_ mutex_unlock(sess->mutex);713 pj_lock_release(sess->lock); 688 714 LOG_ERR_(sess, "Error scheduling response timer", status); 689 715 return status; … … 708 734 709 735 710 pj_ mutex_unlock(sess->mutex);736 pj_lock_release(sess->lock); 711 737 return status; 712 738 } … … 750 776 PJ_ASSERT_RETURN(PJ_STUN_IS_REQUEST(tdata->msg->hdr.type), PJ_EINVAL); 751 777 752 pj_ mutex_lock(sess->mutex);778 pj_lock_acquire(sess->lock); 753 779 754 780 if (notify) { … … 760 786 pj_stun_msg_destroy_tdata(sess, tdata); 761 787 762 pj_ mutex_unlock(sess->mutex);788 pj_lock_release(sess->lock); 763 789 return PJ_SUCCESS; 764 790 } … … 775 801 PJ_ASSERT_RETURN(PJ_STUN_IS_REQUEST(tdata->msg->hdr.type), PJ_EINVAL); 776 802 777 pj_ mutex_lock(sess->mutex);803 pj_lock_acquire(sess->lock); 778 804 779 805 status = pj_stun_client_tsx_retransmit(tdata->client_tsx); 780 806 781 pj_ mutex_unlock(sess->mutex);807 pj_lock_release(sess->lock); 782 808 783 809 return status; … … 1054 1080 pj_stun_msg_dump(msg, dump, PJ_STUN_MAX_PKT_LEN, NULL))); 1055 1081 1056 pj_ mutex_lock(sess->mutex);1082 pj_lock_acquire(sess->lock); 1057 1083 1058 1084 /* For requests, check if we have cached response */ … … 1089 1115 1090 1116 on_return: 1091 pj_ mutex_unlock(sess->mutex);1117 pj_lock_release(sess->lock); 1092 1118 1093 1119 pj_pool_release(tmp_pool); -
pjproject/trunk/pjnath/src/pjnath/turn_session.c
r1854 r1862 18 18 */ 19 19 #include <pjnath/turn_session.h> 20 #include <pjnath/errno.h> 20 21 #include <pjlib-util/srv_resolver.h> 21 22 #include <pj/addr_resolv.h> 22 23 #include <pj/assert.h> 23 24 #include <pj/errno.h> 25 #include <pj/hash.h> 26 #include <pj/lock.h> 24 27 #include <pj/log.h> 28 #include <pj/os.h> 25 29 #include <pj/pool.h> 26 30 #include <pj/sock.h> 27 31 28 29 enum state_t 30 { 31 STATE_NULL, 32 STATE_RESOLVING, 33 STATE_RESOLVED, 34 STATE_ALLOCATING, 35 STATE_READY 32 #define MAX_SRV_CNT 4 33 #define REFRESH_SEC_BEFORE 60 34 35 static const char *state_names[] = 36 { 37 "Null", 38 "Resolving", 39 "Resolved", 40 "Allocating", 41 "Ready", 42 "Deallocating", 43 "Deallocated", 44 "Destroying" 36 45 }; 37 46 47 enum timer_id_t 48 { 49 TIMER_NONE, 50 TIMER_KEEP_ALIVE, 51 TIMER_DESTROY 52 }; 53 54 38 55 struct peer 39 56 { 40 unsigned ch_id; 41 pj_sockaddr peer_addr; 57 pj_uint16_t ch_id; 58 pj_bool_t bound; 59 pj_sockaddr addr; 42 60 pj_time_val expiry; 43 pj_uint8_t tsx_id[12]; /* Pending ChannelBind request */44 61 }; 45 62 … … 49 66 const char *obj_name; 50 67 pj_turn_session_cb cb; 51 52 enum state_t state; 68 void *user_data; 69 70 pj_lock_t *lock; 71 int busy; 72 73 pj_turn_state_t state; 74 pj_bool_t pending_destroy; 75 pj_bool_t destroy_notified; 53 76 54 77 pj_stun_session *stun; 55 78 79 unsigned lifetime; 80 int ka_interval; 81 pj_time_val expiry; 82 83 pj_timer_heap_t *timer_heap; 84 pj_timer_entry timer; 85 56 86 pj_dns_async_query *dns_async; 57 58 unsigned srv_addr_cnt; 87 pj_uint16_t default_port; 88 89 pj_uint16_t af; 90 pj_turn_tp_type tp_type; 91 pj_uint16_t srv_addr_cnt; 59 92 pj_sockaddr *srv_addr_list; 60 93 pj_sockaddr *srv_addr; … … 63 96 pj_turn_alloc_param alloc_param; 64 97 98 pj_hash_table_t *peer_table; 99 65 100 /* tx_pkt must be 16bit aligned */ 66 101 pj_uint8_t tx_pkt[PJ_TURN_MAX_PKT_LEN]; … … 73 108 * Prototypes. 74 109 */ 110 static void sess_shutdown(pj_turn_session *sess, 111 pj_bool_t notify, 112 pj_status_t status); 113 static void do_destroy(pj_turn_session *sess); 114 static void send_refresh(pj_turn_session *sess, int lifetime); 75 115 static pj_status_t stun_on_send_msg(pj_stun_session *sess, 76 116 const void *pkt, … … 93 133 pj_status_t status, 94 134 const pj_dns_srv_record *rec); 95 static void dns_a_resolver_cb(void *user_data,96 pj_status_t status,97 pj_dns_parsed_packet *response);98 135 static struct peer *lookup_peer_by_addr(pj_turn_session *sess, 99 136 const pj_sockaddr_t *addr, 100 137 unsigned addr_len, 101 pj_bool_t update); 138 pj_bool_t update, 139 pj_bool_t bind_channel); 102 140 static struct peer *lookup_peer_by_chnum(pj_turn_session *sess, 103 unsigned chnum); 104 141 pj_uint16_t chnum); 142 static void on_timer_event(pj_timer_heap_t *th, pj_timer_entry *e); 143 144 145 /** 146 * Get TURN state name. 147 */ 148 PJ_DEF(const char*) pj_turn_state_name(pj_turn_state_t state) 149 { 150 return state_names[state]; 151 } 105 152 106 153 /* … … 108 155 */ 109 156 PJ_DEF(pj_status_t) pj_turn_session_create( pj_stun_config *cfg, 157 const char *name, 158 int af, 159 pj_turn_tp_type tp_type, 110 160 const pj_turn_session_cb *cb, 161 void *user_data, 162 unsigned options, 111 163 pj_turn_session **p_sess) 112 164 { … … 114 166 pj_turn_session *sess; 115 167 pj_stun_session_cb stun_cb; 168 pj_lock_t *null_lock; 116 169 pj_status_t status; 117 170 118 171 PJ_ASSERT_RETURN(cfg && cfg->pf && cb && p_sess, PJ_EINVAL); 172 PJ_ASSERT_RETURN(cb->on_send_pkt, PJ_EINVAL); 173 174 PJ_UNUSED_ARG(options); 175 176 if (name == NULL) 177 name = "turn%p"; 119 178 120 179 /* Allocate and create TURN session */ 121 pool = pj_pool_create(cfg->pf, "turn%p", 1000, 1000, NULL);180 pool = pj_pool_create(cfg->pf, name, 1000, 1000, NULL); 122 181 sess = PJ_POOL_ZALLOC_T(pool, pj_turn_session); 123 182 sess->pool = pool; 124 183 sess->obj_name = pool->obj_name; 125 184 sess->timer_heap = cfg->timer_heap; 185 sess->af = (pj_uint16_t)af; 186 sess->tp_type = tp_type; 187 sess->ka_interval = PJ_TURN_KEEP_ALIVE_SEC; 188 sess->user_data = user_data; 189 190 /* Copy callback */ 126 191 pj_memcpy(&sess->cb, cb, sizeof(*cb)); 192 193 /* Peer hash table */ 194 sess->peer_table = pj_hash_create(pool, PJ_TURN_PEER_HTABLE_SIZE); 195 196 /* Session lock */ 197 status = pj_lock_create_recursive_mutex(pool, sess->obj_name, 198 &sess->lock); 199 if (status != PJ_SUCCESS) { 200 do_destroy(sess); 201 return status; 202 } 203 204 /* Timer */ 205 pj_timer_entry_init(&sess->timer, TIMER_NONE, sess, &on_timer_event); 127 206 128 207 /* Create STUN session */ … … 134 213 &sess->stun); 135 214 if (status != PJ_SUCCESS) { 136 pj_turn_session_destroy(sess);215 do_destroy(sess); 137 216 return status; 138 217 } 139 218 140 /* Done for now */ 219 /* Replace mutex in STUN session with a NULL mutex, since access to 220 * STUN session is serialized. 221 */ 222 status = pj_lock_create_null_mutex(pool, name, &null_lock); 223 if (status != PJ_SUCCESS) { 224 do_destroy(sess); 225 return status; 226 } 227 pj_stun_session_set_lock(sess->stun, null_lock, PJ_TRUE); 228 229 /* Done */ 230 231 PJ_LOG(4,(sess->obj_name, "TURN client session created")); 232 141 233 *p_sess = sess; 142 234 return PJ_SUCCESS; … … 144 236 145 237 146 /* 147 * Destroy TURN client session. 238 /* Destroy */ 239 static void do_destroy(pj_turn_session *sess) 240 { 241 /* Lock session */ 242 if (sess->lock) { 243 pj_lock_acquire(sess->lock); 244 } 245 246 /* Cancel pending timer, if any */ 247 if (sess->timer.id != TIMER_NONE) { 248 pj_timer_heap_cancel(sess->timer_heap, &sess->timer); 249 sess->timer.id = TIMER_NONE; 250 } 251 252 /* Destroy STUN session */ 253 if (sess->stun) { 254 pj_stun_session_destroy(sess->stun); 255 sess->stun = NULL; 256 } 257 258 /* Destroy lock */ 259 if (sess->lock) { 260 pj_lock_release(sess->lock); 261 pj_lock_destroy(sess->lock); 262 sess->lock = NULL; 263 } 264 265 /* Destroy pool */ 266 if (sess->pool) { 267 pj_pool_t *pool = sess->pool; 268 269 PJ_LOG(4,(sess->obj_name, "TURN client session destroyed")); 270 271 sess->pool = NULL; 272 pj_pool_release(pool); 273 } 274 } 275 276 277 /* Set session state */ 278 static void set_state(pj_turn_session *sess, enum pj_turn_state_t state) 279 { 280 pj_turn_state_t old_state = sess->state; 281 282 PJ_LOG(4,(sess->obj_name, "State changed %s --> %s", 283 state_names[old_state], state_names[state])); 284 sess->state = state; 285 286 if (sess->cb.on_state) { 287 (*sess->cb.on_state)(sess, old_state, state); 288 } 289 } 290 291 /* 292 * Notify application and shutdown the TURN session. 293 */ 294 static void sess_shutdown(pj_turn_session *sess, 295 pj_bool_t notify, 296 pj_status_t status) 297 { 298 pj_bool_t can_destroy = PJ_TRUE; 299 300 PJ_UNUSED_ARG(notify); 301 302 PJ_LOG(4,(sess->obj_name, "Request to shutdown in state %s, cause:%d", 303 state_names[sess->state], status)); 304 305 switch (sess->state) { 306 case PJ_TURN_STATE_NULL: 307 break; 308 case PJ_TURN_STATE_RESOLVING: 309 pj_assert(sess->dns_async != NULL); 310 pj_dns_resolver_cancel_query(sess->dns_async, PJ_FALSE); 311 sess->dns_async = NULL; 312 break; 313 case PJ_TURN_STATE_RESOLVED: 314 break; 315 case PJ_TURN_STATE_ALLOCATING: 316 /* We need to wait until allocation complete */ 317 sess->pending_destroy = PJ_TRUE; 318 can_destroy = PJ_FALSE; 319 break; 320 case PJ_TURN_STATE_READY: 321 /* Send REFRESH with LIFETIME=0 */ 322 can_destroy = PJ_FALSE; 323 sess->pending_destroy = PJ_TRUE; 324 break; 325 case PJ_TURN_STATE_DEALLOCATING: 326 can_destroy = PJ_FALSE; 327 /* This may recursively call this function again with 328 * state==PJ_TURN_STATE_DEALLOCATED. 329 */ 330 send_refresh(sess, 0); 331 break; 332 case PJ_TURN_STATE_DEALLOCATED: 333 break; 334 } 335 336 if (can_destroy) { 337 /* Schedule destroy */ 338 pj_time_val delay = {0, 0}; 339 340 if (sess->timer.id != TIMER_NONE) { 341 pj_timer_heap_cancel(sess->timer_heap, &sess->timer); 342 sess->timer.id = TIMER_NONE; 343 } 344 345 set_state(sess, PJ_TURN_STATE_DESTROYING); 346 347 sess->timer.id = TIMER_DESTROY; 348 pj_timer_heap_schedule(sess->timer_heap, &sess->timer, &delay); 349 } 350 } 351 352 353 /* 354 * Public API to destroy TURN client session. 148 355 */ 149 356 PJ_DEF(pj_status_t) pj_turn_session_destroy(pj_turn_session *sess) … … 151 358 PJ_ASSERT_RETURN(sess, PJ_EINVAL); 152 359 153 /* TODO */ 154 } 155 156 157 /* 158 * Notify application and destroy the TURN session. 159 */ 160 static void destroy(pj_turn_session *sess, 161 pj_bool_t notify, 162 pj_status_t status) 163 { 360 pj_lock_acquire(sess->lock); 361 362 sess_shutdown(sess, PJ_FALSE, PJ_SUCCESS); 363 364 pj_lock_release(sess->lock); 365 366 return PJ_SUCCESS; 367 } 368 369 370 /* 371 * Re-assign user data. 372 */ 373 PJ_DEF(pj_status_t) pj_turn_session_set_user_data( pj_turn_session *sess, 374 void *user_data) 375 { 376 sess->user_data = user_data; 377 return PJ_SUCCESS; 378 } 379 380 381 /** 382 * Retrieve user data. 383 */ 384 PJ_DEF(void*) pj_turn_session_get_user_data(pj_turn_session *sess) 385 { 386 return sess->user_data; 164 387 } 165 388 … … 170 393 PJ_DEF(pj_status_t) pj_turn_session_set_server( pj_turn_session *sess, 171 394 const pj_str_t *domain, 172 const pj_str_t *res_name,173 395 int default_port, 174 396 pj_dns_resolver *resolver) … … 177 399 178 400 PJ_ASSERT_RETURN(sess && domain, PJ_EINVAL); 179 180 if (res_name) { 181 /* res_name is specified, resolve with DNS SRV resolution. 182 * Resolver must be specified in this case. 401 PJ_ASSERT_RETURN(sess->state == PJ_TURN_STATE_NULL, PJ_EINVALIDOP); 402 403 pj_lock_acquire(sess->lock); 404 405 if (resolver) { 406 /* Resolve with DNS SRV resolution, and fallback to DNS A resolution 407 * if default_port is specified. 183 408 */ 184 PJ_ASSERT_RETURN(resolver, PJ_EINVAL); 185 186 sess->state = STATE_RESOLVING; 187 status = pj_dns_srv_resolve(domain, res_name, default_port, sess->pool, 188 resolver, PJ_DNS_SRV_FALLBACK_A, sess, 409 unsigned opt = 0; 410 pj_str_t res_name; 411 412 switch (sess->tp_type) { 413 case PJ_TURN_TP_UDP: 414 res_name = pj_str("_turn._udp."); 415 break; 416 case PJ_TURN_TP_TCP: 417 res_name = pj_str("_turn._tcp."); 418 break; 419 case PJ_TURN_TP_TLS: 420 res_name = pj_str("_turns._tcp."); 421 break; 422 default: 423 status = PJNATH_ETURNINTP; 424 goto on_return; 425 } 426 427 /* Fallback to DNS A only if default port is specified */ 428 if (default_port>0 && default_port<65536) { 429 opt = PJ_DNS_SRV_FALLBACK_A; 430 sess->default_port = (pj_uint16_t)default_port; 431 } 432 433 set_state(sess, PJ_TURN_STATE_RESOLVING); 434 status = pj_dns_srv_resolve(domain, &res_name, default_port, 435 sess->pool, resolver, opt, sess, 189 436 &dns_srv_resolver_cb, &sess->dns_async); 190 437 if (status != PJ_SUCCESS) { 191 se ss->state = STATE_NULL;192 return status;193 } 194 195 } else if (resolver){196 /* res_name is not specified, but resolver is specified.197 * Resolve domain as a hostname with DNS A resolution.438 set_state(sess, PJ_TURN_STATE_NULL); 439 goto on_return; 440 } 441 442 } else { 443 /* Resolver is not specified, resolve with standard gethostbyname(). 444 * The default_port MUST be specified in this case. 198 445 */ 199 sess->state = STATE_RESOLVING; 200 status = pj_dns_resolver_start_query(resolver, domain, PJ_DNS_TYPE_A, 201 0, &dns_a_resolver_cb, 202 sess, &sess->dns_async); 203 if (status != PJ_SUCCESS) { 204 sess->state = STATE_NULL; 205 return status; 206 } 207 208 } else { 209 /* Both res_name and resolver is not specified. 210 * Resolve with standard gethostbyname() 211 */ 212 pj_addrinfo ai[3]; 213 unsigned i, cnt = PJ_ARRAY_SIZE(ai); 214 215 status = pj_getaddrinfo(pj_AF_INET(), domain, &cnt, ai); 446 pj_addrinfo *ai; 447 unsigned i, cnt; 448 449 /* Default port must be specified */ 450 PJ_ASSERT_RETURN(default_port>0 && default_port<65536, PJ_EINVAL); 451 sess->default_port = (pj_uint16_t)default_port; 452 453 cnt = MAX_SRV_CNT; 454 ai = (pj_addrinfo*) 455 pj_pool_calloc(sess->pool, cnt, sizeof(pj_addrinfo)); 456 457 status = pj_getaddrinfo(sess->af, domain, &cnt, ai); 216 458 if (status != PJ_SUCCESS) 217 return status;218 219 sess->srv_addr_cnt = cnt;459 goto on_return; 460 461 sess->srv_addr_cnt = (pj_uint16_t)cnt; 220 462 sess->srv_addr_list = (pj_sockaddr*) 221 463 pj_pool_calloc(sess->pool, cnt, 222 464 sizeof(pj_sockaddr)); 223 465 for (i=0; i<cnt; ++i) { 224 pj_memcpy(&sess->srv_addr_list[i], &ai[i].ai_addr, 225 sizeof(pj_sockaddr)); 466 pj_sockaddr *addr = &sess->srv_addr_list[i]; 467 pj_memcpy(addr, &ai[i].ai_addr, sizeof(pj_sockaddr)); 468 addr->addr.sa_family = sess->af; 469 addr->ipv4.sin_port = pj_htons(sess->default_port); 226 470 } 227 471 228 472 sess->srv_addr = &sess->srv_addr_list[0]; 229 sess->state = STATE_RESOLVED; 230 } 231 232 return PJ_SUCCESS; 473 set_state(sess, PJ_TURN_STATE_RESOLVED); 474 } 475 476 on_return: 477 pj_lock_release(sess->lock); 478 return status; 233 479 } 234 480 … … 241 487 { 242 488 PJ_ASSERT_RETURN(sess && cred, PJ_EINVAL); 489 490 pj_lock_acquire(sess->lock); 491 243 492 pj_stun_session_set_credential(sess->stun, cred); 493 494 pj_lock_release(sess->lock); 495 244 496 return PJ_SUCCESS; 245 497 } … … 256 508 257 509 PJ_ASSERT_RETURN(sess, PJ_EINVAL); 258 PJ_ASSERT_RETURN(sess->state <= STATE_RESOLVED, PJ_EINVALIDOP); 259 260 if (sess->state < STATE_RESOLVED) { 261 if (param) 510 PJ_ASSERT_RETURN(sess->state>PJ_TURN_STATE_NULL && sess->state<=PJ_TURN_STATE_RESOLVED, 511 PJ_EINVALIDOP); 512 513 pj_lock_acquire(sess->lock); 514 515 if (sess->state < PJ_TURN_STATE_RESOLVED) { 516 if (param && param != &sess->alloc_param) 262 517 pj_memcpy(&sess->alloc_param, param, sizeof(*param)); 263 518 sess->pending_alloc = PJ_TRUE; 519 520 PJ_LOG(4,(sess->obj_name, "Pending ALLOCATE in state %s", 521 state_names[sess->state])); 522 523 pj_lock_release(sess->lock); 264 524 return PJ_SUCCESS; 265 525 … … 267 527 268 528 /* Ready to allocate */ 269 pj_assert(sess->state == STATE_RESOLVED);529 pj_assert(sess->state == PJ_TURN_STATE_RESOLVED); 270 530 271 531 /* Create a bare request */ 272 532 status = pj_stun_session_create_req(sess->stun, PJ_STUN_ALLOCATE_REQUEST, 273 533 PJ_STUN_MAGIC, NULL, &tdata); 274 if (status != PJ_SUCCESS) 534 if (status != PJ_SUCCESS) { 535 pj_lock_release(sess->lock); 275 536 return status; 537 } 276 538 277 539 /* MUST include REQUESTED-TRANSPORT attribute */ … … 294 556 } 295 557 296 /* Se lect server address*/558 /* Server address must be set */ 297 559 pj_assert(sess->srv_addr != NULL); 298 560 299 561 /* Send request */ 300 se ss->state = STATE_ALLOCATING;562 set_state(sess, PJ_TURN_STATE_ALLOCATING); 301 563 status = pj_stun_session_send_msg(sess->stun, PJ_FALSE, sess->srv_addr, 302 564 pj_sockaddr_get_len(sess->srv_addr), 303 565 tdata); 304 566 if (status != PJ_SUCCESS) { 305 sess->state = STATE_RESOLVED; 306 } 307 567 /* Set state back to RESOLVED. We don't want to destroy session now, 568 * let the application do it if it wants to. 569 */ 570 set_state(sess, PJ_TURN_STATE_RESOLVED); 571 } 572 573 pj_lock_release(sess->lock); 308 574 return status; 575 } 576 577 578 /* 579 * Send REFRESH 580 */ 581 static void send_refresh(pj_turn_session *sess, int lifetime) 582 { 583 pj_stun_tx_data *tdata; 584 pj_status_t status; 585 586 PJ_ASSERT_ON_FAIL(sess->state==PJ_TURN_STATE_READY, return); 587 588 /* Create a bare REFRESH request */ 589 status = pj_stun_session_create_req(sess->stun, PJ_STUN_REFRESH_REQUEST, 590 PJ_STUN_MAGIC, NULL, &tdata); 591 if (status != PJ_SUCCESS) 592 goto on_error; 593 594 /* Add LIFETIME */ 595 if (lifetime >= 0) { 596 pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg, 597 PJ_STUN_ATTR_LIFETIME, lifetime); 598 } 599 600 /* Send request */ 601 if (lifetime == 0) { 602 set_state(sess, PJ_TURN_STATE_DEALLOCATING); 603 } 604 605 status = pj_stun_session_send_msg(sess->stun, PJ_FALSE, sess->srv_addr, 606 pj_sockaddr_get_len(sess->srv_addr), 607 tdata); 608 if (status != PJ_SUCCESS) 609 goto on_error; 610 611 return; 612 613 on_error: 614 if (lifetime == 0) { 615 set_state(sess, PJ_TURN_STATE_DEALLOCATED); 616 sess_shutdown(sess, PJ_FALSE, status); 617 } 309 618 } 310 619 … … 316 625 const pj_uint8_t *pkt, 317 626 unsigned pkt_len, 318 const pj_sockaddr_t * peer_addr,627 const pj_sockaddr_t *addr, 319 628 unsigned addr_len) 320 629 { 321 630 struct peer *peer; 322 323 PJ_ASSERT_RETURN(sess && pkt && pkt_len && peer_addr && addr_len, 631 pj_status_t status; 632 633 PJ_ASSERT_RETURN(sess && pkt && pkt_len && addr && addr_len, 324 634 PJ_EINVAL); 325 635 326 636 /* Return error if we're not ready */ 327 if (sess->state != STATE_READY) {637 if (sess->state != PJ_TURN_STATE_READY) { 328 638 return PJ_EIGNORED; 329 639 } 640 641 /* Lock session now */ 642 pj_lock_acquire(sess->lock); 330 643 331 644 /* Lookup peer to see whether we've assigned a channel number 332 645 * to this peer. 333 646 */ 334 peer = lookup_peer_by_addr(sess, peer_addr, addr_len, PJ_TRUE);647 peer = lookup_peer_by_addr(sess, addr, addr_len, PJ_TRUE, PJ_FALSE); 335 648 pj_assert(peer != NULL); 336 649 337 if (peer->ch_id != PJ_TURN_INVALID_CHANNEL ) {650 if (peer->ch_id != PJ_TURN_INVALID_CHANNEL && peer->bound) { 338 651 /* Peer is assigned Channel number, we can use ChannelData */ 339 652 pj_turn_channel_data *cd = (pj_turn_channel_data*)sess->tx_pkt; … … 341 654 pj_assert(sizeof(*cd)==4); 342 655 343 if (pkt_len > sizeof(sess->tx_pkt)-sizeof(*cd)) 344 return PJ_ETOOBIG; 656 if (pkt_len > sizeof(sess->tx_pkt)-sizeof(*cd)) { 657 status = PJ_ETOOBIG; 658 goto on_return; 659 } 345 660 346 661 cd->ch_number = pj_htons((pj_uint16_t)peer->ch_id); … … 350 665 pj_assert(sess->srv_addr != NULL); 351 666 352 returnsess->cb.on_send_pkt(sess, sess->tx_pkt, pkt_len+sizeof(*cd),353 sess->srv_addr,354 pj_sockaddr_get_len(sess->srv_addr));667 status = sess->cb.on_send_pkt(sess, sess->tx_pkt, pkt_len+sizeof(*cd), 668 sess->srv_addr, 669 pj_sockaddr_get_len(sess->srv_addr)); 355 670 356 671 } else { … … 359 674 */ 360 675 pj_stun_tx_data *tdata; 361 pj_status_t status;362 676 363 677 /* Create blank SEND-INDICATION */ … … 365 679 PJ_STUN_SEND_INDICATION, &tdata); 366 680 if (status != PJ_SUCCESS) 367 return status;681 goto on_return; 368 682 369 683 /* Add PEER-ADDRESS */ 370 684 pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg, 371 685 PJ_STUN_ATTR_PEER_ADDR, PJ_TRUE, 372 peer_addr, addr_len);686 addr, addr_len); 373 687 374 688 /* Add DATA attribute */ … … 377 691 378 692 /* Send the indication */ 379 return pj_stun_session_send_msg(sess->stun, PJ_FALSE, sess->srv_addr, 380 pj_sockaddr_get_len(sess->srv_addr), 381 tdata); 382 } 693 status = pj_stun_session_send_msg(sess->stun, PJ_FALSE, sess->srv_addr, 694 pj_sockaddr_get_len(sess->srv_addr), 695 tdata); 696 } 697 698 on_return: 699 pj_lock_release(sess->lock); 700 return status; 383 701 } 384 702 … … 393 711 struct peer *peer; 394 712 pj_stun_tx_data *tdata; 395 unsignedch_num;713 pj_uint16_t ch_num; 396 714 pj_status_t status; 397 715 398 PJ_ASSERT_RETURN(sess && peer && addr_len, PJ_EINVAL); 716 PJ_ASSERT_RETURN(sess && peer_adr && addr_len, PJ_EINVAL); 717 PJ_ASSERT_RETURN(sess->state == PJ_TURN_STATE_READY, PJ_EINVALIDOP); 718 719 pj_lock_acquire(sess->lock); 399 720 400 721 /* Create blank ChannelBind request */ … … 403 724 PJ_STUN_MAGIC, NULL, &tdata); 404 725 if (status != PJ_SUCCESS) 405 return status;726 goto on_return; 406 727 407 728 /* Lookup peer */ 408 peer = lookup_peer_by_addr(sess, peer_adr, addr_len, PJ_TRUE );729 peer = lookup_peer_by_addr(sess, peer_adr, addr_len, PJ_TRUE, PJ_FALSE); 409 730 pj_assert(peer); 410 731 732 /* Associate peer data structure with tdata for future reference 733 * when we receive the ChannelBind response. 734 */ 735 tdata->user_data = peer; 736 411 737 if (peer->ch_id != PJ_TURN_INVALID_CHANNEL) { 738 /* Channel is already bound. This is a refresh request. */ 412 739 ch_num = peer->ch_id; 413 740 } else { 414 PJ_ASSERT_RETURN(sess->next_ch <= PJ_TURN_CHANNEL_MAX, PJ_ETOOMANY); 415 ch_num = sess->next_ch++; 741 PJ_ASSERT_ON_FAIL(sess->next_ch <= PJ_TURN_CHANNEL_MAX, 742 {status=PJ_ETOOMANY; goto on_return;}); 743 peer->ch_id = ch_num = sess->next_ch++; 416 744 } 417 745 … … 426 754 peer_adr, addr_len); 427 755 428 /* Save transaction ID to peer */429 pj_memcpy(peer->tsx_id, tdata->msg->hdr.tsx_id, sizeof(peer->tsx_id));430 431 756 /* Send the request */ 432 return pj_stun_session_send_msg(sess->stun, PJ_FALSE, sess->srv_addr, 433 pj_sockaddr_get_len(sess->srv_addr), 434 tdata); 757 status = pj_stun_session_send_msg(sess->stun, PJ_FALSE, sess->srv_addr, 758 pj_sockaddr_get_len(sess->srv_addr), 759 tdata); 760 761 on_return: 762 pj_lock_release(sess->lock); 763 return status; 435 764 } 436 765 … … 446 775 { 447 776 pj_bool_t is_stun; 777 pj_status_t status; 448 778 449 779 /* Packet could be ChannelData or STUN message (response or 450 780 * indication). 451 781 */ 782 783 /* Start locking the session */ 784 pj_lock_acquire(sess->lock); 785 452 786 /* Quickly check if this is STUN message */ 453 787 is_stun = ((pkt[0] & 0xC0) == 0); … … 460 794 if (is_datagram) 461 795 options |= PJ_STUN_IS_DATAGRAM; 462 returnpj_stun_session_on_rx_pkt(sess->stun, pkt, pkt_len,796 status=pj_stun_session_on_rx_pkt(sess->stun, pkt, pkt_len, 463 797 options, NULL, 464 798 sess->srv_addr, 465 799 pj_sockaddr_get_len(sess->srv_addr)); 466 } else { 467 /* This must be ChannelData */ 800 801 } else if (sess->cb.on_rx_data) { 802 803 /* This must be ChannelData. Only makes sense when on_rx_data() is 804 * implemented by application. 805 */ 468 806 pj_turn_channel_data cd; 469 807 struct peer *peer; 470 808 809 PJ_ASSERT_RETURN(pkt_len >= 4, PJ_ETOOSMALL); 810 471 811 /* Lookup peer */ 472 812 pj_memcpy(&cd, pkt, sizeof(pj_turn_channel_data)); 473 peer = lookup_peer_by_chnum(sess, pj_ntohs(cd.ch_number)); 474 if (!peer) 475 return PJ_ENOTFOUND; 813 cd.ch_number = pj_ntohs(cd.ch_number); 814 cd.length = pj_ntohs(cd.length); 815 peer = lookup_peer_by_chnum(sess, cd.ch_number); 816 if (!peer || !peer->bound) { 817 status = PJ_ENOTFOUND; 818 goto on_return; 819 } 820 821 /* Check that size is correct, for UDP */ 822 if (pkt_len < cd.length+sizeof(cd)) { 823 status = PJ_ETOOSMALL; 824 goto on_return; 825 } 476 826 477 827 /* Notify application */ 478 if (sess->cb.on_rx_data) { 479 (*sess->cb.on_rx_data)(sess, pkt+sizeof(cd), pj_ntohs(cd.length), 480 &peer->peer_addr, 481 pj_sockaddr_get_len(&peer->peer_addr)); 482 } 483 484 return PJ_SUCCESS; 485 } 828 (*sess->cb.on_rx_data)(sess, pkt+sizeof(cd), cd.length, 829 &peer->addr, 830 pj_sockaddr_get_len(&peer->addr)); 831 832 status = PJ_SUCCESS; 833 834 } else { 835 /* This is ChannelData and application doesn't implement 836 * on_rx_data() callback. Just ignore the packet. 837 */ 838 status = PJ_SUCCESS; 839 } 840 841 on_return: 842 pj_lock_release(sess->lock); 843 return status; 486 844 } 487 845 … … 503 861 } 504 862 863 864 /* 865 * Handle failed ALLOCATE or REFRESH request. This may switch to alternate 866 * server if we have one. 867 */ 868 static void on_session_fail( pj_turn_session *sess, 869 enum pj_stun_method_e method, 870 pj_status_t status, 871 const pj_str_t *reason) 872 { 873 do { 874 pj_str_t reason1; 875 char err_msg[PJ_ERR_MSG_SIZE]; 876 877 if (reason == NULL) { 878 pj_strerror(status, err_msg, sizeof(err_msg)); 879 reason1 = pj_str(err_msg); 880 reason = &reason1; 881 } 882 883 PJ_LOG(4,(sess->obj_name, "%s error: %.*s", 884 pj_stun_get_method_name(method), 885 (int)reason->slen, reason->ptr)); 886 887 /* If this is ALLOCATE response and we don't have more server 888 * addresses to try, notify application and destroy the TURN 889 * session. 890 */ 891 if (method==PJ_STUN_ALLOCATE_METHOD && 892 sess->srv_addr == &sess->srv_addr_list[sess->srv_addr_cnt-1]) 893 { 894 895 set_state(sess, PJ_TURN_STATE_DEALLOCATED); 896 sess_shutdown(sess, PJ_TRUE, status); 897 return; 898 } 899 900 /* Otherwise if this is REFRESH response, notify application 901 * that session has been TERMINATED. 902 */ 903 if (method==PJ_STUN_REFRESH_METHOD) { 904 set_state(sess, PJ_TURN_STATE_DEALLOCATED); 905 sess_shutdown(sess, PJ_TRUE, status); 906 return; 907 } 908 909 /* Try next server */ 910 ++sess->srv_addr; 911 reason = NULL; 912 913 PJ_LOG(4,(sess->obj_name, "Trying next server")); 914 915 status = pj_turn_session_alloc(sess, NULL); 916 917 } while (status != PJ_SUCCESS); 918 } 919 920 921 /* 922 * Handle successful response to ALLOCATE or REFRESH request. 923 */ 924 static void on_allocate_success(pj_turn_session *sess, 925 enum pj_stun_method_e method, 926 const pj_stun_msg *msg) 927 { 928 const pj_stun_lifetime_attr *lf_attr; 929 const pj_stun_relay_addr_attr *raddr_attr; 930 pj_str_t s; 931 pj_time_val timeout; 932 933 /* Must have LIFETIME attribute */ 934 lf_attr = (const pj_stun_lifetime_attr*) 935 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_LIFETIME, 0); 936 if (lf_attr == NULL) { 937 on_session_fail(sess, method, PJNATH_EINSTUNMSG, 938 pj_cstr(&s, "Error: Missing LIFETIME attribute")); 939 return; 940 } 941 942 /* If LIFETIME is zero, this is a deallocation */ 943 if (lf_attr->value == 0) { 944 pj_bool_t notify = sess->state < PJ_TURN_STATE_DEALLOCATING; 945 set_state(sess, PJ_TURN_STATE_DEALLOCATED); 946 sess_shutdown(sess, notify, PJ_SUCCESS); 947 return; 948 } 949 950 /* Update lifetime and keep-alive interval */ 951 sess->lifetime = lf_attr->value; 952 pj_gettimeofday(&sess->expiry); 953 954 if (sess->lifetime < PJ_TURN_KEEP_ALIVE_SEC) { 955 if (sess->lifetime <= 2) { 956 on_session_fail(sess, method, PJ_ETOOSMALL, 957 pj_cstr(&s, "Error: LIFETIME too small")); 958 return; 959 } 960 sess->ka_interval = sess->lifetime - 2; 961 sess->expiry.sec += (sess->ka_interval-1); 962 } else { 963 int timeout; 964 965 sess->ka_interval = PJ_TURN_KEEP_ALIVE_SEC; 966 967 timeout = sess->lifetime - PJ_TURN_REFRESH_SEC_BEFORE; 968 if (timeout < sess->ka_interval) 969 timeout = sess->ka_interval - 1; 970 971 sess->expiry.sec += timeout; 972 } 973 974 /* Check that relayed transport address contains correct 975 * address family. 976 */ 977 raddr_attr = (const pj_stun_relay_addr_attr*) 978 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_RELAY_ADDR, 0); 979 if (raddr_attr == NULL && method==PJ_STUN_ALLOCATE_METHOD) { 980 on_session_fail(sess, method, PJNATH_EINSTUNMSG, 981 pj_cstr(&s, "Error: Received ALLOCATE without " 982 "RELAY-ADDRESS attribute")); 983 return; 984 } 985 if (raddr_attr && raddr_attr->sockaddr.addr.sa_family != sess->af) { 986 on_session_fail(sess, method, PJNATH_EINSTUNMSG, 987 pj_cstr(&s, "Error: RELAY-ADDRESS with non IPv4" 988 " address family is not supported " 989 "for now")); 990 return; 991 } 992 993 994 /* Success */ 995 996 /* Cancel existing keep-alive timer, if any */ 997 pj_assert(sess->timer.id != TIMER_DESTROY); 998 999 if (sess->timer.id != TIMER_NONE) { 1000 pj_timer_heap_cancel(sess->timer_heap, &sess->timer); 1001 sess->timer.id = TIMER_NONE; 1002 } 1003 1004 /* Start keep-alive timer once allocation succeeds */ 1005 timeout.sec = sess->ka_interval; 1006 timeout.msec = 0; 1007 1008 sess->timer.id = TIMER_KEEP_ALIVE; 1009 pj_timer_heap_schedule(sess->timer_heap, &sess->timer, &timeout); 1010 1011 set_state(sess, PJ_TURN_STATE_READY); 1012 } 505 1013 506 1014 /* … … 515 1023 { 516 1024 pj_turn_session *sess; 517 int method = PJ_STUN_GET_METHOD(response->hdr.type); 1025 int method = PJ_STUN_GET_METHOD(tdata->msg->hdr.type); 1026 1027 PJ_UNUSED_ARG(src_addr); 1028 PJ_UNUSED_ARG(src_addr_len); 518 1029 519 1030 sess = (pj_turn_session*)pj_stun_session_get_user_data(stun); … … 521 1032 if (method == PJ_STUN_ALLOCATE_METHOD) { 522 1033 /* Handle ALLOCATE response */ 523 if (PJ_STUN_IS_SUCCESS_RESPONSE(response->hdr.type)) { 1034 if (status==PJ_SUCCESS && 1035 PJ_STUN_IS_SUCCESS_RESPONSE(response->hdr.type)) 1036 { 1037 524 1038 /* Successful Allocate response */ 1039 on_allocate_success(sess, method, response); 525 1040 526 1041 } else { 527 /* Error Allocate response */ 528 1042 /* Failed Allocate request */ 1043 const pj_str_t *err_msg = NULL; 1044 1045 if (status == PJ_SUCCESS) { 1046 const pj_stun_errcode_attr *err_attr; 1047 err_attr = (const pj_stun_errcode_attr*) 1048 pj_stun_msg_find_attr(response, 1049 PJ_STUN_ATTR_ERROR_CODE, 0); 1050 if (err_attr) { 1051 status = PJ_STATUS_FROM_STUN_CODE(err_attr->err_code); 1052 err_msg = &err_attr->reason; 1053 } else { 1054 status = PJNATH_EINSTUNMSG; 1055 } 1056 } 1057 1058 on_session_fail(sess, method, status, err_msg); 1059 } 1060 1061 } else if (method == PJ_STUN_REFRESH_METHOD) { 1062 /* Handle Refresh response */ 1063 if (status==PJ_SUCCESS && 1064 PJ_STUN_IS_SUCCESS_RESPONSE(response->hdr.type)) 1065 { 1066 /* Success, schedule next refresh. */ 1067 on_allocate_success(sess, method, response); 1068 1069 } else { 1070 /* Failed Refresh request */ 1071 const pj_str_t *err_msg = NULL; 1072 1073 if (status == PJ_SUCCESS) { 1074 const pj_stun_errcode_attr *err_attr; 1075 err_attr = (const pj_stun_errcode_attr*) 1076 pj_stun_msg_find_attr(response, 1077 PJ_STUN_ATTR_ERROR_CODE, 0); 1078 if (err_attr) { 1079 status = PJ_STATUS_FROM_STUN_CODE(err_attr->err_code); 1080 err_msg = &err_attr->reason; 1081 } else { 1082 status = PJNATH_EINSTUNMSG; 1083 } 1084 } 1085 1086 /* Notify and destroy */ 1087 on_session_fail(sess, method, status, err_msg); 529 1088 } 530 1089 531 1090 } else if (method == PJ_STUN_CHANNEL_BIND_METHOD) { 532 1091 /* Handle ChannelBind response */ 533 if (PJ_STUN_IS_SUCCESS_RESPONSE(response->hdr.type)) { 1092 if (status==PJ_SUCCESS && 1093 PJ_STUN_IS_SUCCESS_RESPONSE(response->hdr.type)) 1094 { 534 1095 /* Successful ChannelBind response */ 1096 struct peer *peer = (struct peer*)tdata->user_data; 1097 1098 pj_assert(peer->ch_id != PJ_TURN_INVALID_CHANNEL); 1099 peer->bound = PJ_TRUE; 1100 1101 /* Update hash table */ 1102 lookup_peer_by_addr(sess, &peer->addr, 1103 pj_sockaddr_get_len(&peer->addr), 1104 PJ_TRUE, PJ_TRUE); 535 1105 536 1106 } else { 537 /* Error ChannelBind response */ 538 1107 /* Failed ChannelBind response */ 1108 pj_str_t err_msg = {"", 0}; 1109 1110 if (status == PJ_SUCCESS) { 1111 const pj_stun_errcode_attr *err_attr; 1112 err_attr = (const pj_stun_errcode_attr*) 1113 pj_stun_msg_find_attr(response, 1114 PJ_STUN_ATTR_ERROR_CODE, 0); 1115 if (err_attr) { 1116 status = PJ_STATUS_FROM_STUN_CODE(err_attr->err_code); 1117 err_msg = err_attr->reason; 1118 } else { 1119 status = PJNATH_EINSTUNMSG; 1120 } 1121 } 1122 1123 PJ_LOG(4,(sess->obj_name, "ChannelBind failed: %.*s", 1124 (int)err_msg.slen, err_msg.ptr)); 539 1125 } 540 1126 … … 561 1147 pj_stun_data_attr *data_attr; 562 1148 1149 PJ_UNUSED_ARG(src_addr); 1150 PJ_UNUSED_ARG(src_addr_len); 1151 563 1152 sess = (pj_turn_session*)pj_stun_session_get_user_data(stun); 564 1153 … … 604 1193 { 605 1194 pj_turn_session *sess = (pj_turn_session*) user_data; 1195 unsigned i, cnt; 1196 1197 /* Clear async resolver */ 1198 sess->dns_async = NULL; 606 1199 607 1200 /* Check failure */ 608 1201 if (status != PJ_SUCCESS) { 609 destroy(sess, PJ_TRUE, status);1202 sess_shutdown(sess, PJ_TRUE, status); 610 1203 return; 611 1204 } 612 1205 613 1206 /* Copy results to server entries */ 614 615 /* Set state to STATE_RESOLVED */ 1207 for (i=0, cnt=0; i<rec->count && cnt<MAX_SRV_CNT; ++i) { 1208 unsigned j; 1209 1210 for (j=0; j<rec->entry[i].server.addr_count && cnt<MAX_SRV_CNT; ++j) { 1211 pj_sockaddr_in *addr = &sess->srv_addr[cnt].ipv4; 1212 1213 addr->sin_family = sess->af; 1214 addr->sin_port = pj_htons(rec->entry[i].port); 1215 addr->sin_addr.s_addr = rec->entry[i].server.addr[j].s_addr; 1216 1217 ++cnt; 1218 } 1219 } 1220 sess->srv_addr_cnt = (pj_uint16_t)cnt; 1221 1222 /* Set current server */ 1223 sess->srv_addr = &sess->srv_addr[0]; 1224 1225 /* Set state to PJ_TURN_STATE_RESOLVED */ 1226 set_state(sess, PJ_TURN_STATE_RESOLVED); 616 1227 617 1228 /* Run pending allocation */ 618 } 619 620 621 /* 622 * Notification on completion of DNS A resolution. 623 */ 624 static void dns_a_resolver_cb(void *user_data, 625 pj_status_t status, 626 pj_dns_parsed_packet *response) 627 { 1229 if (sess->pending_alloc) { 1230 pj_turn_session_alloc(sess, NULL); 1231 } 628 1232 } 629 1233 … … 635 1239 const pj_sockaddr_t *addr, 636 1240 unsigned addr_len, 637 pj_bool_t update) 638 { 1241 pj_bool_t update, 1242 pj_bool_t bind_channel) 1243 { 1244 unsigned hval = 0; 1245 struct peer *peer; 1246 1247 peer = (struct peer*) pj_hash_get(sess->peer_table, addr, addr_len, &hval); 1248 if (peer == NULL && update) { 1249 peer = PJ_POOL_ZALLOC_T(sess->pool, struct peer); 1250 peer->ch_id = PJ_TURN_INVALID_CHANNEL; 1251 pj_memcpy(&peer->addr, addr, addr_len); 1252 1253 /* Register by peer address */ 1254 pj_hash_set(sess->pool, sess->peer_table, &peer->addr, addr_len, 1255 hval, peer); 1256 } 1257 1258 if (peer && update) { 1259 pj_gettimeofday(&peer->expiry); 1260 if (peer->bound) { 1261 peer->expiry.sec += PJ_TURN_CHANNEL_TIMEOUT - 10; 1262 } else { 1263 peer->expiry.sec += PJ_TURN_PERM_TIMEOUT - 10; 1264 } 1265 1266 if (bind_channel) { 1267 /* Register by channel number */ 1268 pj_assert(peer->ch_id != PJ_TURN_INVALID_CHANNEL && peer->bound); 1269 pj_assert(pj_hash_get(sess->peer_table, &peer->ch_id, 1270 sizeof(peer->ch_id), NULL)==0); 1271 1272 pj_hash_set(sess->pool, sess->peer_table, &peer->ch_id, 1273 sizeof(peer->ch_id), 0, peer); 1274 } 1275 } 1276 1277 return peer; 639 1278 } 640 1279 … … 644 1283 */ 645 1284 static struct peer *lookup_peer_by_chnum(pj_turn_session *sess, 646 unsigned chnum) 647 { 648 } 649 650 1285 pj_uint16_t chnum) 1286 { 1287 return (struct peer*) pj_hash_get(sess->peer_table, &chnum, 1288 sizeof(chnum), NULL); 1289 } 1290 1291 1292 /* 1293 * Timer event. 1294 */ 1295 static void on_timer_event(pj_timer_heap_t *th, pj_timer_entry *e) 1296 { 1297 pj_turn_session *sess = (pj_turn_session*)e->user_data; 1298 enum timer_id_t eid; 1299 1300 PJ_UNUSED_ARG(th); 1301 1302 pj_lock_acquire(sess->lock); 1303 1304 eid = e->id; 1305 e->id = TIMER_NONE; 1306 1307 if (eid == TIMER_KEEP_ALIVE) { 1308 pj_time_val now; 1309 pj_hash_iterator_t itbuf, *it; 1310 pj_bool_t resched = PJ_TRUE; 1311 pj_bool_t pkt_sent = PJ_FALSE; 1312 1313 pj_gettimeofday(&now); 1314 1315 /* Refresh allocation if it's time to do so */ 1316 if (PJ_TIME_VAL_LTE(sess->expiry, now)) { 1317 int lifetime = sess->alloc_param.lifetime; 1318 1319 if (lifetime == 0) 1320 lifetime = -1; 1321 1322 send_refresh(sess, lifetime); 1323 resched = PJ_FALSE; 1324 pkt_sent = PJ_TRUE; 1325 } 1326 1327 /* Scan hash table to refresh bound channels */ 1328 it = pj_hash_first(sess->peer_table, &itbuf); 1329 while (it) { 1330 struct peer *peer = (struct peer*) 1331 pj_hash_this(sess->peer_table, it); 1332 if (peer->bound && PJ_TIME_VAL_LTE(peer->expiry, now)) { 1333 1334 /* Send ChannelBind to refresh channel binding and 1335 * permission. 1336 */ 1337 pj_turn_session_bind_channel(sess, &peer->addr, 1338 pj_sockaddr_get_len(&peer->addr)); 1339 pkt_sent = PJ_TRUE; 1340 } 1341 1342 it = pj_hash_next(sess->peer_table, it); 1343 } 1344 1345 /* If no packet is sent, send a blank Send indication to 1346 * refresh local NAT. 1347 */ 1348 if (!pkt_sent && sess->alloc_param.ka_interval > 0) { 1349 pj_stun_tx_data *tdata; 1350 pj_status_t rc; 1351 1352 /* Create blank SEND-INDICATION */ 1353 rc = pj_stun_session_create_ind(sess->stun, 1354 PJ_STUN_SEND_INDICATION, &tdata); 1355 if (rc == PJ_SUCCESS) { 1356 /* Add DATA attribute with zero length */ 1357 pj_stun_msg_add_binary_attr(tdata->pool, tdata->msg, 1358 PJ_STUN_ATTR_DATA, NULL, 0); 1359 1360 /* Send the indication */ 1361 pj_stun_session_send_msg(sess->stun, PJ_FALSE, sess->srv_addr, 1362 pj_sockaddr_get_len(sess->srv_addr), 1363 tdata); 1364 } 1365 } 1366 1367 /* Reshcedule timer */ 1368 if (resched) { 1369 pj_time_val delay; 1370 1371 delay.sec = sess->ka_interval; 1372 delay.msec = 0; 1373 1374 pj_timer_heap_schedule(sess->timer_heap, &sess->timer, &delay); 1375 } 1376 1377 pj_lock_release(sess->lock); 1378 1379 } else if (eid == TIMER_DESTROY) { 1380 /* Time to destroy */ 1381 pj_lock_release(sess->lock); 1382 do_destroy(sess); 1383 } 1384 } 1385
Note: See TracChangeset
for help on using the changeset viewer.