Commit 243c47ec authored by Philip Withnall's avatar Philip Withnall Committed by Olivier Crête

agent: Add nice_agent_recv() allowing blocking receives on sockets

This is a blocking receive function, designed to be called from a worker
thread. It cannot be used in conjunction with the existing
nice_agent_attach_recv() API, as the blocking receive and the GSource
would compete over access to the single copy of the data in the kernel’s
receive buffer.
parent c5672702
......@@ -178,4 +178,7 @@ component_io_cb (
GIOCondition condition,
gpointer data);
gssize agent_recv_locked (NiceAgent *agent, Stream *stream,
Component *component, NiceSocket *socket, guint8 *buf, gsize buf_len);
#endif /*_NICE_AGENT_PRIV_H */
This diff is collapsed.
......@@ -676,6 +676,15 @@ nice_agent_attach_recv (
NiceAgentRecvFunc func,
gpointer data);
gssize
nice_agent_recv (
NiceAgent *agent,
guint stream_id,
guint component_id,
guint8 *buf,
gsize buf_len,
GCancellable *cancellable,
GError **error);
/**
* nice_agent_set_selected_pair:
......
......@@ -61,7 +61,7 @@ component_deschedule_io_callback (Component *component);
/* Must *not* take the agent lock, since it’s called from within
* component_set_io_callback(), which holds the Component’s I/O lock. */
* component_set_io_context(), which holds the Component’s I/O lock. */
static void
socket_source_attach (SocketSource *socket_source, GMainContext *context)
{
......@@ -129,7 +129,7 @@ component_new (guint id, NiceAgent *agent, Stream *stream)
* will be updated when nice_agent_attach_recv() or nice_agent_recv() are
* called. */
component_set_io_context (component, NULL);
component_set_io_callback (component, NULL, NULL);
component_set_io_callback (component, NULL, NULL, NULL, 0, NULL);
return component;
}
......@@ -438,7 +438,7 @@ component_attach_socket (Component *component, NiceSocket *socket)
/* Reattaches socket handles of @component to the main context.
*
* Must *not* take the agent lock, since it’s called from within
* component_set_io_callback(), which holds the Component’s I/O lock. */
* component_set_io_context(), which holds the Component’s I/O lock. */
static void
component_reattach_all_sockets (Component *component)
{
......@@ -486,7 +486,7 @@ component_detach_socket (Component *component, NiceSocket *socket)
* sockets themselves untouched.
*
* Must *not* take the agent lock, since it’s called from within
* component_set_io_callback(), which holds the Component’s I/O lock.
* component_set_io_context(), which holds the Component’s I/O lock.
*/
void
component_detach_all_sockets (Component *component)
......@@ -511,6 +511,12 @@ component_free_socket_sources (Component *component)
component->socket_sources = NULL;
}
GMainContext *
component_dup_io_context (Component *component)
{
return g_main_context_ref (component->ctx);
}
/* If @context is %NULL, a fresh context is used, so component->ctx is always
* guaranteed to be non-%NULL. */
void
......@@ -534,24 +540,40 @@ component_set_io_context (Component *component, GMainContext *context)
g_mutex_unlock (&component->io_mutex);
}
/* (func, user_data) and (recv_buf, recv_buf_len) are mutually exclusive.
* At most one of the two must be specified; if both are NULL, the Component
* will not receive any data (i.e. reception is paused). */
void
component_set_io_callback (Component *component,
NiceAgentRecvFunc func, gpointer user_data)
NiceAgentRecvFunc func, gpointer user_data,
guint8 *recv_buf, gsize recv_buf_len,
GError **error)
{
g_assert (func == NULL || recv_buf == NULL);
g_assert (recv_buf != NULL || recv_buf_len == 0);
g_assert (error == NULL || *error == NULL);
g_mutex_lock (&component->io_mutex);
if (func != NULL) {
component->io_callback = func;
component->io_user_data = user_data;
component->recv_buf = NULL;
component->recv_buf_len = 0;
component_schedule_io_callback (component);
} else {
component->io_callback = NULL;
component->io_user_data = NULL;
component->recv_buf = recv_buf;
component->recv_buf_len = recv_buf_len;
component_deschedule_io_callback (component);
}
component->recv_buf_valid_len = 0;
component->recv_buf_error = error;
g_mutex_unlock (&component->io_mutex);
}
......
......@@ -150,7 +150,10 @@ struct _Component
/* I/O handling. The main context must always be non-NULL, and is used for all
* socket recv() operations. All io_callback emissions are invoked in this
* context too. */
* context too.
*
* recv_buf and io_callback are mutually exclusive, but it is allowed for both
* to be NULL if the Component is not currently ready to receive data. */
GMutex io_mutex; /**< protects io_callback, io_user_data,
pending_io_messages and io_callback_id.
immutable: can be accessed without
......@@ -159,8 +162,6 @@ struct _Component
taken before this one */
NiceAgentRecvFunc io_callback; /**< function called on io cb */
gpointer io_user_data; /**< data passed to the io function */
GMainContext *ctx; /**< context for GSources for this
component */
GQueue pending_io_messages; /**< queue of packets which have been
received but not passed to the client
in an I/O callback or recv() call yet.
......@@ -168,6 +169,13 @@ struct _Component
IOCallbackData */
guint io_callback_id; /* GSource ID of the I/O callback */
GMainContext *ctx; /**< context for GSources for this
component */
guint8 *recv_buf; /**< unowned buffer for receiving into */
gsize recv_buf_len; /**< allocated size of recv_buf in bytes */
gsize recv_buf_valid_len; /**< length of valid data in recv_buf */
GError **recv_buf_error; /**< error information about failed reads */
NiceAgent *agent; /* unowned, immutable: can be accessed without holding the
* agent lock */
Stream *stream; /* unowned, immutable: can be accessed without holding the
......@@ -212,11 +220,15 @@ component_detach_all_sockets (Component *component);
void
component_free_socket_sources (Component *component);
GMainContext *
component_dup_io_context (Component *component);
void
component_set_io_context (Component *component, GMainContext *context);
void
component_set_io_callback (Component *component,
NiceAgentRecvFunc func, gpointer user_data);
NiceAgentRecvFunc func, gpointer user_data,
guint8 *recv_buf, gsize recv_buf_len,
GError **error);
void
component_emit_io_callback (Component *component,
const guint8 *buf, gsize buf_len);
......
......@@ -23,6 +23,7 @@ nice_agent_get_remote_candidates
nice_agent_get_local_candidates
nice_agent_get_selected_pair
nice_agent_send
nice_agent_recv
nice_agent_attach_recv
nice_agent_set_selected_pair
nice_agent_set_selected_remote_candidate
......
......@@ -16,6 +16,7 @@ nice_address_set_port
nice_address_to_string
nice_agent_add_local_address
nice_agent_add_stream
nice_agent_recv
nice_agent_attach_recv
nice_agent_gather_candidates
nice_agent_generate_local_candidate_sdp
......
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