[Pkg-telepathy-commits] [libnice] 79/265: agent: Add a nice_agent_send_full() API exposing error information

Simon McVittie smcv at debian.org
Wed May 14 12:04:55 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 5d63de5a952dbb56d1141175a55dd40dea4396be
Author: Philip Withnall <philip.withnall at collabora.co.uk>
Date:   Fri Jan 3 11:18:51 2014 +0000

    agent: Add a nice_agent_send_full() API exposing error information
    
    This adds GError and GCancellable parameters to the existing
    nice_agent_send() API, and is identical in all other respects (notably,
    it is non-blocking).
    
    The GCancellable is currently unused, but could be used in future if the
    API grows to support blocking writes.
    
    The GError is used to return more interesting error codes than just
    ‘-1’.
---
 agent/agent.c                               | 141 +++++++++++++++++++++++-----
 agent/agent.h                               |  10 ++
 docs/reference/libnice/libnice-sections.txt |   1 +
 nice/libnice.sym                            |   1 +
 4 files changed, 131 insertions(+), 22 deletions(-)

diff --git a/agent/agent.c b/agent/agent.c
index bd21e78..020e60c 100644
--- a/agent/agent.c
+++ b/agent/agent.c
@@ -2636,39 +2636,106 @@ done:
   return len;
 }
 
