Commit be03b19f authored by Youness Alaoui's avatar Youness Alaoui

Add support for tcp turn in the agent's code. Thanks to Olivier Crete

parent d34c720b
......@@ -58,7 +58,7 @@
#include "debug.h"
#include "socket.h"
#include "udp-turn.h"
#include "stun/usages/turn.h"
#include "candidate.h"
#include "component.h"
#include "conncheck.h"
......@@ -102,7 +102,6 @@ enum
N_SIGNALS,
};
static guint signals[N_SIGNALS];
static gboolean priv_attach_stream_component (NiceAgent *agent,
......@@ -110,6 +109,16 @@ static gboolean priv_attach_stream_component (NiceAgent *agent,
Component *component);
static void priv_detach_stream_component (Stream *stream, Component *component);
static StunUsageTurnCompatibility
priv_agent_to_turn_compatibility (NiceAgent *agent) {
return agent->compatibility == NICE_COMPATIBILITY_DRAFT19 ?
STUN_USAGE_TURN_COMPATIBILITY_DRAFT9 :
agent->compatibility == NICE_COMPATIBILITY_GOOGLE ?
STUN_USAGE_TURN_COMPATIBILITY_GOOGLE :
agent->compatibility == NICE_COMPATIBILITY_MSN ?
STUN_USAGE_TURN_COMPATIBILITY_MSN : STUN_USAGE_TURN_COMPATIBILITY_DRAFT9;
}
Stream *agent_find_stream (NiceAgent *agent, guint stream_id)
{
GSList *i;
......@@ -646,8 +655,7 @@ agent_candidate_pair_priority (NiceAgent *agent, NiceCandidate *local, NiceCandi
static gboolean
priv_add_new_candidate_discovery_stun (NiceAgent *agent,
NiceCandidate *host_candidate, NiceAddress server,
Stream *stream, guint component_id,
NiceAddress *addr)
Stream *stream, guint component_id)
{
CandidateDiscovery *cdisco;
GSList *modified_list;
......@@ -679,9 +687,8 @@ priv_add_new_candidate_discovery_stun (NiceAgent *agent,
static gboolean
priv_add_new_candidate_discovery_turn (NiceAgent *agent,
NiceCandidate *host_candidate, NiceAddress server,
Stream *stream, guint component_id,
NiceAddress *addr)
NiceCandidate *host_candidate, TurnServer *turn,
Stream *stream, guint component_id)
{
CandidateDiscovery *cdisco;
GSList *modified_list;
......@@ -692,11 +699,25 @@ priv_add_new_candidate_discovery_turn (NiceAgent *agent,
cdisco = g_slice_new0 (CandidateDiscovery);
if (cdisco) {
modified_list = g_slist_append (agent->discovery_list, cdisco);
priv_agent_to_turn_compatibility (agent);
if (modified_list) {
cdisco->type = NICE_CANDIDATE_TYPE_RELAYED;
cdisco->nicesock = host_candidate->sockptr;
cdisco->server = server;
if (turn->type == NICE_RELAY_TYPE_UDP) {
cdisco->nicesock = host_candidate->sockptr;
} else {
cdisco->nicesock = nice_tcp_turn_socket_new (agent,
&turn->server,
priv_agent_to_turn_compatibility (agent));
if (!cdisco->nicesock) {
agent->discovery_list = g_slist_remove (modified_list, cdisco);
g_slice_free (CandidateDiscovery, cdisco);
return FALSE;
}
}
cdisco->turn = turn;
cdisco->server = turn->server;
cdisco->stream = stream;
cdisco->component = stream_find_component_by_id (stream, component_id);
cdisco->agent = agent;
......@@ -779,10 +800,12 @@ nice_agent_add_stream (
}
NICEAPI_EXPORT void nice_agent_set_relay_info(NiceAgent *agent,
NICEAPI_EXPORT gboolean
nice_agent_set_relay_info(NiceAgent *agent,
guint stream_id, guint component_id,
const gchar *server_ip, guint server_port,
const gchar *username, const gchar *password)
const gchar *username, const gchar *password,
NiceRelayType type)
{
Component *component = NULL;
......@@ -790,21 +813,27 @@ NICEAPI_EXPORT void nice_agent_set_relay_info(NiceAgent *agent,
g_static_rec_mutex_lock (&agent->mutex);
if (agent_find_component (agent, stream_id, component_id, NULL, &component)) {
nice_address_init (&component->turn_server);
if (nice_address_set_from_string (&component->turn_server, server_ip)) {
nice_address_set_port (&component->turn_server, server_port);
TurnServer *turn = g_slice_new0 (TurnServer);
nice_address_init (&turn->server);
if (nice_address_set_from_string (&turn->server, server_ip)) {
nice_address_set_port (&turn->server, server_port);
} else {
g_slice_free (TurnServer, turn);
g_static_rec_mutex_unlock (&agent->mutex);
return FALSE;
}
g_free (component->turn_username);
component->turn_username = g_strdup (username);
g_free (component->turn_password);
component->turn_password = g_strdup (password);
turn->username = g_strdup (username);
turn->password = g_strdup (password);
turn->type = type;
component->turn_servers = g_list_append (component->turn_servers, turn);
}
g_static_rec_mutex_unlock (&agent->mutex);
return TRUE;
}
......@@ -860,8 +889,7 @@ nice_agent_gather_candidates (
host_candidate,
stun_server,
stream,
n + 1 /* component-id */,
addr);
n + 1);
if (res != TRUE) {
/* note: memory allocation failure, return error */
......@@ -870,22 +898,25 @@ nice_agent_gather_candidates (
}
}
if (agent->full_mode &&
component && nice_address_is_valid (&component->turn_server)) {
gboolean res =
priv_add_new_candidate_discovery_turn (agent,
host_candidate,
component->turn_server,
stream,
n + 1 /* component-id */,
addr);
if (res != TRUE) {
/* note: memory allocation failure, return error */
g_error ("Memory allocation failure?");
}
}
if (agent->full_mode && component) {
GList *item;
for (item = component->turn_servers; item; item = item->next) {
TurnServer *turn = item->data;
gboolean res =
priv_add_new_candidate_discovery_turn (agent,
host_candidate,
turn,
stream,
n + 1);
if (res != TRUE) {
/* note: memory allocation failure, return error */
g_error ("Memory allocation failure?");
}
}
}
}
}
......@@ -1307,6 +1338,7 @@ _nice_agent_recv (
{
NiceAddress from;
gint len;
GList *item;
len = nice_socket_recv (socket, &from, buf_len, buf);
......@@ -1329,18 +1361,24 @@ _nice_agent_recv (
return 0;
}
if (nice_address_equal (&from, &component->turn_server)) {
GSList * i = NULL;
for (item = component->turn_servers; item; item = g_list_next (item)) {
TurnServer *turn = item->data;
if (nice_address_equal (&from, &turn->server)) {
GSList * i = NULL;
#ifndef NDEBUG
nice_debug ("Agent %p : Packet received from TURN server candidate.", agent);
nice_debug ("Agent %p : Packet received from TURN server candidate.",
agent);
#endif
for (i = component->local_candidates; i; i = i->next) {
NiceCandidate *cand = i->data;
if (cand->type == NICE_CANDIDATE_TYPE_RELAYED &&
cand->stream_id == stream->id && cand->component_id == component->id) {
len = nice_udp_turn_socket_parse_recv (cand->sockptr, &socket,
&from, len, buf, &from, buf, len);
for (i = component->local_candidates; i; i = i->next) {
NiceCandidate *cand = i->data;
if (cand->type == NICE_CANDIDATE_TYPE_RELAYED &&
cand->stream_id == stream->id &&
cand->component_id == component->id) {
len = nice_udp_turn_socket_parse_recv (cand->sockptr, &socket,
&from, len, buf, &from, buf, len);
}
}
break;
}
}
......
......@@ -98,6 +98,7 @@ typedef enum
NICE_COMPONENT_TYPE_RTCP = 2
} NiceComponentType;
typedef enum
{
NICE_COMPATIBILITY_DRAFT19 = 0,
......@@ -139,14 +140,15 @@ nice_agent_remove_stream (
guint stream_id);
void nice_agent_set_relay_info(
gboolean nice_agent_set_relay_info(
NiceAgent *agent,
guint stream_id,
guint component_id,
const gchar *server_ip,
guint server_port,
const gchar *username,
const gchar *password);
const gchar *password,
NiceRelayType type);
void
nice_agent_gather_candidates (
......
......@@ -64,8 +64,25 @@ typedef enum
NICE_CANDIDATE_TRANSPORT_UDP,
} NiceCandidateTransport;
typedef enum {
NICE_RELAY_TYPE_UDP,
NICE_RELAY_TYPE_TCP,
NICE_RELAY_TYPE_TLS
} NiceRelayType;
typedef struct _NiceCandidate NiceCandidate;
typedef struct _TurnServer TurnServer;
struct _TurnServer
{
NiceAddress server; /**< TURN server address */
gchar *username; /**< TURN username */
gchar *password; /**< TURN password */
NiceRelayType type; /**< TURN type */
};
struct _NiceCandidate
{
NiceCandidateType type;
......@@ -79,6 +96,7 @@ struct _NiceCandidate
NiceSocket *sockptr;
gchar *username; /* pointer to a NULL-terminated username string */
gchar *password; /* pointer to a NULL-terminated password string */
TurnServer *turn;
};
......
......@@ -71,6 +71,7 @@ void
component_free (Component *cmp)
{
GSList *i;
GList *item;
for (i = cmp->local_candidates; i; i = i->next) {
NiceCandidate *candidate = i->data;
......@@ -107,8 +108,13 @@ component_free (Component *cmp)
g_slist_free (cmp->gsources);
g_slist_free (cmp->incoming_checks);
g_free (cmp->turn_username);
g_free (cmp->turn_password);
for (item = cmp->turn_servers; item; item = g_list_next (item)) {
TurnServer *turn = item->data;
g_free (turn->username);
g_free (turn->password);
g_slice_free (TurnServer, turn);
}
g_list_free (cmp->turn_servers);
g_slice_free (Component, cmp);
}
......
......@@ -82,9 +82,7 @@ struct _Component
GSList *sockets; /**< list of NiceSocket objs */
GSList *gsources; /**< list of GSource objs */
GSList *incoming_checks; /**< list of IncomingCheck objs */
NiceAddress turn_server; /**< TURN server address */
gchar *turn_username; /**< TURN username */
gchar *turn_password; /**< TURN password */
GList *turn_servers; /**< List of TURN servers */
CandidatePair selected_pair; /**< independent from checklists,
see ICE 11.1. "Sending Media" (ID-19) */
gboolean media_after_tick; /**< true if media received since last
......
......@@ -560,10 +560,10 @@ static void priv_turn_allocate_refresh_tick_unlocked (CandidateRefresh *cand)
size_t password_len;
size_t buffer_len = 0;
username = (uint8_t *)cand->component->turn_username;
username_len = (size_t) strlen (cand->component->turn_username);
password = (uint8_t *)cand->component->turn_password;
password_len = (size_t) strlen (cand->component->turn_password);
username = (uint8_t *)cand->turn->username;
username_len = (size_t) strlen (cand->turn->username);
password = (uint8_t *)cand->turn->password;
password_len = (size_t) strlen (cand->turn->password);
if (cand->agent->compatibility == NICE_COMPATIBILITY_MSN) {
username = g_base64_decode ((gchar *)username, &username_len);
......@@ -1856,6 +1856,7 @@ priv_add_new_turn_refresh (CandidateDiscovery *cdisco, NiceCandidate *relay_cand
cand->nicesock = cdisco->nicesock;
cand->relay_socket = relay_cand->sockptr;
cand->server = cdisco->server;
cand->turn = cdisco->turn;
cand->stream = cdisco->stream;
cand->component = cdisco->component;
cand->agent = cdisco->agent;
......@@ -1917,7 +1918,7 @@ static gboolean priv_map_reply_to_relay_request (NiceAgent *agent, StunMessage *
if (res == STUN_USAGE_TURN_RETURN_ALTERNATE_SERVER) {
/* handle alternate server */
nice_address_set_from_sockaddr (&d->server, &alternate);
nice_address_set_from_sockaddr (&d->component->turn_server, &alternate);
nice_address_set_from_sockaddr (&d->turn->server, &alternate);
d->pending = FALSE;
} else if (res == STUN_USAGE_TURN_RETURN_RELAY_SUCCESS ||
......@@ -1944,7 +1945,8 @@ static gboolean priv_map_reply_to_relay_request (NiceAgent *agent, StunMessage *
d->stream->id,
d->component->id,
&niceaddr,
d->nicesock);
d->nicesock,
d->turn);
priv_add_new_turn_refresh (d, relay_cand, lifetime);
......
......@@ -179,10 +179,10 @@ void refresh_free_item (gpointer data, gpointer user_data)
cand->tick_source = NULL;
}
username = (uint8_t *)cand->component->turn_username;
username_len = (size_t) strlen (cand->component->turn_username);
password = (uint8_t *)cand->component->turn_password;
password_len = (size_t) strlen (cand->component->turn_password);
username = (uint8_t *)cand->turn->username;
username_len = (size_t) strlen (cand->turn->username);
password = (uint8_t *)cand->turn->password;
password_len = (size_t) strlen (cand->turn->password);
if (agent->compatibility == NICE_COMPATIBILITY_MSN) {
username = g_base64_decode ((gchar *)username, &username_len);
......@@ -524,7 +524,8 @@ discovery_add_relay_candidate (
guint stream_id,
guint component_id,
NiceAddress *address,
NiceSocket *base_socket)
NiceSocket *base_socket,
TurnServer *turn)
{
NiceCandidate *candidate;
Component *component;
......@@ -549,11 +550,12 @@ discovery_add_relay_candidate (
candidate->stream_id = stream_id;
candidate->component_id = component_id;
candidate->addr = *address;
candidate->turn = turn;
/* step: link to the base candidate+socket */
relay_socket = nice_udp_turn_socket_new (agent, address,
base_socket, &component->turn_server,
component->turn_username, component->turn_password,
base_socket, &turn->server,
turn->username, turn->password,
priv_agent_to_udp_turn_compatibility (agent));
if (relay_socket) {
candidate->sockptr = relay_socket;
......@@ -564,7 +566,7 @@ discovery_add_relay_candidate (
/* Google uses the turn username as the candidate username */
if (agent->compatibility == NICE_COMPATIBILITY_GOOGLE) {
g_free (candidate->username);
candidate->username = g_strdup (component->turn_username);
candidate->username = g_strdup (turn->username);
}
priv_assign_foundation (agent, candidate);
......@@ -826,10 +828,10 @@ static gboolean priv_discovery_tick_unlocked (gpointer pointer)
buffer_len = stun_usage_bind_create (&agent->stun_agent,
&cand->stun_message, cand->stun_buffer, sizeof(cand->stun_buffer));
} else if (cand->type == NICE_CANDIDATE_TYPE_RELAYED) {
uint8_t *username = (uint8_t *)cand->component->turn_username;
size_t username_len = (size_t) strlen (cand->component->turn_username);
uint8_t *password = (uint8_t *)cand->component->turn_password;
size_t password_len = (size_t) strlen (cand->component->turn_password);
uint8_t *username = (uint8_t *)cand->turn->username;
size_t username_len = (size_t) strlen (cand->turn->username);
uint8_t *password = (uint8_t *)cand->turn->password;
size_t password_len = (size_t) strlen (cand->turn->password);
if (agent->compatibility == NICE_COMPATIBILITY_MSN) {
username = g_base64_decode ((gchar *)username, &username_len);
......@@ -846,6 +848,8 @@ static gboolean priv_discovery_tick_unlocked (gpointer pointer)
priv_agent_to_turn_compatibility (agent));
if (agent->compatibility == NICE_COMPATIBILITY_MSN) {
g_free (cand->msn_turn_username);
g_free (cand->msn_turn_password);
cand->msn_turn_username = username;
cand->msn_turn_password = password;
}
......
......@@ -52,6 +52,7 @@ typedef struct
gboolean done; /**< is discovery complete? */
Stream *stream;
Component *component;
TurnServer *turn;
StunAgent turn_agent;
uint8_t *msn_turn_username;
uint8_t *msn_turn_password;
......@@ -70,6 +71,7 @@ typedef struct
NiceAddress server; /**< STUN/TURN server address */
Stream *stream;
Component *component;
TurnServer *turn;
StunAgent turn_agent;
GSource *timer_source;
GSource *tick_source;
......@@ -106,7 +108,8 @@ discovery_add_relay_candidate (
guint stream_id,
guint component_id,
NiceAddress *address,
NiceSocket *base_socket);
NiceSocket *base_socket,
TurnServer *turn);
NiceCandidate*
discovery_add_server_reflexive_candidate (
......
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