Import all the highlevel socket classes from gnio

This commit is contained in:
Alexander Larsson 2009-05-15 21:26:24 +02:00
parent 2597e3adc3
commit ce8361217c
23 changed files with 4550 additions and 3 deletions

View File

@ -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 \

View File

@ -2,3 +2,4 @@ VOID:STRING,STRING,STRING,FLAGS
VOID:STRING,BOXED
VOID:BOOLEAN,POINTER
VOID:OBJECT,OBJECT,ENUM
BOOLEAN:OBJECT,OBJECT

View File

@ -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>

View File

@ -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

View File

@ -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 */

912
gio/gsocketclient.c Normal file
View File

@ -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"

115
gio/gsocketclient.h Normal file
View File

@ -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___ */

474
gio/gsocketconnection.c Normal file
View File

@ -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"

91
gio/gsocketconnection.h Normal file
View File

@ -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__ */

259
gio/gsocketinputstream.c Normal file
View File

@ -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));
}

58
gio/gsocketinputstream.h Normal file
View File

@ -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___ */

815
gio/gsocketlistener.c Normal file
View File

@ -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"

134
gio/gsocketlistener.h Normal file
View File

@ -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__ */

259
gio/gsocketoutputstream.c Normal file
View File

@ -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));
}

58
gio/gsocketoutputstream.h Normal file
View File

@ -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__ */

330
gio/gsocketservice.c Normal file
View File

@ -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"

88
gio/gsocketservice.h Normal file
View File

@ -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__ */

67
gio/gtcpconnection.c Normal file
View File

@ -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"

64
gio/gtcpconnection.h Normal file
View File

@ -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__ */

View File

@ -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"

View File

@ -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__ */

293
gio/gunixconnection.c Normal file
View File

@ -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"

77
gio/gunixconnection.h Normal file
View File

@ -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__ */