Commit 547311bf authored by Dan Winship's avatar Dan Winship

Always do async vs sync correctly in GSocketConnection streams

Previously if a GSocketConnection had a blocking GSocket, it would
sometimes block during asynchonous I/O, and if it had a non-blocking
socket, it would sometimes return G_IO_ERROR_WOULD_BLOCK from
synchronous I/O. This fixes the connection to not depend on the socket
state.

https://bugzilla.gnome.org/show_bug.cgi?id=616458
parent 17fea2f7
...@@ -1716,9 +1716,11 @@ g_socket_check_connect_result ...@@ -1716,9 +1716,11 @@ g_socket_check_connect_result
g_socket_receive g_socket_receive
g_socket_receive_from g_socket_receive_from
g_socket_receive_message g_socket_receive_message
g_socket_receive_with_blocking
g_socket_send g_socket_send
g_socket_send_to g_socket_send_to
g_socket_send_message g_socket_send_message
g_socket_send_with_blocking
g_socket_close g_socket_close
g_socket_is_closed g_socket_is_closed
g_socket_shutdown g_socket_shutdown
......
...@@ -1271,9 +1271,11 @@ g_socket_new_from_fd ...@@ -1271,9 +1271,11 @@ g_socket_new_from_fd
g_socket_receive g_socket_receive
g_socket_receive_from g_socket_receive_from
g_socket_receive_message g_socket_receive_message
g_socket_receive_with_blocking
g_socket_send g_socket_send
g_socket_send_message g_socket_send_message
g_socket_send_to g_socket_send_to
g_socket_send_with_blocking
g_socket_set_blocking g_socket_set_blocking
g_socket_set_timeout g_socket_set_timeout
g_socket_set_keepalive g_socket_set_keepalive
......
...@@ -1721,6 +1721,37 @@ g_socket_receive (GSocket *socket, ...@@ -1721,6 +1721,37 @@ g_socket_receive (GSocket *socket,
gsize size, gsize size,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{
return g_socket_receive_with_blocking (socket, buffer, size,
socket->priv->blocking,
cancellable, error);
}
/**
* g_socket_receive_with_blocking:
* @socket: a #GSocket
* @buffer: a buffer to read data into (which should be at least @size
* bytes long).
* @size: the number of bytes you want to read from the socket
* @blocking: whether to do blocking or non-blocking I/O
* @cancellable: a %GCancellable or %NULL
* @error: #GError for error reporting, or %NULL to ignore.
*
* This behaves exactly the same as g_socket_receive(), except that
* the choice of blocking or non-blocking behavior is determined by
* the @blocking argument rather than by @socket's properties.
*
* Returns: Number of bytes read, or -1 on error
*
* Since: 2.26
*/
gssize
g_socket_receive_with_blocking (GSocket *socket,
gchar *buffer,
gsize size,
gboolean blocking,
GCancellable *cancellable,
GError **error)
{ {
gssize ret; gssize ret;
...@@ -1734,7 +1765,7 @@ g_socket_receive (GSocket *socket, ...@@ -1734,7 +1765,7 @@ g_socket_receive (GSocket *socket,
while (1) while (1)
{ {
if (socket->priv->blocking && if (blocking &&
!g_socket_condition_wait (socket, !g_socket_condition_wait (socket,
G_IO_IN, cancellable, error)) G_IO_IN, cancellable, error))
return -1; return -1;
...@@ -1746,7 +1777,7 @@ g_socket_receive (GSocket *socket, ...@@ -1746,7 +1777,7 @@ g_socket_receive (GSocket *socket,
if (errsv == EINTR) if (errsv == EINTR)
continue; continue;
if (socket->priv->blocking) if (blocking)
{ {
#ifdef WSAEWOULDBLOCK #ifdef WSAEWOULDBLOCK
if (errsv == WSAEWOULDBLOCK) if (errsv == WSAEWOULDBLOCK)
...@@ -1861,6 +1892,37 @@ g_socket_send (GSocket *socket, ...@@ -1861,6 +1892,37 @@ g_socket_send (GSocket *socket,
gsize size, gsize size,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{
return g_socket_send_with_blocking (socket, buffer, size,
socket->priv->blocking,
cancellable, error);
}
/**
* g_socket_send_with_blocking:
* @socket: a #GSocket
* @buffer: the buffer containing the data to send.
* @size: the number of bytes to send
* @blocking: whether to do blocking or non-blocking I/O
* @cancellable: a %GCancellable or %NULL
* @error: #GError for error reporting, or %NULL to ignore.
*
* This behaves exactly the same as g_socket_send(), except that
* the choice of blocking or non-blocking behavior is determined by
* the @blocking argument rather than by @socket's properties.
*
* Returns: Number of bytes written (which may be less than @size), or -1
* on error
*
* Since: 2.26
*/
gssize
g_socket_send_with_blocking (GSocket *socket,
const gchar *buffer,
gsize size,
gboolean blocking,
GCancellable *cancellable,
GError **error)
{ {
gssize ret; gssize ret;
...@@ -1874,7 +1936,7 @@ g_socket_send (GSocket *socket, ...@@ -1874,7 +1936,7 @@ g_socket_send (GSocket *socket,
while (1) while (1)
{ {
if (socket->priv->blocking && if (blocking &&
!g_socket_condition_wait (socket, !g_socket_condition_wait (socket,
G_IO_OUT, cancellable, error)) G_IO_OUT, cancellable, error))
return -1; return -1;
...@@ -1891,7 +1953,7 @@ g_socket_send (GSocket *socket, ...@@ -1891,7 +1953,7 @@ g_socket_send (GSocket *socket,
win32_unset_event_mask (socket, FD_WRITE); win32_unset_event_mask (socket, FD_WRITE);
#endif #endif
if (socket->priv->blocking) if (blocking)
{ {
#ifdef WSAEWOULDBLOCK #ifdef WSAEWOULDBLOCK
if (errsv == WSAEWOULDBLOCK) if (errsv == WSAEWOULDBLOCK)
......
...@@ -176,6 +176,19 @@ gboolean g_socket_speaks_ipv4 (GSocket ...@@ -176,6 +176,19 @@ gboolean g_socket_speaks_ipv4 (GSocket
GCredentials *g_socket_get_credentials (GSocket *socket, GCredentials *g_socket_get_credentials (GSocket *socket,
GError **error); GError **error);
gssize g_socket_receive_with_blocking (GSocket *socket,
gchar *buffer,
gsize size,
gboolean blocking,
GCancellable *cancellable,
GError **error);
gssize g_socket_send_with_blocking (GSocket *socket,
const gchar *buffer,
gsize size,
gboolean blocking,
GCancellable *cancellable,
GError **error);
G_END_DECLS G_END_DECLS
#endif /* __G_SOCKET_H__ */ #endif /* __G_SOCKET_H__ */
...@@ -111,8 +111,9 @@ g_socket_input_stream_read (GInputStream *stream, ...@@ -111,8 +111,9 @@ g_socket_input_stream_read (GInputStream *stream,
{ {
GSocketInputStream *input_stream = G_SOCKET_INPUT_STREAM (stream); GSocketInputStream *input_stream = G_SOCKET_INPUT_STREAM (stream);
return g_socket_receive (input_stream->priv->socket, buffer, count, return g_socket_receive_with_blocking (input_stream->priv->socket,
cancellable, error); buffer, count, TRUE,
cancellable, error);
} }
static gboolean static gboolean
...@@ -124,11 +125,12 @@ g_socket_input_stream_read_ready (GSocket *socket, ...@@ -124,11 +125,12 @@ g_socket_input_stream_read_ready (GSocket *socket,
GError *error = NULL; GError *error = NULL;
gssize result; gssize result;
result = g_socket_receive (stream->priv->socket, result = g_socket_receive_with_blocking (stream->priv->socket,
stream->priv->buffer, stream->priv->buffer,
stream->priv->count, stream->priv->count,
stream->priv->cancellable, FALSE,
&error); stream->priv->cancellable,
&error);
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
return TRUE; return TRUE;
......
...@@ -113,8 +113,9 @@ g_socket_output_stream_write (GOutputStream *stream, ...@@ -113,8 +113,9 @@ g_socket_output_stream_write (GOutputStream *stream,
{ {
GSocketOutputStream *onput_stream = G_SOCKET_OUTPUT_STREAM (stream); GSocketOutputStream *onput_stream = G_SOCKET_OUTPUT_STREAM (stream);
return g_socket_send (onput_stream->priv->socket, buffer, count, return g_socket_send_with_blocking (onput_stream->priv->socket,
cancellable, error); buffer, count, TRUE,
cancellable, error);
} }
static gboolean static gboolean
...@@ -126,11 +127,12 @@ g_socket_output_stream_write_ready (GSocket *socket, ...@@ -126,11 +127,12 @@ g_socket_output_stream_write_ready (GSocket *socket,
GError *error = NULL; GError *error = NULL;
gssize result; gssize result;
result = g_socket_send (stream->priv->socket, result = g_socket_send_with_blocking (stream->priv->socket,
stream->priv->buffer, stream->priv->buffer,
stream->priv->count, stream->priv->count,
stream->priv->cancellable, FALSE,
&error); stream->priv->cancellable,
&error);
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
return TRUE; return TRUE;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment