Unverified Commit ebb5e5c1 authored by Sébastien Blin's avatar Sébastien Blin
Browse files

contrib: bump pjproject

Now that RFC6062 is merged upstream, we can remove the patch from
our stack. The API changed a bit, so this patch also updates
turn_transport.cpp to follow changes

Change-Id: If6e0bae8280d586b2e5fcb0babe83df8127789b6
parent 5b6063dc
e203f3846db1a380b2bcb2e18fb73f6296a87c25d5b0b38d44df88a398c597bcb31c85a0e72b476908e4b56fdeb6fc5c586cf595f9723091d6a09659b75d1d5c pjproject-6b9212dcb4b3f781c1e922ae544b063880bc46ac.tar.gz
\ No newline at end of file
a9433b47294434288d61524dea556687fb02137ed56a10e8e2ba85d7888a2ca2a5bea4ae4a9ad008a4c208c5ec53fe364b10ed14481700d6aa8b9b6137e5e9ee pjproject-5dfa75be7d69047387f9b0436dd9492bbbf03fe4.tar.gz
\ No newline at end of file
set BUILD=%SRC%..\build
set PJPROJECT_VERSION=6b9212dcb4b3f781c1e922ae544b063880bc46ac
set PJPROJECT_VERSION=5dfa75be7d69047387f9b0436dd9492bbbf03fe4
set PJPROJECT_URL=https://github.com/pjsip/pjproject/archive/%PJPROJECT_VERSION%.tar.gz
mkdir %BUILD%
......@@ -33,7 +33,6 @@ bash -c "%PATCH_CMD% %UNIXPATH%pjproject/pj_ice_sess.patch"
bash -c "%PATCH_CMD% %UNIXPATH%pjproject/fix_turn_fallback.patch"
bash -c "%PATCH_CMD% %UNIXPATH%pjproject/fix_ioqueue_ipv6_sendto.patch"
bash -c "%PATCH_CMD% %UNIXPATH%pjproject/add_dtls_transport.patch"
bash -c "%PATCH_CMD% %UNIXPATH%pjproject/rfc6062.patch"
bash -c "%PATCH_CMD% %UNIXPATH%pjproject/rfc6544.patch"
bash -c "%PATCH_CMD% %UNIXPATH%pjproject/ice_config.patch"
......
Copyright (C) 2017-2019 Savoir-faire Linux Inc.
turn: rfc 6062 support
Current implementation of TURN and STUN doesn't support TCP as a valid
peer connection. This connection is defined by the rfc 6062.
This patch is an implementation proposal of this rfc into PJNATH.
Modifications are API backware compatible, not ABI.
Users must rebuild their code.
Written by
Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
on behalf of Savoir-faire Linux.
---
pjnath/include/pjnath/config.h | 8 +
pjnath/include/pjnath/stun_msg.h | 26 ++
pjnath/include/pjnath/stun_session.h | 7 +
pjnath/include/pjnath/turn_session.h | 38 +++
pjnath/include/pjnath/turn_sock.h | 24 ++
pjnath/src/pjnath/stun_msg.c | 13 +-
pjnath/src/pjnath/stun_session.c | 13 +
pjnath/src/pjnath/turn_session.c | 59 +++-
pjnath/src/pjnath/turn_sock.c | 474 ++++++++++++++++++++++++++-
9 files changed, 655 insertions(+), 7 deletions(-)
diff --git a/pjnath/include/pjnath/config.h b/pjnath/include/pjnath/config.h
index 540e32ad1..e157d39ee 100644
--- a/pjnath/include/pjnath/config.h
+++ b/pjnath/include/pjnath/config.h
@@ -220,6 +220,14 @@
# define PJ_TURN_KEEP_ALIVE_SEC 15
#endif
+/**
+ * Maximal number of TCP data connection that a client can open/accept with
+ * peers.
+ */
+#ifndef PJ_TURN_MAX_TCP_CNX
+# define PJ_TURN_MAX_TCP_CNX 32
+#endif
+
/* **************************************************************************
* ICE CONFIGURATION
diff --git a/pjnath/include/pjnath/stun_msg.h b/pjnath/include/pjnath/stun_msg.h
index 7efdf57a2..4d04016ff 100644
--- a/pjnath/include/pjnath/stun_msg.h
+++ b/pjnath/include/pjnath/stun_msg.h
@@ -92,6 +92,21 @@ enum pj_stun_method_e
*/
PJ_STUN_CHANNEL_BIND_METHOD = 9,
+ /*
+ * STUN/TURN Connect as defined by RFC 6062
+ */
+ PJ_STUN_CONNECT_METHOD = 10,
+
+ /*
+ * STUN/TURN ConnectionBind as defined by RFC 6062
+ */
+ PJ_STUN_CONNECTION_BIND_METHOD = 11,
+
+ /*
+ * STUN/TURN ConnectionAttempt as defined by RFC 6062
+ */
+ PJ_STUN_CONNECTION_ATTEMPT_METHOD = 12,
+
/**
* All known methods.
*/
@@ -261,6 +276,16 @@ typedef enum pj_stun_msg_type
*/
PJ_STUN_DATA_INDICATION = 0x0017,
+ /**
+ * STUN/TURN ConnectBind Request
+ */
+ PJ_STUN_CONNECTION_BIND_REQUEST = 0x000b,
+
+ /**
+ * TURN ConnectionAttempt indication
+ */
+ PJ_STUN_CONNECTION_ATTEMPT_INDICATION = 0x001c,
+
/**
* TURN CreatePermission request
@@ -333,6 +358,7 @@ typedef enum pj_stun_attr_type
PJ_STUN_ATTR_XOR_REFLECTED_FROM = 0x0023,/**< XOR-REFLECTED-FROM */
PJ_STUN_ATTR_PRIORITY = 0x0024,/**< PRIORITY */
PJ_STUN_ATTR_USE_CANDIDATE = 0x0025,/**< USE-CANDIDATE */
+ PJ_STUN_ATTR_CONNECTION_ID = 0x002a,/**< CONNECTION-ID */
PJ_STUN_ATTR_ICMP = 0x0030,/**< ICMP (TURN) */
PJ_STUN_ATTR_END_MANDATORY_ATTR,
diff --git a/pjnath/include/pjnath/stun_session.h b/pjnath/include/pjnath/stun_session.h
index f8ea4d1dc..28c5985e8 100644
--- a/pjnath/include/pjnath/stun_session.h
+++ b/pjnath/include/pjnath/stun_session.h
@@ -750,6 +750,13 @@ 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);
+PJ_DEF(void)
+pj_stun_session_get_server_cred(pj_stun_session *sess, pj_pool_t *pool,
+ pj_str_t *nonce, pj_str_t *realm);
+
+PJ_DEF(void)
+pj_stun_session_set_server_cred(pj_stun_session *sess, const pj_str_t *nonce,
+ pj_str_t *realm);
/**
* @}
diff --git a/pjnath/include/pjnath/turn_session.h b/pjnath/include/pjnath/turn_session.h
index cc3d5d8d5..3bb073beb 100644
--- a/pjnath/include/pjnath/turn_session.h
+++ b/pjnath/include/pjnath/turn_session.h
@@ -183,6 +183,12 @@ typedef enum pj_turn_state_t
*/
PJ_TURN_STATE_ALLOCATING,
+ /**
+ * TURN session has issued CONNECTION-BIND request and is waiting for response
+ * from the TURN server.
+ */
+ PJ_TURN_STATE_CONNECTION_BINDING,
+
/**
* TURN session has successfully allocated relay resoruce and now is
* ready to be used.
@@ -298,6 +304,21 @@ typedef struct pj_turn_session_cb
pj_turn_state_t old_state,
pj_turn_state_t new_state);
+ /**
+ * Notification when TURN session get a ConnectionAttempt indication.
+ *
+ * @param sess The TURN session.
+ * @param conn_id The connection-id to use for connection binding.
+ * @param peer_addr Peer address that tried to connect on the TURN server.
+ * @param addr_len Length of the peer address.
+
+ */
+ void (*on_peer_connection)(pj_turn_session *sess,
+ pj_uint32_t conn_id,
+ const pj_sockaddr_t *peer_addr,
+ unsigned addr_len,
+ pj_status_t status);
+
} pj_turn_session_cb;
@@ -339,6 +360,14 @@ typedef struct pj_turn_alloc_param
*/
int af;
+ /**
+ * Type of connection to from TURN server to peer.
+ *
+ * Supported values: PJ_TURN_TP_UDP (rfc 5766), PJ_TURN_TP_TLS (rfc 6062)
+ *
+ * Default is PJ_TURN_TP_UDP.
+ */
+ pj_turn_tp_type peer_conn_type;
} pj_turn_alloc_param;
@@ -741,6 +770,15 @@ PJ_DECL(pj_status_t) pj_turn_session_on_rx_pkt(pj_turn_session *sess,
pj_size_t pkt_len,
pj_size_t *parsed_len);
+/**
+ * rfc6062
+ */
+PJ_DEF(void) pj_turn_session_get_server_cred(
+ pj_turn_session *sess,
+ pj_pool_t *pool, pj_str_t *nonce, pj_str_t *realm);
+
+PJ_DEF(void) pj_turn_session_set_server_cred(
+ pj_turn_session *sess, const pj_str_t *nonce, pj_str_t *realm);
/**
* @}
diff --git a/pjnath/include/pjnath/turn_sock.h b/pjnath/include/pjnath/turn_sock.h
index bbff6bf7b..6a4d915c2 100644
--- a/pjnath/include/pjnath/turn_sock.h
+++ b/pjnath/include/pjnath/turn_sock.h
@@ -98,6 +98,23 @@ typedef struct pj_turn_sock_cb
pj_turn_state_t old_state,
pj_turn_state_t new_state);
+ /**
+ * Notification when TURN session get a ConnectionAttempt indication.
+ *
+ * @param turn_sock The TURN client transport.
+ * @param conn_id The connection-id to use for connection binding.
+ * @param peer_addr Peer address that tried to connect on the TURN server.
+ * @param addr_len Length of the peer address.
+ * @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).
+ */
+ void (*on_peer_connection)(pj_turn_sock *turn_sock,
+ pj_uint32_t conn_id,
+ const pj_sockaddr_t *peer_addr,
+ unsigned addr_len,
+ pj_status_t status);
+
} pj_turn_sock_cb;
@@ -446,6 +463,13 @@ PJ_DECL(pj_status_t) pj_turn_sock_bind_channel(pj_turn_sock *turn_sock,
const pj_sockaddr_t *peer,
unsigned addr_len);
+/**
+ * RFC 6062
+ */
+PJ_DECL(pj_status_t) pj_turn_connect_peer(pj_turn_sock *sock,
+ pj_uint32_t conn_id,
+ const pj_sockaddr_t *peer_addr,
+ unsigned addr_len);
/**
* @}
diff --git a/pjnath/src/pjnath/stun_msg.c b/pjnath/src/pjnath/stun_msg.c
index 896848b7a..acaf3b70f 100644
--- a/pjnath/src/pjnath/stun_msg.c
+++ b/pjnath/src/pjnath/stun_msg.c
@@ -45,6 +45,9 @@ static const char *stun_method_names[PJ_STUN_METHOD_MAX] =
"Data", /* 7 */
"CreatePermission", /* 8 */
"ChannelBind", /* 9 */
+ "Connect", /* 10 */
+ "ConnectionBind", /* 11 */
+ "ConnectionAttempt", /* 12 */
};
static struct
@@ -476,11 +479,11 @@ static struct attr_desc mandatory_attr_desc[] =
NULL
},
{
- /* ID 0x002a is not assigned */
- NULL,
- NULL,
- NULL,
- NULL
+ /* PJ_STUN_ATTR_CONNECTION_ID, */
+ "CONNECTION-ID",
+ &decode_uint_attr,
+ &encode_uint_attr,
+ &clone_uint_attr
},
{
/* ID 0x002b is not assigned */
diff --git a/pjnath/src/pjnath/stun_session.c b/pjnath/src/pjnath/stun_session.c
index d7eb2dbb5..5e2efc35a 100644
--- a/pjnath/src/pjnath/stun_session.c
+++ b/pjnath/src/pjnath/stun_session.c
@@ -1511,3 +1511,16 @@ PJ_DEF(pj_status_t) pj_stun_session_on_rx_pkt(pj_stun_session *sess,
return status;
}
+PJ_DEF(void)
+pj_stun_session_get_server_cred(pj_stun_session *sess, pj_pool_t *pool,
+ pj_str_t *nonce, pj_str_t *realm) {
+ pj_strdup(pool, nonce, &sess->next_nonce);
+ pj_strdup(pool, realm, &sess->server_realm);
+}
+
+PJ_DEF(void)
+pj_stun_session_set_server_cred(pj_stun_session *sess, const pj_str_t *nonce,
+ pj_str_t *realm) {
+ pj_strdup(sess->pool, &sess->next_nonce, nonce);
+ pj_strdup(sess->pool, &sess->server_realm, realm);
+}
diff --git a/pjnath/src/pjnath/turn_session.c b/pjnath/src/pjnath/turn_session.c
index bbea027f3..4fd643be1 100644
--- a/pjnath/src/pjnath/turn_session.c
+++ b/pjnath/src/pjnath/turn_session.c
@@ -42,6 +42,7 @@ static const char *state_names[] =
"Resolving",
"Resolved",
"Allocating",
+ "TcpBinding",
"Ready",
"Deallocating",
"Deallocated",
@@ -208,6 +209,7 @@ static void on_timer_event(pj_timer_heap_t *th, pj_timer_entry *e);
PJ_DEF(void) pj_turn_alloc_param_default(pj_turn_alloc_param *prm)
{
pj_bzero(prm, sizeof(*prm));
+ prm->peer_conn_type = PJ_TURN_TP_UDP;
}
/*
@@ -403,6 +405,11 @@ static void sess_shutdown(pj_turn_session *sess,
sess->pending_destroy = PJ_TRUE;
can_destroy = PJ_FALSE;
break;
+ case PJ_TURN_STATE_CONNECTION_BINDING:
+ /* We need to wait until connection binding complete */
+ sess->pending_destroy = PJ_TRUE;
+ can_destroy = PJ_FALSE;
+ break;
case PJ_TURN_STATE_READY:
/* Send REFRESH with LIFETIME=0 */
can_destroy = PJ_FALSE;
@@ -723,6 +730,9 @@ PJ_DEF(pj_status_t) pj_turn_session_alloc(pj_turn_session *sess,
PJ_ASSERT_RETURN(sess->state>PJ_TURN_STATE_NULL &&
sess->state<=PJ_TURN_STATE_RESOLVED,
PJ_EINVALIDOP);
+ PJ_ASSERT_RETURN(param->peer_conn_type == PJ_TURN_TP_UDP ||
+ param->peer_conn_type == PJ_TURN_TP_TCP,
+ PJ_EINVAL);
/* Verify address family in allocation param */
if (param && param->af) {
@@ -760,7 +770,7 @@ PJ_DEF(pj_status_t) pj_turn_session_alloc(pj_turn_session *sess,
/* MUST include REQUESTED-TRANSPORT attribute */
pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
PJ_STUN_ATTR_REQ_TRANSPORT,
- PJ_STUN_SET_RT_PROTO(PJ_TURN_TP_UDP));
+ PJ_STUN_SET_RT_PROTO(param->peer_conn_type));
/* Include BANDWIDTH if requested */
if (sess->alloc_param.bandwidth > 0) {
@@ -998,6 +1008,13 @@ PJ_DEF(pj_status_t) pj_turn_session_sendto( pj_turn_session *sess,
}
}
+ /* rfc6062: direct send if peer connection is TCP */
+ if (sess->alloc_param.peer_conn_type == PJ_TURN_TP_TCP) {
+ status = sess->cb.on_send_pkt(sess, pkt, pkt_len,
+ addr, addr_len);
+ goto on_return;
+ }
+
/* See if the peer is bound to a channel number */
ch = lookup_ch_by_addr(sess, addr, pj_sockaddr_get_len(addr),
PJ_FALSE, PJ_FALSE);
@@ -1674,6 +1691,33 @@ static pj_status_t stun_on_rx_indication(pj_stun_session *stun,
sess = (pj_turn_session*)pj_stun_session_get_user_data(stun);
+ if (msg->hdr.type == PJ_STUN_CONNECTION_ATTEMPT_INDICATION) {
+ pj_stun_uint_attr *connection_id_attr;
+ /* Get CONNECTION-ID attribute */
+ connection_id_attr = (pj_stun_uint_attr*)
+ pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_CONNECTION_ID, 0);
+
+ /* Get XOR-PEER-ADDRESS attribute */
+ peer_attr = (pj_stun_xor_peer_addr_attr*)
+ pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_XOR_PEER_ADDR, 0);
+
+ /* Must have both XOR-PEER-ADDRESS and CONNECTION-ID attributes */
+ if (!peer_attr || !connection_id_attr) {
+ PJ_LOG(4,(sess->obj_name,
+ "Received ConnectionAttempt indication with missing attributes"));
+ return PJ_EINVALIDOP;
+ }
+
+ /* Notify application */
+ if (sess->cb.on_peer_connection) {
+ (*sess->cb.on_peer_connection)(sess, connection_id_attr->value,
+ &peer_attr->sockaddr,
+ pj_sockaddr_get_len(&peer_attr->sockaddr),
+ PJ_SUCCESS);
+ }
+ return PJ_SUCCESS;
+ }
+
/* Expecting Data Indication only */
if (msg->hdr.type != PJ_STUN_DATA_INDICATION) {
PJ_LOG(4,(sess->obj_name, "Unexpected STUN %s indication",
@@ -2096,3 +2140,16 @@ static void on_timer_event(pj_timer_heap_t *th, pj_timer_entry *e)
pj_grp_lock_release(sess->grp_lock);
}
+PJ_DEF(void) pj_turn_session_get_server_cred(pj_turn_session *sess,
+ pj_pool_t *pool, pj_str_t *nonce,
+ pj_str_t *realm)
+{
+ pj_stun_session_get_server_cred(sess->stun, pool, nonce, realm);
+}
+
+PJ_DEF(void) pj_turn_session_set_server_cred(pj_turn_session *sess,
+ const pj_str_t *nonce,
+ pj_str_t *realm)
+{
+ pj_stun_session_set_server_cred(sess->stun, nonce, realm);
+}
diff --git a/pjnath/src/pjnath/turn_sock.c b/pjnath/src/pjnath/turn_sock.c
index a30ab5153..c267871e2 100644
--- a/pjnath/src/pjnath/turn_sock.c
+++ b/pjnath/src/pjnath/turn_sock.c
@@ -35,9 +35,29 @@ enum
enum { MAX_BIND_RETRY = 100 };
+enum { CONNECTION_USED = (1<<0), /* TCP connection slot is used or free */
+ CONNECTION_READY = (1<<1) /* TCP connection bind and ready to use for data transfer */
+};
#define INIT 0x1FFFFFFF
+/**
+ * pj_turn_tcp_data_connection contains information on TCP connection open between
+ * the client and the turn server, conveying data from/to a specific peer.
+ * notes: part of RFC 6062 support
+ */
+typedef struct pj_turn_tcp_data_connection
+{
+ pj_uint32_t id; /* identity of this connection as given by the TURN server */
+ pj_uint32_t flags; /* 0 or CONNECTION_USED */
+ pj_sockaddr peer_addr; /* mapped address of connected peer */
+ unsigned peer_addr_len;
+ pj_activesock_t *active_tcp_sock; /* socket between client and TURN server */
+ pj_ioqueue_op_key_t send_key;
+ pj_stun_session *stun_sess; /* STUN session used to send ConnectBind msg */
+ pj_turn_sock *turn_sock; /* up link */
+} pj_turn_tcp_data_connection;
+
struct pj_turn_sock
{
pj_pool_t *pool;
@@ -59,6 +79,11 @@ struct pj_turn_sock
pj_turn_tp_type conn_type;
pj_activesock_t *active_sock;
pj_ioqueue_op_key_t send_key;
+
+ /* RFC 6062 */
+ pj_stun_auth_cred cred; /* saved from control connection */
+ pj_size_t tcp_cnx_count; /* number of elements in tcp_cnx */
+ pj_turn_tcp_data_connection tcp_cnx[PJ_TURN_MAX_TCP_CNX]; /* peer dedicated data connections throught the TURN server */
};
@@ -82,6 +107,12 @@ static void turn_on_rx_data(pj_turn_session *sess,
static void turn_on_state(pj_turn_session *sess,
pj_turn_state_t old_state,
pj_turn_state_t new_state);
+static void turn_on_peer_connection(pj_turn_session *sess,
+ pj_uint32_t conn_id,
+ const pj_sockaddr_t *peer_addr,
+ unsigned addr_len,
+ pj_status_t status);
+
static pj_bool_t on_data_read(pj_activesock_t *asock,
void *data,
@@ -97,6 +128,26 @@ static void turn_sock_on_destroy(void *comp);
static void destroy(pj_turn_sock *turn_sock);
static void timer_cb(pj_timer_heap_t *th, pj_timer_entry *e);
+static pj_bool_t on_peer_data_read(pj_activesock_t *asock,
+ void *data,
+ pj_size_t size,
+ pj_status_t status,
+ pj_size_t *remainder);
+static pj_bool_t on_peer_connect_complete(pj_activesock_t *asock,
+ pj_status_t status);
+static pj_status_t on_tcp_stun_send_msg(pj_stun_session *sess,
+ void *token,
+ const void *pkt,
+ pj_size_t pkt_size,
+ const pj_sockaddr_t *dst_addr,
+ unsigned addr_len);
+static void on_tcp_stun_request_complete(pj_stun_session *sess,
+ pj_status_t status,
+ void *token,
+ pj_stun_tx_data *tdata,
+ const pj_stun_msg *response,
+ const pj_sockaddr_t *src_addr,
+ unsigned src_addr_len);
/* Init config */
PJ_DEF(void) pj_turn_sock_cfg_default(pj_turn_sock_cfg *cfg)
@@ -193,6 +244,7 @@ PJ_DEF(pj_status_t) pj_turn_sock_create(pj_stun_config *cfg,
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;
+ sess_cb.on_peer_connection = &turn_on_peer_connection;
status = pj_turn_session_create(cfg, pool->obj_name, af, conn_type,
turn_sock->grp_lock, &sess_cb, 0,
turn_sock, &turn_sock->sess);
@@ -238,6 +290,9 @@ static void destroy(pj_turn_sock *turn_sock)
pj_turn_session_shutdown(turn_sock->sess);
if (turn_sock->active_sock)
pj_activesock_close(turn_sock->active_sock);
+ for (int i=0; i < turn_sock->tcp_cnx_count; ++i) {
+ pj_activesock_close(turn_sock->tcp_cnx[i].active_tcp_sock);
+ }
pj_grp_lock_dec_ref(turn_sock->grp_lock);
pj_grp_lock_release(turn_sock->grp_lock);
}
@@ -302,6 +357,34 @@ static void sess_fail(pj_turn_sock *turn_sock, const char *title,
}
}
+static void peer_cnx_fail(pj_turn_tcp_data_connection *tcp_cnx,
+ const char *title, pj_status_t status)
+{
+ pj_turn_sock *turn_sock = tcp_cnx->turn_sock;
+
+ show_err(turn_sock, title, status);
+ if (tcp_cnx->stun_sess) {
+ pj_stun_session_destroy(tcp_cnx->stun_sess);
+ tcp_cnx->stun_sess = NULL;
+ }
+ if (tcp_cnx->active_tcp_sock) {
+ for (int i=0; i < turn_sock->tcp_cnx_count; ++i) {
+ if (&turn_sock->tcp_cnx[i] == tcp_cnx) {
+ turn_on_peer_connection(turn_sock->sess, tcp_cnx->id,
+ &tcp_cnx->peer_addr,
+ tcp_cnx->peer_addr_len,
+ PJ_EEOF);
+ pj_activesock_close(tcp_cnx->active_tcp_sock);
+ tcp_cnx->active_tcp_sock = NULL;
+ tcp_cnx->flags = 0;
+ if (i == turn_sock->tcp_cnx_count-1)
+ --turn_sock->tcp_cnx_count;
+ break;
+ }
+ }
+ }
+}
+
/*
* Set user data.
*/
@@ -411,6 +494,9 @@ PJ_DEF(pj_status_t) pj_turn_sock_alloc(pj_turn_sock *turn_sock,
/* Set credental */
if (cred) {
+ // save credentials for peer/TCP connections
+ if (param->peer_conn_type == PJ_TURN_TP_TCP)
+ pj_memcpy(&turn_sock->cred, cred, sizeof(turn_sock->cred));
status = pj_turn_session_set_credential(turn_sock->sess, cred);
if (status != PJ_SUCCESS) {
sess_fail(turn_sock, "Error setting credential", status);
@@ -681,7 +767,32 @@ static pj_status_t turn_on_send_pkt(pj_turn_session *sess,
&turn_sock->send_key, pkt, &len, 0,
dst_addr, dst_addr_len);
} else {
- status = pj_activesock_send(turn_sock->active_sock,
+ /* With TCP peer connection filter by address
+ * if packet is for the server or the peer
+ */
+ pj_activesock_t *asock = NULL;
+ pj_turn_session_info info;
+ pj_turn_session_get_info(turn_sock->sess, &info);
+ if (pj_sockaddr_cmp(&info.server, dst_addr) &&
+ turn_sock->alloc_param.peer_conn_type == PJ_TURN_TP_TCP) {
+ for (int i=0; i < turn_sock->tcp_cnx_count; ++i) {
+ pj_turn_tcp_data_connection *tcp_cnx = &turn_sock->tcp_cnx[i];
+ if ((tcp_cnx->flags & CONNECTION_READY) == 0)
+ continue;
+ if (!pj_sockaddr_cmp(&tcp_cnx->peer_addr, dst_addr)) {
+ asock = tcp_cnx->active_tcp_sock;
+ break;
+ }
+ }
+ if (!asock) {
+ status = PJ_ENOTFOUND;
+ show_err(turn_sock, "socket send()", status);
+ return status;
+ }
+ } else {
+ asock = turn_sock->active_sock;
+ }
+ status = pj_activesock_send(asock,
&turn_sock->send_key, pkt, &len, 0);
}
if (status != PJ_SUCCESS && status != PJ_EPENDING) {
@@ -935,4 +1046,365 @@ static void turn_on_state(pj_turn_session *sess,
}
}
+static void turn_on_peer_connection(pj_turn_session *sess,
+ pj_uint32_t conn_id,
+ const pj_sockaddr_t *peer_addr,
+ unsigned addr_len,
+ pj_status_t status)
+{
+ pj_turn_sock *turn_sock = (pj_turn_sock*) pj_turn_session_get_user_data(sess);
+ if (turn_sock == NULL || turn_sock->is_destroying) {
+ /* We've been destroyed */
+ return;
+ }
+
+ if (turn_sock->cb.on_peer_connection) {
+ (*turn_sock->cb.on_peer_connection)(turn_sock, conn_id,
+ peer_addr, addr_len,
+ status);
+ }
+}
+
+PJ_DECL(pj_status_t) pj_turn_connect_peer(pj_turn_sock *turn_sock,
+ pj_uint32_t conn_id,
+ const pj_sockaddr_t *peer_addr,
+ unsigned addr_len)
+{
+ pj_status_t status;
+ pj_turn_tcp_data_connection *new_tcp_cnx = NULL;
+
+ for (int i=0; i < turn_sock->tcp_cnx_count; ++i) {
+ pj_turn_tcp_data_connection *tcp_cnx = &turn_sock->tcp_cnx[i];
+ if ((tcp_cnx->flags & CONNECTION_USED) == 0) {
+ new_tcp_cnx = tcp_cnx;
+ continue;
+ }
+ if (tcp_cnx->id == conn_id)
+ // TODO: need log
+ return PJ_EINVAL; // TODO: need better error code