[gnio/connection-factory: 6/6] Merge branch 'master' into connection-factory



commit 9247ac0a2516f425430cb7be34836a1f2ed392be
Merge: e998aeb... 70d11fa...
Author: Alexander Larsson <alexl redhat com>
Date:   Tue May 12 12:27:47 2009 +0200

    Merge branch 'master' into connection-factory
    
    Trivial Conflicts:
    	gio/gsocketconnection.c
    	gio/gsocketconnection.h
    	gio/gsocketoutputstream.c
    
    Also updated examples/httpd.c to not unref the streams
    from g_io_stream_get_input/output_stream.

 examples/httpd.c          |    2 -
 examples/server.c         |    3 -
 gio/giostream.c           |  510 +++++++++++++++++++++++++++++++++++++++++----
 gio/giostream.h           |   99 +++++++--
 gio/gsocket.c             |   10 +-
 gio/gsocket.h             |   14 ++
 gio/gsocketconnection.c   |  127 +++++++----
 gio/gsocketconnection.h   |    7 +-
 gio/gsocketoutputstream.c |   24 +-
 gio/gtcpconnection.h      |    5 +-
 gio/gtls.c                |   66 ++-----
 11 files changed, 681 insertions(+), 186 deletions(-)

diff --cc examples/httpd.c
index eff6204,0000000..ecc9056
mode 100644,000000..100644
--- a/examples/httpd.c
+++ b/examples/httpd.c
@@@ -1,185 -1,0 +1,183 @@@
 +#include <gio/gnio.h>
 +#include <string.h>
 +
 +static int port = 8080;
 +static char *root = NULL;
 +static GOptionEntry cmd_entries[] = {
 +  {"port", 'p', 0, G_OPTION_ARG_INT, &port,
 +   "Local port to bind to", NULL},
 +  {NULL}
 +};
 +
 +static void
 +send_error (GOutputStream *out,
 +	    int error_code,
 +	    char *reason)
 +{
 +  char *res;
 +
 +  res = g_strdup_printf ("HTTP/1.0 %d %s\r\n\r\n"
 +			 "<html><head><title>%d %s</title></head>"
 +			 "<body>%s</body></html>",
 +			 error_code, reason,
 +			 error_code, reason,
 +			 reason);
 +  g_output_stream_write_all (out, res, strlen (res), NULL, NULL, NULL);
 +  g_free (res);
 +}
 +
 +static gboolean
 +handler (GThreadedSocketService *service,
 +	 GSocketConnection      *connection,
 +	 GSocketListener        *listener,
 +	 gpointer                user_data)
 +{
 +  GOutputStream *out;
 +  GInputStream *in;
 +  GFileInputStream *file_in;
 +  GDataInputStream *data;
 +  char *line, *escaped, *tmp, *query, *unescaped, *path, *version;
 +  GFile *f;
 +  GError *error;
 +  GFileInfo *info;
 +  GString *s;
 +
 +  in = g_io_stream_get_input_stream (G_IO_STREAM (connection));
 +  out = g_io_stream_get_output_stream (G_IO_STREAM (connection));
 +
 +  data = g_data_input_stream_new (in);
 +  /* Be tolerant of input */
 +  g_data_input_stream_set_newline_type (data, G_DATA_STREAM_NEWLINE_TYPE_ANY);
 +
 +  line = g_data_input_stream_read_line (data, NULL, NULL, NULL);
 +
 +  if (line == NULL)
 +    {
 +      send_error (out, 400, "Invalid request");
 +      goto out;
 +    }
 +
 +  if (!g_str_has_prefix (line, "GET "))
 +    {
 +      send_error (out, 501, "Only GET implemented");
 +      goto out;
 +    }
 +
 +  escaped = line + 4; /* Skip "GET " */
 +
 +  version = NULL;
 +  tmp = strchr (escaped, ' ');
 +  if (tmp != NULL)
 +    {
 +      *tmp = 0;
 +      version = tmp + 1;
 +    }
 +
 +  query = strchr (escaped, '?');
 +  if (query != NULL)
 +    *query++ = 0;
 +
 +  unescaped = g_uri_unescape_string (escaped, NULL);
 +  path = g_build_filename (root, unescaped, NULL);
 +  g_free (unescaped);
 +  f = g_file_new_for_path (path);
 +  g_free (path);
 +
 +  error = NULL;
 +  file_in = g_file_read (f, NULL, &error);
 +  if (file_in == NULL)
 +    {
 +      send_error (out, 404, error->message);
 +      g_error_free (error);
 +      goto out;
 +    }
 +
 +  s = g_string_new ("HTTP/1.0 200 OK\r\n");
 +  info = g_file_input_stream_query_info (file_in,
 +					 G_FILE_ATTRIBUTE_STANDARD_SIZE ","
 +					 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
 +					 NULL, NULL);
 +  if (info)
 +    {
 +      const char *content_type;
 +      char *mime_type;
 +
 +      if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_SIZE))
 +	g_string_append_printf (s, "Content-Length: %"G_GINT64_FORMAT"\r\n",
 +				g_file_info_get_size (info));
 +      content_type = g_file_info_get_content_type (info);
 +      if (content_type)
 +	{
 +	  mime_type = g_content_type_get_mime_type (content_type);
 +	  if (mime_type)
 +	    {
 +	      g_string_append_printf (s, "Content-Type: %s\r\n",
 +				      mime_type);
 +	      g_free (mime_type);
 +	    }
 +	}
 +    }
 +  g_string_append (s, "\r\n");
 +
 +  if (g_output_stream_write_all (out,
 +				 s->str, s->len,
 +				 NULL, NULL, NULL))
 +    {
 +      g_output_stream_splice (out,
 +			      G_INPUT_STREAM (file_in),
 +			      0, NULL, NULL);
 +    }
 +  g_string_free (s, TRUE);
 +
 +  g_input_stream_close (G_INPUT_STREAM (file_in), NULL, NULL);
 +  g_object_unref (file_in);
 +
 + out:
