Commit 5869965e authored by Youness Alaoui's avatar Youness Alaoui

Add support for UDP retransmissions and timeouts for channel bindings in turn

parent 16cfd73b
...@@ -41,6 +41,8 @@ ...@@ -41,6 +41,8 @@
#include <glib-object.h> #include <glib-object.h>
typedef struct _NiceAgent NiceAgent;
#include "socket.h" #include "socket.h"
#include "address.h" #include "address.h"
#include "candidate.h" #include "candidate.h"
...@@ -106,7 +108,6 @@ typedef enum ...@@ -106,7 +108,6 @@ typedef enum
NICE_COMPATIBILITY_LAST = NICE_COMPATIBILITY_MSN NICE_COMPATIBILITY_LAST = NICE_COMPATIBILITY_MSN
} NiceCompatibility; } NiceCompatibility;
typedef struct _NiceAgent NiceAgent;
typedef void (*NiceAgentRecvFunc) ( typedef void (*NiceAgentRecvFunc) (
NiceAgent *agent, guint stream_id, guint component_id, guint len, NiceAgent *agent, guint stream_id, guint component_id, guint len,
......
...@@ -445,10 +445,10 @@ discovery_add_relay_candidate ( ...@@ -445,10 +445,10 @@ discovery_add_relay_candidate (
candidate->addr = *address; candidate->addr = *address;
/* step: link to the base candidate+socket */ /* step: link to the base candidate+socket */
relay_socket = nice_udp_turn_socket_new (address, relay_socket = nice_udp_turn_socket_new (agent, address,
base_socket, &component->turn_server, base_socket, &component->turn_server,
component->turn_username, component->turn_password, component->turn_username, component->turn_password,
priv_agent_to_udp_turn_compatibility (agent), &agent->mutex); priv_agent_to_udp_turn_compatibility (agent));
if (relay_socket) { if (relay_socket) {
candidate->sockptr = relay_socket; candidate->sockptr = relay_socket;
candidate->base_addr = base_socket->addr; candidate->base_addr = base_socket->addr;
......
...@@ -11,7 +11,9 @@ include $(top_srcdir)/common.mk ...@@ -11,7 +11,9 @@ include $(top_srcdir)/common.mk
AM_CFLAGS = \ AM_CFLAGS = \
$(ERROR_CFLAGS) \ $(ERROR_CFLAGS) \
$(GLIB_CFLAGS) \ $(GLIB_CFLAGS) \
-I $(top_srcdir)/address -I $(top_srcdir)/address \
-I $(top_srcdir)/random \
-I $(top_srcdir)/agent
COMMON_LDADD = libsocket.la $(GLIB_LIBS) $(top_builddir)/address/libaddress.la $(top_builddir)/stun/libstun.la COMMON_LDADD = libsocket.la $(GLIB_LIBS) $(top_builddir)/address/libaddress.la $(top_builddir)/stun/libstun.la
......
...@@ -56,14 +56,13 @@ ...@@ -56,14 +56,13 @@
#include "udp-bsd.h" #include "udp-bsd.h"
#include <stun/stunagent.h> #include <stun/stunagent.h>
#include <stun/usages/timer.h> #include <stun/usages/timer.h>
#include "agent-priv.h"
typedef struct { typedef struct {
StunMessage msg; StunMessage message;
uint8_t buffer[STUN_MAX_MESSAGE_SIZE]; uint8_t buffer[STUN_MAX_MESSAGE_SIZE];
stun_timer_t timer; stun_timer_t timer;
gboolean done; } TURNMessage;
} UDPMessage;
typedef struct { typedef struct {
...@@ -72,10 +71,12 @@ typedef struct { ...@@ -72,10 +71,12 @@ typedef struct {
} ChannelBinding; } ChannelBinding;
typedef struct { typedef struct {
NiceAgent *nice;
StunAgent agent; StunAgent agent;
GList *channels; GList *channels;
GList *retransmissions;
ChannelBinding *current_binding; ChannelBinding *current_binding;
TURNMessage *current_binding_msg;
GSource *tick_source;
NiceSocket *base_socket; NiceSocket *base_socket;
NiceAddress server_addr; NiceAddress server_addr;
uint8_t *username; uint8_t *username;
...@@ -85,47 +86,128 @@ typedef struct { ...@@ -85,47 +86,128 @@ typedef struct {
NiceUdpTurnSocketCompatibility compatibility; NiceUdpTurnSocketCompatibility compatibility;
} turn_priv; } turn_priv;
#if 0 static void
static gboolean retransmit_udp_packet (turn_priv *priv) priv_schedule_tick (turn_priv *priv);
static gboolean
priv_retransmissions_tick_unlocked (turn_priv *priv)
{
if (priv->current_binding_msg) {
guint timeout = stun_timer_refresh (&priv->current_binding_msg->timer);
switch (timeout) {
case -1:
/* Time out */
g_free (priv->current_binding);
priv->current_binding = NULL;
g_free (priv->current_binding_msg);
priv->current_binding_msg = NULL;
break;
case 0:
/* Retransmit */
nice_socket_send (priv->base_socket, &priv->server_addr,
stun_message_length (&priv->current_binding_msg->message),
(gchar *)priv->current_binding_msg->buffer);
break;
default:
break;
}
}
priv_schedule_tick (priv);
return FALSE;
}
static gboolean
priv_retransmissions_tick (gpointer pointer)
{ {
NiceAgent *agent = pointer; turn_priv *priv = pointer;
gboolean ret; gboolean ret;
g_static_rec_mutex_lock (&agent->mutex); g_static_rec_mutex_lock (&priv->nice->mutex);
ret = priv_discovery_tick_unlocked (pointer); ret = priv_retransmissions_tick_unlocked (priv);
g_static_rec_mutex_unlock (&agent->mutex); g_static_rec_mutex_unlock (&priv->nice->mutex);
return ret; return ret;
} }
#endif
static void
priv_schedule_tick (turn_priv *priv)
{
if (priv->tick_source != NULL) {
g_source_destroy (priv->tick_source);
g_source_unref (priv->tick_source);
priv->tick_source = NULL;
}
if (priv->current_binding_msg) {
guint timeout = stun_timer_remainder (&priv->current_binding_msg->timer);
if (timeout > 0) {
priv->tick_source = agent_timeout_add_with_context (priv->nice, timeout,
priv_retransmissions_tick, priv);
} else {
priv_retransmissions_tick_unlocked (priv);
}
}
}
static void
priv_send_turn_message (turn_priv *priv, TURNMessage *msg)
{
size_t stun_len = stun_message_length (&msg->message);
if (priv->current_binding_msg) {
g_free (priv->current_binding_msg);
priv->current_binding_msg = NULL;
}
nice_socket_send (priv->base_socket, &priv->server_addr,
stun_len, (gchar *)msg->buffer);
if (nice_socket_is_reliable (priv->base_socket)) {
stun_timer_start_reliable (&msg->timer);
} else {
stun_timer_start (&msg->timer);
priv->current_binding_msg = msg;
priv_schedule_tick (priv);
}
}
static gboolean static gboolean
priv_send_channel_bind (turn_priv *priv, StunMessage *resp, priv_send_channel_bind (turn_priv *priv, StunMessage *resp,
uint16_t channel, NiceAddress *peer) { uint16_t channel, NiceAddress *peer) {
uint32_t channel_attr = channel << 16; uint32_t channel_attr = channel << 16;
StunMessage msg;
uint8_t buffer[STUN_MAX_MESSAGE_SIZE];
size_t stun_len; size_t stun_len;
struct sockaddr_storage sa; struct sockaddr_storage sa;
TURNMessage *msg = g_new0 (TURNMessage, 1);
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, if (!stun_agent_init_request (&priv->agent, &msg->message,
buffer, sizeof(buffer), STUN_CHANNELBIND)) msg->buffer, sizeof(msg->buffer), STUN_CHANNELBIND)) {
g_free (msg);
return FALSE; return FALSE;
}
if (stun_message_append32 (&msg, STUN_ATTRIBUTE_CHANNEL_NUMBER, if (stun_message_append32 (&msg->message, STUN_ATTRIBUTE_CHANNEL_NUMBER,
channel_attr) != 0) channel_attr) != 0) {
g_free (msg);
return FALSE; return FALSE;
}
if (stun_message_append_xor_addr (&msg, STUN_ATTRIBUTE_PEER_ADDRESS, if (stun_message_append_xor_addr (&msg->message, STUN_ATTRIBUTE_PEER_ADDRESS,
(struct sockaddr *)&sa, sizeof(sa)) != 0) (struct sockaddr *)&sa, sizeof(sa)) != 0) {
g_free (msg);
return FALSE; return FALSE;
}
if (priv->username != NULL && priv->username_len > 0) { if (priv->username != NULL && priv->username_len > 0) {
if (stun_message_append_bytes (&msg, STUN_ATTRIBUTE_USERNAME, if (stun_message_append_bytes (&msg->message, STUN_ATTRIBUTE_USERNAME,
priv->username, priv->username_len) != 0) priv->username, priv->username_len) != 0) {
g_free (msg);
return FALSE; return FALSE;
}
} }
if (resp) { if (resp) {
...@@ -135,25 +217,31 @@ priv_send_channel_bind (turn_priv *priv, StunMessage *resp, ...@@ -135,25 +217,31 @@ priv_send_channel_bind (turn_priv *priv, StunMessage *resp,
realm = (uint8_t *) stun_message_find (resp, STUN_ATTRIBUTE_REALM, &len); realm = (uint8_t *) stun_message_find (resp, STUN_ATTRIBUTE_REALM, &len);
if (realm != NULL) { if (realm != NULL) {
if (stun_message_append_bytes (&msg, STUN_ATTRIBUTE_REALM, realm, len) != 0) if (stun_message_append_bytes (&msg->message, STUN_ATTRIBUTE_REALM,
realm, len) != 0) {
g_free (msg);
return 0; return 0;
}
} }
nonce = (uint8_t *) stun_message_find (resp, STUN_ATTRIBUTE_NONCE, &len); nonce = (uint8_t *) stun_message_find (resp, STUN_ATTRIBUTE_NONCE, &len);
if (nonce != NULL) { if (nonce != NULL) {
if (stun_message_append_bytes (&msg, STUN_ATTRIBUTE_NONCE, nonce, len) != 0) if (stun_message_append_bytes (&msg->message, STUN_ATTRIBUTE_NONCE,
nonce, len) != 0) {
g_free (msg);
return 0; return 0;
}
} }
} }
stun_len = stun_agent_finish_message (&priv->agent, &msg, stun_len = stun_agent_finish_message (&priv->agent, &msg->message,
priv->password, priv->password_len); priv->password, priv->password_len);
if (stun_len > 0) { if (stun_len > 0) {
nice_socket_send (priv->base_socket, &priv->server_addr, priv_send_turn_message (priv, msg);
stun_len, (gchar *)buffer);
return TRUE; return TRUE;
} }
g_free (msg);
return FALSE; return FALSE;
} }
NICEAPI_EXPORT gboolean NICEAPI_EXPORT gboolean
...@@ -284,6 +372,8 @@ nice_udp_turn_socket_parse_recv ( ...@@ -284,6 +372,8 @@ nice_udp_turn_socket_parse_recv (
return 0; return 0;
} else if (stun_message_get_class (&msg) == STUN_ERROR && } else if (stun_message_get_class (&msg) == STUN_ERROR &&
stun_message_get_method (&msg) == STUN_CHANNELBIND) { stun_message_get_method (&msg) == STUN_CHANNELBIND) {
g_free (priv->current_binding_msg);
priv->current_binding_msg = NULL;
if (priv->current_binding) { if (priv->current_binding) {
priv_send_channel_bind (priv, &msg, priv_send_channel_bind (priv, &msg,
priv->current_binding->channel, &priv->current_binding->peer); priv->current_binding->channel, &priv->current_binding->peer);
...@@ -291,6 +381,8 @@ nice_udp_turn_socket_parse_recv ( ...@@ -291,6 +381,8 @@ nice_udp_turn_socket_parse_recv (
return 0; return 0;
} else if (stun_message_get_class (&msg) == STUN_RESPONSE && } else if (stun_message_get_class (&msg) == STUN_RESPONSE &&
stun_message_get_method (&msg) == STUN_CHANNELBIND) { stun_message_get_method (&msg) == STUN_CHANNELBIND) {
g_free (priv->current_binding_msg);
priv->current_binding_msg = NULL;
if (priv->current_binding) { if (priv->current_binding) {
priv->channels = g_list_append (priv->channels, priv->current_binding); priv->channels = g_list_append (priv->channels, priv->current_binding);
priv->current_binding = NULL; priv->current_binding = NULL;
...@@ -496,13 +588,13 @@ socket_close (NiceSocket *sock) ...@@ -496,13 +588,13 @@ socket_close (NiceSocket *sock)
NICEAPI_EXPORT NiceSocket * NICEAPI_EXPORT NiceSocket *
nice_udp_turn_socket_new ( nice_udp_turn_socket_new (
NiceAgent *agent,
NiceAddress *addr, NiceAddress *addr,
NiceSocket *base_socket, NiceSocket *base_socket,
NiceAddress *server_addr, NiceAddress *server_addr,
gchar *username, gchar *username,
gchar *password, gchar *password,
NiceUdpTurnSocketCompatibility compatibility, NiceUdpTurnSocketCompatibility compatibility)
GStaticRecMutex *mutex)
{ {
turn_priv *priv = g_new0 (turn_priv, 1); turn_priv *priv = g_new0 (turn_priv, 1);
NiceSocket *sock = g_slice_new0 (NiceSocket); NiceSocket *sock = g_slice_new0 (NiceSocket);
...@@ -527,6 +619,7 @@ nice_udp_turn_socket_new ( ...@@ -527,6 +619,7 @@ nice_udp_turn_socket_new (
STUN_AGENT_USAGE_IGNORE_CREDENTIALS); STUN_AGENT_USAGE_IGNORE_CREDENTIALS);
} }
priv->nice = agent;
priv->channels = NULL; priv->channels = NULL;
priv->current_binding = NULL; priv->current_binding = NULL;
priv->base_socket = base_socket; priv->base_socket = base_socket;
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#define _UDP_TURN_H #define _UDP_TURN_H
#include "socket.h" #include "socket.h"
#include "agent.h"
G_BEGIN_DECLS G_BEGIN_DECLS
...@@ -63,13 +64,13 @@ nice_udp_turn_socket_set_peer (NiceSocket *sock, NiceAddress *peer); ...@@ -63,13 +64,13 @@ nice_udp_turn_socket_set_peer (NiceSocket *sock, NiceAddress *peer);
NiceSocket * NiceSocket *
nice_udp_turn_socket_new ( nice_udp_turn_socket_new (
NiceAgent *agent,
NiceAddress *addr, NiceAddress *addr,
NiceSocket *udp_socket, NiceSocket *udp_socket,
NiceAddress *server_addr, NiceAddress *server_addr,
gchar *username, gchar *username,
gchar *password, gchar *password,
NiceUdpTurnSocketCompatibility compatibility, NiceUdpTurnSocketCompatibility compatibility);
GStaticRecMutex *mutex);
G_END_DECLS G_END_DECLS
......
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