[glib: 7/15] Add g_socket_send_message_with_timeout()



commit f0a11b27274747499e4f31deca23fca51e830caf
Author: Sebastian Dröge <sebastian centricular com>
Date:   Fri Sep 14 10:28:12 2018 +0300

    Add g_socket_send_message_with_timeout()

 gio/gsocket.c | 153 ++++++++++++++++++++++++++++++++++++++--------------------
 gio/gsocket.h |  13 ++++-
 2 files changed, 113 insertions(+), 53 deletions(-)
---
diff --git a/gio/gsocket.c b/gio/gsocket.c
index 8ceaa16d3..ecb233230 100644
--- a/gio/gsocket.c
+++ b/gio/gsocket.c
@@ -194,17 +194,6 @@ g_socket_receive_messages_with_timeout (GSocket        *socket,
                                         gint64          timeout,
                                         GCancellable   *cancellable,
                                         GError        **error);
-static gssize
-g_socket_send_message_with_timeout     (GSocket                 *socket,
-                                        GSocketAddress          *address,
-                                        GOutputVector           *vectors,
-                                        gint                     num_vectors,
-                                        GSocketControlMessage  **messages,
-                                        gint                     num_messages,
-                                        gint                     flags,
-                                        gint64                   timeout,
-                                        GCancellable            *cancellable,
-                                        GError                 **error);
 static gint
 g_socket_send_messages_with_timeout    (GSocket        *socket,
                                         GOutputMessage *messages,
@@ -4606,22 +4595,61 @@ g_socket_send_message (GSocket                *socket,
                       GCancellable           *cancellable,
                       GError                **error)
 {
-  return g_socket_send_message_with_timeout (socket, address,
-                                             vectors, num_vectors,
-                                             messages, num_messages, flags,
-                                             socket->priv->blocking ? -1 : 0,
-                                             cancellable, error);
+  GPollableReturn res;
+  gsize bytes_written = 0;
+
+  res = g_socket_send_message_with_timeout (socket, address,
+                                            vectors, num_vectors,
+                                            messages, num_messages, flags,
+                                            socket->priv->blocking ? -1 : 0,
+                                            &bytes_written,
+                                            cancellable, error);
+
+  if (res == G_POLLABLE_RETURN_WOULD_BLOCK)
+    socket_set_error_lazy (error, EWOULDBLOCK, _("Error sending message: %s"));
+
+  return res == G_POLLABLE_RETURN_OK ? bytes_written : -1;
 }
 
-static gssize
+/**
+ * g_socket_send_message_with_timeout:
+ * @socket: a #GSocket
+ * @address: (nullable): a #GSocketAddress, or %NULL
+ * @vectors: (array length=num_vectors): an array of #GOutputVector structs
+ * @num_vectors: the number of elements in @vectors, or -1
+ * @messages: (array length=num_messages) (nullable): a pointer to an
+ *   array of #GSocketControlMessages, or %NULL.
+ * @num_messages: number of elements in @messages, or -1.
+ * @flags: an int containing #GSocketMsgFlags flags
+ * @timeout: the maximum time (in microseconds) to wait, or -1
+ * @bytes_written: (out) (optional): location to store the number of bytes that were written to the socket
+ * @cancellable: (nullable): a %GCancellable or %NULL
+ * @error: #GError for error reporting, or %NULL to ignore.
+ *
+ * This behaves exactly the same as g_socket_send_message(), except that
+ * the choice of timeout behavior is determined by the @timeout argument
+ * rather than by @socket's properties.
+ *
+ * On error %G_POLLABLE_RETURN_FAILED is returned and @error is set accordingly, or
+ * if the socket is currently not writable %G_POLLABLE_RETURN_WOULD_BLOCK is
+ * returned. @bytes_written will contain 0 in both cases.
+ *
+ * Returns: %G_POLLABLE_RETURN_OK if all data was successfully written,
+ * %G_POLLABLE_RETURN_WOULD_BLOCK if the socket is currently not writable, or
+ * %G_POLLABLE_RETURN_FAILED if an error happened and @error is set.
+ *
+ * Since: 2.60
+ */
+GPollableReturn
 g_socket_send_message_with_timeout (GSocket                *socket,
                                     GSocketAddress         *address,
-                                    GOutputVector          *vectors,
+                                    const GOutputVector    *vectors,
                                     gint                    num_vectors,
                                     GSocketControlMessage **messages,
                                     gint                    num_messages,
                                     gint                    flags,
                                     gint64                  timeout,
+                                    gsize                  *bytes_written,
                                     GCancellable           *cancellable,
                                     GError                **error)
 {
@@ -4629,23 +4657,26 @@ g_socket_send_message_with_timeout (GSocket                *socket,
   char zero;
   gint64 start_time;
 
-  g_return_val_if_fail (G_IS_SOCKET (socket), -1);
-  g_return_val_if_fail (address == NULL || G_IS_SOCKET_ADDRESS (address), -1);
-  g_return_val_if_fail (num_vectors == 0 || vectors != NULL, -1);
-  g_return_val_if_fail (num_messages == 0 || messages != NULL, -1);
-  g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), -1);
-  g_return_val_if_fail (error == NULL || *error == NULL, -1);
+  if (bytes_written)
+    *bytes_written = 0;
+
+  g_return_val_if_fail (G_IS_SOCKET (socket), G_POLLABLE_RETURN_FAILED);
+  g_return_val_if_fail (address == NULL || G_IS_SOCKET_ADDRESS (address), G_POLLABLE_RETURN_FAILED);
+  g_return_val_if_fail (num_vectors == 0 || vectors != NULL, G_POLLABLE_RETURN_FAILED);
+  g_return_val_if_fail (num_messages == 0 || messages != NULL, G_POLLABLE_RETURN_FAILED);
+  g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), G_POLLABLE_RETURN_FAILED);
+  g_return_val_if_fail (error == NULL || *error == NULL, G_POLLABLE_RETURN_FAILED);
 
   start_time = g_get_monotonic_time ();
 
   if (!check_socket (socket, error))
