[Pkg-telepathy-commits] [libnice] 91/265: agent: Combine nice_agent_recv() and nice_agent_recv_nonblocking()
Simon McVittie
smcv at debian.org
Wed May 14 12:04:56 UTC 2014
This is an automated email from the git hooks/post-receive script.
smcv pushed a commit to branch debian
in repository libnice.
commit b560a86f66b516aab07dd12ea1369928d3ef9635
Author: Philip Withnall <philip.withnall at collabora.co.uk>
Date: Tue Jan 14 09:32:10 2014 +0000
agent: Combine nice_agent_recv() and nice_agent_recv_nonblocking()
Sharing is caring.
---
agent/agent.c | 273 +++++++++++++++++++++-------------------------------------
1 file changed, 100 insertions(+), 173 deletions(-)
diff --git a/agent/agent.c b/agent/agent.c
index 0669b9c..b9bcf3b 100644
--- a/agent/agent.c
+++ b/agent/agent.c
@@ -2463,47 +2463,10 @@ nice_agent_recv_cancelled_cb (GCancellable *cancellable, gpointer user_data)
return !g_cancellable_set_error_if_cancelled (cancellable, error);
}
-/**
- * nice_agent_recv:
- * @agent: a #NiceAgent
- * @stream_id: the ID of the stream to receive on
- * @component_id: the ID of the component to receive on
- * @buf: (array length=buf_len) (out caller-allocates): caller-allocated buffer
- * to write the received data into, of length at least @buf_len
- * @buf_len: length of @buf
- * @cancellable: (allow-none): a #GCancellable to allow the operation to be
- * cancelled from another thread, or %NULL
- * @error: (allow-none): return location for a #GError, or %NULL
- *
- * Block on receiving data from the given stream/component combination on
- * @agent, returning only once at least 1 byte has been received and written
- * into @buf, the stream is closed by the other end or by calling
- * nice_agent_remove_stream(), or @cancellable is cancelled.
- *
- * In the non-error case, in reliable mode, this will block until exactly
- * @buf_len bytes have been received. In non-reliable mode, it will block until
- * a single message has been received. In this case, @buf must be big enough to
- * contain an entire message (65536 bytes), or any excess data may be silently
- * dropped.
- *
- * This must not be used in combination with nice_agent_attach_recv() on the
- * same stream/component pair.
- *
- * Internally, this may iterate the current thread’s default main context.
- *
- * If the stream/component pair doesn’t exist, or if a suitable candidate socket
- * hasn’t yet been selected for it, a %G_IO_ERROR_BROKEN_PIPE error will be
- * returned. A %G_IO_ERROR_CANCELLED error will be returned if the operation was
- * cancelled. %G_IO_ERROR_FAILED will be returned for other errors.
- *
- * Returns: the number of bytes written to @buf on success (guaranteed to be
- * greater than 0 unless @buf_len is 0), or -1 on error
- *
- * Since: 0.1.5
- */
-NICEAPI_EXPORT gssize
-nice_agent_recv (NiceAgent *agent, guint stream_id, guint component_id,
- guint8 *buf, gsize buf_len, GCancellable *cancellable, GError **error)
+static gssize
+nice_agent_recv_blocking_or_nonblocking (NiceAgent *agent, guint stream_id,
+ guint component_id, gboolean blocking, guint8 *buf, gsize buf_len,
+ GCancellable *cancellable, GError **error)
{
GMainContext *context;
Stream *stream;
@@ -2511,6 +2474,7 @@ nice_agent_recv (NiceAgent *agent, guint stream_id, guint component_id,
gssize len = -1;
GSource *cancellable_source = NULL;
gboolean received_enough = FALSE, error_reported = FALSE;
+ gboolean all_sockets_would_block = FALSE;
GError *child_error = NULL;
g_return_val_if_fail (NICE_IS_AGENT (agent), -1);
@@ -2588,21 +2552,57 @@ nice_agent_recv (NiceAgent *agent, guint stream_id, guint component_id,
g_mutex_unlock (&component->io_mutex);
+ /* For a reliable stream, grab any data from the pseudo-TCP input buffer
+ * before trying the sockets. */
+ if (agent->reliable && component->tcp != NULL &&
+ pseudo_tcp_socket_get_available_bytes (component->tcp) > 0) {
+ len = pseudo_tcp_socket_recv (component->tcp, (gchar *) component->recv_buf,
+ component->recv_buf_len);
+ adjust_tcp_clock (agent, stream, component);
+
+ nice_debug ("%s: Received %" G_GSSIZE_FORMAT " bytes from pseudo-TCP read "
+ "buffer.", G_STRFUNC, len);
+
+ if (len < 0 &&
+ pseudo_tcp_socket_get_error (component->tcp) == EWOULDBLOCK) {
+ len = 0;
+ } else if (len < 0 &&
+ pseudo_tcp_socket_get_error (component->tcp) == ENOTCONN) {
+ g_set_error (&child_error, G_IO_ERROR, G_IO_ERROR_BROKEN_PIPE,
+ "Error reading data from pseudo-TCP socket: not connected.");
+ } else if (len < 0) {
+ g_set_error (&child_error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Error reading data from pseudo-TCP socket.");
+ } else if (len > 0) {
+ /* Got some data! */
+ component->recv_buf_valid_len += len;
+ }
+
+ received_enough = (component->recv_buf_valid_len == buf_len);
+ error_reported = (child_error != NULL);
+ }
+
/* Each iteration of the main context will either receive some data, a
* cancellation error or a socket error.
*
- * In reliable mode, iterate the loop enough to receive exactly @buf_len
- * bytes. In non-reliable mode, iterate the loop to receive a single message.
+ * In blocking, reliable mode, iterate the loop enough to receive exactly
+ * @buf_len bytes. In blocking, non-reliable mode, iterate the loop to receive
+ * a single message. In non-blocking mode, stop iterating the loop if all
+ * sockets would block (i.e. if no data was received for an iteration).
*/
- while (!received_enough && !error_reported) {
+ while (!received_enough && !error_reported && !all_sockets_would_block) {
+ gsize prev_recv_buf_valid_len = component->recv_buf_valid_len;
+
agent_unlock ();
- g_main_context_iteration (context, TRUE);
+ g_main_context_iteration (context, blocking);
agent_lock ();
received_enough =
- ((agent->reliable && component->recv_buf_valid_len >= buf_len) ||
+ ((agent->reliable && component->recv_buf_valid_len == buf_len) ||
(!agent->reliable && component->recv_buf_valid_len > 0));
error_reported = (child_error != NULL);
+ all_sockets_would_block =
+ !blocking && (component->recv_buf_valid_len == prev_recv_buf_valid_len);
}
len = component->recv_buf_valid_len;
@@ -2619,14 +2619,18 @@ nice_agent_recv (NiceAgent *agent, guint stream_id, guint component_id,
g_main_context_unref (context);
/* Handle errors and cancellations. */
- if (!received_enough) {
- g_assert (error_reported);
+ if (error_reported) {
+ len = -1;
+ } else if (len == 0 && all_sockets_would_block) {
+ g_set_error_literal (&child_error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK,
+ g_strerror (EAGAIN));
len = -1;
}
done:
g_assert ((child_error != NULL) == (len == -1));
g_assert (len != 0);
+ g_assert (len < 0 || (gsize) len <= buf_len);
if (child_error != NULL)
g_propagate_error (error, child_error);
@@ -2637,6 +2641,52 @@ done:
}
/**
+ * nice_agent_recv:
+ * @agent: a #NiceAgent
+ * @stream_id: the ID of the stream to receive on
+ * @component_id: the ID of the component to receive on
+ * @buf: (array length=buf_len) (out caller-allocates): caller-allocated buffer
+ * to write the received data into, of length at least @buf_len
+ * @buf_len: length of @buf
+ * @cancellable: (allow-none): a #GCancellable to allow the operation to be
+ * cancelled from another thread, or %NULL
+ * @error: (allow-none): return location for a #GError, or %NULL
+ *
+ * Block on receiving data from the given stream/component combination on
+ * @agent, returning only once at least 1 byte has been received and written
+ * into @buf, the stream is closed by the other end or by calling
+ * nice_agent_remove_stream(), or @cancellable is cancelled.
+ *
+ * In the non-error case, in reliable mode, this will block until exactly
+ * @buf_len bytes have been received. In non-reliable mode, it will block until
+ * a single message has been received. In this case, @buf must be big enough to
+ * contain an entire message (65536 bytes), or any excess data may be silently
+ * dropped.
+ *
+ * This must not be used in combination with nice_agent_attach_recv() on the
+ * same stream/component pair.
+ *
+ * Internally, this may iterate the current thread’s default main context.
+ *
+ * If the stream/component pair doesn’t exist, or if a suitable candidate socket
+ * hasn’t yet been selected for it, a %G_IO_ERROR_BROKEN_PIPE error will be
+ * returned. A %G_IO_ERROR_CANCELLED error will be returned if the operation was
+ * cancelled. %G_IO_ERROR_FAILED will be returned for other errors.
+ *
+ * Returns: the number of bytes written to @buf on success (guaranteed to be
+ * greater than 0 unless @buf_len is 0), or -1 on error
+ *
+ * Since: 0.1.5
+ */
+NICEAPI_EXPORT gssize
+nice_agent_recv (NiceAgent *agent, guint stream_id, guint component_id,
+ guint8 *buf, gsize buf_len, GCancellable *cancellable, GError **error)
+{
+ return nice_agent_recv_blocking_or_nonblocking (agent, stream_id,
+ component_id, TRUE, buf, buf_len, cancellable, error);
+}
+
+/**
* nice_agent_recv_nonblocking:
* @agent: a #NiceAgent
* @stream_id: the ID of the stream to receive on
@@ -2684,131 +2734,8 @@ nice_agent_recv_nonblocking (NiceAgent *agent, guint stream_id,
guint component_id, guint8 *buf, gsize buf_len, GCancellable *cancellable,
GError **error)
{
- Component *component;
- Stream *stream;
- gssize total_len = 0;
- gboolean received_enough = FALSE, error_reported = FALSE;
- gboolean all_sockets_would_block = FALSE;
- GError *child_error = NULL;
-
- if (buf_len == 0)
- return 0;
-
- /* Support cancellation at the beginning only. */
- if (g_cancellable_set_error_if_cancelled (cancellable, error))
- return -1;
-
- /* Try and receive some data. */
- agent_lock ();
-
- if (!agent_find_component (agent, stream_id, component_id,
- &stream, &component)) {
- g_set_error (&child_error, G_IO_ERROR, G_IO_ERROR_BROKEN_PIPE,
- "Invalid stream/component.");
- total_len = -1;
- goto done;
- }
-
- /* For a reliable stream, grab any data from the pseudo-TCP input buffer
- * before trying the sockets (which we try to see if there’s any more data
- * available to read without blocking). */
- if (agent->reliable && component->tcp != NULL &&
- pseudo_tcp_socket_get_available_bytes (component->tcp) > 0) {
- gssize len;
-
- len = pseudo_tcp_socket_recv (component->tcp, (gchar *) buf, buf_len);
- adjust_tcp_clock (agent, stream, component);
-
- nice_debug ("%s: Received %" G_GSSIZE_FORMAT " bytes from pseudo-TCP read "
- "buffer.", G_STRFUNC, len);
-
- if (len < 0 &&
- pseudo_tcp_socket_get_error (component->tcp) == EWOULDBLOCK) {
- len = 0;
- } else if (len < 0 &&
- pseudo_tcp_socket_get_error (component->tcp) == ENOTCONN) {
- g_set_error (&child_error, G_IO_ERROR, G_IO_ERROR_BROKEN_PIPE,
- "Error reading data from pseudo-TCP socket: not connected.");
- } else if (len < 0) {
- g_set_error (&child_error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Error reading data from pseudo-TCP socket.");
- } else if (len > 0) {
- /* Got some data! */
- buf += len;
- buf_len -= len;
- total_len += len;
- }
-
- received_enough = ((gsize) total_len == buf_len);
- error_reported = (len < 0);
- }
-
- /* Each call to agent_recv_locked() will either receive some data or a socket
- * error (including EWOULDBLOCK). (Cancellation is not supported.) If *any*
- * socket returns an error, discard all the data in @buf and return an error
- * from nice_agent_recv_nonblocking() overall.
- *
- * In reliable mode, iterate the loop enough to receive at least one byte.
- * In non-reliable mode, iterate the loop to receive a single message. */
- while (!received_enough && !error_reported && !all_sockets_would_block) {
- GSList *i;
- gssize len = 0;
-
- for (i = component->socket_sources; i != NULL; i = i->next) {
- SocketSource *socket_source = i->data;
-
- /* Actually read the data. This will return 0 if the data has already been
- * handled (e.g. for STUN control packets). */
- len = agent_recv_locked (agent, stream, component,
- socket_source->socket, buf, buf_len);
-
- nice_debug ("%s: Received %" G_GSSIZE_FORMAT " bytes from socket %p.",
- G_STRFUNC, len, socket_source->socket);
-
- if (len < 0) {
- g_set_error (&child_error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Unable to receive from socket %p. Detaching.",
- socket_source->socket);
-
- break;
- } else if (len > 0) {
- /* Got some data! */
- buf += len;
- buf_len -= len;
- total_len += len;
-
- break;
- }
- }
-
- received_enough =
- ((agent->reliable && (gsize) total_len == buf_len) ||
- (!agent->reliable && total_len > 0));
- error_reported = (len < 0);
- all_sockets_would_block = (len == 0);
- }
-
- nice_debug ("%s: total_len: %" G_GSSIZE_FORMAT ", buf_len: %" G_GSIZE_FORMAT,
- G_STRFUNC, total_len, buf_len);
-
- if (error_reported) {
- total_len = -1;
- } else if (total_len == 0 && all_sockets_would_block) {
- g_set_error_literal (&child_error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK,
- g_strerror (EAGAIN));
- total_len = -1;
- }
-
-done:
- g_assert ((child_error != NULL) == (total_len == -1));
- g_assert (total_len != 0);
-
- if (child_error != NULL)
- g_propagate_error (error, child_error);
-
- agent_unlock ();
-
- return total_len;
+ return nice_agent_recv_blocking_or_nonblocking (agent, stream_id,
+ component_id, FALSE, buf, buf_len, cancellable, error);
}
/**
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-telepathy/libnice.git
More information about the Pkg-telepathy-commits
mailing list