static GStaticRecMutex agent_mutex = G_STATIC_REC_MUTEX_INIT;
#endif
-static gboolean priv_attach_stream_component (NiceAgent *agent,
+static void priv_attach_stream_component (NiceAgent *agent,
Stream *stream,
Component *component);
-static void priv_detach_stream_component (Stream *stream, Component *component);
static void priv_free_upnp (NiceAgent *agent);
if (component->tcp) {
agent_signal_component_state_change (agent, stream->id,
component->id, NICE_COMPONENT_STATE_FAILED);
- priv_detach_stream_component (stream, component);
+ component_detach_socket_sources (component);
}
priv_destroy_component_tcp (component);
}
_priv_set_socket_tos (agent, new_socket, stream->tos);
agent_attach_stream_component_socket (agent, stream,
component, new_socket);
- component->sockets= g_slist_append (component->sockets, new_socket);
socket = new_socket;
}
}
agent_attach_stream_component_socket (agent, stream,
component, cdisco->nicesock);
- component->sockets = g_slist_append (component->sockets, cdisco->nicesock);
}
cdisco->turn = turn;
for (n = 0; n < stream->n_components; n++) {
Component *component = stream_find_component_by_id (stream, n + 1);
- priv_detach_stream_component (stream, component);
+ component_free_socket_sources (component);
for (i = component->local_candidates; i; i = i->next) {
NiceCandidate *candidate = i->data;
nice_candidate_free (candidate);
}
- for (i = component->sockets; i; i = i->next) {
- NiceSocket *udpsocket = i->data;
- nice_socket_free (udpsocket);
- }
g_slist_free (component->local_candidates);
component->local_candidates = NULL;
- g_slist_free (component->sockets);
- component->sockets = NULL;
}
discovery_prune_stream (agent, stream_id);
}
MAX_BUFFER_SIZE, buf);
if (len < 0) {
- GSource *source = ctx->source;
-
- component->gsources = g_slist_remove (component->gsources, source);
- g_source_destroy (source);
- g_source_unref (source);
-
- /* We don't close the socket because it would be way too complicated to
- * take care of every path where the socket might still be used.. */
+ /* Error. Detach the source but don’t close the socket. We don’t close the
+ * socket because it would be way too complicated to take care of every path
+ * where it might still be used. */
nice_debug ("Agent %p: unable to recv from socket %p. Detaching",
ctx->agent, ctx->socket);
+ component_detach_socket_source (component, ctx->socket);
} else if (len > 0 && component->g_source_io_cb) {
gpointer data = ctx->component->data;
gint sid = ctx->stream->id;
}
/*
- * Attaches one socket handle to the main loop event context
+ * Attaches one socket handle to the main loop event context.
+ *
+ * Takes ownership of the socket.
*/
void
GSource *source;
IOCtx *ctx;
- if (!component->ctx)
+ if (!component->ctx) {
+ component_add_detached_socket (component, socket);
return;
+ }
/* note: without G_IO_ERR the glib mainloop goes into
* busyloop if errors are encountered */
- source = g_socket_create_source(socket->fileno, G_IO_IN | G_IO_ERR, NULL);
+ source = g_socket_create_source (socket->fileno, G_IO_IN | G_IO_ERR, NULL);
ctx = io_ctx_new (agent, stream, component, socket, source);
g_source_set_callback (source, (GSourceFunc) nice_agent_g_source_cb,
ctx, (GDestroyNotify) io_ctx_free);
- nice_debug ("Agent %p : Attach source %p (stream %u).", agent, source, stream->id);
- g_source_attach (source, component->ctx);
- component->gsources = g_slist_append (component->gsources, source);
+ nice_debug ("Agent %p : Attach source %p (stream %u).", agent, source,
+ stream->id);
+
+ /* Add the pair to the component. */
+ component_add_socket_source (component, socket, source);
}
* context.
*
*/
-static gboolean
+static void
priv_attach_stream_component (NiceAgent *agent,
Stream *stream,
Component *component)
{
GSList *i;
- for (i = component->sockets; i; i = i->next)
- agent_attach_stream_component_socket (agent, stream, component, i->data);
-
- return TRUE;
-}
-
-/*
- * Detaches socket handles of 'stream' from the main eventloop
- * context.
- *
- */
-static void priv_detach_stream_component (Stream *stream, Component *component)
-{
- GSList *i;
+ /* Don’t bother if there is no main context. */
+ if (component->ctx == NULL)
+ return;
- for (i = component->gsources; i; i = i->next) {
- GSource *source = i->data;
- nice_debug ("Detach source %p (stream %u).", source, stream->id);
- g_source_destroy (source);
- g_source_unref (source);
+ for (i = component->socket_sources; i != NULL; i = i->next) {
+ SocketSource *socket_source = i->data;
+ agent_attach_stream_component_socket (agent, stream, component,
+ socket_source->socket);
}
-
- g_slist_free (component->gsources);
- component->gsources = NULL;
}
NICEAPI_EXPORT gboolean
Stream *stream = NULL;
gboolean ret = FALSE;
+ /* ctx must be non-NULL if func is non-NULL. */
+ g_return_val_if_fail (func == NULL || ctx != NULL, FALSE);
+
agent_lock();
/* attach candidates */
}
if (component->g_source_io_cb)
- priv_detach_stream_component (stream, component);
+ component_detach_socket_sources (component);
ret = TRUE;
#include "component.h"
#include "agent-priv.h"
+
+static void
+socket_source_detach (SocketSource *source)
+{
+ if (source->source != NULL) {
+ g_source_destroy (source->source);
+ g_source_unref (source->source);
+ }
+ source->source = NULL;
+}
+
+static void
+socket_source_free (SocketSource *source)
+{
+ nice_socket_free (source->socket);
+ socket_source_detach (source);
+
+ g_slice_free (SocketSource, source);
+}
+
+
Component *
component_new (guint id)
{
return component;
}
-
void
component_free (Component *cmp)
{
nice_candidate_free (cmp->restart_candidate),
cmp->restart_candidate = NULL;
- for (i = cmp->sockets; i; i = i->next) {
- NiceSocket *udpsocket = i->data;
- nice_socket_free (udpsocket);
- }
-
- for (i = cmp->gsources; i; i = i->next) {
- GSource *source = i->data;
- g_source_destroy (source);
- g_source_unref (source);
- }
-
for (i = cmp->incoming_checks; i; i = i->next) {
IncomingCheck *icheck = i->data;
g_free (icheck->username);
g_slist_free (cmp->local_candidates);
g_slist_free (cmp->remote_candidates);
- g_slist_free (cmp->sockets);
- g_slist_free (cmp->gsources);
+ g_slist_free_full (cmp->socket_sources, (GDestroyNotify) socket_source_free);
g_slist_free (cmp->incoming_checks);
for (item = cmp->turn_servers; item; item = g_list_next (item)) {
return local;
}
+
+static gint
+_find_socket_source (gconstpointer a, gconstpointer b)
+{
+ const SocketSource *source_a = a;
+ const NiceSocket *socket_b = b;
+
+ return (source_a->socket == socket_b) ? 0 : 1;
+}
+
+/* This takes ownership of socket and source.
+ * It attaches the source to the component’s context. */
+void
+component_add_socket_source (Component *component, NiceSocket *socket,
+ GSource *source)
+{
+ GSList *l;
+ SocketSource *socket_source;
+
+ g_assert (component != NULL);
+ g_assert (socket != NULL);
+ g_assert (source != NULL);
+
+ /* Find an existing SocketSource in the component which contains socket, or
+ * create a new one. */
+ l = g_slist_find_custom (component->socket_sources, socket,
+ _find_socket_source);
+ if (l != NULL) {
+ socket_source = l->data;
+ } else {
+ socket_source = g_slice_new0 (SocketSource);
+ socket_source->socket = socket;
+ component->socket_sources =
+ g_slist_prepend (component->socket_sources, socket_source);
+ }
+
+ /* Add the source. */
+ g_assert (socket_source->source == NULL);
+ g_assert (component->ctx != NULL);
+ socket_source->source = source;
+ g_source_attach (source, component->ctx);
+}
+
+void
+component_add_detached_socket (Component *component, NiceSocket *socket)
+{
+ SocketSource *socket_source;
+
+ socket_source = g_slice_new0 (SocketSource);
+ socket_source->socket = socket;
+ socket_source->source = NULL;
+ component->socket_sources =
+ g_slist_prepend (component->socket_sources, socket_source);
+}
+
+/**
+ * component_detach_socket_source:
+ * @component: a #Component
+ * @socket: the socket to detach the source for
+ *
+ * Detach the #GSource for the single specified @socket. Leave the socket itself
+ * untouched.
+ *
+ * If the @socket doesn’t exist in this @component, do nothing.
+ */
+void
+component_detach_socket_source (Component *component, NiceSocket *socket)
+{
+ GSList *l;
+ SocketSource *socket_source;
+
+ /* Find the SocketSource for the socket. */
+ l = g_slist_find_custom (component->socket_sources, socket,
+ _find_socket_source);
+ if (l == NULL)
+ return;
+
+ /* Detach the source. */
+ socket_source = l->data;
+ socket_source_detach (socket_source);
+}
+
+/*
+ * Detaches socket handles of @component from the main context. Leaves the
+ * sockets themselves untouched.
+ */
+void
+component_detach_socket_sources (Component *component)
+{
+ GSList *i;
+
+ for (i = component->socket_sources; i != NULL; i = i->next) {
+ SocketSource *socket_source = i->data;
+ nice_debug ("Detach source %p.", socket_source->source);
+ socket_source_detach (socket_source);
+ }
+}
+
+void
+component_free_socket_sources (Component *component)
+{
+ g_slist_free_full (component->socket_sources,
+ (GDestroyNotify) socket_source_free);
+ component->socket_sources = NULL;
+}
Component *component;
} TcpUserData;
+/* A pair of a socket and the GSource which polls it from the main loop. All
+ * GSources in a Component must be attached to the same main context:
+ * component->ctx.
+ *
+ * Socket must be non-NULL, but source may be NULL if it has been detached. */
+typedef struct {
+ NiceSocket *socket;
+ GSource *source;
+} SocketSource;
+
struct _Component
{
NiceComponentType type;
NiceComponentState state;
GSList *local_candidates; /**< list of Candidate objs */
GSList *remote_candidates; /**< list of Candidate objs */
- GSList *sockets; /**< list of NiceSocket objs */
- GSList *gsources; /**< list of GSource objs */
+ GSList *socket_sources; /**< list of SocketSource objs */
GSList *incoming_checks; /**< list of IncomingCheck objs */
GList *turn_servers; /**< List of TURN servers */
CandidatePair selected_pair; /**< independent from checklists,
component_set_selected_remote_candidate (NiceAgent *agent, Component *component,
NiceCandidate *candidate);
+void
+component_add_socket_source (Component *component, NiceSocket *socket,
+ GSource *source);
+void
+component_add_detached_socket (Component *component, NiceSocket *socket);
+
+void
+component_detach_socket_source (Component *component, NiceSocket *socket);
+void
+component_detach_socket_sources (Component *component);
+void
+component_free_socket_sources (Component *component);
+
G_END_DECLS
#endif /* _NICE_COMPONENT_H */
if (!udp_socket)
goto errors;
-
- _priv_set_socket_tos (agent, udp_socket, stream->tos);
- agent_attach_stream_component_socket (agent, stream,
- component, udp_socket);
-
candidate->sockptr = udp_socket;
candidate->addr = udp_socket->addr;
candidate->base_addr = udp_socket->addr;
if (!priv_add_local_candidate_pruned (agent, stream_id, component, candidate))
goto errors;
- component->sockets = g_slist_append (component->sockets, udp_socket);
+ _priv_set_socket_tos (agent, udp_socket, stream->tos);
+ agent_attach_stream_component_socket (agent, stream,
+ component, udp_socket);
return candidate;
if (!priv_add_local_candidate_pruned (agent, stream_id, component, candidate))
goto errors;
- component->sockets = g_slist_append (component->sockets, relay_socket);
+ component_add_detached_socket (component, relay_socket);
agent_signal_new_candidate (agent, candidate);
return candidate;