-    return -1;
+    return G_POLLABLE_RETURN_FAILED;
 
   if (!check_timeout (socket, error))
-    return -1;
+    return G_POLLABLE_RETURN_FAILED;
 
   if (g_cancellable_set_error_if_cancelled (cancellable, error))
-    return -1;
+    return G_POLLABLE_RETURN_FAILED;
 
   if (num_vectors == -1)
     {
@@ -4681,7 +4712,7 @@ g_socket_send_message_with_timeout (GSocket                *socket,
     GError *child_error = NULL;
 
     output_message.address = address;
-    output_message.vectors = vectors;
+    output_message.vectors = (GOutputVector *) vectors;
     output_message.num_vectors = num_vectors;
     output_message.bytes_sent = 0;
     output_message.control_messages = messages;
@@ -4692,7 +4723,7 @@ g_socket_send_message_with_timeout (GSocket                *socket,
     if (child_error != NULL)
       {
         g_propagate_error (error, child_error);
-        return -1;
+        return G_POLLABLE_RETURN_FAILED;
       }
 
     while (1)
@@ -4705,24 +4736,30 @@ g_socket_send_message_with_timeout (GSocket                *socket,
            if (errsv == EINTR)
              continue;
 
-           if (timeout != 0 &&
-               (errsv == EWOULDBLOCK ||
-                errsv == EAGAIN))
+           if (errsv == EWOULDBLOCK || errsv == EAGAIN)
               {
-                if (!block_on_timeout (socket, G_IO_OUT, timeout, start_time,
-                                       cancellable, error))
-                  return -1;
+                if (timeout != 0)
+                  {
+                    if (!block_on_timeout (socket, G_IO_OUT, timeout, start_time,
+                                           cancellable, error))
+                      return G_POLLABLE_RETURN_FAILED;
 
-                continue;
+                    continue;
+                  }
+
+                return G_POLLABLE_RETURN_WOULD_BLOCK;
               }
 
-           socket_set_error_lazy (error, errsv, _("Error sending message: %s"));
-           return -1;
+            socket_set_error_lazy (error, errsv, _("Error sending message: %s"));
+            return G_POLLABLE_RETURN_FAILED;
          }
        break;
       }
 
-    return result;
+    if (bytes_written)
+      *bytes_written = result;
+
+    return G_POLLABLE_RETURN_OK;
   }
 #else
   {
@@ -4741,7 +4778,7 @@ g_socket_send_message_with_timeout (GSocket                *socket,
       {
         g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
                              _("GSocketControlMessage not supported on Windows"));
-       return -1;
+       return G_POLLABLE_RETURN_FAILED;
       }
 
     /* iov */
@@ -4758,7 +4795,7 @@ g_socket_send_message_with_timeout (GSocket                *socket,
       {
        addrlen = g_socket_address_get_native_size (address);
        if (!g_socket_address_to_native (address, &addr, sizeof addr, error))
-         return -1;
+         return G_POLLABLE_RETURN_FAILED;
       }
 
     while (1)
@@ -4790,19 +4827,23 @@ g_socket_send_message_with_timeout (GSocket                *socket,
                   {
                     if (!block_on_timeout (socket, G_IO_OUT, timeout,
                                            start_time, cancellable, error))
-                      return -1;
+                      return G_POLLABLE_RETURN_FAILED;
 
                     continue;
                   }
+
+                return G_POLLABLE_RETURN_WOULD_BLOCK;
               }
 
            socket_set_error_lazy (error, errsv, _("Error sending message: %s"));
-           return -1;
+           return G_POLLABLE_RETURN_FAILED;
          }
        break;
       }
 
-    return bytes_sent;
+    if (bytes_written)
+      *bytes_written = bytes_sent;
+    return G_POLLABLE_RETURN_OK;
   }
 #endif
 }
