Commit bbd1d93e authored by Marcus Lundblad's avatar Marcus Lundblad Committed by Youness Alaoui

Remaining changes for RFC 5766

parent a58b6e00
...@@ -172,7 +172,7 @@ nice_interfaces_get_local_ips (gboolean include_loopback) ...@@ -172,7 +172,7 @@ nice_interfaces_get_local_ips (gboolean include_loopback)
GList *ips = NULL; GList *ips = NULL;
struct ifaddrs *ifa, *results; struct ifaddrs *ifa, *results;
GList *loopbacks = NULL; GList *loopbacks = NULL;
int ret;
if (getifaddrs (&results) < 0) if (getifaddrs (&results) < 0)
return NULL; return NULL;
......
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdlib.h>
#include "turn.h" #include "turn.h"
#include "stun/stunagent.h" #include "stun/stunagent.h"
...@@ -52,7 +53,8 @@ ...@@ -52,7 +53,8 @@
#define STUN_END_TIMEOUT 8000 #define STUN_END_TIMEOUT 8000
#define STUN_MAX_MS_REALM_LEN 128 // as defined in [MS-TURN] #define STUN_MAX_MS_REALM_LEN 128 // as defined in [MS-TURN]
#define STUN_PERMISSION_TIMEOUT 240 /* 300-60 s */
#define STUN_BINDING_TIMEOUT 540 /* 600-60 s */
typedef struct { typedef struct {
StunMessage message; StunMessage message;
...@@ -72,8 +74,9 @@ typedef struct { ...@@ -72,8 +74,9 @@ typedef struct {
GList *pending_bindings; GList *pending_bindings;
ChannelBinding *current_binding; ChannelBinding *current_binding;
TURNMessage *current_binding_msg; TURNMessage *current_binding_msg;
GSource *tick_source; TURNMessage *current_create_permission_msg;
GSource *tick_source_channel_bind; GSource *tick_source_channel_bind;
GSource *tick_source_create_permission;
NiceSocket *base_socket; NiceSocket *base_socket;
NiceAddress server_addr; NiceAddress server_addr;
uint8_t *username; uint8_t *username;
...@@ -86,6 +89,14 @@ typedef struct { ...@@ -86,6 +89,14 @@ typedef struct {
uint8_t ms_connection_id[20]; uint8_t ms_connection_id[20];
uint32_t ms_sequence_num; uint32_t ms_sequence_num;
bool ms_connection_id_valid; bool ms_connection_id_valid;
gboolean has_permission;
gboolean sent_permission;
guint num_sent_permission;
GQueue *send_data;
guint permission_timeout_source;
gboolean has_binding;
gboolean sent_binding;
guint binding_timeout_source;
} TurnPriv; } TurnPriv;
...@@ -95,6 +106,12 @@ typedef struct { ...@@ -95,6 +106,12 @@ typedef struct {
TurnPriv *priv; TurnPriv *priv;
} SendRequest; } SendRequest;
typedef struct {
gchar *data;
guint data_len;
NiceAddress *to;
} SendData;
static void socket_close (NiceSocket *sock); static void socket_close (NiceSocket *sock);
static gint socket_recv (NiceSocket *sock, NiceAddress *from, static gint socket_recv (NiceSocket *sock, NiceAddress *from,
guint len, gchar *buf); guint len, gchar *buf);
...@@ -107,9 +124,12 @@ static gboolean priv_retransmissions_tick_unlocked (TurnPriv *priv); ...@@ -107,9 +124,12 @@ static gboolean priv_retransmissions_tick_unlocked (TurnPriv *priv);
static gboolean priv_retransmissions_tick (gpointer pointer); static gboolean priv_retransmissions_tick (gpointer pointer);
static void priv_schedule_tick (TurnPriv *priv); static void priv_schedule_tick (TurnPriv *priv);
static void priv_send_turn_message (TurnPriv *priv, TURNMessage *msg); static void priv_send_turn_message (TurnPriv *priv, TURNMessage *msg);
static gboolean priv_send_create_permission (TurnPriv *priv,
uint8_t *realm, gsize realm_len, uint8_t *nonce, gsize nonce_len,
struct sockaddr *peer);
static gboolean priv_send_channel_bind (TurnPriv *priv, StunMessage *resp, static gboolean priv_send_channel_bind (TurnPriv *priv, StunMessage *resp,
uint16_t channel, NiceAddress *peer); uint16_t channel, const NiceAddress *peer);
static gboolean priv_add_channel_binding (TurnPriv *priv, NiceAddress *peer); static gboolean priv_add_channel_binding (TurnPriv *priv, const NiceAddress *peer);
static gboolean priv_forget_send_request (gpointer pointer); static gboolean priv_forget_send_request (gpointer pointer);
...@@ -125,7 +145,8 @@ nice_turn_socket_new (NiceAgent *agent, NiceAddress *addr, ...@@ -125,7 +145,8 @@ nice_turn_socket_new (NiceAgent *agent, NiceAddress *addr,
return NULL; return NULL;
} }
if (compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9) { if (compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9 ||
compatibility == NICE_TURN_SOCKET_COMPATIBILITY_RFC5766) {
stun_agent_init (&priv->agent, STUN_ALL_KNOWN_ATTRIBUTES, stun_agent_init (&priv->agent, STUN_ALL_KNOWN_ATTRIBUTES,
STUN_COMPATIBILITY_RFC5389, STUN_COMPATIBILITY_RFC5389,
STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS); STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS);
...@@ -170,6 +191,7 @@ nice_turn_socket_new (NiceAgent *agent, NiceAddress *addr, ...@@ -170,6 +191,7 @@ nice_turn_socket_new (NiceAgent *agent, NiceAddress *addr,
priv->server_addr = *server_addr; priv->server_addr = *server_addr;
priv->compatibility = compatibility; priv->compatibility = compatibility;
priv->send_requests = g_queue_new (); priv->send_requests = g_queue_new ();
priv->send_data = g_queue_new();
sock->addr = *addr; sock->addr = *addr;
sock->fileno = base_socket->fileno; sock->fileno = base_socket->fileno;
sock->send = socket_send; sock->send = socket_send;
...@@ -216,9 +238,18 @@ socket_close (NiceSocket *sock) ...@@ -216,9 +238,18 @@ socket_close (NiceSocket *sock)
} }
g_queue_free (priv->send_requests); g_queue_free (priv->send_requests);
for (i = g_queue_peek_head_link (priv->send_data) ; i; i = i->next) {
SendData *d = i->data;
nice_address_free (d->to);
g_slice_free (SendData, d);
}
g_queue_free (priv->send_data);
g_source_remove (priv->permission_timeout_source);
g_free (priv->current_binding); g_free (priv->current_binding);
g_free (priv->current_binding_msg); g_free (priv->current_binding_msg);
g_free (priv->current_create_permission_msg);
g_free (priv->username); g_free (priv->username);
g_free (priv->password); g_free (priv->password);
g_free (priv); g_free (priv);
...@@ -233,6 +264,8 @@ socket_recv (NiceSocket *sock, NiceAddress *from, guint len, gchar *buf) ...@@ -233,6 +264,8 @@ socket_recv (NiceSocket *sock, NiceAddress *from, guint len, gchar *buf)
NiceAddress recv_from; NiceAddress recv_from;
NiceSocket *dummy;; NiceSocket *dummy;;
nice_debug ("received message on TURN socket");
recv_len = nice_socket_recv (priv->base_socket, &recv_from, recv_len = nice_socket_recv (priv->base_socket, &recv_from,
sizeof(recv_buf), (gchar *) recv_buf); sizeof(recv_buf), (gchar *) recv_buf);
...@@ -270,6 +303,40 @@ stun_message_ensure_ms_realm(StunMessage *msg, uint8_t *realm) ...@@ -270,6 +303,40 @@ stun_message_ensure_ms_realm(StunMessage *msg, uint8_t *realm)
} }
} }
static void
socket_enqueue_data(NiceSocket *sock, const NiceAddress *to,
guint len, const gchar *buf)
{
SendData *data = g_slice_new0 (SendData);
data->data = g_memdup(buf, len);
data->data_len = len;
data->to = nice_address_dup (to);
g_queue_push_tail(((TurnPriv *) sock->priv)->send_data, data);
}
static gboolean
socket_has_enqueued_data(NiceSocket *sock)
{
return g_queue_get_length(((TurnPriv *) sock->priv)->send_data) > 0;
}
static void
socket_dequeue_data(NiceSocket *sock)
{
SendData *data =
(SendData *) g_queue_pop_head(((TurnPriv *) sock->priv)->send_data);
nice_debug("dequeing data enqueued when installing permission or binding");
socket_send (sock, data->to, data->data_len, data->data);
g_free (data->data);
nice_address_free (data->to);
g_slice_free (SendData, data);
}
static gboolean static gboolean
socket_send (NiceSocket *sock, const NiceAddress *to, socket_send (NiceSocket *sock, const NiceAddress *to,
guint len, const gchar *buf) guint len, const gchar *buf)
...@@ -290,10 +357,13 @@ socket_send (NiceSocket *sock, const NiceAddress *to, ...@@ -290,10 +357,13 @@ socket_send (NiceSocket *sock, const NiceAddress *to,
} }
} }
nice_debug ("in turn.c:socket_send");
nice_address_copy_to_sockaddr (to, (struct sockaddr *)&sa); nice_address_copy_to_sockaddr (to, (struct sockaddr *)&sa);
if (binding) { if (binding) {
if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9) { if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9 ||
priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_RFC5766) {
if (len + sizeof(uint32_t) <= sizeof(buffer)) { if (len + sizeof(uint32_t) <= sizeof(buffer)) {
uint16_t len16 = htons ((uint16_t) len); uint16_t len16 = htons ((uint16_t) len);
uint16_t channel16 = htons (binding->channel); uint16_t channel16 = htons (binding->channel);
...@@ -308,7 +378,9 @@ socket_send (NiceSocket *sock, const NiceAddress *to, ...@@ -308,7 +378,9 @@ socket_send (NiceSocket *sock, const NiceAddress *to,
return nice_socket_send (priv->base_socket, &priv->server_addr, len, buf); return nice_socket_send (priv->base_socket, &priv->server_addr, len, buf);
} }
} else { } else {
if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9) { nice_debug("no binding");
if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9 ||
priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_RFC5766) {
if (!stun_agent_init_indication (&priv->agent, &msg, if (!stun_agent_init_indication (&priv->agent, &msg,
buffer, sizeof(buffer), STUN_IND_SEND)) buffer, sizeof(buffer), STUN_IND_SEND))
goto send; goto send;
...@@ -369,9 +441,34 @@ socket_send (NiceSocket *sock, const NiceAddress *to, ...@@ -369,9 +441,34 @@ socket_send (NiceSocket *sock, const NiceAddress *to,
} }
if (msg_len > 0) { if (msg_len > 0) {
nice_debug("before send");
if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_RFC5766) {
if (!priv->has_permission && !priv->sent_permission) {
nice_debug ("no permission installed for peer");
priv_send_create_permission(priv, NULL, 0, NULL, 0,
(struct sockaddr *)&sa);
}
}
if (!priv->has_binding && !priv->sent_binding && binding) {
nice_debug("renewing channel binding");
priv_send_channel_bind (priv, NULL, binding->channel, to);
}
nice_debug("about to send: permission %d, binding %d", priv->has_permission,
priv->has_binding);
if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_RFC5766 &&
!priv->has_permission) {
/* enque data */
nice_debug("enqueing data to be sent when aquiring permission or binding");
socket_enqueue_data(sock, to, msg_len,
(gchar *)buffer);
return TRUE;
} else {
return nice_socket_send (priv->base_socket, &priv->server_addr, return nice_socket_send (priv->base_socket, &priv->server_addr,
msg_len, (gchar *)buffer); msg_len, (gchar *)buffer);
} }
}
send: send:
return nice_socket_send (priv->base_socket, to, len, buf); return nice_socket_send (priv->base_socket, to, len, buf);
} }
...@@ -412,6 +509,33 @@ priv_forget_send_request (gpointer pointer) ...@@ -412,6 +509,33 @@ priv_forget_send_request (gpointer pointer)
return FALSE; return FALSE;
} }
static gboolean
priv_permission_timeout (gpointer data)
{
TurnPriv *priv = (TurnPriv *) data;
nice_debug ("Permission is about to timeout, schedule renewal");
agent_lock ();
priv->has_permission = FALSE;
agent_unlock ();
return TRUE;
}
static gboolean
priv_binding_timeout (gpointer data)
{
TurnPriv *priv = (TurnPriv *) data;
nice_debug ("Permission is about to timeout, schedule renewal");
agent_lock ();
priv->has_binding = FALSE;
agent_unlock ();
return TRUE;
}
gint gint
nice_turn_socket_parse_recv (NiceSocket *sock, NiceSocket **from_sock, nice_turn_socket_parse_recv (NiceSocket *sock, NiceSocket **from_sock,
...@@ -432,7 +556,8 @@ nice_turn_socket_parse_recv (NiceSocket *sock, NiceSocket **from_sock, ...@@ -432,7 +556,8 @@ nice_turn_socket_parse_recv (NiceSocket *sock, NiceSocket **from_sock,
(uint8_t *) recv_buf, (size_t) recv_len, NULL, NULL); (uint8_t *) recv_buf, (size_t) recv_len, NULL, NULL);
if (valid == STUN_VALIDATION_SUCCESS) { if (valid == STUN_VALIDATION_SUCCESS) {
if (priv->compatibility != NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9) { if (priv->compatibility != NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9 &&
priv->compatibility != NICE_TURN_SOCKET_COMPATIBILITY_RFC5766) {
uint32_t cookie; uint32_t cookie;
if (stun_message_find32 (&msg, STUN_ATTRIBUTE_MAGIC_COOKIE, if (stun_message_find32 (&msg, STUN_ATTRIBUTE_MAGIC_COOKIE,
&cookie) != STUN_MESSAGE_RETURN_SUCCESS) &cookie) != STUN_MESSAGE_RETURN_SUCCESS)
...@@ -500,7 +625,8 @@ nice_turn_socket_parse_recv (NiceSocket *sock, NiceSocket **from_sock, ...@@ -500,7 +625,8 @@ nice_turn_socket_parse_recv (NiceSocket *sock, NiceSocket **from_sock,
} else if (stun_message_get_method (&msg) == STUN_CHANNELBIND) { } else if (stun_message_get_method (&msg) == STUN_CHANNELBIND) {
StunTransactionId request_id; StunTransactionId request_id;
StunTransactionId response_id; StunTransactionId response_id;
if (priv->current_binding && priv->current_binding_msg) {
if (priv->current_binding_msg) {
stun_message_id (&msg, response_id); stun_message_id (&msg, response_id);
stun_message_id (&priv->current_binding_msg->message, request_id); stun_message_id (&priv->current_binding_msg->message, request_id);
if (memcmp (request_id, response_id, sizeof(StunTransactionId)) == 0) { if (memcmp (request_id, response_id, sizeof(StunTransactionId)) == 0) {
...@@ -517,6 +643,11 @@ nice_turn_socket_parse_recv (NiceSocket *sock, NiceSocket **from_sock, ...@@ -517,6 +643,11 @@ nice_turn_socket_parse_recv (NiceSocket *sock, NiceSocket **from_sock,
recv_realm = (uint8_t *) stun_message_find (&msg, recv_realm = (uint8_t *) stun_message_find (&msg,
STUN_ATTRIBUTE_REALM, &recv_realm_len); STUN_ATTRIBUTE_REALM, &recv_realm_len);
if (!priv->has_binding) {
nice_debug ("sent realm: %s\n", sent_realm);
nice_debug ("recv realm: %s\n", recv_realm);
}
/* check for unauthorized error response */ /* check for unauthorized error response */
if (stun_message_find_error (&msg, &code) == if (stun_message_find_error (&msg, &code) ==
STUN_MESSAGE_RETURN_SUCCESS && STUN_MESSAGE_RETURN_SUCCESS &&
...@@ -526,12 +657,39 @@ nice_turn_socket_parse_recv (NiceSocket *sock, NiceSocket **from_sock, ...@@ -526,12 +657,39 @@ nice_turn_socket_parse_recv (NiceSocket *sock, NiceSocket **from_sock,
recv_realm_len == sent_realm_len && recv_realm_len == sent_realm_len &&
sent_realm != NULL && sent_realm != NULL &&
memcmp (sent_realm, recv_realm, sent_realm_len) == 0)))) { memcmp (sent_realm, recv_realm, sent_realm_len) == 0)))) {
if (priv->current_binding) {
g_free (priv->current_binding_msg); g_free (priv->current_binding_msg);
priv->current_binding_msg = NULL; priv->current_binding_msg = NULL;
if (priv->current_binding) {
priv_send_channel_bind (priv, &msg, priv_send_channel_bind (priv, &msg,
priv->current_binding->channel, priv->current_binding->channel,
&priv->current_binding->peer); &priv->current_binding->peer);
} else {
/* look up binding associated with peer */
GList *i = priv->channels;
ChannelBinding *binding = NULL;
struct sockaddr sa;
socklen_t sa_len = sizeof(sa);
NiceAddress to;
stun_message_find_xor_addr (&priv->current_binding_msg->message,
STUN_ATTRIBUTE_XOR_PEER_ADDRESS, &sa,
&sa_len);
nice_address_set_from_sockaddr (&to, &sa);
for (; i; i = i->next) {
ChannelBinding *b = i->data;
if (nice_address_equal (&b->peer, &to)) {
binding = b;
break;
}
}
g_free (priv->current_binding_msg);
priv->current_binding_msg = NULL;
if (binding)
priv_send_channel_bind (priv, &msg, binding->channel, &to);
} }
} else { } else {
g_free (priv->current_binding); g_free (priv->current_binding);
...@@ -543,22 +701,92 @@ nice_turn_socket_parse_recv (NiceSocket *sock, NiceSocket **from_sock, ...@@ -543,22 +701,92 @@ nice_turn_socket_parse_recv (NiceSocket *sock, NiceSocket **from_sock,
} else if (stun_message_get_class (&msg) == STUN_RESPONSE) { } else if (stun_message_get_class (&msg) == STUN_RESPONSE) {
g_free (priv->current_binding_msg); g_free (priv->current_binding_msg);
priv->current_binding_msg = NULL; priv->current_binding_msg = NULL;
priv->has_binding = TRUE;
priv->sent_binding = FALSE;
if (priv->current_binding) { if (priv->current_binding) {
priv->channels = g_list_append (priv->channels, priv->channels = g_list_append (priv->channels,
priv->current_binding); priv->current_binding);
priv->current_binding = NULL; priv->current_binding = NULL;
} }
priv_process_pending_bindings (priv); priv_process_pending_bindings (priv);
/* install timer to schedule refresh of the permission */
if (!priv->binding_timeout_source) {
priv->binding_timeout_source =
g_timeout_add_seconds (STUN_BINDING_TIMEOUT,
priv_binding_timeout, priv);
}
}
}
}
return 0;
} else if (stun_message_get_method (&msg) == STUN_CREATEPERMISSION) {
StunTransactionId request_id;
StunTransactionId response_id;
if (priv->current_create_permission_msg) {
stun_message_id (&msg, response_id);
stun_message_id (&priv->current_create_permission_msg->message, request_id);
if (memcmp (request_id, response_id, sizeof(StunTransactionId)) == 0) {
struct sockaddr peer;
socklen_t peer_len = sizeof(peer);
nice_debug("got response for CreatePermission");
stun_message_find_xor_addr (&priv->current_create_permission_msg->message,
STUN_ATTRIBUTE_XOR_PEER_ADDRESS, &peer,
&peer_len);
g_free (priv->current_create_permission_msg);
priv->current_create_permission_msg = NULL;
if (stun_message_get_class (&msg) == STUN_ERROR) {
uint8_t *recv_realm = NULL;
uint16_t recv_realm_len = 0;
uint8_t *recv_nonce = NULL;
uint16_t recv_nonce_len = 0;
recv_realm = (uint8_t *) stun_message_find (&msg,
STUN_ATTRIBUTE_REALM, &recv_realm_len);
recv_nonce = (uint8_t *) stun_message_find (&msg,
STUN_ATTRIBUTE_NONCE, &recv_nonce_len);
nice_debug("got realm: %s", recv_realm);
nice_debug("got nonce: %s", recv_nonce);
/* resend CreatePermission */
if (priv->num_sent_permission < 2)
priv_send_create_permission (priv, recv_realm, recv_realm_len,
recv_nonce, recv_nonce_len, &peer);
} else {
priv->has_permission = TRUE;
priv->sent_permission = FALSE;
priv->num_sent_permission = 0;
/* install timer to schedule refresh of the permission */
if (!priv->permission_timeout_source) {
priv->permission_timeout_source =
g_timeout_add_seconds (STUN_PERMISSION_TIMEOUT,
priv_permission_timeout, priv);
}
/* send enqued data, unless there is also an ongoing channel bind */
nice_debug("about to dequeue data: sent_binding: %d", priv->sent_binding);
while (socket_has_enqueued_data (sock)) {
socket_dequeue_data (sock);
} }
} }
} }
}
return 0; return 0;
} else if (stun_message_get_class (&msg) == STUN_INDICATION && } else if (stun_message_get_class (&msg) == STUN_INDICATION &&
stun_message_get_method (&msg) == STUN_IND_DATA) { stun_message_get_method (&msg) == STUN_IND_DATA) {
uint16_t data_len; uint16_t data_len;
uint8_t *data; uint8_t *data;
if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9) { if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9 ||
priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_RFC5766) {
if (stun_message_find_xor_addr (&msg, STUN_ATTRIBUTE_REMOTE_ADDRESS, if (stun_message_find_xor_addr (&msg, STUN_ATTRIBUTE_REMOTE_ADDRESS,
(struct sockaddr *)&sa, &from_len) != (struct sockaddr *)&sa, &from_len) !=
STUN_MESSAGE_RETURN_SUCCESS) STUN_MESSAGE_RETURN_SUCCESS)
...@@ -590,7 +818,8 @@ nice_turn_socket_parse_recv (NiceSocket *sock, NiceSocket **from_sock, ...@@ -590,7 +818,8 @@ nice_turn_socket_parse_recv (NiceSocket *sock, NiceSocket **from_sock,
recv: recv:
for (i = priv->channels; i; i = i->next) { for (i = priv->channels; i; i = i->next) {
ChannelBinding *b = i->data; ChannelBinding *b = i->data;
if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9) { if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9 ||
priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_RFC5766) {
if (b->channel == ntohs(((uint16_t *)recv_buf)[0])) { if (b->channel == ntohs(((uint16_t *)recv_buf)[0])) {
recv_len = ntohs (((uint16_t *)recv_buf)[1]); recv_len = ntohs (((uint16_t *)recv_buf)[1]);
recv_buf += sizeof(uint32_t); recv_buf += sizeof(uint32_t);
...@@ -634,6 +863,7 @@ gboolean ...@@ -634,6 +863,7 @@ gboolean
nice_turn_socket_set_peer (NiceSocket *sock, NiceAddress *peer) nice_turn_socket_set_peer (NiceSocket *sock, NiceAddress *peer)
{ {
TurnPriv *priv = (TurnPriv *) sock->priv; TurnPriv *priv = (TurnPriv *) sock->priv;
return priv_add_channel_binding (priv, peer); return priv_add_channel_binding (priv, peer);
} }
...@@ -649,6 +879,7 @@ priv_process_pending_bindings (TurnPriv *priv) ...@@ -649,6 +879,7 @@ priv_process_pending_bindings (TurnPriv *priv)
} }
} }
static gboolean static gboolean
priv_retransmissions_tick_unlocked (TurnPriv *priv) priv_retransmissions_tick_unlocked (TurnPriv *priv)
{ {
...@@ -686,6 +917,38 @@ priv_retransmissions_tick_unlocked (TurnPriv *priv) ...@@ -686,6 +917,38 @@ priv_retransmissions_tick_unlocked (TurnPriv *priv)
return FALSE; return FALSE;
} }
static gboolean
priv_retransmissions_create_permission_tick_unlocked (TurnPriv *priv)
{
if (priv->current_create_permission_msg) {
switch (stun_timer_refresh (&priv->current_create_permission_msg->timer)) {
case STUN_USAGE_TIMER_RETURN_TIMEOUT:
{
/* Time out */
StunTransactionId id;
stun_message_id (&priv->current_create_permission_msg->message, id);
stun_agent_forget_transaction (&priv->agent, id);
g_free (priv->current_create_permission_msg);
priv->current_create_permission_msg = NULL;
break;
}
case STUN_USAGE_TIMER_RETURN_RETRANSMIT:
/* Retransmit */
nice_socket_send (priv->base_socket, &priv->server_addr,
stun_message_length (&priv->current_create_permission_msg->message),
(gchar *)priv->current_create_permission_msg->buffer);
break;
case STUN_USAGE_TIMER_RETURN_SUCCESS:
break;
}
}
priv_schedule_tick (priv);
return FALSE;
}
static gboolean static gboolean
priv_retransmissions_tick (gpointer pointer) priv_retransmissions_tick (gpointer pointer)
...@@ -714,6 +977,33 @@ priv_retransmissions_tick (gpointer pointer) ...@@ -714,6 +977,33 @@ priv_retransmissions_tick (gpointer pointer)
return ret; return ret;
} }
static gboolean
priv_retransmissions_create_permission_tick (gpointer pointer)
{
TurnPriv *priv = pointer;
gboolean ret;
agent_lock ();
if (g_source_is_destroyed (g_main_current_source ())) {
nice_debug ("Source was destroyed. "
"Avoided race condition in turn.c:priv_retransmissions_create_permission_tick");
agent_unlock ();
return FALSE;
}
ret = priv_retransmissions_create_permission_tick_unlocked (priv);
if (ret == FALSE) {
if (priv->tick_source_create_permission != NULL) {
g_source_destroy (priv->tick_source_create_permission);
g_source_unref (priv->tick_source_create_permission);
priv->tick_source_create_permission = NULL;
}
}
agent_unlock ();
return ret;
}
static void static void
priv_schedule_tick (TurnPriv *priv) priv_schedule_tick (TurnPriv *priv)
{ {
...@@ -733,6 +1023,16 @@ priv_schedule_tick (TurnPriv *priv) ...@@ -733,6 +1023,16 @@ priv_schedule_tick (TurnPriv *priv)
priv_retransmissions_tick_unlocked (priv); priv_retransmissions_tick_unlocked (priv);
} }
} }
if (priv->current_create_permission_msg) {
guint timeout = stun_timer_remainder (&priv->current_create_permission_msg->timer);
if (timeout > 0) {
priv->tick_source_create_permission = agent_timeout_add_with_context (priv->nice, timeout,
priv_retransmissions_create_permission_tick, priv);
} else {
priv_retransmissions_create_permission_tick_unlocked (priv);
}
}
} }
static void static void
...@@ -760,15 +1060,57 @@ priv_send_turn_message (TurnPriv *priv, TURNMessage *msg) ...@@ -760,15 +1060,57 @@ priv_send_turn_message (TurnPriv *priv, TURNMessage *msg)
priv_schedule_tick (priv); priv_schedule_tick (priv);
} }
static gboolean
priv_send_create_permission(TurnPriv *priv, uint8_t *realm, gsize realm_len,
uint8_t *nonce, gsize nonce_len,
struct sockaddr *peer)
{
guint msg_buf_len;
gboolean res = FALSE;
TURNMessage *msg = g_new0 (TURNMessage, 1);
nice_debug("creating CreatePermission message");
priv->sent_permission = TRUE;
priv->num_sent_permission++;
/* send CreatePermission */
msg_buf_len = stun_usage_turn_create_permission(&priv->agent, &msg->message,
msg->buffer, sizeof(msg->buffer), priv->username, priv->username_len,
priv->password, priv->password_len, realm, realm_len, nonce, nonce_len,
peer,
NICE_TURN_SOCKET_COMPATIBILITY_RFC5766);
if (msg_buf_len > 0) {
nice_debug("sending CreatePermission message, lenght: %d",
msg_buf_len);
res = nice_socket_send (priv->base_socket, &priv->server_addr,
msg_buf_len, (gchar *) msg->buffer);
nice_debug("sent CreatePermission message, result: %d", res);
if (nice_socket_is_reliable (priv->base_socket)) {
stun_timer_start_reliable (&msg->timer);
} else {
stun_timer_start (&msg->timer);
}
priv_schedule_tick (priv);
priv->current_create_permission_msg = msg;
} else {
g_free(msg);
}
return res;
}
static gboolean static gboolean
priv_send_channel_bind (TurnPriv *priv, StunMessage *resp, priv_send_channel_bind (TurnPriv *priv, StunMessage *resp,
uint16_t channel, NiceAddress *peer) uint16_t channel, const NiceAddress *peer)
{ {
uint32_t channel_attr = channel << 16; uint32_t channel_attr = channel << 16;
size_t stun_len; size_t stun_len;
struct sockaddr_storage sa; struct sockaddr_storage sa;
TURNMessage *msg = g_new0 (TURNMessage, 1); TURNMessage *msg = g_new0 (TURNMessage, 1);
priv->sent_binding = TRUE;
nice_address_copy_to_sockaddr (peer, (struct sockaddr *)&sa); nice_address_copy_to_sockaddr (peer, (struct sockaddr *)&sa);
if (!stun_agent_init_request (&priv->agent, &msg->message, if (!stun_agent_init_request (&priv->agent, &msg->message,
...@@ -833,11 +1175,12 @@ priv_send_channel_bind (TurnPriv *priv, StunMessage *resp, ...@@ -833,11 +1175,12 @@ priv_send_channel_bind (TurnPriv *priv, StunMessage *resp,
} }
static gboolean static gboolean
priv_add_channel_binding (TurnPriv *priv, NiceAddress *peer) priv_add_channel_binding (TurnPriv *priv, const NiceAddress *peer)
{ {
size_t stun_len; size_t stun_len;
struct sockaddr_storage sa; struct sockaddr_storage sa;
priv->sent_binding = TRUE;
nice_address_copy_to_sockaddr (peer, (struct sockaddr *)&sa); nice_address_copy_to_sockaddr (peer, (struct sockaddr *)&sa);
if (priv->current_binding) { if (priv->current_binding) {
...@@ -847,7 +1190,8 @@ priv_add_channel_binding (TurnPriv *priv, NiceAddress *peer) ...@@ -847,7 +1190,8 @@ priv_add_channel_binding (TurnPriv *priv, NiceAddress *peer)
return FALSE; return FALSE;
} }
if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9) { if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_DRAFT9 ||
priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_RFC5766) {
uint16_t channel = 0x4000; uint16_t channel = 0x4000;
GList *i = priv->channels; GList *i = priv->channels;
for (; i; i = i->next) { for (; i; i = i->next) {
......
...@@ -43,6 +43,7 @@ typedef enum { ...@@ -43,6 +43,7 @@ typedef enum {
NICE_TURN_SOCKET_COMPATIBILITY_GOOGLE, NICE_TURN_SOCKET_COMPATIBILITY_GOOGLE,
NICE_TURN_SOCKET_COMPATIBILITY_MSN, NICE_TURN_SOCKET_COMPATIBILITY_MSN,
NICE_TURN_SOCKET_COMPATIBILITY_OC2007, NICE_TURN_SOCKET_COMPATIBILITY_OC2007,
NICE_TURN_SOCKET_COMPATIBILITY_RFC5766,
} NiceTurnSocketCompatibility; } NiceTurnSocketCompatibility;
#include "socket.h" #include "socket.h"
......
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
#include "stunhmac.h" #include "stunhmac.h"
#include "stun5389.h" #include "stun5389.h"
#include "utils.h" #include "utils.h"
#include "debug.h"
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
...@@ -548,6 +549,7 @@ size_t stun_agent_finish_message (StunAgent *agent, StunMessage *msg, ...@@ -548,6 +549,7 @@ size_t stun_agent_finish_message (StunAgent *agent, StunMessage *msg,
STUN_ATTRIBUTE_REALM, &realm_len); STUN_ATTRIBUTE_REALM, &realm_len);
username = (uint8_t *) stun_message_find (msg, username = (uint8_t *) stun_message_find (msg,
STUN_ATTRIBUTE_USERNAME, &username_len); STUN_ATTRIBUTE_USERNAME, &username_len);
if (username == NULL || realm == NULL) { if (username == NULL || realm == NULL) {
skip = TRUE; skip = TRUE;
} else { } else {
...@@ -640,6 +642,8 @@ size_t stun_agent_finish_message (StunAgent *agent, StunMessage *msg, ...@@ -640,6 +642,8 @@ size_t stun_agent_finish_message (StunAgent *agent, StunMessage *msg,
msg->key = (uint8_t *) key; msg->key = (uint8_t *) key;
msg->key_len = key_len; msg->key_len = key_len;
stun_debug("stun_agent_finish_message, returning lenght: %d\n",
stun_message_length(msg));
return stun_message_length (msg); return stun_message_length (msg);
} }
......
...@@ -59,7 +59,6 @@ ...@@ -59,7 +59,6 @@
bool stun_message_init (StunMessage *msg, StunClass c, StunMethod m, bool stun_message_init (StunMessage *msg, StunClass c, StunMethod m,
const StunTransactionId id) const StunTransactionId id)
{ {
if (msg->buffer_len < STUN_MESSAGE_HEADER_LENGTH) if (msg->buffer_len < STUN_MESSAGE_HEADER_LENGTH)
return FALSE; return FALSE;
......
...@@ -238,7 +238,7 @@ static void test_turn (char *username, char *password, char *hostname, int port) ...@@ -238,7 +238,7 @@ static void test_turn (char *username, char *password, char *hostname, int port)
static void turnserver (void) static void turnserver (void)
{ {
test_turn ("toto", "password", "127.0.0.1", "3478"); test_turn ("anonymous", "anonymous", "91.121.109.155", "3480");
} }
static void numb (void) static void numb (void)
......
...@@ -79,7 +79,8 @@ size_t stun_usage_turn_create (StunAgent *agent, StunMessage *msg, ...@@ -79,7 +79,8 @@ size_t stun_usage_turn_create (StunAgent *agent, StunMessage *msg,
{ {
stun_agent_init_request (agent, msg, buffer, buffer_len, STUN_ALLOCATE); stun_agent_init_request (agent, msg, buffer, buffer_len, STUN_ALLOCATE);
if (compatibility == STUN_USAGE_TURN_COMPATIBILITY_DRAFT9) { if (compatibility == STUN_USAGE_TURN_COMPATIBILITY_DRAFT9 ||
compatibility == STUN_USAGE_TURN_COMPATIBILITY_RFC5766) {
if (stun_message_append32 (msg, STUN_ATTRIBUTE_REQUESTED_TRANSPORT, if (stun_message_append32 (msg, STUN_ATTRIBUTE_REQUESTED_TRANSPORT,
TURN_REQUESTED_TRANSPORT_UDP) != STUN_MESSAGE_RETURN_SUCCESS) TURN_REQUESTED_TRANSPORT_UDP) != STUN_MESSAGE_RETURN_SUCCESS)
return 0; return 0;
...@@ -104,7 +105,8 @@ size_t stun_usage_turn_create (StunAgent *agent, StunMessage *msg, ...@@ -104,7 +105,8 @@ size_t stun_usage_turn_create (StunAgent *agent, StunMessage *msg,
return 0; return 0;
} }
if (compatibility == STUN_USAGE_TURN_COMPATIBILITY_DRAFT9 && if ((compatibility == STUN_USAGE_TURN_COMPATIBILITY_DRAFT9 ||
compatibility == STUN_USAGE_TURN_COMPATIBILITY_RFC5766) &&
request_props != STUN_USAGE_TURN_REQUEST_PORT_NORMAL) { request_props != STUN_USAGE_TURN_REQUEST_PORT_NORMAL) {
uint32_t req = 0; uint32_t req = 0;
...@@ -166,7 +168,8 @@ size_t stun_usage_turn_create_refresh (StunAgent *agent, StunMessage *msg, ...@@ -166,7 +168,8 @@ size_t stun_usage_turn_create_refresh (StunAgent *agent, StunMessage *msg,
StunUsageTurnCompatibility compatibility) StunUsageTurnCompatibility compatibility)
{ {
if (compatibility != STUN_USAGE_TURN_COMPATIBILITY_DRAFT9) { if (compatibility != STUN_USAGE_TURN_COMPATIBILITY_DRAFT9 &&
compatibility != STUN_USAGE_TURN_COMPATIBILITY_RFC5766) {
return stun_usage_turn_create (agent, msg, buffer, buffer_len, return stun_usage_turn_create (agent, msg, buffer, buffer_len,
previous_response, STUN_USAGE_TURN_REQUEST_PORT_NORMAL, 0, lifetime, previous_response, STUN_USAGE_TURN_REQUEST_PORT_NORMAL, 0, lifetime,
username, username_len, password, password_len, compatibility); username, username_len, password, password_len, compatibility);
...@@ -211,6 +214,52 @@ size_t stun_usage_turn_create_refresh (StunAgent *agent, StunMessage *msg, ...@@ -211,6 +214,52 @@ size_t stun_usage_turn_create_refresh (StunAgent *agent, StunMessage *msg,
return stun_agent_finish_message (agent, msg, password, password_len); return stun_agent_finish_message (agent, msg, password, password_len);
} }
size_t stun_usage_turn_create_permission (StunAgent *agent, StunMessage *msg,
uint8_t *buffer, size_t buffer_len,
uint8_t *username, size_t username_len,
uint8_t *password, size_t password_len,
uint8_t *realm, size_t realm_len,
uint8_t *nonce, size_t nonce_len,
struct sockaddr *peer,
StunUsageTurnCompatibility compatibility)
{
stun_agent_init_request (agent, msg, buffer, buffer_len,
STUN_CREATEPERMISSION);
/* PEER address */
if (peer) {
if (stun_message_append_xor_addr (msg, STUN_ATTRIBUTE_XOR_PEER_ADDRESS,
peer, sizeof(*peer)) != STUN_MESSAGE_RETURN_SUCCESS) {
return 0;
}
}
/* nonce */
if (nonce != NULL) {
if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_NONCE,
nonce, nonce_len) != STUN_MESSAGE_RETURN_SUCCESS)
return 0;
}
/* realm */
if (realm != NULL) {
if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_REALM,
realm, realm_len) != STUN_MESSAGE_RETURN_SUCCESS)
return 0;
}
/* username */
if (username != NULL) {
if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_USERNAME,
username, username_len) != STUN_MESSAGE_RETURN_SUCCESS)
return 0;
}
stun_debug("before stun_agent_finish_message \n");
return stun_agent_finish_message (agent, msg, password, password_len);
}
StunUsageTurnReturn stun_usage_turn_process (StunMessage *msg, StunUsageTurnReturn stun_usage_turn_process (StunMessage *msg,
struct sockaddr *relay_addr, socklen_t *relay_addrlen, struct sockaddr *relay_addr, socklen_t *relay_addrlen,
struct sockaddr *addr, socklen_t *addrlen, struct sockaddr *addr, socklen_t *addrlen,
...@@ -269,7 +318,8 @@ StunUsageTurnReturn stun_usage_turn_process (StunMessage *msg, ...@@ -269,7 +318,8 @@ StunUsageTurnReturn stun_usage_turn_process (StunMessage *msg,
stun_debug ("Received %u-bytes STUN message\n", stun_message_length (msg)); stun_debug ("Received %u-bytes STUN message\n", stun_message_length (msg));
if (compatibility == STUN_USAGE_TURN_COMPATIBILITY_DRAFT9) { if (compatibility == STUN_USAGE_TURN_COMPATIBILITY_DRAFT9 ||
compatibility == STUN_USAGE_TURN_COMPATIBILITY_RFC5766) {
val = stun_message_find_xor_addr (msg, val = stun_message_find_xor_addr (msg,
STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, addr, addrlen); STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, addr, addrlen);
...@@ -320,7 +370,8 @@ StunUsageTurnReturn stun_usage_turn_refresh_process (StunMessage *msg, ...@@ -320,7 +370,8 @@ StunUsageTurnReturn stun_usage_turn_refresh_process (StunMessage *msg,
int code = -1; int code = -1;
StunUsageTurnReturn ret = STUN_USAGE_TURN_RETURN_RELAY_SUCCESS; StunUsageTurnReturn ret = STUN_USAGE_TURN_RETURN_RELAY_SUCCESS;
if (compatibility == STUN_USAGE_TURN_COMPATIBILITY_DRAFT9) { if (compatibility == STUN_USAGE_TURN_COMPATIBILITY_DRAFT9 ||
compatibility == STUN_USAGE_TURN_COMPATIBILITY_RFC5766) {
if (stun_message_get_method (msg) != STUN_REFRESH) if (stun_message_get_method (msg) != STUN_REFRESH)
return STUN_USAGE_TURN_RETURN_INVALID; return STUN_USAGE_TURN_RETURN_INVALID;
} else { } else {
......
...@@ -59,8 +59,14 @@ ...@@ -59,8 +59,14 @@
# include <stdint.h> # include <stdint.h>
#endif #endif
# include "stun/stunagent.h" #ifdef _WIN32
#include <winsock2.h>
#else
#include <sys/types.h>
#include <sys/socket.h>
#endif
# include "stun/stunagent.h"
# ifdef __cplusplus # ifdef __cplusplus
extern "C" { extern "C" {
# endif # endif
...@@ -97,6 +103,7 @@ typedef enum { ...@@ -97,6 +103,7 @@ typedef enum {
STUN_USAGE_TURN_COMPATIBILITY_GOOGLE, STUN_USAGE_TURN_COMPATIBILITY_GOOGLE,
STUN_USAGE_TURN_COMPATIBILITY_MSN, STUN_USAGE_TURN_COMPATIBILITY_MSN,
STUN_USAGE_TURN_COMPATIBILITY_OC2007 STUN_USAGE_TURN_COMPATIBILITY_OC2007
STUN_USAGE_TURN_COMPATIBILITY_RFC5766,
} StunUsageTurnCompatibility; } StunUsageTurnCompatibility;
/** /**
...@@ -197,6 +204,16 @@ size_t stun_usage_turn_create_refresh (StunAgent *agent, StunMessage *msg, ...@@ -197,6 +204,16 @@ size_t stun_usage_turn_create_refresh (StunAgent *agent, StunMessage *msg,
uint8_t *password, size_t password_len, uint8_t *password, size_t password_len,
StunUsageTurnCompatibility compatibility); StunUsageTurnCompatibility compatibility);
size_t stun_usage_turn_create_permission (StunAgent *agent, StunMessage *msg,
uint8_t *buffer, size_t buffer_len,
uint8_t *username, size_t username_len,
uint8_t *password, size_t password_len,
uint8_t *realm, size_t realm_len,
uint8_t *nonce, size_t nonce_len,
struct sockaddr *peer,
StunUsageTurnCompatibility compatibility);
/** /**
* stun_usage_turn_process: * stun_usage_turn_process:
* @msg: The message containing the response * @msg: The message containing the response
......
...@@ -44,9 +44,10 @@ ...@@ -44,9 +44,10 @@
#include <string.h> #include <string.h>
#define USE_TURN 0 #define USE_TURN 1
#define USE_LOOPBACK 1 #define USE_LOOPBACK 1
#define TEST_GOOGLE 0 #define TEST_GOOGLE 0
#define USE_TURN_SERVER_ORG 1
#define PROXY_IP "127.0.0.1" #define PROXY_IP "127.0.0.1"
#define PROXY_PORT 1080 #define PROXY_PORT 1080
...@@ -85,10 +86,10 @@ ...@@ -85,10 +86,10 @@
#define NUMB_USER "youness.alaoui@collabora.co.uk" #define NUMB_USER "youness.alaoui@collabora.co.uk"
#define NUMB_PASS "badger" #define NUMB_PASS "badger"
#define TSORG_IP "127.0.0.1" #define TSORG_IP "91.121.109.155"
#define TSORG_PORT 3478 #define TSORG_PORT 3480
#define TSORG_USER "toto" #define TSORG_USER "anonymous"
#define TSORG_PASS "password" #define TSORG_PASS "anonymous"
#if USE_TURN_SERVER_ORG #if USE_TURN_SERVER_ORG
...@@ -348,6 +349,7 @@ static int run_full_test (NiceAgent *lagent, NiceAgent *ragent, NiceAddress *bas ...@@ -348,6 +349,7 @@ static int run_full_test (NiceAgent *lagent, NiceAgent *ragent, NiceAddress *bas
g_assert (ls_id > 0); g_assert (ls_id > 0);
g_assert (rs_id > 0); g_assert (rs_id > 0);
#if USE_TURN #if USE_TURN
nice_debug("TURN_IP: %s\n", TURN_IP);
nice_agent_set_relay_info(lagent, ls_id, 1, nice_agent_set_relay_info(lagent, ls_id, 1,
TURN_IP, TURN_PORT, TURN_USER, TURN_PASS, TURN_TYPE); TURN_IP, TURN_PORT, TURN_USER, TURN_PASS, TURN_TYPE);
nice_agent_set_relay_info(lagent, ls_id, 2, nice_agent_set_relay_info(lagent, ls_id, 2,
......
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