-   g_object_unref (out);
-   g_object_unref (in);
 +  g_object_unref (data);
 +
 +  return TRUE;
 +}
 +
 +int
 +main (int argc, char *argv[])
 +{
 +  GSocketService *service;
 +  GOptionContext *context;
 +  GError *error = NULL;
 +
 +  g_type_init ();
 +  g_thread_init (NULL);
 +
 +  context = g_option_context_new ("<http root dir> - Simple HTTP server");
 +  g_option_context_add_main_entries (context, cmd_entries, NULL);
 +  if (!g_option_context_parse (context, &argc, &argv, &error))
 +    {
 +      g_printerr ("%s: %s\n", argv[0], error->message);
 +      return 1;
 +    }
 +
 +  if (argc != 2)
 +    {
 +      g_printerr ("Root directory not specified\n");
 +      return 1;
 +    }
 +
 +  root = g_strdup (argv[1]);
 +
 +  service = g_threaded_socket_service_new ();
 +  if (!g_socket_listener_add_inet_port (G_SOCKET_LISTENER (service),
 +					port,
 +					NULL,
 +					&error))
 +    {
 +      g_printerr ("%s: %s\n", argv[0], error->message);
 +      return 1;
 +    }
 +
 +  g_print ("Http server listening on port %d\n", port);
 +
 +  g_signal_connect (service, "run", G_CALLBACK (handler), NULL);
 +
 +  g_main_loop_run (g_main_loop_new (NULL, FALSE));
 +  g_assert_not_reached ();
 +}
diff --cc gio/gsocketconnection.c
index 286b559,b45e2dc..9c75fe6
--- a/gio/gsocketconnection.c
+++ b/gio/gsocketconnection.c
@@@ -36,17 -36,11 +36,13 @@@
  
  #include "gsocketoutputstream.h"
  #include "gsocketinputstream.h"
- #include "giostream.h"
- 
+ #include <gio/giostream.h>
+ #include <gio/gsimpleasyncresult.h>
 +#include "gunixconnection.h"
 +#include "gtcpconnection.h"
  
- 
- static void g_socket_connection_iface_init (GIOStreamIface *iface);
- G_DEFINE_TYPE_WITH_CODE (GSocketConnection,
-                          g_socket_connection, G_TYPE_OBJECT,
-   G_IMPLEMENT_INTERFACE (G_TYPE_IO_STREAM,
-                          g_socket_connection_iface_init));
+ G_DEFINE_TYPE (GSocketConnection,
+ 	       g_socket_connection, G_TYPE_IO_STREAM);
  
  enum
  {
@@@ -81,20 -85,12 +87,20 @@@ g_socket_connection_get_output_stream (
    GSocketConnection *connection = G_SOCKET_CONNECTION (io_stream);
  
    if (connection->priv->output_stream == NULL)
-     connection->priv->output_stream =
+     connection->priv->output_stream = (GOutputStream *)
        _g_socket_output_stream_new (connection->priv->socket);
  
-   return g_object_ref (connection->priv->output_stream);
+   return connection->priv->output_stream;
  }
  
 +GSocket *
 +g_socket_connection_get_socket (GSocketConnection *connection)
 +{
 +  g_return_val_if_fail (G_IS_SOCKET_CONNECTION (connection), NULL);
 +
 +  return connection->priv->socket;
 +}
 +
  static void
  g_socket_connection_get_property (GObject *object, guint prop_id,
                                    GValue *value, GParamSpec *pspec)
@@@ -200,156 -185,57 +195,194 @@@ g_socket_connection_init (GSocketConnec
                                                    GSocketConnectionPrivate);
  }
  
- gboolean
- g_socket_connection_close (GSocketConnection *connection,
- 			   GError **error)
+ static gboolean
+ g_socket_connection_close (GIOStream            *stream,
+ 			   GCancellable         *cancellable,
+ 			   GError              **error)
  {
-   g_return_val_if_fail (G_IS_SOCKET_CONNECTION (connection), TRUE);
+   GSocketConnection *connection = G_SOCKET_CONNECTION (stream);
  
-   return g_socket_close (connection->priv->socket,
- 			 error);
+   if (connection->priv->output_stream)
+     g_output_stream_close (connection->priv->output_stream,
+ 			   cancellable, NULL);
+   if (connection->priv->input_stream)
+     g_input_stream_close (connection->priv->input_stream,
+ 			  cancellable, NULL);
+ 
+   return g_socket_close (connection->priv->socket, error);
  }
  
+ 
  static void
- g_socket_connection_iface_init (GIOStreamIface *iface)
+ g_socket_connection_close_async (GIOStream        *stream,
+ 				 int               io_priority,
+ 				 GCancellable     *cancellable,
+ 				 GAsyncReadyCallback callback,
+ 				 gpointer          user_data)
+ {
+   GSimpleAsyncResult *res;
+   GError *error;
+ 
+   /* socket close is not blocked, just do it! */
+   error = NULL;
+   if (!g_io_stream_close (stream, cancellable, &error))
+     {
+       g_simple_async_report_gerror_in_idle (G_OBJECT (stream),
+ 					    callback, user_data,
+ 					    error);
+       g_error_free (error);
+       return;
+     }
+ 
+   res = g_simple_async_result_new (G_OBJECT (stream),
+ 				   callback,
+ 				   user_data,
+ 				   g_socket_connection_close_async);
+   g_simple_async_result_complete_in_idle (res);
+   g_object_unref (res);
+ }
+ 
+ static gboolean
+ g_socket_connection_close_finish (GIOStream  *stream,
+ 				  GAsyncResult  *result,
+ 				  GError       **error)
  {
-   iface->get_input_stream = g_socket_connection_get_input_stream;
-   iface->get_output_stream = g_socket_connection_get_output_stream;
+   return TRUE;
  }
 +
 +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)
 +{
 +  volatile GType a_type;
 +#ifndef G_OS_WIN32
 +  a_type = g_unix_connection_get_type ();
 +#endif
 +  a_type = g_tcp_connection_get_type ();
 +}
 +
 +GType
 +g_socket_connection_factory_lookup_type (GSocketFamily  family,
 +					 GSocketType    type,
 +					 const char    *protocol)
 +{
 +  ConnectionFactory *factory, key;
 +  GType g_type;
 +
 +  init_builtin_types ();
 +
 +  G_LOCK (connection_factories);
 +
 +  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 --cc gio/gsocketconnection.h
index 8fad718,e32f0dd..96481a1
--- a/gio/gsocketconnection.h
+++ b/gio/gsocketconnection.h
@@@ -22,7 -22,7 +22,8 @@@
  #define _gsocketconnection_h_
  
  #include <glib-object.h>
 +#include <gio/gsocket.h>
+ #include <gio/giostream.h>
  
  G_BEGIN_DECLS
  
@@@ -53,20 -53,7 +54,18 @@@ struct _GSocketConnectio
    GSocketConnectionPrivate *priv;
  };
  
 -GType                   g_socket_connection_get_type                    (void);
 +GType              g_socket_connection_get_type                  (void);
 +
 +GSocket           *g_socket_connection_get_socket                (GSocketConnection *connection);
- 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
  
diff --cc gio/gsocketoutputstream.c
index 2bb55d6,ddf7931..b8b94f7
--- a/gio/gsocketoutputstream.c
+++ b/gio/gsocketoutputstream.c
@@@ -195,8 -194,8 +195,8 @@@ g_socket_output_stream_write_async (GOu
      }
    else
      {
-       input_stream->priv->from_mainloop = FALSE;
-       g_socket_output_stream_write_ready (input_stream->priv->socket, G_IO_OUT, input_stream);
+       output_stream->priv->from_mainloop = FALSE;
 -      g_socket_output_stream_write_ready (output_stream, G_IO_OUT);
++      g_socket_output_stream_write_ready (output_stream->priv->socket, G_IO_OUT, output_stream);
      }
  }
  



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