@@ -4999,14 +5040,22 @@ g_socket_send_messages_with_timeout (GSocket        *socket,
       {
         GOutputMessage *msg = &messages[i];
         GError *msg_error = NULL;
-
-        result = g_socket_send_message_with_timeout (socket, msg->address,
-                                                     msg->vectors,
-                                                     msg->num_vectors,
-                                                     msg->control_messages,
-                                                     msg->num_control_messages,
-                                                     flags, wait_timeout,
-                                                     cancellable, &msg_error);
+        GPollableReturn pollable_result;
+        gsize bytes_written = 0;
+
+        pollable_result = g_socket_send_message_with_timeout (socket, msg->address,
+                                                              msg->vectors,
+                                                              msg->num_vectors,
+                                                              msg->control_messages,
+                                                              msg->num_control_messages,
+                                                              flags, wait_timeout,
+                                                              &bytes_written,
+                                                              cancellable, &msg_error);
+
+        if (pollable_result == G_POLLABLE_RETURN_WOULD_BLOCK)
+          socket_set_error_lazy (&msg_error, EWOULDBLOCK, _("Error sending message: %s"));
+
+        result = pollable_result == G_POLLABLE_RETURN_OK ? bytes_written : -1;
 
         /* check if we've timed out or how much time to wait at most */
         if (timeout > 0)
diff --git a/gio/gsocket.h b/gio/gsocket.h
index a65cbc22f..30a32a84d 100644
--- a/gio/gsocket.h
+++ b/gio/gsocket.h
@@ -298,7 +298,18 @@ gssize                 g_socket_send_with_blocking      (GSocket
                                                         gboolean                 blocking,
                                                         GCancellable            *cancellable,
                                                         GError                 **error);
-
+GLIB_AVAILABLE_IN_2_60
+GPollableReturn        g_socket_send_message_with_timeout (GSocket                *socket,
+                                                          GSocketAddress         *address,
+                                                          const GOutputVector    *vectors,
+                                                          gint                    num_vectors,
+                                                          GSocketControlMessage **messages,
+                                                          gint                    num_messages,
+                                                          gint                    flags,
+                                                          gint64                  timeout,
+                                                          gsize                  *bytes_written,
+                                                          GCancellable           *cancellable,
+                                                          GError                **error);
 GLIB_AVAILABLE_IN_2_36
 gboolean               g_socket_get_option              (GSocket                 *socket,
                                                         gint                     level,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]