Commit 03ce5e8a authored by Simon Morlat's avatar Simon Morlat
Browse files

Fix issue where DTLS handshake cannot take place when the media path goes through a TURN server

parent 37215342
......@@ -1564,26 +1564,52 @@ static int ms_turn_rtp_endpoint_recvfrom(RtpTransport *rtptp, mblk_t *msg, int f
return msgsize;
}
/* This function checks whether the specified source address requires to go through the TURN relay.
* The convention is that when source address is the relay address of the TURN server, then it has to go through TURN.
* One exception: if the address is INADDR_ANY or has family AF_UNSPEC, which means that the source address wasn't specified
* by the originator of the packet, then the default policy of the context in force_rtp_sending_via_relay is used.
* The code is a bit complex because we have to take into account that the source address is a V4 mapped address.
*/
static bool_t ms_turn_rtp_endpoint_send_via_turn_relay(MSTurnContext *context, const struct sockaddr *from, socklen_t fromlen) {
struct sockaddr_storage relay_ss;
struct sockaddr *relay_sa = (struct sockaddr *)&relay_ss;
socklen_t relay_sa_len = sizeof(relay_ss);
if (from->sa_family == AF_UNSPEC || fromlen == 0) return context->force_rtp_sending_via_relay;
memset(relay_sa, 0, relay_sa_len);
ms_stun_address_to_sockaddr(&context->relay_addr, relay_sa, &relay_sa_len);
if (relay_sa->sa_family != from->sa_family) return FALSE;
if (relay_sa->sa_family == AF_INET) {
struct sockaddr_in *relay_sa_in = (struct sockaddr_in *)relay_sa;
struct sockaddr_in *from_in = (struct sockaddr_in *)from;
return (relay_sa_in->sin_port == from_in->sin_port) && (relay_sa_in->sin_addr.s_addr == from_in->sin_addr.s_addr);
struct sockaddr_storage removed_v4mapping;
socklen_t removed_v4mapping_len = sizeof(removed_v4mapping);
if (from->sa_family == AF_INET6){
/* Handle the case of a V4 mapped address. */
bctbx_sockaddr_remove_v4_mapping(from, (struct sockaddr*)&removed_v4mapping, &removed_v4mapping_len);
if (removed_v4mapping.ss_family == AF_INET){
struct sockaddr_in *from_in = (struct sockaddr_in *)&removed_v4mapping;
return relay_sa_in->sin_addr.s_addr == from_in->sin_addr.s_addr
|| (context->force_rtp_sending_via_relay && from_in->sin_addr.s_addr == 0);
}else{
/* It is a pure IPv6, so this can't match our IPv4 relay address.*/
return FALSE;
}
}else{
struct sockaddr_in *from_in = (struct sockaddr_in *)from;
return relay_sa_in->sin_addr.s_addr == from_in->sin_addr.s_addr
|| (context->force_rtp_sending_via_relay && from_in->sin_addr.s_addr == 0);
}
} else if (relay_sa->sa_family == AF_INET6) {
struct sockaddr_in6 *relay_sa_in6 = (struct sockaddr_in6 *)relay_sa;
struct sockaddr_in6 *from_in6 = (struct sockaddr_in6 *)from;
return (relay_sa_in6->sin6_port == from_in6->sin6_port) && (memcmp(&relay_sa_in6->sin6_addr, &from_in6->sin6_addr, sizeof(from_in6->sin6_addr)) == 0);
} else return FALSE;
return memcmp(&relay_sa_in6->sin6_addr, &from_in6->sin6_addr, sizeof(from_in6->sin6_addr)) == 0
|| (context->force_rtp_sending_via_relay && memcmp(&from_in6->sin6_addr, &in6addr_any, sizeof(from_in6->sin6_addr)) == 0);
}
return FALSE;
}
static bool_t ms_turn_rtp_endpoint_send_via_turn_server(MSTurnContext *context, const struct sockaddr *from, socklen_t fromlen) {
static bool_t ms_turn_rtp_endpoint_should_be_sent_to_turn_server(MSTurnContext *context, const struct sockaddr *from, socklen_t fromlen) {
struct sockaddr *turn_server_sa = (struct sockaddr *)&context->turn_server_addr;
if (turn_server_sa->sa_family != from->sa_family) return FALSE;
......@@ -1601,17 +1627,21 @@ static bool_t ms_turn_rtp_endpoint_send_via_turn_server(MSTurnContext *context,
static int ms_turn_rtp_endpoint_sendto(RtpTransport *rtptp, mblk_t *msg, int flags, const struct sockaddr *to, socklen_t tolen) {
MSTurnContext *context = (MSTurnContext *)rtptp->data;
MSStunMessage *stun_msg = NULL;
bool_t rtp_packet = FALSE;
bool_t send_via_turn_tcp = FALSE;
int ret = 0;
int ret = msgdsize(msg);
int sub_ret = 0;
mblk_t *new_msg = NULL;
struct sockaddr_storage sourceAddr;
socklen_t sourceAddrLen;
if ((context != NULL) && (context->rtp_session != NULL)) {
if ((msgdsize(msg) >= RTP_FIXED_HEADER_SIZE) && (rtp_get_version(msg) == 2)) rtp_packet = TRUE;
ortp_recvaddr_to_sockaddr(&msg->recv_addr, (struct sockaddr*) &sourceAddr, &sourceAddrLen);
if ((rtp_packet && context->force_rtp_sending_via_relay) || ms_turn_rtp_endpoint_send_via_turn_relay(context, (struct sockaddr*) &sourceAddr, sourceAddrLen)) {
if (ms_turn_rtp_endpoint_should_be_sent_to_turn_server(context, to, tolen)) {
ms_message("Sent to TURN server.");
if (context->transport != MS_TURN_CONTEXT_TRANSPORT_UDP) {
send_via_turn_tcp = TRUE;
}
}else if (ms_turn_rtp_endpoint_send_via_turn_relay(context, (struct sockaddr*) &sourceAddr, sourceAddrLen)) {
if (ms_turn_context_get_state(context) >= MS_TURN_CONTEXT_STATE_CHANNEL_BOUND) {
/* Use a TURN ChannelData message */
new_msg = allocb(4, 0);
......@@ -1632,6 +1662,7 @@ static int ms_turn_rtp_endpoint_sendto(RtpTransport *rtptp, mblk_t *msg, int fla
size_t len;
uint8_t *data;
uint16_t datalen;
msgpullup(msg, -1);
datalen = (uint16_t)(msg->b_wptr - msg->b_rptr);
bctbx_sockaddr_ipv6_to_ipv4(to, (struct sockaddr *)&realto, &realtolen);
......@@ -1649,29 +1680,22 @@ static int ms_turn_rtp_endpoint_sendto(RtpTransport *rtptp, mblk_t *msg, int fla
to = (const struct sockaddr *)&context->turn_server_addr;
tolen = context->turn_server_addrlen;
if (context->transport != MS_TURN_CONTEXT_TRANSPORT_UDP) {
send_via_turn_tcp = TRUE;
}
} else if (ms_turn_rtp_endpoint_send_via_turn_server(context, to, tolen)) {
// This is not a RTP packet and it is in destination of the turn server
// then it's a STUN packet and it still should go through the turn TCP client
// if the transport is not set to UDP
if (context->transport != MS_TURN_CONTEXT_TRANSPORT_UDP) {
send_via_turn_tcp = TRUE;
}
}
if (send_via_turn_tcp && context->turn_tcp_client) {
ret = ms_turn_tcp_client_sendto(context->turn_tcp_client, msg, flags, to, tolen);
sub_ret = ms_turn_tcp_client_sendto(context->turn_tcp_client, msg, flags, to, tolen);
} else {
ret = rtp_session_sendto(context->rtp_session, context->type == MS_TURN_CONTEXT_TYPE_RTP, msg, flags, to, tolen);
sub_ret = rtp_session_sendto(context->rtp_session, context->type == MS_TURN_CONTEXT_TYPE_RTP, msg, flags, to, tolen);
}
}
if (stun_msg != NULL) ms_stun_message_destroy(stun_msg);
if (new_msg != NULL) {
freemsg(new_msg);
}
return ret;
return sub_ret > 0 ? ret : sub_ret; /* The sendto() function shall not return more or less than requested. The same amount, otherwise an error.*/
}
static void ms_turn_rtp_endpoint_close(RtpTransport *rtptp) {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment