Always do async vs sync correctly in GSocketConnection streams
authorDan Winship <danw@gnome.org>
Thu, 24 Jun 2010 17:09:14 +0000 (13:09 -0400)
committerDan Winship <danw@gnome.org>
Sun, 15 Aug 2010 19:34:29 +0000 (15:34 -0400)
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

docs/reference/gio/gio-sections.txt
gio/gio.symbols
gio/gsocket.c
gio/gsocket.h
gio/gsocketinputstream.c
gio/gsocketoutputstream.c

index 7ed6cfd..cd23dea 100644 (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
index 68ea6d4..eb23edd 100644 (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
index 3a26a7d..880ba38 100644 (file)
@@ -1722,6 +1722,37 @@ g_socket_receive (GSocket       *socket,
                  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;
 
   g_return_val_if_fail (G_IS_SOCKET (socket) && buffer != NULL, FALSE);
@@ -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)
@@ -1862,6 +1893,37 @@ g_socket_send (GSocket       *socket,
               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;
 
   g_return_val_if_fail (G_IS_SOCKET (socket) && buffer != NULL, FALSE);
@@ -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)
index b2476cc..d17de32 100644 (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__ */
index 4b26ed4..07c4740 100644 (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;
index e79e261..b5d9412 100644 (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;