[glib] Import all the highlevel socket classes from gnio



commit ce8361217c1c9bd458eab55554a77d24210235cc
Author: Alexander Larsson <alexl redhat com>
Date:   Fri May 15 21:26:24 2009 +0200

    Import all the highlevel socket classes from gnio
---
 gio/Makefile.am              |   22 +-
 gio/gio-marshal.list         |    1 +
 gio/gio.h                    |    8 +-
 gio/gio.symbols              |   82 ++++
 gio/giotypes.h               |   50 +++
 gio/gsocketclient.c          |  912 ++++++++++++++++++++++++++++++++++++++++++
 gio/gsocketclient.h          |  115 ++++++
 gio/gsocketconnection.c      |  474 ++++++++++++++++++++++
 gio/gsocketconnection.h      |   91 +++++
 gio/gsocketinputstream.c     |  259 ++++++++++++
 gio/gsocketinputstream.h     |   58 +++
 gio/gsocketlistener.c        |  815 +++++++++++++++++++++++++++++++++++++
 gio/gsocketlistener.h        |  134 ++++++
 gio/gsocketoutputstream.c    |  259 ++++++++++++
 gio/gsocketoutputstream.h    |   58 +++
 gio/gsocketservice.c         |  330 +++++++++++++++
 gio/gsocketservice.h         |   88 ++++
 gio/gtcpconnection.c         |   67 +++
 gio/gtcpconnection.h         |   64 +++
 gio/gthreadedsocketservice.c |  215 ++++++++++
 gio/gthreadedsocketservice.h |   81 ++++
 gio/gunixconnection.c        |  293 ++++++++++++++
 gio/gunixconnection.h        |   77 ++++
 23 files changed, 4550 insertions(+), 3 deletions(-)

diff --git a/gio/Makefile.am b/gio/Makefile.am
index 12413c1..3f8f180 100644
--- a/gio/Makefile.am
+++ b/gio/Makefile.am
@@ -130,6 +130,7 @@ appinfo_sources += gdesktopappinfo.c gdesktopappinfo.h
 platform_libadd += libasyncns/libasyncns.la xdgmime/libxdgmime.la
 platform_deps += libasyncns/libasyncns.la xdgmime/libxdgmime.la
 unix_sources = \
+	gunixconnection.c	\
 	gunixfdmessage.c	\
 	gunixmount.c		\
 	gunixmount.h		\
@@ -150,6 +151,7 @@ unix_sources = \
 giounixincludedir=$(includedir)/gio-unix-2.0/gio
 giounixinclude_HEADERS = \
 	gdesktopappinfo.h	\
+	gunixconnection.h	\
 	gunixmounts.h 		\
 	gunixfdmessage.h	\
 	gunixinputstream.h 	\
@@ -235,11 +237,21 @@ libgio_2_0_la_SOURCES =		\
 	gseekable.c 		\
 	gsimpleasyncresult.c 	\
 	gsocket.c		\
-	gsocketcontrolmessage.c	\
 	gsocketaddress.c	\
 	gsocketaddressenumerator.c \
+	gsocketclient.c		\
 	gsocketconnectable.c	\
+	gsocketconnection.c	\
+	gsocketcontrolmessage.c	\
+	gsocketinputstream.c	\
+	gsocketinputstream.h	\
+	gsocketlistener.c	\
+	gsocketoutputstream.c	\
+	gsocketoutputstream.h	\
+	gsocketservice.c	\
 	gsrvtarget.c		\
+	gtcpconnection.c	\
+	gthreadedsocketservice.c\
 	gthemedicon.c 		\
 	gthreadedresolver.c	\
 	gthreadedresolver.h	\
@@ -353,11 +365,17 @@ gio_headers =			\
 	gseekable.h 		\
 	gsimpleasyncresult.h 	\
 	gsocket.h		\
-	gsocketcontrolmessage.h	\
 	gsocketaddress.h	\
 	gsocketaddressenumerator.h \
+	gsocketclient.h		\
 	gsocketconnectable.h	\
+	gsocketconnection.h	\
+	gsocketcontrolmessage.h	\
+	gsocketlistener.h	\
+	gsocketservice.h	\
 	gsrvtarget.h		\
+	gtcpconnection.h	\
+	gthreadedsocketservice.h\
 	gthemedicon.h 		\
 	gvfs.h 			\
 	gvolume.h 		\
diff --git a/gio/gio-marshal.list b/gio/gio-marshal.list
index ab176d6..ee0d2e3 100644
--- a/gio/gio-marshal.list
+++ b/gio/gio-marshal.list
@@ -2,3 +2,4 @@ VOID:STRING,STRING,STRING,FLAGS
 VOID:STRING,BOXED
 VOID:BOOLEAN,POINTER
 VOID:OBJECT,OBJECT,ENUM
+BOOLEAN:OBJECT,OBJECT
diff --git a/gio/gio.h b/gio/gio.h
index 0160b82..ad17503 100644
--- a/gio/gio.h
+++ b/gio/gio.h
@@ -74,10 +74,16 @@
 #include <gio/gseekable.h>
 #include <gio/gsimpleasyncresult.h>
 #include <gio/gsocket.h>
-#include <gio/gsocketcontrolmessage.h>
 #include <gio/gsocketaddress.h>
 #include <gio/gsocketaddressenumerator.h>
+#include <gio/gsocketclient.h>
 #include <gio/gsocketconnectable.h>
+#include <gio/gsocketconnection.h>
+#include <gio/gsocketcontrolmessage.h>
+#include <gio/gsocketlistener.h>
+#include <gio/gsocketservice.h>
+#include <gio/gtcpconnection.h>
+#include <gio/gthreadedsocketservice.h>
 #include <gio/gsrvtarget.h>
 #include <gio/gthemedicon.h>
 #include <gio/gvfs.h>
diff --git a/gio/gio.symbols b/gio/gio.symbols
index 3078b3b..48561b6 100644
--- a/gio/gio.symbols
+++ b/gio/gio.symbols
@@ -1110,6 +1110,88 @@ g_socket_control_message_serialize
 #endif
 #endif
 
+#if IN_HEADER(__G_SOCKET_CLIENT_H__)
+#if IN_FILE(__G_SOCKET_CLIENT_C__)
+g_socket_client_get_type G_GNUC_CONST
+g_socket_client_connect
+g_socket_client_connect_async
+g_socket_client_connect_finish
+g_socket_client_connect_to_host
+g_socket_client_connect_to_host_async
+g_socket_client_connect_to_host_finish
+g_socket_client_get_family
+g_socket_client_get_local_address
+g_socket_client_get_protocol
+g_socket_client_get_socket_type
+g_socket_client_new
+g_socket_client_set_family
+g_socket_client_set_local_address
+g_socket_client_set_protocol
+g_socket_client_set_socket_type
+#endif
+#endif
+
+#if IN_HEADER(__G_SOCKET_CONNECTION_H__)
+#if IN_FILE(__G_SOCKET_CONNECTION_C__)
+g_socket_connection_get_type G_GNUC_CONST
+g_socket_connection_factory_create_connection
+g_socket_connection_factory_lookup_type
+g_socket_connection_factory_register_type
+g_socket_connection_get_local_address
+g_socket_connection_get_remote_address
+g_socket_connection_get_socket
+#endif
+#endif
+
+#if IN_HEADER(__G_SOCKET_LISTENER_H__)
+#if IN_FILE(__G_SOCKET_LISTENER_C__)
+g_socket_listener_get_type G_GNUC_CONST
+g_socket_listener_accept
+g_socket_listener_accept_async
+g_socket_listener_accept_finish
+g_socket_listener_accept_socket
+g_socket_listener_accept_socket_async
+g_socket_listener_accept_socket_finish
+g_socket_listener_add_address
+g_socket_listener_add_inet_port
+g_socket_listener_add_socket
+g_socket_listener_close
+g_socket_listener_new
+g_socket_listener_set_backlog
+#endif
+#endif
+
+#if IN_HEADER(__G_SOCKET_SERVICE_H__)
+#if IN_FILE(__G_SOCKET_SERVICE_C__)
+g_socket_service_get_type G_GNUC_CONST
+g_socket_service_is_active
+g_socket_service_new
+g_socket_service_start
+g_socket_service_stop
+#endif
+#endif
+
+#if IN_HEADER(__G_THREADED_SOCKET_SERVICE_H__)
+#if IN_FILE(__G_THREADED_SOCKET_SERVICE_C__)
+g_threaded_socket_service_get_type G_GNUC_CONST
+g_threaded_socket_service_new
+#endif
+#endif
+
+#if IN_HEADER(__G_TCP_CONNECTION_H__)
+#if IN_FILE(__G_TCP_CONNECTION_C__)
+g_tcp_connection_get_type G_GNUC_CONST
+#endif
+#endif
+
+#if IN_HEADER(__G_UNIX_CONNECTION_H__)
+#if IN_FILE(__G_UNIX_CONNECTION_C__)
+g_unix_connection_get_type G_GNUC_CONST
+g_unix_connection_receive_fd
+g_unix_connection_send_fd
+#endif
+#endif
+
 #if IN_HEADER(__G_UNIX_FD_MESSAGE_H__)
 #if IN_FILE(__G_UNIX_FD_MESSAGE_C__)
 g_unix_fd_message_get_type G_GNUC_CONST
diff --git a/gio/giotypes.h b/gio/giotypes.h
index 70bc054..2a7fbac 100644
--- a/gio/giotypes.h
+++ b/gio/giotypes.h
@@ -126,10 +126,60 @@ typedef struct _GSocket                       GSocket;
  * received over #GSocket.
  **/
 typedef struct _GSocketControlMessage         GSocketControlMessage;
+/**
+ * GSocketClient:
+ *
+ * A helper class for network clients to make connections.
+ *
+ * Since: 2.22
+ **/
+typedef struct _GSocketClient                               GSocketClient;
+/**
+ * GSocketConnection:
+ *
+ * A socket connection GIOStream object for connection-oriented sockets.
+ *
+ * Since: 2.22
+ **/
+typedef struct _GSocketConnection                           GSocketConnection;
+/**
+ * GSocketClient:
+ *
+ * A helper class for network servers to listen for and accept connections.
+ *
+ * Since: 2.22
+ **/
+typedef struct _GSocketListener                             GSocketListener;
+/**
+ * GSocketService:
+ *
+ * A helper class for handling accepting incomming connections in the
+ * glib mainloop.
+ *
+ * Since: 2.22
+ **/
+typedef struct _GSocketService                              GSocketService;
 typedef struct _GSocketAddress                GSocketAddress;
 typedef struct _GSocketAddressEnumerator      GSocketAddressEnumerator;
 typedef struct _GSocketConnectable            GSocketConnectable;
 typedef struct _GSrvTarget                    GSrvTarget;
+/**
+ * GTcpConnection:
+ *
+ * A #GSocketConnection for TCP/IP connections.
+ *
+ * Since: 2.22
+ **/
+typedef struct _GTcpConnection                              GTcpConnection;
+/**
+ * GThreadedSocketService:
+ *
+ * A helper class for handling accepting incomming connections in the
+ * glib mainloop and handling them in a thread.
+ *
+ * Since: 2.22
+ **/
+typedef struct _GThreadedSocketService                      GThreadedSocketService;
 typedef struct _GThemedIcon                   GThemedIcon;
 typedef struct _GVfs                          GVfs; /* Dummy typedef */
 
