Commit 78c20768 authored by Ghislain MARY's avatar Ghislain MARY

Handle TURN with ICE.

parent a2a772ff
......@@ -123,6 +123,7 @@ typedef struct _IceSession {
uint8_t max_connectivity_checks; /**< Configuration parameter to limit the number of connectivity checks performed by the agent (default is 100) */
uint8_t keepalive_timeout; /**< Configuration parameter to define the timeout between each keepalive packets (default is 15s) */
bool_t forced_relay; /**< Force use of relay by modifying the local and reflexive candidates */
bool_t turn_enabled; /**< TURN protocol enabled */
} IceSession;
typedef struct _IceStunServerCheckTransaction {
......@@ -500,6 +501,13 @@ MS2_PUBLIC int ice_session_gathering_duration(IceSession *session);
*/
MS2_PUBLIC void ice_session_enable_forced_relay(IceSession *session, bool_t enable);
/**
* Enable TURN protol.
* @param session A pointer to a session
* @param enable A boolean value telling whether to enable TURN protocol or not.
*/
MS2_PUBLIC void ice_session_enable_turn(IceSession *session, bool_t enable);
/**
* Tell the average round trip time during the gathering process for an ICE session in ms.
*
......
......@@ -128,11 +128,14 @@ typedef struct {
MSStunErrorCode error_code;
MSStunAddress mapped_address;
MSStunAddress xor_mapped_address;
MSStunAddress xor_relayed_address;
uint32_t change_request;
uint32_t fingerprint;
uint32_t priority;
uint64_t ice_controlling;
uint64_t ice_controlled;
uint32_t lifetime;
uint8_t requested_transport;
bool_t include_username_attribute;
bool_t has_error_code;
bool_t has_message_integrity;
......@@ -140,10 +143,13 @@ typedef struct {
bool_t has_fingerprint;
bool_t has_mapped_address;
bool_t has_xor_mapped_address;
bool_t has_xor_relayed_address;
bool_t has_priority;
bool_t has_use_candidate;
bool_t has_ice_controlling;
bool_t has_ice_controlled;
bool_t has_lifetime;
bool_t has_requested_transport;
} MSStunMessage;
......@@ -194,6 +200,8 @@ MS2_PUBLIC const MSStunAddress * ms_stun_message_get_mapped_address(const MSStun
MS2_PUBLIC void ms_stun_message_set_mapped_address(MSStunMessage *msg, MSStunAddress mapped_address);
MS2_PUBLIC const MSStunAddress * ms_stun_message_get_xor_mapped_address(const MSStunMessage *msg);
MS2_PUBLIC void ms_stun_message_set_xor_mapped_address(MSStunMessage *msg, MSStunAddress xor_mapped_address);
MS2_PUBLIC const MSStunAddress * ms_stun_message_get_xor_relayed_address(const MSStunMessage *msg);
MS2_PUBLIC void ms_stun_message_set_xor_relayed_address(MSStunMessage *msg, MSStunAddress xor_relayed_address);
MS2_PUBLIC void ms_stun_message_enable_change_ip(MSStunMessage *msg, bool_t enable);
MS2_PUBLIC void ms_stun_message_enable_change_port(MSStunMessage *msg, bool_t enable);
......@@ -212,6 +220,13 @@ MS2_PUBLIC void ms_stun_message_set_ice_controlled(MSStunMessage *msg, uint64_t
MS2_PUBLIC bool_t ms_stun_message_dummy_message_integrity_enabled(const MSStunMessage *msg);
MS2_PUBLIC void ms_stun_message_enable_dummy_message_integrity(MSStunMessage *msg, bool_t enable);
MS2_PUBLIC MSStunMessage * ms_turn_allocate_request_create(void);
MS2_PUBLIC bool_t ms_stun_message_has_requested_transport(const MSStunMessage *msg);
MS2_PUBLIC uint8_t ms_stun_message_get_requested_transport(const MSStunMessage *msg);
MS2_PUBLIC bool_t ms_stun_message_has_lifetime(const MSStunMessage *msg);
MS2_PUBLIC uint32_t ms_stun_message_get_lifetime(const MSStunMessage *msg);
MS2_PUBLIC void ms_stun_message_set_lifetime(MSStunMessage *msg, uint32_t lifetime);
#ifdef __cplusplus
}
#endif
......
......@@ -127,6 +127,7 @@ static int32_t ice_compare_time(MSTimeSpec ts1, MSTimeSpec ts2);
static char * ice_inet_ntoa(struct sockaddr *addr, int addrlen, char *dest, int destlen);
static void transactionID2string(const UInt96 *tr_id, char *tr_id_str);
static void ice_send_stun_server_binding_request(RtpTransport *rtptp, const struct sockaddr *server, socklen_t addrlen, IceStunServerCheck *check);
static void ice_send_turn_server_allocate_request(RtpTransport *rtptp, const struct sockaddr *server, socklen_t addrlen, IceStunServerCheck *check);
static int ice_compare_transport_addresses(const IceTransportAddress *ta1, const IceTransportAddress *ta2);
static int ice_compare_pair_priorities(const IceCandidatePair *p1, const IceCandidatePair *p2);
static int ice_compare_pairs(const IceCandidatePair *p1, const IceCandidatePair *p2);
......@@ -940,7 +941,11 @@ static void ice_check_list_gather_candidates(IceCheckList *cl, Session_Index *si
check->srcport = rtp_session_get_local_port(cl->rtp_session);
if (si->index == 0) {
check->next_transmission_time = ice_add_ms(curtime, ICE_DEFAULT_RTO_DURATION);
ice_send_stun_server_binding_request(rtptp, (struct sockaddr *)&cl->session->ss, cl->session->ss_len, check);
if (cl->session->turn_enabled) {
ice_send_turn_server_allocate_request(rtptp, (struct sockaddr *)&cl->session->ss, cl->session->ss_len, check);
} else {
ice_send_stun_server_binding_request(rtptp, (struct sockaddr *)&cl->session->ss, cl->session->ss_len, check);
}
} else {
check->next_transmission_time = ice_add_ms(curtime, 2 * si->index * ICE_DEFAULT_TA_DURATION);
}
......@@ -1020,6 +1025,11 @@ void ice_session_enable_forced_relay(IceSession *session, bool_t enable)
session->forced_relay = enable;
}
void ice_session_enable_turn(IceSession *session, bool_t enable)
{
session->turn_enabled = enable;
}
static void ice_transaction_sum_gathering_round_trip_time(const IceStunServerCheckTransaction *transaction, StunRequestRoundTripTime *rtt)
{
if ((transaction->response_time.tv_sec != 0) && (transaction->response_time.tv_nsec != 0)) {
......@@ -1141,14 +1151,12 @@ static int ice_send_message_to_stun_addr(const RtpTransport * rtpt,char* buff,si
return ice_send_message_to_socket(rtpt, buff, len,(struct sockaddr *)&dest_addr, sizeof(dest_addr));
}
static void ice_send_stun_server_binding_request(RtpTransport *rtptp, const struct sockaddr *server, socklen_t addrlen, IceStunServerCheck *check)
static void ice_send_stun_request(RtpTransport *rtptp, const struct sockaddr *server, socklen_t addrlen, IceStunServerCheck *check, MSStunMessage *msg, const char *request_type)
{
MSStunMessage *msg;
char *buf = NULL;
int len;
char tr_id_str[25];
msg = ms_stun_binding_request_create();
len = ms_stun_message_encode(msg, &buf);
if (len > 0) {
IceStunServerCheckTransaction *transaction = ms_new0(IceStunServerCheckTransaction, 1);
......@@ -1156,31 +1164,47 @@ static void ice_send_stun_server_binding_request(RtpTransport *rtptp, const stru
transaction->transactionID = ms_stun_message_get_tr_id(msg);
check->transactions = ms_list_append(check->transactions, transaction);
transactionID2string(&transaction->transactionID, tr_id_str);
ms_message("ice: Send STUN binding request from port %u [%s]", check->srcport, tr_id_str);
ms_message("ice: Send %s from port %u [%s]", request_type, check->srcport, tr_id_str);
ice_send_message_to_socket(rtptp, buf, len, server, addrlen);
} else {
ms_error("ice: encoding stun binding request from port %u [%s] failed", check->srcport, tr_id_str);
ms_error("ice: encoding %s from port %u [%s] failed", request_type, check->srcport, tr_id_str);
}
if (buf != NULL) ms_free(buf);
ms_stun_message_destroy(msg);
}
static int ice_parse_stun_server_binding_response(const MSStunMessage *msg, char *addr, int addr_len, int *port)
static void ice_send_stun_server_binding_request(RtpTransport *rtptp, const struct sockaddr *server, socklen_t addrlen, IceStunServerCheck *check)
{
struct sockaddr_in addr_in;
const MSStunAddress *stunaddr;
MSStunMessage *msg = ms_stun_binding_request_create();
ice_send_stun_request(rtptp, server, addrlen, check, msg, "STUN binding request");
ms_stun_message_destroy(msg);
}
memset(&addr_in, 0, sizeof(addr_in));
stunaddr = ms_stun_message_get_xor_mapped_address(msg);
static int ice_parse_stun_server_response(const MSStunMessage *msg, MSStunAddress *srflx_address, MSStunAddress *relay_address)
{
const MSStunAddress *stunaddr = ms_stun_message_get_xor_mapped_address(msg);
if (stunaddr == NULL) stunaddr = ms_stun_message_get_mapped_address(msg);
if (stunaddr == NULL) return -1;
*port = stunaddr->ipv4.port;
addr_in.sin_addr.s_addr = htonl(stunaddr->ipv4.addr);
*srflx_address = *stunaddr;
stunaddr = ms_stun_message_get_xor_relayed_address(msg);
if (stunaddr != NULL) *relay_address = *stunaddr;
return 0;
}
static void stun_address_to_str(const MSStunAddress *stun_address, char *addr, int addr_len)
{
struct sockaddr_in addr_in;
memset(&addr_in, 0, sizeof(addr_in));
addr_in.sin_addr.s_addr = htonl(stun_address->ipv4.addr);
addr_in.sin_family = AF_INET;
addr_in.sin_port = htons(*port);
addr_in.sin_port = htons(stun_address->ipv4.port);
ice_inet_ntoa((struct sockaddr *)&addr_in, sizeof(addr_in), addr, addr_len);
return 0;
}
static void ice_send_turn_server_allocate_request(RtpTransport *rtptp, const struct sockaddr *server, socklen_t addrlen, IceStunServerCheck *check)
{
MSStunMessage *msg = ms_turn_allocate_request_create();
ice_send_stun_request(rtptp, server, addrlen, check, msg, "TURN allocate request");
ms_stun_message_destroy(msg);
}
/* Send a STUN binding request for ICE connectivity checks according to 7.1.2. */
......@@ -1974,8 +1998,10 @@ static void ice_handle_received_binding_response(IceCheckList *cl, RtpSession *r
MSList *elem;
MSList *base_elem;
OrtpEvent *ev;
char addr[64];
int port;
MSStunAddress srflx_addr;
MSStunAddress relay_addr;
char srflx_addr_str[64];
char relay_addr_str[64];
RtpTransport *rtptp=NULL;
int componentID;
const struct sockaddr_in *servaddr = (const struct sockaddr_in *)&cl->session->ss;
......@@ -1994,12 +2020,22 @@ static void ice_handle_received_binding_response(IceCheckList *cl, RtpSession *r
transaction = (IceStunServerCheckTransaction *)elem->data;
if (transaction != NULL) {
componentID = ice_get_componentID_from_rtp_session(evt_data);
if ((componentID > 0) && (ice_parse_stun_server_binding_response(msg, addr, sizeof(addr), &port) >= 0)) {
memset(&srflx_addr, 0, sizeof(srflx_addr));
memset(&relay_addr, 0, sizeof(relay_addr));
if ((componentID > 0) && (ice_parse_stun_server_response(msg, &srflx_addr, &relay_addr) >= 0)) {
base_elem = ms_list_find_custom(cl->local_candidates, (MSCompareFunc)ice_find_host_candidate, &componentID);
if (base_elem != NULL) {
candidate = (IceCandidate *)base_elem->data;
ice_add_local_candidate(cl, "srflx", addr, port, componentID, candidate);
ms_message("ice: Add candidate obtained by STUN: %s:%u:srflx", addr, port);
if (srflx_addr.ipv4.port != 0) {
stun_address_to_str(&srflx_addr, srflx_addr_str, sizeof(srflx_addr_str));
candidate = ice_add_local_candidate(cl, "srflx", srflx_addr_str, srflx_addr.ipv4.port, componentID, candidate);
ms_message("ice: Add candidate obtained by STUN/TURN: %s:%u:srflx", srflx_addr_str, srflx_addr.ipv4.port);
if (relay_addr.ipv4.port != 0) {
stun_address_to_str(&relay_addr, relay_addr_str, sizeof(relay_addr_str));
ice_add_local_candidate(cl, "relay", relay_addr_str, relay_addr.ipv4.port, componentID, candidate);
ms_message("ice: Add candidate obtained by STUN/TURN: %s:%u:relay", relay_addr_str, relay_addr.ipv4.port);
}
}
}
transaction->response_time = evt_data->ts;
check->responded = TRUE;
......@@ -2200,7 +2236,6 @@ static IceCandidate * ice_candidate_new(const char *type, const char *ip, int po
switch (candidate->type) {
case ICT_HostCandidate:
case ICT_RelayedCandidate:
candidate->base = candidate;
break;
default:
......@@ -3165,7 +3200,11 @@ static void ice_send_stun_server_checks(IceStunServerCheck *check, IceCheckList
if (ice_compare_time(curtime, check->next_transmission_time) >= 0) {
if (ms_list_size(check->transactions) < ICE_MAX_STUN_REQUEST_RETRANSMISSIONS) {
check->next_transmission_time = ice_add_ms(curtime, ICE_DEFAULT_RTO_DURATION);
ice_send_stun_server_binding_request(check->rtptp, (struct sockaddr *)&cl->session->ss, cl->session->ss_len, check);
if (cl->session->turn_enabled) {
ice_send_turn_server_allocate_request(check->rtptp, (struct sockaddr *)&cl->session->ss, cl->session->ss_len, check);
} else {
ice_send_stun_server_binding_request(check->rtptp, (struct sockaddr *)&cl->session->ss, cl->session->ss_len, check);
}
}
}
}
......
......@@ -22,6 +22,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <bctoolbox/crypto.h>
#define IANA_PROTOCOL_NUMBERS_UDP 17
#define STUN_FLAG_CHANGE_IP 0x04
#define STUN_FLAG_CHANGE_PORT 0x02
......@@ -236,6 +238,14 @@ static void encode_fingerprint(StunMessageEncoder *encoder) {
encode32(encoder, fingerprint);
}
static void encode_requested_transport(StunMessageEncoder *encoder, uint8_t requested_transport) {
encode16(encoder, MS_TURN_ATTR_REQUESTED_TRANSPORT);
encode16(encoder, 4);
encode8(encoder, requested_transport);
encode8(encoder, 0);
encode16(encoder, 0);
}
typedef struct {
const char *buffer;
......@@ -384,7 +394,7 @@ static uint16_t decode_error_code(StunMessageDecoder *decoder, uint16_t length,
if (reason_length > 0) {
*reason = ms_malloc(reason_length + 1);
memcpy(*reason, decode(decoder, reason_length), reason_length);
*reason[reason_length] = '\0';
(*reason)[reason_length] = '\0';
}
return number;
}
......@@ -430,6 +440,15 @@ static uint64_t decode_ice_control(StunMessageDecoder *decoder, uint16_t length)
return decode64(decoder);
}
static uint32_t decode_lifetime(StunMessageDecoder *decoder, uint16_t length) {
if (length != 4) {
ms_warning("STUN lifetime attribute with wrong length");
decoder->error = TRUE;
return 0;
}
return decode32(decoder);
}
MSStunAddress4 ms_stun_hostname_to_stun_addr(const char *hostname, uint16_t default_port) {
char *host;
......@@ -670,6 +689,17 @@ MSStunMessage * ms_stun_message_create_from_buffer_parsing(const char *buf, size
case MS_ICE_ATTR_ICE_CONTROLLING:
ms_stun_message_set_ice_controlling(msg, decode_ice_control(&decoder, length));
break;
case MS_TURN_ATTR_XOR_RELAYED_ADDRESS:
{
MSStunAddress stun_addr = decode_addr(&decoder, length);
stun_addr.ipv4.addr ^= MS_STUN_MAGIC_COOKIE;
stun_addr.ipv4.port ^= MS_STUN_MAGIC_COOKIE >> 16;
ms_stun_message_set_xor_relayed_address(msg, stun_addr);
}
break;
case MS_TURN_ATTR_LIFETIME:
ms_stun_message_set_lifetime(msg, decode_lifetime(&decoder, length));
break;
default:
if (type <= 0x7FFF) {
ms_error("STUN unknown Comprehension-Required attribute: 0x%04x", type);
......@@ -758,6 +788,11 @@ size_t ms_stun_message_encode(const MSStunMessage *msg, char **buf) {
}
stun_addr = ms_stun_message_get_xor_mapped_address(msg);
if (stun_addr != NULL) encode_addr(&encoder, MS_STUN_ATTR_XOR_MAPPED_ADDRESS, stun_addr);
stun_addr = ms_stun_message_get_xor_relayed_address(msg);
if (stun_addr != NULL) encode_addr(&encoder, MS_TURN_ATTR_XOR_RELAYED_ADDRESS, stun_addr);
if (ms_stun_message_has_requested_transport(msg)) encode_requested_transport(&encoder, ms_stun_message_get_requested_transport(msg));
if (ms_stun_message_has_priority(msg)) encode_priority(&encoder, ms_stun_message_get_priority(msg));
if (ms_stun_message_use_candidate_enabled(msg)) encode_use_candidate(&encoder);
if (ms_stun_message_has_ice_controlled(msg))
......@@ -903,6 +938,16 @@ void ms_stun_message_set_xor_mapped_address(MSStunMessage *msg, MSStunAddress xo
msg->has_xor_mapped_address = TRUE;
}
const MSStunAddress * ms_stun_message_get_xor_relayed_address(const MSStunMessage *msg) {
if (msg->has_xor_relayed_address) return &msg->xor_relayed_address;
return NULL;
}
void ms_stun_message_set_xor_relayed_address(MSStunMessage *msg, MSStunAddress xor_relayed_address) {
msg->xor_relayed_address = xor_relayed_address;
msg->has_xor_relayed_address = TRUE;
}
void ms_stun_message_enable_change_ip(MSStunMessage *msg, bool_t enable) {
if (enable) msg->change_request |= STUN_FLAG_CHANGE_IP;
else {
......@@ -973,3 +1018,31 @@ bool_t ms_stun_message_dummy_message_integrity_enabled(const MSStunMessage *msg)
void ms_stun_message_enable_dummy_message_integrity(MSStunMessage *msg, bool_t enable) {
msg->has_dummy_message_integrity = enable;
}
MSStunMessage * ms_turn_allocate_request_create(void) {
MSStunMessage *msg = ms_stun_message_create(MS_STUN_TYPE_REQUEST, MS_TURN_METHOD_ALLOCATE);
msg->requested_transport = IANA_PROTOCOL_NUMBERS_UDP;
msg->has_requested_transport = TRUE;
return msg;
}
bool_t ms_stun_message_has_requested_transport(const MSStunMessage *msg) {
return msg->has_requested_transport;
}
uint8_t ms_stun_message_get_requested_transport(const MSStunMessage *msg) {
return msg->requested_transport;
}
bool_t ms_stun_message_has_lifetime(const MSStunMessage *msg) {
return msg->has_lifetime;
}
uint32_t ms_stun_message_get_lifetime(const MSStunMessage *msg) {
return msg->lifetime;
}
void ms_stun_message_set_lifetime(MSStunMessage *msg, uint32_t lifetime) {
msg->lifetime = lifetime;
msg->has_lifetime = TRUE;
}
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