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
This commit is contained in:
Philip Withnall 2015-08-17 18:10:43 +01:00
parent f62cbfc022
commit 1086507e75
2 changed files with 30 additions and 23 deletions

View File

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

View File

@ -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);