[glib] gsocket: Fix error behaviour of g_socket_send_messages()



commit 1086507e75580083aef46ad3072e9ff7869c2bc4
Author: Philip Withnall <philip withnall collabora co uk>
Date:   Mon Aug 17 18:10:43 2015 +0100

    gsocket: Fix error behaviour of g_socket_send_messages()
    
    If an error in the underlying sendmmsg() syscall occurs after
    successfully sending one or more messages, g_socket_send_messages()
    should return the number of messages successfully sent, rather than an
    error. This mirrors the documented sendmmsg() behaviour.
    
    This is a slight behaviour change for g_socket_send_messages(), but as
    it relaxes the error reporting (reporting errors in fewer situations
    than before), it should not cause problems.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=751924

 gio/gsocket.c      |   32 +++++++++++---------------------
 gio/tests/socket.c |   21 +++++++++++++++++++--
 2 files changed, 30 insertions(+), 23 deletions(-)
---
diff --git a/gio/gsocket.c b/gio/gsocket.c
index a0759d4..310238e 100644
--- a/gio/gsocket.c
+++ b/gio/gsocket.c
@@ -4295,7 +4295,9 @@ g_socket_send_message (GSocket                *socket,
  * notified of a %G_IO_OUT condition. (On Windows in particular, this is
  * very common due to the way the underlying APIs work.)
  *
- * On error -1 is returned and @error is set accordingly.
+ * On error -1 is returned and @error is set accordingly. An error will only
+ * be returned if zero messages could be sent; otherwise the number of messages
+ * successfully sent before the error will be returned.
  *
  * Returns: number of messages sent, or -1 on error. Note that the number of
  *     messages sent may be smaller than @num_messages if the socket is
@@ -4351,7 +4353,7 @@ g_socket_send_messages_with_timeout (GSocket        *socket,
 #if !defined (G_OS_WIN32) && defined (HAVE_SENDMMSG)
   {
     struct mmsghdr *msgvec;
-    gint i, num_sent, result, max_sent;
+    gint i, num_sent;
 
 #ifdef UIO_MAXIOV
 #define MAX_NUM_MESSAGES UIO_MAXIOV
@@ -4383,9 +4385,7 @@ g_socket_send_messages_with_timeout (GSocket        *socket,
           }
       }
 
-    num_sent = result = 0;
-    max_sent = num_messages;
-    while (num_sent < num_messages)
+    for (num_sent = 0; num_sent < num_messages;)
       {
         gint ret;
 
@@ -4418,32 +4418,22 @@ g_socket_send_messages_with_timeout (GSocket        *socket,
                 continue;
               }
 
-            if (num_sent > 0 &&
-                (errsv == EWOULDBLOCK ||
-                 errsv == EAGAIN))
-              {
-                max_sent = num_sent;
-                break;
-              }
+            /* If any messages were successfully sent, do not error. */
+            if (num_sent > 0)
+              break;
 
             socket_set_error_lazy (error, errsv, _("Error sending message: %s"));
 
-            /* we have to iterate over all messages below now, because we don't
-             * know where between num_sent and num_messages the error occured */
-            max_sent = num_messages;
-
-            result = -1;
-            break;
+            return -1;
           }
 
         num_sent += ret;
-        result = num_sent;
       }
 
-    for (i = 0; i < max_sent; ++i)
+    for (i = 0; i < num_sent; ++i)
       messages[i].bytes_sent = msgvec[i].msg_len;
 
-    return result;
+    return num_sent;
   }
 #else
   {
diff --git a/gio/tests/socket.c b/gio/tests/socket.c
index 15fb61a..a5b2573 100644
--- a/gio/tests/socket.c
+++ b/gio/tests/socket.c
@@ -703,14 +703,31 @@ test_ip_sync_dgram (GSocketFamily family)
     m[1].bytes_sent = 0;
     m[2].bytes_sent = 0;
 
-    /* now try to generate an error by omitting the destination address on [1] */
+    /* now try to generate an early return by omitting the destination address on [1] */
     m[1].address = NULL;
     len = g_socket_send_messages (client, m, G_N_ELEMENTS (m), 0, NULL, &error);
+    g_assert_no_error (error);
+    g_assert_cmpint (len, ==, 1);
+
+    g_assert_cmpint (m[0].bytes_sent, ==, 3);
+    g_assert_cmpint (m[1].bytes_sent, ==, 0);
+    g_assert_cmpint (m[2].bytes_sent, ==, 0);
+
+    /* reset since we're re-using the message structs */
+    m[0].bytes_sent = 0;
+    m[1].bytes_sent = 0;
+    m[2].bytes_sent = 0;
+
+    /* now try to generate an error by omitting all destination addresses */
+    m[0].address = NULL;
+    m[1].address = NULL;
+    m[2].address = NULL;
+    len = g_socket_send_messages (client, m, G_N_ELEMENTS (m), 0, NULL, &error);
     g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
     g_clear_error (&error);
     g_assert_cmpint (len, ==, -1);
 
-    g_assert_cmpint (m[0].bytes_sent, ==, 3);
+    g_assert_cmpint (m[0].bytes_sent, ==, 0);
     g_assert_cmpint (m[1].bytes_sent, ==, 0);
     g_assert_cmpint (m[2].bytes_sent, ==, 0);
 


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