[gnio/connection-factory: 6/6] Merge branch 'master' into connection-factory
- From: Alexander Larsson <alexl src gnome org>
- To: svn-commits-list gnome org
- Subject: [gnio/connection-factory: 6/6] Merge branch 'master' into connection-factory
- Date: Tue, 12 May 2009 06:41:13 -0400 (EDT)
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]