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
This commit is contained in:
Dan Winship 2010-06-24 13:09:14 -04:00
parent 17fea2f749
commit 547311bfd8
6 changed files with 101 additions and 18 deletions

View File

@ -1716,9 +1716,11 @@ g_socket_check_connect_result
g_socket_receive
g_socket_receive_from
g_socket_receive_message
g_socket_receive_with_blocking
g_socket_send
g_socket_send_to
g_socket_send_message
g_socket_send_with_blocking
g_socket_close
g_socket_is_closed
g_socket_shutdown

View File

@ -1271,9 +1271,11 @@ g_socket_new_from_fd
g_socket_receive
g_socket_receive_from
g_socket_receive_message
g_socket_receive_with_blocking
g_socket_send
g_socket_send_message
g_socket_send_to
g_socket_send_with_blocking
g_socket_set_blocking
g_socket_set_timeout
g_socket_set_keepalive

View File

@ -1721,6 +1721,37 @@ g_socket_receive (GSocket *socket,
gsize size,
GCancellable *cancellable,
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;
@ -1734,7 +1765,7 @@ g_socket_receive (GSocket *socket,
while (1)
{
if (socket->priv->blocking &&
if (blocking &&
!g_socket_condition_wait (socket,
G_IO_IN, cancellable, error))
return -1;
@ -1746,7 +1777,7 @@ g_socket_receive (GSocket *socket,
if (errsv == EINTR)
continue;
if (socket->priv->blocking)
if (blocking)
{
#ifdef WSAEWOULDBLOCK
if (errsv == WSAEWOULDBLOCK)
@ -1861,6 +1892,37 @@ g_socket_send (GSocket *socket,
gsize size,
GCancellable *cancellable,
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;
@ -1874,7 +1936,7 @@ g_socket_send (GSocket *socket,
while (1)
{
if (socket->priv->blocking &&
if (blocking &&
!g_socket_condition_wait (socket,
G_IO_OUT, cancellable, error))
return -1;
@ -1891,7 +1953,7 @@ g_socket_send (GSocket *socket,
win32_unset_event_mask (socket, FD_WRITE);
#endif
if (socket->priv->blocking)
if (blocking)
{
#ifdef WSAEWOULDBLOCK
if (errsv == WSAEWOULDBLOCK)

View File

@ -176,6 +176,19 @@ gboolean g_socket_speaks_ipv4 (GSocket
GCredentials *g_socket_get_credentials (GSocket *socket,
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
#endif /* __G_SOCKET_H__ */

View File

@ -111,8 +111,9 @@ g_socket_input_stream_read (GInputStream *stream,
{
GSocketInputStream *input_stream = G_SOCKET_INPUT_STREAM (stream);
return g_socket_receive (input_stream->priv->socket, buffer, count,
cancellable, error);
return g_socket_receive_with_blocking (input_stream->priv->socket,
buffer, count, TRUE,
cancellable, error);
}
static gboolean
@ -124,11 +125,12 @@ g_socket_input_stream_read_ready (GSocket *socket,
GError *error = NULL;
gssize result;
result = g_socket_receive (stream->priv->socket,
stream->priv->buffer,
stream->priv->count,
stream->priv->cancellable,
&error);
result = g_socket_receive_with_blocking (stream->priv->socket,
stream->priv->buffer,
stream->priv->count,
FALSE,
stream->priv->cancellable,
&error);
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
return TRUE;

View File

@ -113,8 +113,9 @@ g_socket_output_stream_write (GOutputStream *stream,
{
GSocketOutputStream *onput_stream = G_SOCKET_OUTPUT_STREAM (stream);
return g_socket_send (onput_stream->priv->socket, buffer, count,
cancellable, error);
return g_socket_send_with_blocking (onput_stream->priv->socket,
buffer, count, TRUE,
cancellable, error);
}
static gboolean
@ -126,11 +127,12 @@ g_socket_output_stream_write_ready (GSocket *socket,
GError *error = NULL;
gssize result;
result = g_socket_send (stream->priv->socket,
stream->priv->buffer,
stream->priv->count,
stream->priv->cancellable,
&error);
result = g_socket_send_with_blocking (stream->priv->socket,
stream->priv->buffer,
stream->priv->count,
FALSE,
stream->priv->cancellable,
&error);
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
return TRUE;