mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-24 14:36:13 +01:00
Import all the highlevel socket classes from gnio
This commit is contained in:
parent
2597e3adc3
commit
ce8361217c
@ -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 \
|
||||
|
@ -2,3 +2,4 @@ VOID:STRING,STRING,STRING,FLAGS
|
||||
VOID:STRING,BOXED
|
||||
VOID:BOOLEAN,POINTER
|
||||
VOID:OBJECT,OBJECT,ENUM
|
||||
BOOLEAN:OBJECT,OBJECT
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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
912
gio/gsocketclient.c
Normal 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
115
gio/gsocketclient.h
Normal 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
474
gio/gsocketconnection.c
Normal 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
91
gio/gsocketconnection.h
Normal 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
259
gio/gsocketinputstream.c
Normal 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
58
gio/gsocketinputstream.h
Normal 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
815
gio/gsocketlistener.c
Normal 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
134
gio/gsocketlistener.h
Normal 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
259
gio/gsocketoutputstream.c
Normal 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
58
gio/gsocketoutputstream.h
Normal 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
330
gio/gsocketservice.c
Normal 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
88
gio/gsocketservice.h
Normal 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
67
gio/gtcpconnection.c
Normal 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
64
gio/gtcpconnection.h
Normal 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__ */
|
215
gio/gthreadedsocketservice.c
Normal file
215
gio/gthreadedsocketservice.c
Normal 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"
|
81
gio/gthreadedsocketservice.h
Normal file
81
gio/gthreadedsocketservice.h
Normal 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
293
gio/gunixconnection.c
Normal 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
77
gio/gunixconnection.h
Normal 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__ */
|
Loading…
Reference in New Issue
Block a user