Add g_socket_send_message_with_timeout()

This commit is contained in:
Sebastian Dröge 2018-09-14 10:28:12 +03:00
parent 63ea8d18f3
commit f0a11b2727
2 changed files with 112 additions and 52 deletions

View File

@ -194,17 +194,6 @@ g_socket_receive_messages_with_timeout (GSocket *socket,
gint64 timeout, gint64 timeout,
GCancellable *cancellable, GCancellable *cancellable,
GError **error); 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 static gint
g_socket_send_messages_with_timeout (GSocket *socket, g_socket_send_messages_with_timeout (GSocket *socket,
GOutputMessage *messages, GOutputMessage *messages,
@ -4606,22 +4595,61 @@ g_socket_send_message (GSocket *socket,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
return g_socket_send_message_with_timeout (socket, address, GPollableReturn res;
vectors, num_vectors, gsize bytes_written = 0;
messages, num_messages, flags,
socket->priv->blocking ? -1 : 0, res = g_socket_send_message_with_timeout (socket, address,
cancellable, error); 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, g_socket_send_message_with_timeout (GSocket *socket,
GSocketAddress *address, GSocketAddress *address,
GOutputVector *vectors, const GOutputVector *vectors,
gint num_vectors, gint num_vectors,
GSocketControlMessage **messages, GSocketControlMessage **messages,
gint num_messages, gint num_messages,
gint flags, gint flags,
gint64 timeout, gint64 timeout,
gsize *bytes_written,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
@ -4629,23 +4657,26 @@ g_socket_send_message_with_timeout (GSocket *socket,
char zero; char zero;
gint64 start_time; gint64 start_time;
g_return_val_if_fail (G_IS_SOCKET (socket), -1); if (bytes_written)
g_return_val_if_fail (address == NULL || G_IS_SOCKET_ADDRESS (address), -1); *bytes_written = 0;
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 (G_IS_SOCKET (socket), G_POLLABLE_RETURN_FAILED);
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), -1); g_return_val_if_fail (address == NULL || G_IS_SOCKET_ADDRESS (address), G_POLLABLE_RETURN_FAILED);
g_return_val_if_fail (error == NULL || *error == NULL, -1); 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 (); start_time = g_get_monotonic_time ();
if (!check_socket (socket, error)) if (!check_socket (socket, error))
return -1; return G_POLLABLE_RETURN_FAILED;
if (!check_timeout (socket, error)) if (!check_timeout (socket, error))
return -1; return G_POLLABLE_RETURN_FAILED;
if (g_cancellable_set_error_if_cancelled (cancellable, error)) if (g_cancellable_set_error_if_cancelled (cancellable, error))
return -1; return G_POLLABLE_RETURN_FAILED;
if (num_vectors == -1) if (num_vectors == -1)
{ {
@ -4681,7 +4712,7 @@ g_socket_send_message_with_timeout (GSocket *socket,
GError *child_error = NULL; GError *child_error = NULL;
output_message.address = address; output_message.address = address;
output_message.vectors = vectors; output_message.vectors = (GOutputVector *) vectors;
output_message.num_vectors = num_vectors; output_message.num_vectors = num_vectors;
output_message.bytes_sent = 0; output_message.bytes_sent = 0;
output_message.control_messages = messages; output_message.control_messages = messages;
@ -4692,7 +4723,7 @@ g_socket_send_message_with_timeout (GSocket *socket,
if (child_error != NULL) if (child_error != NULL)
{ {
g_propagate_error (error, child_error); g_propagate_error (error, child_error);
return -1; return G_POLLABLE_RETURN_FAILED;
} }
while (1) while (1)
@ -4705,24 +4736,30 @@ g_socket_send_message_with_timeout (GSocket *socket,
if (errsv == EINTR) if (errsv == EINTR)
continue; continue;
if (timeout != 0 && if (errsv == EWOULDBLOCK || errsv == EAGAIN)
(errsv == EWOULDBLOCK ||
errsv == EAGAIN))
{ {
if (!block_on_timeout (socket, G_IO_OUT, timeout, start_time, if (timeout != 0)
cancellable, error)) {
return -1; 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")); socket_set_error_lazy (error, errsv, _("Error sending message: %s"));
return -1; return G_POLLABLE_RETURN_FAILED;
} }
break; break;
} }
return result; if (bytes_written)
*bytes_written = result;
return G_POLLABLE_RETURN_OK;
} }
#else #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, g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
_("GSocketControlMessage not supported on Windows")); _("GSocketControlMessage not supported on Windows"));
return -1; return G_POLLABLE_RETURN_FAILED;
} }
/* iov */ /* iov */
@ -4758,7 +4795,7 @@ g_socket_send_message_with_timeout (GSocket *socket,
{ {
addrlen = g_socket_address_get_native_size (address); addrlen = g_socket_address_get_native_size (address);
if (!g_socket_address_to_native (address, &addr, sizeof addr, error)) if (!g_socket_address_to_native (address, &addr, sizeof addr, error))
return -1; return G_POLLABLE_RETURN_FAILED;
} }
while (1) while (1)
@ -4790,19 +4827,23 @@ g_socket_send_message_with_timeout (GSocket *socket,
{ {
if (!block_on_timeout (socket, G_IO_OUT, timeout, if (!block_on_timeout (socket, G_IO_OUT, timeout,
start_time, cancellable, error)) start_time, cancellable, error))
return -1; return G_POLLABLE_RETURN_FAILED;
continue; continue;
} }
return G_POLLABLE_RETURN_WOULD_BLOCK;
} }
socket_set_error_lazy (error, errsv, _("Error sending message: %s")); socket_set_error_lazy (error, errsv, _("Error sending message: %s"));
return -1; return G_POLLABLE_RETURN_FAILED;
} }
break; break;
} }
return bytes_sent; if (bytes_written)
*bytes_written = bytes_sent;
return G_POLLABLE_RETURN_OK;
} }
#endif #endif
} }
@ -4999,14 +5040,22 @@ g_socket_send_messages_with_timeout (GSocket *socket,
{ {
GOutputMessage *msg = &messages[i]; GOutputMessage *msg = &messages[i];
GError *msg_error = NULL; GError *msg_error = NULL;
GPollableReturn pollable_result;
gsize bytes_written = 0;
result = g_socket_send_message_with_timeout (socket, msg->address, pollable_result = g_socket_send_message_with_timeout (socket, msg->address,
msg->vectors, msg->vectors,
msg->num_vectors, msg->num_vectors,
msg->control_messages, msg->control_messages,
msg->num_control_messages, msg->num_control_messages,
flags, wait_timeout, flags, wait_timeout,
cancellable, &msg_error); &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 */ /* check if we've timed out or how much time to wait at most */
if (timeout > 0) if (timeout > 0)

View File

@ -298,7 +298,18 @@ gssize g_socket_send_with_blocking (GSocket
gboolean blocking, gboolean blocking,
GCancellable *cancellable, GCancellable *cancellable,
GError **error); 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 GLIB_AVAILABLE_IN_2_36
gboolean g_socket_get_option (GSocket *socket, gboolean g_socket_get_option (GSocket *socket,
gint level, gint level,