-NICEAPI_EXPORT gint
-nice_agent_send (
+/**
+ * nice_agent_send_full:
+ * @agent: a #NiceAgent
+ * @stream_id: the ID of the stream to send to
+ * @component_id: the ID of the component to send to
+ * @buf: (array length=buf_len): data to transmit, of at least @buf_len bytes in
+ * size
+ * @buf_len: length of valid data in @buf, in bytes
+ * @cancellable: (allow-none): a #GCancellable to cancel the operation from
+ * another thread, or %NULL
+ * @error: (allow-none): return location for a #GError, or %NULL
+ *
+ * Sends the data in @buf on the socket identified by the given stream/component
+ * pair. Transmission is non-blocking, so a %G_IO_ERROR_WOULD_BLOCK error may be
+ * returned if the send buffer is full.
+ *
+ * As with nice_agent_send(), the given component must be in
+ * %NICE_COMPONENT_STATE_READY or, as a special case, in any state if it was
+ * previously ready and was then restarted.
+ *
+ * On success, the number of bytes written to the socket will be returned (which
+ * will always be @buf_len when in non-reliable mode, and may be less than
+ * @buf_len when in reliable mode).
+ *
+ * On failure, -1 will be returned and @error will be set. If the #NiceAgent is
+ * reliable and the socket is not yet connected, %G_IO_ERROR_BROKEN_PIPE will be
+ * returned; if the write buffer is full, %G_IO_ERROR_WOULD_BLOCK will be
+ * returned. In both cases, wait for the #NiceAgent::reliable-transport-writable
+ * signal before trying again. If the given @stream_id or @component_id are
+ * invalid or not yet connected, %G_IO_ERROR_BROKEN_PIPE will be returned.
+ * %G_IO_ERROR_FAILED will be returned for other errors.
+ *
+ * Returns: the number of bytes sent (guaranteed to be greater than 0), or -1 on
+ * error
+ *
+ * Since: 0.1.5
+ */
+NICEAPI_EXPORT gssize
+nice_agent_send_full (
   NiceAgent *agent,
   guint stream_id,
   guint component_id,
-  guint len,
-  const gchar *buf)
+  const guint8 *buf,
+  gsize buf_len,
+  GCancellable *cancellable,
+  GError **error)
 {
   Stream *stream;
   Component *component;
-  gint ret = -1;
+  gssize ret = -1;
+  GError *child_error = NULL;
 
-  agent_lock();
+  g_return_val_if_fail (NICE_IS_AGENT (agent), -1);
+  g_return_val_if_fail (stream_id >= 1, -1);
+  g_return_val_if_fail (component_id >= 1, -1);
+  g_return_val_if_fail (buf != NULL, -1);
+  g_return_val_if_fail (
+      cancellable == NULL || G_IS_CANCELLABLE (cancellable), -1);
+  g_return_val_if_fail (error == NULL || *error == NULL, -1);
+
+  agent_lock ();
 
   if (!agent_find_component (agent, stream_id, component_id,
           &stream, &component)) {
-    g_critical ("Unknown stream/component combination: %d:%d",
-        stream_id, component_id);
+    g_set_error (&child_error, G_IO_ERROR, G_IO_ERROR_BROKEN_PIPE,
+                 "Invalid stream/component.");
     goto done;
   }
 
+  /* FIXME: Cancellation isn’t yet supported, but it doesn’t matter because
+   * we only deal with non-blocking writes. */
+
   if (component->tcp != NULL) {
-    ret = pseudo_tcp_socket_send (component->tcp, buf, len);
+    /* Send on the pseudo-TCP socket. */
+    ret = pseudo_tcp_socket_send (component->tcp, (const gchar *) buf, buf_len);
     adjust_tcp_clock (agent, stream, component);
-    /*
-    if (ret == -1 &&
-        pseudo_tcp_socket_get_error (component->tcp) != EWOULDBLOCK) {
-        }
-    */
+
     /* In case of -1, the error is either EWOULDBLOCK or ENOTCONN, which both
        need the user to wait for the reliable-transport-writable signal */
-  } else if(agent->reliable) {
-    nice_debug ("Trying to send on a pseudo tcp FAILED component");
+    if (ret < 0 &&
+        pseudo_tcp_socket_get_error (component->tcp) == EWOULDBLOCK) {
+      g_set_error (&child_error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK,
+          "Write would block.");
+      goto done;
+    } else if (ret < 0 &&
+        pseudo_tcp_socket_get_error (component->tcp) == ENOTCONN) {
+      g_set_error (&child_error, G_IO_ERROR, G_IO_ERROR_BROKEN_PIPE,
+          "TCP connection is not yet established.");
+      goto done;
+    } else if (ret < 0) {
+      /* Signal error */
+      priv_pseudo_tcp_error (agent, stream, component);
+
+      g_set_error (&child_error, G_IO_ERROR, G_IO_ERROR_FAILED,
+          "Error writing data to pseudo-TCP socket.");
+      goto done;
+    }
+  } else if (agent->reliable) {
+    g_set_error (&child_error, G_IO_ERROR, G_IO_ERROR_FAILED,
+        "Error writing data to failed pseudo-TCP socket.");
     goto done;
   } else if (component->selected_pair.local != NULL) {
     NiceSocket *sock;
@@ -2678,24 +2745,54 @@ nice_agent_send (
     gchar tmpbuf[INET6_ADDRSTRLEN];
     nice_address_to_string (&component->selected_pair.remote->addr, tmpbuf);
 
-    nice_debug ("Agent %p : s%d:%d: sending %d bytes to [%s]:%d", agent, stream_id, component_id,
-        len, tmpbuf,
+    nice_debug ("Agent %p : s%d:%d: sending %" G_GSIZE_FORMAT " bytes to "
+        "[%s]:%d", agent, stream_id, component_id, buf_len, tmpbuf,
         nice_address_get_port (&component->selected_pair.remote->addr));
 #endif
 
     sock = component->selected_pair.local->sockptr;
     addr = &component->selected_pair.remote->addr;
-    if (nice_socket_send (sock, addr, len, buf)) {
-      ret = len;
+
+    if (nice_socket_send (sock, addr, buf_len, (const gchar *) buf)) {
+      /* Success: sent all the bytes. */
+      ret = buf_len;
+    } else {
+      /* Some error. Since nice_socket_send() provides absolutely no useful
+       * feedback, assume it’s EWOULDBLOCK. */
+      g_set_error (&child_error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK,
+          "Error writing data to socket: probably would block.");
+      goto done;
     }
+  } else {
+    /* Socket isn’t properly open yet. */
+    g_set_error (&child_error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK,
+        "Can’t send: No selected pair yet.");
     goto done;
   }
 
- done:
-  agent_unlock();
+done:
+  g_assert ((child_error != NULL) == (ret == -1));
+  g_assert (ret != 0);
+
+  if (child_error != NULL)
+    g_propagate_error (error, child_error);
+
+  agent_unlock ();
+
   return ret;
 }
 
+NICEAPI_EXPORT gint
+nice_agent_send (
+  NiceAgent *agent,
+  guint stream_id,
+  guint component_id,
+  guint len,
+  const gchar *buf)
+{
+  return nice_agent_send_full (agent, stream_id, component_id,
+      (const guint8 *) buf, len, NULL, NULL);
+}
 
 NICEAPI_EXPORT GSList *
 nice_agent_get_local_candidates (
diff --git a/agent/agent.h b/agent/agent.h
index 64df422..9d7bb25 100644
--- a/agent/agent.h
+++ b/agent/agent.h
@@ -579,6 +579,16 @@ nice_agent_send (
   guint len,
   const gchar *buf);
 
+gssize
+nice_agent_send_full (
+    NiceAgent *agent,
+    guint stream_id,
+    guint component_id,
+    const guint8 *buf,
+    gsize buf_len,
+    GCancellable *cancellable,
+    GError **error);
+
 /**
  * nice_agent_get_local_candidates:
  * @agent: The #NiceAgent Object
diff --git a/docs/reference/libnice/libnice-sections.txt b/docs/reference/libnice/libnice-sections.txt
index 7a1c53a..bad2dfb 100644
--- a/docs/reference/libnice/libnice-sections.txt
+++ b/docs/reference/libnice/libnice-sections.txt
@@ -23,6 +23,7 @@ nice_agent_get_remote_candidates
 nice_agent_get_local_candidates
 nice_agent_get_selected_pair
 nice_agent_send
+nice_agent_send_full
 nice_agent_recv
 nice_agent_attach_recv
 nice_agent_set_selected_pair
diff --git a/nice/libnice.sym b/nice/libnice.sym
index 0f7208d..014142c 100644
--- a/nice/libnice.sym
+++ b/nice/libnice.sym
@@ -38,6 +38,7 @@ nice_agent_parse_remote_stream_sdp
 nice_agent_remove_stream
 nice_agent_restart
 nice_agent_send
+nice_agent_send_full
 nice_agent_set_port_range
 nice_agent_set_relay_info
 nice_agent_set_remote_candidates

-- 
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