Changeset 5987
- Timestamp:
- May 14, 2019 9:31:39 AM (4 years ago)
- Location:
- pjproject/trunk/pjnath
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjnath/include/pjnath/config.h
r5850 r5987 221 221 #endif 222 222 223 /** 224 * Maximum number of TCP data connection to peer(s) that a TURN client can 225 * open/accept for each TURN allocation (or TURN control connection). 226 */ 227 #ifndef PJ_TURN_MAX_TCP_CONN_CNT 228 # define PJ_TURN_MAX_TCP_CONN_CNT 8 229 #endif 223 230 224 231 /* ************************************************************************** -
pjproject/trunk/pjnath/include/pjnath/stun_msg.h
r5527 r5987 94 94 95 95 /** 96 * STUN/TURN Connect as defined by RFC 6062 97 */ 98 PJ_STUN_CONNECT_METHOD = 10, 99 100 /** 101 * STUN/TURN ConnectionBind as defined by RFC 6062 102 */ 103 PJ_STUN_CONNECTION_BIND_METHOD = 11, 104 105 /** 106 * STUN/TURN ConnectionAttempt as defined by RFC 6062 107 */ 108 PJ_STUN_CONNECTION_ATTEMPT_METHOD = 12, 109 110 /** 96 111 * All known methods. 97 112 */ … … 292 307 * Error response to STUN ChannelBind request. 293 308 */ 294 PJ_STUN_CHANNEL_BIND_ERROR_RESPONSE = 0x0119 309 PJ_STUN_CHANNEL_BIND_ERROR_RESPONSE = 0x0119, 310 311 312 /** 313 * STUN/TURN ConnectBind Request 314 */ 315 PJ_STUN_CONNECTION_BIND_REQUEST = 0x000b, 316 317 /** 318 * TURN ConnectionAttempt indication 319 */ 320 PJ_STUN_CONNECTION_ATTEMPT_INDICATION = 0x001c, 295 321 296 322 } pj_stun_msg_type; … … 334 360 PJ_STUN_ATTR_PRIORITY = 0x0024,/**< PRIORITY */ 335 361 PJ_STUN_ATTR_USE_CANDIDATE = 0x0025,/**< USE-CANDIDATE */ 362 PJ_STUN_ATTR_CONNECTION_ID = 0x002a,/**< CONNECTION-ID */ 336 363 PJ_STUN_ATTR_ICMP = 0x0030,/**< ICMP (TURN) */ 337 364 -
pjproject/trunk/pjnath/include/pjnath/turn_session.h
r5481 r5987 299 299 pj_turn_state_t new_state); 300 300 301 /** 302 * Notification when TURN client received a ConnectionAttempt Indication 303 * from the TURN server, which indicates that peer initiates a TCP 304 * connection to allocated slot in the TURN server. Application must 305 * implement this callback if it uses RFC 6062 (TURN TCP allocations). 306 * 307 * After receiving this callback, application should establish a new TCP 308 * connection to the TURN server and send ConnectionBind request (using 309 * pj_turn_session_connection_bind()). After the connection binding 310 * succeeds, this new connection will become a data only connection. 311 * 312 * @param sess The TURN session. 313 * @param conn_id The connection ID assigned by TURN server. 314 * @param peer_addr Peer address that tried to connect to the TURN server. 315 * @param addr_len Length of the peer address. 316 */ 317 void (*on_connection_attempt)(pj_turn_session *sess, 318 pj_uint32_t conn_id, 319 const pj_sockaddr_t *peer_addr, 320 unsigned addr_len); 321 322 /** 323 * Notification for ConnectionBind request sent using 324 * pj_turn_session_connection_bind(). 325 * 326 * @param sess The TURN session. 327 * @param status The status code. 328 * @param conn_id The connection ID. 329 * @param peer_addr Peer address. 330 * @param addr_len Length of the peer address. 331 */ 332 void (*on_connection_bind_status)(pj_turn_session *sess, 333 pj_status_t status, 334 pj_uint32_t conn_id, 335 const pj_sockaddr_t *peer_addr, 336 unsigned addr_len); 337 301 338 } pj_turn_session_cb; 302 339 … … 340 377 int af; 341 378 379 /** 380 * Type of connection to from TURN server to peer. Supported values are 381 * PJ_TURN_TP_UDP (RFC 5766) and PJ_TURN_TP_TCP (RFC 6062) 382 * 383 * Default is PJ_TURN_TP_UDP. 384 */ 385 pj_turn_tp_type peer_conn_type; 342 386 343 387 } pj_turn_alloc_param; … … 385 429 386 430 } pj_turn_session_info; 431 432 433 /** 434 * Parameters for function pj_turn_session_on_rx_pkt2(). 435 */ 436 typedef struct pj_turn_session_on_rx_pkt_param 437 { 438 /** 439 * The packet as received from the TURN server. This should contain 440 * either STUN encapsulated message or a ChannelData packet. 441 */ 442 void *pkt; 443 444 /** 445 * The length of the packet. 446 */ 447 pj_size_t pkt_len; 448 449 /** 450 * The number of parsed or processed data from the packet. 451 */ 452 pj_size_t parsed_len; 453 454 /** 455 * Source address where the packet is received from. 456 */ 457 const pj_sockaddr_t *src_addr; 458 459 /** 460 * Length of the source address. 461 */ 462 unsigned src_addr_len; 463 464 } pj_turn_session_on_rx_pkt_param; 387 465 388 466 … … 742 820 pj_size_t *parsed_len); 743 821 822 /** 823 * Notify TURN client session upon receiving a packet from server. Since 824 * the TURN session is transport independent, it does not read packet from 825 * any sockets, and rather relies on application giving it packets that 826 * are received from the TURN server. The session then processes this packet 827 * and decides whether it is part of TURN protocol exchange or if it is a 828 * data to be reported back to user, which in this case it will call the 829 * \a on_rx_data() callback. 830 * 831 * This function is variant of pj_turn_session_on_rx_pkt() with additional 832 * parameters such as source address. Source address will allow STUN/TURN 833 * session to resend the request (e.g: with updated authentication) to the 834 * provided source address which may be different to the initial connection, 835 * for example in RFC 6062 scenario that there can be some data connection 836 * and a control connection. 837 * 838 * @param sess The TURN client session. 839 * @param prm The function parameters, e.g: packet, source address. 840 * 841 * @return The function may return non-PJ_SUCCESS if it receives 842 * non-STUN and non-ChannelData packet, or if the 843 * \a on_rx_data() returns non-PJ_SUCCESS; 844 */ 845 PJ_DECL(pj_status_t) pj_turn_session_on_rx_pkt2( 846 pj_turn_session *sess, 847 pj_turn_session_on_rx_pkt_param *prm); 848 849 /** 850 * Initiate connection binding to the specified peer using ConnectionBind 851 * request. Application must call this function when it uses RFC 6062 852 * (TURN TCP allocations) to establish a data connection with peer after 853 * opening/accepting connection to/from peer. The connection binding status 854 * will be notified via on_connection_bind_status callback. 855 * 856 * @param sess The TURN session. 857 * @param pool The memory pool. 858 * @param conn_id The connection ID assigned by TURN server. 859 * @param peer_addr Peer address. 860 * @param addr_len Length of the peer address. 861 * 862 * @return PJ_SUCCESS if the operation has been successfully 863 * issued, or the appropriate error code. Note that 864 * the operation itself will complete asynchronously. 865 */ 866 PJ_DECL(pj_status_t) pj_turn_session_connection_bind( 867 pj_turn_session *sess, 868 pj_pool_t *pool, 869 pj_uint32_t conn_id, 870 const pj_sockaddr_t *peer_addr, 871 unsigned addr_len); 744 872 745 873 /** -
pjproject/trunk/pjnath/include/pjnath/turn_sock.h
r4606 r5987 98 98 pj_turn_state_t old_state, 99 99 pj_turn_state_t new_state); 100 101 /** 102 * Notification when TURN client received a ConnectionAttempt Indication 103 * from the TURN server, which indicates that peer initiates a TCP 104 * connection to allocated slot in the TURN server. Application should 105 * implement this callback if it uses RFC 6062 (TURN TCP allocations), 106 * otherwise TURN client will automatically accept it. 107 * 108 * If application accepts the peer connection attempt (i.e: by returning 109 * PJ_SUCCESS or not implementing this callback), the TURN socket will 110 * initiate a new connection to the TURN server and send ConnectionBind 111 * request, and eventually will notify application via 112 * on_connection_status callback, if implemented. 113 * 114 * @param turn_sock The TURN client transport. 115 * @param conn_id The connection ID assigned by TURN server. 116 * @param peer_addr Peer address that tried to connect to the 117 * TURN server. 118 * @param addr_len Length of the peer address. 119 * 120 * @return The callback must return PJ_SUCCESS to accept 121 * the connection attempt. 122 */ 123 pj_status_t (*on_connection_attempt)(pj_turn_sock *turn_sock, 124 pj_uint32_t conn_id, 125 const pj_sockaddr_t *peer_addr, 126 unsigned addr_len); 127 128 /** 129 * Notification for initiated TCP data connection to peer (RFC 6062), 130 * for example after peer connection attempt is accepted. 131 * 132 * @param turn_sock The TURN client transport. 133 * @param status The status code. 134 * @param conn_id The connection ID. 135 * @param peer_addr Peer address. 136 * @param addr_len Length of the peer address. 137 */ 138 void (*on_connection_status)(pj_turn_sock *turn_sock, 139 pj_status_t status, 140 pj_uint32_t conn_id, 141 const pj_sockaddr_t *peer_addr, 142 unsigned addr_len); 100 143 101 144 } pj_turn_sock_cb; -
pjproject/trunk/pjnath/src/pjnath/stun_msg.c
r5527 r5987 46 46 "CreatePermission", /* 8 */ 47 47 "ChannelBind", /* 9 */ 48 "Connect", /* 10 */ 49 "ConnectionBind", /* 11 */ 50 "ConnectionAttempt", /* 12 */ 48 51 }; 49 52 … … 477 480 }, 478 481 { 479 /* ID 0x002a is not assigned*/480 NULL,481 NULL,482 NULL,483 NULL482 /* PJ_STUN_ATTR_CONNECTION_ID, */ 483 "CONNECTION-ID", 484 &decode_uint_attr, 485 &encode_uint_attr, 486 &clone_uint_attr 484 487 }, 485 488 { -
pjproject/trunk/pjnath/src/pjnath/turn_session.c
r5983 r5987 104 104 }; 105 105 106 struct conn_bind_t 107 { 108 pj_uint32_t id; /* Connection ID. */ 109 pj_sockaddr peer_addr; /* Peer address. */ 110 unsigned peer_addr_len; 111 }; 106 112 107 113 /* The TURN client session structure */ … … 209 215 { 210 216 pj_bzero(prm, sizeof(*prm)); 217 prm->peer_conn_type = PJ_TURN_TP_UDP; 211 218 } 212 219 … … 724 731 sess->state<=PJ_TURN_STATE_RESOLVED, 725 732 PJ_EINVALIDOP); 733 PJ_ASSERT_RETURN(param->peer_conn_type == PJ_TURN_TP_UDP || 734 param->peer_conn_type == PJ_TURN_TP_TCP, 735 PJ_EINVAL); 726 736 727 737 /* Verify address family in allocation param */ … … 761 771 pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg, 762 772 PJ_STUN_ATTR_REQ_TRANSPORT, 763 PJ_STUN_SET_RT_PROTO( PJ_TURN_TP_UDP));773 PJ_STUN_SET_RT_PROTO(param->peer_conn_type)); 764 774 765 775 /* Include BANDWIDTH if requested */ … … 999 1009 } 1000 1010 1011 /* If peer connection is TCP (RFC 6062), send it directly */ 1012 if (sess->alloc_param.peer_conn_type == PJ_TURN_TP_TCP) { 1013 status = sess->cb.on_send_pkt(sess, pkt, pkt_len, addr, addr_len); 1014 goto on_return; 1015 } 1016 1001 1017 /* See if the peer is bound to a channel number */ 1002 1018 ch = lookup_ch_by_addr(sess, addr, pj_sockaddr_get_len(addr), … … 1139 1155 1140 1156 /** 1141 * Notify TURN client session upon receiving a packet from server. 1142 * The packet maybe a STUN packet or ChannelData packet. 1143 */ 1157 * Send ConnectionBind request. 1158 */ 1159 PJ_DEF(pj_status_t) pj_turn_session_connection_bind( 1160 pj_turn_session *sess, 1161 pj_pool_t *pool, 1162 pj_uint32_t conn_id, 1163 const pj_sockaddr_t *peer_addr, 1164 unsigned addr_len) 1165 { 1166 pj_stun_tx_data *tdata; 1167 struct conn_bind_t *conn_bind; 1168 pj_status_t status; 1169 1170 PJ_ASSERT_RETURN(sess && pool && conn_id && peer_addr && addr_len, 1171 PJ_EINVAL); 1172 PJ_ASSERT_RETURN(sess->state == PJ_TURN_STATE_READY, PJ_EINVALIDOP); 1173 1174 pj_grp_lock_acquire(sess->grp_lock); 1175 1176 /* Create blank ConnectionBind request */ 1177 status = pj_stun_session_create_req(sess->stun, 1178 PJ_STUN_CONNECTION_BIND_REQUEST, 1179 PJ_STUN_MAGIC, NULL, &tdata); 1180 if (status != PJ_SUCCESS) 1181 goto on_return; 1182 1183 /* Add CONNECTION_ID attribute */ 1184 pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg, 1185 PJ_STUN_ATTR_CONNECTION_ID, 1186 conn_id); 1187 1188 conn_bind = PJ_POOL_ZALLOC_T(pool, struct conn_bind_t); 1189 conn_bind->id = conn_id; 1190 pj_sockaddr_cp(&conn_bind->peer_addr, peer_addr); 1191 conn_bind->peer_addr_len = addr_len; 1192 1193 /* Send the request, associate connection data structure with tdata 1194 * for future reference when we receive the ConnectionBind response. 1195 */ 1196 status = pj_stun_session_send_msg(sess->stun, conn_bind, PJ_FALSE, 1197 PJ_FALSE, peer_addr, addr_len, tdata); 1198 1199 on_return: 1200 pj_grp_lock_release(sess->grp_lock); 1201 return status; 1202 } 1203 1144 1204 PJ_DEF(pj_status_t) pj_turn_session_on_rx_pkt(pj_turn_session *sess, 1145 1205 void *pkt, … … 1147 1207 pj_size_t *parsed_len) 1148 1208 { 1209 pj_turn_session_on_rx_pkt_param prm; 1210 pj_status_t status; 1211 1212 pj_bzero(&prm, sizeof(prm)); 1213 prm.pkt = pkt; 1214 prm.pkt_len = pkt_len; 1215 status = pj_turn_session_on_rx_pkt2(sess, &prm); 1216 if (status == PJ_SUCCESS && parsed_len) 1217 *parsed_len = prm.parsed_len; 1218 return status; 1219 } 1220 1221 /** 1222 * Notify TURN client session upon receiving a packet from server. 1223 * The packet maybe a STUN packet or ChannelData packet. 1224 */ 1225 PJ_DEF(pj_status_t) pj_turn_session_on_rx_pkt2( 1226 pj_turn_session *sess, 1227 pj_turn_session_on_rx_pkt_param *prm) 1228 { 1149 1229 pj_bool_t is_stun; 1150 1230 pj_status_t status; … … 1161 1241 1162 1242 /* Quickly check if this is STUN message */ 1163 is_stun = ((((pj_uint8_t*)p kt)[0] & 0xC0) == 0);1243 is_stun = ((((pj_uint8_t*)prm->pkt)[0] & 0xC0) == 0); 1164 1244 1165 1245 if (is_stun) { 1166 1246 /* This looks like STUN, give it to the STUN session */ 1167 1247 unsigned options; 1248 const pj_sockaddr_t *src_addr = prm->src_addr? 1249 prm->src_addr:sess->srv_addr; 1250 unsigned src_addr_len = prm->src_addr_len? prm->src_addr_len: 1251 pj_sockaddr_get_len(sess->srv_addr); 1168 1252 1169 1253 options = PJ_STUN_CHECK_PACKET | PJ_STUN_NO_FINGERPRINT_CHECK; 1170 1254 if (is_datagram) 1171 1255 options |= PJ_STUN_IS_DATAGRAM; 1172 status=pj_stun_session_on_rx_pkt(sess->stun, pkt, pkt_len, 1173 options, NULL, parsed_len, 1174 sess->srv_addr, 1175 pj_sockaddr_get_len(sess->srv_addr)); 1256 status=pj_stun_session_on_rx_pkt(sess->stun, prm->pkt, prm->pkt_len, 1257 options, NULL, &prm->parsed_len, 1258 src_addr, src_addr_len); 1176 1259 1177 1260 } else { … … 1180 1263 struct ch_t *ch; 1181 1264 1182 if (p kt_len < 4) {1183 if (parsed_len) *parsed_len = 0;1265 if (prm->pkt_len < 4) { 1266 prm->parsed_len = 0; 1184 1267 return PJ_ETOOSMALL; 1185 1268 } 1186 1269 1187 1270 /* Decode ChannelData packet */ 1188 pj_memcpy(&cd, p kt, sizeof(pj_turn_channel_data));1271 pj_memcpy(&cd, prm->pkt, sizeof(pj_turn_channel_data)); 1189 1272 cd.ch_number = pj_ntohs(cd.ch_number); 1190 1273 cd.length = pj_ntohs(cd.length); 1191 1274 1192 1275 /* Check that size is sane */ 1193 if (pkt_len < cd.length+sizeof(cd)) { 1194 if (parsed_len) { 1195 if (is_datagram) { 1196 /* Discard the datagram */ 1197 *parsed_len = pkt_len; 1198 } else { 1199 /* Insufficient fragment */ 1200 *parsed_len = 0; 1201 } 1276 if (prm->pkt_len < cd.length+sizeof(cd)) { 1277 if (is_datagram) { 1278 /* Discard the datagram */ 1279 prm->parsed_len = prm->pkt_len; 1280 } else { 1281 /* Insufficient fragment */ 1282 prm->parsed_len = 0; 1202 1283 } 1203 1284 status = PJ_ETOOSMALL; 1204 1285 goto on_return; 1205 1286 } else { 1206 if (parsed_len) { 1207 /* Apply padding too */ 1208 *parsed_len = ((cd.length + 3) & (~3)) + sizeof(cd); 1209 } 1287 /* Apply padding too */ 1288 prm->parsed_len = ((cd.length + 3) & (~3)) + sizeof(cd); 1210 1289 } 1211 1290 … … 1219 1298 /* Notify application */ 1220 1299 if (sess->cb.on_rx_data) { 1221 (*sess->cb.on_rx_data)(sess, ((pj_uint8_t*)p kt)+sizeof(cd),1300 (*sess->cb.on_rx_data)(sess, ((pj_uint8_t*)prm->pkt)+sizeof(cd), 1222 1301 cd.length, &ch->addr, 1223 1302 pj_sockaddr_get_len(&ch->addr)); … … 1643 1722 } 1644 1723 1724 } else if (method == PJ_STUN_CONNECTION_BIND_METHOD) { 1725 /* Handle ConnectionBind response */ 1726 struct conn_bind_t *conn_bind = (struct conn_bind_t*)token; 1727 1728 if (status != PJ_SUCCESS || 1729 !PJ_STUN_IS_SUCCESS_RESPONSE(response->hdr.type)) 1730 { 1731 pj_str_t reason = {0}; 1732 if (status == PJ_SUCCESS) { 1733 const pj_stun_errcode_attr *err_attr; 1734 err_attr = (const pj_stun_errcode_attr*) 1735 pj_stun_msg_find_attr(response, 1736 PJ_STUN_ATTR_ERROR_CODE, 0); 1737 if (err_attr) { 1738 status = PJ_STATUS_FROM_STUN_CODE(err_attr->err_code); 1739 reason = err_attr->reason; 1740 } else { 1741 status = PJNATH_EINSTUNMSG; 1742 } 1743 } 1744 pj_perror(1, sess->obj_name, status, "ConnectionBind failed: %.*s", 1745 (int)reason.slen, reason.ptr); 1746 } 1747 1748 /* Notify app */ 1749 if (sess->cb.on_connection_bind_status) { 1750 (*sess->cb.on_connection_bind_status) 1751 (sess, status, conn_bind->id, 1752 &conn_bind->peer_addr, conn_bind->peer_addr_len); 1753 } 1645 1754 } else { 1646 1755 PJ_LOG(4,(sess->obj_name, "Unexpected STUN %s response", … … 1675 1784 sess = (pj_turn_session*)pj_stun_session_get_user_data(stun); 1676 1785 1677 /* Expecting Data Indication only */ 1786 /* ConnectionAttempt Indication */ 1787 if (msg->hdr.type == PJ_STUN_CONNECTION_ATTEMPT_INDICATION) { 1788 pj_stun_uint_attr *connection_id_attr; 1789 1790 /* Get CONNECTION-ID attribute */ 1791 connection_id_attr = (pj_stun_uint_attr*) 1792 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_CONNECTION_ID, 0); 1793 1794 /* Get XOR-PEER-ADDRESS attribute */ 1795 peer_attr = (pj_stun_xor_peer_addr_attr*) 1796 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_XOR_PEER_ADDR, 0); 1797 1798 /* Must have both XOR-PEER-ADDRESS and CONNECTION-ID attributes */ 1799 if (!peer_attr || !connection_id_attr) { 1800 PJ_LOG(4,(sess->obj_name, 1801 "Received ConnectionAttempt indication with missing " 1802 "attributes")); 1803 return PJ_EINVALIDOP; 1804 } 1805 1806 /* Notify application */ 1807 if (sess->cb.on_connection_attempt) { 1808 (*sess->cb.on_connection_attempt) 1809 (sess, 1810 connection_id_attr->value, 1811 &peer_attr->sockaddr, 1812 pj_sockaddr_get_len(&peer_attr->sockaddr)); 1813 } 1814 return PJ_SUCCESS; 1815 } 1816 1817 /* Next, expecting Data Indication only */ 1678 1818 if (msg->hdr.type != PJ_STUN_DATA_INDICATION) { 1679 1819 PJ_LOG(4,(sess->obj_name, "Unexpected STUN %s indication", -
pjproject/trunk/pjnath/src/pjnath/turn_sock.c
r5983 r5987 39 39 #define INIT 0x1FFFFFFF 40 40 41 enum { 42 DATACONN_STATE_NULL, 43 DATACONN_STATE_INITSOCK, 44 DATACONN_STATE_CONN_BINDING, 45 DATACONN_STATE_READY, 46 }; 47 48 /* This structure describe data connection of TURN TCP allocations 49 * (RFC 6062). 50 */ 51 typedef struct tcp_data_conn_t 52 { 53 pj_pool_t *pool; 54 55 pj_uint32_t id; /* Connection ID. */ 56 int state; /* Connection state. */ 57 pj_sockaddr peer_addr; /* Peer address (mapped). */ 58 unsigned peer_addr_len; 59 60 pj_activesock_t *asock; /* Active socket. */ 61 pj_ioqueue_op_key_t send_key; 62 63 pj_turn_sock *turn_sock; /* TURN socket parent. */ 64 } tcp_data_conn_t; 65 66 41 67 struct pj_turn_sock 42 68 { … … 60 86 pj_activesock_t *active_sock; 61 87 pj_ioqueue_op_key_t send_key; 88 89 /* Data connection, when peer_conn_type==PJ_TURN_TP_TCP (RFC 6062) */ 90 unsigned data_conn_cnt; 91 tcp_data_conn_t data_conn[PJ_TURN_MAX_TCP_CONN_CNT]; 62 92 }; 63 93 … … 83 113 pj_turn_state_t old_state, 84 114 pj_turn_state_t new_state); 115 static void turn_on_connection_attempt(pj_turn_session *sess, 116 pj_uint32_t conn_id, 117 const pj_sockaddr_t *peer_addr, 118 unsigned addr_len); 119 static void turn_on_connection_bind_status(pj_turn_session *sess, 120 pj_status_t status, 121 pj_uint32_t conn_id, 122 const pj_sockaddr_t *peer_addr, 123 unsigned addr_len); 85 124 86 125 static pj_bool_t on_data_read(pj_activesock_t *asock, … … 92 131 pj_status_t status); 93 132 94 133 static pj_bool_t dataconn_on_data_read(pj_activesock_t *asock, 134 void *data, 135 pj_size_t size, 136 pj_status_t status, 137 pj_size_t *remainder); 138 static pj_bool_t dataconn_on_connect_complete(pj_activesock_t *asock, 139 pj_status_t status); 140 static void dataconn_cleanup(tcp_data_conn_t *conn); 95 141 96 142 static void turn_sock_on_destroy(void *comp); … … 194 240 sess_cb.on_rx_data = &turn_on_rx_data; 195 241 sess_cb.on_state = &turn_on_state; 242 sess_cb.on_connection_attempt = &turn_on_connection_attempt; 243 sess_cb.on_connection_bind_status = &turn_on_connection_bind_status; 196 244 status = pj_turn_session_create(cfg, pool->obj_name, af, conn_type, 197 245 turn_sock->grp_lock, &sess_cb, 0, … … 225 273 static void destroy(pj_turn_sock *turn_sock) 226 274 { 275 unsigned i; 276 227 277 PJ_LOG(4,(turn_sock->obj_name, "TURN socket destroy request, ref_cnt=%d", 228 278 pj_grp_lock_get_ref(turn_sock->grp_lock))); … … 239 289 if (turn_sock->active_sock) 240 290 pj_activesock_close(turn_sock->active_sock); 291 292 for (i=0; i < PJ_TURN_MAX_TCP_CONN_CNT; ++i) { 293 dataconn_cleanup(&turn_sock->data_conn[i]); 294 } 295 turn_sock->data_conn_cnt = 0; 296 241 297 pj_grp_lock_dec_ref(turn_sock->grp_lock); 242 298 pj_grp_lock_release(turn_sock->grp_lock); … … 668 724 pj_turn_session_get_user_data(sess); 669 725 pj_ssize_t len = pkt_len; 670 pj_status_t status ;726 pj_status_t status = PJ_SUCCESS; 671 727 672 728 if (turn_sock == NULL || turn_sock->is_destroying) { … … 681 737 &turn_sock->send_key, pkt, &len, 0, 682 738 dst_addr, dst_addr_len); 739 } else if (turn_sock->alloc_param.peer_conn_type == PJ_TURN_TP_TCP) { 740 pj_turn_session_info info; 741 pj_turn_session_get_info(turn_sock->sess, &info); 742 if (pj_sockaddr_cmp(&info.server, dst_addr) == 0) { 743 /* Destination address is TURN server */ 744 status = pj_activesock_send(turn_sock->active_sock, 745 &turn_sock->send_key, pkt, &len, 0); 746 } else { 747 /* Destination address is peer, lookup data connection */ 748 unsigned i; 749 750 status = PJ_ENOTFOUND; 751 for (i=0; i < PJ_TURN_MAX_TCP_CONN_CNT; ++i) { 752 tcp_data_conn_t *conn = &turn_sock->data_conn[i]; 753 if (conn->state < DATACONN_STATE_CONN_BINDING) 754 continue; 755 if (pj_sockaddr_cmp(&conn->peer_addr, dst_addr) == 0) { 756 status = pj_activesock_send(conn->asock, 757 &conn->send_key, 758 pkt, &len, 0); 759 break; 760 } 761 } 762 } 683 763 } else { 684 764 status = pj_activesock_send(turn_sock->active_sock, 685 765 &turn_sock->send_key, pkt, &len, 0); 686 766 } 767 687 768 if (status != PJ_SUCCESS && status != PJ_EPENDING) { 688 769 show_err(turn_sock, "socket send()", status); … … 721 802 if (turn_sock == NULL || turn_sock->is_destroying) { 722 803 /* We've been destroyed */ 804 return; 805 } 806 807 if (turn_sock->alloc_param.peer_conn_type != PJ_TURN_TP_UDP) { 808 /* Data traffic for RFC 6062 is not via TURN session */ 723 809 return; 724 810 } … … 937 1023 938 1024 1025 static void dataconn_cleanup(tcp_data_conn_t *conn) 1026 { 1027 if (conn->asock) 1028 pj_activesock_close(conn->asock); 1029 1030 pj_pool_safe_release(&conn->pool); 1031 1032 pj_bzero(conn, sizeof(conn)); 1033 } 1034 1035 static pj_bool_t dataconn_on_data_read(pj_activesock_t *asock, 1036 void *data, 1037 pj_size_t size, 1038 pj_status_t status, 1039 pj_size_t *remainder) 1040 { 1041 tcp_data_conn_t *conn = (tcp_data_conn_t*) 1042 pj_activesock_get_user_data(asock); 1043 pj_turn_sock *turn_sock = conn->turn_sock; 1044 1045 pj_grp_lock_acquire(turn_sock->grp_lock); 1046 1047 if (size == 0 && status != PJ_SUCCESS) { 1048 /* Connection gone, release data connection */ 1049 dataconn_cleanup(conn); 1050 --turn_sock->data_conn_cnt; 1051 pj_grp_lock_release(turn_sock->grp_lock); 1052 return PJ_FALSE; 1053 } 1054 1055 if (conn->state == DATACONN_STATE_READY) { 1056 /* Application data */ 1057 if (turn_sock->cb.on_rx_data) { 1058 (*turn_sock->cb.on_rx_data)(turn_sock, data, size, 1059 &conn->peer_addr, 1060 conn->peer_addr_len); 1061 } 1062 } else if (conn->state == DATACONN_STATE_CONN_BINDING) { 1063 /* Waiting for ConnectionBind response */ 1064 pj_bool_t is_stun; 1065 pj_turn_session_on_rx_pkt_param prm; 1066 1067 /* Ignore if this is not a STUN message */ 1068 is_stun = ((((pj_uint8_t*)data)[0] & 0xC0) == 0); 1069 if (!is_stun) 1070 goto on_return; 1071 1072 pj_bzero(&prm, sizeof(prm)); 1073 prm.pkt = data; 1074 prm.pkt_len = size; 1075 prm.src_addr = &conn->peer_addr; 1076 prm.src_addr_len = conn->peer_addr_len; 1077 pj_turn_session_on_rx_pkt2(conn->turn_sock->sess, &prm); 1078 /* Got remainder? */ 1079 if (prm.parsed_len < size) { 1080 *remainder = size - prm.parsed_len; 1081 if (prm.parsed_len) { 1082 pj_memmove(data, (pj_uint8_t*)data+prm.parsed_len, 1083 *remainder); 1084 } 1085 } 1086 } 1087 1088 on_return: 1089 pj_grp_lock_release(turn_sock->grp_lock); 1090 return PJ_TRUE; 1091 } 1092 1093 static pj_bool_t dataconn_on_connect_complete(pj_activesock_t *asock, 1094 pj_status_t status) 1095 { 1096 tcp_data_conn_t *conn = (tcp_data_conn_t*) 1097 pj_activesock_get_user_data(asock); 1098 pj_turn_sock *turn_sock = conn->turn_sock; 1099 1100 pj_grp_lock_acquire(turn_sock->grp_lock); 1101 1102 if (status == PJ_SUCCESS) { 1103 status = pj_activesock_start_read(asock, turn_sock->pool, 1104 turn_sock->setting.max_pkt_size, 0); 1105 } 1106 if (status == PJ_SUCCESS) { 1107 conn->state = DATACONN_STATE_CONN_BINDING; 1108 status = pj_turn_session_connection_bind(turn_sock->sess, 1109 conn->pool, 1110 conn->id, 1111 &conn->peer_addr, 1112 conn->peer_addr_len); 1113 } 1114 if (status != PJ_SUCCESS) { 1115 dataconn_cleanup(conn); 1116 --turn_sock->data_conn_cnt; 1117 pj_grp_lock_release(turn_sock->grp_lock); 1118 return PJ_FALSE; 1119 } 1120 1121 pj_grp_lock_release(turn_sock->grp_lock); 1122 return PJ_TRUE; 1123 } 1124 1125 1126 static void turn_on_connection_attempt(pj_turn_session *sess, 1127 pj_uint32_t conn_id, 1128 const pj_sockaddr_t *peer_addr, 1129 unsigned addr_len) 1130 { 1131 pj_turn_sock *turn_sock = (pj_turn_sock*) 1132 pj_turn_session_get_user_data(sess); 1133 pj_pool_t *pool; 1134 tcp_data_conn_t *new_conn; 1135 pj_turn_session_info info; 1136 pj_sock_t sock = PJ_INVALID_SOCKET; 1137 pj_activesock_cfg asock_cfg; 1138 pj_activesock_cb asock_cb; 1139 pj_sockaddr bound_addr, *cfg_bind_addr; 1140 pj_uint16_t max_bind_retry; 1141 char addrtxt[PJ_INET6_ADDRSTRLEN+8]; 1142 pj_status_t status; 1143 unsigned i; 1144 1145 PJ_ASSERT_ON_FAIL(turn_sock->conn_type == PJ_TURN_TP_TCP && 1146 turn_sock->alloc_param.peer_conn_type == PJ_TURN_TP_TCP, 1147 return); 1148 1149 PJ_LOG(5,(turn_sock->pool->obj_name, "Connection attempt from peer %s", 1150 pj_sockaddr_print(&peer_addr, addrtxt, sizeof(addrtxt), 3))); 1151 1152 if (turn_sock == NULL) { 1153 /* We've been destroyed */ 1154 return; 1155 } 1156 1157 pj_grp_lock_acquire(turn_sock->grp_lock); 1158 1159 if (turn_sock->data_conn_cnt == PJ_TURN_MAX_TCP_CONN_CNT) { 1160 /* Data connection has reached limit */ 1161 pj_grp_lock_release(turn_sock->grp_lock); 1162 return; 1163 } 1164 1165 /* Check if app wants to accept this connection */ 1166 status = PJ_SUCCESS; 1167 if (turn_sock->cb.on_connection_attempt) { 1168 status = (*turn_sock->cb.on_connection_attempt)(turn_sock, conn_id, 1169 peer_addr, addr_len); 1170 } 1171 /* App rejects it */ 1172 if (status != PJ_SUCCESS) { 1173 pj_perror(4, turn_sock->pool->obj_name, status, 1174 "Rejected connection attempt from peer %s", 1175 pj_sockaddr_print(peer_addr, addrtxt, sizeof(addrtxt), 3)); 1176 pj_grp_lock_release(turn_sock->grp_lock); 1177 return; 1178 } 1179 1180 /* Find free data connection slot */ 1181 for (i=0; i < PJ_TURN_MAX_TCP_CONN_CNT; ++i) { 1182 if (turn_sock->data_conn[i].state == DATACONN_STATE_NULL) 1183 break; 1184 } 1185 pj_assert(i < turn_sock->data_conn_cnt); 1186 ++turn_sock->data_conn_cnt; 1187 1188 /* Init new data connection */ 1189 new_conn = &turn_sock->data_conn[i]; 1190 pj_bzero(new_conn, sizeof(*new_conn)); 1191 pool = pj_pool_create(turn_sock->cfg.pf, "dataconn", 128, 128, NULL); 1192 new_conn->pool = pool; 1193 new_conn->id = conn_id; 1194 new_conn->turn_sock = turn_sock; 1195 pj_sockaddr_cp(&new_conn->peer_addr, peer_addr); 1196 new_conn->peer_addr_len = addr_len; 1197 pj_ioqueue_op_key_init(&new_conn->send_key, sizeof(new_conn->send_key)); 1198 new_conn->state = DATACONN_STATE_INITSOCK; 1199 1200 /* Init socket */ 1201 status = pj_sock_socket(turn_sock->af, pj_SOCK_STREAM(), 0, &sock); 1202 if (status != PJ_SUCCESS) 1203 goto on_return; 1204 1205 /* Bind socket */ 1206 cfg_bind_addr = &turn_sock->setting.bound_addr; 1207 max_bind_retry = MAX_BIND_RETRY; 1208 if (turn_sock->setting.port_range && 1209 turn_sock->setting.port_range < max_bind_retry) 1210 { 1211 max_bind_retry = turn_sock->setting.port_range; 1212 } 1213 pj_sockaddr_init(turn_sock->af, &bound_addr, NULL, 0); 1214 if (cfg_bind_addr->addr.sa_family == pj_AF_INET() || 1215 cfg_bind_addr->addr.sa_family == pj_AF_INET6()) 1216 { 1217 pj_sockaddr_cp(&bound_addr, cfg_bind_addr); 1218 } 1219 status = pj_sock_bind_random(sock, &bound_addr, 1220 turn_sock->setting.port_range, 1221 max_bind_retry); 1222 if (status != PJ_SUCCESS) 1223 goto on_return; 1224 1225 /* Apply socket buffer size */ 1226 if (turn_sock->setting.so_rcvbuf_size > 0) { 1227 unsigned sobuf_size = turn_sock->setting.so_rcvbuf_size; 1228 status = pj_sock_setsockopt_sobuf(sock, pj_SO_RCVBUF(), PJ_TRUE, 1229 &sobuf_size); 1230 if (status != PJ_SUCCESS) { 1231 pj_perror(3, turn_sock->obj_name, status, 1232 "Failed setting SO_RCVBUF"); 1233 } else { 1234 if (sobuf_size < turn_sock->setting.so_rcvbuf_size) { 1235 PJ_LOG(4, (turn_sock->obj_name, 1236 "Warning! Cannot set SO_RCVBUF as configured," 1237 " now=%d, configured=%d", sobuf_size, 1238 turn_sock->setting.so_rcvbuf_size)); 1239 } else { 1240 PJ_LOG(5, (turn_sock->obj_name, "SO_RCVBUF set to %d", 1241 sobuf_size)); 1242 } 1243 } 1244 } 1245 if (turn_sock->setting.so_sndbuf_size > 0) { 1246 unsigned sobuf_size = turn_sock->setting.so_sndbuf_size; 1247 status = pj_sock_setsockopt_sobuf(sock, pj_SO_SNDBUF(), PJ_TRUE, 1248 &sobuf_size); 1249 if (status != PJ_SUCCESS) { 1250 pj_perror(3, turn_sock->obj_name, status, 1251 "Failed setting SO_SNDBUF"); 1252 } else { 1253 if (sobuf_size < turn_sock->setting.so_sndbuf_size) { 1254 PJ_LOG(4, (turn_sock->obj_name, 1255 "Warning! Cannot set SO_SNDBUF as configured," 1256 " now=%d, configured=%d", sobuf_size, 1257 turn_sock->setting.so_sndbuf_size)); 1258 } else { 1259 PJ_LOG(5, (turn_sock->obj_name, "SO_SNDBUF set to %d", 1260 sobuf_size)); 1261 } 1262 } 1263 } 1264 1265 /* Create active socket */ 1266 pj_activesock_cfg_default(&asock_cfg); 1267 asock_cfg.grp_lock = turn_sock->grp_lock; 1268 1269 pj_bzero(&asock_cb, sizeof(asock_cb)); 1270 asock_cb.on_data_read = &dataconn_on_data_read; 1271 asock_cb.on_connect_complete = &dataconn_on_connect_complete; 1272 status = pj_activesock_create(pool, sock, 1273 pj_SOCK_STREAM(), &asock_cfg, 1274 turn_sock->cfg.ioqueue, &asock_cb, 1275 new_conn, &new_conn->asock); 1276 if (status != PJ_SUCCESS) 1277 goto on_return; 1278 1279 /* Connect to TURN server for data connection */ 1280 pj_turn_session_get_info(turn_sock->sess, &info); 1281 status = pj_activesock_start_connect(new_conn->asock, 1282 pool, 1283 &info.server, 1284 pj_sockaddr_get_len(&info.server)); 1285 if (status == PJ_SUCCESS) { 1286 dataconn_on_connect_complete(new_conn->asock, PJ_SUCCESS); 1287 pj_grp_lock_release(turn_sock->grp_lock); 1288 return; 1289 } 1290 1291 on_return: 1292 if (status == PJ_EPENDING) { 1293 PJ_LOG(5,(pool->obj_name, 1294 "Accepting connection from peer %s", 1295 pj_sockaddr_print(peer_addr, addrtxt, sizeof(addrtxt), 3))); 1296 } else { 1297 /* not PJ_SUCCESS */ 1298 pj_perror(4, pool->obj_name, status, 1299 "Failed in accepting connection from peer %s", 1300 pj_sockaddr_print(peer_addr, addrtxt, sizeof(addrtxt), 3)); 1301 1302 if (!new_conn->asock && sock != PJ_INVALID_SOCKET) 1303 pj_sock_close(sock); 1304 1305 dataconn_cleanup(new_conn); 1306 --turn_sock->data_conn_cnt; 1307 1308 /* Notify app for failure */ 1309 if (turn_sock->cb.on_connection_status) { 1310 (*turn_sock->cb.on_connection_status)(turn_sock, status, conn_id, 1311 peer_addr, addr_len); 1312 } 1313 } 1314 pj_grp_lock_release(turn_sock->grp_lock); 1315 } 1316 1317 static void turn_on_connection_bind_status(pj_turn_session *sess, 1318 pj_status_t status, 1319 pj_uint32_t conn_id, 1320 const pj_sockaddr_t *peer_addr, 1321 unsigned addr_len) 1322 { 1323 pj_turn_sock *turn_sock = (pj_turn_sock*) 1324 pj_turn_session_get_user_data(sess); 1325 tcp_data_conn_t *conn = NULL; 1326 unsigned i; 1327 1328 pj_grp_lock_acquire(turn_sock->grp_lock); 1329 1330 for (i=0; i < PJ_TURN_MAX_TCP_CONN_CNT; ++i) { 1331 tcp_data_conn_t *c = &turn_sock->data_conn[i]; 1332 if (c->id == conn_id && 1333 pj_sockaddr_cmp(peer_addr, &c->peer_addr) == 0) 1334 { 1335 conn = c; 1336 break; 1337 } 1338 } 1339 if (!conn) { 1340 PJ_LOG(5,(turn_sock->pool->obj_name, 1341 "Warning: stray connection bind event")); 1342 pj_grp_lock_release(turn_sock->grp_lock); 1343 return; 1344 } 1345 1346 if (status == PJ_SUCCESS) { 1347 conn->state = DATACONN_STATE_READY; 1348 } else { 1349 dataconn_cleanup(conn); 1350 --turn_sock->data_conn_cnt; 1351 } 1352 1353 pj_grp_lock_release(turn_sock->grp_lock); 1354 1355 if (turn_sock->cb.on_connection_status) { 1356 (*turn_sock->cb.on_connection_status)(turn_sock, status, conn_id, 1357 peer_addr, addr_len); 1358 } 1359 }
Note: See TracChangeset
for help on using the changeset viewer.