[gnio/connection-factory] Various GSocketClient cleanups and fixes



commit 73e9962366e8256227eb1da6d93fcb33f71de17c
Author: Alexander Larsson <alexl redhat com>
Date:   Fri May 8 20:43:55 2009 +0200

    Various GSocketClient cleanups and fixes
    
    Bind to the local address if set.
    We have no enum GType for GSocketType yet, use int for now.
    Check cancellation during async connect
    Remove unused getting of the class
    Restructure async connect to look like the sync one for easy reading.
    Fix leak of connection (it was ref:ed twice)
---
 gio/gsocketclient.c |  187 +++++++++++++++++++++++++++++----------------------
 1 files changed, 107 insertions(+), 80 deletions(-)

diff --git a/gio/gsocketclient.c b/gio/gsocketclient.c
index 6e46e02..908e6c4 100644
--- a/gio/gsocketclient.c
+++ b/gio/gsocketclient.c
@@ -42,7 +42,6 @@ enum
   PROP_LOCAL_ADDRESS
 };
 
-
 struct _GSocketClientPrivate
 {
   GSocketFamily family;
@@ -57,6 +56,7 @@ create_socket (GSocketClient  *client,
 	       GError        **error)
 {
   GSocketFamily family;
+  GSocket *socket;
 
   family = client->priv->family;
   if (family == G_SOCKET_FAMILY_INVALID &&
@@ -65,10 +65,25 @@ create_socket (GSocketClient  *client,
   if (family == G_SOCKET_FAMILY_INVALID)
     family = g_socket_address_get_family (dest_address);
 
-  return g_socket_new (family,
-		       client->priv->type,
-		       client->priv->protocol,
-		       error);
+  socket = g_socket_new (family,
+			 client->priv->type,
+			 client->priv->protocol,
+			 error);
+  if (socket == NULL)
+    return NULL;
+
+  if (client->priv->local_address)
+    {
+      if (!g_socket_bind (socket,
+			  client->priv->local_address,
+			  error))
+	{
+	  g_object_unref (socket);
+	  return NULL;
+	}
+    }
+
+  return socket;
 }
 
 static void
@@ -109,7 +124,7 @@ g_socket_client_get_property (GObject    *object,
         break;
 
       case PROP_TYPE:
-        g_value_set_enum (value, client->priv->type);
+        g_value_set_int (value, client->priv->type);
         break;
 
       case PROP_PROTOCOL:
@@ -140,7 +155,7 @@ g_socket_client_set_property (GObject      *object,
         break;
 
       case PROP_TYPE:
-        client->priv->type = g_value_get_enum (value);
+        client->priv->type = g_value_get_int (value);
         break;
 
       case PROP_PROTOCOL:
@@ -210,20 +225,21 @@ g_socket_client_connect (GSocketClient       *client,
                          GError             **error)
 {
   GSocketConnection *connection = NULL;
-  GSocketClientClass *class;
   GSocketAddressEnumerator *enumerator;
 
-  class = G_SOCKET_CLIENT_GET_CLASS (client);
-
-  if (g_cancellable_set_error_if_cancelled (cancellable, error))
-    return NULL;
-
   enumerator = g_socket_connectable_enumerate (connectable);
-  while (!connection && !g_cancellable_is_cancelled (cancellable))
+  while (connection == NULL)
     {
       GSocketAddress *address;
       GSocket *socket;
 
+      if (g_cancellable_is_cancelled (cancellable))
+	{
+	  g_clear_error (error);
+	  g_cancellable_set_error_if_cancelled (cancellable, error);
+	  break;
+	}
+
       address =
         g_socket_address_enumerator_next (enumerator, cancellable, error);
 
@@ -234,18 +250,18 @@ g_socket_client_connect (GSocketClient       *client,
         }
 
       /* clear error from previous attempt */
-      if (error && *error)
-        g_clear_error (error);
+      g_clear_error (error);
 
       socket = create_socket (client, address, error);
       if (socket != NULL)
 	{
 	  if (g_socket_connect (socket, address, error))
 	    connection = g_socket_connection_factory_create_connection (socket);
+
+	  g_object_unref (socket);
 	}
 
       g_object_unref (address);
-      g_object_unref (socket);
     }
   g_object_unref (enumerator);
 
@@ -268,21 +284,21 @@ static void
 g_socket_client_async_connect_complete (GSocketClientAsyncConnectData *data)
 {
   GSocketConnection *connection;
-  GSocketClientClass *class;
 
   if (data->last_error)
     {
       g_simple_async_result_set_from_error (data->result, data->last_error);
       g_error_free (data->last_error);
     }
-
   else
     {
       g_assert (data->current_socket);
-      class = G_SOCKET_CLIENT_GET_CLASS (data->client);
+
+      g_socket_set_blocking (data->current_socket, TRUE);
+
       connection = g_socket_connection_factory_create_connection (data->current_socket);
       g_simple_async_result_set_op_res_gpointer (data->result,
-                                                 g_object_ref (connection),
+                                                 connection,
                                                  g_object_unref);
     }
 
@@ -296,9 +312,17 @@ g_socket_client_enumerator_callback (GObject      *object,
 				     GAsyncResult *result,
 				     gpointer      user_data);
 
+static void
+set_last_error (GSocketClientAsyncConnectData *data,
+		GError *error)
+{
+  g_clear_error (&data->last_error);
+  data->last_error = error;
+}
+
 static gboolean
 g_socket_client_socket_callback (GSocketClientAsyncConnectData *data,
-                                 GIOCondition                   condition)
+                                 GIOCondition  condition)
 {
   GError *error = NULL;
 
@@ -306,6 +330,8 @@ g_socket_client_socket_callback (GSocketClientAsyncConnectData *data,
     {
       /* Cancelled, return done with last error being cancelled */
       g_clear_error (&data->last_error);
+      g_object_unref (data->current_socket);
+      data->current_socket = NULL;
       g_cancellable_set_error_if_cancelled (data->cancellable,
 					    &data->last_error);
     }
@@ -314,12 +340,13 @@ g_socket_client_socket_callback (GSocketClientAsyncConnectData *data,
       /* socket is ready for writing = connect done, did it succeed? */
       if (!g_socket_check_pending_error (data->current_socket, &error))
 	{
-	  g_clear_error (&data->last_error);
-	  data->last_error = error;
+	  set_last_error (data, error);
 
 	  /* try next one */
 	  g_socket_address_enumerator_next_async (data->enumerator,
-						  data->cancellable, g_socket_client_enumerator_callback, data);
+						  data->cancellable,
+						  g_socket_client_enumerator_callback,
+						  data);
 
 	  return FALSE;
 	}
@@ -329,6 +356,8 @@ g_socket_client_socket_callback (GSocketClientAsyncConnectData *data,
       /* G_IO_ERR maybe?, can this happen? */
       g_object_unref (data->current_socket);
       data->current_socket = NULL;
+      g_set_error (&data->last_error, G_IO_ERROR, G_IO_ERROR_FAILED,
+		   _("Unknown error on connect"));
 
       /* try next one */
       g_socket_address_enumerator_next_async (data->enumerator,
@@ -342,7 +371,6 @@ g_socket_client_socket_callback (GSocketClientAsyncConnectData *data,
   return FALSE;
 }
 
-
 static void
 g_socket_client_enumerator_callback (GObject      *object,
 				     GAsyncResult *result,
@@ -350,77 +378,76 @@ g_socket_client_enumerator_callback (GObject      *object,
 {
   GSocketClientAsyncConnectData *data = user_data;
   GSocketAddress *address;
+  GSocket *socket;
+  GError *tmp_error = NULL;
 
-  {
-    GError *tmp_error = NULL;
-
-    address = g_socket_address_enumerator_next_finish (data->enumerator,
-						       result, &tmp_error);
-    if (address || tmp_error)
+  if (g_cancellable_is_cancelled (data->cancellable))
+    {
       g_clear_error (&data->last_error);
+      g_cancellable_set_error_if_cancelled (data->cancellable, &data->last_error);
+      g_socket_client_async_connect_complete (data);
+      return;
+    }
 
-    if (tmp_error)
-      data->last_error = tmp_error;
-  }
+  address = g_socket_address_enumerator_next_finish (data->enumerator,
+						     result, &tmp_error);
 
-  if (address)
+  if (address == NULL)
     {
-      GSocketClientClass *class;
-      GError *tmp_error = NULL;
-      gboolean pending;
-      GSocket *socket;
+      if (tmp_error)
+	set_last_error (data, tmp_error);
+      else if (data->last_error == NULL)
+	g_set_error (&data->last_error, G_IO_ERROR, G_IO_ERROR_FAILED,
+		     _("Unknown error on connect"));
+
+      g_socket_client_async_connect_complete (data);
+      return;
+    }
 
-      class = G_SOCKET_CLIENT_GET_CLASS (data->client);
-      socket = create_socket (data->client, address, &tmp_error);
+  g_clear_error (&data->last_error);
 
-      if (socket == NULL)
+  socket = create_socket (data->client, address, &data->last_error);
+  if (socket != NULL)
+    {
+      g_socket_set_blocking (socket, FALSE);
+      if (g_socket_connect (socket, address, &tmp_error))
 	{
-	  g_clear_error (&data->last_error);
-	  data->last_error = tmp_error;
-	  g_socket_address_enumerator_next_async (data->enumerator,
-						  data->cancellable,
-						  g_socket_client_enumerator_callback,
-						  data);
+	  data->current_socket = socket;
+	  g_socket_client_async_connect_complete (data);
+
 	  g_object_unref (address);
 	  return;
 	}
+      else if (g_error_matches (tmp_error, G_IO_ERROR, G_IO_ERROR_PENDING))
+	{
+	  GSource *source;
 
-      g_socket_set_blocking (socket, FALSE);
-      pending = (g_socket_connect (socket, address, &tmp_error) == FALSE) &&
-                 g_error_matches (tmp_error, G_IO_ERROR, G_IO_ERROR_PENDING);
-      g_socket_set_blocking (socket, TRUE);
-
-      if (pending)
-        {
-          GSource *source;
-
-          data->current_socket = g_object_ref (socket);
-          g_error_free (tmp_error);
+	  data->current_socket = socket;
+	  g_error_free (tmp_error);
 
-          source = g_socket_create_source (socket, G_IO_OUT,
-                                           data->cancellable);
-          g_source_set_callback (source,
-                                 (GSourceFunc) g_socket_client_socket_callback,
-                                 data, NULL);
-          g_source_attach (source, NULL);
+	  source = g_socket_create_source (socket, G_IO_OUT,
+					   data->cancellable);
+	  g_source_set_callback (source,
+				 (GSourceFunc) g_socket_client_socket_callback,
+				 data, NULL);
+	  g_source_attach (source, NULL);
 	  g_source_unref (source);
 
-          return;
-        }
-
-      else if (tmp_error)
-        data->last_error = tmp_error;
-
-      g_object_unref (socket);
-
-      /* in theory connect should never immediately succeed?
-       * this assert is just out of curiosity.  things will be OK if there
-       * is success anyway.
-       */
-      g_assert (tmp_error);
+	  g_object_unref (address);
+	  return;
+	}
+      else
+	{
+	  data->last_error = tmp_error;
+	  g_object_unref (socket);
+	}
+      g_object_unref (address);
     }
 
-  g_socket_client_async_connect_complete (data);
+  g_socket_address_enumerator_next_async (data->enumerator,
+					  data->cancellable,
+					  g_socket_client_enumerator_callback,
+					  data);
 }
 
 void



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]