[gnio/connection-factory: 1/6] Add generic socket connection factory



commit fe7937c1553fb5d3eb4660b83025edc0666152b7
Author: Alexander Larsson <alexl redhat com>
Date:   Fri May 8 14:33:37 2009 +0200

    Add generic socket connection factory
    
    Classes can register a specific type for a family/type/protocol tuple.
    This will be used when creating a connection from a socket.
---
 gio/gsocketconnection.c |  140 +++++++++++++++++++++++++++++++++++++++++++++++
 gio/gsocketconnection.h |   16 ++++-
 2 files changed, 153 insertions(+), 3 deletions(-)

diff --git a/gio/gsocketconnection.c b/gio/gsocketconnection.c
index 3d9a7c1..60687e3 100644
--- a/gio/gsocketconnection.c
+++ b/gio/gsocketconnection.c
@@ -38,6 +38,9 @@
 #include "gsocketinputstream.h"
 #include "giostream.h"
 
+#include "gunixconnection.h"
+
+
 static void g_socket_connection_iface_init (GIOStreamIface *iface);
 G_DEFINE_TYPE_WITH_CODE (GSocketConnection,
                          g_socket_connection, G_TYPE_OBJECT,
@@ -204,3 +207,140 @@ g_socket_connection_iface_init (GIOStreamIface *iface)
   iface->get_input_stream = g_socket_connection_get_input_stream;
   iface->get_output_stream = g_socket_connection_get_output_stream;
 }
+
+typedef struct {
+  GSocketFamily socket_family;
+  GSocketType socket_type;
+  char *protocol;
+  GType implementation;
+} ConnectionFactory;
+
+static guint
+connection_factory_hash (gconstpointer key)
+{
+  const ConnectionFactory *factory = key;
+  guint h;
+
+  h = factory->socket_family ^ (factory->socket_type << 4);
+  /* This is likely to be small, so spread over whole
+     hash space to get some distribution */
+  h = h ^ (h << 8) ^ (h << 16) ^ (h << 24);
+
+  if (factory->protocol)
+    h ^= g_str_hash (factory->protocol);
+  return h;
+}
+
+static gboolean
+connection_factory_equal (gconstpointer _a,
+			  gconstpointer _b)
+{
+  const ConnectionFactory *a = _a;
+  const ConnectionFactory *b = _b;
+
+  if (a->socket_family != b->socket_family)
+    return FALSE;
+
+  if (a->socket_type != b->socket_type)
+    return FALSE;
+
+  if (a->protocol != b->protocol)
+    {
+      if (a->protocol == NULL || b->protocol == NULL)
+	return FALSE;
+
+      if (strcmp (a->protocol, b->protocol) != 0)
+	return FALSE;
+    }
+
+  return TRUE;
+}
+
+static void
+connection_factory_free (ConnectionFactory *factory)
+{
+  g_free (factory->protocol);
+  g_free (factory);
+}
+
+static GHashTable *connection_factories = NULL;
+G_LOCK_DEFINE_STATIC(connection_factories);
+
+void
+g_socket_connection_factory_register_type (GType g_type,
+					   GSocketFamily family,
+					   GSocketType type,
+					   const char *protocol)
+{
+  ConnectionFactory *factory;
+
+  G_LOCK (connection_factories);
+
+  if (connection_factories == NULL)
+    connection_factories = g_hash_table_new_full (connection_factory_hash,
+						  connection_factory_equal,
+						  (GDestroyNotify)connection_factory_free,
+						  NULL);
+
+  factory = g_new0 (ConnectionFactory, 1);
+  factory->socket_family = family;
+  factory->socket_type = type;
+  factory->protocol = g_strdup (protocol);
+  factory->implementation = g_type;
+
+  g_hash_table_insert (connection_factories,
+		       factory, factory);
+
+  G_UNLOCK (connection_factories);
+}
+
+static void
+init_builtin_types (void)
+{
+#ifndef G_OS_WIN32
+  volatile GType a_type;
+
+  a_type = g_unix_connection_get_type ();
+#endif
+}
+
+GType
+g_socket_connection_factory_lookup_type (GSocketFamily  family,
+					 GSocketType    type,
+					 const char    *protocol)
+{
+  ConnectionFactory *factory, key;
+  GType g_type;
+
+  G_LOCK (connection_factories);
+
+  init_builtin_types ();
+
+  g_type = G_TYPE_SOCKET_CONNECTION;
+
+  if (connection_factories)
+    {
+      key.socket_family = family;
+      key.socket_type = type;
+      key.protocol = (char *)protocol;
+
+      factory = g_hash_table_lookup (connection_factories, &key);
+      if (factory)
+	g_type = factory->implementation;
+    }
+
+  G_UNLOCK (connection_factories);
+
+  return g_type;
+}
+
+GSocketConnection *
+g_socket_connection_factory_create_connection (GSocket *socket)
+{
+  GType type;
+
+  type = g_socket_connection_factory_lookup_type (g_socket_get_family (socket),
+						  g_socket_get_socket_type (socket),
+						  g_socket_get_protocol (socket));
+  return g_object_new (type, "socket", socket, NULL);
+}
diff --git a/gio/gsocketconnection.h b/gio/gsocketconnection.h
index 40ed737..55b1996 100644
--- a/gio/gsocketconnection.h
+++ b/gio/gsocketconnection.h
@@ -22,6 +22,7 @@
 #define _gsocketconnection_h_
 
 #include <glib-object.h>
+#include <gio/gsocket.h>
 
 G_BEGIN_DECLS
 
@@ -52,10 +53,19 @@ struct _GSocketConnection
   GSocketConnectionPrivate *priv;
 };
 
-GType                   g_socket_connection_get_type                    (void);
+GType              g_socket_connection_get_type                  (void);
 
-gboolean                g_socket_connection_close                       (GSocketConnection *connection,
-									 GError **error);
+gboolean           g_socket_connection_close                     (GSocketConnection *connection,
+								  GError **error);
+
+void               g_socket_connection_factory_register_type     (GType          g_type,
+								  GSocketFamily  family,
+								  GSocketType    type,
+								  const char    *protocol);
+GType              g_socket_connection_factory_lookup_type       (GSocketFamily  family,
+								  GSocketType    type,
+								  const char    *protocol);
+GSocketConnection *g_socket_connection_factory_create_connection (GSocket       *socket);
 
 G_END_DECLS
 



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