Commit 0d130b14 authored by Youness Alaoui's avatar Youness Alaoui

Make the binding timeout unique per channel binding. And refactor code.

The binding renewal must be sent 60 seconds before it expires, but also add
a second timer to destroy the binding if the renewal fails.
Also refactored to make sure the binding is correctly handled when we receive a success response.
parent d79f997e
...@@ -53,8 +53,9 @@ ...@@ -53,8 +53,9 @@
#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_EXPIRE_TIMEOUT 60 /* Time we refresh before expiration */
#define STUN_BINDING_TIMEOUT 540 /* 600-60 s */ #define STUN_PERMISSION_TIMEOUT (300 - STUN_EXPIRE_TIMEOUT) /* 240 s */
#define STUN_BINDING_TIMEOUT (600 - STUN_EXPIRE_TIMEOUT) /* 540 s */
typedef struct { typedef struct {
StunMessage message; StunMessage message;
...@@ -66,6 +67,7 @@ typedef struct { ...@@ -66,6 +67,7 @@ typedef struct {
NiceAddress peer; NiceAddress peer;
uint16_t channel; uint16_t channel;
gboolean active; gboolean active;
guint timeout_source;
} ChannelBinding; } ChannelBinding;
typedef struct { typedef struct {
...@@ -96,7 +98,6 @@ typedef struct { ...@@ -96,7 +98,6 @@ typedef struct {
GHashTable *send_data_queues; /* stores a send data queue for per peer */ GHashTable *send_data_queues; /* stores a send data queue for per peer */
guint permission_timeout_source; /* timer used to invalidate guint permission_timeout_source; /* timer used to invalidate
permissions */ permissions */
guint binding_timeout_source;
} TurnPriv; } TurnPriv;
...@@ -246,6 +247,7 @@ socket_close (NiceSocket *sock) ...@@ -246,6 +247,7 @@ socket_close (NiceSocket *sock)
for (i = priv->channels; i; i = i->next) { for (i = priv->channels; i; i = i->next) {
ChannelBinding *b = i->data; ChannelBinding *b = i->data;
g_source_remove (b->timeout_source);
g_free (b); g_free (b);
} }
g_list_free (priv->channels); g_list_free (priv->channels);
...@@ -284,7 +286,6 @@ socket_close (NiceSocket *sock) ...@@ -284,7 +286,6 @@ socket_close (NiceSocket *sock)
g_list_foreach (priv->sent_permissions, (GFunc) nice_address_free, NULL); g_list_foreach (priv->sent_permissions, (GFunc) nice_address_free, NULL);
g_list_free (priv->sent_permissions); g_list_free (priv->sent_permissions);
g_hash_table_destroy (priv->send_data_queues); g_hash_table_destroy (priv->send_data_queues);
g_source_remove (priv->binding_timeout_source);
g_source_remove (priv->permission_timeout_source); g_source_remove (priv->permission_timeout_source);
g_free (priv->current_binding); g_free (priv->current_binding);
...@@ -560,11 +561,6 @@ socket_send (NiceSocket *sock, const NiceAddress *to, ...@@ -560,11 +561,6 @@ socket_send (NiceSocket *sock, const NiceAddress *to,
} }
if (msg_len > 0) { if (msg_len > 0) {
if (!priv->current_binding_msg && binding && !binding->active) {
nice_debug ("renewing channel binding");
priv_send_channel_bind (priv, NULL, binding->channel, to);
}
if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_RFC5766 && if (priv->compatibility == NICE_TURN_SOCKET_COMPATIBILITY_RFC5766 &&
!priv_has_permission_for_peer (priv, to)) { !priv_has_permission_for_peer (priv, to)) {
if (!priv_has_sent_permission_for_peer (priv, to)) { if (!priv_has_sent_permission_for_peer (priv, to)) {
...@@ -636,25 +632,77 @@ priv_permission_timeout (gpointer data) ...@@ -636,25 +632,77 @@ priv_permission_timeout (gpointer data)
return TRUE; return TRUE;
} }
static gboolean
priv_binding_expired_timeout (gpointer data)
{
TurnPriv *priv = (TurnPriv *) data;
GList *i;
GSource *source = NULL;
nice_debug ("Permission expired, refresh failed");
agent_lock ();
source = g_main_current_source ();
if (g_source_is_destroyed (source)) {
nice_debug ("Source was destroyed. "
"Avoided race condition in turn.c:priv_binding_expired_timeout");
agent_unlock ();
return FALSE;
}
/* find current binding and destroy it */
for (i = priv->channels ; i; i = i->next) {
ChannelBinding *b = i->data;
if (b->timeout_source == g_source_get_id (source)) {
priv->channels = g_list_remove (priv->channels, b);
g_free (b);
break;
}
}
agent_unlock ();
return FALSE;
}
static gboolean static gboolean
priv_binding_timeout (gpointer data) priv_binding_timeout (gpointer data)
{ {
TurnPriv *priv = (TurnPriv *) data; TurnPriv *priv = (TurnPriv *) data;
GList *i; GList *i;
GSource *source = NULL;
nice_debug ("Permission is about to timeout, schedule renewal"); nice_debug ("Permission is about to timeout, sending binding renewal");
agent_lock (); agent_lock ();
source = g_main_current_source ();
if (g_source_is_destroyed (source)) {
nice_debug ("Source was destroyed. "
"Avoided race condition in turn.c:priv_binding_timeout");
agent_unlock ();
return FALSE;
}
/* find current binding and inactivate it */ /* find current binding and inactivate it */
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 (b->timeout_source == g_source_get_id (source)) {
b->active = FALSE; b->active = FALSE;
/* Install timer to expire the permission */
b->timeout_source = g_timeout_add_seconds (STUN_EXPIRE_TIMEOUT,
priv_binding_expired_timeout, priv);
/* Send renewal */
if (!priv->current_binding_msg)
priv_send_channel_bind (priv, NULL, b->channel, &b->peer);
break;
}
} }
agent_unlock (); agent_unlock ();
return TRUE; return FALSE;
} }
gint gint
...@@ -753,6 +801,33 @@ nice_turn_socket_parse_recv (NiceSocket *sock, NiceSocket **from_sock, ...@@ -753,6 +801,33 @@ nice_turn_socket_parse_recv (NiceSocket *sock, NiceSocket **from_sock,
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, if (memcmp (request_id, response_id,
sizeof(StunTransactionId)) == 0) { sizeof(StunTransactionId)) == 0) {
if (priv->current_binding) {
/* New channel binding */
binding = priv->current_binding;
} else {
/* Existing binding refresh */
GList *i;
struct sockaddr sa;
socklen_t sa_len = sizeof(sa);
NiceAddress to;
/* look up binding associated with peer */
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 = priv->channels; i; i = i->next) {
ChannelBinding *b = i->data;
if (nice_address_equal (&b->peer, &to)) {
binding = b;
break;
}
}
}
if (stun_message_get_class (&msg) == STUN_ERROR) { if (stun_message_get_class (&msg) == STUN_ERROR) {
int code = -1; int code = -1;
uint8_t *sent_realm = NULL; uint8_t *sent_realm = NULL;
...@@ -779,40 +854,11 @@ nice_turn_socket_parse_recv (NiceSocket *sock, NiceSocket **from_sock, ...@@ -779,40 +854,11 @@ nice_turn_socket_parse_recv (NiceSocket *sock, NiceSocket **from_sock,
memcmp (sent_realm, recv_realm, memcmp (sent_realm, recv_realm,
sent_realm_len) == 0)))) { 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;
priv_send_channel_bind (priv, &msg,
priv->current_binding->channel,
&priv->current_binding->peer);
} else {
/* look up binding associated with peer */
GList *i;
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 = priv->channels; 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) if (binding)
priv_send_channel_bind (priv, &msg, binding->channel, &to); priv_send_channel_bind (priv, &msg, binding->channel,
} &binding->peer);
} else { } else {
g_free (priv->current_binding); g_free (priv->current_binding);
priv->current_binding = NULL; priv->current_binding = NULL;
...@@ -824,20 +870,24 @@ nice_turn_socket_parse_recv (NiceSocket *sock, NiceSocket **from_sock, ...@@ -824,20 +870,24 @@ nice_turn_socket_parse_recv (NiceSocket *sock, NiceSocket **from_sock,
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) { /* If it's a new channel binding, then add it to the list */
priv->current_binding->active = TRUE; 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);
/* install timer to schedule refresh of the permission */ if (binding) {
if (!priv->binding_timeout_source) { binding->active = TRUE;
priv->binding_timeout_source =
/* Remove any existing timer */
if (binding->timeout_source)
g_source_remove (binding->timeout_source);
/* Install timer to schedule refresh of the permission */
binding->timeout_source =
g_timeout_add_seconds (STUN_BINDING_TIMEOUT, g_timeout_add_seconds (STUN_BINDING_TIMEOUT,
priv_binding_timeout, priv); priv_binding_timeout, priv);
} }
priv_process_pending_bindings (priv);
} }
} }
} }
......
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