#define STUN_PERMISSION_TIMEOUT (300 - STUN_EXPIRE_TIMEOUT) /* 240 s */
#define STUN_BINDING_TIMEOUT (600 - STUN_EXPIRE_TIMEOUT) /* 540 s */
+static GMutex mutex;
+
typedef struct {
StunMessage message;
uint8_t buffer[STUN_MAX_MESSAGE_SIZE];
} ChannelBinding;
typedef struct {
- GMutex mutex;
GMainContext *ctx;
StunAgent agent;
GList *channels;
STUN_AGENT_USAGE_NO_ALIGNED_ATTRIBUTES);
}
- g_mutex_init (&priv->mutex);
priv->channels = NULL;
priv->current_binding = NULL;
priv->base_socket = base_socket;
UdpTurnPriv *priv = (UdpTurnPriv *) sock->priv;
GList *i = NULL;
+ g_mutex_lock (&mutex);
+
for (i = priv->channels; i; i = i->next) {
ChannelBinding *b = i->data;
if (b->timeout_source) {
priv->tick_source_create_permission = NULL;
}
-
g_queue_free_full (priv->send_requests, (GDestroyNotify) send_request_free);
priv_clear_permissions (priv);
g_free (priv);
sock->priv = NULL;
+
+ g_mutex_unlock (&mutex);
}
static gint
{
guint i;
+ g_mutex_lock (&mutex);
+
/* Make sure socket has not been freed: */
g_assert (sock->priv != NULL);
/* Error. */
if (i > 0)
break;
+ g_mutex_unlock (&mutex);
return len;
} else if (len == 0) {
/* EWOULDBLOCK. */
}
}
+ g_mutex_unlock (&mutex);
+
return i;
}
UdpTurnPriv *priv = (UdpTurnPriv *) sock->priv;
guint i;
+ g_mutex_lock (&mutex);
+
/* TURN can depend either on tcp-turn or udp-bsd as a base socket
* if we allow reliable send and need to create permissions and we queue the
* data, then we must be sure that the reliable send will succeed later, so
* we check for udp-bsd here as the base socket and don't allow it.
*/
- if (priv->base_socket->type == NICE_SOCKET_TYPE_UDP_BSD)
+ if (priv->base_socket->type == NICE_SOCKET_TYPE_UDP_BSD) {
+ g_mutex_unlock (&mutex);
return -1;
+ }
for (i = 0; i < n_messages; i++) {
const NiceOutputMessage *message = &messages[i];
if (len < 0) {
/* Error. */
+ g_mutex_unlock (&mutex);
return len;
} else if (len == 0) {
/* EWOULDBLOCK. */
}
}
+ g_mutex_unlock (&mutex);
return i;
}
{
SendRequest *req = pointer;
+ g_mutex_lock (&mutex);
+ if (g_source_is_destroyed (g_main_current_source ())) {
+ nice_debug ("Source was destroyed. "
+ "Avoided race condition in turn.c:priv_forget_send_request");
+ g_mutex_unlock (&mutex);
+ return G_SOURCE_REMOVE;
+ }
+
send_request_free (req);
g_queue_remove (req->priv->send_requests, req);
+ g_mutex_unlock (&mutex);
+
return G_SOURCE_REMOVE;
}
nice_debug ("Permission is about to timeout, schedule renewal");
- g_mutex_lock (&priv->mutex);
+ g_mutex_lock (&mutex);
+
+ if (g_source_is_destroyed (g_main_current_source ())) {
+ nice_debug ("Source was destroyed. Avoided race condition in "
+ "udp-turn.c:priv_permission_timeout");
+
+ g_mutex_unlock (&mutex);
+ return G_SOURCE_REMOVE;
+ }
+
+
/* remove all permissions for this agent (the permission for the peer
we are sending to will be renewed) */
priv_clear_permissions (priv);
- g_mutex_unlock (&priv->mutex);
+ g_mutex_unlock (&mutex);
return TRUE;
}
GList *i;
GSource *source = NULL;
+ g_mutex_lock (&mutex);
+ if (g_source_is_destroyed (g_main_current_source ())) {
+ nice_debug ("Source was destroyed. Avoided race condition in "
+ "udp-turn.c:priv_permission_timeout");
+
+ g_mutex_unlock (&mutex);
+ return G_SOURCE_REMOVE;
+ }
+
nice_debug ("Permission expired, refresh failed");
/* find current binding and destroy it */
}
}
- return FALSE;
+ g_mutex_unlock (&mutex);
+ return G_SOURCE_REMOVE;
}
static gboolean
GList *i;
GSource *source = NULL;
+ g_mutex_lock (&mutex);
+ if (g_source_is_destroyed (g_main_current_source ())) {
+ nice_debug ("Source was destroyed. Avoided race condition in "
+ "udp-turn.c:priv_permission_timeout");
+
+ g_mutex_unlock (&mutex);
+ return G_SOURCE_REMOVE;
+ }
+
nice_debug ("Permission is about to timeout, sending binding renewal");
/* find current binding and mark it for renewal */
}
}
- return FALSE;
+ g_mutex_unlock (&mutex);
+
+ return G_SOURCE_REMOVE;
}
void
g_assert (sock->type == NICE_SOCKET_TYPE_UDP_TURN);
+ g_mutex_lock (&mutex);
+
g_free (priv->cached_realm);
priv->cached_realm = NULL;
priv->cached_realm_len = 0;
tmp = stun_message_find (msg, STUN_ATTRIBUTE_NONCE, &priv->cached_nonce_len);
if (tmp && priv->cached_nonce_len < 764)
priv->cached_nonce = g_memdup (tmp, priv->cached_nonce_len);
+
+ g_mutex_unlock (&mutex);
}
guint
const guint16 *u16;
} recv_buf;
+ g_mutex_unlock (&mutex);
+
/* In the case of a reliable UDP-TURN-OVER-TCP (which means MS-TURN)
* we must use RFC4571 framing */
if (nice_socket_is_reliable (sock)) {
goto msn_google_lock;
}
}
- return 0;
+
+ goto done;
} else if (stun_message_get_method (&msg) == STUN_OLD_SET_ACTIVE_DST) {
StunTransactionId request_id;
StunTransactionId response_id;
}
}
- return 0;
+ goto done;
} else if (stun_message_get_method (&msg) == STUN_CHANNELBIND) {
StunTransactionId request_id;
StunTransactionId response_id;
}
}
}
- return 0;
+ goto done;
} else if (stun_message_get_method (&msg) == STUN_CREATEPERMISSION) {
StunTransactionId request_id;
StunTransactionId response_id;
nice_udp_turn_socket_cache_realm_nonce (sock, &msg);
/* resend CreatePermission */
priv_send_create_permission (priv, &to);
- return 0;
+ goto done;
}
}
/* If we get an error, we just assume the server somehow
}
}
- return 0;
+ goto done;
} else if (stun_message_get_class (&msg) == STUN_INDICATION &&
stun_message_get_method (&msg) == STUN_IND_DATA) {
uint16_t data_len;
*from_sock = sock;
memmove (buf, data, len > data_len ? data_len : len);
+ g_mutex_unlock (&mutex);
return len > data_len ? data_len : len;
} else {
goto recv;
}
memmove (buf, recv_buf.u8, len > recv_len ? recv_len : len);
+ g_mutex_unlock (&mutex);
return len > recv_len ? recv_len : len;
msn_google_lock:
priv_process_pending_bindings (priv);
}
+ done:
+ g_mutex_unlock (&mutex);
return 0;
}
gboolean
nice_udp_turn_socket_set_peer (NiceSocket *sock, NiceAddress *peer)
{
- UdpTurnPriv *priv = (UdpTurnPriv *) sock->priv;
+ UdpTurnPriv *priv;
+ gboolean ret;
- return priv_add_channel_binding (priv, peer);
+ g_mutex_lock (&mutex);
+
+ priv = (UdpTurnPriv *) sock->priv;
+
+ ret = priv_add_channel_binding (priv, peer);
+
+ g_mutex_unlock (&mutex);
+
+ return ret;
}
static void
{
UdpTurnPriv *priv = pointer;
+ g_mutex_lock (&mutex);
+ if (g_source_is_destroyed (g_main_current_source ())) {
+ nice_debug ("Source was destroyed. Avoided race condition in "
+ "udp-turn.c:priv_permission_timeout");
+
+ g_mutex_unlock (&mutex);
+ return G_SOURCE_REMOVE;
+ }
+
if (priv_retransmissions_tick_unlocked (priv) == FALSE) {
if (priv->tick_source_channel_bind != NULL) {
g_source_destroy (priv->tick_source_channel_bind);
}
}
- return FALSE;
+ g_mutex_unlock (&mutex);
+
+ return G_SOURCE_REMOVE;
}
static gboolean
{
UdpTurnPriv *priv = pointer;
+ g_mutex_lock (&mutex);
+ if (g_source_is_destroyed (g_main_current_source ())) {
+ nice_debug ("Source was destroyed. Avoided race condition in "
+ "udp-turn.c:priv_permission_timeout");
+
+ g_mutex_unlock (&mutex);
+ return G_SOURCE_REMOVE;
+ }
+
/* This will call priv_retransmissions_create_permission_tick_unlocked() for
* every pending permission with an expired timer and will create a new timer
* if there are pending permissions that require it */
priv_schedule_tick (priv);
- return FALSE;
+ g_mutex_unlock (&mutex);
+
+ return G_SOURCE_REMOVE;
}
static void
const uint8_t *realm = stun_message_find(msg, STUN_ATTRIBUTE_REALM, &alen);
if (realm && alen <= STUN_MAX_MS_REALM_LEN) {
+ g_mutex_lock (&mutex);
memcpy(priv->ms_realm, realm, alen);
priv->ms_realm[alen] = '\0';
+ g_mutex_unlock (&mutex);
}
}
const uint8_t *ms_seq_num = stun_message_find(msg,
STUN_ATTRIBUTE_MS_SEQUENCE_NUMBER, &alen);
+
if (ms_seq_num && alen == 24) {
+ g_mutex_lock (&mutex);
memcpy (priv->ms_connection_id, ms_seq_num, 20);
priv->ms_sequence_num = ntohl((uint32_t)*(ms_seq_num + 20));
priv->ms_connection_id_valid = TRUE;
+ g_mutex_unlock (&mutex);
}
}