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; + GPollableReturn pollable_result; + gsize bytes_written = 0; - 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); + 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,