diff --git a/contrib/src/pjproject/0001-android.patch b/contrib/src/pjproject/0001-android.patch index 8142a78668e730ca9251b6268ea310cac5730cbb..c127d58e9c82c903e4bbaba635eb17cec543efca 100644 --- a/contrib/src/pjproject/0001-android.patch +++ b/contrib/src/pjproject/0001-android.patch @@ -1,43 +1,3 @@ -From 34ca3353abf3e6bdaab4abb7d5b996421500f3e0 Mon Sep 17 00:00:00 2001 -From: jrun <darwinskernel@gmail.com> -Date: Fri, 28 Feb 2020 12:33:24 -0500 -Subject: [PATCH] android - ---- - aconfigure | 3 --- - aconfigure.ac | 3 --- - pjlib/include/pj/config_site.h | 11 +++++++++++ - pjlib/src/pj/os_timestamp_posix.c | 2 +- - 4 files changed, 12 insertions(+), 7 deletions(-) - -diff --git a/aconfigure b/aconfigure -index 7faf6e24c..de04d77a6 100755 ---- a/aconfigure -+++ b/aconfigure -@@ -5996,9 +5996,6 @@ case $target in - esac - # UUID - case $target in -- *android*) -- ac_os_objs="$ac_os_objs guid_android.o" -- ;; - *) - if test "$ac_has_uuid_lib" = "1" -a "$ac_has_uuid_h" = "1"; then - ac_os_objs="$ac_os_objs guid_uuid.o" -diff --git a/aconfigure.ac b/aconfigure.ac -index 35d577081..a6a261cb4 100644 ---- a/aconfigure.ac -+++ b/aconfigure.ac -@@ -514,9 +514,6 @@ case $target in - esac - # UUID - case $target in -- *android*) -- ac_os_objs="$ac_os_objs guid_android.o" -- ;; - *) - if test "$ac_has_uuid_lib" = "1" -a "$ac_has_uuid_h" = "1"; then - ac_os_objs="$ac_os_objs guid_uuid.o" diff --git a/pjlib/include/pj/config_site.h b/pjlib/include/pj/config_site.h index 7b8ea2561..333dfc2f2 100644 --- a/pjlib/include/pj/config_site.h @@ -58,19 +18,6 @@ index 7b8ea2561..333dfc2f2 100644 +#define PJMEDIA_HAS_G722_CODEC 1 +#define PJMEDIA_VID_DEV_INFO_FMT_CNT 128 \ No newline at end of file -diff --git a/pjlib/src/pj/os_timestamp_posix.c b/pjlib/src/pj/os_timestamp_posix.c -index 0aed8c470..1ec156b0d 100644 ---- a/pjlib/src/pj/os_timestamp_posix.c -+++ b/pjlib/src/pj/os_timestamp_posix.c -@@ -203,7 +203,7 @@ PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq) - return PJ_SUCCESS; - } - --#elif defined(__ANDROID__) -+#elif defined(PJ_ANDROID) && PJ_ANDROID - - #include <errno.h> - #include <time.h> -- 2.25.1 diff --git a/contrib/src/pjproject/0001-rfc6544.patch b/contrib/src/pjproject/0001-rfc6544.patch deleted file mode 100644 index 4bce2171817dbc368480bf1ab2fcce701e6ff088..0000000000000000000000000000000000000000 --- a/contrib/src/pjproject/0001-rfc6544.patch +++ /dev/null @@ -1,4477 +0,0 @@ -Copyright (C) 2018-2021 Savoir-faire Linux Inc. - -ice: rfc6544 support - -This patch is an implementation proposal of the RFC 6544 into PJNATH. -This allow PJNATH to support TCP ICE candidates and open a direct TCP -connection between peers. - -+ BUG (semi-fixed with this patch): If an active_sock is busy due to -a pending packet and receives a new packet to send, the final sent -packet will be a mix between the pending packet and the new one. -To avoid this, pj_ice_strans_sendto2 is now introduced. - -Written by -Sébastien Blin <sebastien.blin@savoirfairelinux.com> -on behalf of Savoir-faire Linux. - -Rebased for pjsip 2.10 by Peymane Marandi -<paymon@savoirfairelinux.com> -on behalf of Savoir-faire Linux. - ---- - pjnath/include/pjnath/config.h | 9 + - pjnath/include/pjnath/ice_session.h | 216 ++++- - pjnath/include/pjnath/ice_strans.h | 21 + - pjnath/include/pjnath/stun_session.h | 75 +- - pjnath/include/pjnath/stun_sock.h | 67 +- - pjnath/include/pjnath/turn_sock.h | 11 + - pjnath/src/pjnath-test/concur_test.c | 5 +- - pjnath/src/pjnath-test/sess_auth.c | 14 +- - pjnath/src/pjnath-test/stun_sock_test.c | 7 +- - pjnath/src/pjnath/ice_session.c | 632 +++++++++++-- - pjnath/src/pjnath/ice_strans.c | 749 +++++++++++++--- - pjnath/src/pjnath/nat_detect.c | 7 +- - pjnath/src/pjnath/stun_session.c | 19 +- - pjnath/src/pjnath/stun_sock.c | 1081 +++++++++++++++++++---- - pjnath/src/pjnath/stun_transaction.c | 3 + - pjnath/src/pjnath/turn_session.c | 3 +- - pjnath/src/pjnath/turn_sock.c | 26 +- - pjnath/src/pjturn-client/client_main.c | 2 +- - pjnath/src/pjturn-srv/allocation.c | 3 +- - pjnath/src/pjturn-srv/server.c | 2 +- - pjsip-apps/src/samples/icedemo.c | 116 ++- - pjsip/src/pjsua-lib/pjsua_core.c | 2 +- - 22 files changed, 2606 insertions(+), 464 deletions(-) - -diff --git a/pjnath/include/pjnath/config.h b/pjnath/include/pjnath/config.h -index 8a656c225..3e7c6ae3a 100644 ---- a/pjnath/include/pjnath/config.h -+++ b/pjnath/include/pjnath/config.h -@@ -383,6 +383,15 @@ - # define ICE_CONTROLLED_AGENT_WAIT_NOMINATION_TIMEOUT 10000 - #endif - -+/** -+ * For TCP transport, this timer is time that a controlling agent must wait for -+ * incoming checks if the local candidate is of type "passive" or "s-o". -+ * -+ * Default: 10000 (milliseconds) -+ */ -+#ifndef ICE_CONTROLLING_PASSIVE_TIMEOUT -+# define ICE_CONTROLLING_PASSIVE_TIMEOUT 10000 -+#endif - - /** - * For controlling agent if it uses regular nomination, specify the delay to -diff --git a/pjnath/include/pjnath/ice_session.h b/pjnath/include/pjnath/ice_session.h -index 53d7fd2d4..5362c72e9 100644 ---- a/pjnath/include/pjnath/ice_session.h -+++ b/pjnath/include/pjnath/ice_session.h -@@ -163,6 +163,52 @@ typedef enum pj_ice_cand_type - - } pj_ice_cand_type; - -+/** -+ * ICE candidates types like described by RFC 6544. -+ */ -+typedef enum pj_ice_cand_transport { -+ /** -+ * Candidates UDP compatible -+ */ -+ PJ_CAND_UDP, -+ /** -+ * Candidates sending outgoing TCP connections -+ */ -+ PJ_CAND_TCP_ACTIVE, -+ /** -+ * Candidates accepting incoming TCP connections -+ */ -+ PJ_CAND_TCP_PASSIVE, -+ /** -+ * Candidates capable of receiving incoming connections and sending -+ * connections -+ */ -+ PJ_CAND_TCP_SO -+} pj_ice_cand_transport; -+ -+/** -+ * ICE transport types, which will be used both to specify the connection -+ * type for reaching candidates and other client -+ */ -+typedef enum pj_ice_tp_type { -+ /** -+ * UDP transport, which value corresponds to IANA protocol number. -+ */ -+ PJ_ICE_TP_UDP = 17, -+ -+ /** -+ * TCP transport, which value corresponds to IANA protocol number. -+ */ -+ PJ_ICE_TP_TCP = 6, -+ -+ /** -+ * TLS transport. The TLS transport will only be used as the connection -+ * type to reach the server and never as the allocation transport type. -+ */ -+ PJ_ICE_TP_TLS = 255 -+ -+} pj_ice_tp_type; -+ - - /** Forward declaration for pj_ice_sess */ - typedef struct pj_ice_sess pj_ice_sess; -@@ -170,9 +216,6 @@ typedef struct pj_ice_sess pj_ice_sess; - /** Forward declaration for pj_ice_sess_check */ - typedef struct pj_ice_sess_check pj_ice_sess_check; - --/** Forward declaration for pj_ice_sess_cand */ --typedef struct pj_ice_sess_cand pj_ice_sess_cand; -- - /** - * This structure describes ICE component. - * A media stream may require multiple components, each of which has -@@ -205,32 +248,6 @@ typedef struct pj_ice_sess_comp - } pj_ice_sess_comp; - - --/** -- * Data structure to be attached to internal message processing. -- */ --typedef struct pj_ice_msg_data --{ -- /** Transport ID for this message */ -- unsigned transport_id; -- -- /** Flag to indicate whether data.req contains data */ -- pj_bool_t has_req_data; -- -- /** The data */ -- union data { -- /** Request data */ -- struct request_data { -- pj_ice_sess *ice; /**< ICE session */ -- pj_ice_sess_checklist *clist; /**< Checklist */ -- unsigned ckid; /**< Check ID */ -- pj_ice_sess_cand *lcand; /**< Local cand */ -- pj_ice_sess_cand *rcand; /**< Remote cand */ -- } req; -- } data; -- --} pj_ice_msg_data; -- -- - /** - * This structure describes an ICE candidate. - * ICE candidate is a transport address that is to be tested by ICE -@@ -239,7 +256,7 @@ typedef struct pj_ice_msg_data - * (server reflexive, relayed or host), priority, foundation, and - * base. - */ --struct pj_ice_sess_cand -+typedef struct pj_ice_sess_cand - { - /** - * The candidate ID. -@@ -318,7 +335,37 @@ struct pj_ice_sess_cand - */ - pj_sockaddr rel_addr; - --}; -+ /** -+ * Transport used (TCP or UDP) -+ */ -+ pj_ice_cand_transport transport; -+ -+} pj_ice_sess_cand; -+ -+/** -+ * Data structure to be attached to internal message processing. -+ */ -+typedef struct pj_ice_msg_data -+{ -+ /** Transport ID for this message */ -+ unsigned transport_id; -+ -+ /** Flag to indicate whether data.req contains data */ -+ pj_bool_t has_req_data; -+ -+ /** The data */ -+ union data { -+ /** Request data */ -+ struct request_data { -+ pj_ice_sess *ice; /**< ICE session */ -+ pj_ice_sess_checklist *clist; /**< Checklist */ -+ unsigned ckid; /**< Check ID */ -+ pj_ice_sess_cand *lcand; /**< Local cand */ -+ pj_ice_sess_cand *rcand; /**< Remote cand */ -+ } req; -+ } data; -+ -+} pj_ice_msg_data; - - - /** -@@ -333,6 +380,22 @@ typedef enum pj_ice_sess_check_state - */ - PJ_ICE_SESS_CHECK_STATE_FROZEN, - -+ /** -+ * The following status is used when a packet sent via TURN got a -+ * "Connection reset by peer". This mean that the peer didn't allow -+ * us to connect yet. The socket will be reconnected during the next -+ * loop. -+ */ -+ PJ_ICE_SESS_CHECK_STATE_NEEDS_RETRY, -+ -+ /** -+ * TODO (sblin): REMOVE THIS! - https://github.com/coturn/coturn/issues/408 -+ * For now, this status is only used because sometimes, the first packet -+ * doesn't receive any response. So, we retry to send the packet every -+ * 50 loops. -+ */ -+ PJ_ICE_SESS_CHECK_STATE_NEEDS_FIRST_PACKET, -+ - /** - * A check has not been performed for this pair, and can be - * performed as soon as it is the highest priority Waiting pair on -@@ -340,6 +403,12 @@ typedef enum pj_ice_sess_check_state - */ - PJ_ICE_SESS_CHECK_STATE_WAITING, - -+ /** -+ * A check has not been performed for this pair, but TCP socket -+ * is currently connecting to the pair. Wait to finish the connection. -+ */ -+ PJ_ICE_SESS_CHECK_STATE_PENDING, -+ - /** - * A check has not been performed for this pair, and can be - * performed as soon as it is the highest priority Waiting pair on -@@ -544,6 +613,41 @@ typedef struct pj_ice_sess_cb - void *pkt, pj_size_t size, - const pj_sockaddr_t *src_addr, - unsigned src_addr_len); -+ -+ /** -+ * Wait for TCP and send connectivity check -+ * -+ * @param ice The ICE session. -+ * @param clist The ICE connection list -+ * @param check_id The wanted check. -+ */ -+ pj_status_t (*wait_tcp_connection)(pj_ice_sess *ice, -+ pj_ice_sess_checklist *clist, -+ unsigned check_id); -+ -+ /** -+ * Reconnect a resetted TCP connection and send connectivity check -+ * cf. PJ_ICE_SESS_CHECK_STATE_NEEDS_RETRY -+ * -+ * @param ice The ICE session. -+ * @param clist The ICE connection list -+ * @param check_id The wanted check. -+ */ -+ pj_status_t (*reconnect_tcp_connection)(pj_ice_sess *ice, -+ pj_ice_sess_checklist *clist, -+ unsigned check_id); -+ -+ /** -+ * Close TCP socket -+ * -+ * @param ice The ICE session. -+ * @param clist The ICE connection list -+ * @param check_id The wanted check. -+ */ -+ pj_status_t (*close_tcp_connection)(pj_ice_sess *ice, -+ pj_ice_sess_checklist *clist, -+ unsigned check_id); -+ - } pj_ice_sess_cb; - - -@@ -673,6 +777,13 @@ typedef struct pj_ice_sess_options - */ - pj_ice_sess_trickle trickle; - -+ /** -+ * For a controlling agent, specify how long it wants to wait -+ * in milliseconds for passive candidates and wait for connection -+ * attempts -+ */ -+ int controlling_agent_passive_timeout; -+ - } pj_ice_sess_options; - - -@@ -705,6 +816,7 @@ struct pj_ice_sess - pj_status_t ice_status; /**< Error status. */ - pj_timer_entry timer; /**< ICE timer. */ - pj_timer_entry timer_end_of_cand; /**< End-of-cand timer. */ -+ pj_timer_entry timer_connect; /**< ICE timer tcp timeout*/ - pj_ice_sess_cb cb; /**< Callback. */ - - pj_stun_config stun_cfg; /**< STUN settings. */ -@@ -928,6 +1040,7 @@ PJ_DECL(pj_status_t) pj_ice_sess_set_prefs(pj_ice_sess *ice, - * @param rel_addr Optional related address. - * @param addr_len Length of addresses. - * @param p_cand_id Optional pointer to receive the candidate ID. -+ * @param transport Candidate's type - * - * @return PJ_SUCCESS if candidate is successfully added. - */ -@@ -941,7 +1054,8 @@ PJ_DECL(pj_status_t) pj_ice_sess_add_cand(pj_ice_sess *ice, - const pj_sockaddr_t *base_addr, - const pj_sockaddr_t *rel_addr, - int addr_len, -- unsigned *p_cand_id); -+ unsigned *p_cand_id, -+ pj_ice_cand_transport transport); - - /** - * Find default candidate for the specified component ID, using this -@@ -1088,6 +1202,44 @@ PJ_DECL(pj_status_t) pj_ice_sess_on_rx_pkt(pj_ice_sess *ice, - const pj_sockaddr_t *src_addr, - int src_addr_len); - -+/** -+ * Notification when ICE session get a new incoming connection -+ * -+ * @param ice The ICE session. -+ * @param transport_id Related transport -+ * @param status PJ_SUCCESS when connection is made, or any errors -+ * if the connection has failed (or if the peer has -+ * disconnected after an established connection). -+ * @param remote_addr Connected remove address -+ */ -+PJ_DECL(void) ice_sess_on_peer_connection(pj_ice_sess *ice, -+ pj_uint8_t transport_id, -+ pj_status_t status, -+ pj_sockaddr_t* remote_addr); -+ -+/** -+ * Notification when ICE session get a new resetted connection -+ * cf PJ_ICE_SESS_CHECK_STATE_NEEDS_RETRY -+ * -+ * @param ice The ICE session. -+ * @param transport_id Related transport -+ * @param remote_addr Connected remove address -+ */ -+PJ_DECL(void) ice_sess_on_peer_reset_connection(pj_ice_sess *ice, -+ pj_uint8_t transport_id, -+ pj_sockaddr_t* remote_addr); -+ -+/** -+ * Notification when ICE session get a new packet -+ * Used to remove the PJ_ICE_SESS_CHECK_STATE_NEEDS_FIRST_PACKET status -+ * -+ * @param ice The ICE session. -+ * @param transport_id Related transport -+ * @param remote_addr Connected remove address -+ */ -+PJ_DECL(void) ice_sess_on_peer_packet(pj_ice_sess *ice, -+ pj_uint8_t transport_id, -+ pj_sockaddr_t* remote_addr); - - - /** -diff --git a/pjnath/include/pjnath/ice_strans.h b/pjnath/include/pjnath/ice_strans.h -index dbad30766..1c20729e8 100644 ---- a/pjnath/include/pjnath/ice_strans.h -+++ b/pjnath/include/pjnath/ice_strans.h -@@ -301,6 +301,13 @@ typedef struct pj_ice_strans_stun_cfg - */ - pj_bool_t ignore_stun_error; - -+ /** -+ * Type of connection to the STUN server. -+ * -+ * Default is PJ_STUN_TP_UDP. -+ */ -+ pj_stun_tp_type conn_type; -+ - } pj_ice_strans_stun_cfg; - - -@@ -316,6 +323,13 @@ typedef struct pj_ice_strans_turn_cfg - */ - int af; - -+ /** -+ * If we want to use UDP or TCP as described by RFC 6544. -+ * This will discover candidates via TCP sockets. Then it will -+ * transfer messages on the transport via TCP. -+ */ -+ pj_ice_tp_type protocol; -+ - /** - * Optional TURN socket settings. The default values will be - * initialized by #pj_turn_sock_cfg_default(). This contains -@@ -395,6 +409,13 @@ typedef struct pj_ice_strans_cfg - */ - int af; - -+ /** -+ * If we want to use UDP or TCP as described by RFC 6544. -+ * This will discover candidates via TCP sockets. Then it will -+ * transfer messages on the transport via TCP. -+ */ -+ pj_ice_tp_type protocol; -+ - /** - * STUN configuration which contains the timer heap and - * ioqueue instance to be used, and STUN retransmission -diff --git a/pjnath/include/pjnath/stun_session.h b/pjnath/include/pjnath/stun_session.h -index bee630ab4..3f2ecf739 100644 ---- a/pjnath/include/pjnath/stun_session.h -+++ b/pjnath/include/pjnath/stun_session.h -@@ -174,6 +174,29 @@ typedef struct pj_stun_rx_data pj_stun_rx_data; - /** Forward declaration for pj_stun_session */ - typedef struct pj_stun_session pj_stun_session; - -+/** -+ * STUN transport types, which will be used both to specify the connection -+ * type for reaching STUN server and the type of allocation transport to be -+ * requested to server (the REQUESTED-TRANSPORT attribute). -+ */ -+typedef enum pj_stun_tp_type { -+ /** -+ * UDP transport, which value corresponds to IANA protocol number. -+ */ -+ PJ_STUN_TP_UDP = 17, -+ -+ /** -+ * TCP transport, which value corresponds to IANA protocol number. -+ */ -+ PJ_STUN_TP_TCP = 6, -+ -+ /** -+ * TLS transport. The TLS transport will only be used as the connection -+ * type to reach the server and never as the allocation transport type. -+ */ -+ PJ_STUN_TP_TLS = 255 -+ -+} pj_stun_tp_type; - - /** - * This is the callback to be registered to pj_stun_session, to send -@@ -307,6 +330,38 @@ typedef struct pj_stun_session_cb - const pj_sockaddr_t *src_addr, - unsigned src_addr_len); - -+ /** -+ * Notification when STUN session get a ConnectionAttempt indication. -+ * -+ * @param stun_session The STUN session. -+ * @param status PJ_SUCCESS when connection is made, or any errors -+ * if the connection has failed (or if the peer has -+ * disconnected after an established connection). -+ * @param remote_addr The remote connected -+ */ -+ void (*on_peer_connection)(pj_stun_session *sess, -+ pj_status_t status, -+ pj_sockaddr_t* remote_addr); -+ -+ /** -+ * Notification when STUN connection is resetted (TCP only). -+ * -+ * @param stun_session The STUN session. -+ * @param remote_addr The remote resetted -+ */ -+ void (*on_peer_reset_connection)(pj_stun_session *sess, -+ pj_sockaddr_t* -+ remote_addr); -+ -+ /** -+ * Notification when STUN connection is resetted (TCP only). -+ * -+ * @param stun_session The STUN session. -+ * @param remote_addr The remote resetted -+ */ -+ void (*on_peer_packet)(pj_stun_session *sess, -+ pj_sockaddr_t* remote_addr); -+ - } pj_stun_session_cb; - - -@@ -390,6 +445,7 @@ typedef enum pj_stun_sess_msg_log_flag - * @param grp_lock Optional group lock to be used by this session. - * If NULL, the session will create one itself. - * @param p_sess Pointer to receive STUN session instance. -+ * @param conn_type If the session use UDP or TCP - * - * @return PJ_SUCCESS on success, or the appropriate error code. - */ -@@ -398,7 +454,8 @@ PJ_DECL(pj_status_t) pj_stun_session_create(pj_stun_config *cfg, - const pj_stun_session_cb *cb, - pj_bool_t fingerprint, - pj_grp_lock_t *grp_lock, -- pj_stun_session **p_sess); -+ pj_stun_session **p_sess, -+ pj_stun_tp_type conn_type); - - /** - * Destroy the STUN session and all objects created in the context of -@@ -752,6 +809,22 @@ PJ_DECL(pj_status_t) pj_stun_session_on_rx_pkt(pj_stun_session *sess, - PJ_DECL(void) pj_stun_msg_destroy_tdata(pj_stun_session *sess, - pj_stun_tx_data *tdata); - -+/** -+ * -+ * @param sess The STUN session. -+ * -+ * @return The callback linked to the STUN session -+ */ -+PJ_DECL(pj_stun_session_cb *) pj_stun_session_callback(pj_stun_session *sess); -+ -+/** -+ * -+ * @param sess The STUN session. -+ * -+ * @return The connection type linked to the STUN session -+ */ -+PJ_DECL(pj_stun_tp_type) pj_stun_session_tp_type(pj_stun_session *sess); -+ - - /** - * @} -diff --git a/pjnath/include/pjnath/stun_sock.h b/pjnath/include/pjnath/stun_sock.h -index fe99292de..51f60cc03 100644 ---- a/pjnath/include/pjnath/stun_sock.h -+++ b/pjnath/include/pjnath/stun_sock.h -@@ -24,10 +24,14 @@ - * @file stun_sock.h - * @brief STUN aware socket transport - */ -+#include <pj/activesock.h> - #include <pjnath/stun_config.h> -+#include <pjnath/stun_session.h> - #include <pjlib-util/resolver.h> -+#include <pjlib-util/srv_resolver.h> - #include <pj/ioqueue.h> - #include <pj/lock.h> -+#include <pj/pool.h> - #include <pj/sock.h> - #include <pj/sock_qos.h> - -@@ -87,7 +91,17 @@ typedef enum pj_stun_sock_op - /** - * IP address change notification from the keep-alive operation. - */ -- PJ_STUN_SOCK_MAPPED_ADDR_CHANGE -+ PJ_STUN_SOCK_MAPPED_ADDR_CHANGE, -+ -+ /** -+ * STUN session was destroyed. -+ */ -+ PJ_STUN_SESS_DESTROYED, -+ -+ /** -+ * TCP fails to connect -+ */ -+ PJ_STUN_TCP_CONNECT_ERROR - - - } pj_stun_sock_op; -@@ -197,6 +211,11 @@ typedef struct pj_stun_sock_info - */ - pj_sockaddr mapped_addr; - -+ /** -+ * If connected, the remote address will be stored here. -+ */ -+ pj_sockaddr outgoing_addr; -+ - /** - * Number of interface address aliases. The interface address aliases - * are list of all interface addresses in this host. -@@ -208,6 +227,11 @@ typedef struct pj_stun_sock_info - */ - pj_sockaddr aliases[PJ_ICE_ST_MAX_CAND]; - -+ /** -+ * The tranport type of the socket -+ */ -+ pj_stun_tp_type conn_type; -+ - } pj_stun_sock_info; - - -@@ -343,6 +367,9 @@ PJ_DECL(void) pj_stun_sock_cfg_default(pj_stun_sock_cfg *cfg); - * the operation of this transport. - * @param af Address family of socket. Currently pj_AF_INET() - * and pj_AF_INET6() are supported. -+ * @param conn_type Connection type to the STUN server. Both TCP and UDP are -+ * supported. -+ * - * @param name Optional name to be given to this transport to - * assist debugging. - * @param cb Callback to receive events/data from the transport. -@@ -357,6 +384,7 @@ PJ_DECL(void) pj_stun_sock_cfg_default(pj_stun_sock_cfg *cfg); - PJ_DECL(pj_status_t) pj_stun_sock_create(pj_stun_config *stun_cfg, - const char *name, - int af, -+ pj_stun_tp_type conn_type, - const pj_stun_sock_cb *cb, - const pj_stun_sock_cfg *cfg, - void *user_data, -@@ -485,6 +513,43 @@ PJ_DECL(pj_status_t) pj_stun_sock_sendto(pj_stun_sock *stun_sock, - const pj_sockaddr_t *dst_addr, - unsigned addr_len); - -+ -+#if PJ_HAS_TCP -+/** -+ * Connect active socket to remote address -+ * @param stun_sock -+ * @param remote_addr the destination -+ * @param af address family -+ */ -+PJ_DECL(pj_status_t) pj_stun_sock_connect_active(pj_stun_sock *stun_sock, -+ const pj_sockaddr_t *remote_addr, -+ int af); -+ -+/** -+ * Connect active socket to remote address -+ * @param stun_sock -+ * @param remote_addr the destination -+ * @param af address family -+ */ -+PJ_DECL(pj_status_t) pj_stun_sock_reconnect_active(pj_stun_sock *stun_sock, -+ const pj_sockaddr_t *remote_addr, -+ int af); -+ -+/** -+ * Close active socket -+ * @param stun_sock -+ * @param remote_addr The remote address linked -+ */ -+PJ_DECL(pj_status_t) pj_stun_sock_close(pj_stun_sock *stun_sock, -+ const pj_sockaddr_t *remote_addr); -+ -+#endif -+ -+/** -+ * Retrieve the linked session -+ * @param stun_sock -+ */ -+PJ_DECL(pj_stun_session *) pj_stun_sock_get_session(pj_stun_sock *stun_sock); - /** - * @} - */ -diff --git a/pjnath/include/pjnath/turn_sock.h b/pjnath/include/pjnath/turn_sock.h -index e4d306174..35388809f 100644 ---- a/pjnath/include/pjnath/turn_sock.h -+++ b/pjnath/include/pjnath/turn_sock.h -@@ -623,6 +623,17 @@ PJ_DECL(pj_status_t) pj_turn_sock_bind_channel(pj_turn_sock *turn_sock, - const pj_sockaddr_t *peer, - unsigned addr_len); - -+/** -+ * Check if peer is a dataconn -+ * -+ * @param turn_sock The turn sock -+ * @param peer The peer addr to check -+ * -+ * @return true if dataconn else false -+ */ -+PJ_DECL(pj_bool_t) pj_turn_sock_has_dataconn(pj_turn_sock *turn_sock, -+ const pj_sockaddr_t *peer); -+ - - /** - * @} -diff --git a/pjnath/src/pjnath-test/concur_test.c b/pjnath/src/pjnath-test/concur_test.c -index c3013d2ab..7777c637c 100644 ---- a/pjnath/src/pjnath-test/concur_test.c -+++ b/pjnath/src/pjnath-test/concur_test.c -@@ -184,8 +184,9 @@ static int stun_destroy_test_session(struct stun_test_session *test_sess) - char name[10]; - sprintf(name, "stun%02d", i); - status = pj_stun_sock_create(&test_sess->stun_cfg, name, pj_AF_INET(), -- &stun_cb, NULL, test_sess, -- &stun_sock[i]); -+ PJ_STUN_TP_UDP, -+ &stun_cb, NULL, test_sess, -+ &stun_sock[i]); - if (status != PJ_SUCCESS) { - PJ_PERROR(1,(THIS_FILE, status, "Error creating stun socket")); - return -10; -diff --git a/pjnath/src/pjnath-test/sess_auth.c b/pjnath/src/pjnath-test/sess_auth.c -index 055eaad61..1d07bf299 100644 ---- a/pjnath/src/pjnath-test/sess_auth.c -+++ b/pjnath/src/pjnath-test/sess_auth.c -@@ -248,7 +248,8 @@ static int create_std_server(pj_stun_auth_type auth_type, - pj_bzero(&sess_cb, sizeof(sess_cb)); - sess_cb.on_rx_request = &server_on_rx_request; - sess_cb.on_send_msg = &server_send_msg; -- status = pj_stun_session_create(&stun_cfg, "server", &sess_cb, PJ_FALSE, NULL, &server->sess); -+ status = pj_stun_session_create(&stun_cfg, "server", &sess_cb, PJ_FALSE, -+ NULL, &server->sess, PJ_STUN_TP_UDP); - if (status != PJ_SUCCESS) { - destroy_server(); - return -10; -@@ -489,7 +490,8 @@ static int run_client_test(const char *title, - pj_bzero(&sess_cb, sizeof(sess_cb)); - sess_cb.on_request_complete = &client_on_request_complete; - sess_cb.on_send_msg = &client_send_msg; -- status = pj_stun_session_create(&stun_cfg, "client", &sess_cb, PJ_FALSE, NULL, &client->sess); -+ status = pj_stun_session_create(&stun_cfg, "client", &sess_cb, PJ_FALSE, -+ NULL, &client->sess, PJ_STUN_TP_UDP); - if (status != PJ_SUCCESS) { - destroy_client_server(); - return -200; -@@ -575,8 +577,12 @@ static int run_client_test(const char *title, - } - - /* Send the request */ -- status = pj_stun_session_send_msg(client->sess, NULL, PJ_FALSE, PJ_TRUE, &server->addr, -- pj_sockaddr_get_len(&server->addr), tdata); -+ status = pj_stun_session_send_msg(client->sess, NULL, PJ_FALSE, -+ (pj_stun_session_tp_type(client->sess) == -+ PJ_STUN_TP_UDP), -+ &server->addr, -+ pj_sockaddr_get_len(&server->addr), -+ tdata); - if (status != PJ_SUCCESS) { - destroy_client_server(); - return -270; -diff --git a/pjnath/src/pjnath-test/stun_sock_test.c b/pjnath/src/pjnath-test/stun_sock_test.c -index 18a1bbd13..577659c87 100644 ---- a/pjnath/src/pjnath-test/stun_sock_test.c -+++ b/pjnath/src/pjnath-test/stun_sock_test.c -@@ -254,8 +254,9 @@ static pj_status_t create_client(pj_stun_config *cfg, - pj_bzero(&cb, sizeof(cb)); - cb.on_status = &stun_sock_on_status; - cb.on_rx_data = &stun_sock_on_rx_data; -- status = pj_stun_sock_create(cfg, NULL, GET_AF(use_ipv6), &cb, &sock_cfg, -- client, &client->sock); -+ status = pj_stun_sock_create(cfg, NULL, GET_AF(use_ipv6), -+ PJ_STUN_TP_UDP, -+ &cb, &sock_cfg, client, &client->sock); - if (status != PJ_SUCCESS) { - app_perror(" pj_stun_sock_create()", status); - pj_pool_release(pool); -@@ -584,7 +585,7 @@ static int keep_alive_test(pj_stun_config *cfg, pj_bool_t use_ipv6) - PJ_LOG(3,(THIS_FILE, " sending to %s", pj_sockaddr_print(&info.srv_addr, txt, sizeof(txt), 3))); - } - status = pj_stun_sock_sendto(client->sock, NULL, &ret, sizeof(ret), -- 0, &info.srv_addr, -+ 0, &info.srv_addr, - pj_sockaddr_get_len(&info.srv_addr)); - if (status != PJ_SUCCESS && status != PJ_EPENDING) { - app_perror(" error: server sending data", status); -diff --git a/pjnath/src/pjnath/ice_session.c b/pjnath/src/pjnath/ice_session.c -index 3fecc3def..8917f647c 100644 ---- a/pjnath/src/pjnath/ice_session.c -+++ b/pjnath/src/pjnath/ice_session.c -@@ -18,6 +18,7 @@ - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - #include <pjnath/ice_session.h> -+#include <pjnath/stun_session.h> - #include <pj/addr_resolv.h> - #include <pj/array.h> - #include <pj/assert.h> -@@ -44,7 +45,10 @@ static const char *cand_type_names[] = - static const char *check_state_name[] = - { - "Frozen", -+ "Needs Retry", -+ "Needs First Packet", - "Waiting", -+ "Pending", - "In Progress", - "Succeeded", - "Failed" -@@ -69,13 +73,15 @@ enum timer_type - { - TIMER_NONE, /**< Timer not active */ - TIMER_COMPLETION_CALLBACK, /**< Call on_ice_complete() callback */ -+ TIMER_CONTROLLING_TCP_PASSIVE_TIMEOUT, /** < Controlling agent is waiting for passive TCP connection timeout **/ - TIMER_CONTROLLED_WAIT_NOM, /**< Controlled agent is waiting for - controlling agent to send connectivity - check with nominated flag after it has - valid check for every components. */ - TIMER_START_NOMINATED_CHECK,/**< Controlling agent start connectivity - checks with USE-CANDIDATE flag. */ -- TIMER_KEEP_ALIVE /**< ICE keep-alive timer. */ -+ TIMER_KEEP_ALIVE, /**< ICE keep-alive timer. */ -+ TIMER_CONNECTION_TIMEOUT - - }; - -@@ -123,6 +129,8 @@ typedef struct timer_data - { - pj_ice_sess *ice; - pj_ice_sess_checklist *clist; -+ /* TODO (remove), for now, needed for the NEEDS_FIRST_PACKET state */ -+ unsigned first_packet_counter; - } timer_data; - - -@@ -133,6 +141,7 @@ typedef struct timer_data - - /* Forward declarations */ - static void on_timer(pj_timer_heap_t *th, pj_timer_entry *te); -+static void on_tcp_connect_timeout(pj_ice_sess *ice); - static void on_ice_complete(pj_ice_sess *ice, pj_status_t status); - static void ice_keep_alive(pj_ice_sess *ice, pj_bool_t send_now); - static void ice_on_destroy(void *obj); -@@ -293,7 +302,8 @@ static pj_status_t init_comp(pj_ice_sess *ice, - status = pj_stun_session_create(&ice->stun_cfg, NULL, - &sess_cb, PJ_TRUE, - ice->grp_lock, -- &comp->stun_sess); -+ &comp->stun_sess, -+ PJ_STUN_TP_UDP); - if (status != PJ_SUCCESS) - return status; - -@@ -326,6 +336,7 @@ PJ_DEF(void) pj_ice_sess_options_default(pj_ice_sess_options *opt) - opt->controlled_agent_want_nom_timeout = - ICE_CONTROLLED_AGENT_WAIT_NOMINATION_TIMEOUT; - opt->trickle = PJ_ICE_SESS_TRICKLE_DISABLED; -+ opt->controlling_agent_passive_timeout = ICE_CONTROLLING_PASSIVE_TIMEOUT; - } - - /* -@@ -362,6 +373,7 @@ PJ_DEF(pj_status_t) pj_ice_sess_create(pj_stun_config *stun_cfg, - pj_ice_sess_options_default(&ice->opt); - - pj_timer_entry_init(&ice->timer, TIMER_NONE, (void*)ice, &on_timer); -+ pj_timer_entry_init(&ice->timer_connect, TIMER_NONE, (void*)ice, &on_timer); - - pj_ansi_snprintf(ice->obj_name, sizeof(ice->obj_name), - name, ice); -@@ -508,6 +520,9 @@ static void destroy_ice(pj_ice_sess *ice, - pj_timer_heap_cancel_if_active(ice->stun_cfg.timer_heap, - &ice->timer, PJ_FALSE); - -+ pj_timer_heap_cancel_if_active(ice->stun_cfg.timer_heap, -+ &ice->timer_connect, TIMER_NONE); -+ - for (i=0; i<ice->comp_cnt; ++i) { - if (ice->comp[i].stun_sess) { - pj_stun_session_destroy(ice->comp[i].stun_sess); -@@ -733,7 +748,8 @@ PJ_DEF(pj_status_t) pj_ice_sess_add_cand(pj_ice_sess *ice, - const pj_sockaddr_t *base_addr, - const pj_sockaddr_t *rel_addr, - int addr_len, -- unsigned *p_cand_id) -+ unsigned *p_cand_id, -+ pj_ice_cand_transport transport) - { - pj_ice_sess_cand *lcand; - pj_status_t status = PJ_SUCCESS; -@@ -779,6 +795,7 @@ PJ_DEF(pj_status_t) pj_ice_sess_add_cand(pj_ice_sess *ice, - lcand->comp_id = (pj_uint8_t)comp_id; - lcand->transport_id = (pj_uint8_t)transport_id; - lcand->type = type; -+ lcand->transport = transport; - pj_strdup(ice->pool, &lcand->foundation, foundation); - lcand->local_pref = local_pref; - lcand->prio = CALC_CAND_PRIO(ice, type, local_pref, lcand->comp_id); -@@ -1020,6 +1037,9 @@ static void check_set_state(pj_ice_sess *ice, pj_ice_sess_check *check, - pj_ice_sess_check_state st, - pj_status_t err_code) - { -+ if (check->state >= PJ_ICE_SESS_CHECK_STATE_SUCCEEDED) -+ return; -+ - LOG5((ice->obj_name, "Check %s: state changed from %s to %s", - dump_check(ice->tmp.txt, sizeof(ice->tmp.txt), &ice->clist, check), - check_state_name[check->state], -@@ -1171,6 +1191,15 @@ static pj_status_t prune_checklist(pj_ice_sess *ice, - return PJNATH_EICENOHOSTCAND; - } - } -+ -+ /* Section 6.2, RFC 6544 (https://tools.ietf.org/html/rfc6544) -+ * When the agent prunes the check list, it MUST also remove any pair -+ * for which the local candidate is a passive TCP candidate -+ */ -+ if (clist->checks[i].lcand->transport == PJ_CAND_TCP_PASSIVE) { -+ remove_check(ice, clist, i, "local passive TCP"); -+ i--; -+ } - } - - /* Next remove a pair if its local and remote candidates are identical -@@ -1240,10 +1269,14 @@ static void on_timer(pj_timer_heap_t *th, pj_timer_entry *te) - } - - switch (type) { -+ case TIMER_CONTROLLING_TCP_PASSIVE_TIMEOUT: -+ LOG4((ice->obj_name, -+ "Controlling agent timed-out while waiting for incoming TCP checks. Set state to failed!")); -+ on_ice_complete(ice, PJNATH_EICEFAILED); -+ break; - case TIMER_CONTROLLED_WAIT_NOM: - LOG4((ice->obj_name, -- "Controlled agent timed-out in waiting for the controlling " -- "agent to send nominated check. Setting state to fail now..")); -+ "Controlled agent timed-out while waiting for nomination controlling agent")); - on_ice_complete(ice, PJNATH_EICENOMTIMEOUT); - break; - case TIMER_COMPLETION_CALLBACK: -@@ -1273,6 +1306,9 @@ static void on_timer(pj_timer_heap_t *th, pj_timer_entry *te) - case TIMER_KEEP_ALIVE: - ice_keep_alive(ice, PJ_TRUE); - break; -+ case TIMER_CONNECTION_TIMEOUT: -+ on_tcp_connect_timeout(ice); -+ break; - case TIMER_NONE: - /* Nothing to do, just to get rid of gcc warning */ - break; -@@ -1481,15 +1517,27 @@ static pj_bool_t check_ice_complete(pj_ice_sess *ice) - * See if all checks in the checklist have completed. If we do, - * then mark ICE processing as failed. - */ -- if (!ice->is_trickling) { -- for (i=0; i<ice->clist.count; ++i) { -- pj_ice_sess_check *c = &ice->clist.checks[i]; -- if (c->state < PJ_ICE_SESS_CHECK_STATE_SUCCEEDED) { -- break; -- } -+#if PJ_HAS_TCP -+ pj_bool_t hasTCP = PJ_FALSE; -+#endif -+ for (i=0; i<ice->clist.count; ++i) { -+ pj_ice_sess_check *c = &ice->clist.checks[i]; -+ -+#if PJ_HAS_TCP -+ if (c && c->lcand && -+ ( -+ c->lcand->transport == PJ_CAND_TCP_ACTIVE -+ )) { -+ hasTCP = PJ_TRUE; -+ } -+#endif -+ if (!ice->is_trickling &&c->state < PJ_ICE_SESS_CHECK_STATE_SUCCEEDED) { -+ break; - } -- no_pending_check = (i == ice->clist.count); - } -+ if (!ice->is_trickling) { -+ no_pending_check = (i == ice->clist.count); -+ } - - if (no_pending_check) { - /* All checks have completed, but we don't have nominated pair. -@@ -1506,8 +1554,8 @@ static pj_bool_t check_ice_complete(pj_ice_sess *ice) - - if (i < ice->comp_cnt) { - /* This component ID doesn't have valid pair. -- * Mark ICE as failed. -- */ -+ * Mark ICE as failed. -+ */ - on_ice_complete(ice, PJNATH_EICEFAILED); - return PJ_TRUE; - } else { -@@ -1541,11 +1589,48 @@ static pj_bool_t check_ice_complete(pj_ice_sess *ice) - /* Unreached */ - - } else if (ice->is_nominating) { -- /* We are controlling agent and all checks have completed but -- * there's at least one component without nominated pair (or -- * more likely we don't have any nominated pairs at all). -- */ -- on_ice_complete(ice, PJNATH_EICEFAILED); -+#if PJ_HAS_TCP -+ if (hasTCP) { -+ // STUN server procedure https://tools.ietf.org/html/rfc6544#section-7.2 -+ // An ICE TCP agent, full or lite, MUST be prepared to receive incoming -+ // TCP connection requests on the base of any TCP candidate that is -+ // simultaneous-open or passive. When the connection request is -+ // received, the agent MUST accept it. -+ // https://tools.ietf.org/html/rfc5245#section-2.6 -+ // In that case, allowing ICE to run a little longer might produce -+ // better results. -+ if (ice->timer.id == TIMER_NONE && -+ ice->opt.controlling_agent_passive_timeout >= 0) -+ { -+ pj_time_val delay; -+ -+ delay.sec = 0; -+ delay.msec = ice->opt.controlling_agent_passive_timeout; -+ pj_time_val_normalize(&delay); -+ -+ pj_timer_heap_schedule_w_grp_lock( -+ ice->stun_cfg.timer_heap, -+ &ice->timer, &delay, -+ TIMER_CONTROLLING_TCP_PASSIVE_TIMEOUT, -+ ice->grp_lock); -+ -+ LOG5((ice->obj_name, -+ "All checks have completed but failed. Just " -+ "wait for passive connections to timeout " -+ "(timeout=%d msec)", -+ ice->opt.controlling_agent_passive_timeout)); -+ } -+ return PJ_FALSE; -+ } else { -+#endif -+ /* We are controlling agent and all checks have completed but -+ * there's at least one component without nominated pair (or -+ * more likely we don't have any nominated pairs at all). -+ */ -+ on_ice_complete(ice, PJNATH_EICEFAILED); -+#if PJ_HAS_TCP -+ } -+#endif - return PJ_TRUE; - - } else { -@@ -1737,6 +1822,44 @@ static pj_bool_t on_check_complete(pj_ice_sess *ice, - return check_ice_complete(ice); - } - -+static void on_tcp_connect_timeout(pj_ice_sess* ice) -+{ -+ pj_timer_heap_cancel_if_active(ice->stun_cfg.timer_heap,&ice->timer_connect, -+ TIMER_NONE); -+ -+ pj_bool_t first_found = PJ_FALSE, set_timer = PJ_FALSE; -+ -+ for (int i = 0; i<ice->clist.count && !set_timer; ++i) { -+ pj_ice_sess_check *check = &ice->clist.checks[i]; -+ if (check->state == PJ_ICE_SESS_CHECK_STATE_PENDING) { -+ if (first_found) { -+ set_timer = PJ_TRUE; -+ } else { -+ first_found = PJ_TRUE; -+ if (*ice->cb.close_tcp_connection) -+ (*ice->cb.close_tcp_connection)(ice, &ice->clist, i); -+ -+ check_set_state(ice, check, -+ PJ_ICE_SESS_CHECK_STATE_FAILED, PJ_ECANCELLED); -+ on_check_complete(ice, check); -+ } -+ } -+ } -+ -+ if (set_timer && ice->timer_connect.id == TIMER_NONE) { -+ /* Reschedule */ -+ pj_time_val delay = { -+ .sec = 15, -+ .msec = 0 -+ }; -+ pj_time_val_normalize(&delay); -+ pj_timer_heap_schedule_w_grp_lock(ice->stun_cfg.timer_heap, -+ &ice->timer_connect, &delay, -+ TIMER_CONNECTION_TIMEOUT, -+ ice->grp_lock); -+ } -+} -+ - - /* Get foundation index of a check pair. This function can also be used for - * adding a new foundation (combination of local & remote cands foundations) -@@ -1905,6 +2028,29 @@ static pj_status_t add_rcand_and_update_checklist( - continue; - } - -+ /* Section 6.2, RFC 6544 (https://tools.ietf.org/html/rfc6544) -+ * As with UDP, check lists are formed only by full ICE implementations. -+ * When forming candidate pairs, the following types of TCP candidates -+ * can be paired with each other: -+ * -+ * Local Remote -+ * Candidate Candidate -+ * --------------------------- -+ * tcp-so tcp-so -+ * tcp-active tcp-passive -+ * tcp-passive tcp-active -+ */ -+ if ((lcand->transport == PJ_CAND_UDP && -+ rcand->transport != PJ_CAND_UDP) || -+ (lcand->transport == PJ_CAND_TCP_PASSIVE && -+ rcand->transport != PJ_CAND_TCP_ACTIVE) || -+ (lcand->transport == PJ_CAND_TCP_ACTIVE && -+ rcand->transport != PJ_CAND_TCP_PASSIVE) || -+ (lcand->transport == PJ_CAND_TCP_SO && -+ rcand->transport != PJ_CAND_TCP_SO)) -+ { -+ continue; -+ } - #if 0 - /* Trickle ICE: - * Make sure that pair has not been added to checklist -@@ -1925,7 +2071,6 @@ static pj_status_t add_rcand_and_update_checklist( - } - #endif - -- - /* Add the pair */ - chk = &clist->checks[clist->count]; - chk->lcand = lcand; -@@ -2121,6 +2266,7 @@ PJ_DEF(pj_status_t) pj_ice_sess_create_check_list( - td = PJ_POOL_ZALLOC_T(ice->pool, timer_data); - td->ice = ice; - td->clist = clist; -+ td->first_packet_counter = 1; - clist->timer.user_data = (void*)td; - clist->timer.cb = &periodic_timer; - -@@ -2209,6 +2355,36 @@ PJ_DEF(pj_status_t) pj_ice_sess_update_check_list( - return status; - } - -+static pj_status_t send_connectivity_check(pj_ice_sess *ice, -+ pj_ice_sess_checklist *clist, -+ unsigned check_id, -+ pj_bool_t nominate, -+ pj_ice_msg_data *msg_data) -+{ -+ pj_ice_sess_check *check; -+ const pj_ice_sess_cand *lcand; -+ const pj_ice_sess_cand *rcand; -+ pj_ice_sess_comp *comp; -+ -+ check = &clist->checks[check_id]; -+ lcand = check->lcand; -+ rcand = check->rcand; -+ comp = find_comp(ice, lcand->comp_id); -+ -+ /* Note that USERNAME and MESSAGE-INTEGRITY will be added by the -+ * STUN session. -+ */ -+ -+ /* Initiate STUN transaction to send the request */ -+ -+ return pj_stun_session_send_msg(comp->stun_sess, msg_data, PJ_FALSE, -+ pj_stun_session_tp_type(comp->stun_sess)== -+ PJ_STUN_TP_UDP, -+ &rcand->addr, -+ pj_sockaddr_get_len(&rcand->addr), -+ check->tdata); -+} -+ - /* Perform check on the specified candidate pair. */ - static pj_status_t perform_check(pj_ice_sess *ice, - pj_ice_sess_checklist *clist, -@@ -2219,19 +2395,17 @@ static pj_status_t perform_check(pj_ice_sess *ice, - pj_ice_msg_data *msg_data; - pj_ice_sess_check *check; - const pj_ice_sess_cand *lcand; -- const pj_ice_sess_cand *rcand; - pj_uint32_t prio; - pj_status_t status; - - check = &clist->checks[check_id]; - lcand = check->lcand; -- rcand = check->rcand; - comp = find_comp(ice, lcand->comp_id); - -+ pj_log_push_indent(); - LOG5((ice->obj_name, - "Sending connectivity check for check %s", - dump_check(ice->tmp.txt, sizeof(ice->tmp.txt), clist, check))); -- pj_log_push_indent(); - - /* Create request */ - status = pj_stun_session_create_req(comp->stun_sess, -@@ -2282,32 +2456,71 @@ static pj_status_t perform_check(pj_ice_sess *ice, - &ice->tie_breaker); - - } else { -+ if (nominate) { -+ check->nominated = PJ_TRUE; -+ } - pj_stun_msg_add_uint64_attr(check->tdata->pool, check->tdata->msg, - PJ_STUN_ATTR_ICE_CONTROLLED, - &ice->tie_breaker); - } - -+#if PJ_HAS_TCP -+ switch (lcand->transport) { -+ case PJ_CAND_TCP_ACTIVE: -+ switch (check->state) { -+ case PJ_ICE_SESS_CHECK_STATE_NEEDS_RETRY: -+ status = (*ice->cb.reconnect_tcp_connection)(ice, clist, check_id); -+ break; -+ case PJ_ICE_SESS_CHECK_STATE_NEEDS_FIRST_PACKET: -+ status = send_connectivity_check(ice, clist, check_id, -+ nominate, msg_data); -+ break; -+ default: -+ pj_timer_heap_cancel_if_active(ice->stun_cfg.timer_heap, -+ &ice->timer_connect, TIMER_NONE); -+ status = (*ice->cb.wait_tcp_connection)(ice, clist, check_id); -+ if (ice->timer_connect.id != TIMER_NONE) { -+ pj_assert(!"Not expected any timer active"); -+ } else { -+ pj_time_val delay = { -+ .sec = 15, -+ .msec = 0, -+ }; -+ pj_time_val_normalize(&delay); -+ pj_timer_heap_schedule_w_grp_lock(ice->stun_cfg.timer_heap, -+ &ice->timer_connect, &delay, -+ TIMER_CONNECTION_TIMEOUT, -+ ice->grp_lock); -+ } -+ break; -+ } -+ break; -+ case PJ_CAND_TCP_PASSIVE: -+ case PJ_CAND_TCP_SO: -+ case PJ_CAND_UDP: -+ default: -+ status = send_connectivity_check(ice, clist, check_id, nominate, msg_data); -+ break; -+ } -+#else -+ status = send_connectivity_check(ice, clist, check_id, nominate, msg_data); -+#endif - -- /* Note that USERNAME and MESSAGE-INTEGRITY will be added by the -- * STUN session. -- */ -- -- /* Initiate STUN transaction to send the request */ -- status = pj_stun_session_send_msg(comp->stun_sess, msg_data, PJ_FALSE, -- PJ_TRUE, &rcand->addr, -- pj_sockaddr_get_len(&rcand->addr), -- check->tdata); -- if (status != PJ_SUCCESS) { -+ if (status == PJ_SUCCESS) { -+ check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS, -+ status); -+ } else if (status == PJ_EPENDING) { -+ check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_PENDING, status); -+ } else if (check->rcand->type == PJ_ICE_CAND_TYPE_RELAYED) { -+ /* TODO (sblin) remove this - https://github.com/coturn/coturn/issues/408 */ -+ check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_NEEDS_FIRST_PACKET, -+ status); -+ } else { - check->tdata = NULL; -- pjnath_perror(ice->obj_name, "Error sending STUN request", status); -- pj_log_pop_indent(); -- return status; -+ pjnath_perror(ice->obj_name, "Error sending STUN request (perform check)", status); - } -- -- check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS, -- PJ_SUCCESS); - pj_log_pop_indent(); -- return PJ_SUCCESS; -+ return status; - } - - -@@ -2344,55 +2557,108 @@ static pj_status_t start_periodic_check(pj_timer_heap_t *th, - pj_log_push_indent(); - - /* Send STUN Binding request for check with highest priority on -- * Waiting state. -+ * Retry state. - */ -- for (i=0; i<clist->count; ++i) { -- pj_ice_sess_check *check = &clist->checks[i]; - -- if (check->state == PJ_ICE_SESS_CHECK_STATE_WAITING) { -- status = perform_check(ice, clist, i, ice->is_nominating); -- if (status != PJ_SUCCESS) { -- check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, -- status); -- on_check_complete(ice, check); -+ if (start_count == 0) { -+ for (i = 0; i < clist->count; ++i) { -+ pj_ice_sess_check *check = &clist->checks[i]; -+ // Reconnect closed TURN sockets -+ if (check->state == PJ_ICE_SESS_CHECK_STATE_NEEDS_RETRY) { -+ status = perform_check(ice, clist, i, ice->is_nominating); -+ if (status != PJ_SUCCESS && status != PJ_EPENDING) { -+ check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, -+ status); -+ on_check_complete(ice, check); -+ } -+ ++start_count; -+ break; - } -+ } -+ } - -- ++start_count; -- break; -+ if (start_count == 0) { -+ // TODO (sblin) remove - https://github.com/coturn/coturn/issues/408 -+ pj_bool_t inc_counter = PJ_TRUE; -+ for (i = 0; i < clist->count; ++i) { -+ pj_ice_sess_check *check = &clist->checks[i]; -+ if (check->state == PJ_ICE_SESS_CHECK_STATE_NEEDS_FIRST_PACKET) { -+ if (inc_counter) { -+ td->first_packet_counter += 1; -+ inc_counter = PJ_FALSE; -+ } -+ if (td->first_packet_counter % 50 == 0) { -+ status = perform_check(ice, clist, i, ice->is_nominating); -+ if (status != PJ_SUCCESS && status != PJ_EPENDING) { -+ check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, -+ status); -+ on_check_complete(ice, check); -+ } -+ } -+ ++start_count; -+ break; -+ } -+ } -+ } -+ -+ /* Send STUN Binding request for check with highest priority on -+ * Waiting state. -+ */ -+ -+ if (start_count == 0) { -+ for (i = 0; i < clist->count; ++i) { -+ pj_ice_sess_check *check = &clist->checks[i]; -+ -+ if (check->state == PJ_ICE_SESS_CHECK_STATE_WAITING) { -+ status = perform_check(ice, clist, i, ice->is_nominating); -+ if (status != PJ_SUCCESS && status != PJ_EPENDING) { -+ check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, -+ status); -+ on_check_complete(ice, check); -+ } -+ ++start_count; -+ break; -+ } - } - } - - /* If we don't have anything in Waiting state, perform check to - * highest priority pair that is in Frozen state. - */ -- if (start_count==0) { -- for (i=0; i<clist->count; ++i) { -+ if (start_count == 0) { -+ for (i = 0; i < clist->count; ++i) { - pj_ice_sess_check *check = &clist->checks[i]; - - if (check->state == PJ_ICE_SESS_CHECK_STATE_FROZEN) { - status = perform_check(ice, clist, i, ice->is_nominating); -- if (status != PJ_SUCCESS) { -- check_set_state(ice, check, -- PJ_ICE_SESS_CHECK_STATE_FAILED, status); -+ if (status != PJ_SUCCESS && status != PJ_EPENDING) { -+ check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, status); - on_check_complete(ice, check); - } -+ ++start_count; -+ break; -+ } -+ } -+ } - -+ if (start_count == 0) { -+ // If all sockets are pending, do nothing -+ for (i = 0; i < clist->count; ++i) { -+ pj_ice_sess_check *check = &clist->checks[i]; -+ if (check->state == PJ_ICE_SESS_CHECK_STATE_PENDING) { - ++start_count; - break; - } - } - } - -- /* Schedule next check for next candidate pair, unless there is no -- * suitable candidate pair (all pairs have been checked or empty -- * checklist). -- */ -+ // Cannot start check because there's no suitable candidate pair. - if (start_count!=0) { - pj_time_val timeout = {0, PJ_ICE_TA_VAL}; - - pj_time_val_normalize(&timeout); - pj_timer_heap_schedule_w_grp_lock(th, te, &timeout, PJ_TRUE, -- ice->grp_lock); -+ ice->grp_lock); - } - - pj_grp_lock_release(ice->grp_lock); -@@ -2636,6 +2902,222 @@ static pj_status_t on_stun_send_msg(pj_stun_session *sess, - return status; - } - -+static pj_ice_sess_check* get_current_check_at_state(pj_ice_sess *ice, -+ pj_sockaddr_t *remote_addr, -+ pj_ice_sess_check_state state, -+ int *current_check) -+{ -+ if (!ice || !remote_addr) -+ return NULL; -+ // NOTE: Multiple checks can have the same remote, we only take care of the first -+ // First, check if the TCP is really connected. If not, abort -+ pj_ice_sess_check *check = NULL; -+ for (int i = 0; i < ice->clist.count; ++i) { -+ // Find related check -+ pj_ice_sess_check *c = &ice->clist.checks[i]; -+ /* Host candidate not found this this srflx! */ -+ if (pj_sockaddr_cmp(remote_addr, &c->rcand->addr) == 0) { -+ if (c->tdata == NULL || c->state != state) -+ continue; -+ /* Match */ -+ check = c; -+ if (current_check) *current_check = i; -+ break; -+ } -+ } -+ return check; -+} -+ -+void ice_sess_on_peer_connection(pj_ice_sess *ice, -+ pj_uint8_t transport_id, -+ pj_status_t status, -+ pj_sockaddr_t* remote_addr) -+{ -+ // The TCP link is now ready. We can now send the first STUN message (send -+ // connectivity check) This should trigger on_stun_request_complete when -+ // finished -+ if (!remote_addr) -+ return; -+ -+ pj_grp_lock_acquire(ice->grp_lock); -+ -+ int current_check = -1; -+ pj_ice_sess_check *check = get_current_check_at_state(ice,remote_addr, -+ PJ_ICE_SESS_CHECK_STATE_PENDING, -+ ¤t_check); -+ if (!check) { -+ // Handle peer reflexive candidates (incoming are still waiting here) -+ check = get_current_check_at_state(ice, remote_addr, -+ PJ_ICE_SESS_CHECK_STATE_WAITING, -+ ¤t_check); -+ if (!check) { -+ pj_grp_lock_release(ice->grp_lock); -+ return; -+ } -+ } -+ -+ const pj_ice_sess_cand *rcand = check->rcand; -+ if (rcand->type == PJ_ICE_CAND_TYPE_RELAYED && ( -+ status == PJ_ERRNO_START_SYS + 104 || status == 130054 /* CONNECTION RESET BY PEER */ || -+ status == PJ_ERRNO_START_SYS + 111 /* Connection refused */ -+ )) { -+ /** -+ * This part of the code is triggered when using ICE over TCP via TURN -+ * In fact, the other peer has to authorize this peer to connect to -+ * the relayed candidate. This is done by set_perm from the other case. -+ * But from this side, we can't know if the peer has authorized us. If it's -+ * not the case, the connection will got a CONNECTION RESET BY PEER status. -+ * In this case, we can try to reconnect a bit after and this until the check -+ * reached its timeout. -+ */ -+ check->state = PJ_ICE_SESS_CHECK_STATE_NEEDS_RETRY; -+ check_set_state(ice, check,PJ_ICE_SESS_CHECK_STATE_NEEDS_RETRY, -+ status); -+ pj_grp_lock_release(ice->grp_lock); -+ return; -+ } else if (status != PJ_SUCCESS) { -+ if (rcand->type == PJ_ICE_CAND_TYPE_RELAYED) { -+ char raddr[PJ_INET6_ADDRSTRLEN + 10]; -+ PJ_LOG(4, (ice->obj_name, -+ "Connection to TURN (%s) failed with status %u", -+ pj_sockaddr_print(&rcand->addr, raddr, sizeof(raddr), 3), status)); -+ } -+ check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, status); -+ on_check_complete(ice, check); -+ pj_grp_lock_release(ice->grp_lock); -+ return; -+ } -+ -+ // TCP is correctly connected. Craft the message to send -+ const pj_ice_sess_cand *lcand = check->lcand; -+ if (check->tdata == NULL) { -+ LOG5((ice->obj_name, "Error sending STUN request, empty data")); -+ pj_grp_lock_release(ice->grp_lock); -+ return; -+ } -+ pj_ice_msg_data *msg_data = -+ PJ_POOL_ZALLOC_T(check->tdata->pool, pj_ice_msg_data); -+ -+ msg_data->transport_id = transport_id; -+ msg_data->has_req_data = PJ_TRUE; -+ msg_data->data.req.ice = ice; -+ msg_data->data.req.clist = &ice->clist; -+ msg_data->data.req.ckid = current_check; -+ msg_data->data.req.lcand = check->lcand; -+ msg_data->data.req.rcand = check->rcand; -+ -+ pj_ice_sess_comp *comp = find_comp(ice, lcand->comp_id); -+ // Note that USERNAME and MESSAGE-INTEGRITY will be added by the -+ // STUN session. -+ -+ // Initiate STUN transaction to send the request -+ status = pj_stun_session_send_msg(comp->stun_sess, msg_data, -+ PJ_FALSE, PJ_FALSE, &rcand->addr, -+ pj_sockaddr_get_len(&rcand->addr), -+ check->tdata); -+ -+ if (rcand->type == PJ_ICE_CAND_TYPE_RELAYED && ( -+ status == PJ_ERRNO_START_SYS + 104 || status == 130054 || /* CONNECTION RESET BY PEER */ -+ status == PJ_ERRNO_START_SYS + 32 /* EPIPE */ || -+ status == PJ_ERRNO_START_SYS + 111 /* Connection refused */ -+ )) { -+ /** -+ * This part of the code is triggered when using ICE over TCP via TURN -+ * In fact, the other peer has to authorize this peer to connect to -+ * the relayed candidate. This is done by set_perm from the other case. -+ * But from this side, we can't know if the peer has authorized us. If it's -+ * not the case, the connection will got a CONNECTION RESET BY PEER status. -+ * In this case, we can try to reconnect a bit after and this until the check -+ * reached its timeout. -+ */ -+ check_set_state(ice, check,PJ_ICE_SESS_CHECK_STATE_NEEDS_RETRY, -+ status); -+ } else if (status == PJ_EBUSY /* EBUSY */) { -+ check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_NEEDS_FIRST_PACKET, -+ status); -+ } else if (status != PJ_SUCCESS) { -+ -+ if (rcand->type == PJ_ICE_CAND_TYPE_RELAYED) { -+ char raddr[PJ_INET6_ADDRSTRLEN + 10]; -+ PJ_LOG(5, (ice->obj_name, -+ "STUN send message to TURN (%s) failed with status %u", -+ pj_sockaddr_print(&rcand->addr, raddr, sizeof(raddr), 3), status)); -+ } -+ check->tdata = NULL; -+ pjnath_perror(ice->obj_name, "Error sending STUN request (on peer connection)", status); -+ pj_log_pop_indent(); -+ check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, status); -+ on_check_complete(ice, check); -+ } else { -+ check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS, status); -+ } -+ pj_grp_lock_release(ice->grp_lock); -+} -+ -+void ice_sess_on_peer_reset_connection(pj_ice_sess *ice, -+ pj_uint8_t transport_id, -+ pj_sockaddr_t* remote_addr) -+{ -+ // The TCP link is reset -+ if (!remote_addr) -+ return; -+ -+ pj_grp_lock_acquire(ice->grp_lock); -+ pj_ice_sess_check *check = get_current_check_at_state(ice, remote_addr, -+ PJ_ICE_SESS_CHECK_STATE_PENDING, -+ NULL); -+ if (!check) { -+ // Just check if it's not the first packet failing -+ check = get_current_check_at_state(ice, remote_addr, -+ PJ_ICE_SESS_CHECK_STATE_NEEDS_FIRST_PACKET, -+ NULL); -+ if (!check) { -+ pj_grp_lock_release(ice->grp_lock); -+ return; -+ } -+ } -+ -+ const pj_ice_sess_cand *rcand = check->rcand; -+ if (rcand->type == PJ_ICE_CAND_TYPE_RELAYED) { -+ char raddr[PJ_INET6_ADDRSTRLEN + 10]; -+ PJ_LOG(5, (ice->obj_name, -+ "Connection to TURN (%s) is reset", -+ pj_sockaddr_print(&rcand->addr, raddr, sizeof(raddr), 3))); -+ -+ check->state = PJ_ICE_SESS_CHECK_STATE_NEEDS_RETRY; -+ check_set_state(ice, check, -+ PJ_ICE_SESS_CHECK_STATE_NEEDS_RETRY, 120104); -+ } -+ -+ pj_grp_lock_release(ice->grp_lock); -+} -+ -+void ice_sess_on_peer_packet(pj_ice_sess *ice, -+ pj_uint8_t transport_id, -+ pj_sockaddr_t* remote_addr) -+{ -+ // The TCP link received its bind request response -+ if (!ice || !remote_addr) { -+ return; -+ } -+ -+ pj_grp_lock_acquire(ice->grp_lock); -+ pj_ice_sess_check *check = -+ get_current_check_at_state(ice, remote_addr, -+ PJ_ICE_SESS_CHECK_STATE_NEEDS_FIRST_PACKET, -+ NULL); -+ if (!check) { -+ pj_grp_lock_release(ice->grp_lock); -+ return; -+ } -+ -+ const pj_ice_sess_cand *rcand = check->rcand; -+ if (rcand->type == PJ_ICE_CAND_TYPE_RELAYED) { -+ check_set_state(ice, check, -+ PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS, PJ_SUCCESS); -+ } -+ pj_grp_lock_release(ice->grp_lock); -+} - - /* This callback is called when outgoing STUN request completed */ - static void on_stun_request_complete(pj_stun_session *stun_sess, -@@ -2941,7 +3423,9 @@ static void on_stun_request_complete(pj_stun_session *stun_sess, - &check->lcand->base_addr, - &check->lcand->base_addr, - pj_sockaddr_get_len(&xaddr->sockaddr), -- &cand_id); -+ &cand_id, -+ check->rcand->transport == PJ_CAND_UDP ? -+ PJ_CAND_UDP : PJ_CAND_TCP_PASSIVE); - if (status != PJ_SUCCESS) { - check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, - status); -@@ -3003,11 +3487,7 @@ static void on_stun_request_complete(pj_stun_session *stun_sess, - /* Perform 7.1.2.2.2. Updating Pair States. - * This may terminate ICE processing. - */ -- if (on_check_complete(ice, check)) { -- /* ICE complete! */ -- pj_grp_lock_release(ice->grp_lock); -- return; -- } -+ on_check_complete(ice, check); - - pj_grp_lock_release(ice->grp_lock); - } -@@ -3202,9 +3682,13 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess, - msg_data->has_req_data = PJ_FALSE; - - /* Send the response */ -- status = pj_stun_session_send_msg(sess, msg_data, PJ_TRUE, PJ_TRUE, -+ status = pj_stun_session_send_msg(sess, msg_data, PJ_TRUE, -+ pj_stun_session_tp_type(sess) == -+ PJ_STUN_TP_UDP, - src_addr, src_addr_len, tdata); -- -+ if (status == PJ_EBUSY) { -+ PJ_LOG(5, (ice->obj_name, "on_stun_rx_request, PJ_EBUSY")); -+ } - - /* - * Handling early check. -@@ -3323,12 +3807,12 @@ static void handle_incoming_check(pj_ice_sess *ice, - /* Just get candidate with the highest priority and same transport ID - * for the specified component ID in the checklist. - */ -- for (i=0; i<ice->clist.count; ++i) { -- pj_ice_sess_check *c = &ice->clist.checks[i]; -- if (c->lcand->comp_id == rcheck->comp_id && -- c->lcand->transport_id == rcheck->transport_id) -+ for (i=0; i<ice->lcand_cnt; ++i) { -+ pj_ice_sess_cand* lcand_tmp = &ice->lcand[i]; -+ if (lcand_tmp->comp_id == rcheck->comp_id && -+ lcand_tmp->transport_id == rcheck->transport_id) - { -- lcand = c->lcand; -+ lcand = lcand_tmp; - break; - } - } -diff --git a/pjnath/src/pjnath/ice_strans.c b/pjnath/src/pjnath/ice_strans.c -index 72978a574..0fdd2c695 100644 ---- a/pjnath/src/pjnath/ice_strans.c -+++ b/pjnath/src/pjnath/ice_strans.c -@@ -69,6 +69,7 @@ enum tp_type - # define RELAY_PREF ((1 << PJ_ICE_LOCAL_PREF_BITS) - 1) - #endif - -+#define MAX_RTP_SIZE 65536 - - /* The candidate type preference when STUN candidate is used */ - static pj_uint8_t srflx_pref_table[PJ_ICE_CAND_TYPE_MAX] = -@@ -87,6 +88,14 @@ static pj_uint8_t srflx_pref_table[PJ_ICE_CAND_TYPE_MAX] = - #endif - }; - -+////////////////////////////////////////////////////////////////////////////// -+ -+static pj_uint16_t GETVAL16H(const pj_uint8_t *buf1, const pj_uint8_t *buf2) -+{ -+ return (pj_uint16_t) ((buf1[0] << 8) | (buf2[0] << 0)); -+} -+ -+////////////////////////////////////////////////////////////////////////////// - - /* ICE callbacks */ - static void on_valid_pair(pj_ice_sess *ice); -@@ -104,6 +113,20 @@ static void ice_rx_data(pj_ice_sess *ice, - const pj_sockaddr_t *src_addr, - unsigned src_addr_len); - -+#if PJ_HAS_TCP -+static pj_status_t ice_wait_tcp_connection(pj_ice_sess *ice, -+ pj_ice_sess_checklist *clist, -+ unsigned check_id); -+ -+static pj_status_t ice_reconnect_tcp_connection(pj_ice_sess *ice, -+ pj_ice_sess_checklist *clist, -+ unsigned check_id); -+ -+static pj_status_t ice_close_tcp_connection(pj_ice_sess *ice, -+ pj_ice_sess_checklist *clist, -+ unsigned check_id); -+#endif -+ - - /* STUN socket callbacks */ - /* Notification when incoming packet has been received. */ -@@ -183,6 +206,16 @@ typedef struct pj_ice_strans_comp - } pj_ice_strans_comp; - - -+static pj_bool_t add_local_candidate(pj_ice_sess_cand *cand, -+ unsigned idx, -+ unsigned i, -+ unsigned *cand_cnt, -+ unsigned *max_cand_cnt, -+ pj_stun_sock_info stun_sock_info, -+ pj_ice_strans *ice_st, -+ pj_ice_strans_comp *comp, -+ pj_ice_cand_transport transport); -+ - /* Pending send buffer */ - typedef struct pending_send - { -@@ -231,6 +264,12 @@ struct pj_ice_strans - signalled end of candidate? */ - pj_bool_t loc_cand_end;/**< Trickle ICE: local has - signalled end of candidate? */ -+ pj_uint8_t rtp_pkt[MAX_RTP_SIZE]; -+ pj_uint8_t rx_buffer[MAX_RTP_SIZE]; -+ pj_uint16_t rx_buffer_size; -+ pj_uint16_t rx_wanted_size; -+ -+ pj_ssize_t last_data_len; /**< What the application is waiting. */ - }; - - -@@ -267,6 +306,7 @@ PJ_DEF(void) pj_ice_strans_cfg_default(pj_ice_strans_cfg *cfg) - pj_bzero(cfg, sizeof(*cfg)); - - cfg->af = pj_AF_INET(); -+ cfg->protocol = PJ_ICE_TP_UDP; - pj_stun_config_init(&cfg->stun_cfg, NULL, 0, NULL, NULL); - pj_ice_strans_stun_cfg_default(&cfg->stun); - pj_ice_strans_turn_cfg_default(&cfg->turn); -@@ -284,6 +324,7 @@ PJ_DEF(void) pj_ice_strans_stun_cfg_default(pj_ice_strans_stun_cfg *cfg) - pj_bzero(cfg, sizeof(*cfg)); - - cfg->af = pj_AF_INET(); -+ cfg->conn_type = PJ_STUN_TP_UDP; - cfg->port = PJ_STUN_PORT; - cfg->max_host_cands = 64; - cfg->ignore_stun_error = PJ_FALSE; -@@ -427,6 +468,9 @@ static pj_status_t add_update_turn(pj_ice_strans *ice_st, - cand->transport_id = tp_id; - cand->comp_id = (pj_uint8_t) comp->comp_id; - new_cand = PJ_TRUE; -+ cand->transport = turn_cfg->conn_type == PJ_TURN_TP_UDP ? -+ PJ_CAND_UDP : -+ PJ_CAND_TCP_PASSIVE; - } - - /* Allocate and initialize TURN socket data */ -@@ -434,6 +478,10 @@ static pj_status_t add_update_turn(pj_ice_strans *ice_st, - data->comp = comp; - data->transport_id = cand->transport_id; - -+ if (turn_cfg->conn_type == PJ_TURN_TP_TCP) { -+ turn_cfg->alloc_param.peer_conn_type = PJ_TURN_TP_TCP; -+ } -+ - /* Create the TURN transport */ - status = pj_turn_sock_create(&ice_st->cfg.stun_cfg, turn_cfg->af, - turn_cfg->conn_type, -@@ -475,7 +523,7 @@ static pj_status_t add_update_turn(pj_ice_strans *ice_st, - return PJ_SUCCESS; - } - --static pj_bool_t ice_cand_equals(pj_ice_sess_cand *lcand, -+static pj_bool_t ice_cand_equals(pj_ice_sess_cand *lcand, - pj_ice_sess_cand *rcand) - { - if (lcand == NULL && rcand == NULL){ -@@ -484,7 +532,7 @@ static pj_bool_t ice_cand_equals(pj_ice_sess_cand *lcand, - if (lcand == NULL || rcand == NULL){ - return PJ_FALSE; - } -- -+ - if (lcand->type != rcand->type - || lcand->status != rcand->status - || lcand->comp_id != rcand->comp_id -@@ -492,16 +540,16 @@ static pj_bool_t ice_cand_equals(pj_ice_sess_cand *lcand, - // local pref is no longer a constant, so it may be different - //|| lcand->local_pref != rcand->local_pref - || lcand->prio != rcand->prio -+ || lcand->transport != rcand->transport - || pj_sockaddr_cmp(&lcand->addr, &rcand->addr) != 0 - || pj_sockaddr_cmp(&lcand->base_addr, &rcand->base_addr) != 0) - { - return PJ_FALSE; - } -- -+ - return PJ_TRUE; - } - -- - static pj_status_t add_stun_and_host(pj_ice_strans *ice_st, - pj_ice_strans_comp *comp, - unsigned idx, -@@ -552,6 +600,9 @@ static pj_status_t add_stun_and_host(pj_ice_strans *ice_st, - cand->local_pref = (pj_uint16_t)(SRFLX_PREF - idx); - cand->transport_id = CREATE_TP_ID(TP_STUN, idx); - cand->comp_id = (pj_uint8_t) comp->comp_id; -+ cand->transport = stun_cfg->conn_type == PJ_STUN_TP_UDP ? -+ PJ_CAND_UDP : -+ PJ_CAND_TCP_PASSIVE; - - /* Allocate and initialize STUN socket data */ - data = PJ_POOL_ZALLOC_T(ice_st->pool, sock_user_data); -@@ -560,8 +611,9 @@ static pj_status_t add_stun_and_host(pj_ice_strans *ice_st, - - /* Create the STUN transport */ - status = pj_stun_sock_create(&ice_st->cfg.stun_cfg, NULL, -- stun_cfg->af, &stun_sock_cb, -- sock_cfg, data, &comp->stun[idx].sock); -+ stun_cfg->af, stun_cfg->conn_type, -+ &stun_sock_cb, sock_cfg, data, -+ &comp->stun[idx].sock); - if (status != PJ_SUCCESS) - return status; - -@@ -646,105 +698,153 @@ static pj_status_t add_stun_and_host(pj_ice_strans *ice_st, - } - - for (i = 0; i < stun_sock_info.alias_cnt && -- cand_cnt < stun_cfg->max_host_cands; ++i) -+ cand_cnt < stun_cfg->max_host_cands && -+ status == PJ_SUCCESS; ++i) - { -- unsigned j; -- pj_bool_t cand_duplicate = PJ_FALSE; -- char addrinfo[PJ_INET6_ADDRSTRLEN+10]; -- const pj_sockaddr *addr = &stun_sock_info.aliases[i]; -+ status = !PJ_SUCCESS; -+ if (stun_sock_info.conn_type == PJ_STUN_TP_UDP) { -+ status = add_local_candidate(cand, idx, i, -+ &cand_cnt, &max_cand_cnt, -+ stun_sock_info, ice_st, comp, -+ PJ_CAND_UDP); -+ } else { -+ status = add_local_candidate(cand, idx, i, -+ &cand_cnt, &max_cand_cnt, -+ stun_sock_info, ice_st, comp, -+ PJ_CAND_TCP_PASSIVE); -+ /** RFC 6544, Section 4.1: -+ * First, agents SHOULD obtain host candidates as described in -+ * Section 5.1. Then, each agent SHOULD "obtain" (allocate a -+ * placeholder for) an active host candidate for each component of -+ * each TCP-capable media stream on each interface that the host -+ * has. The agent does not yet have to actually allocate a port for -+ * these candidates, but they are used for the creation of the check -+ * lists. -+ */ -+ status = add_local_candidate(cand, idx, i, -+ &cand_cnt, &max_cand_cnt, -+ stun_sock_info, ice_st, comp, -+ PJ_CAND_TCP_ACTIVE); -+ } -+ } -+ } - -- if (max_cand_cnt==0) { -- PJ_LOG(4,(ice_st->obj_name, "Too many host candidates")); -- break; -- } -+ return status; -+} - -- /* Ignore loopback addresses if cfg->stun.loop_addr is unset */ -- if (stun_cfg->loop_addr==PJ_FALSE) { -- if (stun_cfg->af == pj_AF_INET() && -- (pj_ntohl(addr->ipv4.sin_addr.s_addr)>>24)==127) -- { -- continue; -- } -- else if (stun_cfg->af == pj_AF_INET6()) { -- pj_in6_addr in6addr = {{{0}}}; -- in6addr.s6_addr[15] = 1; -- if (pj_memcmp(&in6addr, &addr->ipv6.sin6_addr, -- sizeof(in6addr))==0) -- { -- continue; -- } -- } -- } -+static pj_bool_t add_local_candidate(pj_ice_sess_cand *cand, -+ unsigned idx, -+ unsigned i, -+ unsigned *cand_cnt, -+ unsigned *max_cand_cnt, -+ pj_stun_sock_info stun_sock_info, -+ pj_ice_strans *ice_st, -+ pj_ice_strans_comp *comp, -+ pj_ice_cand_transport transport) -+{ -+ unsigned j; -+ pj_bool_t cand_duplicate = PJ_FALSE; -+ char addrinfo[PJ_INET6_ADDRSTRLEN+10]; -+ const pj_sockaddr *addr = &stun_sock_info.aliases[i]; -+ pj_ice_strans_stun_cfg *stun_cfg = &ice_st->cfg.stun_tp[idx]; - -- /* Ignore IPv6 link-local address, unless it is the default -- * address (first alias). -- */ -- if (stun_cfg->af == pj_AF_INET6() && i != 0) { -- const pj_in6_addr *a = &addr->ipv6.sin6_addr; -- if (a->s6_addr[0] == 0xFE && (a->s6_addr[1] & 0xC0) == 0x80) -- continue; -- } - -- cand = &comp->cand_list[comp->cand_cnt]; -- -- cand->type = PJ_ICE_CAND_TYPE_HOST; -- cand->status = PJ_SUCCESS; -- cand->local_pref = (pj_uint16_t)(HOST_PREF - cand_cnt); -- cand->transport_id = CREATE_TP_ID(TP_STUN, idx); -- cand->comp_id = (pj_uint8_t) comp->comp_id; -- pj_sockaddr_cp(&cand->addr, addr); -- pj_sockaddr_cp(&cand->base_addr, addr); -- pj_bzero(&cand->rel_addr, sizeof(cand->rel_addr)); -- -- /* Check if not already in list */ -- for (j=0; j<comp->cand_cnt; j++) { -- if (ice_cand_equals(cand, &comp->cand_list[j])) { -- cand_duplicate = PJ_TRUE; -- break; -- } -- } -+ if (*max_cand_cnt==0) { -+ PJ_LOG(4,(ice_st->obj_name, "Too many host candidates")); -+ return !PJ_SUCCESS; -+ } - -- if (cand_duplicate) { -- PJ_LOG(4, (ice_st->obj_name, -- "Comp %d: host candidate %s (tpid=%d) is a duplicate", -- comp->comp_id, pj_sockaddr_print(&cand->addr, addrinfo, -- sizeof(addrinfo), 3), cand->transport_id)); -+ /* Ignore loopback addresses if cfg->stun.loop_addr is unset */ -+ if (stun_cfg->loop_addr==PJ_FALSE) { -+ if (stun_cfg->af == pj_AF_INET() && -+ (pj_ntohl(addr->ipv4.sin_addr.s_addr)>>24)==127) -+ { -+ return PJ_SUCCESS; -+ } -+ else if (stun_cfg->af == pj_AF_INET6()) { -+ pj_in6_addr in6addr = {{0}}; -+ in6addr.s6_addr[15] = 1; -+ if (pj_memcmp(&in6addr, &addr->ipv6.sin6_addr, -+ sizeof(in6addr))==0) -+ { -+ return PJ_SUCCESS; -+ } -+ } -+ } - -- pj_bzero(&cand->addr, sizeof(cand->addr)); -- pj_bzero(&cand->base_addr, sizeof(cand->base_addr)); -- continue; -- } else { -- comp->cand_cnt+=1; -- cand_cnt++; -- max_cand_cnt--; -- } -- -- pj_ice_calc_foundation(ice_st->pool, &cand->foundation, -- cand->type, &cand->base_addr); -+ /* Ignore IPv6 link-local address, unless it is the default -+ * address (first alias). -+ */ -+ if (stun_cfg->af == pj_AF_INET6() && i != 0) { -+ const pj_in6_addr *a = &addr->ipv6.sin6_addr; -+ if (a->s6_addr[0] == 0xFE && (a->s6_addr[1] & 0xC0) == 0x80) -+ return PJ_SUCCESS; -+ } - -- /* Set default candidate with the preferred default -- * address family -- */ -- if (comp->ice_st->cfg.af != pj_AF_UNSPEC() && -- addr->addr.sa_family == comp->ice_st->cfg.af && -- comp->cand_list[comp->default_cand].base_addr.addr.sa_family != -- ice_st->cfg.af) -- { -- comp->default_cand = (unsigned)(cand - comp->cand_list); -- } -+ cand = &comp->cand_list[comp->cand_cnt]; - -- PJ_LOG(4,(ice_st->obj_name, -- "Comp %d/%d: host candidate %s (tpid=%d) added", -- comp->comp_id, comp->cand_cnt-1, -- pj_sockaddr_print(&cand->addr, addrinfo, -- sizeof(addrinfo), 3), -- cand->transport_id)); -- } -+ cand->type = PJ_ICE_CAND_TYPE_HOST; -+ cand->status = PJ_SUCCESS; -+ cand->local_pref = (pj_uint16_t)(HOST_PREF - *cand_cnt); -+ cand->transport_id = CREATE_TP_ID(TP_STUN, idx); -+ cand->comp_id = (pj_uint8_t) comp->comp_id; -+ cand->transport = transport; -+ -+ pj_sockaddr_cp(&cand->addr, addr); -+ pj_sockaddr_cp(&cand->base_addr, addr); -+ pj_bzero(&cand->rel_addr, sizeof(cand->rel_addr)); -+ -+ /* Check if not already in list */ -+ for (j=0; j<comp->cand_cnt; j++) { -+ if (ice_cand_equals(cand, &comp->cand_list[j])) { -+ cand_duplicate = PJ_TRUE; -+ return !PJ_SUCCESS; -+ } - } - -- return status; --} -+ if (cand_duplicate) { -+ PJ_LOG(4, (ice_st->obj_name, -+ "Comp %d: host candidate %s (tpid=%d) is a duplicate", -+ comp->comp_id, -+ pj_sockaddr_print(&cand->addr, -+ addrinfo, sizeof(addrinfo), 3), -+ cand->transport_id)); - -+ pj_bzero(&cand->addr, sizeof(cand->addr)); -+ pj_bzero(&cand->base_addr, sizeof(cand->base_addr)); -+ return PJ_SUCCESS; -+ } else { -+ comp->cand_cnt+=1; -+ (*cand_cnt)++; -+ (*max_cand_cnt)--; -+ } -+ pj_ice_calc_foundation(ice_st->pool, &cand->foundation, -+ cand->type, &cand->base_addr); -+ -+ /* Set default candidate with the preferred default -+ * address family -+ */ -+ if (comp->ice_st->cfg.af != pj_AF_UNSPEC() && -+ addr->addr.sa_family == comp->ice_st->cfg.af && -+ comp->cand_list[comp->default_cand].base_addr.addr.sa_family != -+ ice_st->cfg.af) -+ { -+ comp->default_cand = (unsigned)(cand - comp->cand_list); -+ } -+ -+ if (transport == PJ_CAND_TCP_ACTIVE) { -+ // Use the port 9 (DISCARD Protocol) for TCP active candidates. -+ pj_sockaddr_set_port(&cand->addr, 9); -+ } -+ -+ PJ_LOG(4,(ice_st->obj_name, -+ "Comp %d/%d: host candidate %s (tpid=%d) added", -+ comp->comp_id, comp->cand_cnt-1, -+ pj_sockaddr_print(&cand->addr, addrinfo, -+ sizeof(addrinfo), 3), -+ cand->transport_id)); -+ return PJ_SUCCESS; -+} - - /* - * Create the component. -@@ -827,10 +927,10 @@ static pj_status_t alloc_send_buf(pj_ice_strans *ice_st, unsigned buf_size) - { - if (buf_size > ice_st->buf_size) { - unsigned i; -- -+ - if (ice_st->is_pending) { - /* The current buffer is insufficient, but still currently used.*/ -- return PJ_EBUSY; -+ return PJ_EPENDING; - } - - pj_pool_safe_release(&ice_st->buf_pool); -@@ -850,7 +950,7 @@ static pj_status_t alloc_send_buf(pj_ice_strans *ice_st, unsigned buf_size) - } - ice_st->buf_idx = ice_st->empty_idx = 0; - } -- -+ - return PJ_SUCCESS; - } - -@@ -917,7 +1017,7 @@ PJ_DEF(pj_status_t) pj_ice_strans_create( const char *name, - /* To maintain backward compatibility, check if old/deprecated setting is set - * and the new setting is not, copy the value to the new setting. - */ -- if (cfg->stun_tp_cnt == 0 && -+ if (cfg->stun_tp_cnt == 0 && - (cfg->stun.server.slen || cfg->stun.max_host_cands)) - { - ice_st->cfg.stun_tp_cnt = 1; -@@ -1125,7 +1225,7 @@ static void sess_init_update(pj_ice_strans *ice_st) - pj_ice_get_cand_type_name(cand->type))); - return; - } -- -+ - if (status == PJ_EUNKNOWN) { - status = cand->status; - } else { -@@ -1134,7 +1234,7 @@ static void sess_init_update(pj_ice_strans *ice_st) - status = PJ_SUCCESS; - } - } -- -+ - if (status != PJ_SUCCESS) - break; - } -@@ -1278,6 +1378,11 @@ PJ_DEF(pj_status_t) pj_ice_strans_init_ice(pj_ice_strans *ice_st, - ice_cb.on_ice_complete = &on_ice_complete; - ice_cb.on_rx_data = &ice_rx_data; - ice_cb.on_tx_pkt = &ice_tx_pkt; -+#if PJ_HAS_TCP -+ ice_cb.wait_tcp_connection = &ice_wait_tcp_connection; -+ ice_cb.reconnect_tcp_connection = &ice_reconnect_tcp_connection; -+ ice_cb.close_tcp_connection = &ice_close_tcp_connection; -+#endif - - /* Create! */ - status = pj_ice_sess_create(&ice_st->cfg.stun_cfg, ice_st->obj_name, role, -@@ -1353,7 +1458,8 @@ PJ_DEF(pj_status_t) pj_ice_strans_init_ice(pj_ice_strans *ice_st, - &cand->foundation, &cand->addr, - &cand->base_addr, &cand->rel_addr, - pj_sockaddr_get_len(&cand->addr), -- (unsigned*)&ice_cand_id); -+ (unsigned*)&ice_cand_id, -+ cand->transport); - if (status != PJ_SUCCESS) - goto on_error; - } -@@ -1718,7 +1824,7 @@ pj_ice_strans_get_valid_pair(const pj_ice_strans *ice_st, - PJ_DEF(pj_status_t) pj_ice_strans_stop_ice(pj_ice_strans *ice_st) - { - PJ_ASSERT_RETURN(ice_st, PJ_EINVAL); -- -+ - /* Protect with group lock, since this may cause race condition with - * pj_ice_strans_sendto2(). - * See ticket #1877. -@@ -1752,10 +1858,10 @@ static pj_status_t use_buffer( pj_ice_strans *ice_st, - status = alloc_send_buf(ice_st, data_len); - if (status != PJ_SUCCESS) - return status; -- -+ - if (ice_st->is_pending && ice_st->empty_idx == ice_st->buf_idx) { - /* We don't use buffer or there's no more empty buffer. */ -- return PJ_EBUSY; -+ return PJ_EPENDING; - } - - idx = ice_st->empty_idx; -@@ -1767,12 +1873,12 @@ static pj_status_t use_buffer( pj_ice_strans *ice_st, - pj_sockaddr_cp(&ice_st->send_buf[idx].dst_addr, dst_addr); - ice_st->send_buf[idx].dst_addr_len = dst_addr_len; - *buffer = ice_st->send_buf[idx].buffer; -- -+ - if (ice_st->is_pending) { - /* We'll continue later since there's still a pending send. */ - return PJ_EPENDING; - } -- -+ - ice_st->is_pending = PJ_TRUE; - ice_st->buf_idx = idx; - -@@ -1825,6 +1931,8 @@ static pj_status_t send_data(pj_ice_strans *ice_st, - } - } - -+ def_cand = &comp->cand_list[comp->default_cand]; -+ pj_bool_t add_header = def_cand->transport != PJ_CAND_UDP; - /* If ICE is available, send data with ICE. If ICE nego is not completed - * yet, ICE will try to send using any valid candidate pair. For any - * failure, it will fallback to sending with the default candidate -@@ -1843,8 +1951,29 @@ static pj_status_t send_data(pj_ice_strans *ice_st, - - pj_grp_lock_release(ice_st->grp_lock); - -- def_cand = &comp->cand_list[comp->default_cand]; -- -+ /* TCP, add header */ -+ if (add_header) { -+ /* -+ * RFC6544 ICE requires an agent to demultiplex STUN and -+ * application-layer traffic, since they appear on the same port. This -+ * demultiplexing is described in [RFC5245] and is done using the magic -+ * cookie and other fields of the message. Stream-oriented transports -+ * introduce another wrinkle, since they require a way to frame the -+ * connection so that the application and STUN packets can be extracted -+ * in order to differentiate STUN packets from application-layer -+ * traffic. For this reason, TCP media streams utilizing ICE use the -+ * basic framing provided in RFC 4571 [RFC4571], even if the application -+ * layer protocol is not RTP. -+ */ -+ pj_uint8_t header_1 = data_len % 256; -+ pj_uint8_t header_0 = data_len >> 8; -+ pj_memcpy(&ice_st->rtp_pkt, &(header_0), sizeof(pj_uint8_t)); -+ pj_memcpy(&ice_st->rtp_pkt[1], &(header_1), sizeof(pj_uint8_t)); -+ pj_memcpy(&ice_st->rtp_pkt[2], (unsigned char *)data, data_len); -+ buf = &ice_st->rtp_pkt; -+ data_len += 2; -+ } -+ - if (def_cand->status == PJ_SUCCESS) { - unsigned tp_idx = GET_TP_IDX(def_cand->transport_id); - -@@ -1906,6 +2035,11 @@ static pj_status_t send_data(pj_ice_strans *ice_st, - status = pj_stun_sock_sendto(comp->stun[tp_idx].sock, NULL, buf, - (unsigned)data_len, 0, dest_addr, - dest_addr_len); -+ /* Do not count the header */ -+ if (add_header) { -+ data_len -= sizeof(pj_uint16_t); -+ } -+ - goto on_return; - } - -@@ -1914,8 +2048,14 @@ static pj_status_t send_data(pj_ice_strans *ice_st, - - on_return: - /* We continue later in on_data_sent() callback. */ -- if (status == PJ_EPENDING) -+ if (status == PJ_EPENDING) { -+ ice_st->last_data_len = data_len; -+ if (add_header) { -+ // Don't forget the header -+ ice_st->last_data_len += sizeof(pj_uint16_t); -+ } - return status; -+ } - - if (call_cb) { - on_data_sent(ice_st, (status == PJ_SUCCESS? data_len: -status)); -@@ -1947,7 +2087,7 @@ PJ_DEF(pj_status_t) pj_ice_strans_sendto( pj_ice_strans *ice_st, - dst_addr_len, PJ_TRUE, PJ_FALSE); - if (status == PJ_EPENDING) - status = PJ_SUCCESS; -- -+ - return status; - } - #endif -@@ -2098,7 +2238,22 @@ static void on_ice_complete(pj_ice_sess *ice, pj_status_t status) - sizeof(lip), 3); - pj_sockaddr_print(&check->rcand->addr, rip, - sizeof(rip), 3); -- -+#if PJ_HAS_TCP -+ int idx = -1; -+ for (int i=0; i<ice_st->cfg.stun_tp_cnt; ++i) { -+ if (ice_st->cfg.stun_tp[i].af == -+ check->rcand->addr.addr.sa_family) -+ { -+ idx = i; -+ break; -+ } -+ } -+ if (idx == -1) { -+ PJ_LOG(4, (ice_st->obj_name, -+ "Comp %d: No STUN sock found.", -+ comp->comp_id)); -+ } -+#endif - if (tp_typ == TP_TURN) { - /* Activate channel binding for the remote address - * for more efficient data transfer using TURN. -@@ -2192,6 +2347,29 @@ static pj_status_t ice_tx_pkt(pj_ice_sess *ice, - pj_sockaddr_get_port(dst_addr), - tp_typ)); - -+ /* TCP, add header */ -+ if (comp->ice_st->cfg.stun_tp->conn_type == PJ_STUN_TP_TCP) { -+ /* -+ * RFC6544 ICE requires an agent to demultiplex STUN and -+ * application-layer traffic, since they appear on the same port. This -+ * demultiplexing is described in [RFC5245] and is done using the magic -+ * cookie and other fields of the message. Stream-oriented transports -+ * introduce another wrinkle, since they require a way to frame the -+ * connection so that the application and STUN packets can be extracted -+ * in order to differentiate STUN packets from application-layer -+ * traffic. For this reason, TCP media streams utilizing ICE use the -+ * basic framing provided in RFC 4571 [RFC4571], even if the application -+ * layer protocol is not RTP. -+ */ -+ pj_uint8_t header_1 = size % 256; -+ pj_uint8_t header_0 = size >> 8; -+ pj_memcpy(&ice_st->rtp_pkt, &(header_0), sizeof(pj_uint8_t)); -+ pj_memcpy(&ice_st->rtp_pkt[1], &(header_1), sizeof(pj_uint8_t)); -+ pj_memcpy(&ice_st->rtp_pkt[2], (unsigned char *)pkt, size); -+ buf = &ice_st->rtp_pkt; -+ size += 2; -+ } -+ - if (tp_typ == TP_TURN) { - if (comp->turn[tp_idx].sock) { - status = pj_turn_sock_sendto(comp->turn[tp_idx].sock, -@@ -2214,7 +2392,7 @@ static pj_status_t ice_tx_pkt(pj_ice_sess *ice, - if (status != PJ_SUCCESS) { - goto on_return; - } -- -+ - pj_sockaddr_cp(&comp->dst_addr, dst_addr); - comp->synth_addr_len = pj_sockaddr_get_len(&comp->synth_addr); - } -@@ -2225,9 +2403,13 @@ static pj_status_t ice_tx_pkt(pj_ice_sess *ice, - dest_addr_len = dst_addr_len; - } - -- status = pj_stun_sock_sendto(comp->stun[tp_idx].sock, NULL, -- buf, (unsigned)size, 0, -- dest_addr, dest_addr_len); -+ if (comp->stun[tp_idx].sock) { -+ status = pj_stun_sock_sendto(comp->stun[tp_idx].sock, NULL, -+ buf, (unsigned)size, 0, -+ dest_addr, dest_addr_len); -+ } else { -+ status = PJ_EINVALIDOP; -+ } - } else { - pj_assert(!"Invalid transport ID"); - status = PJ_EINVALIDOP; -@@ -2273,7 +2455,7 @@ static void check_pending_send(pj_ice_strans *ice_st) - - if (ice_st->num_buf > 0) - ice_st->buf_idx = (ice_st->buf_idx + 1) % ice_st->num_buf; -- -+ - if (ice_st->num_buf > 0 && ice_st->buf_idx != ice_st->empty_idx) { - /* There's some pending send. Send it one by one. */ - pending_send *ps = &ice_st->send_buf[ice_st->buf_idx]; -@@ -2287,6 +2469,219 @@ static void check_pending_send(pj_ice_strans *ice_st) - } - } - -+static void on_peer_connection(pj_stun_session* sess, -+ pj_status_t status, -+ pj_sockaddr_t* remote_addr) -+{ -+ -+ pj_stun_sock *stun_sock; -+ sock_user_data *data; -+ pj_ice_strans_comp *comp; -+ pj_ice_strans *ice_st; -+ -+ stun_sock = (pj_stun_sock *)pj_stun_session_get_user_data(sess); -+ /* We have disassociated ourselves from the STUN session */ -+ if (!stun_sock) -+ return; -+ -+ data = (sock_user_data *)pj_stun_sock_get_user_data(stun_sock); -+ /* We have disassociated ourselves from the STUN socket */ -+ if (!data) -+ return; -+ -+ comp = data->comp; -+ ice_st = comp->ice_st; -+ -+ /* Incorrect ICE */ -+ if (!ice_st || !ice_st->ice) -+ return; -+ -+ pj_grp_lock_add_ref(ice_st->grp_lock); -+ ice_sess_on_peer_connection(ice_st->ice, -+ data->transport_id, status, remote_addr); -+ pj_grp_lock_dec_ref(ice_st->grp_lock); -+} -+ -+static void on_peer_reset_connection(pj_stun_session* sess, -+ pj_sockaddr_t* remote_addr) -+{ -+ pj_stun_sock *stun_sock; -+ sock_user_data *data; -+ pj_ice_strans_comp *comp; -+ pj_ice_strans *ice_st; -+ -+ stun_sock = (pj_stun_sock *)pj_stun_session_get_user_data(sess); -+ /* We have disassociated ourselves from the STUN session */ -+ if (!stun_sock) -+ return; -+ -+ data = (sock_user_data *)pj_stun_sock_get_user_data(stun_sock); -+ /* We have disassociated ourselves from the STUN socket */ -+ if (!data) -+ return; -+ -+ comp = data->comp; -+ ice_st = comp->ice_st; -+ -+ /* Incorrect ICE */ -+ if (!ice_st || !ice_st->ice) -+ return; -+ -+ pj_grp_lock_add_ref(ice_st->grp_lock); -+ -+ ice_sess_on_peer_reset_connection(ice_st->ice, -+ data->transport_id, remote_addr); -+ pj_grp_lock_dec_ref(ice_st->grp_lock); -+} -+ -+static void on_peer_packet(pj_stun_session* sess, pj_sockaddr_t* remote_addr) -+{ -+ -+ if (!sess || !remote_addr) -+ return; -+ -+ pj_stun_sock *stun_sock; -+ sock_user_data *data; -+ pj_ice_strans_comp *comp; -+ pj_ice_strans *ice_st; -+ -+ stun_sock = (pj_stun_sock *)pj_stun_session_get_user_data(sess); -+ /* We have disassociated ourselves from the STUN session */ -+ if (!stun_sock) -+ return; -+ -+ data = (sock_user_data *)pj_stun_sock_get_user_data(stun_sock); -+ /* We have disassociated ourselves from the STUN socket */ -+ if (!data) -+ return; -+ -+ comp = data->comp; -+ if (!comp) -+ return; -+ -+ ice_st = comp->ice_st; -+ /* Incorrect ICE */ -+ if (!ice_st || !ice_st->ice) -+ return; -+ -+ pj_grp_lock_add_ref(ice_st->grp_lock); -+ ice_sess_on_peer_packet(ice_st->ice, data->transport_id, remote_addr); -+ pj_grp_lock_dec_ref(ice_st->grp_lock); -+} -+ -+#if PJ_HAS_TCP -+static pj_status_t ice_wait_tcp_connection(pj_ice_sess *ice, -+ pj_ice_sess_checklist *clist, -+ unsigned check_id) -+{ -+ pj_ice_sess_check *check = &clist->checks[check_id]; -+ const pj_ice_sess_cand *lcand = check->lcand; -+ const pj_ice_sess_cand *rcand = check->rcand; -+ pj_ice_strans *ice_st = (pj_ice_strans *)ice->user_data; -+ pj_ice_strans_comp *st_comp = ice_st->comp[lcand->comp_id - 1]; -+ -+ int idx = -1; -+ for (int i=0; i<ice_st->cfg.stun_tp_cnt; ++i) -+ if (ice_st->cfg.stun_tp[i].af == rcand->addr.addr.sa_family) { -+ idx = i; -+ break; -+ } -+ -+ if (idx == -1) { -+ PJ_LOG(4, (ice_st->obj_name, "Comp %d: No STUN sock found.", -+ st_comp->comp_id)); -+ return PJ_EINVAL; -+ } -+ if (st_comp->stun[idx].sock) { -+ pj_stun_session *sess = pj_stun_sock_get_session(st_comp->stun[idx].sock); -+ if (!sess) { -+ PJ_LOG(4, (ice_st->obj_name, "Comp %d: No STUN session.", -+ st_comp->comp_id)); -+ return PJ_EINVAL; -+ } -+ pj_stun_session_callback(sess)->on_peer_connection = -+ &on_peer_connection; -+ pj_stun_session_callback(sess)->on_peer_reset_connection = -+ &on_peer_reset_connection; -+ pj_stun_session_callback(sess)->on_peer_packet = &on_peer_packet; -+ -+ return pj_stun_sock_connect_active(st_comp->stun[idx].sock, -+ &rcand->addr, -+ rcand->addr.addr.sa_family); -+ } -+ -+ return PJ_EINVAL; -+} -+ -+static pj_status_t ice_reconnect_tcp_connection(pj_ice_sess *ice, -+ pj_ice_sess_checklist *clist, -+ unsigned check_id) -+{ -+ pj_ice_sess_check *check = &clist->checks[check_id]; -+ const pj_ice_sess_cand *lcand = check->lcand; -+ const pj_ice_sess_cand *rcand = check->rcand; -+ pj_ice_strans *ice_st = (pj_ice_strans *)ice->user_data; -+ pj_ice_strans_comp *st_comp = ice_st->comp[lcand->comp_id - 1]; -+ -+ int idx = -1; -+ for (int i=0; i<ice_st->cfg.stun_tp_cnt; ++i) -+ if (ice_st->cfg.stun_tp[i].af == rcand->addr.addr.sa_family) { -+ idx = i; -+ break; -+ } -+ -+ if (idx == -1) { -+ PJ_LOG(4, (ice_st->obj_name, "Comp %d: No STUN sock found.", -+ st_comp->comp_id)); -+ return PJ_EINVAL; -+ } -+ -+ if (st_comp->stun[idx].sock) { -+ pj_stun_session *sess = pj_stun_sock_get_session(st_comp->stun[idx].sock); -+ if (!sess) { -+ PJ_LOG(4, (ice_st->obj_name, "Comp %d: No STUN session.", -+ st_comp->comp_id)); -+ return PJ_EINVAL; -+ } -+ pj_stun_session_callback(sess)->on_peer_connection = -+ &on_peer_connection; -+ pj_stun_session_callback(sess)->on_peer_reset_connection = -+ &on_peer_reset_connection; -+ pj_stun_session_callback(sess)->on_peer_packet = &on_peer_packet; -+ return pj_stun_sock_reconnect_active(st_comp->stun[idx].sock, -+ &rcand->addr, -+ rcand->addr.addr.sa_family); -+ } -+ -+ return PJ_EINVAL; -+} -+ -+static pj_status_t ice_close_tcp_connection(pj_ice_sess *ice, -+ pj_ice_sess_checklist *clist, -+ unsigned check_id) -+{ -+ pj_ice_sess_check *check = &clist->checks[check_id]; -+ const pj_ice_sess_cand *lcand = check->lcand; -+ const pj_ice_sess_cand *rcand = check->rcand; -+ pj_ice_strans *ice_st = (pj_ice_strans *)ice->user_data; -+ pj_ice_strans_comp *st_comp = ice_st->comp[lcand->comp_id - 1]; -+ -+ int idx = -1; -+ for (int i=0; i<ice_st->cfg.stun_tp_cnt; ++i) -+ if (ice_st->cfg.stun_tp[i].af == rcand->addr.addr.sa_family) { -+ idx = i; -+ break; -+ } -+ -+ if (idx != -1 && st_comp->stun[idx].sock) { -+ const pj_ice_sess_cand *rcand = check->rcand; -+ return pj_stun_sock_close(st_comp->stun[idx].sock, &rcand->addr); -+ } -+ -+ return PJ_EINVAL; -+} -+#endif -+ - /* Notifification when asynchronous send operation via STUN/TURN - * has completed. - */ -@@ -2295,7 +2690,8 @@ static pj_bool_t on_data_sent(pj_ice_strans *ice_st, pj_ssize_t sent) - if (ice_st->destroy_req || !ice_st->is_pending) - return PJ_TRUE; - -- if (ice_st->call_send_cb && ice_st->cb.on_data_sent) { -+ if (ice_st->call_send_cb && ice_st->cb.on_data_sent -+ && sent == ice_st->last_data_len /* Only app data should be announced */) { - (*ice_st->cb.on_data_sent)(ice_st, sent); - } - -@@ -2453,7 +2849,7 @@ static pj_bool_t stun_on_status(pj_stun_sock *stun_sock, - { - /* We get an IPv4 mapped address for our IPv6 - * host address. -- */ -+ */ - comp->ipv4_mapped = PJ_TRUE; - - /* Find other host candidates with the same (IPv6) -@@ -2465,7 +2861,7 @@ static pj_bool_t stun_on_status(pj_stun_sock *stun_sock, - - if (comp->cand_list[i].type != PJ_ICE_CAND_TYPE_HOST) - continue; -- -+ - a1 = &comp->cand_list[i].addr; - a2 = &cand->base_addr; - if (pj_memcmp(pj_sockaddr_get_addr(a1), -@@ -2482,7 +2878,7 @@ static pj_bool_t stun_on_status(pj_stun_sock *stun_sock, - pj_sockaddr_cp(&cand->base_addr, &info.mapped_addr); - pj_sockaddr_cp(&cand->rel_addr, &info.mapped_addr); - } -- -+ - /* Eliminate the srflx candidate if the address is - * equal to other (host) candidates. - */ -@@ -2529,7 +2925,8 @@ static pj_bool_t stun_on_status(pj_stun_sock *stun_sock, - &cand->base_addr, - &cand->rel_addr, - pj_sockaddr_get_len(&cand->addr), -- NULL); -+ NULL, -+ cand->transport); - } - } - -@@ -2554,7 +2951,7 @@ static pj_bool_t stun_on_status(pj_stun_sock *stun_sock, - if (op == PJ_STUN_SOCK_MAPPED_ADDR_CHANGE && - ice_st->cb.on_ice_complete) - { -- (*ice_st->cb.on_ice_complete)(ice_st, -+ (*ice_st->cb.on_ice_complete)(ice_st, - PJ_ICE_STRANS_OP_ADDR_CHANGE, - status); - } -@@ -2610,6 +3007,10 @@ static pj_bool_t stun_on_status(pj_stun_sock *stun_sock, - } - } - break; -+ case PJ_STUN_SESS_DESTROYED: -+ case PJ_STUN_TCP_CONNECT_ERROR: -+ default: -+ break; - } - - return pj_grp_lock_dec_ref(ice_st->grp_lock)? PJ_FALSE : PJ_TRUE; -@@ -2650,14 +3051,103 @@ static void turn_on_rx_data(pj_turn_sock *turn_sock, - } else { - - /* Hand over the packet to ICE */ -- status = pj_ice_sess_on_rx_pkt(comp->ice_st->ice, comp->comp_id, -- data->transport_id, pkt, pkt_len, -- peer_addr, addr_len); -+ if (comp->ice_st->cfg.turn_tp->conn_type == PJ_TURN_TP_TCP && pkt_len > 0) { -+ unsigned parsed = 0; -+ pj_status_t status; - -- if (status != PJ_SUCCESS) { -- ice_st_perror(comp->ice_st, -- "Error processing packet from TURN relay", -- status); -+ do { -+ pj_uint16_t leftover = pkt_len - parsed; -+ pj_uint8_t *current_packet = ((pj_uint8_t *)(pkt)) + parsed; -+ -+ /** -+ * RFC6544, the packet is wrapped into a packet following the -+ * RFC4571 -+ */ -+ pj_bool_t store_remaining = PJ_TRUE; -+ if (comp->ice_st->rx_buffer_size || -+ comp->ice_st->rx_wanted_size) -+ { -+ /* a single packet left to process */ -+ if (comp->ice_st->rx_buffer_size == 1 && comp->ice_st->rx_wanted_size == 0) { -+ /* get last frame's lenght from its header */ -+ leftover = GETVAL16H(comp->ice_st->rx_buffer, -+ current_packet); -+ /* adjust counters accordingly */ -+ comp->ice_st->rx_buffer_size = 0; -+ current_packet++; -+ parsed++; -+ -+ if (leftover + parsed <= pkt_len) { -+ /* we didn't get what we were promissed in the -+ * header. furthermore, this was the last frame and -+ * therefore we're done. -+ */ -+ store_remaining = PJ_FALSE; -+ parsed += leftover; -+ } else { -+ comp->ice_st->rx_wanted_size = leftover; -+ } -+ } else if (leftover + comp->ice_st->rx_buffer_size >= -+ comp->ice_st->rx_wanted_size) -+ { -+ /* We have enough leftover bytes in buffer to build a new -+ * packet and parse it -+ */ -+ store_remaining = PJ_FALSE; -+ -+ pj_uint16_t eaten_bytes = comp->ice_st->rx_wanted_size - -+ comp->ice_st->rx_buffer_size; -+ pj_memcpy(comp->ice_st->rx_buffer + -+ comp->ice_st->rx_buffer_size, -+ current_packet, eaten_bytes); -+ -+ leftover = comp->ice_st->rx_wanted_size; -+ current_packet = comp->ice_st->rx_buffer; -+ parsed += eaten_bytes; -+ -+ comp->ice_st->rx_buffer_size = 0; -+ comp->ice_st->rx_wanted_size = 0; -+ } -+ } else if (leftover > 1) { -+ leftover = GETVAL16H(current_packet, current_packet+1); -+ current_packet += 2; -+ parsed += 2; -+ if (leftover + parsed <= pkt_len) { -+ store_remaining = PJ_FALSE; -+ parsed += leftover; -+ } else { -+ comp->ice_st->rx_wanted_size = leftover; -+ } -+ } -+ -+ if (store_remaining) { -+ leftover = pkt_len - parsed; -+ pj_memcpy(comp->ice_st->rx_buffer + -+ comp->ice_st->rx_buffer_size, -+ current_packet, leftover); -+ comp->ice_st->rx_buffer_size += leftover; -+ status = PJ_SUCCESS; -+ break; -+ } -+ -+ status = pj_ice_sess_on_rx_pkt(comp->ice_st->ice, comp->comp_id, -+ data->transport_id, -+ current_packet, leftover, -+ peer_addr, addr_len); -+ if (status != PJ_SUCCESS) { -+ ice_st_perror(comp->ice_st, -+ "Error processing packet from TURN relay", -+ status); -+ } -+ } while (parsed < pkt_len); -+ } else { -+ status = pj_ice_sess_on_rx_pkt(comp->ice_st->ice, comp->comp_id, -+ data->transport_id, pkt, pkt_len, -+ peer_addr, addr_len); -+ if (status != PJ_SUCCESS) -+ ice_st_perror(comp->ice_st, -+ "Error processing packet from TURN relay", -+ status); - } - } - -@@ -2797,7 +3287,8 @@ static void turn_on_state(pj_turn_sock *turn_sock, pj_turn_state_t old_state, - &cand->base_addr, - &cand->rel_addr, - pj_sockaddr_get_len(&cand->addr), -- NULL); -+ NULL, -+ cand->transport); - if (status != PJ_SUCCESS) { - PJ_PERROR(4,(comp->ice_st->obj_name, status, - "Comp %d/%d: failed to add TURN (tpid=%d) to ICE", -diff --git a/pjnath/src/pjnath/nat_detect.c b/pjnath/src/pjnath/nat_detect.c -index db0de10bc..808342bec 100644 ---- a/pjnath/src/pjnath/nat_detect.c -+++ b/pjnath/src/pjnath/nat_detect.c -@@ -329,7 +329,8 @@ PJ_DEF(pj_status_t) pj_stun_detect_nat_type2(const pj_sockaddr *server, - sess_cb.on_request_complete = &on_request_complete; - sess_cb.on_send_msg = &on_send_msg; - status = pj_stun_session_create(stun_cfg, pool->obj_name, &sess_cb, -- PJ_FALSE, sess->grp_lock, &sess->stun_sess); -+ PJ_FALSE, sess->grp_lock, &sess->stun_sess, -+ PJ_STUN_TP_UDP); - if (status != PJ_SUCCESS) - goto on_error; - -@@ -875,7 +876,9 @@ static pj_status_t send_test(nat_detect_session *sess, - - /* Send the request */ - status = pj_stun_session_send_msg(sess->stun_sess, NULL, PJ_TRUE, -- PJ_TRUE, sess->cur_server, -+ (pj_stun_session_tp_type(sess->stun_sess) == -+ PJ_STUN_TP_UDP), -+ sess->cur_server, - pj_sockaddr_get_len(sess->cur_server), - sess->result[test_id].tdata); - if (status != PJ_SUCCESS) -diff --git a/pjnath/src/pjnath/stun_session.c b/pjnath/src/pjnath/stun_session.c -index f2b4f7058..20a9b1320 100644 ---- a/pjnath/src/pjnath/stun_session.c -+++ b/pjnath/src/pjnath/stun_session.c -@@ -49,6 +49,8 @@ struct pj_stun_session - - pj_stun_tx_data pending_request_list; - pj_stun_tx_data cached_response_list; -+ -+ pj_stun_tp_type conn_type; - }; - - #define SNAME(s_) ((s_)->pool->obj_name) -@@ -524,7 +526,8 @@ PJ_DEF(pj_status_t) pj_stun_session_create( pj_stun_config *cfg, - const pj_stun_session_cb *cb, - pj_bool_t fingerprint, - pj_grp_lock_t *grp_lock, -- pj_stun_session **p_sess) -+ pj_stun_session **p_sess, -+ pj_stun_tp_type conn_type) - { - pj_pool_t *pool; - pj_stun_session *sess; -@@ -545,6 +548,7 @@ PJ_DEF(pj_status_t) pj_stun_session_create( pj_stun_config *cfg, - pj_memcpy(&sess->cb, cb, sizeof(*cb)); - sess->use_fingerprint = fingerprint; - sess->log_flag = 0xFFFF; -+ sess->conn_type = conn_type; - - if (grp_lock) { - sess->grp_lock = grp_lock; -@@ -1010,7 +1014,7 @@ PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess, - (unsigned)tdata->pkt_size); - if (status != PJ_SUCCESS && status != PJ_EPENDING) { - pj_stun_msg_destroy_tdata(sess, tdata); -- LOG_ERR_(sess, "Error sending STUN request", status); -+ LOG_ERR_(sess, "Error sending STUN request (pj_stun_client_tsx_send_msg)", status); - goto on_return; - } - -@@ -1067,7 +1071,7 @@ PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess, - - if (status != PJ_SUCCESS && status != PJ_EPENDING) { - pj_stun_msg_destroy_tdata(sess, tdata); -- LOG_ERR_(sess, "Error sending STUN request", status); -+ LOG_ERR_(sess, "Error sending STUN request (pj_stun_session_send_msg)", status); - goto on_return; - } - -@@ -1538,3 +1542,12 @@ on_return: - return status; - } - -+PJ_DECL(pj_stun_session_cb *) pj_stun_session_callback(pj_stun_session *sess) -+{ -+ return sess ? &sess->cb : NULL; -+} -+ -+PJ_DECL(pj_stun_tp_type) pj_stun_session_tp_type(pj_stun_session *sess) -+{ -+ return sess ? sess->conn_type : PJ_STUN_TP_UDP; -+} -diff --git a/pjnath/src/pjnath/stun_sock.c b/pjnath/src/pjnath/stun_sock.c -index 5fe825cf5..6d2602552 100644 ---- a/pjnath/src/pjnath/stun_sock.c -+++ b/pjnath/src/pjnath/stun_sock.c -@@ -40,6 +40,36 @@ - - enum { MAX_BIND_RETRY = 100 }; - -+#if PJ_HAS_TCP -+// The head of a RTP packet is stored in a 16 bits header, so the max size of a -+// packet is 65536 -+#define MAX_RTP_SIZE 65536 -+#endif -+ -+// TODO (sblin) The incoming socks are a bit HACKY for now. -+// Need a better approach -+typedef struct outgoing_sock { -+ pj_sock_t fd; -+ pj_activesock_t *sock; -+ pj_sockaddr_t *addr; -+} outgoing_sock; -+ -+typedef struct incoming_sock { -+ pj_sock_t fd; -+ pj_activesock_t *sock; -+ pj_sockaddr addr; -+ int addr_len; -+} incoming_sock; -+ -+typedef struct rx_buf { -+ pj_activesock_t *asock; -+ pj_uint8_t rx_buffer[MAX_RTP_SIZE]; -+ pj_uint16_t rx_buffer_size; -+ pj_uint16_t rx_wanted_size; -+ struct rx_buf *next; -+ struct rx_buf *prev; -+} rx_buf; -+ - struct pj_stun_sock - { - char *obj_name; /* Log identification */ -@@ -47,6 +77,8 @@ struct pj_stun_sock - void *user_data; /* Application user data */ - pj_bool_t is_destroying; /* Destroy already called */ - int af; /* Address family */ -+ pj_stun_tp_type conn_type; -+ pj_stun_sock_cfg cfg; - pj_stun_config stun_cfg; /* STUN config (ioqueue etc)*/ - pj_stun_sock_cb cb; /* Application callbacks */ - -@@ -59,6 +91,13 @@ struct pj_stun_sock - pj_dns_srv_async_query *q; /* Pending DNS query */ - pj_sock_t sock_fd; /* Socket descriptor */ - pj_activesock_t *active_sock; /* Active socket object */ -+#if PJ_HAS_TCP -+ int outgoing_nb; -+ outgoing_sock outgoing_socks[PJ_ICE_MAX_CHECKS]; -+ int incoming_nb; -+ incoming_sock incoming_socks[PJ_ICE_MAX_CHECKS]; -+ rx_buf *rx_buffers; -+#endif - pj_ioqueue_op_key_t send_key; /* Default send key for app */ - pj_ioqueue_op_key_t int_send_key; /* Send key for internal */ - pj_status_t last_err; /* Last error status */ -@@ -68,6 +107,15 @@ struct pj_stun_sock - pj_grp_lock_t *grp_lock; /* Session group lock */ - }; - -+////////////////////////////////////////////////////////////////////////////// -+ -+static pj_uint16_t GETVAL16H(const pj_uint8_t *buf1, const pj_uint8_t *buf2) -+{ -+ return (pj_uint16_t) ((buf1[0] << 8) | (buf2[0] << 0)); -+} -+ -+////////////////////////////////////////////////////////////////////////////// -+ - /* - * Prototypes for static functions - */ -@@ -120,6 +168,24 @@ static void start_ka_timer(pj_stun_sock *stun_sock); - /* Keep-alive timer callback */ - static void ka_timer_cb(pj_timer_heap_t *th, pj_timer_entry *te); - -+ -+static pj_bool_t on_stun_sock_ready(pj_activesock_t *asock, -+ pj_status_t status); -+ -+static pj_bool_t on_stun_sock_accept(pj_activesock_t *asock, -+ pj_sock_t newsock, -+ const pj_sockaddr_t *src_addr, -+ int src_addr_len); -+ -+static pj_bool_t on_connect_complete(pj_activesock_t *asock, -+ pj_status_t status); -+ -+/* Notify application that session has failed */ -+static pj_bool_t sess_fail(pj_stun_sock *stun_sock, -+ pj_stun_sock_op op, -+ pj_status_t status); -+ -+ - #define INTERNAL_MSG_TOKEN (void*)(pj_ssize_t)1 - - -@@ -160,12 +226,183 @@ static pj_bool_t pj_stun_sock_cfg_is_valid(const pj_stun_sock_cfg *cfg) - return cfg->max_pkt_size > 1 && cfg->async_cnt >= 1; - } - -+/* -+ * Initialize. -+ */ -+PJ_DEF(pj_status_t) pj_stun_sock_alloc(pj_stun_sock *stun_sock) -+{ -+ pj_status_t status; -+ pj_sockaddr bound_addr; -+ pj_uint16_t max_bind_retry; -+ int sock_type; -+ -+ pj_grp_lock_acquire(stun_sock->grp_lock); -+ -+ if (stun_sock->conn_type == PJ_STUN_TP_UDP) -+ sock_type = pj_SOCK_DGRAM(); -+ else -+ sock_type = pj_SOCK_STREAM(); -+ -+ stun_sock->ka_interval = stun_sock->cfg.ka_interval; -+ if (stun_sock->ka_interval == 0) -+ stun_sock->ka_interval = PJ_STUN_KEEP_ALIVE_SEC; -+ /* Create socket and bind socket */ -+ status = pj_sock_socket(stun_sock->af, sock_type, 0, &stun_sock->sock_fd); -+ if (status != PJ_SUCCESS) { -+ pj_stun_sock_destroy(stun_sock); -+ pj_grp_lock_release(stun_sock->grp_lock); -+ return status; -+ } -+ -+ /* Apply QoS, if specified */ -+ status = pj_sock_apply_qos2(stun_sock->sock_fd, stun_sock->cfg.qos_type, -+ &stun_sock->cfg.qos_params, 2, -+ stun_sock->obj_name, NULL); -+ if (status != PJ_SUCCESS && !stun_sock->cfg.qos_ignore_error) { -+ pj_stun_sock_destroy(stun_sock); -+ pj_grp_lock_release(stun_sock->grp_lock); -+ return status; -+ } -+ -+ /* Apply socket buffer size */ -+ if (stun_sock->cfg.so_rcvbuf_size > 0) { -+ unsigned sobuf_size = stun_sock->cfg.so_rcvbuf_size; -+ status = pj_sock_setsockopt_sobuf(stun_sock->sock_fd, pj_SO_RCVBUF(), -+ PJ_TRUE, &sobuf_size); -+ if (status != PJ_SUCCESS) { -+ pj_perror(3, stun_sock->obj_name, status, -+ "Failed setting SO_RCVBUF"); -+ } else { -+ if (sobuf_size < stun_sock->cfg.so_rcvbuf_size) { -+ PJ_LOG(4, (stun_sock->obj_name, -+ "Warning! Cannot set SO_RCVBUF as configured, " -+ "now=%d, configured=%d", -+ sobuf_size, stun_sock->cfg.so_rcvbuf_size)); -+ } else { -+ PJ_LOG(5, (stun_sock->obj_name, -+ "SO_RCVBUF set to %d", sobuf_size)); -+ } -+ } -+ } -+ if (stun_sock->cfg.so_sndbuf_size > 0) { -+ unsigned sobuf_size = stun_sock->cfg.so_sndbuf_size; -+ status = pj_sock_setsockopt_sobuf(stun_sock->sock_fd, pj_SO_SNDBUF(), -+ PJ_TRUE, &sobuf_size); -+ if (status != PJ_SUCCESS) { -+ pj_perror(3, stun_sock->obj_name, status, -+ "Failed setting SO_SNDBUF"); -+ } else { -+ if (sobuf_size < stun_sock->cfg.so_sndbuf_size) { -+ PJ_LOG(4, (stun_sock->obj_name, -+ "Warning! Cannot set SO_SNDBUF as configured, " -+ "now=%d, configured=%d", -+ sobuf_size, stun_sock->cfg.so_sndbuf_size)); -+ } else { -+ PJ_LOG(5, (stun_sock->obj_name, -+ "SO_SNDBUF set to %d", sobuf_size)); -+ } -+ } -+ } -+ -+ /* Bind socket */ -+ max_bind_retry = MAX_BIND_RETRY; -+ if (stun_sock->cfg.port_range && -+ stun_sock->cfg.port_range < max_bind_retry) -+ max_bind_retry = stun_sock->cfg.port_range; -+ -+ pj_sockaddr_init(stun_sock->af, &bound_addr, NULL, 0); -+ if (stun_sock->cfg.bound_addr.addr.sa_family == pj_AF_INET() || -+ stun_sock->cfg.bound_addr.addr.sa_family == pj_AF_INET6()) -+ { -+ pj_sockaddr_cp(&bound_addr, &stun_sock->cfg.bound_addr); -+ } -+ -+ status = pj_sock_bind_random(stun_sock->sock_fd, &bound_addr, -+ stun_sock->cfg.port_range, max_bind_retry); -+ if (status != PJ_SUCCESS) { -+ pj_stun_sock_destroy(stun_sock); -+ pj_grp_lock_release(stun_sock->grp_lock); -+ return status; -+ } -+ -+ /* Init active socket configuration */ -+ { -+ pj_activesock_cfg activesock_cfg; -+ pj_activesock_cb activesock_cb; -+ -+ pj_activesock_cfg_default(&activesock_cfg); -+ activesock_cfg.grp_lock = stun_sock->grp_lock; -+ activesock_cfg.async_cnt = stun_sock->cfg.async_cnt; -+ activesock_cfg.concurrency = 0; -+ -+ /* Create the active socket */ -+ pj_bzero(&activesock_cb, sizeof(activesock_cb)); -+ activesock_cb.on_data_sent = &on_data_sent; -+ activesock_cb.on_data_recvfrom = &on_data_recvfrom; -+ -+#if PJ_HAS_TCP -+ if (stun_sock->conn_type != PJ_STUN_TP_UDP) { -+ activesock_cb.on_accept_complete = &on_stun_sock_accept; -+ // Will be ready to accept incoming connections from the external world -+ status = pj_sock_listen(stun_sock->sock_fd, PJ_SOMAXCONN); -+ if (status != PJ_SUCCESS) { -+ pj_stun_sock_destroy(stun_sock); -+ pj_grp_lock_release(stun_sock->grp_lock); -+ return status; -+ } -+ } else { -+ activesock_cb.on_connect_complete = &on_stun_sock_ready; -+ } -+#else -+ activesock_cb.on_connect_complete = &on_stun_sock_ready; -+#endif -+ -+ status = pj_activesock_create(stun_sock->pool, stun_sock->sock_fd, -+ sock_type, &activesock_cfg, -+ stun_sock->stun_cfg.ioqueue, -+ &activesock_cb, stun_sock, -+ &stun_sock->active_sock); -+ if (status != PJ_SUCCESS) { -+ pj_stun_sock_destroy(stun_sock); -+ pj_grp_lock_release(stun_sock->grp_lock); -+ return status; -+ } -+ -+#if PJ_HAS_TCP -+ if (stun_sock->conn_type != PJ_STUN_TP_UDP) { -+ status = pj_activesock_start_accept(stun_sock->active_sock, -+ stun_sock->pool); -+ } else { -+ status = PJ_SUCCESS; -+ } -+ if (status == PJ_SUCCESS) { -+ on_stun_sock_ready(stun_sock->active_sock, PJ_SUCCESS); -+ } else if (status != PJ_EPENDING) { -+ char addrinfo[PJ_INET6_ADDRSTRLEN + 10]; -+ pj_perror(3, stun_sock->pool->obj_name, status, -+ "Failed to connect to %s", -+ pj_sockaddr_print(&bound_addr, addrinfo, -+ sizeof(addrinfo), 3)); -+ pj_stun_sock_destroy(stun_sock); -+ pj_grp_lock_release(stun_sock->grp_lock); -+ return status; -+ } -+#else -+ on_stun_sock_ready(stun_sock->active_sock, PJ_SUCCESS); -+#endif -+ } -+ -+ pj_grp_lock_release(stun_sock->grp_lock); -+ return status; -+} -+ - /* - * Create the STUN transport using the specified configuration. - */ - PJ_DEF(pj_status_t) pj_stun_sock_create( pj_stun_config *stun_cfg, - const char *name, - int af, -+ pj_stun_tp_type conn_type, - const pj_stun_sock_cb *cb, - const pj_stun_sock_cfg *cfg, - void *user_data, -@@ -174,22 +411,32 @@ PJ_DEF(pj_status_t) pj_stun_sock_create( pj_stun_config *stun_cfg, - pj_pool_t *pool; - pj_stun_sock *stun_sock; - pj_stun_sock_cfg default_cfg; -- pj_sockaddr bound_addr; -- unsigned i; -- pj_uint16_t max_bind_retry; - pj_status_t status; - - PJ_ASSERT_RETURN(stun_cfg && cb && p_stun_sock, PJ_EINVAL); - PJ_ASSERT_RETURN(af==pj_AF_INET()||af==pj_AF_INET6(), PJ_EAFNOTSUP); - PJ_ASSERT_RETURN(!cfg || pj_stun_sock_cfg_is_valid(cfg), PJ_EINVAL); - PJ_ASSERT_RETURN(cb->on_status, PJ_EINVAL); -+ PJ_ASSERT_RETURN(conn_type != PJ_STUN_TP_TCP || PJ_HAS_TCP, PJ_EINVAL); - - status = pj_stun_config_check_valid(stun_cfg); - if (status != PJ_SUCCESS) - return status; - -- if (name == NULL) -- name = "stuntp%p"; -+ if (name == NULL) { -+ switch (conn_type) { -+ case PJ_STUN_TP_UDP: -+ name = "udpstun%p"; -+ break; -+ case PJ_STUN_TP_TCP: -+ name = "tcpstun%p"; -+ break; -+ default: -+ PJ_ASSERT_RETURN(!"Invalid STUN conn_type", PJ_EINVAL); -+ name = "tcpstun%p"; -+ break; -+ } -+ } - - if (cfg == NULL) { - pj_stun_sock_cfg_default(&default_cfg); -@@ -204,9 +451,16 @@ PJ_DEF(pj_status_t) pj_stun_sock_create( pj_stun_config *stun_cfg, - stun_sock->obj_name = pool->obj_name; - stun_sock->user_data = user_data; - stun_sock->af = af; -+ stun_sock->conn_type = conn_type; - stun_sock->sock_fd = PJ_INVALID_SOCKET; -+#if PJ_HAS_TCP -+ stun_sock->outgoing_nb = -1; -+ stun_sock->incoming_nb = -1; -+#endif - pj_memcpy(&stun_sock->stun_cfg, stun_cfg, sizeof(*stun_cfg)); - pj_memcpy(&stun_sock->cb, cb, sizeof(*cb)); -+ /* Copy socket settings; QoS parameters etc */ -+ pj_memcpy(&stun_sock->cfg, cfg, sizeof(*cfg)); - - stun_sock->ka_interval = cfg->ka_interval; - if (stun_sock->ka_interval == 0) -@@ -226,140 +480,68 @@ PJ_DEF(pj_status_t) pj_stun_sock_create( pj_stun_config *stun_cfg, - pj_grp_lock_add_handler(stun_sock->grp_lock, pool, stun_sock, - &stun_sock_destructor); - -- /* Create socket and bind socket */ -- status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &stun_sock->sock_fd); -- if (status != PJ_SUCCESS) -- goto on_error; -- -- /* Apply QoS, if specified */ -- status = pj_sock_apply_qos2(stun_sock->sock_fd, cfg->qos_type, -- &cfg->qos_params, 2, stun_sock->obj_name, -- NULL); -- if (status != PJ_SUCCESS && !cfg->qos_ignore_error) -- goto on_error; -+ /* Create STUN session */ -+ { -+ pj_stun_session_cb sess_cb; - -- /* Apply socket buffer size */ -- if (cfg->so_rcvbuf_size > 0) { -- unsigned sobuf_size = cfg->so_rcvbuf_size; -- status = pj_sock_setsockopt_sobuf(stun_sock->sock_fd, pj_SO_RCVBUF(), -- PJ_TRUE, &sobuf_size); -- if (status != PJ_SUCCESS) { -- PJ_PERROR(3, (stun_sock->obj_name, status, -- "Failed setting SO_RCVBUF")); -- } else { -- if (sobuf_size < cfg->so_rcvbuf_size) { -- PJ_LOG(4, (stun_sock->obj_name, -- "Warning! Cannot set SO_RCVBUF as configured, " -- "now=%d, configured=%d", -- sobuf_size, cfg->so_rcvbuf_size)); -- } else { -- PJ_LOG(5, (stun_sock->obj_name, "SO_RCVBUF set to %d", -- sobuf_size)); -- } -- } -- } -- if (cfg->so_sndbuf_size > 0) { -- unsigned sobuf_size = cfg->so_sndbuf_size; -- status = pj_sock_setsockopt_sobuf(stun_sock->sock_fd, pj_SO_SNDBUF(), -- PJ_TRUE, &sobuf_size); -+ pj_bzero(&sess_cb, sizeof(sess_cb)); -+ sess_cb.on_request_complete = &sess_on_request_complete; -+ sess_cb.on_send_msg = &sess_on_send_msg; -+ status = pj_stun_session_create(&stun_sock->stun_cfg, -+ stun_sock->obj_name, -+ &sess_cb, PJ_FALSE, -+ stun_sock->grp_lock, -+ &stun_sock->stun_sess, -+ conn_type); - if (status != PJ_SUCCESS) { -- PJ_PERROR(3, (stun_sock->obj_name, status, -- "Failed setting SO_SNDBUF")); -- } else { -- if (sobuf_size < cfg->so_sndbuf_size) { -- PJ_LOG(4, (stun_sock->obj_name, -- "Warning! Cannot set SO_SNDBUF as configured, " -- "now=%d, configured=%d", -- sobuf_size, cfg->so_sndbuf_size)); -- } else { -- PJ_LOG(5, (stun_sock->obj_name, "SO_SNDBUF set to %d", -- sobuf_size)); -- } -+ pj_stun_sock_destroy(stun_sock); -+ return status; - } - } - -- /* Bind socket */ -- max_bind_retry = MAX_BIND_RETRY; -- if (cfg->port_range && cfg->port_range < max_bind_retry) -- max_bind_retry = cfg->port_range; -- pj_sockaddr_init(af, &bound_addr, NULL, 0); -- if (cfg->bound_addr.addr.sa_family == pj_AF_INET() || -- cfg->bound_addr.addr.sa_family == pj_AF_INET6()) -- { -- pj_sockaddr_cp(&bound_addr, &cfg->bound_addr); -- } -- status = pj_sock_bind_random(stun_sock->sock_fd, &bound_addr, -- cfg->port_range, max_bind_retry); -- if (status != PJ_SUCCESS) -- goto on_error; -+ pj_stun_sock_alloc(stun_sock); - -- /* Create more useful information string about this transport */ --#if 0 -- { -- pj_sockaddr bound_addr; -- int addr_len = sizeof(bound_addr); -+ /* Done */ -+ *p_stun_sock = stun_sock; -+ return PJ_SUCCESS; -+} -+ -+/* -+ * Notification when outgoing TCP socket has been connected. -+ */ -+static pj_bool_t on_stun_sock_ready(pj_activesock_t *asock, pj_status_t status) -+{ -+ pj_stun_sock *stun_sock; -+ stun_sock = (pj_stun_sock *)pj_activesock_get_user_data(asock); -+ if (!stun_sock) -+ return PJ_FALSE; - -- status = pj_sock_getsockname(stun_sock->sock_fd, &bound_addr, -- &addr_len); -- if (status != PJ_SUCCESS) -- goto on_error; -+ pj_grp_lock_acquire(stun_sock->grp_lock); - -- stun_sock->info = pj_pool_alloc(pool, PJ_INET6_ADDRSTRLEN+10); -- pj_sockaddr_print(&bound_addr, stun_sock->info, -- PJ_INET6_ADDRSTRLEN, 3); -+ /* TURN session may have already been destroyed here. -+ * See ticket #1557 (http://trac.pjsip.org/repos/ticket/1557). -+ */ -+ if (!stun_sock->stun_sess) { -+ sess_fail(stun_sock, PJ_STUN_SESS_DESTROYED, status); -+ pj_grp_lock_release(stun_sock->grp_lock); -+ return PJ_FALSE; - } --#endif - -- /* Init active socket configuration */ -- { -- pj_activesock_cfg activesock_cfg; -- pj_activesock_cb activesock_cb; -- -- pj_activesock_cfg_default(&activesock_cfg); -- activesock_cfg.grp_lock = stun_sock->grp_lock; -- activesock_cfg.async_cnt = cfg->async_cnt; -- activesock_cfg.concurrency = 0; -- -- /* Create the active socket */ -- pj_bzero(&activesock_cb, sizeof(activesock_cb)); -- activesock_cb.on_data_recvfrom = &on_data_recvfrom; -- activesock_cb.on_data_sent = &on_data_sent; -- status = pj_activesock_create(pool, stun_sock->sock_fd, -- pj_SOCK_DGRAM(), -- &activesock_cfg, stun_cfg->ioqueue, -- &activesock_cb, stun_sock, -- &stun_sock->active_sock); -- if (status != PJ_SUCCESS) -- goto on_error; -- -- /* Start asynchronous read operations */ -- status = pj_activesock_start_recvfrom(stun_sock->active_sock, pool, -- cfg->max_pkt_size, 0); -- if (status != PJ_SUCCESS) -- goto on_error; -- -- /* Init send keys */ -- pj_ioqueue_op_key_init(&stun_sock->send_key, -- sizeof(stun_sock->send_key)); -- pj_ioqueue_op_key_init(&stun_sock->int_send_key, -- sizeof(stun_sock->int_send_key)); -+ if (status != PJ_SUCCESS) { -+ sess_fail(stun_sock, PJ_STUN_TCP_CONNECT_ERROR, status); -+ pj_grp_lock_release(stun_sock->grp_lock); -+ return PJ_FALSE; - } - -- /* Create STUN session */ -- { -- pj_stun_session_cb sess_cb; -+ if (stun_sock->conn_type != PJ_STUN_TP_UDP) -+ PJ_LOG(5,(stun_sock->obj_name, "TCP connected")); - -- pj_bzero(&sess_cb, sizeof(sess_cb)); -- sess_cb.on_request_complete = &sess_on_request_complete; -- sess_cb.on_send_msg = &sess_on_send_msg; -- status = pj_stun_session_create(&stun_sock->stun_cfg, -- stun_sock->obj_name, -- &sess_cb, PJ_FALSE, -- stun_sock->grp_lock, -- &stun_sock->stun_sess); -- if (status != PJ_SUCCESS) -- goto on_error; -- } -+ /* Start asynchronous read operations */ -+ pj_status_t result; -+ result = pj_activesock_start_recvfrom(asock, stun_sock->pool, -+ stun_sock->cfg.max_pkt_size, 0); -+ if (result != PJ_SUCCESS) -+ return PJ_FALSE; - - /* Associate us with the STUN session */ - pj_stun_session_set_user_data(stun_sock->stun_sess, stun_sock); -@@ -369,25 +551,305 @@ PJ_DEF(pj_status_t) pj_stun_sock_create( pj_stun_config *stun_cfg, - * STUN messages we sent with STUN messages that the application sends. - * The last 16bit value in the array is a counter. - */ -+ unsigned i; - for (i=0; i<PJ_ARRAY_SIZE(stun_sock->tsx_id); ++i) { - stun_sock->tsx_id[i] = (pj_uint16_t) pj_rand(); - } - stun_sock->tsx_id[5] = 0; - -- - /* Init timer entry */ - stun_sock->ka_timer.cb = &ka_timer_cb; - stun_sock->ka_timer.user_data = stun_sock; - -- /* Done */ -- *p_stun_sock = stun_sock; -- return PJ_SUCCESS; -+ if (status != PJ_SUCCESS) { -+ pj_stun_sock_destroy(stun_sock); -+ pj_grp_lock_release(stun_sock->grp_lock); -+ return status; -+ } - --on_error: -- pj_stun_sock_destroy(stun_sock); -- return status; -+ /* Init send keys */ -+ pj_ioqueue_op_key_init(&stun_sock->send_key, sizeof(stun_sock->send_key)); -+ pj_ioqueue_op_key_init(&stun_sock->int_send_key, -+ sizeof(stun_sock->int_send_key)); -+ -+ pj_grp_lock_release(stun_sock->grp_lock); -+ return PJ_TRUE; - } - -+static pj_bool_t parse_rx_packet(pj_activesock_t *asock, -+ void *data, -+ pj_size_t size, -+ const pj_sockaddr_t *rx_addr, -+ unsigned sock_addr_len) -+{ -+ -+ pj_stun_sock *stun_sock = (pj_stun_sock*) pj_activesock_get_user_data(asock); -+ if (!stun_sock) -+ return PJ_FALSE; -+ -+ pj_grp_lock_acquire(stun_sock->grp_lock); -+ pj_uint16_t parsed = 0; -+ pj_status_t result = PJ_TRUE; -+ pj_status_t status; -+ -+#if PJ_HAS_TCP -+ // Search current rx_buf -+ rx_buf* buf = NULL; -+ rx_buf* stun_sock_buf = stun_sock->rx_buffers; -+ while (stun_sock_buf) { -+ if (stun_sock_buf->asock == asock) { -+ buf = stun_sock_buf; -+ break; -+ } -+ stun_sock_buf = stun_sock_buf->next; -+ } -+ if (!buf) { -+ // Create rx_buf, this buf will be released when the pool is released -+ buf = (rx_buf*)pj_pool_calloc(stun_sock->pool, 1, sizeof(rx_buf)); -+ if (!buf) { -+ PJ_LOG(5, (stun_sock->obj_name, "Cannot allocate memory for rx_buf")); -+ status = pj_grp_lock_release(stun_sock->grp_lock); -+ return PJ_FALSE; -+ } -+ buf->asock = asock; -+ buf->next = stun_sock->rx_buffers; -+ if (stun_sock->rx_buffers) -+ stun_sock->rx_buffers->prev = buf; -+ stun_sock->rx_buffers = buf; -+ } -+#endif -+ -+ do { -+ pj_uint16_t leftover = size - parsed; -+ pj_uint8_t *current_packet = ((pj_uint8_t *)(data)) + parsed; -+ -+#if PJ_HAS_TCP -+ if (stun_sock->conn_type != PJ_STUN_TP_UDP) { -+ /* RFC6544, the packet is wrapped into a packet following the RFC4571 */ -+ pj_bool_t store_remaining = PJ_TRUE; -+ if (buf->rx_buffer_size != 0 || buf->rx_wanted_size != 0) { -+ if (buf->rx_buffer_size == 1 && buf->rx_wanted_size == 0) { -+ // In this case, we want to know the header size -+ leftover = GETVAL16H(buf->rx_buffer, current_packet); -+ -+ buf->rx_buffer_size = 0; -+ current_packet++; -+ parsed++; -+ -+ if (leftover + parsed <= size) { -+ store_remaining = PJ_FALSE; -+ parsed += leftover; -+ } else { -+ buf->rx_wanted_size = leftover; -+ } -+ -+ } else if (leftover + buf->rx_buffer_size >= buf->rx_wanted_size) { -+ // We have enough data Build new packet to parse -+ store_remaining = PJ_FALSE; -+ pj_uint16_t eaten_bytes = buf->rx_wanted_size - buf->rx_buffer_size; -+ pj_memcpy(buf->rx_buffer + buf->rx_buffer_size, -+ current_packet, eaten_bytes); -+ -+ leftover = buf->rx_wanted_size; -+ current_packet = buf->rx_buffer; -+ parsed += eaten_bytes; -+ -+ buf->rx_buffer_size = 0; -+ buf->rx_wanted_size = 0; -+ } -+ } else if (leftover > 1) { -+ leftover = GETVAL16H(current_packet, current_packet+1); -+ current_packet += 2; -+ parsed += 2; -+ if (leftover + parsed <= size) { -+ store_remaining = PJ_FALSE; -+ parsed += leftover; -+ } else { -+ buf->rx_wanted_size = leftover; -+ } -+ } -+ if (store_remaining) { -+ leftover = size - parsed; -+ pj_memcpy(buf->rx_buffer + buf->rx_buffer_size, -+ current_packet, leftover); -+ buf->rx_buffer_size += leftover; -+ break; -+ } -+ } else { -+#endif -+ parsed = size; -+#if PJ_HAS_TCP -+ } -+#endif -+ /* Check that this is STUN message */ -+ status = pj_stun_msg_check((const pj_uint8_t *)current_packet, leftover, -+ PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET); -+ if (status != PJ_SUCCESS) { -+ /* Not STUN -- give it to application */ -+ goto process_app_data; -+ } -+ -+ /* Treat packet as STUN header and copy the STUN message type. -+ * We don't want to access the type directly from the header -+ * since it may not be properly aligned. -+ */ -+ pj_stun_msg_hdr *hdr = (pj_stun_msg_hdr *)current_packet; -+ pj_uint16_t type; -+ pj_memcpy(&type, &hdr->type, 2); -+ type = pj_ntohs(type); -+ -+ /* If the packet is a STUN Binding response and part of the -+ * transaction ID matches our internal ID, then this is -+ * our internal STUN message (Binding request or keep alive). -+ * Give it to our STUN session. -+ */ -+ if (!PJ_STUN_IS_RESPONSE(type) || -+ PJ_STUN_GET_METHOD(type) != PJ_STUN_BINDING_METHOD || -+ pj_memcmp(hdr->tsx_id, stun_sock->tsx_id, 10) != 0) -+ { -+ /* Not STUN Binding response, or STUN transaction ID mismatch. -+ * This is not our message too -- give it to application. -+ */ -+ goto process_app_data; -+ } -+ -+ /* This is our STUN Binding response. Give it to the STUN session */ -+ status = pj_stun_session_on_rx_pkt(stun_sock->stun_sess, current_packet, -+ leftover, PJ_STUN_IS_DATAGRAM, NULL, -+ NULL, rx_addr, sock_addr_len); -+ -+ result &= status != PJ_EGONE ? PJ_TRUE : PJ_FALSE; -+ continue; -+ -+process_app_data: -+ if (stun_sock->cb.on_rx_data) -+ (*stun_sock->cb.on_rx_data)(stun_sock, current_packet, -+ (unsigned)leftover, rx_addr, sock_addr_len); -+ -+ result &= status != PJ_EGONE ? PJ_TRUE : PJ_FALSE; -+ } while (parsed < size && result); -+ -+ status = pj_grp_lock_release(stun_sock->grp_lock); -+ return result; -+} -+ -+static pj_bool_t on_data_read(pj_activesock_t *asock, -+ void *data, -+ pj_size_t size, -+ pj_status_t status, -+ pj_size_t *remainder) -+{ -+ -+ pj_stun_sock *stun_sock; -+ -+ if (!(stun_sock = (pj_stun_sock *)pj_activesock_get_user_data(asock))) -+ return PJ_FALSE; -+ -+ pj_stun_session_cb *cb = pj_stun_session_callback(stun_sock->stun_sess); -+ /* Log socket error or disconnection */ -+ if (status != PJ_SUCCESS) { -+ if (stun_sock->conn_type == PJ_STUN_TP_UDP -+ || (status != PJ_EEOF && status != 120104 && status != 130054)) -+ { -+ PJ_PERROR(2, (stun_sock->obj_name, status, "read() error")); -+ } else if (status == 120104 -+ || status == 130054 /* RESET BY PEER */) -+ { -+ for (int i = 0; i <= stun_sock->outgoing_nb; ++i) -+ if (stun_sock->outgoing_socks[i].sock == asock -+ && cb -+ && (cb->on_peer_reset_connection)) -+ { -+ (cb->on_peer_reset_connection)(stun_sock->stun_sess, -+ stun_sock->outgoing_socks[i].addr); -+ } -+ } -+ return PJ_FALSE; -+ } -+#if PJ_HAS_TCP -+ pj_sockaddr_t *rx_addr = NULL; -+ unsigned sock_addr_len = 0; -+ for (int i = 0; i <= stun_sock->outgoing_nb; ++i) -+ if (stun_sock->outgoing_socks[i].sock == asock) { -+ rx_addr = stun_sock->outgoing_socks[i].addr; -+ sock_addr_len = pj_sockaddr_get_len(rx_addr); -+ if (cb && (cb->on_peer_packet)) -+ (cb->on_peer_packet)(stun_sock->stun_sess, -+ stun_sock->outgoing_socks[i].addr); -+ } -+ -+ if (rx_addr == NULL && stun_sock->incoming_nb != -1) { -+ // It's an incoming message -+ for (int i = 0; i <= stun_sock->incoming_nb; ++i) -+ if (stun_sock->incoming_socks[i].sock == asock) { -+ rx_addr = &stun_sock->incoming_socks[i].addr; -+ sock_addr_len = stun_sock->incoming_socks[i].addr_len; -+ } -+ } -+ return parse_rx_packet(asock, data, size, rx_addr, sock_addr_len); -+#else -+ pj_grp_lock_release(stun_sock->grp_lock); -+ return PJ_FALSE; -+#endif -+} -+ -+#if PJ_HAS_TCP -+/* -+ * Notification when incoming TCP socket has been connected. -+ * NOTE: cf https://www.pjsip.org/docs/latest/pjlib/docs/html//structpj__activesock__cb.htm if status needed -+ */ -+static pj_bool_t on_stun_sock_accept(pj_activesock_t *active_sock, -+ pj_sock_t sock, -+ const pj_sockaddr_t *src_addr, -+ int src_addr_len) -+{ -+ pj_status_t status; -+ pj_stun_sock *stun_sock; -+ int sock_type = pj_SOCK_STREAM(); -+ stun_sock = (pj_stun_sock *)pj_activesock_get_user_data(active_sock); -+ -+ stun_sock->incoming_nb += 1; -+ int nb_check = stun_sock->incoming_nb; -+ pj_sock_t *fd = &stun_sock->incoming_socks[nb_check].fd; -+ pj_activesock_t **asock = &stun_sock->incoming_socks[nb_check].sock; -+ -+ pj_sockaddr_cp(&stun_sock->incoming_socks[nb_check].addr, src_addr); -+ stun_sock->incoming_socks[nb_check].addr_len = src_addr_len; -+ *fd = sock; -+ -+ pj_activesock_cfg activesock_cfg; -+ pj_activesock_cb activesock_cb; -+ -+ pj_activesock_cfg_default(&activesock_cfg); -+ activesock_cfg.grp_lock = stun_sock->grp_lock; -+ activesock_cfg.async_cnt = stun_sock->cfg.async_cnt; -+ activesock_cfg.concurrency = 0; -+ -+ /* Create the active socket */ -+ pj_bzero(&activesock_cb, sizeof(activesock_cb)); -+ activesock_cb.on_data_read = &on_data_read; -+ activesock_cb.on_data_sent = &on_data_sent; -+ -+ status = pj_activesock_create(stun_sock->pool, *fd, sock_type, -+ &activesock_cfg, stun_sock->stun_cfg.ioqueue, -+ &activesock_cb, stun_sock, asock); -+ if (status != PJ_SUCCESS) { -+ pj_stun_sock_destroy(stun_sock); -+ pj_grp_lock_release(stun_sock->grp_lock); -+ return status; -+ } -+ -+ /* Start asynchronous read operations */ -+ pj_status_t result; -+ result = pj_activesock_start_read(*asock, stun_sock->pool, -+ stun_sock->cfg.max_pkt_size, 0); -+ if (result != PJ_SUCCESS) -+ return PJ_FALSE; -+ -+ return PJ_TRUE; -+} -+#endif -+ - /* Start socket. */ - PJ_DEF(pj_status_t) pj_stun_sock_start( pj_stun_sock *stun_sock, - const pj_str_t *domain, -@@ -526,6 +988,26 @@ PJ_DEF(pj_status_t) pj_stun_sock_destroy(pj_stun_sock *stun_sock) - stun_sock->sock_fd = PJ_INVALID_SOCKET; - } - -+ for (int i = 0; i <= stun_sock->incoming_nb ; ++i) { -+ if (stun_sock->incoming_socks[i].sock != NULL) { -+ stun_sock->incoming_socks[i].fd = PJ_INVALID_SOCKET; -+ pj_activesock_close(stun_sock->incoming_socks[i].sock); -+ } else if (stun_sock->incoming_socks[i].fd != PJ_INVALID_SOCKET) { -+ pj_sock_close(stun_sock->incoming_socks[i].fd); -+ stun_sock->incoming_socks[i].fd = PJ_INVALID_SOCKET; -+ } -+ } -+ -+ for (int i = 0; i <= stun_sock->outgoing_nb ; ++i) { -+ if (stun_sock->outgoing_socks[i].sock != NULL) { -+ stun_sock->outgoing_socks[i].fd = PJ_INVALID_SOCKET; -+ pj_activesock_close(stun_sock->outgoing_socks[i].sock); -+ } else if (stun_sock->outgoing_socks[i].fd != PJ_INVALID_SOCKET) { -+ pj_sock_close(stun_sock->outgoing_socks[i].fd); -+ stun_sock->outgoing_socks[i].fd = PJ_INVALID_SOCKET; -+ } -+ } -+ - if (stun_sock->stun_sess) { - pj_stun_session_destroy(stun_sock->stun_sess); - } -@@ -634,10 +1116,12 @@ static pj_status_t get_mapped_addr(pj_stun_sock *stun_sock) - - /* Send request */ - status=pj_stun_session_send_msg(stun_sock->stun_sess, INTERNAL_MSG_TOKEN, -- PJ_FALSE, PJ_TRUE, &stun_sock->srv_addr, -+ PJ_FALSE, -+ (stun_sock->conn_type == PJ_STUN_TP_UDP), -+ &stun_sock->srv_addr, - pj_sockaddr_get_len(&stun_sock->srv_addr), - tdata); -- if (status != PJ_SUCCESS) -+ if (status != PJ_SUCCESS && status != PJ_EPENDING) - goto on_error; - - return PJ_SUCCESS; -@@ -658,6 +1142,8 @@ PJ_DEF(pj_status_t) pj_stun_sock_get_info( pj_stun_sock *stun_sock, - - pj_grp_lock_acquire(stun_sock->grp_lock); - -+ info->conn_type = stun_sock->conn_type; -+ - /* Copy STUN server address and mapped address */ - pj_memcpy(&info->srv_addr, &stun_sock->srv_addr, - sizeof(pj_sockaddr)); -@@ -770,13 +1256,246 @@ PJ_DEF(pj_status_t) pj_stun_sock_sendto( pj_stun_sock *stun_sock, - send_key = &stun_sock->send_key; - - size = pkt_len; -- status = pj_activesock_sendto(stun_sock->active_sock, send_key, -- pkt, &size, flag, dst_addr, addr_len); -+ if (stun_sock->conn_type == PJ_STUN_TP_UDP) { -+ status = pj_activesock_sendto(stun_sock->active_sock, send_key, -+ pkt, &size, flag, dst_addr, addr_len); -+ } else { -+#if PJ_HAS_TCP -+ pj_bool_t is_outgoing = PJ_FALSE; -+ pj_bool_t is_incoming = PJ_FALSE; -+ for (int i = 0; i <= stun_sock->outgoing_nb; ++i) { -+ if (stun_sock->outgoing_socks[i].sock != NULL -+ && pj_sockaddr_cmp(stun_sock->outgoing_socks[i].addr, dst_addr) == 0) { -+ is_outgoing = PJ_TRUE; -+ status = pj_activesock_send(stun_sock->outgoing_socks[i].sock, -+ send_key, pkt, &size, flag); -+ break; -+ } -+ } -+ if (is_outgoing == PJ_FALSE) { -+ for (int i = 0 ; i <= stun_sock->incoming_nb; ++i) { -+ if (stun_sock->incoming_socks[i].sock != NULL -+ && pj_sockaddr_cmp(&stun_sock->incoming_socks[i].addr, -+ dst_addr) == 0) { -+ status = pj_activesock_send(stun_sock->incoming_socks[i].sock, -+ send_key, pkt, &size, flag); -+ is_incoming = PJ_TRUE; -+ break; -+ } -+ } -+ } -+ if (is_outgoing == PJ_FALSE && is_incoming == PJ_FALSE) { -+ status = pj_activesock_send(stun_sock->active_sock, send_key, pkt, -+ &size, flag); -+ } -+ -+#endif -+ } - - pj_grp_lock_release(stun_sock->grp_lock); - return status; - } - -+#if PJ_HAS_TCP -+ -+PJ_DECL(pj_status_t) pj_stun_sock_connect(pj_stun_sock *stun_sock, -+ const pj_sockaddr_t *remote_addr, -+ int af, -+ int nb_check) -+{ -+ -+ pj_grp_lock_acquire(stun_sock->grp_lock); -+ int sock_type = pj_SOCK_STREAM(); -+ -+ pj_sock_t *fd = &stun_sock->outgoing_socks[nb_check].fd; -+ pj_activesock_t **asock = &stun_sock->outgoing_socks[nb_check].sock; -+ pj_sockaddr_t **addr = &stun_sock->outgoing_socks[nb_check].addr; -+ -+ pj_status_t status = pj_sock_socket(af, sock_type, 0, fd); -+ if (status != PJ_SUCCESS) { -+ pj_stun_sock_destroy(stun_sock); -+ pj_grp_lock_release(stun_sock->grp_lock); -+ return status; -+ } -+ -+ /* Apply QoS, if specified */ -+ status = pj_sock_apply_qos2(*fd, stun_sock->cfg.qos_type, -+ &stun_sock->cfg.qos_params, 2, stun_sock->obj_name, NULL); -+ if (status != PJ_SUCCESS && !stun_sock->cfg.qos_ignore_error) { -+ pj_stun_sock_destroy(stun_sock); -+ pj_grp_lock_release(stun_sock->grp_lock); -+ return status; -+ } -+ -+ /* Apply socket buffer size */ -+ if (stun_sock->cfg.so_rcvbuf_size > 0) { -+ unsigned sobuf_size = stun_sock->cfg.so_rcvbuf_size; -+ status = pj_sock_setsockopt_sobuf(*fd, pj_SO_RCVBUF(), PJ_TRUE, &sobuf_size); -+ if (status != PJ_SUCCESS) { -+ pj_perror(3, stun_sock->obj_name, status, "Failed setting SO_RCVBUF"); -+ } else { -+ if (sobuf_size < stun_sock->cfg.so_rcvbuf_size) { -+ PJ_LOG(4, (stun_sock->obj_name, -+ "Warning! Cannot set SO_RCVBUF as configured, " -+ "now=%d, configured=%d", -+ sobuf_size, stun_sock->cfg.so_rcvbuf_size)); -+ } else { -+ PJ_LOG(5, (stun_sock->obj_name, "SO_RCVBUF set to %d", sobuf_size)); -+ } -+ } -+ } -+ -+ if (stun_sock->cfg.so_sndbuf_size > 0) { -+ unsigned sobuf_size = stun_sock->cfg.so_sndbuf_size; -+ status = pj_sock_setsockopt_sobuf(*fd, pj_SO_SNDBUF(), PJ_TRUE, &sobuf_size); -+ if (status != PJ_SUCCESS) { -+ pj_perror(3, stun_sock->obj_name, status, "Failed setting SO_SNDBUF"); -+ } else { -+ if (sobuf_size < stun_sock->cfg.so_sndbuf_size) { -+ PJ_LOG(4, (stun_sock->obj_name, -+ "Warning! Cannot set SO_SNDBUF as configured, " -+ "now=%d, configured=%d", -+ sobuf_size, stun_sock->cfg.so_sndbuf_size)); -+ } else { -+ PJ_LOG(5, (stun_sock->obj_name, "SO_SNDBUF set to %d", sobuf_size)); -+ } -+ } -+ } -+ -+ /* Init active socket configuration */ -+ { -+ pj_activesock_cfg activesock_cfg; -+ pj_activesock_cb activesock_cb; -+ -+ pj_activesock_cfg_default(&activesock_cfg); -+ activesock_cfg.grp_lock = stun_sock->grp_lock; -+ activesock_cfg.async_cnt = stun_sock->cfg.async_cnt; -+ activesock_cfg.concurrency = 0; -+ -+ /* Create the active socket */ -+ pj_bzero(&activesock_cb, sizeof(activesock_cb)); -+ activesock_cb.on_data_read = &on_data_read; -+ activesock_cb.on_data_sent = &on_data_sent; -+ activesock_cb.on_connect_complete = &on_connect_complete; -+ -+ status = pj_activesock_create(stun_sock->pool, *fd, -+ sock_type, &activesock_cfg, -+ stun_sock->stun_cfg.ioqueue, &activesock_cb, -+ stun_sock, asock); -+ -+ if (status != PJ_SUCCESS) { -+ pj_grp_lock_release(stun_sock->grp_lock); -+ return status; -+ } -+ -+ *addr = (pj_sockaddr_t*)remote_addr; -+ -+ status = pj_activesock_start_connect( -+ *asock, stun_sock->pool, *addr, -+ pj_sockaddr_get_len(*addr)); -+ if (status == PJ_SUCCESS) { -+ on_connect_complete(*asock, status); -+ } else if (status != PJ_EPENDING) { -+ char addrinfo[PJ_INET6_ADDRSTRLEN+8]; -+ pj_perror(3, stun_sock->pool->obj_name, status, "Failed to connect to %s", -+ pj_sockaddr_print(*addr, addrinfo, sizeof(addrinfo), 3)); -+ pj_grp_lock_release(stun_sock->grp_lock); -+ return status; -+ } -+ } -+ -+ pj_grp_lock_release(stun_sock->grp_lock); -+ return status; -+} -+ -+PJ_DECL(pj_status_t) pj_stun_sock_connect_active(pj_stun_sock *stun_sock, -+ const pj_sockaddr_t *remote_addr, -+ int af) -+{ -+ -+ if (stun_sock->incoming_nb != -1) { -+ // Check if not incoming, if so, already connected (mainly for PRFLX candidates) -+ for (int i = 0 ; i <= stun_sock->incoming_nb; ++i) { -+ if (stun_sock->incoming_socks[i].sock != NULL -+ && pj_sockaddr_cmp(&stun_sock->incoming_socks[i].addr, remote_addr)==0) { -+ pj_stun_session_cb *cb = -+ pj_stun_session_callback(stun_sock->stun_sess); -+ (cb->on_peer_connection)(stun_sock->stun_sess, PJ_SUCCESS, -+ (pj_sockaddr_t *)remote_addr); -+ return PJ_SUCCESS; -+ } -+ } -+ } -+ -+ /* Create socket and bind socket */ -+ stun_sock->outgoing_nb += 1; -+ int nb_check = stun_sock->outgoing_nb; -+ return pj_stun_sock_connect(stun_sock, remote_addr, af, nb_check); -+ -+} -+ -+PJ_DECL(pj_status_t) pj_stun_sock_reconnect_active(pj_stun_sock *stun_sock, -+ const pj_sockaddr_t *remote_addr, -+ int af) -+{ -+ for (int i = 0; i <= stun_sock->outgoing_nb; ++i) { -+ if (stun_sock->outgoing_socks[i].sock != NULL -+ && pj_sockaddr_cmp(stun_sock->outgoing_socks[i].addr, remote_addr) == 0) { -+ pj_activesock_close(stun_sock->outgoing_socks[i].sock); -+ return pj_stun_sock_connect(stun_sock, remote_addr, af, i); -+ } -+ } -+ return PJ_EINVAL; -+} -+ -+PJ_DECL(pj_status_t) pj_stun_sock_close(pj_stun_sock *stun_sock, -+ const pj_sockaddr_t *remote_addr) -+{ -+ for (int i = 0; i <= stun_sock->outgoing_nb; ++i) { -+ if (stun_sock->outgoing_socks[i].sock != NULL -+ && pj_sockaddr_cmp(stun_sock->outgoing_socks[i].addr, remote_addr) == 0) { -+ return pj_activesock_close(stun_sock->outgoing_socks[i].sock); -+ } -+ } -+ -+ for (int i = 0; i <= stun_sock->incoming_nb; ++i) { -+ if (stun_sock->incoming_socks[i].sock != NULL -+ && pj_sockaddr_cmp(&stun_sock->incoming_socks[i].addr, remote_addr) == 0) { -+ return pj_activesock_close(stun_sock->incoming_socks[i].sock); -+ } -+ } -+ return PJ_EINVAL; -+} -+ -+static pj_bool_t on_connect_complete(pj_activesock_t *asock, pj_status_t status) -+{ -+ pj_stun_sock *stun_sock; -+ stun_sock = (pj_stun_sock *)pj_activesock_get_user_data(asock); -+ -+ pj_sockaddr_t* remote_addr = NULL; -+ // Get remote connected address -+ for (int i = 0 ; i <= stun_sock->outgoing_nb ; ++i) { -+ if (stun_sock->outgoing_socks[i].sock == asock) { -+ remote_addr = stun_sock->outgoing_socks[i].addr; -+ } -+ } -+ if (!remote_addr) return PJ_FALSE; -+ -+ pj_stun_session_cb *cb = pj_stun_session_callback(stun_sock->stun_sess); -+ if (!cb->on_peer_connection) { -+ return PJ_FALSE; -+ } -+ -+ (cb->on_peer_connection)(stun_sock->stun_sess, status, remote_addr); -+ if (status == PJ_SUCCESS) { -+ status = pj_activesock_start_read(asock, stun_sock->pool, -+ stun_sock->cfg.max_pkt_size, 0); -+ } -+ return status != PJ_SUCCESS; -+} -+ -+#endif -+ - /* This callback is called by the STUN session to send packet */ - static pj_status_t sess_on_send_msg(pj_stun_session *sess, - void *token, -@@ -787,6 +1506,7 @@ static pj_status_t sess_on_send_msg(pj_stun_session *sess, - { - pj_stun_sock *stun_sock; - pj_ssize_t size; -+ pj_status_t status; - - stun_sock = (pj_stun_sock *) pj_stun_session_get_user_data(sess); - if (!stun_sock || !stun_sock->active_sock) { -@@ -800,9 +1520,30 @@ static pj_status_t sess_on_send_msg(pj_stun_session *sess, - PJ_UNUSED_ARG(token); - - size = pkt_size; -- return pj_activesock_sendto(stun_sock->active_sock, -- &stun_sock->int_send_key, -- pkt, &size, 0, dst_addr, addr_len); -+ if (stun_sock->conn_type == PJ_STUN_TP_UDP) { -+ status = pj_activesock_sendto(stun_sock->active_sock, -+ &stun_sock->int_send_key,pkt, &size, 0, -+ dst_addr, addr_len); -+ } -+#if PJ_HAS_TCP -+ else { -+ for (int i = 0 ; i <= stun_sock->incoming_nb; ++i) { -+ if (stun_sock->incoming_socks[i].sock != NULL -+ && !pj_sockaddr_cmp(&stun_sock->incoming_socks[i].addr, dst_addr)) { -+ status = pj_activesock_send(stun_sock->incoming_socks[i].sock, -+ &stun_sock->int_send_key, -+ pkt, &size, 0); -+ if (status != PJ_SUCCESS && status != PJ_EPENDING) -+ PJ_PERROR(4,(stun_sock->obj_name, status, -+ "Error sending answer on incoming_sock(s)")); -+ } -+ } -+ /* last attempt */ -+ status = pj_activesock_send(stun_sock->active_sock, -+ &stun_sock->int_send_key, pkt, &size, 0); -+ } -+#endif -+ return status; - } - - /* This callback is called by the STUN session when outgoing transaction -@@ -942,8 +1683,6 @@ static pj_bool_t on_data_recvfrom(pj_activesock_t *asock, - pj_status_t status) - { - pj_stun_sock *stun_sock; -- pj_stun_msg_hdr *hdr; -- pj_uint16_t type; - - stun_sock = (pj_stun_sock*) pj_activesock_get_user_data(asock); - if (!stun_sock) -@@ -955,58 +1694,7 @@ static pj_bool_t on_data_recvfrom(pj_activesock_t *asock, - return PJ_TRUE; - } - -- pj_grp_lock_acquire(stun_sock->grp_lock); -- -- /* Check that this is STUN message */ -- status = pj_stun_msg_check((const pj_uint8_t*)data, size, -- PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET); -- if (status != PJ_SUCCESS) { -- /* Not STUN -- give it to application */ -- goto process_app_data; -- } -- -- /* Treat packet as STUN header and copy the STUN message type. -- * We don't want to access the type directly from the header -- * since it may not be properly aligned. -- */ -- hdr = (pj_stun_msg_hdr*) data; -- pj_memcpy(&type, &hdr->type, 2); -- type = pj_ntohs(type); -- -- /* If the packet is a STUN Binding response and part of the -- * transaction ID matches our internal ID, then this is -- * our internal STUN message (Binding request or keep alive). -- * Give it to our STUN session. -- */ -- if (!PJ_STUN_IS_RESPONSE(type) || -- PJ_STUN_GET_METHOD(type) != PJ_STUN_BINDING_METHOD || -- pj_memcmp(hdr->tsx_id, stun_sock->tsx_id, 10) != 0) -- { -- /* Not STUN Binding response, or STUN transaction ID mismatch. -- * This is not our message too -- give it to application. -- */ -- goto process_app_data; -- } -- -- /* This is our STUN Binding response. Give it to the STUN session */ -- status = pj_stun_session_on_rx_pkt(stun_sock->stun_sess, data, size, -- PJ_STUN_IS_DATAGRAM, NULL, NULL, -- src_addr, addr_len); -- -- status = pj_grp_lock_release(stun_sock->grp_lock); -- -- return status!=PJ_EGONE ? PJ_TRUE : PJ_FALSE; -- --process_app_data: -- if (stun_sock->cb.on_rx_data) { -- (*stun_sock->cb.on_rx_data)(stun_sock, data, (unsigned)size, -- src_addr, addr_len); -- status = pj_grp_lock_release(stun_sock->grp_lock); -- return status!=PJ_EGONE ? PJ_TRUE : PJ_FALSE; -- } -- -- status = pj_grp_lock_release(stun_sock->grp_lock); -- return status!=PJ_EGONE ? PJ_TRUE : PJ_FALSE; -+ return parse_rx_packet(asock, data, size, src_addr, addr_len); - } - - /* Callback from active socket about send status */ -@@ -1047,3 +1735,8 @@ static pj_bool_t on_data_sent(pj_activesock_t *asock, - return PJ_TRUE; - } - -+pj_stun_session* pj_stun_sock_get_session(pj_stun_sock *stun_sock) -+{ -+ return stun_sock ? stun_sock->stun_sess : NULL; -+} -+ -diff --git a/pjnath/src/pjnath/stun_transaction.c b/pjnath/src/pjnath/stun_transaction.c -index e4d67db0f..569b4826d 100644 ---- a/pjnath/src/pjnath/stun_transaction.c -+++ b/pjnath/src/pjnath/stun_transaction.c -@@ -396,6 +396,9 @@ static void retransmit_timer_callback(pj_timer_heap_t *timer_heap, - PJ_DEF(pj_status_t) pj_stun_client_tsx_retransmit(pj_stun_client_tsx *tsx, - pj_bool_t mod_count) - { -+ if (!tsx) -+ return PJ_EINVAL; -+ - if (tsx->destroy_timer.id != 0) { - return PJ_SUCCESS; - } -diff --git a/pjnath/src/pjnath/turn_session.c b/pjnath/src/pjnath/turn_session.c -index 879ac6ffd..3a7df799a 100644 ---- a/pjnath/src/pjnath/turn_session.c -+++ b/pjnath/src/pjnath/turn_session.c -@@ -311,7 +311,8 @@ PJ_DEF(pj_status_t) pj_turn_session_create( const pj_stun_config *cfg, - stun_cb.on_request_complete = &stun_on_request_complete; - stun_cb.on_rx_indication = &stun_on_rx_indication; - status = pj_stun_session_create(&sess->stun_cfg, sess->obj_name, &stun_cb, -- PJ_FALSE, sess->grp_lock, &sess->stun); -+ PJ_FALSE, sess->grp_lock, &sess->stun, -+ conn_type); - if (status != PJ_SUCCESS) { - do_destroy(sess); - return status; -diff --git a/pjnath/src/pjnath/turn_sock.c b/pjnath/src/pjnath/turn_sock.c -index dc6304d9f..6de6ab1da 100644 ---- a/pjnath/src/pjnath/turn_sock.c -+++ b/pjnath/src/pjnath/turn_sock.c -@@ -894,12 +894,7 @@ static pj_bool_t on_data_sent(pj_turn_sock *turn_sock, - } - - if (turn_sock->cb.on_data_sent) { -- pj_ssize_t header_len, sent_size; -- -- /* Remove the length of packet header from sent size. */ -- header_len = turn_sock->pkt_len - turn_sock->body_len; -- sent_size = (sent > header_len)? (sent - header_len) : 0; -- (*turn_sock->cb.on_data_sent)(turn_sock, sent_size); -+ (*turn_sock->cb.on_data_sent)(turn_sock, sent); - } - - return PJ_TRUE; -@@ -1553,7 +1548,7 @@ static void turn_on_connection_attempt(pj_turn_session *sess, - return); - - PJ_LOG(5,(turn_sock->pool->obj_name, "Connection attempt from peer %s", -- pj_sockaddr_print(&peer_addr, addrtxt, sizeof(addrtxt), 3))); -+ pj_sockaddr_print(peer_addr, addrtxt, sizeof(addrtxt), 3))); - - if (turn_sock == NULL) { - /* We've been destroyed */ -@@ -1766,3 +1761,20 @@ static void turn_on_connection_bind_status(pj_turn_session *sess, - peer_addr, addr_len); - } - } -+ -+pj_bool_t pj_turn_sock_has_dataconn(pj_turn_sock *turn_sock, -+ const pj_sockaddr_t *peer) -+{ -+ if (!turn_sock) return PJ_FALSE; -+ -+ for (int i = 0; i < turn_sock->data_conn_cnt; ++i) { -+ tcp_data_conn_t* dataconn = &turn_sock->data_conn[i]; -+ if (dataconn) { -+ pj_sockaddr_t* conn_peer = &dataconn->peer_addr; -+ if (pj_sockaddr_cmp(conn_peer, peer) == 0) -+ return PJ_TRUE; -+ } -+ } -+ -+ return PJ_FALSE; -+} -diff --git a/pjnath/src/pjturn-client/client_main.c b/pjnath/src/pjturn-client/client_main.c -index 6f9f1ff1a..e56c510c8 100644 ---- a/pjnath/src/pjturn-client/client_main.c -+++ b/pjnath/src/pjturn-client/client_main.c -@@ -155,7 +155,7 @@ static int init() - - name[strlen(name)-1] = '0'+i; - status = pj_stun_sock_create(&g.stun_config, name, pj_AF_INET(), -- &stun_sock_cb, &ss_cfg, -+ PJ_STUN_TP_UDP, &stun_sock_cb, &ss_cfg, - &g.peer[i], &g.peer[i].stun_sock); - if (status != PJ_SUCCESS) { - my_perror("pj_stun_sock_create()", status); -diff --git a/pjnath/src/pjturn-srv/allocation.c b/pjnath/src/pjturn-srv/allocation.c -index 6c9c9ce11..99d1545c7 100644 ---- a/pjnath/src/pjturn-srv/allocation.c -+++ b/pjnath/src/pjturn-srv/allocation.c -@@ -338,7 +338,8 @@ PJ_DEF(pj_status_t) pj_turn_allocation_create(pj_turn_transport *transport, - sess_cb.on_rx_request = &stun_on_rx_request; - sess_cb.on_rx_indication = &stun_on_rx_indication; - status = pj_stun_session_create(&srv->core.stun_cfg, alloc->obj_name, -- &sess_cb, PJ_FALSE, NULL, &alloc->sess); -+ &sess_cb, PJ_FALSE, NULL, &alloc->sess, -+ PJ_STUN_TP_UDP); - if (status != PJ_SUCCESS) { - goto on_error; - } -diff --git a/pjnath/src/pjturn-srv/server.c b/pjnath/src/pjturn-srv/server.c -index 94dda29a3..95ad1793d 100644 ---- a/pjnath/src/pjturn-srv/server.c -+++ b/pjnath/src/pjturn-srv/server.c -@@ -156,7 +156,7 @@ PJ_DEF(pj_status_t) pj_turn_srv_create(pj_pool_factory *pf, - - status = pj_stun_session_create(&srv->core.stun_cfg, srv->obj_name, - &sess_cb, PJ_FALSE, NULL, -- &srv->core.stun_sess); -+ &srv->core.stun_sess, PJ_STUN_TP_UDP); - if (status != PJ_SUCCESS) { - goto on_error; - } -diff --git a/pjsip-apps/src/samples/icedemo.c b/pjsip-apps/src/samples/icedemo.c -index 07ccc31f0..3b93b9417 100644 ---- a/pjsip-apps/src/samples/icedemo.c -+++ b/pjsip-apps/src/samples/icedemo.c -@@ -44,6 +44,7 @@ static struct app_t - pj_str_t stun_srv; - pj_str_t turn_srv; - pj_bool_t turn_tcp; -+ pj_bool_t ice_tcp; - pj_str_t turn_username; - pj_str_t turn_password; - pj_bool_t turn_fingerprint; -@@ -341,6 +342,12 @@ static pj_status_t icedemo_init(void) - else - icedemo.ice_cfg.opt.aggressive = PJ_TRUE; - -+ /* Connection type to STUN server */ -+ if (icedemo.opt.ice_tcp) -+ icedemo.ice_cfg.stun.conn_type = PJ_STUN_TP_TCP; -+ else -+ icedemo.ice_cfg.stun.conn_type = PJ_STUN_TP_UDP; -+ - /* Configure STUN/srflx candidate resolution */ - if (icedemo.opt.stun_srv.slen) { - char *pos; -@@ -384,7 +391,7 @@ static pj_status_t icedemo_init(void) - icedemo.ice_cfg.turn.auth_cred.data.static_cred.data = icedemo.opt.turn_password; - - /* Connection type to TURN server */ -- if (icedemo.opt.turn_tcp) -+ if (icedemo.opt.ice_tcp) - icedemo.ice_cfg.turn.conn_type = PJ_TURN_TP_TCP; - else - icedemo.ice_cfg.turn.conn_type = PJ_TURN_TP_UDP; -@@ -395,6 +402,10 @@ static pj_status_t icedemo_init(void) - icedemo.ice_cfg.turn.alloc_param.ka_interval = KA_INTERVAL; - } - -+ if (icedemo.opt.ice_tcp) { -+ icedemo.ice_cfg.protocol = PJ_ICE_TP_TCP; -+ } -+ - /* -= That's it for now, initialization is complete =- */ - return PJ_SUCCESS; - } -@@ -530,10 +541,27 @@ static int print_cand(char buffer[], unsigned maxlen, - char *p = buffer; - int printed; - -- PRINT("a=candidate:%.*s %u UDP %u %s %u typ ", -+ /** Section 4.5, RFC 6544 (https://tools.ietf.org/html/rfc6544) -+ * candidate-attribute = "candidate" ":" foundation SP component-id SP -+ * "TCP" SP -+ * priority SP -+ * connection-address SP -+ * port SP -+ * cand-type -+ * [SP rel-addr] -+ * [SP rel-port] -+ * SP tcp-type-ext -+ * *(SP extension-att-name SP -+ * extension-att-value) -+ * -+ * tcp-type-ext = "tcptype" SP tcp-type -+ * tcp-type = "active" / "passive" / "so" -+ */ -+ PRINT("a=candidate:%.*s %u %s %u %s %u typ ", - (int)cand->foundation.slen, - cand->foundation.ptr, - (unsigned)cand->comp_id, -+ cand->transport == PJ_CAND_UDP? "UDP" : "TCP", - cand->prio, - pj_sockaddr_print(&cand->addr, ipaddr, - sizeof(ipaddr), 0), -@@ -542,6 +570,23 @@ static int print_cand(char buffer[], unsigned maxlen, - PRINT("%s\n", - pj_ice_get_cand_type_name(cand->type)); - -+ if (cand->transport != PJ_CAND_UDP) { -+ PRINT(" tcptype"); -+ switch (cand->transport) { -+ case PJ_CAND_TCP_ACTIVE: -+ PRINT(" active"); -+ break; -+ case PJ_CAND_TCP_PASSIVE: -+ PRINT(" passive"); -+ break; -+ case PJ_CAND_TCP_SO: -+ default: -+ PRINT(" so"); -+ break; -+ } -+ } -+ PRINT("\n"); -+ - if (p == buffer+maxlen) - return -PJ_ETOOSMALL; - -@@ -608,6 +653,26 @@ static int encode_session(char buffer[], unsigned maxlen) - sizeof(ipaddr), 0)); - } - -+ if (cand[0].transport != PJ_CAND_UDP) { -+ /** RFC 6544, Section 4.5: -+ * If the default candidate is TCP-based, the agent MUST include the -+ * a=setup and a=connection attributes from RFC 4145 [RFC4145], -+ * following the procedures defined there as if ICE were not in use. -+ */ -+ PRINT("a=setup:"); -+ switch (cand[0].transport) { -+ case PJ_CAND_TCP_ACTIVE: -+ PRINT("active\n"); -+ break; -+ case PJ_CAND_TCP_PASSIVE: -+ PRINT("passive\n"); -+ break; -+ default: -+ return PJ_EINVALIDOP; -+ } -+ PRINT("a=connection:new\n"); -+ } -+ - /* Enumerate all candidates for this component */ - cand_cnt = PJ_ARRAY_SIZE(cand); - status = pj_ice_strans_enum_cands(icedemo.icest, comp+1, -@@ -709,7 +774,7 @@ static void icedemo_show_ice(void) - */ - static void icedemo_input_remote(void) - { -- char linebuf[80]; -+ char linebuf[120]; - unsigned media_cnt = 0; - unsigned comp0_port = 0; - char comp0_addr[80]; -@@ -819,27 +884,43 @@ static void icedemo_input_remote(void) - pj_sockaddr_set_port(&icedemo.rem.def_addr[1], (pj_uint16_t)port); - - } else if (strcmp(attr, "candidate")==0) { -+ /** Section 4.5, RFC 6544 (https://tools.ietf.org/html/rfc6544) -+ * candidate-attribute = "candidate" ":" foundation SP component-id -+ * SP "TCP" SP priority SP connection-address SP port SP cand-type [SP -+ * rel-addr] [SP rel-port] SP tcp-type-ext -+ * *(SP extension-att-name SP -+ * extension-att-value) -+ * -+ * tcp-type-ext = "tcptype" SP tcp-type -+ * tcp-type = "active" / "passive" / "so" -+ */ - char *sdpcand = attr+strlen(attr)+1; - int af, cnt; -- char foundation[32], transport[12], ipaddr[80], type[32]; -+ char foundation[32], transport[12], ipaddr[80], type[32], tcp_type[32]; - pj_str_t tmpaddr; - int comp_id, prio, port; - pj_ice_sess_cand *cand; - pj_status_t status; -+ pj_bool_t is_tcp = PJ_FALSE; - -- cnt = sscanf(sdpcand, "%s %d %s %d %s %d typ %s", -+ cnt = sscanf(sdpcand, "%s %d %s %d %s %d typ %s tcptype %s\n", - foundation, - &comp_id, - transport, - &prio, - ipaddr, - &port, -- type); -- if (cnt != 7) { -+ type, -+ tcp_type); -+ if (cnt != 7 && cnt != 8) { - PJ_LOG(1, (THIS_FILE, "error: Invalid ICE candidate line")); - goto on_error; - } - -+ if (strcmp(transport, "TCP") == 0) { -+ is_tcp = PJ_TRUE; -+ } -+ - cand = &icedemo.rem.cand[icedemo.rem.cand_cnt]; - pj_bzero(cand, sizeof(*cand)); - -@@ -855,6 +936,23 @@ static void icedemo_input_remote(void) - goto on_error; - } - -+ if (is_tcp) { -+ if (strcmp(tcp_type, "active") == 0) -+ cand->transport = PJ_CAND_TCP_ACTIVE; -+ else if (strcmp(tcp_type, "passive") == 0) -+ cand->transport = PJ_CAND_TCP_PASSIVE; -+ else if (strcmp(tcp_type, "so") == 0) -+ cand->transport = PJ_CAND_TCP_SO; -+ else { -+ PJ_LOG(1, (THIS_FILE, -+ "Error: invalid transport type '%s'", -+ tcp_type)); -+ goto on_error; -+ } -+ } else { -+ cand->transport = PJ_CAND_UDP; -+ } -+ - cand->comp_id = (pj_uint8_t)comp_id; - pj_strdup2(icedemo.pool, &cand->foundation, foundation); - cand->prio = prio; -@@ -879,6 +977,10 @@ static void icedemo_input_remote(void) - - if (cand->comp_id > icedemo.rem.comp_cnt) - icedemo.rem.comp_cnt = cand->comp_id; -+ } else if (strcmp(attr, "setup") == 0) { -+ // TODO -+ } else if (strcmp(attr, "connection") == 0) { -+ // TODO - } - } - break; -diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c -index 7ae44d7d8..2010864c3 100644 ---- a/pjsip/src/pjsua-lib/pjsua_core.c -+++ b/pjsip/src/pjsua-lib/pjsua_core.c -@@ -1553,7 +1553,7 @@ static void resolve_stun_entry(pjsua_stun_resolve *sess) - stun_sock_cb.on_status = &test_stun_on_status; - sess->async_wait = PJ_FALSE; - status = pj_stun_sock_create(&pjsua_var.stun_cfg, "stunresolve", -- sess->af, &stun_sock_cb, -+ sess->af, PJ_STUN_TP_UDP, &stun_sock_cb, - NULL, sess, &sess->stun_sock); - if (status != PJ_SUCCESS) { - char errmsg[PJ_ERR_MSG_SIZE]; --- -2.25.1 - diff --git a/contrib/src/pjproject/0002-rfc2466.patch b/contrib/src/pjproject/0002-rfc2466.patch deleted file mode 100644 index dc59a8ae841ce865413ec60dc480e52293c87d9c..0000000000000000000000000000000000000000 --- a/contrib/src/pjproject/0002-rfc2466.patch +++ /dev/null @@ -1,207 +0,0 @@ - pjnath/src/pjnath/ice_session.c | 176 ++++++++++++++++++++++++++++++++ - 1 file changed, 176 insertions(+) - -diff --git a/pjnath/src/pjnath/ice_session.c b/pjnath/src/pjnath/ice_session.c -index f35cfba5c..cc7e7d564 100644 ---- a/pjnath/src/pjnath/ice_session.c -+++ b/pjnath/src/pjnath/ice_session.c -@@ -30,6 +30,21 @@ - #include <pj/rand.h> - #include <pj/string.h> - -+#if defined(_WIN32) || defined(__APPLE__) -+/* TODO(sblin): find an alternative for these paltforms */ -+#else -+/* The following headers are used to get DEPRECATED addresses -+ * as specified in RFC 2462 Section 5.5.4 -+ * https://tools.ietf.org/html/rfc2462#section-5.5.4 -+ */ -+#include <arpa/inet.h> -+#include <asm/types.h> -+#include <linux/netlink.h> -+#include <linux/rtnetlink.h> -+#include <sys/socket.h> -+#include <unistd.h> -+#endif -+ - /* String names for candidate types */ - static const char *cand_type_names[] = - { -@@ -734,6 +749,144 @@ static pj_uint32_t CALC_CAND_PRIO(pj_ice_sess *ice, - #endif - } - -+/* retrieve invalid addresses and store it in a string */ -+static PJ_DEF(void) get_invalid_addresses(char** addresses, size_t* size) -+{ -+#if defined(_WIN32) || defined(__APPLE__) -+ // PJ_TODO("sblin: find alternative for WIN32 and APPLE"); -+#else -+ struct { -+ struct nlmsghdr nlmsg_info; -+ struct ifaddrmsg ifaddrmsg_info; -+ } netlink_req; -+ -+ int fd; -+ -+ long pagesize = sysconf(_SC_PAGESIZE); -+ -+ if (!pagesize) -+ pagesize = 4096; /* Assume pagesize is 4096 if sysconf() failed */ -+ -+ fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); -+ if(fd < 0) { -+ perror("socket initialization error: abort"); -+ return; -+ } -+ -+ int rtn; -+ -+ bzero(&netlink_req, sizeof(netlink_req)); -+ -+ netlink_req.nlmsg_info.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); -+ netlink_req.nlmsg_info.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; -+ netlink_req.nlmsg_info.nlmsg_type = RTM_GETADDR; -+ netlink_req.nlmsg_info.nlmsg_pid = getpid(); -+ -+ netlink_req.ifaddrmsg_info.ifa_family = AF_INET6; -+ -+ rtn = send(fd, &netlink_req, netlink_req.nlmsg_info.nlmsg_len, 0); -+ if(rtn < 0) { -+ perror("send error: abort"); -+ return; -+ } -+ -+ char read_buffer[pagesize]; -+ struct nlmsghdr *nlmsg_ptr; -+ int nlmsg_len; -+ -+ size_t idx = 0; -+ /* Will store all deprecated addresses into a string */ -+ char* deprecatedAddrs = malloc(256*sizeof(char)*PJ_INET6_ADDRSTRLEN); -+ if (!deprecatedAddrs) { -+ perror("malloc error: abort"); -+ return; -+ } -+ -+ while(1) { -+ int rtn; -+ -+ bzero(read_buffer, pagesize); -+ rtn = recv(fd, read_buffer, pagesize, 0); -+ if(rtn < 0) { -+ perror ("recv(): "); -+ free(deprecatedAddrs); -+ return; -+ } -+ -+ nlmsg_ptr = (struct nlmsghdr *) read_buffer; -+ nlmsg_len = rtn; -+ -+ if (nlmsg_len < sizeof (struct nlmsghdr)) { -+ perror ("Received an incomplete netlink packet"); -+ free(deprecatedAddrs); -+ return; -+ } -+ -+ if (nlmsg_ptr->nlmsg_type == NLMSG_DONE) -+ break; -+ -+ for(; NLMSG_OK(nlmsg_ptr, nlmsg_len); -+ nlmsg_ptr = NLMSG_NEXT(nlmsg_ptr, nlmsg_len)) -+ { -+ struct ifaddrmsg *ifaddrmsg_ptr; -+ struct rtattr *rtattr_ptr; -+ int ifaddrmsg_len; -+ -+ ifaddrmsg_ptr = (struct ifaddrmsg *) NLMSG_DATA(nlmsg_ptr); -+ -+ if (ifaddrmsg_ptr->ifa_flags & IFA_F_DEPRECATED || -+ ifaddrmsg_ptr->ifa_flags & IFA_F_TENTATIVE) -+ { -+ rtattr_ptr = (struct rtattr *) IFA_RTA(ifaddrmsg_ptr); -+ ifaddrmsg_len = IFA_PAYLOAD(nlmsg_ptr); -+ -+ for(;RTA_OK(rtattr_ptr, ifaddrmsg_len); -+ rtattr_ptr = RTA_NEXT(rtattr_ptr, ifaddrmsg_len)) -+ { -+ switch(rtattr_ptr->rta_type) { -+ case IFA_ADDRESS: -+ /* Any 256 obsolete ips (should not happen), resize the array. */ -+ if (idx > 0 && idx % 256 == 0) { -+ char* newDeprecated = realloc(deprecatedAddrs, -+ (idx + 256)*sizeof(char)*PJ_INET6_ADDRSTRLEN); -+ if (newDeprecated == NULL) { -+ perror("realloc error: abort"); -+ free(deprecatedAddrs); -+ return; -+ } -+ deprecatedAddrs = newDeprecated; -+ } -+ /* Store deprecated IP */ -+ inet_ntop(ifaddrmsg_ptr->ifa_family, -+ RTA_DATA(rtattr_ptr), -+ &deprecatedAddrs[idx*PJ_INET6_ADDRSTRLEN], -+ sizeof(char)*PJ_INET6_ADDRSTRLEN); -+ ++idx; -+ break; -+ default: -+ break; -+ } -+ } -+ } -+ } -+ } -+ -+ close(fd); -+ *size = idx; -+ if (idx > 0) { -+ char *final = realloc(deprecatedAddrs, -+ idx*sizeof(char)*PJ_INET6_ADDRSTRLEN); -+ if (final) { -+ *addresses = final; -+ } else { -+ perror("realloc error: abort"); -+ free(deprecatedAddrs); -+ } -+ } else { -+ free(deprecatedAddrs); -+ } -+#endif -+} - - /* - * Add ICE candidate -@@ -751,6 +904,29 @@ PJ_DEF(pj_status_t) pj_ice_sess_add_cand(pj_ice_sess *ice, - unsigned *p_cand_id, - pj_ice_cand_transport transport) - { -+ /** -+ * RFC 2466: an ip address can have the status DEPRECATED and SHOULD NOT -+ * be used by new by applications unless they already use it. -+ * So, we should ignore these addresses. -+ * Also, ips with the TENTATIVE state are not ready and SHOULD NOT be -+ * used for now. Ignore these addresses too. -+ */ -+ char* deprecatedAddrs = NULL; -+ size_t size = 0; -+ get_invalid_addresses(&deprecatedAddrs, &size); -+ if (deprecatedAddrs != NULL) { -+ char tmpAddrStr[PJ_INET6_ADDRSTRLEN]; -+ pj_sockaddr_print(addr, tmpAddrStr, sizeof(tmpAddrStr), 0); -+ for (int i = 0; i<size*PJ_INET6_ADDRSTRLEN; i+=PJ_INET6_ADDRSTRLEN) { -+ if (!strncmp(tmpAddrStr, &deprecatedAddrs[i], PJ_INET6_ADDRSTRLEN)) { -+ free(deprecatedAddrs); -+ /* This address is considered as deprecated ignore it. */ -+ return PJ_SUCCESS; -+ } -+ } -+ free(deprecatedAddrs); -+ } -+ - pj_ice_sess_cand *lcand; - pj_status_t status = PJ_SUCCESS; - char address[PJ_INET6_ADDRSTRLEN]; --- -2.25.1 - diff --git a/contrib/src/pjproject/0003-add-tcp-keep-alive.patch b/contrib/src/pjproject/0003-add-tcp-keep-alive.patch deleted file mode 100644 index 486b9f664e865f81f23efdfab1fbecfc49861976..0000000000000000000000000000000000000000 --- a/contrib/src/pjproject/0003-add-tcp-keep-alive.patch +++ /dev/null @@ -1,337 +0,0 @@ -From 0d46f77fe2cd2e3197f3b7b745d822b6c1cb9790 Mon Sep 17 00:00:00 2001 -From: jrun <darwinskernel@gmail.com> -Date: Thu, 27 Feb 2020 12:57:17 -0500 -Subject: [PATCH 3/9] add tcp keep alive - ---- - pjlib/include/pj/sock.h | 29 +++++++++++++++++++ - pjlib/src/pj/sock_bsd.c | 45 +++++++++++++++++++++++++++++ - pjlib/src/pj/sock_common.c | 20 +++++++++++++ - pjlib/src/pj/sock_uwp.cpp | 24 +++++++++++++++ - pjlib/src/pj/symbols.c | 3 ++ - pjnath/include/pjnath/ice_session.h | 5 ++++ - pjnath/include/pjnath/ice_strans.h | 7 +++++ - pjnath/src/pjnath/ice_session.c | 6 ++++ - pjnath/src/pjnath/ice_strans.c | 11 +++++++ - 9 files changed, 150 insertions(+) - -diff --git a/pjlib/include/pj/sock.h b/pjlib/include/pj/sock.h -index 292b364e7..7542045b1 100644 ---- a/pjlib/include/pj/sock.h -+++ b/pjlib/include/pj/sock.h -@@ -314,6 +314,11 @@ extern const pj_uint16_t PJ_SO_REUSEADDR; - /** Do not generate SIGPIPE. @see pj_SO_NOSIGPIPE */ - extern const pj_uint16_t PJ_SO_NOSIGPIPE; - -+extern const pj_uint16_t PJ_SO_KEEPALIVE; -+extern const pj_uint16_t PJ_TCP_KEEPIDLE; -+extern const pj_uint16_t PJ_TCP_KEEPINTVL; -+extern const pj_uint16_t PJ_TCP_KEEPCNT; -+ - /** Set the protocol-defined priority for all packets to be sent on socket. - */ - extern const pj_uint16_t PJ_SO_PRIORITY; -@@ -344,9 +349,21 @@ extern const pj_uint16_t PJ_IP_DROP_MEMBERSHIP; - /** Get #PJ_SO_SNDBUF constant */ - PJ_DECL(pj_uint16_t) pj_SO_SNDBUF(void); - -+ /** Get #PJ_SO_KEEPALIVE constant */ -+# define pj_SO_KEEPALIVE() PJ_SO_KEEPALIVE(void); -+ - /** Get #PJ_TCP_NODELAY constant */ - PJ_DECL(pj_uint16_t) pj_TCP_NODELAY(void); - -+ /** Get #PJ_TCP_KEEPIDLE constant */ -+# define pj_TCP_KEEPIDLE() PJ_TCP_KEEPIDLE(void); -+ -+ /** Get #PJ_TCP_KEEPINTVL constant */ -+# define pj_TCP_KEEPINTVL() PJ_TCP_KEEPINTVL(void); -+ -+ /** Get #PJ_TCP_KEEPCNT constant */ -+# define pj_TCP_KEEPCNT() PJ_TCP_KEEPCNT(void); -+ - /** Get #PJ_SO_REUSEADDR constant */ - PJ_DECL(pj_uint16_t) pj_SO_REUSEADDR(void); - -@@ -380,9 +397,21 @@ extern const pj_uint16_t PJ_IP_DROP_MEMBERSHIP; - /** Get #PJ_SO_SNDBUF constant */ - # define pj_SO_SNDBUF() PJ_SO_SNDBUF - -+ /** Get #PJ_SO_KEEPALIVE constant */ -+# define pj_SO_KEEPALIVE() PJ_SO_KEEPALIVE -+ - /** Get #PJ_TCP_NODELAY constant */ - # define pj_TCP_NODELAY() PJ_TCP_NODELAY - -+ /** Get #PJ_TCP_KEEPIDLE constant */ -+# define pj_TCP_KEEPIDLE() PJ_TCP_KEEPIDLE -+ -+ /** Get #PJ_TCP_KEEPINTVL constant */ -+# define pj_TCP_KEEPINTVL() PJ_TCP_KEEPINTVL -+ -+ /** Get #PJ_TCP_KEEPCNT constant */ -+# define pj_TCP_KEEPCNT() PJ_TCP_KEEPCNT -+ - /** Get #PJ_SO_REUSEADDR constant */ - # define pj_SO_REUSEADDR() PJ_SO_REUSEADDR - -diff --git a/pjlib/src/pj/sock_bsd.c b/pjlib/src/pj/sock_bsd.c -index ce23101c4..f9e8ffa82 100644 ---- a/pjlib/src/pj/sock_bsd.c -+++ b/pjlib/src/pj/sock_bsd.c -@@ -28,6 +28,15 @@ - - #define THIS_FILE "sock_bsd.c" - -+#if !defined(PJ_WIN32) && !defined(PJ_WIN64) -+# if !defined(SOL_TCP) && defined(IPPROTO_TCP) -+# define SOL_TCP IPPROTO_TCP -+# endif -+# if !defined(TCP_KEEPIDLE) && defined(TCP_KEEPALIVE) -+# define TCP_KEEPIDLE TCP_KEEPALIVE -+# endif -+#endif -+ - /* - * Address families conversion. - * The values here are indexed based on pj_addr_family. -@@ -144,7 +153,19 @@ const pj_uint16_t PJ_IPV6_TCLASS = 0xFFFF; - const pj_uint16_t PJ_SO_TYPE = SO_TYPE; - const pj_uint16_t PJ_SO_RCVBUF = SO_RCVBUF; - const pj_uint16_t PJ_SO_SNDBUF = SO_SNDBUF; -+const pj_uint16_t PJ_SO_KEEPALIVE = SO_KEEPALIVE; - const pj_uint16_t PJ_TCP_NODELAY= TCP_NODELAY; -+#if !defined(PJ_WIN32) && !defined(PJ_WIN64) -+# ifdef TCP_KEEPIDLE -+const pj_uint16_t PJ_TCP_KEEPIDLE = TCP_KEEPIDLE; -+# endif -+# ifdef TCP_KEEPINTVL -+const pj_uint16_t PJ_TCP_KEEPINTVL = TCP_KEEPINTVL; -+# endif -+# ifdef TCP_KEEPCNT -+const pj_uint16_t PJ_TCP_KEEPCNT = TCP_KEEPCNT; -+# endif -+#endif - const pj_uint16_t PJ_SO_REUSEADDR= SO_REUSEADDR; - #ifdef SO_NOSIGPIPE - const pj_uint16_t PJ_SO_NOSIGPIPE = SO_NOSIGPIPE; -@@ -517,6 +538,20 @@ PJ_DEF(pj_status_t) pj_sock_socket(int af, - if (rc==SOCKET_ERROR) { - // Ignored.. - } -+ } else if(type == pj_SOCK_STREAM()) { -+#ifndef SIO_KEEPALIVE_VALS -+# define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR, 4) -+#endif -+ DWORD dwBytesReturned = 0; -+ struct tcp_keepalive { -+ ULONG onoff; -+ ULONG keepalivetime; -+ ULONG keepaliveinterval; -+ } vals = { TRUE, 30000, 30000 }; -+ WSAIoctl(*sock, SIO_KEEPALIVE_VALS, -+ &vals, sizeof(vals), -+ NULL, 0, &dwBytesReturned, -+ NULL, NULL); - } - #endif - -@@ -548,6 +583,16 @@ PJ_DEF(pj_status_t) pj_sock_socket(int af, - if (type == pj_SOCK_STREAM()) { - pj_sock_setsockopt(*sock, pj_SOL_SOCKET(), pj_SO_NOSIGPIPE(), - &val, sizeof(val)); -+ pj_sock_setsockopt(*sock, pj_SOL_SOCKET(), pj_SO_KEEPALIVE(), -+ &val, sizeof(val)); -+ pj_sock_setsockopt(*sock, pj_SOL_TCP(), pj_TCP_KEEPCNT(), -+ &val, sizeof(val)); -+ val = 30; -+ pj_sock_setsockopt(*sock, pj_SOL_TCP(), pj_TCP_KEEPIDLE(), -+ &val, sizeof(val)); -+ pj_sock_setsockopt(*sock, pj_SOL_TCP(), pj_TCP_KEEPINTVL(), -+ &val, sizeof(val)); -+ val = 1; - } - #if defined(PJ_SOCK_HAS_IPV6_V6ONLY) && PJ_SOCK_HAS_IPV6_V6ONLY != 0 - if (af == PJ_AF_INET6) { -diff --git a/pjlib/src/pj/sock_common.c b/pjlib/src/pj/sock_common.c -index 96cd6b540..671d63f4a 100644 ---- a/pjlib/src/pj/sock_common.c -+++ b/pjlib/src/pj/sock_common.c -@@ -1346,11 +1346,31 @@ PJ_DEF(pj_uint16_t) pj_SO_SNDBUF(void) - return PJ_SO_SNDBUF; - } - -+PJ_DEF(pj_uint16_t) pj_SO_KEEPALIVE(void) -+{ -+ return PJ_SO_KEEPALIVE; -+} -+ - PJ_DEF(pj_uint16_t) pj_TCP_NODELAY(void) - { - return PJ_TCP_NODELAY; - } - -+PJ_DEF(pj_uint16_t) pj_TCP_KEEPIDLE(void) -+{ -+ return PJ_TCP_KEEPIDLE -+} -+ -+PJ_DEF(pj_uint16_t) pj_TCP_KEEPINTVL(void) -+{ -+ return PJ_TCP_KEEPINTVL -+} -+ -+PJ_DEF(pj_uint16_t) pj_TCP_KEEPCNT(void) -+{ -+ return PJ_TCP_KEEPCNT -+} -+ - PJ_DEF(pj_uint16_t) pj_SO_REUSEADDR(void) - { - return PJ_SO_REUSEADDR; -diff --git a/pjlib/src/pj/sock_uwp.cpp b/pjlib/src/pj/sock_uwp.cpp -index 40250bf8d..148571aa8 100644 ---- a/pjlib/src/pj/sock_uwp.cpp -+++ b/pjlib/src/pj/sock_uwp.cpp -@@ -69,6 +69,24 @@ const pj_uint16_t PJ_SOL_IP = IPPROTO_IP; - const pj_uint16_t PJ_SOL_IP = 0; - #endif /* SOL_IP */ - -+#if defined(TCP_KEEPIDLE) -+const pj_uint16_t PJ_TCP_KEEPIDLE = TCP_KEEPIDLE; -+#else -+const pj_uint16_t PJ_TCP_KEEPIDLE = 4; -+#endif -+ -+#if defined(TCP_KEEPINTVL) -+const pj_uint16_t PJ_TCP_KEEPINTVL = TCP_KEEPINTVL; -+#else -+const pj_uint16_t PJ_TCP_KEEPINTVL = 5; -+#endif -+ -+#if defined(TCP_KEEPCNT) -+const pj_uint16_t PJ_TCP_KEEPCNT = TCP_KEEPCNT; -+#else -+const pj_uint16_t PJ_TCP_KEEPCNT = 6; -+#endif -+ - #if defined(SOL_TCP) - const pj_uint16_t PJ_SOL_TCP = SOL_TCP; - #elif defined(IPPROTO_TCP) -@@ -79,6 +97,12 @@ const pj_uint16_t PJ_SOL_TCP = IPPROTO_TCP; - const pj_uint16_t PJ_SOL_TCP = 6; - #endif /* SOL_TCP */ - -+#if defined(SOL_KEEPALIVE) -+const pj_uint16_t PJ_SOL_KEEPALIVE = SOL_KEEPALIVE; -+#else -+const pj_uint16_t PJ_SOL_KEEPALIVE = 9; -+#endif -+ - #ifdef SOL_UDP - const pj_uint16_t PJ_SOL_UDP = SOL_UDP; - #elif defined(IPPROTO_UDP) -diff --git a/pjlib/src/pj/symbols.c b/pjlib/src/pj/symbols.c -index ab83af956..966a9fc43 100644 ---- a/pjlib/src/pj/symbols.c -+++ b/pjlib/src/pj/symbols.c -@@ -259,6 +259,9 @@ PJ_EXPORT_SYMBOL(PJ_SOCK_RAW) - PJ_EXPORT_SYMBOL(PJ_SOCK_RDM) - PJ_EXPORT_SYMBOL(PJ_SOL_SOCKET) - PJ_EXPORT_SYMBOL(PJ_SOL_IP) -+PJ_EXPORT_SYMBOL(PJ_TCP_KEEPIDLE) -+PJ_EXPORT_SYMBOL(PJ_TCP_KEEPINTVL) -+PJ_EXPORT_SYMBOL(PJ_TCP_KEEPCNT) - PJ_EXPORT_SYMBOL(PJ_SOL_TCP) - PJ_EXPORT_SYMBOL(PJ_SOL_UDP) - PJ_EXPORT_SYMBOL(PJ_SOL_IPV6) -diff --git a/pjnath/include/pjnath/ice_session.h b/pjnath/include/pjnath/ice_session.h -index 5362c72e9..97069ed9e 100644 ---- a/pjnath/include/pjnath/ice_session.h -+++ b/pjnath/include/pjnath/ice_session.h -@@ -648,6 +648,11 @@ typedef struct pj_ice_sess_cb - pj_ice_sess_checklist *clist, - unsigned check_id); - -+ /** -+ * If an internal TCP keep alive, this mount the error to the application -+ */ -+ void (*on_ice_destroy)(pj_ice_sess *ice); -+ - } pj_ice_sess_cb; - - -diff --git a/pjnath/include/pjnath/ice_strans.h b/pjnath/include/pjnath/ice_strans.h -index 1c20729e8..1fed15f6f 100644 ---- a/pjnath/include/pjnath/ice_strans.h -+++ b/pjnath/include/pjnath/ice_strans.h -@@ -219,6 +219,13 @@ typedef struct pj_ice_strans_cb - const pj_ice_sess_cand *cand, - pj_bool_t end_of_cand); - -+ /** -+ * This callback is called if an internal operation fails -+ * -+ * @param ice_st The ICE stream transport. -+ */ -+ void (*on_destroy)(pj_ice_strans *ice_st); -+ - } pj_ice_strans_cb; - - -diff --git a/pjnath/src/pjnath/ice_session.c b/pjnath/src/pjnath/ice_session.c -index cc7e7d564..0b1c5fd56 100644 ---- a/pjnath/src/pjnath/ice_session.c -+++ b/pjnath/src/pjnath/ice_session.c -@@ -1534,6 +1534,12 @@ static void ice_keep_alive(pj_ice_sess *ice, pj_bool_t send_now) - PJ_FALSE, PJ_FALSE, - &the_check->rcand->addr, - addr_len, tdata); -+ if (status != PJ_SUCCESS && status != PJ_EPENDING && status != PJ_EBUSY) { -+ if (ice->cb.on_ice_destroy) { -+ ice->cb.on_ice_destroy(ice); -+ } -+ return; -+ } - - /* Restore FINGERPRINT usage */ - pj_stun_session_use_fingerprint(comp->stun_sess, saved); -diff --git a/pjnath/src/pjnath/ice_strans.c b/pjnath/src/pjnath/ice_strans.c -index 0fdd2c695..0bd8c6138 100644 ---- a/pjnath/src/pjnath/ice_strans.c -+++ b/pjnath/src/pjnath/ice_strans.c -@@ -99,6 +99,7 @@ static pj_uint16_t GETVAL16H(const pj_uint8_t *buf1, const pj_uint8_t *buf2) - - /* ICE callbacks */ - static void on_valid_pair(pj_ice_sess *ice); -+static void on_ice_destroy(pj_ice_sess *ice); - static void on_ice_complete(pj_ice_sess *ice, pj_status_t status); - static pj_status_t ice_tx_pkt(pj_ice_sess *ice, - unsigned comp_id, -@@ -1382,6 +1383,7 @@ PJ_DEF(pj_status_t) pj_ice_strans_init_ice(pj_ice_strans *ice_st, - ice_cb.wait_tcp_connection = &ice_wait_tcp_connection; - ice_cb.reconnect_tcp_connection = &ice_reconnect_tcp_connection; - ice_cb.close_tcp_connection = &ice_close_tcp_connection; -+ ice_cb.on_ice_destroy = &on_ice_destroy; - #endif - - /* Create! */ -@@ -2189,6 +2191,15 @@ static void on_valid_pair(pj_ice_sess *ice) - pj_grp_lock_dec_ref(ice_st->grp_lock); - } - -+static void on_ice_destroy(pj_ice_sess *ice) -+{ -+ pj_ice_strans *ice_st = (pj_ice_strans*)ice->user_data; -+ -+ if (ice_st->cb.on_destroy) { -+ (*ice_st->cb.on_destroy)(ice_st); -+ } -+} -+ - /* - * Callback called by ICE session when ICE processing is complete, either - * successfully or with failure. --- -2.25.1 - diff --git a/contrib/src/pjproject/0003-win-vs2017-props.patch b/contrib/src/pjproject/0003-win-vs2017-props.patch deleted file mode 100644 index c2a6d4439774ed558b0446de030325decec70090..0000000000000000000000000000000000000000 --- a/contrib/src/pjproject/0003-win-vs2017-props.patch +++ /dev/null @@ -1,56 +0,0 @@ -From e9c6d327b059866dbf02a3ffd1004bbc677b87db Mon Sep 17 00:00:00 2001 -From: jrun <darwinskernel@gmail.com> -Date: Thu, 27 Feb 2020 14:43:27 -0500 -Subject: [PATCH 3/3] win vs2017 props - ---- - build/vs/pjproject-vs14-common-config.props | 8 ++++---- - build/vs/pjproject-vs14-common-defaults.props | 2 +- - 2 files changed, 5 insertions(+), 5 deletions(-) - -diff --git a/build/vs/pjproject-vs14-common-config.props b/build/vs/pjproject-vs14-common-config.props -index de8848f..6aa0276 100644 ---- a/build/vs/pjproject-vs14-common-config.props -+++ b/build/vs/pjproject-vs14-common-config.props -@@ -18,22 +18,22 @@ - <PropertyGroup> - <API_Family Condition="'$(API_Family)'==''">WinDesktop</API_Family> - <PreprocessorDef></PreprocessorDef> -- <DefaultToolset>v140</DefaultToolset> -+ <DefaultToolset>v141</DefaultToolset> - </PropertyGroup> - <Choose> - <When Condition="'$(API_Family)'=='WinDesktop'"> - <PropertyGroup> -- <BuildToolset>v140</BuildToolset> -+ <BuildToolset>v141</BuildToolset> - <PreprocessorDef Condition="'$(Platform)'=='Win32'">WIN32;PJ_WIN32=1;PJ_M_I386=1;</PreprocessorDef> - <PreprocessorDef Condition="'$(Platform)'=='x64'">WIN64;PJ_WIN64=1;PJ_M_X86_64=1;</PreprocessorDef> - </PropertyGroup> - </When> - <When Condition="'$(API_Family)'=='UWP'"> - <PropertyGroup> -- <BuildToolset>v140</BuildToolset> -+ <BuildToolset>v141</BuildToolset> - <PreprocessorDef>PJ_WIN32_UWP;UNICODE;_UNICODE;</PreprocessorDef> - <PreprocessorDef Condition="'$(Platform)'=='ARM'">$(PreprocessorDef);PJ_M_ARMV7=1;</PreprocessorDef> -- <PlatformVersion>10.0.10586.0</PlatformVersion> -+ <PlatformVersion>10.0.16299.0</PlatformVersion> - <MinPlatformVersion>10.0.10240.0</MinPlatformVersion> - <AppTypeRev>10.0</AppTypeRev> - -diff --git a/build/vs/pjproject-vs14-common-defaults.props b/build/vs/pjproject-vs14-common-defaults.props -index 526f6c9..974447f 100644 ---- a/build/vs/pjproject-vs14-common-defaults.props -+++ b/build/vs/pjproject-vs14-common-defaults.props -@@ -3,7 +3,7 @@ - <ImportGroup Label="PropertySheets"> - </ImportGroup> - <PropertyGroup Label="UserMacros"> -- <VSVer>14</VSVer> -+ <VSVer>15</VSVer> - </PropertyGroup> - <PropertyGroup> - <_ProjectFileVersion>14.0.22823.1</_ProjectFileVersion> --- -2.25.4 diff --git a/contrib/src/pjproject/0004-multiple_listeners.patch b/contrib/src/pjproject/0004-multiple_listeners.patch deleted file mode 100644 index 406f28c570aed7f2423f4ec4c8897cd741793b66..0000000000000000000000000000000000000000 --- a/contrib/src/pjproject/0004-multiple_listeners.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 395a08ba6ebacf0e4039a73128fa147510f36f97 Mon Sep 17 00:00:00 2001 -From: jrun <darwinskernel@gmail.com> -Date: Thu, 20 Feb 2020 12:26:02 -0500 -Subject: [PATCH] multiple_listeners - ---- - pjsip/src/pjsip/sip_transport.c | 22 ++++++++++++++++++---- - 1 file changed, 18 insertions(+), 4 deletions(-) - -diff --git a/pjsip/src/pjsip/sip_transport.c b/pjsip/src/pjsip/sip_transport.c -index 7fac20f41..d5bd8fdda 100644 ---- a/pjsip/src/pjsip/sip_transport.c -+++ b/pjsip/src/pjsip/sip_transport.c -@@ -1488,10 +1488,16 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_register_tpfactory( pjsip_tpmgr *mgr, - /* Check that no same factory has been registered. */ - status = PJ_SUCCESS; - for (p=mgr->factory_list.next; p!=&mgr->factory_list; p=p->next) { -- if (p == tpf) { -- status = PJ_EEXISTS; -- break; -- } -+ if (p->type == tpf->type && -+ !pj_sockaddr_cmp(&tpf->local_addr, &p->local_addr)) -+ { -+ status = PJSIP_ETYPEEXISTS; -+ break; -+ } -+ if (p == tpf) { -+ status = PJ_EEXISTS; -+ break; -+ } - } - - if (status != PJ_SUCCESS) { -@@ -2467,6 +2473,14 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport2(pjsip_tpmgr *mgr, - - } else { - -+ /* Make sure we don't use another factory than the one given if -+ secure flag is set */ -+ if (flag & PJSIP_TRANSPORT_SECURE) { -+ TRACE_((THIS_FILE, "Can't create new TLS transport with no " -+ "provided suitable TLS listener.")); -+ return PJSIP_ETPNOTSUITABLE; -+ } -+ - /* Find factory with type matches the destination type */ - factory = mgr->factory_list.next; - while (factory != &mgr->factory_list) { --- -2.25.1 - diff --git a/contrib/src/pjproject/0005-fix_ebusy_turn.patch b/contrib/src/pjproject/0005-fix_ebusy_turn.patch deleted file mode 100644 index 0151aad5a2d57c86dd09c383ac71c19e9fbb0ec1..0000000000000000000000000000000000000000 --- a/contrib/src/pjproject/0005-fix_ebusy_turn.patch +++ /dev/null @@ -1,335 +0,0 @@ -From a9a8cc6b62dc08e34ed4f7893a822809dd051572 Mon Sep 17 00:00:00 2001 -From: jrun <darwinskernel@gmail.com> -Date: Wed, 19 Feb 2020 15:17:38 -0500 -Subject: [PATCH] fix_ebusy_turn - ---- - pjnath/include/pjnath/turn_session.h | 65 +++++++++++++++++++ - pjnath/include/pjnath/turn_sock.h | 27 ++++++++ - pjnath/src/pjnath/turn_session.c | 24 +++++-- - pjnath/src/pjnath/turn_sock.c | 96 ++++++++++++++++++++++++++++ - 4 files changed, 207 insertions(+), 5 deletions(-) - -diff --git a/pjnath/include/pjnath/turn_session.h b/pjnath/include/pjnath/turn_session.h -index 956f57bf0..f546d7e18 100644 ---- a/pjnath/include/pjnath/turn_session.h -+++ b/pjnath/include/pjnath/turn_session.h -@@ -254,6 +254,35 @@ typedef struct pj_turn_session_cb - const pj_sockaddr_t *dst_addr, - unsigned addr_len); - -+ /** -+ * This callback will be called by the TURN session whenever it -+ * needs to send outgoing message. Since the TURN session doesn't -+ * have a socket on its own, this callback must be implemented. -+ * -+ * The difference with on_send_pkt is that this function returns -+ * the size of the packet actually sent to predict when a busy will -+ * occurs. Indeed, activesock send the data asynchronously. When the -+ * data are actually sent, on_data_sent will be triggered. -+ * -+ * @param sess The TURN session. -+ * @param pkt The packet/data to be sent. -+ * @param pkt_len Length of the packet/data. -+ * @param dst_addr Destination address of the packet. -+ * @param addr_len Length of the destination address. -+ * @param send_size Length sent. -+ * @param original_size The length of the packet without the HEADER -+ * -+ * @return The callback should return the status of the -+ * send operation. -+ */ -+ pj_status_t (*on_send_pkt2)(pj_turn_session *sess, -+ const pj_uint8_t *pkt, -+ unsigned pkt_len, -+ const pj_sockaddr_t *dst_addr, -+ unsigned addr_len, -+ unsigned* sent_size, -+ unsigned original_size); -+ - /** - * This callback will be called by the TURN session whenever it - * needs to send outgoing STUN requests/messages for TURN signalling -@@ -798,6 +827,42 @@ PJ_DECL(pj_status_t) pj_turn_session_sendto(pj_turn_session *sess, - const pj_sockaddr_t *peer_addr, - unsigned addr_len); - -+/** -+ * Send a data to the specified peer address via the TURN relay. This -+ * function will encapsulate the data as STUN Send Indication or TURN -+ * ChannelData packet and send the message to the TURN server. The TURN -+ * server then will send the data to the peer. -+ * -+ * The allocation (pj_turn_session_alloc()) must have been successfully -+ * created before application can relay any data. -+ * -+ * Since TURN session is transport independent, this function will -+ * ultimately call \a on_send_pkt() callback to request the application -+ * to actually send the packet containing the data to the TURN server. -+ * -+ * The difference with pj_turn_session_sendto is that this function returns -+ * the size of the packet actually sent to predict when a busy will -+ * occurs. Indeed, activesock send the data asynchronously. When the -+ * data are actually sent, on_data_sent will be triggered. -+ * -+ * @param sess The TURN client session. -+ * @param pkt The data/packet to be sent to peer. -+ * @param pkt_len Length of the data. -+ * @param peer_addr The remote peer address (the ultimate destination -+ * of the data, and not the TURN server address). -+ * @param addr_len Length of the address. -+ * @param sent The size of the packet actually sent -+ * -+ * @return PJ_SUCCESS if the operation has been successful, -+ * or the appropriate error code on failure. -+ */ -+PJ_DECL(pj_status_t) pj_turn_session_sendto2(pj_turn_session *sess, -+ const pj_uint8_t *pkt, -+ unsigned pkt_len, -+ const pj_sockaddr_t *peer_addr, -+ unsigned addr_len, -+ unsigned *sent); -+ - /** - * Optionally establish channel binding for the specified a peer address. - * This function will assign a unique channel number for the peer address -diff --git a/pjnath/include/pjnath/turn_sock.h b/pjnath/include/pjnath/turn_sock.h -index 35388809f..05b5cafbe 100644 ---- a/pjnath/include/pjnath/turn_sock.h -+++ b/pjnath/include/pjnath/turn_sock.h -@@ -623,6 +623,33 @@ PJ_DECL(pj_status_t) pj_turn_sock_bind_channel(pj_turn_sock *turn_sock, - const pj_sockaddr_t *peer, - unsigned addr_len); - -+/** -+ * Send a data to the specified peer address via the TURN relay. This -+ * function will encapsulate the data as STUN Send Indication or TURN -+ * ChannelData packet and send the message to the TURN server. The TURN -+ * server then will send the data to the peer. -+ * -+ * The allocation (pj_turn_sock_alloc()) must have been successfully -+ * created before application can relay any data. -+ * -+ * @param turn_sock The TURN transport instance. -+ * @param pkt The data/packet to be sent to peer. -+ * @param pkt_len Length of the data. -+ * @param peer_addr The remote peer address (the ultimate destination -+ * of the data, and not the TURN server address). -+ * @param addr_len Length of the address. -+ * @param sent Size actually sent. -+ * -+ * @return PJ_SUCCESS if the operation has been successful, -+ * or the appropriate error code on failure. -+ */ -+PJ_DECL(pj_status_t) pj_turn_sock_sendto2(pj_turn_sock *turn_sock, -+ const pj_uint8_t *pkt, -+ unsigned pkt_len, -+ const pj_sockaddr_t *peer_addr, -+ unsigned addr_len, -+ unsigned* sent); -+ - /** - * Check if peer is a dataconn - * -diff --git a/pjnath/src/pjnath/turn_session.c b/pjnath/src/pjnath/turn_session.c -index 3a7df799a..374b70b59 100644 ---- a/pjnath/src/pjnath/turn_session.c -+++ b/pjnath/src/pjnath/turn_session.c -@@ -975,11 +975,23 @@ on_error: - /** - * Relay data to the specified peer through the session. - */ -+ - PJ_DEF(pj_status_t) pj_turn_session_sendto( pj_turn_session *sess, - const pj_uint8_t *pkt, - unsigned pkt_len, - const pj_sockaddr_t *addr, - unsigned addr_len) -+{ -+ unsigned sent; -+ return pj_turn_session_sendto2(sess, pkt, pkt_len, addr, addr_len, &sent); -+} -+ -+PJ_DEF(pj_status_t) pj_turn_session_sendto2(pj_turn_session *sess, -+ const pj_uint8_t *pkt, -+ unsigned pkt_len, -+ const pj_sockaddr_t *addr, -+ unsigned addr_len, -+ unsigned *sent) - { - struct ch_t *ch; - struct perm_t *perm; -@@ -1016,7 +1028,7 @@ PJ_DEF(pj_status_t) pj_turn_session_sendto( pj_turn_session *sess, - - /* If peer connection is TCP (RFC 6062), send it directly */ - if (sess->alloc_param.peer_conn_type == PJ_TURN_TP_TCP) { -- status = sess->cb.on_send_pkt(sess, pkt, pkt_len, addr, addr_len); -+ status = sess->cb.on_send_pkt2(sess, pkt, pkt_len, addr, addr_len, sent, pkt_len); - goto on_return; - } - -@@ -1044,9 +1056,10 @@ PJ_DEF(pj_status_t) pj_turn_session_sendto( pj_turn_session *sess, - - pj_assert(sess->srv_addr != NULL); - -- status = sess->cb.on_send_pkt(sess, sess->tx_pkt, total_len, -+ status = sess->cb.on_send_pkt2(sess, sess->tx_pkt, total_len, - sess->srv_addr, -- pj_sockaddr_get_len(sess->srv_addr)); -+ pj_sockaddr_get_len(sess->srv_addr), -+ sent, pkt_len); - - } else { - /* Use Send Indication. */ -@@ -1084,10 +1097,11 @@ PJ_DEF(pj_status_t) pj_turn_session_sendto( pj_turn_session *sess, - goto on_return; - - /* Send the Send Indication */ -- status = sess->cb.on_send_pkt(sess, sess->tx_pkt, -+ status = sess->cb.on_send_pkt2(sess, sess->tx_pkt, - (unsigned)send_ind_len, - sess->srv_addr, -- pj_sockaddr_get_len(sess->srv_addr)); -+ pj_sockaddr_get_len(sess->srv_addr), -+ sent, pkt_len); - } - - on_return: -diff --git a/pjnath/src/pjnath/turn_sock.c b/pjnath/src/pjnath/turn_sock.c -index 6de6ab1da..111b4f133 100644 ---- a/pjnath/src/pjnath/turn_sock.c -+++ b/pjnath/src/pjnath/turn_sock.c -@@ -100,6 +100,10 @@ struct pj_turn_sock - /* Data connection, when peer_conn_type==PJ_TURN_TP_TCP (RFC 6062) */ - unsigned data_conn_cnt; - tcp_data_conn_t data_conn[PJ_TURN_MAX_TCP_CONN_CNT]; -+ -+ /* The following variables are used by the on_data_sent callback */ -+ unsigned current_pkt_len; -+ unsigned current_body_len; - }; - - -@@ -116,6 +120,13 @@ static pj_status_t turn_on_stun_send_pkt(pj_turn_session *sess, - unsigned pkt_len, - const pj_sockaddr_t *dst_addr, - unsigned dst_addr_len); -+static pj_status_t turn_on_send_pkt2(pj_turn_session *sess, -+ const pj_uint8_t *pkt, -+ unsigned pkt_len, -+ const pj_sockaddr_t *dst_addr, -+ unsigned dst_addr_len, -+ unsigned *sent, -+ unsigned body_len); - static void turn_on_channel_bound(pj_turn_session *sess, - const pj_sockaddr_t *peer_addr, - unsigned addr_len, -@@ -345,6 +356,7 @@ PJ_DEF(pj_status_t) pj_turn_sock_create(pj_stun_config *cfg, - pj_bzero(&sess_cb, sizeof(sess_cb)); - sess_cb.on_send_pkt = &turn_on_send_pkt; - sess_cb.on_stun_send_pkt = &turn_on_stun_send_pkt; -+ sess_cb.on_send_pkt2 = &turn_on_send_pkt2; - sess_cb.on_channel_bound = &turn_on_channel_bound; - sess_cb.on_rx_data = &turn_on_rx_data; - sess_cb.on_state = &turn_on_state; -@@ -653,6 +665,22 @@ PJ_DEF(pj_status_t) pj_turn_sock_sendto( pj_turn_sock *turn_sock, - addr, addr_len); - } - -+PJ_DEF(pj_status_t) pj_turn_sock_sendto2( pj_turn_sock *turn_sock, -+ const pj_uint8_t *pkt, -+ unsigned pkt_len, -+ const pj_sockaddr_t *addr, -+ unsigned addr_len, -+ unsigned *sent) -+{ -+ PJ_ASSERT_RETURN(turn_sock && addr && addr_len, PJ_EINVAL); -+ -+ if (turn_sock->sess == NULL) -+ return PJ_EINVALIDOP; -+ -+ return pj_turn_session_sendto2(turn_sock->sess, pkt, pkt_len, -+ addr, addr_len, sent); -+} -+ - /* - * Bind a peer address to a channel number. - */ -@@ -1041,6 +1069,74 @@ static pj_status_t turn_on_send_pkt(pj_turn_session *sess, - dst_addr, dst_addr_len); - } - -+static pj_status_t turn_on_send_pkt2(pj_turn_session *sess, -+ const pj_uint8_t *pkt, -+ unsigned pkt_len, -+ const pj_sockaddr_t *dst_addr, -+ unsigned dst_addr_len, -+ unsigned *sent, -+ unsigned body_len) -+{ -+ *sent = pkt_len; -+ pj_turn_sock *turn_sock = (pj_turn_sock*)pj_turn_session_get_user_data(sess); -+ pj_status_t status = PJ_SUCCESS; -+ -+ pj_ssize_t len = pkt_len; -+ turn_sock->current_body_len = body_len; -+ turn_sock->current_pkt_len = pkt_len; -+ -+ if (turn_sock == NULL || turn_sock->is_destroying) { -+ /* We've been destroyed */ -+ // https://trac.pjsip.org/repos/ticket/1316 -+ //pj_assert(!"We should shutdown gracefully"); -+ return PJ_EINVALIDOP; -+ } -+ -+ if (turn_sock->conn_type == PJ_TURN_TP_UDP) { -+ status = pj_activesock_sendto(turn_sock->active_sock, -+ &turn_sock->send_key, pkt, &len, 0, -+ dst_addr, dst_addr_len); -+ } else if (turn_sock->alloc_param.peer_conn_type == PJ_TURN_TP_TCP) { -+ pj_turn_session_info info; -+ pj_turn_session_get_info(turn_sock->sess, &info); -+ if (pj_sockaddr_cmp(&info.server, dst_addr) == 0) { -+ /* Destination address is TURN server */ -+ status = pj_activesock_send(turn_sock->active_sock, -+ &turn_sock->send_key, pkt, &len, 0); -+ } else { -+ /* Destination address is peer, lookup data connection */ -+ unsigned i; -+ -+ status = PJ_ENOTFOUND; -+ for (i=0; i < PJ_TURN_MAX_TCP_CONN_CNT; ++i) { -+ tcp_data_conn_t *conn = &turn_sock->data_conn[i]; -+ if (conn->state < DATACONN_STATE_CONN_BINDING) -+ continue; -+ if (pj_sockaddr_cmp(&conn->peer_addr, dst_addr) == 0) { -+ status = pj_activesock_send(conn->asock, -+ &conn->send_key, -+ pkt, &len, 0); -+ break; -+ } -+ } -+ } -+ } else { -+ status = pj_activesock_send(turn_sock->active_sock, -+ &turn_sock->send_key, pkt, &len, 0); -+ } -+ -+ if (status != PJ_SUCCESS && status != PJ_EPENDING) { -+ show_err(turn_sock, "socket send()", status); -+ } -+ -+ // Remove header from sent size. -+ // The application only wants to know if the packet is actually sent. -+ unsigned header_len = pkt_len - body_len; -+ *sent = (len > header_len)? (len - header_len) : 0; -+ -+ return status; -+ } -+ - static pj_status_t turn_on_stun_send_pkt(pj_turn_session *sess, - const pj_uint8_t *pkt, - unsigned pkt_len, --- -2.25.1 - diff --git a/contrib/src/pjproject/0006-ignore_ipv6_on_transport_check.patch b/contrib/src/pjproject/0006-ignore_ipv6_on_transport_check.patch deleted file mode 100644 index f03e9f174f23be44906054ba83322f3566303e81..0000000000000000000000000000000000000000 --- a/contrib/src/pjproject/0006-ignore_ipv6_on_transport_check.patch +++ /dev/null @@ -1,27 +0,0 @@ -From d8cbda261c7cebec8251742b1e383b69614951c5 Mon Sep 17 00:00:00 2001 -From: jrun <darwinskernel@gmail.com> -Date: Thu, 20 Feb 2020 13:37:23 -0500 -Subject: [PATCH] ignore_ipv6_on_transport_check - ---- - pjsip/src/pjsip/sip_transport.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/pjsip/src/pjsip/sip_transport.c b/pjsip/src/pjsip/sip_transport.c -index d5bd8fdda..e168f14bc 100644 ---- a/pjsip/src/pjsip/sip_transport.c -+++ b/pjsip/src/pjsip/sip_transport.c -@@ -2269,7 +2269,10 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport2(pjsip_tpmgr *mgr, - pjsip_transport *seltp = sel->u.transport; - - /* See if the transport is (not) suitable */ -- if (seltp->key.type != type) { -+ pjsip_transport_type_e type_no_ipv6 = type % PJSIP_TRANSPORT_IPV6; -+ pjsip_transport_type_e key_type_no_ipv6 = seltp->key.type % -+ PJSIP_TRANSPORT_IPV6; -+ if (type_no_ipv6 != key_type_no_ipv6) { - pj_lock_release(mgr->lock); - TRACE_((THIS_FILE, "Transport type in tpsel not matched")); - return PJSIP_ETPNOTSUITABLE; --- -2.30.2 diff --git a/contrib/src/pjproject/0007-upnp-srflx-nat-assisted-cand.patch b/contrib/src/pjproject/0007-upnp-srflx-nat-assisted-cand.patch deleted file mode 100644 index c3faa6b382c44093c0313c3a35342700fbd6d1fb..0000000000000000000000000000000000000000 --- a/contrib/src/pjproject/0007-upnp-srflx-nat-assisted-cand.patch +++ /dev/null @@ -1,256 +0,0 @@ - pjnath/include/pjnath/config.h | 2 +- - pjnath/include/pjnath/stun_sock.h | 22 ++++ - pjnath/src/pjnath/ice_strans.c | 171 +++++++++++++++++++++++++++--- - pjnath/src/pjnath/stun_sock.c | 1 + - 4 files changed, 181 insertions(+), 15 deletions(-) - -diff --git a/pjnath/include/pjnath/config.h b/pjnath/include/pjnath/config.h -index 3e7c6ae3a..89b421c51 100644 ---- a/pjnath/include/pjnath/config.h -+++ b/pjnath/include/pjnath/config.h -@@ -279,7 +279,7 @@ - * the maximum number of components (PJ_ICE_MAX_COMP) value. - */ - #ifndef PJ_ICE_COMP_BITS --# define PJ_ICE_COMP_BITS 1 -+# define PJ_ICE_COMP_BITS 2 - #endif - - -diff --git a/pjnath/include/pjnath/stun_sock.h b/pjnath/include/pjnath/stun_sock.h -index 51f60cc03..ba74cc6a5 100644 ---- a/pjnath/include/pjnath/stun_sock.h -+++ b/pjnath/include/pjnath/stun_sock.h -@@ -276,6 +276,28 @@ typedef struct pj_stun_sock_cfg - */ - pj_sockaddr bound_addr; - -+ /** -+ * This member holds a list of address mappings (internal/external) that -+ * the user (application) provides. These mappings are meant to be used -+ * to add server reflexive candidates that are not typically discovered -+ * by regular ICE operations. This is the case for mappings obtained -+ * through UPNP-IGD/NAT-PMP/PCP requests, or manually configured (port -+ * forward). -+ */ -+ struct { -+ pj_sockaddr local_addr; -+ pj_sockaddr mapped_addr; -+ int tp_type; -+ } user_mapping[PJ_ICE_MAX_COMP]; -+ -+ /** -+ * Holds the actual number of allocated ports. If the feature is used, -+ * this value should match the number of components of the ICE session. -+ * The feature is disabled if this variable is set to 0. -+ * Default value is 0. -+ */ -+ unsigned user_mapping_cnt; -+ - /** - * Specify the port range for STUN socket binding, relative to the start - * port number specified in \a bound_addr. Note that this setting is only -diff --git a/pjnath/src/pjnath/ice_strans.c b/pjnath/src/pjnath/ice_strans.c -index 0bd8c6138..d54eb4bf1 100644 ---- a/pjnath/src/pjnath/ice_strans.c -+++ b/pjnath/src/pjnath/ice_strans.c -@@ -551,6 +551,136 @@ static pj_bool_t ice_cand_equals(pj_ice_sess_cand *lcand, - return PJ_TRUE; - } - -+static pj_status_t add_nat_assisted_cand(pj_ice_strans *ice_st, -+ pj_ice_strans_comp *comp, -+ unsigned idx, -+ unsigned max_cand_cnt) -+{ -+ /* PJNATH library handles host and srflx connections through STUN -+ * sockets, even if there is no actual STUN server configured (for host -+ * only candidates). Since NAT-assisted candidates are srflx candidates, -+ * they will be handled through STUN sockets as well. -+ * NAT-assisted candidates are provided as a STUN configuration (as an -+ * entry in the stun_tp list). The position (index) of the config in the -+ * list is used to calculate the "local preference" of the priority, thus -+ * it will determine the priority of the NAT-assisted candidates relative -+ * to other srflx candidates. -+ */ -+ -+ pj_ice_sess_cand *cand; -+ pj_ice_strans_stun_cfg *nat_cfg = &ice_st->cfg.stun_tp[idx]; -+ pj_stun_sock_cfg *sock_cfg = &nat_cfg->cfg; -+ unsigned comp_idx = comp->comp_id - 1; -+ pj_stun_sock_cb sock_cb; -+ sock_user_data *data; -+ pj_status_t status; -+ -+ PJ_ASSERT_RETURN(max_cand_cnt > 0, PJ_ETOOSMALL); -+ PJ_ASSERT_RETURN(nat_cfg->cfg.user_mapping_cnt > comp_idx, PJ_ETOOSMALL); -+ -+ pj_sockaddr *laddr = &nat_cfg->cfg.user_mapping[comp_idx].local_addr; -+ pj_sockaddr *maddr = &nat_cfg->cfg.user_mapping[comp_idx].mapped_addr; -+ -+ pj_bzero(&sock_cb, sizeof(sock_cb)); -+ sock_cb.on_rx_data = &stun_on_rx_data; -+ sock_cb.on_status = &stun_on_status; -+ sock_cb.on_data_sent = &stun_on_data_sent; -+ -+ /* Override component specific QoS settings, if any */ -+ if (ice_st->cfg.comp[comp_idx].qos_type) { -+ sock_cfg->qos_type = ice_st->cfg.comp[comp_idx].qos_type; -+ } -+ if (ice_st->cfg.comp[comp_idx].qos_params.flags) { -+ pj_memcpy(&sock_cfg->qos_params, -+ &ice_st->cfg.comp[comp_idx].qos_params, -+ sizeof(sock_cfg->qos_params)); -+ } -+ -+ /* Override component specific socket buffer size settings, if any */ -+ if (ice_st->cfg.comp[comp_idx].so_rcvbuf_size > 0) { -+ sock_cfg->so_rcvbuf_size = ice_st->cfg.comp[comp_idx].so_rcvbuf_size; -+ } -+ if (ice_st->cfg.comp[comp_idx].so_sndbuf_size > 0) { -+ sock_cfg->so_sndbuf_size = ice_st->cfg.comp[comp_idx].so_sndbuf_size; -+ } -+ -+ /* Setup srflx candidate*/ -+ cand = &comp->cand_list[comp->cand_cnt]; -+ cand->type = PJ_ICE_CAND_TYPE_SRFLX; -+ /* User candidates are assumed ready */ -+ cand->status = PJ_SUCCESS; -+ cand->local_pref = (pj_uint16_t)(SRFLX_PREF - idx); -+ cand->transport_id = CREATE_TP_ID(TP_STUN, idx); -+ cand->comp_id = (pj_uint8_t) comp->comp_id; -+ cand->transport = nat_cfg->cfg.user_mapping[comp_idx].tp_type; -+ -+ /* Set the user mappings if availlabe. */ -+ pj_sockaddr_cp(&sock_cfg->bound_addr, laddr); -+ -+ { -+ char localStr[PJ_INET6_ADDRSTRLEN+8]; -+ char mappedStr[PJ_INET6_ADDRSTRLEN+8]; -+ PJ_LOG(5,(ice_st->obj_name, "Setting user mapping %s -> %s [%s (%i)] for comp %u at config index %i", -+ pj_sockaddr_print(laddr, localStr, sizeof(localStr), 3), -+ pj_sockaddr_print(maddr, mappedStr, sizeof(mappedStr), 3), -+ nat_cfg->conn_type == PJ_STUN_TP_UDP?"UDP":"TCP", -+ nat_cfg->conn_type, -+ comp->comp_id, idx)); -+ } -+ -+ /* Allocate and initialize STUN socket data */ -+ data = PJ_POOL_ZALLOC_T(ice_st->pool, sock_user_data); -+ data->comp = comp; -+ data->transport_id = cand->transport_id; -+ -+ /* Create the STUN transport */ -+ status = pj_stun_sock_create(&ice_st->cfg.stun_cfg, NULL, -+ nat_cfg->af, nat_cfg->conn_type, -+ &sock_cb, sock_cfg, data, -+ &comp->stun[idx].sock); -+ if (status != PJ_SUCCESS) -+ return status; -+ -+ /* Update and commit NAT-assisted candidate. */ -+ pj_sockaddr_cp(&cand->addr, maddr); -+ pj_sockaddr_cp(&cand->base_addr, laddr); -+ pj_sockaddr_cp(&cand->rel_addr, &cand->base_addr); -+ pj_ice_calc_foundation(ice_st->pool, &cand->foundation, -+ cand->type, &cand->base_addr); -+ comp->cand_cnt++; -+ max_cand_cnt--; -+ -+ // Check if we already have a matching host candidate for -+ // this srflx candidate -+ -+ /* Find the base for this candidate */ -+ unsigned j=0; -+ for (; j<comp->cand_cnt; j++) { -+ pj_ice_sess_cand *host = &comp->cand_list[j]; -+ -+ if (host->type != PJ_ICE_CAND_TYPE_HOST) -+ continue; -+ -+ if (pj_sockaddr_cmp(&cand->base_addr, &host->addr) == 0) { -+ /* Found a matching host cadidate */ -+ break; -+ } -+ } -+ -+ /* Add local address as a host candidate if not already present. */ -+ if (j == comp->cand_cnt && nat_cfg->max_host_cands) { -+ pj_stun_sock_info stun_sock_info; -+ pj_memset(&stun_sock_info, 0, sizeof(stun_sock_info)); -+ stun_sock_info.alias_cnt = 1; -+ pj_sockaddr_cp(&stun_sock_info.aliases[0], laddr); -+ unsigned cand_cnt = 0; -+ status = add_local_candidate(cand, idx, 0, &cand_cnt, &max_cand_cnt, -+ stun_sock_info, ice_st, comp, cand->transport); -+ } -+ -+ return status; -+} -+ - static pj_status_t add_stun_and_host(pj_ice_strans *ice_st, - pj_ice_strans_comp *comp, - unsigned idx, -@@ -875,20 +1005,33 @@ static pj_status_t create_comp(pj_ice_strans *ice_st, unsigned comp_id) - - /* Create STUN transport if configured */ - for (i=0; i<ice_st->cfg.stun_tp_cnt; ++i) { -- unsigned max_cand_cnt = PJ_ICE_ST_MAX_CAND - comp->cand_cnt - -- ice_st->cfg.turn_tp_cnt; -- -- status = PJ_ETOOSMALL; -- -- if ((max_cand_cnt > 0) && (max_cand_cnt <= PJ_ICE_ST_MAX_CAND)) -- status = add_stun_and_host(ice_st, comp, i, max_cand_cnt); -- -- if (status != PJ_SUCCESS) { -- PJ_PERROR(3,(ice_st->obj_name, status, -- "Failed creating STUN transport #%d for comp %d", -- i, comp->comp_id)); -- //return status; -- } -+ unsigned max_cand_cnt = PJ_ICE_ST_MAX_CAND - comp->cand_cnt - -+ ice_st->cfg.turn_tp_cnt; -+ -+ status = PJ_ETOOSMALL; -+ -+ if ((max_cand_cnt > 0) && (max_cand_cnt <= PJ_ICE_ST_MAX_CAND)) { -+ // Set custom mapping (nat) if provided by the user. -+ if (ice_st->cfg.stun_tp[i].cfg.user_mapping_cnt > 0) { -+ status = add_nat_assisted_cand(ice_st, comp, i, max_cand_cnt); -+ if (status != PJ_SUCCESS) -+ PJ_PERROR(3,(ice_st->obj_name, status, -+ "Failed to add NAT-assisted candidate at config #%d for comp %d", -+ i, comp->comp_id)); -+ } else { -+ status = add_stun_and_host(ice_st, comp, i, max_cand_cnt); -+ if (status != PJ_SUCCESS) -+ PJ_PERROR(3,(ice_st->obj_name, status, -+ "Failed creating STUN transport #%d for comp %d", -+ i, comp->comp_id)); -+ } -+ } else { -+ // All STUN config slots have been used. -+ if (status != PJ_SUCCESS) -+ PJ_PERROR(3,(ice_st->obj_name, status, -+ "Max STUN config (%d) has been reached for comp %d", -+ PJ_ICE_ST_MAX_CAND, comp->comp_id)); -+ } - } - - /* Create TURN relay if configured. */ -diff --git a/pjnath/src/pjnath/stun_sock.c b/pjnath/src/pjnath/stun_sock.c -index 6d2602552..b7643ca79 100644 ---- a/pjnath/src/pjnath/stun_sock.c -+++ b/pjnath/src/pjnath/stun_sock.c -@@ -217,6 +217,7 @@ PJ_DEF(void) pj_stun_sock_cfg_default(pj_stun_sock_cfg *cfg) - cfg->ka_interval = PJ_STUN_KEEP_ALIVE_SEC; - cfg->qos_type = PJ_QOS_TYPE_BEST_EFFORT; - cfg->qos_ignore_error = PJ_TRUE; -+ cfg->user_mapping_cnt = 0; - } - - --- -2.25.1 - diff --git a/contrib/src/pjproject/0008-fix_ioqueue_ipv6_sendto.patch b/contrib/src/pjproject/0008-fix_ioqueue_ipv6_sendto.patch deleted file mode 100644 index 5674ff09a10174046c7ca54cf6cd930356df2fc9..0000000000000000000000000000000000000000 --- a/contrib/src/pjproject/0008-fix_ioqueue_ipv6_sendto.patch +++ /dev/null @@ -1,85 +0,0 @@ -From 52f0c422e41ace1f2b682adbbaf67c4ddb0d17ed Mon Sep 17 00:00:00 2001 -From: jrun <darwinskernel@gmail.com> -Date: Thu, 20 Feb 2020 12:39:23 -0500 -Subject: [PATCH] fix_ioqueue_ipv6_sendto - ---- - pjlib/src/pj/ioqueue_common_abs.c | 5 ++++- - pjlib/src/pj/ioqueue_common_abs.h | 17 ++++++++--------- - 2 files changed, 12 insertions(+), 10 deletions(-) - -diff --git a/pjlib/src/pj/ioqueue_common_abs.c b/pjlib/src/pj/ioqueue_common_abs.c -index 0b0abedea..87afabc31 100644 ---- a/pjlib/src/pj/ioqueue_common_abs.c -+++ b/pjlib/src/pj/ioqueue_common_abs.c -@@ -1053,7 +1053,10 @@ retry_on_restart: - /* - * Check that address storage can hold the address parameter. - */ -- PJ_ASSERT_RETURN(addrlen <= (int)sizeof(pj_sockaddr_in), PJ_EBUG); -+ PJ_ASSERT_RETURN((((pj_sockaddr*)addr)->addr.sa_family == pj_AF_INET() && -+ addrlen <= (int)sizeof(pj_sockaddr_in)) || -+ (((pj_sockaddr*)addr)->addr.sa_family == pj_AF_INET6() && -+ addrlen <= (int)sizeof(pj_sockaddr_in6)), PJ_EBUG); - - /* - * Schedule asynchronous send. -diff --git a/pjlib/src/pj/ioqueue_common_abs.h b/pjlib/src/pj/ioqueue_common_abs.h -index d5e36b4d6..b1e9b2083 100644 ---- a/pjlib/src/pj/ioqueue_common_abs.h -+++ b/pjlib/src/pj/ioqueue_common_abs.h -@@ -1,5 +1,5 @@ - /* $Id */ --/* -+/* - * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) - * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org> - * -@@ -15,14 +15,14 @@ - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software -- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - /* ioqueue_common_abs.h - * -- * This file contains private declarations for abstracting various -- * event polling/dispatching mechanisms (e.g. select, poll, epoll) -- * to the ioqueue. -+ * This file contains private declarations for abstracting various -+ * event polling/dispatching mechanisms (e.g. select, poll, epoll) -+ * to the ioqueue. - */ - - #include <pj/list.h> -@@ -63,7 +63,7 @@ struct write_operation - pj_size_t size; - pj_ssize_t written; - unsigned flags; -- pj_sockaddr_in rmt_addr; -+ pj_sockaddr rmt_addr; - int rmt_addrlen; - }; - -@@ -93,7 +93,7 @@ union operation_key - unsigned ref_count; \ - pj_bool_t closing; \ - pj_time_val free_time; \ -- -+ - #else - # define UNREG_FIELDS - #endif -@@ -135,6 +135,5 @@ static void ioqueue_add_to_set( pj_ioqueue_t *ioqueue, - pj_ioqueue_key_t *key, - enum ioqueue_event_type event_type ); - static void ioqueue_remove_from_set( pj_ioqueue_t *ioqueue, -- pj_ioqueue_key_t *key, -+ pj_ioqueue_key_t *key, - enum ioqueue_event_type event_type); -- --- -2.25.1 - diff --git a/contrib/src/pjproject/0010-fix-tcp-death-detection.patch b/contrib/src/pjproject/0010-fix-tcp-death-detection.patch deleted file mode 100644 index 347aacdd7bc39ae260f793b7f8463d94d2bd33f3..0000000000000000000000000000000000000000 --- a/contrib/src/pjproject/0010-fix-tcp-death-detection.patch +++ /dev/null @@ -1,115 +0,0 @@ - pjlib/include/pj/sock.h | 7 +++++++ - pjlib/src/pj/sock_bsd.c | 9 +++++++++ - pjlib/src/pj/sock_common.c | 5 +++++ - pjlib/src/pj/sock_uwp.cpp | 6 ++++++ - pjlib/src/pj/symbols.c | 1 + - 5 files changed, 28 insertions(+) - -diff --git a/pjlib/include/pj/sock.h b/pjlib/include/pj/sock.h -index 7542045b1..3a3154db4 100644 ---- a/pjlib/include/pj/sock.h -+++ b/pjlib/include/pj/sock.h -@@ -318,6 +318,7 @@ extern const pj_uint16_t PJ_SO_KEEPALIVE; - extern const pj_uint16_t PJ_TCP_KEEPIDLE; - extern const pj_uint16_t PJ_TCP_KEEPINTVL; - extern const pj_uint16_t PJ_TCP_KEEPCNT; -+extern const pj_uint16_t PJ_TCP_USER_TIMEOUT; - - /** Set the protocol-defined priority for all packets to be sent on socket. - */ -@@ -361,6 +362,9 @@ extern const pj_uint16_t PJ_IP_DROP_MEMBERSHIP; - /** Get #PJ_TCP_KEEPINTVL constant */ - # define pj_TCP_KEEPINTVL() PJ_TCP_KEEPINTVL(void); - -+ /** Get #PJ_TCP_USER_TIMEOUT constant */ -+ PJ_DECL(pj_uint16_t) PJ_TCP_USER_TIMEOUT(void); -+ - /** Get #PJ_TCP_KEEPCNT constant */ - # define pj_TCP_KEEPCNT() PJ_TCP_KEEPCNT(void); - -@@ -406,6 +410,9 @@ extern const pj_uint16_t PJ_IP_DROP_MEMBERSHIP; - /** Get #PJ_TCP_KEEPIDLE constant */ - # define pj_TCP_KEEPIDLE() PJ_TCP_KEEPIDLE - -+ /** Get #PJ_TCP_USER_TIMEOUT constant */ -+# define pj_TCP_USER_TIMEOUT() PJ_TCP_USER_TIMEOUT -+ - /** Get #PJ_TCP_KEEPINTVL constant */ - # define pj_TCP_KEEPINTVL() PJ_TCP_KEEPINTVL - -diff --git a/pjlib/src/pj/sock_bsd.c b/pjlib/src/pj/sock_bsd.c -index f9e8ffa82..a27fce775 100644 ---- a/pjlib/src/pj/sock_bsd.c -+++ b/pjlib/src/pj/sock_bsd.c -@@ -162,6 +162,11 @@ const pj_uint16_t PJ_TCP_KEEPIDLE = TCP_KEEPIDLE; - # ifdef TCP_KEEPINTVL - const pj_uint16_t PJ_TCP_KEEPINTVL = TCP_KEEPINTVL; - # endif -+# ifdef TCP_USER_TIMEOUT -+const pj_uint16_t PJ_TCP_USER_TIMEOUT = TCP_USER_TIMEOUT; -+#else -+const pj_uint16_t PJ_TCP_USER_TIMEOUT = 18; -+# endif - # ifdef TCP_KEEPCNT - const pj_uint16_t PJ_TCP_KEEPCNT = TCP_KEEPCNT; - # endif -@@ -592,7 +597,11 @@ PJ_DEF(pj_status_t) pj_sock_socket(int af, - &val, sizeof(val)); - pj_sock_setsockopt(*sock, pj_SOL_TCP(), pj_TCP_KEEPINTVL(), - &val, sizeof(val)); -+ val = 30000; -+ pj_sock_setsockopt(*sock, pj_SOL_TCP(), pj_TCP_USER_TIMEOUT(), -+ &val, sizeof(val)); - val = 1; -+ - } - #if defined(PJ_SOCK_HAS_IPV6_V6ONLY) && PJ_SOCK_HAS_IPV6_V6ONLY != 0 - if (af == PJ_AF_INET6) { -diff --git a/pjlib/src/pj/sock_common.c b/pjlib/src/pj/sock_common.c -index 671d63f4a..3cdfc8503 100644 ---- a/pjlib/src/pj/sock_common.c -+++ b/pjlib/src/pj/sock_common.c -@@ -1351,6 +1351,11 @@ PJ_DEF(pj_uint16_t) pj_SO_KEEPALIVE(void) - return PJ_SO_KEEPALIVE; - } - -+PJ_DEF(pj_uint16_t) pj_TCP_USER_TIMEOUT(void) -+{ -+ return PJ_TCP_USER_TIMEOUT; -+} -+ - PJ_DEF(pj_uint16_t) pj_TCP_NODELAY(void) - { - return PJ_TCP_NODELAY; -diff --git a/pjlib/src/pj/sock_uwp.cpp b/pjlib/src/pj/sock_uwp.cpp -index 148571aa8..f1d92d093 100644 ---- a/pjlib/src/pj/sock_uwp.cpp -+++ b/pjlib/src/pj/sock_uwp.cpp -@@ -97,6 +97,12 @@ const pj_uint16_t PJ_SOL_TCP = IPPROTO_TCP; - const pj_uint16_t PJ_SOL_TCP = 6; - #endif /* SOL_TCP */ - -+#if defined(TCP_USER_TIMEOUT) -+const pj_uint16_t PJ_TCP_USER_TIMEOUT = TCP_USER_TIMEOUT; -+#else -+const pj_uint16_t PJ_TCP_USER_TIMEOUT = 18; -+#endif -+ - #if defined(SOL_KEEPALIVE) - const pj_uint16_t PJ_SOL_KEEPALIVE = SOL_KEEPALIVE; - #else -diff --git a/pjlib/src/pj/symbols.c b/pjlib/src/pj/symbols.c -index 966a9fc43..c71e49da4 100644 ---- a/pjlib/src/pj/symbols.c -+++ b/pjlib/src/pj/symbols.c -@@ -262,6 +262,7 @@ PJ_EXPORT_SYMBOL(PJ_SOL_IP) - PJ_EXPORT_SYMBOL(PJ_TCP_KEEPIDLE) - PJ_EXPORT_SYMBOL(PJ_TCP_KEEPINTVL) - PJ_EXPORT_SYMBOL(PJ_TCP_KEEPCNT) -+PJ_EXPORT_SYMBOL(PJ_TCP_USER_TIMEOUT) - PJ_EXPORT_SYMBOL(PJ_SOL_TCP) - PJ_EXPORT_SYMBOL(PJ_SOL_UDP) - PJ_EXPORT_SYMBOL(PJ_SOL_IPV6) --- -2.25.1 - diff --git a/contrib/src/pjproject/0011-fix-turn-shutdown-crash.patch b/contrib/src/pjproject/0011-fix-turn-shutdown-crash.patch deleted file mode 100644 index d0401ff50b720166b7c6662a5e691d4b9bf701f5..0000000000000000000000000000000000000000 --- a/contrib/src/pjproject/0011-fix-turn-shutdown-crash.patch +++ /dev/null @@ -1,20 +0,0 @@ - pjnath/src/pjnath/turn_sock.c | 3 --- - 1 file changed, 3 deletions(-) - -diff --git a/pjnath/src/pjnath/turn_sock.c b/pjnath/src/pjnath/turn_sock.c -index 111b4f133..8e576e031 100644 ---- a/pjnath/src/pjnath/turn_sock.c -+++ b/pjnath/src/pjnath/turn_sock.c -@@ -1492,9 +1492,6 @@ static void turn_on_state(pj_turn_session *sess, - if (new_state >= PJ_TURN_STATE_DESTROYING && turn_sock->sess) { - pj_time_val delay = {0, 0}; - -- turn_sock->sess = NULL; -- pj_turn_session_set_user_data(sess, NULL); -- - pj_timer_heap_cancel_if_active(turn_sock->cfg.timer_heap, - &turn_sock->timer, 0); - pj_timer_heap_schedule_w_grp_lock(turn_sock->cfg.timer_heap, --- -2.25.1 - diff --git a/contrib/src/pjproject/0012-ignore-down-interfaces.patch b/contrib/src/pjproject/0012-ignore-down-interfaces.patch deleted file mode 100644 index 8dd5f1ed74b45ab9b6f52081b984acbe5a76c832..0000000000000000000000000000000000000000 --- a/contrib/src/pjproject/0012-ignore-down-interfaces.patch +++ /dev/null @@ -1,46 +0,0 @@ - pjlib/src/pj/ip_helper_generic.c | 15 +++++++++++++++ - 1 file changed, 15 insertions(+) - -diff --git a/pjlib/src/pj/ip_helper_generic.c b/pjlib/src/pj/ip_helper_generic.c -index d7bbf725e..2a392d16b 100644 ---- a/pjlib/src/pj/ip_helper_generic.c -+++ b/pjlib/src/pj/ip_helper_generic.c -@@ -97,6 +97,11 @@ static pj_status_t if_enum_by_af(int af, - continue; /* Skip when interface is down */ - } - -+ if ((it->ifa_flags & IFF_RUNNING)==0) { -+ TRACE_((THIS_FILE, " interface is not running")); -+ continue; /* Skip when interface is not running */ -+ } -+ - #if PJ_IP_HELPER_IGNORE_LOOPBACK_IF - if (it->ifa_flags & IFF_LOOPBACK) { - TRACE_((THIS_FILE, " loopback interface")); -@@ -208,6 +213,11 @@ static pj_status_t if_enum_by_af(int af, - continue; /* Skip when interface is down */ - } - -+ if ((iff.ifr_flags & IFF_RUNNING)==0) { -+ TRACE_((THIS_FILE, " interface is not running")); -+ continue; /* Skip when interface is not running */ -+ } -+ - #if PJ_IP_HELPER_IGNORE_LOOPBACK_IF - if (iff.ifr_flags & IFF_LOOPBACK) { - TRACE_((THIS_FILE, " loopback interface")); -@@ -286,6 +296,11 @@ static pj_status_t if_enum_by_af(int af, unsigned *p_cnt, pj_sockaddr ifs[]) - continue; /* Skip when interface is down */ - } - -+ if ((ifreq.ifr_flags & IFF_RUNNING)==0) { -+ TRACE_((THIS_FILE, " interface is not running")); -+ continue; /* Skip when interface is not running */ -+ } -+ - #if PJ_IP_HELPER_IGNORE_LOOPBACK_IF - if (ifreq.ifr_flags & IFF_LOOPBACK) { - TRACE_((THIS_FILE, " loopback interface")); --- -2.25.1 - diff --git a/contrib/src/pjproject/0013-ignore-addresses-for-RFC7335.patch b/contrib/src/pjproject/0013-ignore-addresses-for-RFC7335.patch deleted file mode 100644 index e0ce47e89537589f9c52820d88a53ac0377a03a2..0000000000000000000000000000000000000000 --- a/contrib/src/pjproject/0013-ignore-addresses-for-RFC7335.patch +++ /dev/null @@ -1,58 +0,0 @@ -diff --git a/pjlib/src/pj/ip_helper_generic.c b/pjlib/src/pj/ip_helper_generic.c -index 2a392d16b..c1e49c3d3 100644 ---- a/pjlib/src/pj/ip_helper_generic.c -+++ b/pjlib/src/pj/ip_helper_generic.c -@@ -121,6 +121,16 @@ static pj_status_t if_enum_by_af(int af, - continue; /* Skip when interface is down */ - } - -+ /* Ignore 192.0.0.0/29 address. cf https://datatracker.ietf.org/doc/html/rfc7335#section-4 -+ */ -+ if (af==pj_AF_INET() && -+ (pj_ntohl(((pj_sockaddr_in*)ad)->sin_addr.s_addr) >> 4) == 201326592 /* 0b1100000000000000000000000000 which is 192.0.0.0 >> 4 */) -+ { -+ TRACE_((THIS_FILE, " address %s ignored (192.0.0.0/29 class)", -+ get_addr(ad), ad->sa_family)); -+ continue; -+ } -+ - /* Ignore 0.0.0.0/8 address. This is a special address - * which doesn't seem to have practical use. - */ -@@ -225,6 +235,16 @@ static pj_status_t if_enum_by_af(int af, - } - #endif - -+ /* Ignore 192.0.0.0/29 address. cf https://datatracker.ietf.org/doc/html/rfc7335#section-4 -+ */ -+ if (af==pj_AF_INET() && -+ (pj_ntohl(((pj_sockaddr_in*)ad)->sin_addr.s_addr) >> 4) == 201326592 /* 0b1100000000000000000000000000 which is 192.0.0.0 >> 4 */) -+ { -+ TRACE_((THIS_FILE, " address %s ignored (192.0.0.0/29 class)", -+ get_addr(ad), ad->sa_family)); -+ continue; -+ } -+ - /* Ignore 0.0.0.0/8 address. This is a special address - * which doesn't seem to have practical use. - */ -@@ -324,6 +344,16 @@ static pj_status_t if_enum_by_af(int af, unsigned *p_cnt, pj_sockaddr ifs[]) - continue; /* Not address family that we want, continue */ - } - -+ /* Ignore 192.0.0.0/29 address. cf https://datatracker.ietf.org/doc/html/rfc7335#section-4 -+ */ -+ if (af==pj_AF_INET() && -+ (pj_ntohl(((pj_sockaddr_in*)ad)->sin_addr.s_addr) >> 4) == 201326592 /* 0b1100000000000000000000000000 which is 192.0.0.0 >> 4 */) -+ { -+ TRACE_((THIS_FILE, " address %s ignored (192.0.0.0/29 class)", -+ get_addr(ad), ad->sa_family)); -+ continue; -+ } -+ - /* Ignore 0.0.0.0/8 address. This is a special address - * which doesn't seem to have practical use. - */ --- -2.25.1 - diff --git a/contrib/src/pjproject/0014-fix-socket-leak.patch b/contrib/src/pjproject/0014-fix-socket-leak.patch deleted file mode 100644 index 423c4db9b3e5e3d646caf0885fb0eec41197a29a..0000000000000000000000000000000000000000 --- a/contrib/src/pjproject/0014-fix-socket-leak.patch +++ /dev/null @@ -1,46 +0,0 @@ -From c1093eeb18a4090fd7eac6e8e70a6da1777f0907 Mon Sep 17 00:00:00 2001 -From: Olivier Dion <olivier.dion@savoirfairelinux.com> -Date: Mon, 26 Jul 2021 09:52:50 -0400 -Subject: [PATCH] pjnath/turn_sock: Fix leak of socket - -Opened socket is not closed on binding and quality of service error. The socket -is owned by the active sock only if everything went well. ---- - pjnath/src/pjnath/turn_sock.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/pjnath/src/pjnath/turn_sock.c b/pjnath/src/pjnath/turn_sock.c -index 8e576e031..7a88494c6 100644 ---- a/pjnath/src/pjnath/turn_sock.c -+++ b/pjnath/src/pjnath/turn_sock.c -@@ -1286,6 +1286,7 @@ static void turn_on_state(pj_turn_session *sess, - turn_sock->setting.port_range, - max_bind_retry); - if (status != PJ_SUCCESS) { -+ pj_sock_close(sock); - pj_turn_sock_destroy(turn_sock); - return; - } -@@ -1296,6 +1297,7 @@ static void turn_on_state(pj_turn_session *sess, - turn_sock->pool->obj_name, NULL); - if (status != PJ_SUCCESS && !turn_sock->setting.qos_ignore_error) - { -+ pj_sock_close(sock); - pj_turn_sock_destroy(turn_sock); - return; - } -@@ -1353,6 +1355,11 @@ static void turn_on_state(pj_turn_session *sess, - turn_sock->cfg.ioqueue, &asock_cb, - turn_sock, - &turn_sock->active_sock); -+ -+ /* Active socket failed to take ownership of `sock` */ -+ if (status != PJ_SUCCESS) { -+ pj_sock_close(sock); -+ } - } - #if PJ_HAS_SSL_SOCK - else { --- -2.25.1 - diff --git a/contrib/src/pjproject/0015-fix-socktype-and-duplicate-checking.patch b/contrib/src/pjproject/0015-fix-socktype-and-duplicate-checking.patch deleted file mode 100644 index 8384046e5578179e99c5cd7eaad8b20f512daa7b..0000000000000000000000000000000000000000 --- a/contrib/src/pjproject/0015-fix-socktype-and-duplicate-checking.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 2feee8db77ed47e7b574367295d4f03f9aea67f8 Mon Sep 17 00:00:00 2001 -From: sauwming <ming@teluu.com> -Date: Fri, 6 Aug 2021 09:45:54 +0800 -Subject: [PATCH] Fix socktype and duplicate checking in pj_getaddrinfo() - ---- - pjlib/src/pj/addr_resolv_sock.c | 11 ++++++++--- - 1 file changed, 8 insertions(+), 3 deletions(-) - -diff --git a/pjlib/src/pj/addr_resolv_sock.c b/pjlib/src/pj/addr_resolv_sock.c -index f68c4b177..0954f2ee0 100644 ---- a/pjlib/src/pj/addr_resolv_sock.c -+++ b/pjlib/src/pj/addr_resolv_sock.c -@@ -197,15 +197,20 @@ PJ_DEF(pj_status_t) pj_getaddrinfo(int af, const pj_str_t *nodename, - if (af!=PJ_AF_UNSPEC && res->ai_family != af) - continue; - -- if (res->ai_socktype != pj_SOCK_DGRAM() -- && res->ai_socktype != pj_SOCK_STREAM()) { -+ if (res->ai_socktype != pj_SOCK_DGRAM() && -+ res->ai_socktype != pj_SOCK_STREAM() && -+ /* It is possible that the result's sock type -+ * is unspecified. -+ */ -+ res->ai_socktype != 0) -+ { - continue; - } - - /* Add current address in the resulting list if there - * is no duplicates only. */ - for (j = 0; j < i; j++) { -- if (!pj_memcmp(&ai[j].ai_addr, res->ai_addr, res->ai_addrlen)) { -+ if (!pj_sockaddr_cmp(&ai[j].ai_addr, res->ai_addr)) { - duplicate_found = PJ_TRUE; - break; - } --- -2.25.1 - diff --git a/contrib/src/pjproject/0016-use-larger-Ta-interval.patch b/contrib/src/pjproject/0016-use-larger-Ta-interval.patch deleted file mode 100644 index 9de4dfd4172414a67d2adcbdce53fb04ca72b9ac..0000000000000000000000000000000000000000 --- a/contrib/src/pjproject/0016-use-larger-Ta-interval.patch +++ /dev/null @@ -1,132 +0,0 @@ - pjnath/include/pjnath/config.h | 2 +- - pjnath/src/pjnath/ice_session.c | 31 ++++++++++++++++++++----------- - 2 files changed, 21 insertions(+), 12 deletions(-) - -diff --git a/pjnath/include/pjnath/config.h b/pjnath/include/pjnath/config.h -index 89b421c51..fe58be9c9 100644 ---- a/pjnath/include/pjnath/config.h -+++ b/pjnath/include/pjnath/config.h -@@ -340,7 +340,7 @@ - * Default: 20 - */ - #ifndef PJ_ICE_TA_VAL --# define PJ_ICE_TA_VAL 20 -+# define PJ_ICE_TA_VAL 50 - #endif - - -diff --git a/pjnath/src/pjnath/ice_session.c b/pjnath/src/pjnath/ice_session.c -index 0b1c5fd56..503cbfd91 100644 ---- a/pjnath/src/pjnath/ice_session.c -+++ b/pjnath/src/pjnath/ice_session.c -@@ -2705,9 +2705,8 @@ static pj_status_t perform_check(pj_ice_sess *ice, - return status; - } - -- - /* Start periodic check for the specified checklist. -- * This callback is called by timer on every Ta (20msec by default) -+ * This callback is called by timer on every Ta - */ - static pj_status_t start_periodic_check(pj_timer_heap_t *th, - pj_timer_entry *te) -@@ -2735,8 +2734,7 @@ static pj_status_t start_periodic_check(pj_timer_heap_t *th, - /* Set checklist state to Running */ - clist_set_state(ice, clist, PJ_ICE_SESS_CHECKLIST_ST_RUNNING); - -- LOG5((ice->obj_name, "Starting checklist periodic check")); -- pj_log_push_indent(); -+ pj_ice_sess_check *check = NULL; - - /* Send STUN Binding request for check with highest priority on - * Retry state. -@@ -2744,9 +2742,11 @@ static pj_status_t start_periodic_check(pj_timer_heap_t *th, - - if (start_count == 0) { - for (i = 0; i < clist->count; ++i) { -- pj_ice_sess_check *check = &clist->checks[i]; -+ check = &clist->checks[i]; - // Reconnect closed TURN sockets - if (check->state == PJ_ICE_SESS_CHECK_STATE_NEEDS_RETRY) { -+ LOG5((ice->obj_name, "re-Starting periodic check for check %i (needs retry)", i)); -+ pj_log_push_indent(); - status = perform_check(ice, clist, i, ice->is_nominating); - if (status != PJ_SUCCESS && status != PJ_EPENDING) { - check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, -@@ -2763,13 +2763,15 @@ static pj_status_t start_periodic_check(pj_timer_heap_t *th, - // TODO (sblin) remove - https://github.com/coturn/coturn/issues/408 - pj_bool_t inc_counter = PJ_TRUE; - for (i = 0; i < clist->count; ++i) { -- pj_ice_sess_check *check = &clist->checks[i]; -+ check = &clist->checks[i]; - if (check->state == PJ_ICE_SESS_CHECK_STATE_NEEDS_FIRST_PACKET) { - if (inc_counter) { - td->first_packet_counter += 1; - inc_counter = PJ_FALSE; - } - if (td->first_packet_counter % 50 == 0) { -+ LOG5((ice->obj_name, "re-Starting periodic check for check %i (needs 1st packet)", i)); -+ pj_log_push_indent(); - status = perform_check(ice, clist, i, ice->is_nominating); - if (status != PJ_SUCCESS && status != PJ_EPENDING) { - check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, -@@ -2789,9 +2791,12 @@ static pj_status_t start_periodic_check(pj_timer_heap_t *th, - - if (start_count == 0) { - for (i = 0; i < clist->count; ++i) { -- pj_ice_sess_check *check = &clist->checks[i]; -+ check = &clist->checks[i]; - - if (check->state == PJ_ICE_SESS_CHECK_STATE_WAITING) { -+ LOG5((ice->obj_name, "Starting periodic check for check %i (was waiting)", i)); -+ pj_log_push_indent(); -+ - status = perform_check(ice, clist, i, ice->is_nominating); - if (status != PJ_SUCCESS && status != PJ_EPENDING) { - check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, -@@ -2809,9 +2814,11 @@ static pj_status_t start_periodic_check(pj_timer_heap_t *th, - */ - if (start_count == 0) { - for (i = 0; i < clist->count; ++i) { -- pj_ice_sess_check *check = &clist->checks[i]; -+ check = &clist->checks[i]; - - if (check->state == PJ_ICE_SESS_CHECK_STATE_FROZEN) { -+ LOG5((ice->obj_name, "Starting periodic check for check %i (was frozen)", i)); -+ pj_log_push_indent(); - status = perform_check(ice, clist, i, ice->is_nominating); - if (status != PJ_SUCCESS && status != PJ_EPENDING) { - check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, status); -@@ -2826,7 +2833,7 @@ static pj_status_t start_periodic_check(pj_timer_heap_t *th, - if (start_count == 0) { - // If all sockets are pending, do nothing - for (i = 0; i < clist->count; ++i) { -- pj_ice_sess_check *check = &clist->checks[i]; -+ check = &clist->checks[i]; - if (check->state == PJ_ICE_SESS_CHECK_STATE_PENDING) { - ++start_count; - break; -@@ -2834,8 +2841,11 @@ static pj_status_t start_periodic_check(pj_timer_heap_t *th, - } - } - -- // Cannot start check because there's no suitable candidate pair. -+ // The checks are performed at the rate of 1 check per Ta -+ // interval. If a new check was started, we need to re-schedule -+ // for the next one (if any). - if (start_count!=0) { -+ pj_assert(check != NULL); - pj_time_val timeout = {0, PJ_ICE_TA_VAL}; - - pj_time_val_normalize(&timeout); -@@ -2848,7 +2858,6 @@ static pj_status_t start_periodic_check(pj_timer_heap_t *th, - return PJ_SUCCESS; - } - -- - /* Start sending connectivity check with USE-CANDIDATE */ - static void start_nominated_check(pj_ice_sess *ice) - { --- -2.25.1 - diff --git a/contrib/src/pjproject/0017-auto-register-thread.patch b/contrib/src/pjproject/0017-auto-register-thread.patch deleted file mode 100644 index 92acb3b34f5958eb4f4332708bf46629bb7432d2..0000000000000000000000000000000000000000 --- a/contrib/src/pjproject/0017-auto-register-thread.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 2e9dcff92232e7fe6bd779a5947d32d8c94cd807 Mon Sep 17 00:00:00 2001 -From: Olivier Dion <olivier.dion@polymtl.ca> -Date: Wed, 28 Jul 2021 17:27:29 -0400 -Subject: [PATCH] pj/os_core: Register thread if not registered - ---- - pjlib/src/pj/os_core_unix.c | 35 ++++++++++++++++++++++++++++++++--- - pjlib/src/pj/os_core_win32.c | 7 ++++--- - 2 files changed, 36 insertions(+), 6 deletions(-) - -diff --git a/pjlib/src/pj/os_core_unix.c b/pjlib/src/pj/os_core_unix.c -index c9a7b6fc1..7df3c6cc8 100644 ---- a/pjlib/src/pj/os_core_unix.c -+++ b/pjlib/src/pj/os_core_unix.c -@@ -686,6 +686,18 @@ PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *p) - return rc; - } - -+#if PJ_DARWINOS -+static pthread_key_t key; -+static pthread_once_t key_once = PTHREAD_ONCE_INIT; -+ -+static void -+make_key() -+{ -+ (void) pthread_key_create(&key, free); -+} -+#endif -+ -+ - /* - * pj_thread_this() - */ -@@ -695,9 +707,26 @@ PJ_DEF(pj_thread_t*) pj_thread_this(void) - pj_thread_t *rec = (pj_thread_t*)pj_thread_local_get(thread_tls_id); - - if (rec == NULL) { -- pj_assert(!"Calling pjlib from unknown/external thread. You must " -- "register external threads with pj_thread_register() " -- "before calling any pjlib functions."); -+ -+ static pj_thread_t* dummy; -+ -+#if PJ_DARWINOS -+ (void) pthread_once(&key_once, make_key); -+ -+ pj_thread_t* desc; -+ -+ if ((desc = pthread_getspecific(key)) == NULL) { -+ desc = malloc(sizeof(pj_thread_desc)); -+ pj_bzero(desc, sizeof(pj_thread_desc)); -+ (void) pthread_setspecific(key, desc); -+ } -+#else -+ static __thread pj_thread_desc desc; -+#endif -+ -+ pj_thread_register(NULL, (long*)desc, &dummy); -+ -+ rec = (pj_thread_t*)pj_thread_local_get(thread_tls_id); - } - - /* -diff --git a/pjlib/src/pj/os_core_win32.c b/pjlib/src/pj/os_core_win32.c -index 09d714490..10715b60f 100644 ---- a/pjlib/src/pj/os_core_win32.c -+++ b/pjlib/src/pj/os_core_win32.c -@@ -583,9 +583,10 @@ PJ_DEF(pj_thread_t*) pj_thread_this(void) - pj_thread_t *rec = pj_thread_local_get(thread_tls_id); - - if (rec == NULL) { -- pj_assert(!"Calling pjlib from unknown/external thread. You must " -- "register external threads with pj_thread_register() " -- "before calling any pjlib functions."); -+ static __declspec(thread) pj_thread_desc desc; -+ static __declspec(thread) pj_thread_t* this_thread; -+ pj_thread_register(NULL, desc, &this_thread); -+ rec = (pj_thread_t*)pj_thread_local_get(thread_tls_id); - } - - /* --- -2.25.1 - diff --git a/contrib/src/pjproject/0018-fix-ioqueue-lock-acquire.patch b/contrib/src/pjproject/0018-fix-ioqueue-lock-acquire.patch deleted file mode 100644 index 3ffc1cf1fe5c5b5bc422c0622cc25d9b8465e0e0..0000000000000000000000000000000000000000 --- a/contrib/src/pjproject/0018-fix-ioqueue-lock-acquire.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 2bf169548d9d55ca022a3203bb64c3c90ed01891 Mon Sep 17 00:00:00 2001 -From: Olivier Dion <olivier.dion@savoirfairelinux.com> -Date: Thu, 19 Aug 2021 10:15:13 -0400 -Subject: [PATCH] pj/ioqueue_epoll: Acquire ioqueue's lock before destroying - -`ioqueue_destroy(ioqueue)` will call `pj_lock_release(ioqueue->lock)`, which will -result in failure of the assertion `mutex->owner == pj_thread_this()` when -`PJ_DEBUG` is defined. - -Thus, acquire the lock before destroying the ioqueue. ---- - pjlib/src/pj/ioqueue_epoll.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/pjlib/src/pj/ioqueue_epoll.c b/pjlib/src/pj/ioqueue_epoll.c -index dbf479d25..560160ab7 100644 ---- a/pjlib/src/pj/ioqueue_epoll.c -+++ b/pjlib/src/pj/ioqueue_epoll.c -@@ -231,6 +231,7 @@ PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, - - ioqueue->epfd = os_epoll_create(max_fd); - if (ioqueue->epfd < 0) { -+ pj_lock_acquire(ioqueue->lock); - ioqueue_destroy(ioqueue); - return PJ_RETURN_OS_ERROR(pj_get_native_os_error()); - } --- -2.25.1 - diff --git a/contrib/src/pjproject/0019-resort-check-list-after-adding-prflx.patch b/contrib/src/pjproject/0019-resort-check-list-after-adding-prflx.patch deleted file mode 100644 index 97bb6f0abde1019086593d596062d60f4c5b4f02..0000000000000000000000000000000000000000 --- a/contrib/src/pjproject/0019-resort-check-list-after-adding-prflx.patch +++ /dev/null @@ -1,22 +0,0 @@ - pjnath/src/pjnath/ice_session.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/pjnath/src/pjnath/ice_session.c b/pjnath/src/pjnath/ice_session.c -index 503cbfd91..f060aaa9c 100644 ---- a/pjnath/src/pjnath/ice_session.c -+++ b/pjnath/src/pjnath/ice_session.c -@@ -4138,7 +4138,11 @@ static void handle_incoming_check(pj_ice_sess *ice, - LOG4((ice->obj_name, "New triggered check added: %d", - ice->clist.count)); - pj_log_push_indent(); -+ - perform_check(ice, &ice->clist, ice->clist.count++, nominate); -+ /* Re-sort the list because of the newly added pair. */ -+ sort_checklist(ice, &ice->clist); -+ - pj_log_pop_indent(); - - } else { --- -2.25.1 - diff --git a/contrib/src/pjproject/0020-avoid-immediate-nominating-triggered-check.patch b/contrib/src/pjproject/0020-avoid-immediate-nominating-triggered-check.patch deleted file mode 100644 index f8145095e42d6859b578cde9a4c0e501250462a6..0000000000000000000000000000000000000000 --- a/contrib/src/pjproject/0020-avoid-immediate-nominating-triggered-check.patch +++ /dev/null @@ -1,95 +0,0 @@ - pjnath/src/pjnath/ice_session.c | 57 ++++++++++++++++++++++++--------- - 1 file changed, 42 insertions(+), 15 deletions(-) - -diff --git a/pjnath/src/pjnath/ice_session.c b/pjnath/src/pjnath/ice_session.c -index f060aaa9c..f04b7314e 100644 ---- a/pjnath/src/pjnath/ice_session.c -+++ b/pjnath/src/pjnath/ice_session.c -@@ -4057,14 +4057,22 @@ static void handle_incoming_check(pj_ice_sess *ice, - if (c->state == PJ_ICE_SESS_CHECK_STATE_FROZEN || - c->state == PJ_ICE_SESS_CHECK_STATE_WAITING) - { -- /* See if we shall nominate this check */ -- pj_bool_t nominate = (c->nominated || ice->is_nominating); -- -- LOG5((ice->obj_name, "Performing triggered check for check %d",i)); -- pj_log_push_indent(); -- perform_check(ice, &ice->clist, i, nominate); -- pj_log_pop_indent(); -+ /* If we are nominating in regular nomination, don't nominate this -+ * triggered check immediately, just wait for its scheduled check. -+ */ -+ if (ice->is_nominating && !ice->opt.aggressive) { -+ LOG5((ice->obj_name, "Triggered check for check %d not " -+ "performed because nomination is in progress", i)); -+ } else { -+ /* See if we shall nominate this check */ -+ pj_bool_t nominate = (c->nominated || ice->is_nominating); - -+ LOG5((ice->obj_name, "Performing triggered check for " -+ "check %d",i)); -+ pj_log_push_indent(); -+ perform_check(ice, &ice->clist, i, nominate); -+ pj_log_pop_indent(); -+ } - } else if (c->state == PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS) { - /* Should retransmit immediately - */ -@@ -4124,7 +4132,7 @@ static void handle_incoming_check(pj_ice_sess *ice, - else if (ice->clist.count < PJ_ICE_MAX_CHECKS) { - - pj_ice_sess_check *c = &ice->clist.checks[ice->clist.count]; -- pj_bool_t nominate; -+ unsigned check_id = ice->clist.count; - - c->lcand = lcand; - c->rcand = rcand; -@@ -4132,19 +4140,38 @@ static void handle_incoming_check(pj_ice_sess *ice, - c->state = PJ_ICE_SESS_CHECK_STATE_WAITING; - c->nominated = rcheck->use_candidate; - c->err_code = PJ_SUCCESS; -+ ++ice->clist.count; - -- nominate = (c->nominated || ice->is_nominating); -+ LOG4((ice->obj_name, "New triggered check added: %d", check_id)); - -- LOG4((ice->obj_name, "New triggered check added: %d", -- ice->clist.count)); -- pj_log_push_indent(); -+ /* If we are nominating in regular nomination, don't nominate this -+ * newly found pair. -+ */ -+ if (ice->is_nominating && !ice->opt.aggressive) { -+ LOG5((ice->obj_name, "Triggered check for check %d not " -+ "performed because nomination is in progress", check_id)); -+ -+ /* Just in case the periodic check has been stopped (due to no more -+ * pair to check), let's restart it for this pair. -+ */ -+ if (!pj_timer_entry_running(&ice->clist.timer)) { -+ pj_time_val delay = {0, 0}; -+ pj_timer_heap_schedule_w_grp_lock(ice->stun_cfg.timer_heap, -+ &ice->clist.timer, &delay, -+ PJ_TRUE, ice->grp_lock); -+ } -+ } else { -+ pj_bool_t nominate; -+ nominate = (c->nominated || ice->is_nominating); -+ -+ pj_log_push_indent(); -+ perform_check(ice, &ice->clist, check_id, nominate); -+ pj_log_pop_indent(); -+ } - -- perform_check(ice, &ice->clist, ice->clist.count++, nominate); - /* Re-sort the list because of the newly added pair. */ - sort_checklist(ice, &ice->clist); - -- pj_log_pop_indent(); -- - } else { - LOG4((ice->obj_name, "Error: unable to perform triggered check: " - "TOO MANY CHECKS IN CHECKLIST!")); --- -2.25.1 - diff --git a/contrib/src/pjproject/SHA512SUMS b/contrib/src/pjproject/SHA512SUMS index 34aefbccd076c35eb5b0eec7eaf011dbe7bf4e49..e8cf85887a1ca727b585fcc1500ff71fe7d969c2 100644 --- a/contrib/src/pjproject/SHA512SUMS +++ b/contrib/src/pjproject/SHA512SUMS @@ -1 +1 @@ -021fe3f904b15e149cf647fe2ebdf530b5a8f11ba226396b6df1c8b85c406a532e6d9c310617434b520de787ec0cc4b07d9d54507d51b80627a5c23e884516c2 pjproject-2.11.tar.gz +221164832b1922d72f783cfc0ec246de3dcf1121763205c324f2e0654dbb1dbff56f7ab92c7850843034c080e062153ffef838f01433390c72f0a80a33398baf pjproject-f94b3d72b428d7c59b319e35095de711ed1d8534.tar.gz diff --git a/contrib/src/pjproject/package.json b/contrib/src/pjproject/package.json index dbbb0c6e3853632d92e7bcf2b2391bd6600a0c37..4822684e7945ebc3d2094ef3868a418ec517e544 100644 --- a/contrib/src/pjproject/package.json +++ b/contrib/src/pjproject/package.json @@ -1,32 +1,12 @@ { "name": "pjproject", - "version": "2.11", - "url": "https://github.com/pjsip/pjproject/archive/__VERSION__.tar.gz", + "version": "f94b3d72b428d7c59b319e35095de711ed1d8534", + "url": "https://github.com/savoirfairelinux/pjproject/archive/__VERSION__.tar.gz", "deps": ["gnutls"], "patches": [ - "0001-rfc6544.patch", - "0002-rfc2466.patch", - "0003-add-tcp-keep-alive.patch", - "0004-multiple_listeners.patch", - "0005-fix_ebusy_turn.patch", - "0006-ignore_ipv6_on_transport_check.patch", - "0007-upnp-srflx-nat-assisted-cand.patch", - "0008-fix_ioqueue_ipv6_sendto.patch", "0009-add-config-site.patch", - "0010-fix-tcp-death-detection.patch", - "0011-fix-turn-shutdown-crash.patch", - "0012-ignore-down-interfaces.patch", - "0013-ignore-addresses-for-RFC7335.patch", - "0014-fix-socket-leak.patch", - "0015-fix-socktype-and-duplicate-checking.patch", - "0016-use-larger-Ta-interval.patch", - "0017-auto-register-thread.patch", - "0018-fix-ioqueue-lock-acquire.patch", - "0019-resort-check-list-after-adding-prflx.patch", - "0020-avoid-immediate-nominating-triggered-check.patch", "0001-win-config.patch", - "0002-win-vs-gnutls.patch", - "0003-win-vs2017-props.patch" + "0002-win-vs-gnutls.patch" ], "project_paths": [ "pjlib-util/build/pjlib_util.vcxproj", diff --git a/contrib/src/pjproject/rules.mak b/contrib/src/pjproject/rules.mak index bc71723bcc894c89dfcf107f3e3f6e36fec8f463..e1c1fc87922d0c55d786ed314b5f38e0012cd36f 100644 --- a/contrib/src/pjproject/rules.mak +++ b/contrib/src/pjproject/rules.mak @@ -1,6 +1,6 @@ # PJPROJECT -PJPROJECT_VERSION := 2.11 -PJPROJECT_URL := https://github.com/pjsip/pjproject/archive/$(PJPROJECT_VERSION).tar.gz +PJPROJECT_VERSION := f94b3d72b428d7c59b319e35095de711ed1d8534 +PJPROJECT_URL := https://github.com/savoirfairelinux/pjproject/archive/${PJPROJECT_VERSION}.tar.gz PJPROJECT_OPTIONS := --disable-sound \ --enable-video \ @@ -43,29 +43,9 @@ $(TARBALLS)/pjproject-$(PJPROJECT_VERSION).tar.gz: .sum-pjproject: pjproject-$(PJPROJECT_VERSION).tar.gz -# NOTE! Remove 0018-fix-ioqueue-lock-acquire.patch when bumping pjsip to version 2.12 pjproject: pjproject-$(PJPROJECT_VERSION).tar.gz .sum-pjproject $(UNPACK) - $(APPLY) $(SRC)/pjproject/0001-rfc6544.patch - $(APPLY) $(SRC)/pjproject/0002-rfc2466.patch - $(APPLY) $(SRC)/pjproject/0003-add-tcp-keep-alive.patch - $(APPLY) $(SRC)/pjproject/0004-multiple_listeners.patch - $(APPLY) $(SRC)/pjproject/0005-fix_ebusy_turn.patch - $(APPLY) $(SRC)/pjproject/0006-ignore_ipv6_on_transport_check.patch - $(APPLY) $(SRC)/pjproject/0007-upnp-srflx-nat-assisted-cand.patch - $(APPLY) $(SRC)/pjproject/0008-fix_ioqueue_ipv6_sendto.patch $(APPLY) $(SRC)/pjproject/0009-add-config-site.patch - $(APPLY) $(SRC)/pjproject/0010-fix-tcp-death-detection.patch - $(APPLY) $(SRC)/pjproject/0011-fix-turn-shutdown-crash.patch - $(APPLY) $(SRC)/pjproject/0012-ignore-down-interfaces.patch # TODO remove with 2.12 (https://github.com/pjsip/pjproject/commit/997a468a5e90f9a88a36f543bef85e0fb0af0dfc) - $(APPLY) $(SRC)/pjproject/0013-ignore-addresses-for-RFC7335.patch # TODO remove with 2.12 (https://github.com/pjsip/pjproject/commit/d245ffaf91120fab7bb70e3f46206faeb5b01269) - $(APPLY) $(SRC)/pjproject/0014-fix-socket-leak.patch - $(APPLY) $(SRC)/pjproject/0015-fix-socktype-and-duplicate-checking.patch # TODO remove with 2.12 (https://github.com/pjsip/pjproject/commits/2feee8db77ed47e7b574367295d4f03f9aea67f8) - $(APPLY) $(SRC)/pjproject/0016-use-larger-Ta-interval.patch - $(APPLY) $(SRC)/pjproject/0017-auto-register-thread.patch - $(APPLY) $(SRC)/pjproject/0018-fix-ioqueue-lock-acquire.patch - $(APPLY) $(SRC)/pjproject/0019-resort-check-list-after-adding-prflx.patch # TODO remove with 2.12 (https://github.com/pjsip/pjproject/pull/2806) - $(APPLY) $(SRC)/pjproject/0020-avoid-immediate-nominating-triggered-check.patch # TODO remove with 2.12 (https://github.com/pjsip/pjproject/issues/2812) ifdef HAVE_ANDROID $(APPLY) $(SRC)/pjproject/0001-android.patch endif diff --git a/contrib/src/pjproject/sip_td_timeout.patch b/contrib/src/pjproject/sip_td_timeout.patch deleted file mode 100644 index 4005d8a63900602188bcbf6ad189b1dc5629ff61..0000000000000000000000000000000000000000 --- a/contrib/src/pjproject/sip_td_timeout.patch +++ /dev/null @@ -1,15 +0,0 @@ - pjsip/include/pjsip/sip_config.h | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/pjsip/include/pjsip/sip_config.h b/pjsip/include/pjsip/sip_config.h -index 904df24e..0831e4ef 100644 ---- a/pjsip/include/pjsip/sip_config.h -+++ b/pjsip/include/pjsip/sip_config.h -@@ -1054,7 +1054,7 @@ PJ_INLINE(pjsip_cfg_t*) pjsip_cfg(void) - - /** Transaction completed timer for INVITE */ - #if !defined(PJSIP_TD_TIMEOUT) --# define PJSIP_TD_TIMEOUT 32000 -+# define PJSIP_TD_TIMEOUT 15000 - #endif -