[glib] Import all the highlevel socket classes from gnio
- From: Alexander Larsson <alexl src gnome org>
- To: svn-commits-list gnome org
- Subject: [glib] Import all the highlevel socket classes from gnio
- Date: Fri, 15 May 2009 15:35:56 -0400 (EDT)
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]