diff --git a/gio/gsocketclient.c b/gio/gsocketclient.c
new file mode 100644
index 0000000..84b9b32
--- /dev/null
+++ b/gio/gsocketclient.c
@@ -0,0 +1,912 @@
+/*  GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright © 2008, 2009 codethink
+ * Copyright © 2009 Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Ryan Lortie <desrt desrt ca>
+ *          Alexander Larsson <alexl redhat com>
+ */
+
+#include "config.h"
+#include "gsocketclient.h"
+
+#include <stdlib.h>
+
+#include <gio/gioenumtypes.h>
+#include <gio/gsocketaddressenumerator.h>
+#include <gio/gsocketconnectable.h>
+#include <gio/gsocketconnection.h>
+#include <gio/gsimpleasyncresult.h>
+#include <gio/gcancellable.h>
+#include <gio/gioerror.h>
+#include <gio/gsocket.h>
+#include <gio/gnetworkaddress.h>
+#include <gio/gsocketaddress.h>
+#include "glibintl.h"
+
+#include "gioalias.h"
+
+/**
+ * SECTION:gsocketclient
+ * @short_description: High-level client network helper
+ * @include: gio/gio.h
+ * @see_also: #GSocketConnection, #GSocketListener
+ *
+ * #GSocketClient is a high-level utility class for connecting to a
+ * network host using a connection oriented socket type.
+ *
+ * You create a #GSocketClient object, set any options you want, then
+ * call a sync or async connect operation, which returns a #GSocketConnection
+ * subclass on success.
+ *
+ * The type of the #GSocketConnection object returned depends on the type of
+ * the underlying socket that is in use. For instance, for a TCP/IP connection
+ * it will be a #GTcpConnection.
+ *
+ * Since: 2.22
+ **/
+
+
+G_DEFINE_TYPE (GSocketClient, g_socket_client, G_TYPE_OBJECT);
+
+enum
+{
+  PROP_NONE,
+  PROP_FAMILY,
+  PROP_TYPE,
+  PROP_PROTOCOL,
+  PROP_LOCAL_ADDRESS
+};
+
+struct _GSocketClientPrivate
+{
+  GSocketFamily family;
+  GSocketType type;
+  char *protocol;
+  GSocketAddress *local_address;
+};
+
+static GSocket *
+create_socket (GSocketClient  *client,
+	       GSocketAddress *dest_address,
+	       GError        **error)
+{
+  GSocketFamily family;
+  GSocket *socket;
+  int proto;
+
+  family = client->priv->family;
+  if (family == G_SOCKET_FAMILY_INVALID &&
+      client->priv->local_address != NULL)
+    family = g_socket_address_get_family (client->priv->local_address);
+  if (family == G_SOCKET_FAMILY_INVALID)
+    family = g_socket_address_get_family (dest_address);
+
+  proto = g_socket_protocol_id_lookup_by_name (client->priv->protocol);
+  socket = g_socket_new (family,
+			 client->priv->type,
+			 proto,
+			 error);
+  if (socket == NULL)
+    return NULL;
+
+  if (client->priv->local_address)
+    {
+      if (!g_socket_bind (socket,
+			  client->priv->local_address,
+			  FALSE,
+			  error))
+	{
+	  g_object_unref (socket);
+	  return NULL;
+	}
+    }
+
+  return socket;
+}
+
+static void
+g_socket_client_init (GSocketClient *client)
+{
+  client->priv = G_TYPE_INSTANCE_GET_PRIVATE (client,
+					      G_TYPE_SOCKET_CLIENT,
+					      GSocketClientPrivate);
+  client->priv->type = G_SOCKET_TYPE_STREAM;
+}
+
+/**
+ * g_socket_client_new:
+ *
+ * Creates a new #GSocketClient with the default options.
+ *
+ * Returns: a #GSocketClient.
+ *     Free the returned object with g_object_unref().
+ *
+ * Since: 2.22
+ **/
+GSocketClient *
+g_socket_client_new (void)
+{
+  return g_object_new (G_TYPE_SOCKET_CLIENT, NULL);
+}
+
+static void
+g_socket_client_finalize (GObject *object)
+{
+  GSocketClient *client = G_SOCKET_CLIENT (object);
+
+  if (client->priv->local_address)
+    g_object_unref (client->priv->local_address);
+
+  g_free (client->priv->protocol);
+
+  if (G_OBJECT_CLASS (g_socket_client_parent_class)->finalize)
+    (*G_OBJECT_CLASS (g_socket_client_parent_class)->finalize) (object);
+}
+
+static void
+g_socket_client_get_property (GObject    *object,
+			      guint       prop_id,
+			      GValue     *value,
+			      GParamSpec *pspec)
+{
+  GSocketClient *client = G_SOCKET_CLIENT (object);
+
+  switch (prop_id)
+    {
+      case PROP_FAMILY:
+	g_value_set_enum (value, client->priv->family);
+	break;
+
+      case PROP_TYPE:
+	g_value_set_enum (value, client->priv->type);
+	break;
+
+      case PROP_PROTOCOL:
+	g_value_set_string (value, client->priv->protocol);
+	break;
+
+      case PROP_LOCAL_ADDRESS:
+	g_value_set_object (value, client->priv->local_address);
+	break;
+
+      default:
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+g_socket_client_set_property (GObject      *object,
+			      guint         prop_id,
+			      const GValue *value,
+			      GParamSpec   *pspec)
+{
+  GSocketClient *client = G_SOCKET_CLIENT (object);
+
+  switch (prop_id)
+    {
+    case PROP_FAMILY:
+      g_socket_client_set_family (client, g_value_get_enum (value));
+      break;
+
+    case PROP_TYPE:
+      g_socket_client_set_socket_type (client, g_value_get_enum (value));
+      break;
+
+    case PROP_PROTOCOL:
+      g_socket_client_set_protocol (client, g_value_get_string (value));
+      break;
+
+    case PROP_LOCAL_ADDRESS:
+      g_socket_client_set_local_address (client, g_value_get_object (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+/**
+ * g_socket_client_get_family:
+ * @socket: a #GSocket.
+ *
+ * Gets the socket family of the socket client.
+ *
+ * See g_socket_client_set_family() for details.
+ *
+ * Returns: a #GSocketFamily
+ *
+ * Since: 2.22
+ **/
+GSocketFamily
+g_socket_client_get_family (GSocketClient *client)
+{
+  return client->priv->family;
+}
+
+/**
+ * g_socket_client_set_family:
+ * @socket: a #GSocket.
+ * @family: a #GSocketFamily
+ *
+ * Sets the socket family of the socket client.
+ * If this is set to something other than %G_SOCKET_FAMILY_INVALID
+ * then the sockets created by this object will be of the specified
+ * family.
+ *
+ * This might be useful for instance if you want to force the local
+ * connection to be an ipv4 socket, even though the address might
+ * be an ipv6 mapped to ipv4 address.
+ *
+ * Since: 2.22
+ **/
+void
+g_socket_client_set_family (GSocketClient *client,
+			    GSocketFamily family)
+{
+  if (client->priv->family == family)
+    return;
+
+  client->priv->family = family;
+  g_object_notify (G_OBJECT (client), "family");
+}
+
+/**
+ * g_socket_client_get_socket_type:
+ * @socket: a #GSocket.
+ *
+ * Gets the socket type of the socket client.
+ *
+ * See g_socket_client_set_socket_type() for details.
+ *
+ * Returns: a #GSocketFamily
+ *
+ * Since: 2.22
+ **/
+GSocketType
+g_socket_client_get_socket_type (GSocketClient *client)
+{
+  return client->priv->type;
+}
+
+/**
+ * g_socket_client_set_socket_type:
+ * @socket: a #GSocket.
+ * @type: a #GSocketType
+ *
+ * Sets the socket type of the socket client.
+ * The sockets created by this object will be of the specified
+ * type.
+ *
+ * It doesn't make sense to specify a type of %G_SOCKET_TYPE_DATAGRAM,
+ * as GSocketClient is used for connection oriented services.
+ *
+ * Since: 2.22
+ **/
+void
+g_socket_client_set_socket_type (GSocketClient *client,
+				 GSocketType type)
+{
+  if (client->priv->type == type)
+    return;
+
+  client->priv->type = type;
+  g_object_notify (G_OBJECT (client), "type");
+}
+
+/**
+ * g_socket_client_get_protocol:
+ * @socket: a #GSocket.
+ *
+ * Gets the protocol name type of the socket client.
+ *
+ * See g_socket_client_set_protocol() for details.
+ *
+ * Returns: a string or %NULL. don't free
+ *
+ * Since: 2.22
+ **/
+const char *
+g_socket_client_get_protocol (GSocketClient *client)
+{
+  return client->priv->protocol;
+}
+
+/**
+ * g_socket_client_set_protocol:
+ * @socket: a #GSocket.
+ * @protocol: a string, or %NULL
+ *
+ * Sets the protocol of the socket client.
+ * The sockets created by this object will use of the specified
+ * protocol.
+ *
+ * If @protocol is %NULL that means to use the default
+ * protocol for the socket family and type.
+ *
+ * Since: 2.22
+ **/
+void
+g_socket_client_set_protocol (GSocketClient        *client,
+			      const char           *protocol)
+{
+  if (g_strcmp0 (client->priv->protocol, protocol) == 0)
+    return;
+
+  g_free (client->priv->protocol);
+  client->priv->protocol = g_strdup (protocol);
+  g_object_notify (G_OBJECT (client), "protocol");
+}
+
+/**
+ * g_socket_client_get_local_address:
+ * @socket: a #GSocket.
+ *
+ * Gets the local address of the socket client.
+ *
+ * See g_socket_client_set_local_address() for details.
+ *
+ * Returns: a #GSocketAddres or %NULL. don't free
+ *
+ * Since: 2.22
+ **/
+GSocketAddress *
+g_socket_client_get_local_address (GSocketClient *client)
+{
+  return client->priv->local_address;
+}
+
+/**
+ * g_socket_client_set_local_address:
+ * @socket: a #GSocket.
+ * @addres: a #GSocketAddress, or %NULL
+ *
+ * Sets the local address of the socket client.
+ * The sockets created by this object will bound to the
+ * specified address (if not %NULL) before connecting.
+ *
+ * This is useful if you want to ensure the the local
+ * side of the connection is on a specific port, or on
+ * a specific interface.
+ *
+ * Since: 2.22
+ **/
+void
+g_socket_client_set_local_address (GSocketClient        *client,
+				   GSocketAddress       *address)
+{
+  if (address)
+  g_object_ref (address);
+
+  if (client->priv->local_address)
+    {
+      g_object_unref (client->priv->local_address);
+    }
+  client->priv->local_address = address;
+  g_object_notify (G_OBJECT (client), "local-address");
+}
+
+static void
+g_socket_client_class_init (GSocketClientClass *class)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+
+  g_type_class_add_private (class, sizeof (GSocketClientPrivate));
+
+  gobject_class->finalize = g_socket_client_finalize;
+  gobject_class->set_property = g_socket_client_set_property;
+  gobject_class->get_property = g_socket_client_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_FAMILY,
+				   g_param_spec_enum ("family",
+						      P_("Socket family"),
+						      P_("The sockets address family to use for socket construction"),
+						      G_TYPE_SOCKET_FAMILY,
+						      G_SOCKET_FAMILY_INVALID,
+						      G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_TYPE,
+				   g_param_spec_enum ("type",
+						      P_("Socket type"),
+						      P_("The sockets type to use for socket construction"),
+						      G_TYPE_SOCKET_TYPE,
+						      G_SOCKET_TYPE_STREAM,
+						      G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_PROTOCOL,
+				   g_param_spec_string ("protocol",
+							P_("Socket protocol"),
+							P_("The protocol to use for socket construction, or %NULL for default"),
+							NULL,
+							G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_LOCAL_ADDRESS,
+				   g_param_spec_object ("local-address",
+							P_("Local address"),
+							P_("The local address constructed sockets will be bound to"),
+							G_TYPE_SOCKET_ADDRESS,
+							G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+}
+
+/**
+ * g_socket_client_connect:
+ * @client: a #GSocketClient.
+ * @connectable: a #GSocketConnectable specifying the remote address.
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @error: #GError for error reporting, or %NULL to ignore.
+ *
+ * Tries to resolve the @connectable and make a network connection to it..
+ *
+ * Upon a successful connection, a new #GSocketConnection is constructed
+ * and returned.  The caller owns this new object and must drop their
+ * reference to it when finished with it.
+ *
+ * The type of the #GSocketConnection object returned depends on the type of
+ * the underlying socket that is used. For instance, for a TCP/IP connection
+ * it will be a #GTcpConnection.
+ *
+ * The socket created will be the same family as the the address that the
+ * @connectable resolves to, unless family is set with g_socket_client_set_family()
+ * or indirectly via g_socket_client_set_local_address(). The socket type
+ * defaults to %G_SOCKET_TYPE_STREAM but can be set with
+ * g_socket_client_set_socket_type().
+ *
+ * If a local address is specified with g_socket_client_set_local_address() the
+ * socket will be bound to this address before connecting.
+ *
+ * Returns: a #GSocketConnection on success, %NULL on error.
+ *
+ * Since: 2.22
+ **/
+GSocketConnection *
+g_socket_client_connect (GSocketClient       *client,
+			 GSocketConnectable  *connectable,
+			 GCancellable        *cancellable,
+			 GError             **error)
+{
+  GSocketConnection *connection = NULL;
+  GSocketAddressEnumerator *enumerator;
+  GError *last_error, *tmp_error;
+
+  last_error = NULL;
+  enumerator = g_socket_connectable_enumerate (connectable);
+  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;
+	}
+
+      tmp_error = NULL;
+      address = g_socket_address_enumerator_next (enumerator, cancellable,
+						  &tmp_error);
+      if (address == NULL)
+	{
+	  if (tmp_error)
+	    {
+	      g_clear_error (&last_error);
+	      g_propagate_error (error, tmp_error);
+	    }
+	  else if (last_error)
+	    {
+	      g_propagate_error (error, tmp_error);
+	    }
+	  else
+	    g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+			 _("Unknown error on connect"));
+	  break;
+	}
+
+      /* clear error from previous attempt */
+      g_clear_error (&last_error);
+
+      socket = create_socket (client, address, &last_error);
+      if (socket != NULL)
+	{
+	  if (g_socket_connect (socket, address, &last_error))
+	    connection = g_socket_connection_factory_create_connection (socket);
+
+	  g_object_unref (socket);
+	}
+
+      g_object_unref (address);
+    }
+  g_object_unref (enumerator);
+
+  return connection;
+}
+
+/**
+ * g_socket_client_connect_to_host:
+ * @client: a #GTcpClient
+ * @host_and_port: the name and optionally port of the host to connect to
+ * @default_port: the default port to connect to
+ * @cancellable: a #GCancellable, or %NULL
+ * @error: a pointer to a #GError, or %NULL
+ * @returns: a #GSocketConnection if successful, or %NULL on error
+ *
+ * This is a helper function for g_socket_client_connect().
+ *
+ * Attempts to create a TCP connection to the named host.
+ *
+ * @host_and_port may be in any of a number of recognised formats: an IPv6
+ * address, an IPv4 address, or a domain name (in which case a DNS
+ * lookup is performed).  Quoting with [] is supported for all address
+ * types.  A port override may be specified in the usual way with a
+ * colon.  Ports may be given as decimal numbers or symbolic names (in
+ * which case an /etc/services lookup is performed).
+ *
+ * If no port override is given in @host_and_port then @default_port will be
+ * used as the port number to connect to.
+ *
+ * In general, @host_and_port is expected to be provided by the user (allowing
+ * them to give the hostname, and a port overide if necessary) and
+ * @default_port is expected to be provided by the application.
+
+ * In the case that an IP address is given, a single connection
+ * attempt is made.  In the case that a name is given, multiple
+ * connection attempts may be made, in turn and according to the
+ * number of address records in DNS, until a connection succeeds.
+ *
+ * Upon a successful connection, a new #GSocketConnection is constructed
+ * and returned.  The caller owns this new object and must drop their
+ * reference to it when finished with it.
+ *
+ * In the event of any failure (DNS error, service not found, no hosts
+ * connectable) %NULL is returned and @error (if non-%NULL) is set
+ * accordingly.
+ *
+ Returns: a #GSocketConnection on success, %NULL on error.
+ *
+ * Since: 2.22
+ **/
+GSocketConnection *
+g_socket_client_connect_to_host (GSocketClient        *client,
+				 const char           *host_and_port,
+				 int                   default_port,
+				 GCancellable         *cancellable,
+				 GError              **error)
+{
+  GSocketConnectable *connectable;
+  GSocketConnection *connection;
+
+  connectable = g_network_address_parse (host_and_port, default_port, error);
+  if (connectable == NULL)
+    return NULL;
+
+  connection = g_socket_client_connect (client, connectable,
+					cancellable, error);
+  g_object_unref (connectable);
+
+  return connection;
+}
+
+typedef struct
+{
+  GSimpleAsyncResult *result;
+  GCancellable *cancellable;
+  GSocketClient *client;
+
+  GSocketAddressEnumerator *enumerator;
+  GSocket *current_socket;
+
+  GError *last_error;
+} GSocketClientAsyncConnectData;
+
+static void
+g_socket_client_async_connect_complete (GSocketClientAsyncConnectData *data)
+{
+  GSocketConnection *connection;
+
+  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);
+
+      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,
+						 connection,
+						 g_object_unref);
+    }
+
+  g_simple_async_result_complete (data->result);
+  g_object_unref (data->result);
+}
+
+
+static void
+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 (GSocket *socket,
+				 GIOCondition condition,
+				 GSocketClientAsyncConnectData *data)
+{
+  GError *error = NULL;
+
+  if (g_cancellable_is_cancelled (data->cancellable))
+    {
+      /* 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);
+    }
+  else
+    {
+      /* socket is ready for writing means connect done, did it succeed? */
+      if (!g_socket_check_pending_error (data->current_socket, &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);
+
+	  return FALSE;
+	}
+    }
+
+  g_socket_client_async_connect_complete (data);
+
+  return FALSE;
+}
+
+static void
+g_socket_client_enumerator_callback (GObject      *object,
+				     GAsyncResult *result,
+				     gpointer      user_data)
+{
+  GSocketClientAsyncConnectData *data = user_data;
+  GSocketAddress *address;
+  GSocket *socket;
+  GError *tmp_error = NULL;
+
+  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;
+    }
+
+  address = g_socket_address_enumerator_next_finish (data->enumerator,
+						     result, &tmp_error);
+
+  if (address == NULL)
+    {
+      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;
+    }
+
+  g_clear_error (&data->last_error);
+
+  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))
+	{
+	  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;
+
+	  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);
+	  g_source_unref (source);
+
+	  g_object_unref (address);
+	  return;
+	}
+      else
+	{
+	  data->last_error = tmp_error;
+	  g_object_unref (socket);
+	}
+      g_object_unref (address);
+    }
+
+  g_socket_address_enumerator_next_async (data->enumerator,
+					  data->cancellable,
+					  g_socket_client_enumerator_callback,
+					  data);
+}
+
+/**
+ * g_socket_client_connect_to_host_async:
+ * @client: a #GTcpClient
+ * @connectable: a #GSocketConnectable specifying the remote address.
+ * @cancellable: a #GCancellable, or %NULL
+ * @callback: a #GAsyncReadyCallback
+ * @user_data: user data for the callback
+ *
+ * This is the asynchronous version of g_socket_client_connect().
+ *
+ * When the operation is finished @callback will be
+ * called. You can then call g_socket_client_connect_finish() to get
+ * the result of the operation.
+ *
+ * Since: 2.22
+ **/
+void
+g_socket_client_connect_async (GSocketClient       *client,
+			       GSocketConnectable  *connectable,
+			       GCancellable        *cancellable,
+			       GAsyncReadyCallback  callback,
+			       gpointer             user_data)
+{
+  GSocketClientAsyncConnectData *data;
+
+  g_return_if_fail (G_IS_SOCKET_CLIENT (client));
+
+  data = g_slice_new (GSocketClientAsyncConnectData);
+
+  data->result = g_simple_async_result_new (G_OBJECT (client),
+					    callback, user_data,
+					    g_socket_client_connect_async);
+  data->client = client;
+  if (cancellable)
+    data->cancellable = g_object_ref (cancellable);
+  else
+    data->cancellable = NULL;
+  data->last_error = NULL;
+  data->enumerator = g_socket_connectable_enumerate (connectable);
+
+  g_socket_address_enumerator_next_async (data->enumerator, cancellable,
+					  g_socket_client_enumerator_callback,
+					  data);
+}
+
+/**
+ * g_socket_client_connect_to_host_async:
+ * @client: a #GTcpClient
+ * @host_and_port: the name and optionally the port of the host to connect to
+ * @default_port: the default port to connect to
+ * @cancellable: a #GCancellable, or %NULL
+ * @callback: a #GAsyncReadyCallback
+ * @user_data: user data for the callback
+ *
+ * This is the asynchronous version of g_socket_client_connect_to_host().
+ *
+ * When the operation is finished @callback will be
+ * called. You can then call g_socket_client_connect_to_host_finish() to get
+ * the result of the operation.
+ *
+ * Since: 2.22
+ **/
+void
+g_socket_client_connect_to_host_async (GSocketClient        *client,
+				       const char           *host_and_port,
+				       int                   default_port,
+				       GCancellable         *cancellable,
+				       GAsyncReadyCallback   callback,
+				       gpointer              user_data)
+{
+  GSocketConnectable *connectable;
+  GError *error;
+
+  error = NULL;
+  connectable = g_network_address_parse (host_and_port, default_port,
+					 &error);
+  if (connectable == NULL)
+    {
+      g_simple_async_report_gerror_in_idle (G_OBJECT (client),
+					    callback, user_data, error);
+      g_error_free (error);
+    }
+  else
+    {
+      g_socket_client_connect_async (client,
+				     connectable, cancellable,
+				     callback, user_data);
+      g_object_unref (connectable);
+    }
+}
+
+/**
+ * g_socket_client_connect_finish:
+ * @client: a #GSocketClient.
+ * @result: a #GAsyncResult.
+ * @error: a #GError location to store the error occuring, or %NULL to
+ * ignore.
+ *
+ * Finishes an async connect operation. See g_socket_client_connect_async()
+ *
+ * Returns: a #GSocketConnection on success, %NULL on error.
+ *
+ * Since: 2.22
+ **/
+GSocketConnection *
+g_socket_client_connect_finish (GSocketClient  *client,
+				GAsyncResult   *result,
+				GError        **error)
+{
+  GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
+
+  if (g_simple_async_result_propagate_error (simple, error))
+    return NULL;
+
+  return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
+}
+
+/**
+ * g_socket_client_connect_to_host_finish:
+ * @client: a #GSocketClient.
+ * @result: a #GAsyncResult.
+ * @error: a #GError location to store the error occuring, or %NULL to
+ * ignore.
+ *
+ * Finishes an async connect operation. See g_socket_client_connect_to_host_async()
+ *
+ * Returns: a #GSocketConnection on success, %NULL on error.
+ *
+ * Since: 2.22
+ **/
+GSocketConnection *
+g_socket_client_connect_to_host_finish (GSocketClient        *client,
+					GAsyncResult         *result,
+					GError              **error)
+{
+  return g_socket_client_connect_finish (client, result, error);
+}
+
+#define __G_SOCKET_CLIENT_C__
+#include "gioaliasdef.c"
diff --git a/gio/gsocketclient.h b/gio/gsocketclient.h
new file mode 100644
index 0000000..d8259b3
--- /dev/null
+++ b/gio/gsocketclient.h
@@ -0,0 +1,115 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright © 2008, 2009 Codethink Limited
+ * Copyright © 2009 Red Hat, Inc
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the licence or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Ryan Lortie <desrt desrt ca>
+ *          Alexander Larsson <alexl redhat com>
+ */
+
+#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
+#error "Only <gio/gio.h> can be included directly."
+#endif
+
+#ifndef __G_SOCKET_CLIENT_H__
+#define __G_SOCKET_CLIENT_H__
+
+#include <gio/giotypes.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_SOCKET_CLIENT                                (g_socket_client_get_type ())
+#define G_SOCKET_CLIENT(inst)                               (G_TYPE_CHECK_INSTANCE_CAST ((inst),                     \
+                                                             G_TYPE_SOCKET_CLIENT, GSocketClient))
+#define G_SOCKET_CLIENT_CLASS(class)                        (G_TYPE_CHECK_CLASS_CAST ((class),                       \
+                                                             G_TYPE_SOCKET_CLIENT, GSocketClientClass))
+#define G_IS_SOCKET_CLIENT(inst)                            (G_TYPE_CHECK_INSTANCE_TYPE ((inst),                     \
+                                                             G_TYPE_SOCKET_CLIENT))
+#define G_IS_SOCKET_CLIENT_CLASS(class)                     (G_TYPE_CHECK_CLASS_TYPE ((class),                       \
+                                                             G_TYPE_SOCKET_CLIENT))
+#define G_SOCKET_CLIENT_GET_CLASS(inst)                     (G_TYPE_INSTANCE_GET_CLASS ((inst),                      \
+                                                             G_TYPE_SOCKET_CLIENT, GSocketClientClass))
+
+typedef struct _GSocketClientPrivate                        GSocketClientPrivate;
+typedef struct _GSocketClientClass                          GSocketClientClass;
+
+struct _GSocketClientClass
+{
+  GObjectClass parent_class;
+
+  /* Padding for future expansion */
+  void (*_g_reserved1) (void);
+  void (*_g_reserved2) (void);
+  void (*_g_reserved3) (void);
+  void (*_g_reserved4) (void);
+  void (*_g_reserved5) (void);
+};
+
+struct _GSocketClient
+{
+  GObject parent_instance;
+  GSocketClientPrivate *priv;
+};
+
+GType                   g_socket_client_get_type                        (void) G_GNUC_CONST;
+
+GSocketClient          *g_socket_client_new                             (void);
+
+GSocketFamily           g_socket_client_get_family                      (GSocketClient        *client);
+void                    g_socket_client_set_family                      (GSocketClient        *client,
+									 GSocketFamily         family);
+GSocketType             g_socket_client_get_socket_type                 (GSocketClient        *client);
+void                    g_socket_client_set_socket_type                 (GSocketClient        *client,
+									 GSocketType           type);
+const char             *g_socket_client_get_protocol                    (GSocketClient        *client);
+void                    g_socket_client_set_protocol                    (GSocketClient        *client,
+									 const char           *protocol);
+GSocketAddress         *g_socket_client_get_local_address               (GSocketClient        *client);
+void                    g_socket_client_set_local_address               (GSocketClient        *client,
+									 GSocketAddress       *address);
+
+GSocketConnection *     g_socket_client_connect                         (GSocketClient        *client,
+                                                                         GSocketConnectable   *connectable,
+                                                                         GCancellable         *cancellable,
+                                                                         GError              **error);
+GSocketConnection *     g_socket_client_connect_to_host                 (GSocketClient        *client,
+									 const char           *hostname,
+									 int                   port,
+                                                                         GCancellable         *cancellable,
+                                                                         GError              **error);
+void                    g_socket_client_connect_async                   (GSocketClient        *client,
+                                                                         GSocketConnectable   *connectable,
+                                                                         GCancellable         *cancellable,
+                                                                         GAsyncReadyCallback   callback,
+                                                                         gpointer              user_data);
+GSocketConnection *     g_socket_client_connect_finish                  (GSocketClient        *client,
+                                                                         GAsyncResult         *result,
+                                                                         GError              **error);
+void                    g_socket_client_connect_to_host_async           (GSocketClient        *client,
+									 const char           *hostname,
+									 int                   port,
+                                                                         GCancellable         *cancellable,
+                                                                         GAsyncReadyCallback   callback,
+                                                                         gpointer              user_data);
+GSocketConnection *     g_socket_client_connect_to_host_finish          (GSocketClient        *client,
+                                                                         GAsyncResult         *result,
+                                                                         GError              **error);
+
+G_END_DECLS
+
+#endif /* __G_SOCKET_CLIENT_H___ */
diff --git a/gio/gsocketconnection.c b/gio/gsocketconnection.c
new file mode 100644
index 0000000..878a282
--- /dev/null
+++ b/gio/gsocketconnection.c
@@ -0,0 +1,474 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright © 2008 Christian Kellner, Samuel Cormier-Iijima
+ *           © 2008 codethink
+ * Copyright © 2009 Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Christian Kellner <gicmo gnome org>
+ *          Samuel Cormier-Iijima <sciyoshi gmail com>
+ *          Ryan Lortie <desrt desrt ca>
+ *          Alexander Larsson <alexl redhat com>
+ */
+
+#include "config.h"
+
+#include "gsocketconnection.h"
+
+#include "gsocketoutputstream.h"
+#include "gsocketinputstream.h"
+#include <gio/giostream.h>
+#include <gio/gsimpleasyncresult.h>
+#include "gunixconnection.h"
+#include "gtcpconnection.h"
+#include "glibintl.h"
+
+#include "gioalias.h"
+
+/**
+ * SECTION:gsocketconnection
+ * @short_description: High-level socket connection stream
+ * @include: gio/gio.h
+ * @see_also: #GIOStream, #GSocketClient, #GSocketListener
+ *
+ * #GSocketConnection is a #GIOStream for a connected socket. They
+ * can be created either by #GSocketClient when connecting to a host,
+ * or by #GSocketListener when accepting a new client.
+ *
+ * The type of the #GSocketConnection object returned from these calls depends
+ * on the type of the underlying socket that is in use. For instance, for a
+ * TCP/IP connection it will be a #GTcpConnection.
+ *
+ * Chosing what type of object to construct is done with the socket connection
+ * factory, and it is possible for 3rd parties to register custom socket connection
+ * types for specific combination of socket family/type/protocol using
+ * g_socket_connection_factory_register_type().
+ *
+ * Since: 2.22
+ **/
+
+G_DEFINE_TYPE (GSocketConnection,
+	       g_socket_connection, G_TYPE_IO_STREAM);
+
+enum
+{
+  PROP_NONE,
+  PROP_SOCKET,
+};
+
+struct _GSocketConnectionPrivate
+{
+  GSocket       *socket;
+  GInputStream  *input_stream;
+  GOutputStream *output_stream;
+};
+
+static gboolean g_socket_connection_close         (GIOStream            *stream,
+						   GCancellable         *cancellable,
+						   GError              **error);
+static void     g_socket_connection_close_async   (GIOStream            *stream,
+						   int                   io_priority,
+						   GCancellable         *cancellable,
+						   GAsyncReadyCallback   callback,
+						   gpointer              user_data);
+static gboolean g_socket_connection_close_finish  (GIOStream            *stream,
+						   GAsyncResult         *result,
+						   GError              **error);
+
+static GInputStream *
+g_socket_connection_get_input_stream (GIOStream *io_stream)
+{
+  GSocketConnection *connection = G_SOCKET_CONNECTION (io_stream);
+
+  if (connection->priv->input_stream == NULL)
+    connection->priv->input_stream = (GInputStream *)
+      _g_socket_input_stream_new (connection->priv->socket);
+
+  return connection->priv->input_stream;
+}
+
+static GOutputStream *
+g_socket_connection_get_output_stream (GIOStream *io_stream)
+{
+  GSocketConnection *connection = G_SOCKET_CONNECTION (io_stream);
+
+  if (connection->priv->output_stream == NULL)
+    connection->priv->output_stream = (GOutputStream *)
+      _g_socket_output_stream_new (connection->priv->socket);
+
+  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;
+}
+
+/**
+ * g_socket_connection_get_local_address:
+ * @connection: a #GSocketConnection.
+ * @error: #GError for error reporting, or %NULL to ignore.
+ *
+ * Try to get the local address of a socket connection.
+ *
+ * Returns: a #GSocketAddress or %NULL on error.
+ *
+ * Since: 2.22
+ **/
+GSocketAddress *
+g_socket_connection_get_local_address (GSocketConnection  *connection,
+				       GError  **error)
+{
+  return g_socket_get_local_address (connection->priv->socket, error);
+}
+
+/**
+ * g_socket_connection_get_remote_address:
+ * @connection: a #GSocketConnection.
+ * @error: #GError for error reporting, or %NULL to ignore.
+ *
+ * Try to get the remove address of a socket connection.
+ *
+ * Returns: a #GSocketAddress or %NULL on error.
+ *
+ * Since: 2.22
+ **/
+GSocketAddress *
+g_socket_connection_get_remote_address (GSocketConnection  *connection,
+					GError  **error)
+{
+  return g_socket_get_remote_address (connection->priv->socket, error);
+}
+
+static void
+g_socket_connection_get_property (GObject *object, guint prop_id,
+                                  GValue *value, GParamSpec *pspec)
+{
+  GSocketConnection *connection = G_SOCKET_CONNECTION (object);
+
+  switch (prop_id)
+    {
+     case PROP_SOCKET:
+      g_value_set_object (value, connection->priv->socket);
+      break;
+
+     default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+g_socket_connection_set_property (GObject *object, guint prop_id,
+                                  const GValue *value, GParamSpec *pspec)
+{
+  GSocketConnection *connection = G_SOCKET_CONNECTION (object);
+
+  switch (prop_id)
+    {
+     case PROP_SOCKET:
+      connection->priv->socket = G_SOCKET (g_value_dup_object (value));
+      break;
+
+     default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+g_socket_connection_constructed (GObject *object)
+{
+  GSocketConnection *connection = G_SOCKET_CONNECTION (object);
+
+  g_assert (connection->priv->socket != NULL);
+}
+
+static void
+g_socket_connection_finalize (GObject *object)
+{
+  GSocketConnection *connection = G_SOCKET_CONNECTION (object);
+
+  if (connection->priv->input_stream)
+    g_object_unref (connection->priv->input_stream);
+
+  if (connection->priv->output_stream)
+    g_object_unref (connection->priv->output_stream);
+
+  g_object_unref (connection->priv->socket);
+
+  G_OBJECT_CLASS (g_socket_connection_parent_class)
+    ->finalize (object);
+}
+
+static void
+g_socket_connection_class_init (GSocketConnectionClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GIOStreamClass *stream_class = G_IO_STREAM_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (GSocketConnectionPrivate));
+
+  gobject_class->set_property = g_socket_connection_set_property;
+  gobject_class->get_property = g_socket_connection_get_property;
+  gobject_class->constructed = g_socket_connection_constructed;
+  gobject_class->finalize = g_socket_connection_finalize;
+
+  stream_class->get_input_stream = g_socket_connection_get_input_stream;
+  stream_class->get_output_stream = g_socket_connection_get_output_stream;
+  stream_class->close_fn = g_socket_connection_close;
+  stream_class->close_async = g_socket_connection_close_async;
+  stream_class->close_finish = g_socket_connection_close_finish;
+
+  g_object_class_install_property (gobject_class, PROP_SOCKET,
+    g_param_spec_object ("socket",
+			 P_("Socket"),
+			 P_("The underlying GSocket"),
+                         G_TYPE_SOCKET, G_PARAM_CONSTRUCT_ONLY |
+                         G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+g_socket_connection_init (GSocketConnection *connection)
+{
+  connection->priv = G_TYPE_INSTANCE_GET_PRIVATE (connection,
+                                                  G_TYPE_SOCKET_CONNECTION,
+                                                  GSocketConnectionPrivate);
+}
+
+static gboolean
+g_socket_connection_close (GIOStream            *stream,
+			   GCancellable         *cancellable,
+			   GError              **error)
+{
+  GSocketConnection *connection = G_SOCKET_CONNECTION (stream);
+
+  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_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)
+{
+  return TRUE;
+}
+
+typedef struct {
+  GSocketFamily socket_family;
+  GSocketType socket_type;
+  int 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) ^ (factory->protocol << 8);
+  /* This is likely to be small, so spread over whole
+     hash space to get some distribution */
+  h = h ^ (h << 8) ^ (h << 16) ^ (h << 24);
+
+  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)
+    return FALSE;
+
+  return TRUE;
+}
+
+static GHashTable *connection_factories = NULL;
+G_LOCK_DEFINE_STATIC(connection_factories);
+
+/**
+ * g_socket_connection_factory_register_type:
+ * @g_type: a #GType, inheriting from G_SOCKET_CONNECTION
+ * @family: a #GSocketFamily.
+ * @type: a #GSocketType
+ * @protocol: a protocol id
+ *
+ * Looks up the #GType to be used when creating socket connections on
+ * sockets with the specified @family,@type and @protocol_id.
+ *
+ * If no type is registered, the #GSocketConnection base type is returned.
+ *
+ * Returns: a #GType
+ * Since: 2.22
+ **/
+void
+g_socket_connection_factory_register_type (GType g_type,
+					   GSocketFamily family,
+					   GSocketType type,
+					   gint protocol)
+{
+  ConnectionFactory *factory;
+
+  g_return_if_fail (g_type_is_a (g_type, G_TYPE_SOCKET_CONNECTION));
+
+  G_LOCK (connection_factories);
+
+  if (connection_factories == NULL)
+    connection_factories = g_hash_table_new_full (connection_factory_hash,
+						  connection_factory_equal,
+						  (GDestroyNotify)g_free,
+						  NULL);
+
+  factory = g_new0 (ConnectionFactory, 1);
+  factory->socket_family = family;
+  factory->socket_type = type;
+  factory->protocol = 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 ();
+}
+
+/**
+ * g_socket_connection_factory_lookup_type:
+ * @family: a #GSocketFamily.
+ * @type: a #GSocketType
+ * @protocol_id: a protocol id
+ *
+ * Looks up the #GType to be used when creating socket connections on
+ * sockets with the specified @family,@type and @protocol_id.
+ *
+ * If no type is registered, the #GSocketConnection base type is returned.
+ *
+ * Returns: a #GType
+ * Since: 2.22
+ **/
+GType
+g_socket_connection_factory_lookup_type (GSocketFamily family,
+					 GSocketType type,
+					 gint protocol_id)
+{
+  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 = protocol_id;
+
+      factory = g_hash_table_lookup (connection_factories, &key);
+      if (factory)
+	g_type = factory->implementation;
+    }
+
+  G_UNLOCK (connection_factories);
+
+  return g_type;
+}
+
+/**
+ * g_socket_connection_factory_create_connection:
+ * @socket: a #GSocket.
+ *
+ * Creates a #GSocketConnection subclass of the right type for
+ * @socket.
+ *
+ * Returns: a #GSocketConnection
+ *
+ * Since: 2.22
+ **/
+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_id (socket));
+  return g_object_new (type, "socket", socket, NULL);
+}
+
+#define __G_SOCKET_CONNECTION_C__
+#include "gioaliasdef.c"
diff --git a/gio/gsocketconnection.h b/gio/gsocketconnection.h
new file mode 100644
index 0000000..df37c91
--- /dev/null
+++ b/gio/gsocketconnection.h
@@ -0,0 +1,91 @@
+/* GIO - GLib Input, Output and Streaming Library
+ * Copyright © 2008 Christian Kellner, Samuel Cormier-Iijima
+ * Copyright © 2009 Codethink Limited
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the licence or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Christian Kellner <gicmo gnome org>
+ *          Samuel Cormier-Iijima <sciyoshi gmail com>
+ *          Ryan Lortie <desrt desrt ca>
+ *          Alexander Larsson <alexl redhat com>
+ */
+
+#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
+#error "Only <gio/gio.h> can be included directly."
+#endif
+
+#ifndef __G_SOCKET_CONNECTION_H__
+#define __G_SOCKET_CONNECTION_H__
+
+#include <glib-object.h>
+#include <gio/gsocket.h>
+#include <gio/giostream.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_SOCKET_CONNECTION                            (g_socket_connection_get_type ())
+#define G_SOCKET_CONNECTION(inst)                           (G_TYPE_CHECK_INSTANCE_CAST ((inst),                     \
+                                                             G_TYPE_SOCKET_CONNECTION, GSocketConnection))
+#define G_SOCKET_CONNECTION_CLASS(class)                    (G_TYPE_CHECK_CLASS_CAST ((class),                       \
+                                                             G_TYPE_SOCKET_CONNECTION, GSocketConnectionClass))
+#define G_IS_SOCKET_CONNECTION(inst)                        (G_TYPE_CHECK_INSTANCE_TYPE ((inst),                     \
+                                                             G_TYPE_SOCKET_CONNECTION))
+#define G_IS_SOCKET_CONNECTION_CLASS(class)                 (G_TYPE_CHECK_CLASS_TYPE ((class),                       \
+                                                             G_TYPE_SOCKET_CONNECTION))
+#define G_SOCKET_CONNECTION_GET_CLASS(inst)                 (G_TYPE_INSTANCE_GET_CLASS ((inst),                      \
+                                                             G_TYPE_SOCKET_CONNECTION, GSocketConnectionClass))
+
+typedef struct _GSocketConnectionPrivate                    GSocketConnectionPrivate;
+typedef struct _GSocketConnectionClass                      GSocketConnectionClass;
+
+struct _GSocketConnectionClass
+{
+  GIOStreamClass parent_class;
+
+  /* Padding for future expansion */
+  void (*_g_reserved1) (void);
+  void (*_g_reserved2) (void);
+  void (*_g_reserved3) (void);
+  void (*_g_reserved4) (void);
+  void (*_g_reserved5) (void);
+  void (*_g_reserved6) (void);
+};
+
+struct _GSocketConnection
+{
+  GIOStream parent_instance;
+  GSocketConnectionPrivate *priv;
+};
+
+GType              g_socket_connection_get_type                  (void) G_GNUC_CONST;
+
+GSocket           *g_socket_connection_get_socket                (GSocketConnection *connection);
+GSocketAddress    *g_socket_connection_get_local_address         (GSocketConnection *connection,
+								  GError                 **error);
+GSocketAddress    *g_socket_connection_get_remote_address        (GSocketConnection *connection,
+								  GError                 **error);
+void               g_socket_connection_factory_register_type     (GType          g_type,
+								  GSocketFamily  family,
+								  GSocketType    type,
+								  gint           protocol);
+GType              g_socket_connection_factory_lookup_type       (GSocketFamily  family,
+								  GSocketType    type,
+								  gint           protocol);
+GSocketConnection *g_socket_connection_factory_create_connection (GSocket       *socket);
+
+G_END_DECLS
+
+#endif /* __G_SOCKET_CONNECTION_H__ */
diff --git a/gio/gsocketinputstream.c b/gio/gsocketinputstream.c
new file mode 100644
index 0000000..e24ef02
--- /dev/null
+++ b/gio/gsocketinputstream.c
@@ -0,0 +1,259 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright © 2008 Christian Kellner, Samuel Cormier-Iijima
+ *           © 2009 codethink
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Christian Kellner <gicmo gnome org>
+ *          Samuel Cormier-Iijima <sciyoshi gmail com>
+ *          Ryan Lortie <desrt desrt ca>
+ */
+
+#include "config.h"
+#include "gsocketinputstream.h"
+#include "glibintl.h"
+
+#include <gio/gsimpleasyncresult.h>
+#include <gio/gcancellable.h>
+
+#define g_socket_input_stream_get_type _g_socket_input_stream_get_type
+G_DEFINE_TYPE (GSocketInputStream, g_socket_input_stream, G_TYPE_INPUT_STREAM);
+
+enum
+{
+  PROP_0,
+  PROP_SOCKET
+};
+
+struct _GSocketInputStreamPrivate
+{
+  GSocket *socket;
+
+  /* pending operation metadata */
+  GSimpleAsyncResult *result;
+  GCancellable *cancellable;
+  gboolean from_mainloop;
+  gpointer buffer;
+  gsize count;
+};
+
+static void
+g_socket_input_stream_get_property (GObject    *object,
+                                    guint       prop_id,
+                                    GValue     *value,
+                                    GParamSpec *pspec)
+{
+  GSocketInputStream *stream = G_SOCKET_INPUT_STREAM (object);
+
+  switch (prop_id)
+    {
+      case PROP_SOCKET:
+        g_value_set_object (value, stream->priv->socket);
+        break;
+
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+g_socket_input_stream_set_property (GObject      *object,
+                                    guint         prop_id,
+                                    const GValue *value,
+                                    GParamSpec   *pspec)
+{
+  GSocketInputStream *stream = G_SOCKET_INPUT_STREAM (object);
+
+  switch (prop_id)
+    {
+      case PROP_SOCKET:
+        stream->priv->socket = g_value_dup_object (value);
+        break;
+
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+g_socket_input_stream_finalize (GObject *object)
+{
+  GSocketInputStream *stream = G_SOCKET_INPUT_STREAM (object);
+
+  if (stream->priv->socket)
+    g_object_unref (stream->priv->socket);
+
+  if (G_OBJECT_CLASS (g_socket_input_stream_parent_class)->finalize)
+    (*G_OBJECT_CLASS (g_socket_input_stream_parent_class)->finalize) (object);
+}
+
+static gssize
+g_socket_input_stream_read (GInputStream  *stream,
+                            void          *buffer,
+                            gsize          count,
+                            GCancellable  *cancellable,
+                            GError       **error)
+{
+  GSocketInputStream *input_stream = G_SOCKET_INPUT_STREAM (stream);
+
+  if (!g_socket_condition_wait (input_stream->priv->socket,
+                                G_IO_IN, cancellable, error))
+    return -1;
+
+  return g_socket_receive (input_stream->priv->socket, buffer, count, error);
+}
+
+static gboolean
+g_socket_input_stream_read_ready (GSocket *socket,
+                                  GIOCondition condition,
+				  GSocketInputStream *stream)
+{
+  GSimpleAsyncResult *simple;
+  GError *error = NULL;
+
+  simple = stream->priv->result;
+  stream->priv->result = NULL;
+
+  if (!g_cancellable_set_error_if_cancelled (stream->priv->cancellable,
+                                             &error))
+    {
+      gssize result;
+
+      result = g_socket_receive (stream->priv->socket,
+                                 stream->priv->buffer,
+                                 stream->priv->count,
+                                 &error);
+      if (result >= 0)
+        g_simple_async_result_set_op_res_gssize (simple, result);
+    }
+
+  if (error)
+    {
+      g_simple_async_result_set_from_error (simple, error);
+      g_error_free (error);
+    }
+
+  if (stream->priv->cancellable)
+    g_object_unref (stream->priv->cancellable);
+
+  if (stream->priv->from_mainloop)
+    g_simple_async_result_complete (simple);
+  else
+    g_simple_async_result_complete_in_idle (simple);
+
+  g_object_unref (simple);
+
+  return FALSE;
+}
+
+static void
+g_socket_input_stream_read_async (GInputStream        *stream,
+                                  void                *buffer,
+                                  gsize                count,
+                                  gint                 io_priority,
+                                  GCancellable        *cancellable,
+                                  GAsyncReadyCallback  callback,
+                                  gpointer             user_data)
+{
+  GSocketInputStream *input_stream = G_SOCKET_INPUT_STREAM (stream);
+
+  g_assert (input_stream->priv->result == NULL);
+
+  input_stream->priv->result =
+    g_simple_async_result_new (G_OBJECT (stream), callback, user_data,
+                               g_socket_input_stream_read_async);
+  if (cancellable)
+    g_object_ref (cancellable);
+  input_stream->priv->cancellable = cancellable;
+  input_stream->priv->buffer = buffer;
+  input_stream->priv->count = count;
+
+  if (!g_socket_condition_check (input_stream->priv->socket, G_IO_IN))
+    {
+      GSource *source;
+
+      input_stream->priv->from_mainloop = TRUE;
+      source = g_socket_create_source (input_stream->priv->socket,
+                                       G_IO_IN | G_IO_HUP | G_IO_ERR,
+                                       cancellable);
+      g_source_set_callback (source,
+                             (GSourceFunc) g_socket_input_stream_read_ready,
+                             g_object_ref (input_stream), g_object_unref);
+      g_source_attach (source, NULL);
+      g_source_unref (source);
+    }
+  else
+    {
+      input_stream->priv->from_mainloop = FALSE;
+      g_socket_input_stream_read_ready (input_stream->priv->socket, G_IO_IN, input_stream);
+    }
+}
+
+static gssize
+g_socket_input_stream_read_finish (GInputStream  *stream,
+                                   GAsyncResult  *result,
+                                   GError       **error)
+{
+  GSimpleAsyncResult *simple;
+  gssize count;
+
+  g_return_val_if_fail (G_IS_SOCKET_INPUT_STREAM (stream), -1);
+
+  simple = G_SIMPLE_ASYNC_RESULT (result);
+
+  g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_socket_input_stream_read_async);
+
+  count = g_simple_async_result_get_op_res_gssize (simple);
+
+  return count;
+}
+
+static void
+g_socket_input_stream_class_init (GSocketInputStreamClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GInputStreamClass *ginputstream_class = G_INPUT_STREAM_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (GSocketInputStreamPrivate));
+
+  gobject_class->finalize = g_socket_input_stream_finalize;
+  gobject_class->get_property = g_socket_input_stream_get_property;
+  gobject_class->set_property = g_socket_input_stream_set_property;
+
+  ginputstream_class->read_fn = g_socket_input_stream_read;
+  ginputstream_class->read_async = g_socket_input_stream_read_async;
+  ginputstream_class->read_finish = g_socket_input_stream_read_finish;
+
+  g_object_class_install_property (gobject_class, PROP_SOCKET,
+				   g_param_spec_object ("socket",
+							P_("socket"),
+							P_("The socket that this stream wraps"),
+							G_TYPE_SOCKET, G_PARAM_CONSTRUCT_ONLY |
+							G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+g_socket_input_stream_init (GSocketInputStream *stream)
+{
+  stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream, G_TYPE_SOCKET_INPUT_STREAM, GSocketInputStreamPrivate);
+}
+
+GSocketInputStream *
+_g_socket_input_stream_new (GSocket *socket)
+{
+  return G_SOCKET_INPUT_STREAM (g_object_new (G_TYPE_SOCKET_INPUT_STREAM, "socket", socket, NULL));
+}
diff --git a/gio/gsocketinputstream.h b/gio/gsocketinputstream.h
new file mode 100644
index 0000000..8e5776f
--- /dev/null
+++ b/gio/gsocketinputstream.h
@@ -0,0 +1,58 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright © 2008 Christian Kellner, Samuel Cormier-Iijima
+ * Copyright © 2009 Codethink Limited
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the licence or (at
+ * your option) any later version.
+ *
+ * See the included COPYING file for more information.
+ *
+ * Authors: Christian Kellner <gicmo gnome org>
+ *          Samuel Cormier-Iijima <sciyoshi gmail com>
+ *          Ryan Lortie <desrt desrt ca>
+ */
+
+#ifndef __G_SOCKET_INPUT_STREAM_H__
+#define __G_SOCKET_INPUT_STREAM_H__
+
+#include <gio/ginputstream.h>
+#include <gio/gsocket.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_SOCKET_INPUT_STREAM                          (_g_socket_input_stream_get_type ())
+#define G_SOCKET_INPUT_STREAM(inst)                         (G_TYPE_CHECK_INSTANCE_CAST ((inst),                     \
+                                                             G_TYPE_SOCKET_INPUT_STREAM, GSocketInputStream))
+#define G_SOCKET_INPUT_STREAM_CLASS(class)                  (G_TYPE_CHECK_CLASS_CAST ((class),                       \
+                                                             G_TYPE_SOCKET_INPUT_STREAM, GSocketInputStreamClass))
+#define G_IS_SOCKET_INPUT_STREAM(inst)                      (G_TYPE_CHECK_INSTANCE_TYPE ((inst),                     \
+                                                             G_TYPE_SOCKET_INPUT_STREAM))
+#define G_IS_SOCKET_INPUT_STREAM_CLASS(class)               (G_TYPE_CHECK_CLASS_TYPE ((class),                       \
+                                                             G_TYPE_SOCKET_INPUT_STREAM))
+#define G_SOCKET_INPUT_STREAM_GET_CLASS(inst)               (G_TYPE_INSTANCE_GET_CLASS ((inst),                      \
+                                                             G_TYPE_SOCKET_INPUT_STREAM, GSocketInputStreamClass))
+
+typedef struct _GSocketInputStreamPrivate                   GSocketInputStreamPrivate;
+typedef struct _GSocketInputStreamClass                     GSocketInputStreamClass;
+typedef struct _GSocketInputStream                          GSocketInputStream;
+
+struct _GSocketInputStreamClass
+{
+  GInputStreamClass parent_class;
+};
+
+struct _GSocketInputStream
+{
+  GInputStream parent_instance;
+  GSocketInputStreamPrivate *priv;
+};
+
+GType                   _g_socket_input_stream_get_type                  (void) G_GNUC_CONST;
+GSocketInputStream *    _g_socket_input_stream_new                      (GSocket *socket);
+
+G_END_DECLS
+
+#endif /* __G_SOCKET_INPUT_STREAM_H___ */
diff --git a/gio/gsocketlistener.c b/gio/gsocketlistener.c
new file mode 100644
index 0000000..228d914
--- /dev/null
+++ b/gio/gsocketlistener.c
@@ -0,0 +1,815 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright © 2008 Christian Kellner, Samuel Cormier-Iijima
+ * Copyright © 2009 codethink
+ * Copyright © 2009 Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Christian Kellner <gicmo gnome org>
+ *          Samuel Cormier-Iijima <sciyoshi gmail com>
+ *          Ryan Lortie <desrt desrt ca>
+ *          Alexander Larsson <alexl redhat com>
+ */
+
+#include "config.h"
+#include "gsocketlistener.h"
+
+#include <gio/gsimpleasyncresult.h>
+#include <gio/gcancellable.h>
+#include <gio/gsocketaddress.h>
+#include <gio/ginetaddress.h>
+#include <gio/gioerror.h>
+#include <gio/gsocket.h>
+#include <gio/gsocketconnection.h>
+#include <gio/ginetsocketaddress.h>
+#include "glibintl.h"
+
+#include "gioalias.h"
+
+/**
+ * SECTION: gsocketlistener
+ * @title: GSocketListener
+ * @short_description: a high-level helper object for server sockets
+ * @see_also: #GThreadedSocketService, #GSocketService.
+ *
+ * A #GSocketListener is an object that keeps track of a set
+ * of server sockets and helps you accept sockets from any of the
+ * socket, either sync or async.
+ *
+ * If you want to implement a network server, also look at #GSocketService
+ * and #GThreadedSocketService which are subclass of #GSocketListener
+ * that makes this even easier.
+ *
+ * Since: 2.22
+ */
+
+G_DEFINE_TYPE (GSocketListener, g_socket_listener, G_TYPE_OBJECT);
+
+enum
+{
+  PROP_0,
+  PROP_LISTEN_BACKLOG
+};
+
+
+static GQuark source_quark = 0;
+
+struct _GSocketListenerPrivate
+{
+  GPtrArray           *sockets;
+  GMainContext        *main_context;
+  int                 listen_backlog;
+  guint               closed : 1;
+};
+
+static void
+g_socket_listener_finalize (GObject *object)
+{
+  GSocketListener *listener = G_SOCKET_LISTENER (object);
+
+  if (listener->priv->main_context)
+    g_main_context_unref (listener->priv->main_context);
+
+  if (!listener->priv->closed)
+    g_socket_listener_close (listener);
+
+  g_ptr_array_free (listener->priv->sockets, TRUE);
+
+  G_OBJECT_CLASS (g_socket_listener_parent_class)
+    ->finalize (object);
+}
+
+static void
+g_socket_listener_get_property (GObject    *object,
+				guint       prop_id,
+				GValue     *value,
+				GParamSpec *pspec)
+{
+  GSocketListener *listener = G_SOCKET_LISTENER (object);
+
+  switch (prop_id)
+    {
+      case PROP_LISTEN_BACKLOG:
+        g_value_set_int (value, listener->priv->listen_backlog);
+        break;
+
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+g_socket_listener_set_property (GObject      *object,
+				guint         prop_id,
+				const GValue *value,
+				GParamSpec   *pspec)
+{
+  GSocketListener *listener = G_SOCKET_LISTENER (object);
+
+  switch (prop_id)
+    {
+      case PROP_LISTEN_BACKLOG:
+	g_socket_listener_set_backlog (listener, g_value_get_int (value));
+	break;
+
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+
+static void
+g_socket_listener_class_init (GSocketListenerClass *klass)
+{
+  GObjectClass *gobject_class G_GNUC_UNUSED = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (GSocketListenerPrivate));
+
+  gobject_class->finalize = g_socket_listener_finalize;
+  gobject_class->set_property = g_socket_listener_set_property;
+  gobject_class->get_property = g_socket_listener_get_property;
+  g_object_class_install_property (gobject_class, PROP_LISTEN_BACKLOG,
+                                   g_param_spec_int ("listen-backlog",
+                                                     P_("Listen backlog"),
+                                                     P_("outstanding connections in the listen queue"),
+                                                     0,
+                                                     2000,
+                                                     10,
+                                                     G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  source_quark = g_quark_from_static_string ("g-socket-listener-source");
+}
+
+static void
+g_socket_listener_init (GSocketListener *listener)
+{
+  listener->priv = G_TYPE_INSTANCE_GET_PRIVATE (listener,
+						G_TYPE_SOCKET_LISTENER,
+						GSocketListenerPrivate);
+  listener->priv->sockets =
+    g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
+  listener->priv->listen_backlog = 10;
+}
+
+/**
+ * g_socket_service_new:
+ *
+ * Creates a new #GSocketListener with no sockets to listen for.
+ * New listeners can be added with e.g. g_socket_listener_add_address()
+ * or g_socket_listener_add_inet_port().
+ *
+ * Returns: a new #GSocketListener.
+ *
+ * Since: 2.22
+ **/
+GSocketListener *
+g_socket_listener_new (void)
+{
+  return g_object_new (G_TYPE_SOCKET_LISTENER, NULL);
+}
+
+static gboolean
+check_listener (GSocketListener *listener,
+		GError **error)
+{
+  if (listener->priv->closed)
+    {
+      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CLOSED,
+			   _("Listener is already closed"));
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+/**
+ * g_socket_listener_add_socket:
+ * @listener: a #GSocketListener
+ * @socket: a listening #GSocket
+ * @source_object: Optional #GObject identifying this source
+ * @error: #GError for error reporting, or %NULL to ignore.
+ *
+ * Adds @socket to the set of sockets that we try to accept
+ * new clients from. The socket must be bound to a local
+ * address and listened to.
+ *
+ * @source_object will be passed out in the various calls
+ * to accept to identify this particular source, which is
+ * useful if you're listening on multiple addresses and do
+ * different things depending on what address is connected to.
+ *
+ * Returns: %TRUE on success, %FALSE on error.
+ *
+ * Since: 2.22
+ **/
+gboolean
+g_socket_listener_add_socket (GSocketListener *listener,
+			      GSocket *socket,
+			      GObject *source_object,
+			      GError **error)
+{
+  if (!check_listener (listener, error))
+    return FALSE;
+
+  /* TODO: Check that socket it is bound & not closed? */
+
+  if (g_socket_is_closed (socket))
+    {
+      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+			   _("Added socket is closed"));
+      return FALSE;
+    }
+
+  g_ptr_array_add (listener->priv->sockets, socket);
+  g_socket_set_listen_backlog (socket, listener->priv->listen_backlog);
+
+  if (source_object)
+    g_object_set_qdata_full (G_OBJECT (socket), source_quark,
+			     g_object_ref (source_object), g_object_unref);
+
+  return TRUE;
+}
+
+/**
+ * g_socket_listener_add_socket:
+ * @listener: a #GSocketListener
+ * @address: a #GSocketAddres
+ * @type: a #GSocketType
+ * @protocol: a protocol name, or %NULL
+ * @source_object: Optional #GObject identifying this source
+ * @error: #GError for error reporting, or %NULL to ignore.
+ *
+ * Creates a socket of type @type and protocol @protocol, binds
+ * it to @address and adds it to the set of sockets we're accepting
+ * sockets from.
+ *
+ * @source_object will be passed out in the various calls
+ * to accept to identify this particular source, which is
+ * useful if you're listening on multiple addresses and do
+ * different things depending on what address is connected to.
+ *
+ * Returns: %TRUE on success, %FALSE on error.
+ *
+ * Since: 2.22
+ **/
+gboolean
+g_socket_listener_add_address (GSocketListener *listener,
+			       GSocketAddress *address,
+			       GSocketType type,
+			       const char *protocol,
+			       GObject *source_object,
+			       GError **error)
+{
+  GSocketFamily family;
+  GSocket *socket;
+
+  if (!check_listener (listener, error))
+    return FALSE;
+
+  family = g_socket_address_get_family (address);
+  socket = g_socket_new (family, type,
+			 g_socket_protocol_id_lookup_by_name (protocol), error);
+  if (socket == NULL)
+    return FALSE;
+
+  if (!g_socket_bind (socket, address, TRUE, error) ||
+      !g_socket_listen (socket, error) ||
+      !g_socket_listener_add_socket (listener, socket,
+				     source_object,
+				     error))
+    {
+      g_object_unref (socket);
+      return FALSE;
+    }
+
+  if (G_SOCKET_LISTENER_GET_CLASS (listener)->changed)
+    G_SOCKET_LISTENER_GET_CLASS (listener)->changed (listener);
+
+  return TRUE;
+}
+
+/**
+ * g_socket_listener_add_inet_port:
+ * @listener: a #GSocketListener
+ * @port: an ip port number
+ * @source_object: Optional #GObject identifying this source
+ * @error: #GError for error reporting, or %NULL to ignore.
+ *
+ * Helper function for g_socket_listener_add_address() that
+ * creates a TCP/IP socket listening on IPv4 and IPv6 (if
+ * supported) on the specified port on all interfaces.
+ *
+ * @source_object will be passed out in the various calls
+ * to accept to identify this particular source, which is
+ * useful if you're listening on multiple addresses and do
+ * different things depending on what address is connected to.
+ *
+ * Returns: %TRUE on success, %FALSE on error.
+ *
+ * Since: 2.22
+ **/
+gboolean
+g_socket_listener_add_inet_port (GSocketListener *listener,
+				 int port,
+				 GObject *source_object,
+				 GError **error)
+{
+  GSocketAddress *address4, *address6;
+  GInetAddress *inet_address;
+  gboolean res;
+
+  if (!check_listener (listener, error))
+    return FALSE;
+
+  inet_address = g_inet_address_new_any (G_SOCKET_FAMILY_IPV4);
+  address4 = g_inet_socket_address_new (inet_address, port);
+  g_object_unref (inet_address);
+
+  inet_address = g_inet_address_new_any (G_SOCKET_FAMILY_IPV6);
+  address6 = g_inet_socket_address_new (inet_address, port);
+  g_object_unref (inet_address);
+
+  if (!g_socket_listener_add_address (listener,
+				      address6,
+				      G_SOCKET_TYPE_STREAM,
+				      NULL,
+				      source_object,
+				      NULL))
+    {
+      /* Failed, to create ipv6, socket, just use ipv4,
+	 return any error */
+      res = g_socket_listener_add_address (listener,
+					   address4,
+					   G_SOCKET_TYPE_STREAM,
+					   NULL,
+					   source_object,
+					   error);
+    }
+  else
+    {
+      /* Succeeded with ipv6, also try ipv4 in case its ipv6 only,
+	 but ignore errors here */
+      res = TRUE;
+      g_socket_listener_add_address (listener,
+				     address4,
+				     G_SOCKET_TYPE_STREAM,
+				     NULL,
+				     source_object,
+				     NULL);
+    }
+
+  g_object_unref (address4);
+  g_object_unref (address6);
+
+  return res;
+}
+
+static GList *
+add_sources (GSocketListener *listener,
+	     GSocketSourceFunc callback,
+	     gpointer callback_data,
+	     GCancellable *cancellable,
+	     GMainContext *context)
+{
+  GSocket *socket;
+  GSource *source;
+  GList *sources;
+  int i;
+
+  sources = NULL;
+  for (i = 0; i < listener->priv->sockets->len; i++)
+    {
+      socket = listener->priv->sockets->pdata[i];
+
+      source = g_socket_create_source (socket, G_IO_IN, cancellable);
+      g_source_set_callback (source,
+                             (GSourceFunc) callback,
+                             callback_data, NULL);
+      g_source_attach (source, context);
+
+      sources = g_list_prepend (sources, source);
+    }
+
+  return sources;
+}
+
+static void
+free_sources (GList *sources)
+{
+  GSource *source;
+  while (sources != NULL)
+    {
+      source = sources->data;
+      sources = g_list_delete_link (sources, sources);
+      g_source_destroy (source);
+      g_source_unref (source);
+    }
+}
+
+struct AcceptData {
+  GMainLoop *loop;
+  GSocket *socket;
+};
+
+static gboolean
+accept_callback (GSocket *socket,
+		 GIOCondition condition,
+		 gpointer user_data)
+{
+  struct AcceptData *data = user_data;
+
+  data->socket = socket;
+  g_main_loop_quit (data->loop);
+
+  return TRUE;
+}
+
+/**
+ * g_socket_listener_accept_socket:
+ * @listener: a #GSocketListener
+ * @source_object: location where #GObject pointer will be stored, or %NULL
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @error: #GError for error reporting, or %NULL to ignore.
+ *
+ * Blocks waiting for a client to connect to any of the sockets added
+ * to the listener. Returns the #GSocket that was accepted.
+ *
+ * If you want to accept the high-level #GSocketConnection, not a #GSocket,
+ * which is often the case, then you should use g_socket_listener_accept()
+ * instead.
+ *
+ * If @source_object is not %NULL it will be filled out with the source
+ * object specified when the corresponding socket or address was added
+ * to the listener.
+ *
+ * If @cancellable is not NULL, then the operation can be cancelled by
+ * triggering the cancellable object from another thread. If the operation
+ * was cancelled, the error G_IO_ERROR_CANCELLED will be returned.
+ *
+ * Returns: a #GSocket on success, %NULL on error.
+ *
+ * Since: 2.22
+ **/
+GSocket *
+g_socket_listener_accept_socket (GSocketListener  *listener,
+				 GObject         **source_object,
+				 GCancellable     *cancellable,
+				 GError          **error)
+{
+  GSocket *accept_socket, *socket;
+
+  g_return_val_if_fail (G_IS_SOCKET_LISTENER (listener), NULL);
+
+  if (!check_listener (listener, error))
+    return NULL;
+
+  if (listener->priv->sockets->len == 1)
+    {
+      accept_socket = listener->priv->sockets->pdata[0];
+      if (!g_socket_condition_wait (accept_socket, G_IO_IN,
+				    cancellable, error))
+	return NULL;
+    }
+  else
+    {
+      GList *sources;
+      struct AcceptData data;
+      GMainLoop *loop;
+
+      if (listener->priv->main_context == NULL)
+	listener->priv->main_context = g_main_context_new ();
+
+      loop = g_main_loop_new (listener->priv->main_context, FALSE);
+      data.loop = loop;
+      sources = add_sources (listener,
+			     accept_callback,
+			     &data,
+			     cancellable,
+			     listener->priv->main_context);
+      g_main_loop_run (loop);
+      accept_socket = data.socket;
+      free_sources (sources);
+      g_main_loop_unref (loop);
+    }
+
+  if (!(socket = g_socket_accept (accept_socket, error)))
+    return NULL;
+
+  if (source_object)
+    *source_object = g_object_get_qdata (G_OBJECT (accept_socket), source_quark);
+
+  return socket;
+}
+
+/**
+ * g_socket_listener_accept:
+ * @listener: a #GSocketListener
+ * @source_object: location where #GObject pointer will be stored, or %NULL
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @error: #GError for error reporting, or %NULL to ignore.
+ *
+ * Blocks waiting for a client to connect to any of the sockets added
+ * to the listener. Returns a #GSocketConnection for the socket that was
+ * accepted.
+ *
+ * If @source_object is not %NULL it will be filled out with the source
+ * object specified when the corresponding socket or address was added
+ * to the listener.
+ *
+ * If @cancellable is not NULL, then the operation can be cancelled by
+ * triggering the cancellable object from another thread. If the operation
+ * was cancelled, the error G_IO_ERROR_CANCELLED will be returned.
+ *
+ * Returns: a #GSocketConnection on success, %NULL on error.
+ *
+ * Since: 2.22
+ **/
+GSocketConnection *
+g_socket_listener_accept (GSocketListener  *listener,
+			  GObject         **source_object,
+			  GCancellable     *cancellable,
+			  GError          **error)
+{
+  GSocketConnection *connection;
+  GSocket *socket;
+
+  socket = g_socket_listener_accept_socket (listener,
+					    source_object,
+					    cancellable,
+					    error);
+  if (socket == NULL)
+    return NULL;
+
+  connection = g_socket_connection_factory_create_connection (socket);
+  g_object_unref (socket);
+
+  return connection;
+}
+
+struct AcceptAsyncData {
+  GSimpleAsyncResult *simple;
+  GCancellable *cancellable;
+  GList *sources;
+};
+
+static gboolean
+accept_ready (GSocket *accept_socket,
+	      GIOCondition condition,
+	      gpointer _data)
+{
+  struct AcceptAsyncData *data = _data;
+  GError *error = NULL;
+
+  if (!g_cancellable_set_error_if_cancelled (data->cancellable,
+                                             &error))
+    {
+      GSocket *socket;
+      GObject *source_object;
+
+      socket = g_socket_accept (accept_socket, &error);
+      if (socket)
+	{
+	  g_simple_async_result_set_op_res_gpointer (data->simple, socket,
+						     g_object_unref);
+	  source_object = g_object_get_qdata (G_OBJECT (accept_socket), source_quark);
+	  if (source_object)
+	    g_object_set_qdata_full (G_OBJECT (data->simple),
+				     source_quark,
+				     g_object_ref (source_object), g_object_unref);
+	}
+    }
+
+  if (error)
+    {
+      g_simple_async_result_set_from_error (data->simple, error);
+      g_error_free (error);
+    }
+
+  g_simple_async_result_complete_in_idle (data->simple);
+  g_object_unref (data->simple);
+  free_sources (data->sources);
+  g_free (data);
+
+  return FALSE;
+}
+
+/**
+ * g_socket_listener_accept_socket_async:
+ * @listener: a #GSocketListener
+ * @cancellable: a #GCancellable, or %NULL
+ * @callback: a #GAsyncReadyCallback
+ * @user_data: user data for the callback
+ *
+ * This is the asynchronous version of g_socket_listener_accept_socket().
+ *
+ * When the operation is finished @callback will be
+ * called. You can then call g_socket_listener_accept_socket_finish() to get
+ * the result of the operation.
+ *
+ * Since: 2.22
+ **/
+void
+g_socket_listener_accept_socket_async (GSocketListener      *listener,
+				       GCancellable         *cancellable,
+				       GAsyncReadyCallback   callback,
+				       gpointer              user_data)
+{
+  struct AcceptAsyncData *data;
+  GError *error = NULL;
+
+  if (!check_listener (listener, &error))
+    {
+      g_simple_async_report_gerror_in_idle (G_OBJECT (listener),
+					    callback, user_data,
+					    error);
+      g_error_free (error);
+      return;
+    }
+
+  data = g_new0 (struct AcceptAsyncData, 1);
+  data->simple = g_simple_async_result_new (G_OBJECT (listener),
+					    callback, user_data,
+					    g_socket_listener_accept_socket_async);
+  data->cancellable = cancellable;
+  data->sources = add_sources (listener,
+			       accept_ready,
+			       data,
+			       cancellable,
+			       NULL);
+}
+
+/**
+ * g_socket_listener_accept_socket_finish:
+ * @listener: a #GSocketListener
+ * @result: a #GAsyncResult.
+ * @source_object: Optional #GObject identifying this source
+ * @error: a #GError location to store the error occuring, or %NULL to
+ * ignore.
+ *
+ * Finishes an async accept operation. See g_socket_listener_accept_socket_async()
+ *
+ * Returns: a #GSocket on success, %NULL on error.
+ *
+ * Since: 2.22
+ **/
+GSocket *
+g_socket_listener_accept_socket_finish (GSocketListener   *listener,
+					GAsyncResult      *result,
+					GObject          **source_object,
+					GError           **error)
+{
+  GSocket *socket;
+  GSimpleAsyncResult *simple;
+
+  g_return_val_if_fail (G_IS_SOCKET_LISTENER (listener), FALSE);
+
+  simple = G_SIMPLE_ASYNC_RESULT (result);
+
+  if (g_simple_async_result_propagate_error (simple, error))
+    return NULL;
+
+  g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_socket_listener_accept_socket_async);
+
+  socket = g_simple_async_result_get_op_res_gpointer (simple);
+
+  if (source_object)
+    *source_object = g_object_get_qdata (G_OBJECT (result), source_quark);
+
+  return g_object_ref (socket);
+}
+
+/**
+ * g_socket_listener_accept_socket_async:
+ * @listener: a #GSocketListener
+ * @cancellable: a #GCancellable, or %NULL
+ * @callback: a #GAsyncReadyCallback
+ * @user_data: user data for the callback
+ *
+ * This is the asynchronous version of g_socket_listener_accept().
+ *
+ * When the operation is finished @callback will be
+ * called. You can then call g_socket_listener_accept_socket() to get
+ * the result of the operation.
+ *
+ * Since: 2.22
+ **/
+void
+g_socket_listener_accept_async (GSocketListener     *listener,
+                                GCancellable        *cancellable,
+                                GAsyncReadyCallback  callback,
+                                gpointer             user_data)
+{
+  g_socket_listener_accept_socket_async (listener,
+					 cancellable,
+					 callback,
+					 user_data);
+}
+
+/**
+ * g_socket_listener_accept_finish:
+ * @listener: a #GSocketListener
+ * @result: a #GAsyncResult.
+ * @source_object: Optional #GObject identifying this source
+ * @error: a #GError location to store the error occuring, or %NULL to
+ * ignore.
+ *
+ * Finishes an async accept operation. See g_socket_listener_accept_async()
+ *
+ * Returns: a #GSocketConnection on success, %NULL on error.
+ *
+ * Since: 2.22
+ **/
+GSocketConnection *
+g_socket_listener_accept_finish (GSocketListener *listener,
+				 GAsyncResult *result,
+				 GObject **source_object,
+				 GError **error)
+{
+  GSocket *socket;
+  GSocketConnection *connection;
+
+  socket = g_socket_listener_accept_socket_finish (listener,
+						   result,
+						   source_object,
+						   error);
+  if (socket == NULL)
+    return NULL;
+
+  connection = g_socket_connection_factory_create_connection (socket);
+  g_object_unref (socket);
+  return connection;
+}
+
+/**
+ * g_socket_listener_accept_finish:
+ * @listener: a #GSocketListener
+ * @listen_backlog: an integer
+ *
+ * Sets the listen backlog on the sockets in the listener.
+ *
+ * See g_socket_set_listen_backlog() for details
+ *
+ * Since: 2.22
+ **/
+void
+g_socket_listener_set_backlog (GSocketListener *listener,
+			       int listen_backlog)
+{
+  GSocket *socket;
+  int i;
+
+  if (listener->priv->closed)
+    return;
+
+  listener->priv->listen_backlog = listen_backlog;
+
+  for (i = 0; i < listener->priv->sockets->len; i++)
+    {
+      socket = listener->priv->sockets->pdata[i];
+      g_socket_set_listen_backlog (socket, listen_backlog);
+    }
+}
+
+/**
+ * g_socket_listener_close:
+ * @listener: a #GSocketListener
+ *
+ * Closes all the sockets in the listener.
+ *
+ * Since: 2.22
+ **/
+void
+g_socket_listener_close (GSocketListener *listener)
+{
+  GSocket *socket;
+  int i;
+
+  g_return_if_fail (G_IS_SOCKET_LISTENER (listener));
+
+  if (listener->priv->closed)
+    return;
+
+  for (i = 0; i < listener->priv->sockets->len; i++)
+    {
+      socket = listener->priv->sockets->pdata[i];
+      g_socket_close (socket, NULL);
+    }
+  listener->priv->closed = TRUE;
+}
+
+#define __G_SOCKET_LISTENER_C__
+#include "gioaliasdef.c"
diff --git a/gio/gsocketlistener.h b/gio/gsocketlistener.h
new file mode 100644
index 0000000..9a13209
--- /dev/null
+++ b/gio/gsocketlistener.h
@@ -0,0 +1,134 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright © 2008 Christian Kellner, Samuel Cormier-Iijima
+ * Copyright © 2009 Codethink Limited
+ * Copyright © 2009 Red Hat, Inc
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the licence or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Christian Kellner <gicmo gnome org>
+ *          Samuel Cormier-Iijima <sciyoshi gmail com>
+ *          Ryan Lortie <desrt desrt ca>
+ *          Alexander Larsson <alexl redhat com>
+ */
+
+#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
+#error "Only <gio/gio.h> can be included directly."
+#endif
+
+#ifndef __G_SOCKET_LISTENER_H__
+#define __G_SOCKET_LISTENER_H__
+
+#include <gio/giotypes.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_SOCKET_LISTENER                              (g_socket_listener_get_type ())
+#define G_SOCKET_LISTENER(inst)                             (G_TYPE_CHECK_INSTANCE_CAST ((inst),                     \
+                                                             G_TYPE_SOCKET_LISTENER, GSocketListener))
+#define G_SOCKET_LISTENER_CLASS(class)                      (G_TYPE_CHECK_CLASS_CAST ((class),                       \
+                                                             G_TYPE_SOCKET_LISTENER, GSocketListenerClass))
+#define G_IS_SOCKET_LISTENER(inst)                          (G_TYPE_CHECK_INSTANCE_TYPE ((inst),                     \
+                                                             G_TYPE_SOCKET_LISTENER))
+#define G_IS_SOCKET_LISTENER_CLASS(class)                   (G_TYPE_CHECK_CLASS_TYPE ((class),                       \
+                                                             G_TYPE_SOCKET_LISTENER))
+#define G_SOCKET_LISTENER_GET_CLASS(inst)                   (G_TYPE_INSTANCE_GET_CLASS ((inst),                      \
+                                                             G_TYPE_SOCKET_LISTENER, GSocketListenerClass))
+
+typedef struct _GSocketListenerPrivate                      GSocketListenerPrivate;
+typedef struct _GSocketListenerClass                        GSocketListenerClass;
+
+/**
+ * GSocketListenerClass:
+ * @changed: virtual method called when the set of socket listened to changes
+ **/
+struct _GSocketListenerClass
+{
+  GObjectClass parent_class;
+
+  void (* changed) (GSocketListener *listener);
+
+  /* Padding for future expansion */
+  void (*_g_reserved1) (void);
+  void (*_g_reserved2) (void);
+  void (*_g_reserved3) (void);
+  void (*_g_reserved4) (void);
+  void (*_g_reserved5) (void);
+  void (*_g_reserved6) (void);
+};
+
+struct _GSocketListener
+{
+  GObject parent_instance;
+  GSocketListenerPrivate *priv;
+};
+
+GType                   g_socket_listener_get_type                      (void) G_GNUC_CONST;
+
+GSocketListener *       g_socket_listener_new                           (void);
+
+void                    g_socket_listener_set_backlog                   (GSocketListener     *listener,
+									 int                  listen_backlog);
+
+gboolean                g_socket_listener_add_socket                    (GSocketListener     *listener,
+                                                                         GSocket             *socket,
+									 GObject             *source_object,
+									 GError             **error);
+gboolean                g_socket_listener_add_address                   (GSocketListener      *listener,
+                                                                         GSocketAddress      *address,
+									 GSocketType          type,
+									 const char          *protocol,
+									 GObject             *source_object,
+									 GError             **error);
+gboolean                g_socket_listener_add_inet_port                 (GSocketListener      *listener,
+                                                                         int                  port,
+									 GObject             *source_object,
+									 GError             **error);
+
+GSocket *               g_socket_listener_accept_socket                 (GSocketListener      *listener,
+									 GObject             **source_object,
+                                                                         GCancellable         *cancellable,
+                                                                         GError              **error);
+void                    g_socket_listener_accept_socket_async           (GSocketListener      *listener,
+                                                                         GCancellable         *cancellable,
+                                                                         GAsyncReadyCallback   callback,
+                                                                         gpointer              user_data);
+GSocket *               g_socket_listener_accept_socket_finish          (GSocketListener      *listener,
+                                                                         GAsyncResult         *result,
+									 GObject             **source_object,
+                                                                         GError              **error);
+
+
+GSocketConnection *     g_socket_listener_accept                        (GSocketListener      *listener,
+									 GObject             **source_object,
+                                                                         GCancellable         *cancellable,
+                                                                         GError              **error);
+
+void                    g_socket_listener_accept_async                  (GSocketListener      *listener,
+                                                                         GCancellable         *cancellable,
+                                                                         GAsyncReadyCallback   callback,
+                                                                         gpointer              user_data);
+
+GSocketConnection *     g_socket_listener_accept_finish                 (GSocketListener      *listener,
+                                                                         GAsyncResult         *result,
+									 GObject             **source_object,
+                                                                         GError              **error);
+
+void                    g_socket_listener_close                         (GSocketListener      *listener);
+
+G_END_DECLS
+
+#endif /* __G_SOCKET_LISTENER_H__ */
diff --git a/gio/gsocketoutputstream.c b/gio/gsocketoutputstream.c
new file mode 100644
index 0000000..0e53a57
--- /dev/null
+++ b/gio/gsocketoutputstream.c
@@ -0,0 +1,259 @@
+/*  GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright © 2008 Christian Kellner, Samuel Cormier-Iijima
+ *           © 2009 codethink
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Christian Kellner <gicmo gnome org>
+ *          Samuel Cormier-Iijima <sciyoshi gmail com>
+ *          Ryan Lortie <desrt desrt ca>
+ */
+
+#include "config.h"
+#include "gsocketoutputstream.h"
+
+#include <gio/gsimpleasyncresult.h>
+#include <gio/gcancellable.h>
+#include "glibintl.h"
+
+#define g_socket_output_stream_get_type _g_socket_output_stream_get_type
+G_DEFINE_TYPE (GSocketOutputStream, g_socket_output_stream, G_TYPE_OUTPUT_STREAM);
+
+enum
+{
+  PROP_0,
+  PROP_SOCKET
+};
+
+struct _GSocketOutputStreamPrivate
+{
+  GSocket *socket;
+
+  /* pending operation metadata */
+  GSimpleAsyncResult *result;
+  GCancellable *cancellable;
+  gboolean from_mainloop;
+  gconstpointer buffer;
+  gsize count;
+};
+
+static void
+g_socket_output_stream_get_property (GObject    *object,
+                                     guint       prop_id,
+                                     GValue     *value,
+                                     GParamSpec *pspec)
+{
+  GSocketOutputStream *stream = G_SOCKET_OUTPUT_STREAM (object);
+
+  switch (prop_id)
+    {
+      case PROP_SOCKET:
+        g_value_set_object (value, stream->priv->socket);
+        break;
+
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+g_socket_output_stream_set_property (GObject      *object,
+                                     guint         prop_id,
+                                     const GValue *value,
+                                     GParamSpec   *pspec)
+{
+  GSocketOutputStream *stream = G_SOCKET_OUTPUT_STREAM (object);
+
+  switch (prop_id)
+    {
+      case PROP_SOCKET:
+        stream->priv->socket = g_value_dup_object (value);
+        break;
+
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+g_socket_output_stream_finalize (GObject *object)
+{
+  GSocketOutputStream *stream = G_SOCKET_OUTPUT_STREAM (object);
+
+  if (stream->priv->socket)
+    g_object_unref (stream->priv->socket);
+
+  if (G_OBJECT_CLASS (g_socket_output_stream_parent_class)->finalize)
+    (*G_OBJECT_CLASS (g_socket_output_stream_parent_class)->finalize) (object);
+}
+
+static gssize
+g_socket_output_stream_write (GOutputStream  *stream,
+                              const void     *buffer,
+                              gsize           count,
+                              GCancellable   *cancellable,
+                              GError        **error)
+{
+  GSocketOutputStream *onput_stream = G_SOCKET_OUTPUT_STREAM (stream);
+
+  if (!g_socket_condition_wait (onput_stream->priv->socket,
+                                G_IO_OUT, cancellable, error))
+    return -1;
+
+  return g_socket_send (onput_stream->priv->socket, buffer, count, error);
+}
+
+static gboolean
+g_socket_output_stream_write_ready (GSocket *socket,
+                                    GIOCondition condition,
+				    GSocketOutputStream *stream)
+{
+  GSimpleAsyncResult *simple;
+  GError *error = NULL;
+
+  simple = stream->priv->result;
+  stream->priv->result = NULL;
+
+  if (!g_cancellable_set_error_if_cancelled (stream->priv->cancellable,
+                                             &error))
+    {
+      gssize result;
+
+      result = g_socket_send (stream->priv->socket,
+                              stream->priv->buffer,
+                              stream->priv->count,
+                              &error);
+      if (result >= 0)
+        g_simple_async_result_set_op_res_gssize (simple, result);
+    }
+
+  if (error)
+    {
+      g_simple_async_result_set_from_error (simple, error);
+      g_error_free (error);
+    }
+
+  if (stream->priv->cancellable)
+    g_object_unref (stream->priv->cancellable);
+
+  if (stream->priv->from_mainloop)
+    g_simple_async_result_complete (simple);
+  else
+    g_simple_async_result_complete_in_idle (simple);
+
+  g_object_unref (simple);
+
+  return FALSE;
+}
+
+static void
+g_socket_output_stream_write_async (GOutputStream        *stream,
+                                    const void           *buffer,
+                                    gsize                 count,
+                                    gint                  io_priority,
+                                    GCancellable         *cancellable,
+                                    GAsyncReadyCallback   callback,
+                                    gpointer              user_data)
+{
+  GSocketOutputStream *output_stream = G_SOCKET_OUTPUT_STREAM (stream);
+
+  g_assert (output_stream->priv->result == NULL);
+
+  output_stream->priv->result =
+    g_simple_async_result_new (G_OBJECT (stream), callback, user_data,
+                               g_socket_output_stream_write_async);
+  if (cancellable)
+    g_object_ref (cancellable);
+  output_stream->priv->cancellable = cancellable;
+  output_stream->priv->buffer = buffer;
+  output_stream->priv->count = count;
+
+  if (!g_socket_condition_check (output_stream->priv->socket, G_IO_OUT))
+    {
+      GSource *source;
+
+      output_stream->priv->from_mainloop = TRUE;
+      source = g_socket_create_source (output_stream->priv->socket,
+                                       G_IO_OUT | G_IO_HUP | G_IO_ERR,
+                                       cancellable);
+      g_source_set_callback (source,
+                             (GSourceFunc) g_socket_output_stream_write_ready,
+                             g_object_ref (output_stream), g_object_unref);
+      g_source_attach (source, NULL);
+      g_source_unref (source);
+    }
+  else
+    {
+      output_stream->priv->from_mainloop = FALSE;
+      g_socket_output_stream_write_ready (output_stream->priv->socket, G_IO_OUT, output_stream);
+    }
+}
+
+static gssize
+g_socket_output_stream_write_finish (GOutputStream  *stream,
+                                     GAsyncResult   *result,
+                                     GError        **error)
+{
+  GSimpleAsyncResult *simple;
+  gssize count;
+
+  g_return_val_if_fail (G_IS_SOCKET_OUTPUT_STREAM (stream), -1);
+
+  simple = G_SIMPLE_ASYNC_RESULT (result);
+
+  g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_socket_output_stream_write_async);
+
+  count = g_simple_async_result_get_op_res_gssize (simple);
+
+  return count;
+}
+
+static void
+g_socket_output_stream_class_init (GSocketOutputStreamClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GOutputStreamClass *goutputstream_class = G_OUTPUT_STREAM_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (GSocketOutputStreamPrivate));
+
+  gobject_class->finalize = g_socket_output_stream_finalize;
+  gobject_class->get_property = g_socket_output_stream_get_property;
+  gobject_class->set_property = g_socket_output_stream_set_property;
+
+  goutputstream_class->write_fn = g_socket_output_stream_write;
+  goutputstream_class->write_async = g_socket_output_stream_write_async;
+  goutputstream_class->write_finish = g_socket_output_stream_write_finish;
+
+  g_object_class_install_property (gobject_class, PROP_SOCKET,
+				   g_param_spec_object ("socket",
+							P_("socket"),
+							P_("The socket that this stream wraps"),
+							G_TYPE_SOCKET, G_PARAM_CONSTRUCT_ONLY |
+							G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+g_socket_output_stream_init (GSocketOutputStream *stream)
+{
+  stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream, G_TYPE_SOCKET_OUTPUT_STREAM, GSocketOutputStreamPrivate);
+}
+
+GSocketOutputStream *
+_g_socket_output_stream_new (GSocket *socket)
+{
+  return G_SOCKET_OUTPUT_STREAM (g_object_new (G_TYPE_SOCKET_OUTPUT_STREAM, "socket", socket, NULL));
+}
diff --git a/gio/gsocketoutputstream.h b/gio/gsocketoutputstream.h
new file mode 100644
index 0000000..e3514d1
--- /dev/null
+++ b/gio/gsocketoutputstream.h
@@ -0,0 +1,58 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright © 2008 Christian Kellner, Samuel Cormier-Iijima
+ * Copyright © 2009 Codethink Limited
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the licence or (at
+ * your option) any later version.
+ *
+ * See the included COPYING file for more information.
+ *
+ * Authors: Christian Kellner <gicmo gnome org>
+ *          Samuel Cormier-Iijima <sciyoshi gmail com>
+ *          Ryan Lortie <desrt desrt ca>
+ */
+
+#ifndef __G_SOCKET_OUTPUT_STREAM_H__
+#define __G_SOCKET_OUTPUT_STREAM_H__
+
+#include <gio/goutputstream.h>
+#include <gio/gsocket.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_SOCKET_OUTPUT_STREAM                         (_g_socket_output_stream_get_type ())
+#define G_SOCKET_OUTPUT_STREAM(inst)                        (G_TYPE_CHECK_INSTANCE_CAST ((inst),                     \
+                                                             G_TYPE_SOCKET_OUTPUT_STREAM, GSocketOutputStream))
+#define G_SOCKET_OUTPUT_STREAM_CLASS(class)                 (G_TYPE_CHECK_CLASS_CAST ((class),                       \
+                                                             G_TYPE_SOCKET_OUTPUT_STREAM, GSocketOutputStreamClass))
+#define G_IS_SOCKET_OUTPUT_STREAM(inst)                     (G_TYPE_CHECK_INSTANCE_TYPE ((inst),                     \
+                                                             G_TYPE_SOCKET_OUTPUT_STREAM))
+#define G_IS_SOCKET_OUTPUT_STREAM_CLASS(class)              (G_TYPE_CHECK_CLASS_TYPE ((class),                       \
+                                                             G_TYPE_SOCKET_OUTPUT_STREAM))
+#define G_SOCKET_OUTPUT_STREAM_GET_CLASS(inst)              (G_TYPE_INSTANCE_GET_CLASS ((inst),                      \
+                                                             G_TYPE_SOCKET_OUTPUT_STREAM, GSocketOutputStreamClass))
+
+typedef struct _GSocketOutputStreamPrivate                  GSocketOutputStreamPrivate;
+typedef struct _GSocketOutputStreamClass                    GSocketOutputStreamClass;
+typedef struct _GSocketOutputStream                         GSocketOutputStream;
+
+struct _GSocketOutputStreamClass
+{
+  GOutputStreamClass parent_class;
+};
+
+struct _GSocketOutputStream
+{
+  GOutputStream parent_instance;
+  GSocketOutputStreamPrivate *priv;
+};
+
+GType                   _g_socket_output_stream_get_type                 (void) G_GNUC_CONST;
+GSocketOutputStream *   _g_socket_output_stream_new                     (GSocket *socket);
+
+G_END_DECLS
+
+#endif /* __G_SOCKET_OUTPUT_STREAM_H__ */
diff --git a/gio/gsocketservice.c b/gio/gsocketservice.c
new file mode 100644
index 0000000..9c56a69
--- /dev/null
+++ b/gio/gsocketservice.c
@@ -0,0 +1,330 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright © 2009 Codethink Limited
+ * Copyright © 2009 Red Hat, Inc
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the licence or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Ryan Lortie <desrt desrt ca>
+ *          Alexander Larsson <alexl redhat com>
+ */
+
+/**
+ * SECTION: gsocketservice
+ * @title: GSocketService
+ * @short_description: a high-level object representing a service
+ * @see_also: #GThreadedSocketService, #GSocketListener.
+ *
+ * A #GSocketService is an object that represents a service that is
+ * provided to the network or over local sockets.  When a new
+ * connection is made to the service the ::incoming signal is emitted.
+ *
+ * A #GSocketService is a subclass of #GSocketListener and you need
+ * to add the addresses you want to accept connections on to the
+ * with the #GSocketListener APIs.
+ *
+ * There are two options for implementing a network service based on
+ * #GSocketService.  The first is to create the service using
+ * g_socket_service_new() and to connect to the ::incoming signal.
+ * The second is to subclass #GSocketService and override the default
+ * signal handler implementation.
+ *
+ * In either case, the handler must immediately return, or else it
+ * will block additional incoming connections from being serviced.  If
+ * you are interested in writing connection handlers that contain
+ * blocking code then see #GThreadedSocketService.
+ *
+ * The socket service runs on the main loop in the main thread, and is
+ * not threadsafe in general. However, the calls to start and stop
+ * the service are threadsafe so these can be used from threads that
+ * handle incomming clients.
+ *
+ * Since: 2.22
+ */
+
+#include "config.h"
+#include "gsocketservice.h"
+
+#include "gio-marshal.h"
+#include <gio/gio.h>
+#include "gsocketlistener.h"
+#include "gsocketconnection.h"
+
+#include "gioalias.h"
+
+static guint g_socket_service_incoming_signal;
+
+G_DEFINE_TYPE (GSocketService, g_socket_service, G_TYPE_SOCKET_LISTENER);
+
+G_LOCK_DEFINE_STATIC(active);
+
+struct _GSocketServicePrivate
+{
+  GCancellable *cancellable;
+  guint active : 1;
+  guint outstanding_accept : 1;
+};
+
+static void g_socket_service_ready (GObject      *object,
+				    GAsyncResult *result,
+				    gpointer      user_data);
+
+static gboolean
+g_socket_service_real_incoming (GSocketService    *service,
+                                GSocketConnection *connection,
+                                GObject           *source_object)
+{
+  return FALSE;
+}
+
+static void
+g_socket_service_init (GSocketService *service)
+{
+  service->priv = G_TYPE_INSTANCE_GET_PRIVATE (service,
+					       G_TYPE_SOCKET_SERVICE,
+					       GSocketServicePrivate);
+  service->priv->cancellable = g_cancellable_new ();
+  service->priv->active = TRUE;
+}
+
+static void
+g_socket_service_finalize (GObject *object)
+{
+  GSocketService *service = G_SOCKET_SERVICE (object);
+
+  g_object_unref (service->priv->cancellable);
+
+  G_OBJECT_CLASS (g_socket_service_parent_class)
+    ->finalize (object);
+}
+
+static void
+do_accept (GSocketService  *service)
+{
+  g_socket_listener_accept_async (G_SOCKET_LISTENER (service),
+				  service->priv->cancellable,
+				  g_socket_service_ready, NULL);
+  service->priv->outstanding_accept = TRUE;
+}
+
+static void
+g_socket_service_changed (GSocketListener *listener)
+{
+  GSocketService  *service = G_SOCKET_SERVICE (listener);
+
+  G_LOCK (active);
+
+  if (service->priv->active)
+    {
+      if (service->priv->outstanding_accept)
+	g_cancellable_cancel (service->priv->cancellable);
+      else
+	{
+	  g_socket_listener_accept_async (listener, service->priv->cancellable,
+					  g_socket_service_ready, NULL);
+	  service->priv->outstanding_accept = TRUE;
+	}
+    }
+
+  G_UNLOCK (active);
+}
+
+/**
+ * g_socket_service_is_active:
+ * @service: a #GSocketService
+ *
+ * Check whether the service is active or not. An active
+ * service will accept new clients that connect, while
+ * a non-active service will let connecting clients queue
+ * up until the service is started.
+ *
+ * Returns: %TRUE if the service is active, %FALSE otherwise
+ *
+ * Since: 2.22
+ **/
+gboolean
+g_socket_service_is_active (GSocketService *service)
+{
+  gboolean active;
+
+  G_LOCK (active);
+  active = service->priv->active;
+  G_UNLOCK (active);
+  return active;
+}
+
+/**
+ * g_socket_service_start:
+ * @service: a #GSocketService
+ *
+ * Starts the service, i.e. start accepting connections
+ * from the added sockets when the mainloop runs.
+ *
+ * This call is threadsafe, so it may be called from a thread
+ * handling an incomming client request.
+ *
+ * Since: 2.22
+ **/
+void
+g_socket_service_start (GSocketService *service)
+{
+  G_LOCK (active);
+
+  if (!service->priv->active)
+    {
+      service->priv->active = TRUE;
+
+      if (service->priv->outstanding_accept)
+	g_cancellable_cancel (service->priv->cancellable);
+      else
+	do_accept (service);
+    }
+
+  G_UNLOCK (active);
+}
+
+/**
+ * g_socket_service_stop:
+ * @service: a #GSocketService
+ *
+ * Stops the service, i.e. stops accepting connections
+ * from the added sockets when the mainloop runs.
+ *
+ * This call is threadsafe, so it may be called from a thread
+ * handling an incomming client request.
+ *
+ * Since: 2.22
+ **/
+void
+g_socket_service_stop (GSocketService  *service)
+{
+  G_LOCK (active);
+
+  if (service->priv->active)
+    {
+      service->priv->active = FALSE;
+
+      if (service->priv->outstanding_accept)
+	g_cancellable_cancel (service->priv->cancellable);
+    }
+
+  G_UNLOCK (active);
+}
+
+
+static gboolean
+g_socket_service_incoming (GSocketService    *service,
+                           GSocketConnection *connection,
+                           GObject           *source_object)
+{
+  gboolean result;
+
+  g_signal_emit (service, g_socket_service_incoming_signal,
+                 0, connection, source_object, &result);
+  return result;
+}
+
+static void
+g_socket_service_class_init (GSocketServiceClass *class)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+  GSocketListenerClass *listener_class = G_SOCKET_LISTENER_CLASS (class);
+
+  g_type_class_add_private (class, sizeof (GSocketServicePrivate));
+
+  gobject_class->finalize = g_socket_service_finalize;
+  listener_class->changed = g_socket_service_changed;
+  class->incoming = g_socket_service_real_incoming;
+
+  /**
+   * GSocketService::incoming:
+   * @service: the #GSocketService.
+   * @connection: a new #GSocketConnection object.
+   * @source_object: the source_object passed to g_socket_listener_add_address().
+   * @returns: %TRUE if @connection has been handled.
+   *
+   * The ::incoming signal is emitted when a new incoming connection
+   * to @service needs to be handled.  The handler must initiate the
+   * handling of @connection, but may not block; in essence,
+   * asynchronous operations must be used.
+   *
+   * If %TRUE is returned then no other handlers are called.
+   **/
+  g_socket_service_incoming_signal =
+    g_signal_new ("incoming", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (GSocketServiceClass, incoming),
+                  g_signal_accumulator_true_handled, NULL,
+                  _gio_marshal_BOOLEAN__OBJECT_OBJECT, G_TYPE_BOOLEAN,
+                  2, G_TYPE_SOCKET_CONNECTION, G_TYPE_OBJECT);
+}
+
+static void
+g_socket_service_ready (GObject      *object,
+                        GAsyncResult *result,
+                        gpointer      user_data)
+{
+  GSocketListener *listener = G_SOCKET_LISTENER (object);
+  GSocketService *service = G_SOCKET_SERVICE (object);
+  GSocketConnection *connection;
+  GObject *source_object;
+  GError *error = NULL;
+
+  connection = g_socket_listener_accept_finish (listener, result, &source_object, &error);
+  if (error)
+    {
+      if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+	g_warning ("fail: %s", error->message);
+      g_error_free (error);
+    }
+  else
+    {
+      g_socket_service_incoming (service, connection, source_object);
+      g_object_unref (connection);
+    }
+
+  G_LOCK (active);
+
+  g_cancellable_reset (service->priv->cancellable);
+
+  /* requeue */
+  service->priv->outstanding_accept = FALSE;
+  if (service->priv->active)
+    do_accept (service);
+
+  G_UNLOCK (active);
+}
+
+
+/**
+ * g_socket_service_new:
+ * @returns: a new #GSocketService.
+ *
+ * Creates a new #GSocketService with no sockets to listen for.
+ * New listeners can be added with e.g. g_socket_listener_add_address()
+ * or g_socket_listener_add_inet_port().
+ *
+ * Returns: a new #GSocketService.
+ *
+ * Since: 2.22
+ **/
+GSocketService *
+g_socket_service_new (void)
+{
+  return g_object_new (G_TYPE_SOCKET_SERVICE, NULL);
+}
+
+#define __G_SOCKET_SERVICE_C__
+#include "gioaliasdef.c"
diff --git a/gio/gsocketservice.h b/gio/gsocketservice.h
new file mode 100644
index 0000000..fe77984
--- /dev/null
+++ b/gio/gsocketservice.h
@@ -0,0 +1,88 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright © 2009 Codethink Limited
+ * Copyright © 2009 Red Hat, Inc
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the licence or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Ryan Lortie <desrt desrt ca>
+ *          Alexander Larsson <alexl redhat com>
+ */
+
+#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
+#error "Only <gio/gio.h> can be included directly."
+#endif
+
+#ifndef __G_SOCKET_SERVICE_H__
+#define __G_SOCKET_SERVICE_H__
+
+#include <gio/gsocketlistener.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_SOCKET_SERVICE                               (g_socket_service_get_type ())
+#define G_SOCKET_SERVICE(inst)                              (G_TYPE_CHECK_INSTANCE_CAST ((inst),                     \
+                                                             G_TYPE_SOCKET_SERVICE, GSocketService))
+#define G_SOCKET_SERVICE_CLASS(class)                       (G_TYPE_CHECK_CLASS_CAST ((class),                       \
+                                                             G_TYPE_SOCKET_SERVICE, GSocketServiceClass))
+#define G_IS_SOCKET_SERVICE(inst)                           (G_TYPE_CHECK_INSTANCE_TYPE ((inst),                     \
+                                                             G_TYPE_SOCKET_SERVICE))
+#define G_IS_SOCKET_SERVICE_CLASS(class)                    (G_TYPE_CHECK_CLASS_TYPE ((class),                       \
+                                                             G_TYPE_SOCKET_SERVICE))
+#define G_SOCKET_SERVICE_GET_CLASS(inst)                    (G_TYPE_INSTANCE_GET_CLASS ((inst),                      \
+                                                             G_TYPE_SOCKET_SERVICE, GSocketServiceClass))
+
+typedef struct _GSocketServicePrivate                       GSocketServicePrivate;
+typedef struct _GSocketServiceClass                         GSocketServiceClass;
+
+/**
+ * GSocketServiceClass:
+ * @incomming: signal emitted when new connections are accepted
+ **/
+struct _GSocketServiceClass
+{
+  GSocketListenerClass parent_class;
+
+  gboolean (* incoming) (GSocketService    *service,
+                         GSocketConnection *connection,
+			 GObject           *source_object);
+
+  /* Padding for future expansion */
+  void (*_g_reserved1) (void);
+  void (*_g_reserved2) (void);
+  void (*_g_reserved3) (void);
+  void (*_g_reserved4) (void);
+  void (*_g_reserved5) (void);
+  void (*_g_reserved6) (void);
+};
+
+struct _GSocketService
+{
+  GSocketListener parent_instance;
+  GSocketServicePrivate *priv;
+};
+
+GType           g_socket_service_get_type  (void);
+
+GSocketService *g_socket_service_new       (void);
+void            g_socket_service_start     (GSocketService *service);
+void            g_socket_service_stop      (GSocketService *service);
+gboolean        g_socket_service_is_active (GSocketService *service);
+
+
+G_END_DECLS
+
+#endif /* __G_SOCKET_SERVICE_H__ */
diff --git a/gio/gtcpconnection.c b/gio/gtcpconnection.c
new file mode 100644
index 0000000..bd1c411
--- /dev/null
+++ b/gio/gtcpconnection.c
@@ -0,0 +1,67 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright © 2008, 2009 Codethink Limited
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the licence or (at
+ * your option) any later version.
+ *
+ * See the included COPYING file for more information.
+ */
+
+/**
+ * SECTION: gtcpconnection
+ * @title: GTcpConnection
+ * @short_description: a TCP #GSocketConnection
+ * @see_also: #GSocketConnection.
+ *
+ * This is the subclass of #GSocketConnection that is created
+ * for TCP/IP sockets.
+ *
+ * It is currently empty; it offers no additional functionality
+ * over its base class.
+ *
+ * Eventually, some TCP-specific socket stuff will be added.
+ *
+ * Since: 2.22
+ **/
+
+#include "config.h"
+#include "gtcpconnection.h"
+#include "glibintl.h"
+
+#include "gioalias.h"
+
+G_DEFINE_TYPE_WITH_CODE (GTcpConnection, g_tcp_connection,
+			 G_TYPE_SOCKET_CONNECTION,
+  g_socket_connection_factory_register_type (g_define_type_id,
+					     G_SOCKET_FAMILY_IPV4,
+					     G_SOCKET_TYPE_STREAM,
+					     0);
+  g_socket_connection_factory_register_type (g_define_type_id,
+					     G_SOCKET_FAMILY_IPV6,
+					     G_SOCKET_TYPE_STREAM,
+					     0);
+  g_socket_connection_factory_register_type (g_define_type_id,
+					     G_SOCKET_FAMILY_IPV4,
+					     G_SOCKET_TYPE_STREAM,
+					     g_socket_protocol_id_lookup_by_name ("tcp"));
+  g_socket_connection_factory_register_type (g_define_type_id,
+					     G_SOCKET_FAMILY_IPV6,
+					     G_SOCKET_TYPE_STREAM,
+					     g_socket_protocol_id_lookup_by_name ("tcp"));
+			 );
+
+static void
+g_tcp_connection_init (GTcpConnection *connection)
+{
+}
+
+static void
+g_tcp_connection_class_init (GTcpConnectionClass *class)
+{
+}
+
+#define __G_TCP_CONNECTION_C__
+#include "gioaliasdef.c"
diff --git a/gio/gtcpconnection.h b/gio/gtcpconnection.h
new file mode 100644
index 0000000..a9eed5d
--- /dev/null
+++ b/gio/gtcpconnection.h
@@ -0,0 +1,64 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright © 2008, 2009 Codethink Limited
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the licence or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Ryan Lortie <desrt desrt ca>
+ */
+
+#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
+#error "Only <gio/gio.h> can be included directly."
+#endif
+
+#ifndef __G_TCP_CONNECTION_H__
+#define __G_TCP_CONNECTION_H__
+
+#include <gio/gsocketconnection.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_TCP_CONNECTION                               (g_tcp_connection_get_type ())
+#define G_TCP_CONNECTION(inst)                              (G_TYPE_CHECK_INSTANCE_CAST ((inst),                     \
+                                                             G_TYPE_TCP_CONNECTION, GTcpConnection))
+#define G_TCP_CONNECTION_CLASS(class)                       (G_TYPE_CHECK_CLASS_CAST ((class),                       \
+                                                             G_TYPE_TCP_CONNECTION, GTcpConnectionClass))
+#define G_IS_TCP_CONNECTION(inst)                           (G_TYPE_CHECK_INSTANCE_TYPE ((inst),                     \
+                                                             G_TYPE_TCP_CONNECTION))
+#define G_IS_TCP_CONNECTION_CLASS(class)                    (G_TYPE_CHECK_CLASS_TYPE ((class),                       \
+                                                             G_TYPE_TCP_CONNECTION))
+#define G_TCP_CONNECTION_GET_CLASS(inst)                    (G_TYPE_INSTANCE_GET_CLASS ((inst),                      \
+                                                             G_TYPE_TCP_CONNECTION, GTcpConnectionClass))
+
+typedef struct _GTcpConnectionPrivate                       GTcpConnectionPrivate;
+typedef struct _GTcpConnectionClass                         GTcpConnectionClass;
+
+struct _GTcpConnectionClass
+{
+  GSocketConnectionClass parent_class;
+};
+
+struct _GTcpConnection
+{
+  GSocketConnection parent_instance;
+  GTcpConnectionPrivate *priv;
+};
+
+GType                   g_tcp_connection_get_type                       (void);
+
+G_END_DECLS
+
+#endif /* __G_TCP_CONNECTION_H__ */
diff --git a/gio/gthreadedsocketservice.c b/gio/gthreadedsocketservice.c
new file mode 100644
index 0000000..182d1b1
--- /dev/null
+++ b/gio/gthreadedsocketservice.c
@@ -0,0 +1,215 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright © 2009 Codethink Limited
+ * Copyright © 2009 Red Hat, Inc
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the licence or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Ryan Lortie <desrt desrt ca>
+ *          Alexander Larsson <alexl redhat com>
+ */
+
+/**
+ * SECTION: gthreadedsocketservice
+ * @title: GThreadedSocketService
+ * @short_description: a threaded #GSocketService
+ * @see_also: #GSocketService.
+ *
+ * A #GThreadedSocketService is a simple subclass of #GSocketService
+ * that handles incoming connections by creating a worker thread and
+ * dispatching the connection to it by emitting the ::run signal in
+ * the new thread.
+ *
+ * The signal handler may perform blocking IO and need not return
+ * until the connection is closed.
+ *
+ * The service is implemented using a thread pool, so there is a
+ * limited amount of threads availible to serve incomming requests.
+ * The service automatically stops the #GSocketService from accepting
+ * new connections when all threads are busy.
+ *
+ * As with #GSocketService, you may connect to ::run, or subclass and
+ * override the default handler.
+ */
+
+#include "config.h"
+#include "gsocketconnection.h"
+#include "gthreadedsocketservice.h"
+
+#include "gio-marshal.h"
+
+#include "gioalias.h"
+
+static guint g_threaded_socket_service_run_signal;
+
+G_DEFINE_TYPE (GThreadedSocketService,
+               g_threaded_socket_service,
+               G_TYPE_SOCKET_SERVICE);
+
+G_LOCK_DEFINE_STATIC(job_count);
+
+struct _GThreadedSocketServicePrivate
+{
+  GThreadPool *thread_pool;
+  int max_threads;
+  gint job_count;
+};
+
+typedef struct
+{
+  GThreadedSocketService *service;
+  GSocketConnection *connection;
+  GObject *source_object;
+} GThreadedSocketServiceData;
+
+static void
+g_threaded_socket_service_func (gpointer _data,
+				gpointer user_data)
+{
+  GThreadedSocketService *threaded = user_data;
+  GThreadedSocketServiceData *data = _data;
+  gboolean result;
+
+  g_signal_emit (data->service, g_threaded_socket_service_run_signal,
+                 0, data->connection, data->source_object, &result);
+
+  g_object_unref (data->service);
+  g_object_unref (data->connection);
+  if (data->source_object)
+    g_object_unref (data->source_object);
+  g_slice_free (GThreadedSocketServiceData, data);
+
+  G_LOCK (job_count);
+  if (threaded->priv->job_count-- == threaded->priv->max_threads)
+    g_socket_service_start (G_SOCKET_SERVICE (threaded));
+  G_UNLOCK (job_count);
+}
+
+static gboolean
+g_threaded_socket_service_incoming (GSocketService    *service,
+                                    GSocketConnection *connection,
+                                    GObject           *source_object)
+{
+  GThreadedSocketService *threaded;
+  GThreadedSocketServiceData *data;
+
+  threaded = G_THREADED_SOCKET_SERVICE (service);
+
+  data = g_slice_new (GThreadedSocketServiceData);
+  data->service = g_object_ref (service);
+  data->connection = g_object_ref (connection);
+  if (source_object)
+    data->source_object = g_object_ref (source_object);
+  else
+    data->source_object = NULL;
+
+  G_LOCK (job_count);
+  if (++threaded->priv->job_count == threaded->priv->max_threads)
+    g_socket_service_stop (service);
+  G_UNLOCK (job_count);
+
+  g_thread_pool_push (threaded->priv->thread_pool, data, NULL);
+
+
+
+  return FALSE;
+}
+
+static void
+g_threaded_socket_service_init (GThreadedSocketService *service)
+{
+  service->priv = G_TYPE_INSTANCE_GET_PRIVATE (service,
+					       G_TYPE_THREADED_SOCKET_SERVICE,
+					       GThreadedSocketServicePrivate);
+  service->priv->max_threads = 10;
+}
+
+static void
+g_threaded_socket_service_constructed (GObject *object)
+{
+  GThreadedSocketService *service = G_THREADED_SOCKET_SERVICE (object);
+
+  service->priv->thread_pool =
+    g_thread_pool_new  (g_threaded_socket_service_func,
+			service,
+			service->priv->max_threads,
+			FALSE,
+			NULL);
+}
+
+
+static void
+g_threaded_socket_service_finalize (GObject *object)
+{
+  GThreadedSocketService *service = G_THREADED_SOCKET_SERVICE (object);
+
+  g_object_unref (service->priv->thread_pool);
+
+  G_OBJECT_CLASS (g_threaded_socket_service_parent_class)
+    ->finalize (object);
+}
+
+
+static void
+g_threaded_socket_service_class_init (GThreadedSocketServiceClass *class)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+  GSocketServiceClass *ss_class = &class->parent_class;
+
+  g_type_class_add_private (class, sizeof (GThreadedSocketServicePrivate));
+
+  gobject_class->constructed = g_threaded_socket_service_constructed;
+  gobject_class->finalize = g_threaded_socket_service_finalize;
+
+  ss_class->incoming = g_threaded_socket_service_incoming;
+
+  /**
+   * GThreadedSocketService::run:
+   * @service: the #GThreadedSocketService.
+   * @connection: a new #GSocketConnection object.
+   * @source_object: the source_object passed to g_socket_listener_add_address().
+   * @returns: %TRUE if @connection has been handled.
+   *
+   * The ::run signal is emitted in a worker thread in response to an
+   * incoming connection.  This thread is dedicated to handling
+   * @connection and may perform blocking IO.  The signal handler need
+   * not return until the connection is closed.
+   *
+   * If %TRUE is returned then no other handlers are called.
+   **/
+  g_threaded_socket_service_run_signal =
+    g_signal_new ("run", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (GThreadedSocketServiceClass, run),
+                  g_signal_accumulator_true_handled, NULL,
+                  _gio_marshal_BOOLEAN__OBJECT_OBJECT, G_TYPE_BOOLEAN,
+                  2, G_TYPE_SOCKET_CONNECTION, G_TYPE_OBJECT);
+}
+
+/**
+ * g_threaded_socket_service_new:
+ * @returns: a new #GSocketService.
+ *
+ * Creates a new #GThreadedSocketService with no listeners.  Listeners
+ * must be added with g_socket_service_add_listeners().
+ **/
+GSocketService *
+g_threaded_socket_service_new (void)
+{
+  return g_object_new (G_TYPE_THREADED_SOCKET_SERVICE, NULL);
+}
+
+#define __G_THREADED_SOCKET_SERVICE_C__
+#include "gioaliasdef.c"
diff --git a/gio/gthreadedsocketservice.h b/gio/gthreadedsocketservice.h
new file mode 100644
index 0000000..209f83c
--- /dev/null
+++ b/gio/gthreadedsocketservice.h
@@ -0,0 +1,81 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright © 2009 Codethink Limited
+ * Copyright © 2009 Red Hat, Inc
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the licence or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Ryan Lortie <desrt desrt ca>
+ *          Alexander Larsson <alexl redhat com>
+ */
+
+#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
+#error "Only <gio/gio.h> can be included directly."
+#endif
+
+#ifndef __G_THREADED_SOCKET_SERVICE_H__
+#define __G_THREADED_SOCKET_SERVICE_H__
+
+#include <gio/gsocketservice.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_THREADED_SOCKET_SERVICE                      (g_threaded_socket_service_get_type ())
+#define G_THREADED_SOCKET_SERVICE(inst)                     (G_TYPE_CHECK_INSTANCE_CAST ((inst),                     \
+                                                             G_TYPE_THREADED_SOCKET_SERVICE,                         \
+                                                             GThreadedSocketService))
+#define G_THREADED_SOCKET_SERVICE_CLASS(class)              (G_TYPE_CHECK_CLASS_CAST ((class),                       \
+                                                             G_TYPE_THREADED_SOCKET_SERVICE,                         \
+                                                             GThreadedSocketServiceClass))
+#define G_IS_THREADED_SOCKET_SERVICE(inst)                  (G_TYPE_CHECK_INSTANCE_TYPE ((inst),                     \
+                                                             G_TYPE_THREADED_SOCKET_SERVICE))
+#define G_IS_THREADED_SOCKET_SERVICE_CLASS(class)           (G_TYPE_CHECK_CLASS_TYPE ((class),                       \
+                                                             G_TYPE_THREADED_SOCKET_SERVICE))
+#define G_THREADED_SOCKET_SERVICE_GET_CLASS(inst)           (G_TYPE_INSTANCE_GET_CLASS ((inst),                      \
+                                                             G_TYPE_THREADED_SOCKET_SERVICE,                         \
+                                                             GThreadedSocketServiceClass))
+
+typedef struct _GThreadedSocketServicePrivate               GThreadedSocketServicePrivate;
+typedef struct _GThreadedSocketServiceClass                 GThreadedSocketServiceClass;
+
+struct _GThreadedSocketServiceClass
+{
+  GSocketServiceClass parent_class;
+
+  gboolean (* run) (GThreadedSocketService *service,
+                    GSocketConnection      *connection,
+                    GObject                *source_object);
+
+  /* Padding for future expansion */
+  void (*_g_reserved1) (void);
+  void (*_g_reserved2) (void);
+  void (*_g_reserved3) (void);
+  void (*_g_reserved4) (void);
+  void (*_g_reserved5) (void);
+};
+
+struct _GThreadedSocketService
+{
+  GSocketService parent_instance;
+  GThreadedSocketServicePrivate *priv;
+};
+
+GType                   g_threaded_socket_service_get_type              (void);
+GSocketService *        g_threaded_socket_service_new                   (void);
+
+G_END_DECLS
+
+#endif /* __G_THREADED_SOCKET_SERVICE_H__ */
diff --git a/gio/gunixconnection.c b/gio/gunixconnection.c
new file mode 100644
index 0000000..b741651
--- /dev/null
+++ b/gio/gunixconnection.c
@@ -0,0 +1,293 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright © 2009 Codethink Limited
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the licence or (at
+ * your option) any later version.
+ *
+ * See the included COPYING file for more information.
+ *
+ * Authors: Ryan Lortie <desrt desrt ca>
+ */
+
+#include "config.h"
+#include "gunixconnection.h"
+#include "glibintl.h"
+
+/**
+ * SECTION: gunixconnection
+ * @title: GUnixConnection
+ * @short_description: a TCP #GSocketConnection
+ * @see_also: #GSocketConnection.
+ *
+ * This is the subclass of #GSocketConnection that is created
+ * for UNIX domain sockets.
+ *
+ * It contains functions to do some of the unix socket specific
+ * functionallity like passing file descriptors.
+ *
+ * Since: 2.22
+ **/
+
+#include <gio/gsocketcontrolmessage.h>
+#include <gio/gunixfdmessage.h>
+#include <gio/gsocket.h>
+#include <unistd.h>
+
+#include "gioalias.h"
+
+G_DEFINE_TYPE_WITH_CODE (GUnixConnection, g_unix_connection,
+			 G_TYPE_SOCKET_CONNECTION,
+  g_socket_connection_factory_register_type (g_define_type_id,
+					     G_SOCKET_FAMILY_UNIX,
+					     G_SOCKET_TYPE_STREAM,
+					     0);
+			 );
+
+/**
+ * g_unix_connection_send_fd:
+ * @connection: a #GUnixConnection.
+ * @fd: a file descriptor
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @error: #GError for error reporting, or %NULL to ignore.
+ *
+ * Passes a file descriptor to the recieving side of the
+ * connection. The recieving end has to call g_unix_connection_receive_fd()
+ * to accept the file descriptor.
+ *
+ * As well as sending the fd this also writes a single byte to the
+ * stream, as this is required for fd passing to work on some
+ * implementations.
+ *
+ * Returns: a %TRUE on success, %NULL on error.
+ *
+ * Since: 2.22
+ **/
+gboolean
+g_unix_connection_send_fd (GUnixConnection  *connection,
+                           gint              fd,
+                           GCancellable     *cancellable,
+                           GError          **error)
+{
+  GSocketControlMessage *scm;
+  GSocket *socket;
+
+  g_return_val_if_fail (G_IS_UNIX_CONNECTION (connection), FALSE);
+  g_return_val_if_fail (fd >= 0, FALSE);
+
+  scm = g_unix_fd_message_new ();
+
+  if (!g_unix_fd_message_append_fd (G_UNIX_FD_MESSAGE (scm), fd, error))
+    {
+      g_object_unref (scm);
+      return FALSE;
+    }
+
+  g_object_get (connection, "socket", &socket, NULL);
+  if (!g_socket_condition_wait (socket, G_IO_OUT, cancellable, error) ||
+      g_socket_send_message (socket, NULL, NULL, 0, &scm, 1, 0, error) != 1)
+    /* XXX could it 'fail' with zero? */
+    {
+      g_object_unref (socket);
+      g_object_unref (scm);
+
+      return FALSE;
+    }
+
+  g_object_unref (socket);
+  g_object_unref (scm);
+
+  return TRUE;
+}
+
+/**
+ * g_unix_connection_receive_fd:
+ * @connection: a #GUnixConnection.
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @error: #GError for error reporting, or %NULL to ignore.
+ *
+ * Recieves a file descriptor from the sending end of the
+ * connection. The sending end has to call g_unix_connection_send_fd()
+ * for this to work.
+ *
+ * As well as reading the fd this also reads a single byte from the
+ * stream, as this is required for fd passing to work on some
+ * implementations.
+ *
+ * Returns: a file descriptor on success, -1 on error.
+ *
+ * Since: 2.22
+ **/
+gint
+g_unix_connection_receive_fd (GUnixConnection  *connection,
+                              GCancellable     *cancellable,
+                              GError          **error)
+{
+  GSocketControlMessage **scms;
+  gint *fds, nfd, fd, nscm;
+  GUnixFDMessage *fdmsg;
+  GSocket *socket;
+
+  g_return_val_if_fail (G_IS_UNIX_CONNECTION (connection), -1);
+
+  g_object_get (connection, "socket", &socket, NULL);
+  if (!g_socket_condition_wait (socket, G_IO_IN, cancellable, error) ||
+      g_socket_receive_message (socket, NULL, NULL, 0,
+                                &scms, &nscm, NULL, error) != 1)
+    /* XXX it _could_ 'fail' with zero. */
+    {
+      g_object_unref (socket);
+
+      return -1;
+    }
+
+  g_object_unref (socket);
+
+  if (nscm != 1)
+    {
+      gint i;
+
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+		   _("Expecting 1 control message, got %d"), nscm);
+
+      for (i = 0; i < nscm; i++)
+        g_object_unref (scms[i]);
+
+      g_free (scms);
+
+      return -1;
+    }
+
+  if (!G_IS_UNIX_FD_MESSAGE (scms[0]))
+    {
+      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+			   _("Unexpected type of ancillary data"));
+      g_object_unref (scms[0]);
+      g_free (scms);
+
+      return -1;
+    }
+
+  fdmsg = G_UNIX_FD_MESSAGE (scms[0]);
+  g_free (scms);
+
+  fds = g_unix_fd_message_steal_fds (fdmsg, &nfd);
+  g_object_unref (fdmsg);
+
+  if (nfd != 1)
+    {
+      gint i;
+
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+		   _("Expecting one fd, but got %d\n"), nfd);
+
+      for (i = 0; i < nfd; i++)
+        close (fds[i]);
+
+      g_free (fds);
+
+      return -1;
+    }
+
+  fd = *fds;
+  g_free (fds);
+
+  if (fd < 0)
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+		   _("Received invalid fd"));
+      fd = -1;
+    }
+
+  return fd;
+}
+
+static void
+g_unix_connection_init (GUnixConnection *connection)
+{
+}
+
+static void
+g_unix_connection_class_init (GUnixConnectionClass *class)
+{
+}
+
+/* TODO: Other stuff we might want to add are:
+void                    g_unix_connection_send_fd_async                 (GUnixConnection      *connection,
+                                                                         gint                  fd,
+                                                                         gboolean              close,
+                                                                         gint                  io_priority,
+                                                                         GAsyncReadyCallback   callback,
+                                                                         gpointer              user_data);
+gboolean                g_unix_connection_send_fd_finish                (GUnixConnection      *connection,
+                                                                         GError              **error);
+
+gboolean                g_unix_connection_send_fds                      (GUnixConnection      *connection,
+                                                                         gint                 *fds,
+                                                                         gint                  nfds,
+                                                                         GError              **error);
+void                    g_unix_connection_send_fds_async                (GUnixConnection      *connection,
+                                                                         gint                 *fds,
+                                                                         gint                  nfds,
+                                                                         gint                  io_priority,
+                                                                         GAsyncReadyCallback   callback,
+                                                                         gpointer              user_data);
+gboolean                g_unix_connection_send_fds_finish               (GUnixConnection      *connection,
+                                                                         GError              **error);
+
+void                    g_unix_connection_receive_fd_async              (GUnixConnection      *connection,
+                                                                         gint                  io_priority,
+                                                                         GAsyncReadyCallback   callback,
+                                                                         gpointer              user_data);
+gint                    g_unix_connection_receive_fd_finish             (GUnixConnection      *connection,
+                                                                         GError              **error);
+
+
+gboolean                g_unix_connection_send_credentials              (GUnixConnection      *connection,
+                                                                         GError              **error);
+void                    g_unix_connection_send_credentials_async        (GUnixConnection      *connection,
+                                                                         gint                  io_priority,
+                                                                         GAsyncReadyCallback   callback,
+                                                                         gpointer              user_data);
+gboolean                g_unix_connection_send_credentials_finish       (GUnixConnection      *connection,
+                                                                         GError              **error);
+
+gboolean                g_unix_connection_send_fake_credentials         (GUnixConnection      *connection,
+                                                                         guint64               pid,
+                                                                         guint64               uid,
+                                                                         guint64               gid,
+                                                                         GError              **error);
+void                    g_unix_connection_send_fake_credentials_async   (GUnixConnection      *connection,
+                                                                         guint64               pid,
+                                                                         guint64               uid,
+                                                                         guint64               gid,
+                                                                         gint                  io_priority,
+                                                                         GAsyncReadyCallback   callback,
+                                                                         gpointer              user_data);
+gboolean                g_unix_connection_send_fake_credentials_finish  (GUnixConnection      *connection,
+                                                                         GError              **error);
+
+gboolean                g_unix_connection_receive_credentials           (GUnixConnection      *connection,
+                                                                         guint64              *pid,
+                                                                         guint64              *uid,
+                                                                         guint64              *gid,
+                                                                         GError              **error);
+void                    g_unix_connection_receive_credentials_async     (GUnixConnection      *connection,
+                                                                         gint                  io_priority,
+                                                                         GAsyncReadyCallback   callback,
+                                                                         gpointer              user_data);
+gboolean                g_unix_connection_receive_credentials_finish    (GUnixConnection      *connection,
+                                                                         guint64              *pid,
+                                                                         guint64              *uid,
+                                                                         guint64              *gid,
+                                                                         GError              **error);
+
+gboolean                g_unix_connection_create_pair                   (GUnixConnection     **one,
+                                                                         GUnixConnection     **two,
+                                                                         GError              **error);
+*/
+
+#define __G_UNIX_CONNECTION_C__
+#include "gioaliasdef.c"
diff --git a/gio/gunixconnection.h b/gio/gunixconnection.h
new file mode 100644
index 0000000..b51ef90
--- /dev/null
+++ b/gio/gunixconnection.h
@@ -0,0 +1,77 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright © 2009 Codethink Limited
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the licence or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Ryan Lortie <desrt desrt ca>
+ */
+
+#ifndef __G_UNIX_CONNECTION_H__
+#define __G_UNIX_CONNECTION_H__
+
+#include <gio/gsocketconnection.h>
+#include <gio/giotypes.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_UNIX_CONNECTION                              (g_unix_connection_get_type ())
+#define G_UNIX_CONNECTION(inst)                             (G_TYPE_CHECK_INSTANCE_CAST ((inst),                     \
+                                                             G_TYPE_UNIX_CONNECTION, GUnixConnection))
+#define G_UNIX_CONNECTION_CLASS(class)                      (G_TYPE_CHECK_CLASS_CAST ((class),                       \
+                                                             G_TYPE_UNIX_CONNECTION, GUnixConnectionClass))
+#define G_IS_UNIX_CONNECTION(inst)                          (G_TYPE_CHECK_INSTANCE_TYPE ((inst),                     \
+                                                             G_TYPE_UNIX_CONNECTION))
+#define G_IS_UNIX_CONNECTION_CLASS(class)                   (G_TYPE_CHECK_CLASS_TYPE ((class),                       \
+                                                             G_TYPE_UNIX_CONNECTION))
+#define G_UNIX_CONNECTION_GET_CLASS(inst)                   (G_TYPE_INSTANCE_GET_CLASS ((inst),                      \
+                                                             G_TYPE_UNIX_CONNECTION, GUnixConnectionClass))
+
+/**
+ * GTcpConnection:
+ *
+ * A #GSocketConnection for UNIX domain socket connections.
+ *
+ * Since: 2.22
+ **/
+typedef struct _GUnixConnection                             GUnixConnection;
+typedef struct _GUnixConnectionPrivate                      GUnixConnectionPrivate;
+typedef struct _GUnixConnectionClass                        GUnixConnectionClass;
+
+struct _GUnixConnectionClass
+{
+  GSocketConnectionClass parent_class;
+};
+
+struct _GUnixConnection
+{
+  GSocketConnection parent_instance;
+  GUnixConnectionPrivate *priv;
+};
+
+GType                   g_unix_connection_get_type                      (void);
+
+gboolean                g_unix_connection_send_fd                       (GUnixConnection      *connection,
+                                                                         gint                  fd,
+                                                                         GCancellable         *cancellable,
+                                                                         GError              **error);
+gint                    g_unix_connection_receive_fd                    (GUnixConnection      *connection,
+                                                                         GCancellable         *cancellable,
+                                                                         GError              **error);
+
+G_END_DECLS
+
+#endif /* __G_UNIX_CONNECTION_H__ */



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