<xi:include href="xml/ginetsocketaddress.xml"/>
<xi:include href="xml/gunixsocketaddress.xml"/>
<xi:include href="xml/gsrvtarget.xml"/>
+ <xi:include href="xml/gsocketconnectable.xml"/>
+ <xi:include href="xml/gnetworkaddress.xml"/>
+ <xi:include href="xml/gnetworkservice.xml"/>
</chapter>
<chapter id="utils">
<title>Utilities</title>
<SUBSECTION Private>
g_srv_target_get_type
</SECTION>
+
+<SECTION>
+<FILE>gsocketconnectable</FILE>
+<TITLE>GSocketConnectable</TITLE>
+GSocketConnectable
+GSocketConnectableIface
+g_socket_connectable_enumerate
+<SUBSECTION>
+GSocketAddressEnumerator
+g_socket_address_enumerator_next
+g_socket_address_enumerator_next_async
+g_socket_address_enumerator_next_finish
+<SUBSECTION Standard>
+G_IS_SOCKET_CONNECTABLE
+G_SOCKET_CONNECTABLE
+G_SOCKET_CONNECTABLE_GET_IFACE
+G_TYPE_SOCKET_CONNECTABLE
+GSocketAddressEnumeratorClass
+G_IS_SOCKET_ADDRESS_ENUMERATOR
+G_IS_SOCKET_ADDRESS_ENUMERATOR_CLASS
+G_SOCKET_ADDRESS_ENUMERATOR
+G_SOCKET_ADDRESS_ENUMERATOR_CLASS
+G_SOCKET_ADDRESS_ENUMERATOR_GET_CLASS
+G_TYPE_SOCKET_ADDRESS_ENUMERATOR
+<SUBSECTION Private>
+g_socket_address_enumerator_get_type
+g_socket_connectable_get_type
+</SECTION>
+
+<SECTION>
+<FILE>gnetworkaddress</FILE>
+<TITLE>GNetworkAddress</TITLE>
+GNetworkAddress
+g_network_address_new
+g_network_address_get_hostname
+g_network_address_get_ascii_name
+g_network_address_get_port
+<SUBSECTION Standard>
+GNetworkAddressClass
+GNetworkAddressPrivate
+G_IS_NETWORK_ADDRESS
+G_IS_NETWORK_ADDRESS_CLASS
+G_NETWORK_ADDRESS
+G_NETWORK_ADDRESS_CLASS
+G_NETWORK_ADDRESS_GET_CLASS
+G_TYPE_NETWORK_ADDRESS
+<SUBSECTION Private>
+g_network_address_get_type
+</SECTION>
+
+<SECTION>
+<FILE>gnetworkservice</FILE>
+<TITLE>GNetworkService</TITLE>
+GNetworkService
+g_network_service_new
+g_network_service_get_service
+g_network_service_get_protocol
+g_network_service_get_domain
+g_network_service_get_expires
+<SUBSECTION Standard>
+GNetworkServiceClass
+GNetworkServicePrivate
+G_IS_NETWORK_SERVICE
+G_IS_NETWORK_SERVICE_CLASS
+G_NETWORK_SERVICE
+G_NETWORK_SERVICE_CLASS
+G_NETWORK_SERVICE_GET_CLASS
+G_TYPE_NETWORK_SERVICE
+<SUBSECTION Private>
+g_network_service_get_type
+</SECTION>
g_mount_operation_result_get_type
g_mount_unmount_flags_get_type
g_native_volume_monitor_get_type
+g_network_address_get_type
+g_network_service_get_type
g_output_stream_get_type
g_output_stream_splice_flags_get_type
g_password_save_get_type
g_resolver_get_type
g_seekable_get_type
g_simple_async_result_get_type
+g_socket_address_enumerator_get_type
g_socket_address_get_type
+g_socket_connectable_get_type
g_themed_icon_get_type
g_unix_input_stream_get_type
g_unix_mount_monitor_get_type
gmountoperation.c \
gnativevolumemonitor.c \
gnativevolumemonitor.h \
+ gnetworkaddress.c \
gnetworkingprivate.h \
+ gnetworkservice.c \
goutputstream.c \
gpollfilemonitor.c \
gpollfilemonitor.h \
gseekable.c \
gsimpleasyncresult.c \
gsocketaddress.c \
+ gsocketaddressenumerator.c \
+ gsocketconnectable.c \
gsrvtarget.c \
gthemedicon.c \
gthreadedresolver.c \
gmemoryoutputstream.h \
gmountoperation.h \
gnativevolumemonitor.h \
+ gnetworkaddress.h \
+ gnetworkservice.h \
goutputstream.h \
gresolver.h \
gseekable.h \
gsimpleasyncresult.h \
gsocketaddress.h \
+ gsocketaddressenumerator.h \
+ gsocketconnectable.h \
gsrvtarget.h \
gthemedicon.h \
gvfs.h \
#include <gio/gmount.h>
#include <gio/gmountoperation.h>
#include <gio/gnativevolumemonitor.h>
+#include <gio/gnetworkaddress.h>
+#include <gio/gnetworkservice.h>
#include <gio/goutputstream.h>
#include <gio/gresolver.h>
#include <gio/gseekable.h>
#include <gio/gsimpleasyncresult.h>
#include <gio/gsocketaddress.h>
+#include <gio/gsocketaddressenumerator.h>
+#include <gio/gsocketconnectable.h>
#include <gio/gsrvtarget.h>
#include <gio/gthemedicon.h>
#include <gio/gvfs.h>
g_srv_target_list_sort
#endif
#endif
+
+#if IN_HEADER(__G_NETWORK_ADDRESS_H__)
+#if IN_FILE(__G_NETWORK_ADDRESS_C__)
+g_network_address_get_type G_GNUC_CONST
+g_network_address_get_hostname
+g_network_address_get_port
+g_network_address_new
+#endif
+#endif
+
+#if IN_HEADER(__G_NETWORK_SERVICE_H__)
+#if IN_FILE(__G_NETWORK_SERVICE_C__)
+g_network_service_get_type G_GNUC_CONST
+g_network_service_get_service
+g_network_service_get_protocol
+g_network_service_get_domain
+g_network_service_new
+#endif
+#endif
+
+#if IN_HEADER(__G_SOCKET_CONNECTABLE_H__)
+#if IN_FILE(__G_SOCKET_CONNECTABLE_C__)
+g_socket_connectable_enumerate
+g_socket_connectable_get_type G_GNUC_CONST
+#endif
+#endif
+
+#if IN_HEADER(__G_SOCKET_ADDRESS_ENUMERATOR_H__)
+#if IN_FILE(__G_SOCKET_ADDRESS_ENUMERATOR_C__)
+g_socket_address_enumerator_get_type G_GNUC_CONST
+g_socket_address_enumerator_next
+g_socket_address_enumerator_next_async
+g_socket_address_enumerator_next_finish
+#endif
+#endif
**/
typedef struct _GMount GMount; /* Dummy typedef */
typedef struct _GMountOperation GMountOperation;
+typedef struct _GNetworkAddress GNetworkAddress;
+typedef struct _GNetworkService GNetworkService;
typedef struct _GOutputStream GOutputStream;
typedef struct _GResolver GResolver;
typedef struct _GSeekable GSeekable;
typedef struct _GSimpleAsyncResult GSimpleAsyncResult;
typedef struct _GSocketAddress GSocketAddress;
+typedef struct _GSocketAddressEnumerator GSocketAddressEnumerator;
+typedef struct _GSocketConnectable GSocketConnectable;
typedef struct _GSrvTarget GSrvTarget;
typedef struct _GThemedIcon GThemedIcon;
typedef struct _GVfs GVfs; /* Dummy typedef */
--- /dev/null
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2008 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.
+ */
+
+#include "config.h"
+#include <glib.h>
+#include "glibintl.h"
+
+#include "gnetworkaddress.h"
+#include "gasyncresult.h"
+#include "ginetaddress.h"
+#include "ginetsocketaddress.h"
+#include "gresolver.h"
+#include "gsimpleasyncresult.h"
+#include "gsocketaddressenumerator.h"
+#include "gsocketconnectable.h"
+
+#include <string.h>
+
+#include "gioalias.h"
+
+/**
+ * SECTION:gnetworkaddress
+ * @short_description: a #GSocketConnectable for resolving hostnames
+ * @include: gio/gio.h
+ *
+ * #GNetworkAddress provides an easy way to resolve a hostname and
+ * then attempt to connect to that host, handling the possibility of
+ * multiple IP addresses and multiple address families.
+ *
+ * See #GSocketConnectable for and example of using the connectable
+ * interface.
+ **/
+
+/**
+ * GNetworkAddress:
+ *
+ * A #GSocketConnectable for resolving a hostname and connecting to
+ * that host.
+ **/
+
+struct _GNetworkAddressPrivate {
+ gchar *hostname;
+ guint16 port;
+ GList *sockaddrs;
+};
+
+enum {
+ PROP_0,
+ PROP_HOSTNAME,
+ PROP_PORT,
+};
+
+static void g_network_address_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void g_network_address_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static void g_network_address_connectable_iface_init (GSocketConnectableIface *iface);
+static GSocketAddressEnumerator *g_network_address_connectable_enumerate (GSocketConnectable *connectable);
+
+G_DEFINE_TYPE_WITH_CODE (GNetworkAddress, g_network_address, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_SOCKET_CONNECTABLE,
+ g_network_address_connectable_iface_init))
+
+static void
+g_network_address_finalize (GObject *object)
+{
+ GNetworkAddress *addr = G_NETWORK_ADDRESS (object);
+
+ g_free (addr->priv->hostname);
+
+ if (addr->priv->sockaddrs)
+ {
+ GList *a;
+
+ for (a = addr->priv->sockaddrs; a; a = a->next)
+ g_object_unref (a->data);
+ g_list_free (addr->priv->sockaddrs);
+ }
+
+ G_OBJECT_CLASS (g_network_address_parent_class)->finalize (object);
+}
+
+static void
+g_network_address_class_init (GNetworkAddressClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (GNetworkAddressPrivate));
+
+ gobject_class->set_property = g_network_address_set_property;
+ gobject_class->get_property = g_network_address_get_property;
+ gobject_class->finalize = g_network_address_finalize;
+
+ g_object_class_install_property (gobject_class, PROP_HOSTNAME,
+ g_param_spec_string ("hostname",
+ P_("Hostname"),
+ P_("Hostname to resolve"),
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (gobject_class, PROP_PORT,
+ g_param_spec_uint ("port",
+ P_("Port"),
+ P_("Network port"),
+ 0, 65535, 0,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+g_network_address_connectable_iface_init (GSocketConnectableIface *connectable_iface)
+{
+ connectable_iface->enumerate = g_network_address_connectable_enumerate;
+}
+
+static void
+g_network_address_init (GNetworkAddress *addr)
+{
+ addr->priv = G_TYPE_INSTANCE_GET_PRIVATE (addr, G_TYPE_NETWORK_ADDRESS,
+ GNetworkAddressPrivate);
+}
+
+static void
+g_network_address_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GNetworkAddress *addr = G_NETWORK_ADDRESS (object);
+
+ switch (prop_id)
+ {
+ case PROP_HOSTNAME:
+ if (addr->priv->hostname)
+ g_free (addr->priv->hostname);
+ addr->priv->hostname = g_value_dup_string (value);
+ break;
+
+ case PROP_PORT:
+ addr->priv->port = g_value_get_uint (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+
+}
+
+static void
+g_network_address_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GNetworkAddress *addr = G_NETWORK_ADDRESS (object);
+
+ switch (prop_id)
+ {
+ case PROP_HOSTNAME:
+ g_value_set_string (value, addr->priv->hostname);
+ break;
+
+ case PROP_PORT:
+ g_value_set_uint (value, addr->priv->port);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+
+}
+
+static void
+g_network_address_set_addresses (GNetworkAddress *addr,
+ GList *addresses)
+{
+ GList *a;
+ GSocketAddress *sockaddr;
+
+ g_return_if_fail (addresses != NULL && addr->priv->sockaddrs == NULL);
+
+ for (a = addresses; a; a = a->next)
+ {
+ sockaddr = g_inet_socket_address_new (a->data, addr->priv->port);
+ addr->priv->sockaddrs = g_list_prepend (addr->priv->sockaddrs, sockaddr);
+ g_object_unref (a->data);
+ }
+ g_list_free (addresses);
+ addr->priv->sockaddrs = g_list_reverse (addr->priv->sockaddrs);
+}
+
+/**
+ * g_network_address_new:
+ * @hostname: the hostname
+ * @port: the port
+ *
+ * Creates a new #GSocketConnectable for connecting to the given
+ * @hostname and @port.
+ *
+ * Return value: the new #GNetworkAddress
+ *
+ * Since: 2.22
+ **/
+GSocketConnectable *
+g_network_address_new (const gchar *hostname,
+ guint16 port)
+{
+ return g_object_new (G_TYPE_NETWORK_ADDRESS,
+ "hostname", hostname,
+ "port", port,
+ NULL);
+}
+
+/**
+ * g_network_address_get_hostname:
+ * @addr: a #GNetworkAddress
+ *
+ * Gets @addr's hostname. This might be either UTF-8 or ASCII-encoded,
+ * depending on what @addr was created with.
+ *
+ * Return value: @addr's hostname
+ *
+ * Since: 2.22
+ **/
+const gchar *
+g_network_address_get_hostname (GNetworkAddress *addr)
+{
+ g_return_val_if_fail (G_IS_NETWORK_ADDRESS (addr), NULL);
+
+ return addr->priv->hostname;
+}
+
+/**
+ * g_network_address_get_port:
+ * @addr: a #GNetworkAddress
+ *
+ * Gets @addr's port number
+ *
+ * Return value: @addr's port (which may be %0)
+ *
+ * Since: 2.22
+ **/
+guint16
+g_network_address_get_port (GNetworkAddress *addr)
+{
+ g_return_val_if_fail (G_IS_NETWORK_ADDRESS (addr), 0);
+
+ return addr->priv->port;
+}
+
+#define G_TYPE_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (_g_network_address_address_enumerator_get_type ())
+#define G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_NETWORK_ADDRESS_ADDRESS_ENUMERATOR, GNetworkAddressAddressEnumerator))
+
+typedef struct {
+ GSocketAddressEnumerator parent_instance;
+
+ GNetworkAddress *addr;
+ GList *a;
+} GNetworkAddressAddressEnumerator;
+
+typedef struct {
+ GSocketAddressEnumeratorClass parent_class;
+
+} GNetworkAddressAddressEnumeratorClass;
+
+G_DEFINE_TYPE (GNetworkAddressAddressEnumerator, _g_network_address_address_enumerator, G_TYPE_SOCKET_ADDRESS_ENUMERATOR)
+
+static void
+g_network_address_address_enumerator_finalize (GObject *object)
+{
+ GNetworkAddressAddressEnumerator *addr_enum =
+ G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (object);
+
+ g_object_unref (addr_enum->addr);
+
+ G_OBJECT_CLASS (_g_network_address_address_enumerator_parent_class)->finalize (object);
+}
+
+static GSocketAddress *
+g_network_address_address_enumerator_next (GSocketAddressEnumerator *enumerator,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GNetworkAddressAddressEnumerator *addr_enum =
+ G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (enumerator);
+ GSocketAddress *sockaddr;
+
+ if (!addr_enum->addr->priv->sockaddrs)
+ {
+ GResolver *resolver = g_resolver_get_default ();
+ GList *addresses;
+
+ addresses = g_resolver_lookup_by_name (resolver,
+ addr_enum->addr->priv->hostname,
+ cancellable, error);
+ g_object_unref (resolver);
+
+ if (!addresses)
+ return NULL;
+
+ g_network_address_set_addresses (addr_enum->addr, addresses);
+ addr_enum->a = addr_enum->addr->priv->sockaddrs;
+ }
+
+ if (!addr_enum->a)
+ return NULL;
+ else
+ {
+ sockaddr = addr_enum->a->data;
+ addr_enum->a = addr_enum->a->next;
+ return g_object_ref (sockaddr);
+ }
+}
+
+static void
+got_addresses (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple = user_data;
+ GNetworkAddressAddressEnumerator *addr_enum =
+ g_simple_async_result_get_op_res_gpointer (simple);
+ GResolver *resolver = G_RESOLVER (source_object);
+ GList *addresses;
+ GError *error = NULL;
+
+ addresses = g_resolver_lookup_by_name_finish (resolver, result, &error);
+ if (!addr_enum->addr->priv->sockaddrs)
+ {
+ if (error)
+ {
+ g_simple_async_result_set_from_error (simple, error);
+ g_error_free (error);
+ }
+ else
+ {
+ g_network_address_set_addresses (addr_enum->addr, addresses);
+ addr_enum->a = addr_enum->addr->priv->sockaddrs;
+ }
+ }
+ else if (error)
+ g_error_free (error);
+
+ g_object_unref (resolver);
+
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+}
+
+static void
+g_network_address_address_enumerator_next_async (GSocketAddressEnumerator *enumerator,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GNetworkAddressAddressEnumerator *addr_enum =
+ G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (enumerator);
+ GSimpleAsyncResult *simple;
+ GSocketAddress *sockaddr;
+
+ simple = g_simple_async_result_new (G_OBJECT (enumerator),
+ callback, user_data,
+ g_network_address_address_enumerator_next_async);
+
+ if (!addr_enum->addr->priv->sockaddrs)
+ {
+ GResolver *resolver = g_resolver_get_default ();
+
+ g_simple_async_result_set_op_res_gpointer (simple, g_object_ref (addr_enum), g_object_unref);
+ g_resolver_lookup_by_name_async (resolver,
+ addr_enum->addr->priv->hostname,
+ cancellable,
+ got_addresses, simple);
+ }
+ else
+ {
+ sockaddr = g_network_address_address_enumerator_next (enumerator, NULL, NULL);
+ if (sockaddr)
+ g_simple_async_result_set_op_res_gpointer (simple, sockaddr, g_object_unref);
+
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+ }
+}
+
+static GSocketAddress *
+g_network_address_address_enumerator_next_finish (GSocketAddressEnumerator *enumerator,
+ GAsyncResult *result,
+ GError **error)
+{
+ GNetworkAddressAddressEnumerator *addr_enum =
+ G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (enumerator);
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
+ GSocketAddress *sockaddr;
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return NULL;
+ else if (!addr_enum->a)
+ return NULL;
+ else
+ {
+ sockaddr = addr_enum->a->data;
+ addr_enum->a = addr_enum->a->next;
+ return g_object_ref (sockaddr);
+ }
+}
+
+static void
+_g_network_address_address_enumerator_init (GNetworkAddressAddressEnumerator *enumerator)
+{
+}
+
+static void
+_g_network_address_address_enumerator_class_init (GNetworkAddressAddressEnumeratorClass *addrenum_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (addrenum_class);
+ GSocketAddressEnumeratorClass *enumerator_class =
+ G_SOCKET_ADDRESS_ENUMERATOR_CLASS (addrenum_class);
+
+ enumerator_class->next = g_network_address_address_enumerator_next;
+ enumerator_class->next_async = g_network_address_address_enumerator_next_async;
+ enumerator_class->next_finish = g_network_address_address_enumerator_next_finish;
+ object_class->finalize = g_network_address_address_enumerator_finalize;
+}
+
+static GSocketAddressEnumerator *
+g_network_address_connectable_enumerate (GSocketConnectable *connectable)
+{
+ GNetworkAddressAddressEnumerator *addr_enum;
+
+ addr_enum = g_object_new (G_TYPE_NETWORK_ADDRESS_ADDRESS_ENUMERATOR, NULL);
+ addr_enum->addr = g_object_ref (connectable);
+
+ return (GSocketAddressEnumerator *)addr_enum;
+}
+
+#define __G_NETWORK_ADDRESS_C__
+#include "gioaliasdef.c"
--- /dev/null
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2008 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.
+ */
+
+#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
+#error "Only <gio/gio.h> can be included directly."
+#endif
+
+#ifndef __G_NETWORK_ADDRESS_H__
+#define __G_NETWORK_ADDRESS_H__
+
+#include <gio/giotypes.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_NETWORK_ADDRESS (g_network_address_get_type ())
+#define G_NETWORK_ADDRESS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_NETWORK_ADDRESS, GNetworkAddress))
+#define G_NETWORK_ADDRESS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_NETWORK_ADDRESS, GNetworkAddressClass))
+#define G_IS_NETWORK_ADDRESS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_NETWORK_ADDRESS))
+#define G_IS_NETWORK_ADDRESS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_NETWORK_ADDRESS))
+#define G_NETWORK_ADDRESS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_NETWORK_ADDRESS, GNetworkAddressClass))
+
+typedef struct _GNetworkAddressClass GNetworkAddressClass;
+typedef struct _GNetworkAddressPrivate GNetworkAddressPrivate;
+
+struct _GNetworkAddress
+{
+ GObject parent_instance;
+
+ /*< private >*/
+ GNetworkAddressPrivate *priv;
+};
+
+struct _GNetworkAddressClass
+{
+ GObjectClass parent_class;
+
+};
+
+GType g_network_address_get_type (void) G_GNUC_CONST;
+
+GSocketConnectable *g_network_address_new (const gchar *hostname,
+ guint16 port);
+const gchar *g_network_address_get_hostname (GNetworkAddress *addr);
+guint16 g_network_address_get_port (GNetworkAddress *addr);
+
+G_END_DECLS
+
+#endif /* __G_NETWORK_ADDRESS_H__ */
--- /dev/null
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2008 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.
+ */
+
+#include "config.h"
+#include <glib.h>
+#include "glibintl.h"
+
+#include "gnetworkservice.h"
+#include "gcancellable.h"
+#include "ginetaddress.h"
+#include "ginetsocketaddress.h"
+#include "gresolver.h"
+#include "gsimpleasyncresult.h"
+#include "gsocketaddressenumerator.h"
+#include "gsocketconnectable.h"
+#include "gsrvtarget.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "gioalias.h"
+
+/**
+ * SECTION:gnetworkservice
+ * @short_description: a #GSocketConnectable for resolving SRV records
+ * @include: gio/gio.h
+ *
+ * Like #GNetworkAddress does with hostnames, #GNetworkService
+ * provides an easy way to resolve a SRV record, and then attempt to
+ * connect to one of the hosts that implements that service, handling
+ * service priority/weighting, multiple IP addresses, and multiple
+ * address families.
+ *
+ * See #GSrvTarget for more information about SRV records, and see
+ * #GSocketConnectable for and example of using the connectable
+ * interface.
+ **/
+
+/**
+ * GNetworkService:
+ *
+ * A #GSocketConnectable for resolving a SRV record and connecting to
+ * that service.
+ **/
+
+struct _GNetworkServicePrivate
+{
+ gchar *service, *protocol, *domain;
+ GList *targets;
+};
+
+enum {
+ PROP_0,
+ PROP_SERVICE,
+ PROP_PROTOCOL,
+ PROP_DOMAIN,
+};
+
+static void g_network_service_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void g_network_service_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static void g_network_service_connectable_iface_init (GSocketConnectableIface *iface);
+static GSocketAddressEnumerator *g_network_service_connectable_enumerate (GSocketConnectable *connectable);
+
+G_DEFINE_TYPE_WITH_CODE (GNetworkService, g_network_service, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_SOCKET_CONNECTABLE,
+ g_network_service_connectable_iface_init))
+
+static void
+g_network_service_finalize (GObject *object)
+{
+ GNetworkService *srv = G_NETWORK_SERVICE (object);
+
+ g_free (srv->priv->service);
+ g_free (srv->priv->protocol);
+ g_free (srv->priv->domain);
+
+ if (srv->priv->targets)
+ g_resolver_free_targets (srv->priv->targets);
+
+ G_OBJECT_CLASS (g_network_service_parent_class)->finalize (object);
+}
+
+static void
+g_network_service_class_init (GNetworkServiceClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (GNetworkServicePrivate));
+
+ gobject_class->set_property = g_network_service_set_property;
+ gobject_class->get_property = g_network_service_get_property;
+ gobject_class->finalize = g_network_service_finalize;
+
+ g_object_class_install_property (gobject_class, PROP_SERVICE,
+ g_param_spec_string ("service",
+ P_("Service"),
+ P_("Service name, eg \"ldap\""),
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (gobject_class, PROP_PROTOCOL,
+ g_param_spec_string ("protocol",
+ P_("Protocol"),
+ P_("Network protocol, eg \"tcp\""),
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (gobject_class, PROP_DOMAIN,
+ g_param_spec_string ("domain",
+ P_("domain"),
+ P_("Network domain, eg, \"example.com\""),
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+g_network_service_connectable_iface_init (GSocketConnectableIface *connectable_iface)
+{
+ connectable_iface->enumerate = g_network_service_connectable_enumerate;
+}
+
+static void
+g_network_service_init (GNetworkService *srv)
+{
+ srv->priv = G_TYPE_INSTANCE_GET_PRIVATE (srv, G_TYPE_NETWORK_SERVICE,
+ GNetworkServicePrivate);
+}
+
+static void
+g_network_service_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GNetworkService *srv = G_NETWORK_SERVICE (object);
+
+ switch (prop_id)
+ {
+ case PROP_SERVICE:
+ srv->priv->service = g_value_dup_string (value);
+ break;
+
+ case PROP_PROTOCOL:
+ srv->priv->protocol = g_value_dup_string (value);
+ break;
+
+ case PROP_DOMAIN:
+ srv->priv->domain = g_value_dup_string (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+
+}
+
+static void
+g_network_service_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GNetworkService *srv = G_NETWORK_SERVICE (object);
+
+ switch (prop_id)
+ {
+ case PROP_SERVICE:
+ g_value_set_string (value, g_network_service_get_service (srv));
+ break;
+
+ case PROP_PROTOCOL:
+ g_value_set_string (value, g_network_service_get_protocol (srv));
+ break;
+
+ case PROP_DOMAIN:
+ g_value_set_string (value, g_network_service_get_domain (srv));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+
+}
+
+/**
+ * g_network_service_new:
+ * @service: the service type to look up (eg, "ldap")
+ * @protocol: the networking protocol to use for @service (eg, "tcp")
+ * @domain: the DNS domain to look up the service in
+ *
+ * Creates a new #GNetworkService representing the given @service,
+ * @protocol, and @domain. This will initially be unresolved; use the
+ * #GSocketConnectable interface to resolve it.
+ *
+ * Return value: a new #GNetworkService
+ *
+ * Since: 2.22
+ **/
+GSocketConnectable *
+g_network_service_new (const gchar *service,
+ const gchar *protocol,
+ const gchar *domain)
+{
+ return g_object_new (G_TYPE_NETWORK_SERVICE,
+ "service", service,
+ "protocol", protocol,
+ "domain", domain,
+ NULL);
+}
+
+/**
+ * g_network_service_get_service:
+ * @srv: a #GNetworkService
+ *
+ * Gets @srv's service name (eg, "ldap").
+ *
+ * Return value: @srv's service name
+ *
+ * Since: 2.22
+ **/
+const gchar *
+g_network_service_get_service (GNetworkService *srv)
+{
+ g_return_val_if_fail (G_IS_NETWORK_SERVICE (srv), NULL);
+
+ return srv->priv->service;
+}
+
+/**
+ * g_network_service_get_protocol:
+ * @srv: a #GNetworkService
+ *
+ * Gets @srv's protocol name (eg, "tcp").
+ *
+ * Return value: @srv's protocol name
+ *
+ * Since: 2.22
+ **/
+const gchar *
+g_network_service_get_protocol (GNetworkService *srv)
+{
+ g_return_val_if_fail (G_IS_NETWORK_SERVICE (srv), NULL);
+
+ return srv->priv->protocol;
+}
+
+/**
+ * g_network_service_get_domain:
+ * @srv: a #GNetworkService
+ *
+ * Gets the domain that @srv serves. This might be either UTF-8 or
+ * ASCII-encoded, depending on what @srv was created with.
+ *
+ * Return value: @srv's domain name
+ *
+ * Since: 2.22
+ **/
+const gchar *
+g_network_service_get_domain (GNetworkService *srv)
+{
+ g_return_val_if_fail (G_IS_NETWORK_SERVICE (srv), NULL);
+
+ return srv->priv->domain;
+}
+
+#define G_TYPE_NETWORK_SERVICE_ADDRESS_ENUMERATOR (_g_network_service_address_enumerator_get_type ())
+#define G_NETWORK_SERVICE_ADDRESS_ENUMERATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_NETWORK_SERVICE_ADDRESS_ENUMERATOR, GNetworkServiceAddressEnumerator))
+
+typedef struct {
+ GSocketAddressEnumerator parent_instance;
+
+ GResolver *resolver;
+ GNetworkService *srv;
+ GList *addrs, *a, *t;
+
+ GError *error;
+
+ /* For async operation */
+ GCancellable *cancellable;
+ GSimpleAsyncResult *result;
+} GNetworkServiceAddressEnumerator;
+
+typedef struct {
+ GSocketAddressEnumeratorClass parent_class;
+
+} GNetworkServiceAddressEnumeratorClass;
+
+G_DEFINE_TYPE (GNetworkServiceAddressEnumerator, _g_network_service_address_enumerator, G_TYPE_SOCKET_ADDRESS_ENUMERATOR)
+
+static void
+g_network_service_address_enumerator_finalize (GObject *object)
+{
+ GNetworkServiceAddressEnumerator *srv_enum =
+ G_NETWORK_SERVICE_ADDRESS_ENUMERATOR (object);
+
+ g_object_unref (srv_enum->srv);
+ if (srv_enum->addrs)
+ {
+ while (srv_enum->a)
+ {
+ g_object_unref (srv_enum->a->data);
+ srv_enum->a = srv_enum->a->next;
+ }
+ g_list_free (srv_enum->addrs);
+ }
+ g_object_unref (srv_enum->resolver);
+ if (srv_enum->error)
+ g_error_free (srv_enum->error);
+
+ G_OBJECT_CLASS (_g_network_service_address_enumerator_parent_class)->finalize (object);
+}
+
+static GSocketAddress *
+g_network_service_address_enumerator_next (GSocketAddressEnumerator *enumerator,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GNetworkServiceAddressEnumerator *srv_enum =
+ G_NETWORK_SERVICE_ADDRESS_ENUMERATOR (enumerator);
+ GSrvTarget *target;
+ GSocketAddress *sockaddr;
+
+ /* If we haven't yet resolved srv, do that */
+ if (!srv_enum->srv->priv->targets)
+ {
+ GList *targets;
+
+ targets = g_resolver_lookup_service (srv_enum->resolver,
+ srv_enum->srv->priv->service,
+ srv_enum->srv->priv->protocol,
+ srv_enum->srv->priv->domain,
+ cancellable, error);
+ if (!targets)
+ return NULL;
+
+ if (!srv_enum->srv->priv->targets)
+ srv_enum->srv->priv->targets = targets;
+ srv_enum->t = srv_enum->srv->priv->targets;
+ }
+
+ /* Make sure we have a set of resolved addresses for the current
+ * target. When resolving the first target, we save the GError, if
+ * any. If any later target succeeds, we'll free the earlier error,
+ * but if we get to the last target without any of them resolving,
+ * we return that initial error.
+ */
+ do
+ {
+ /* Return if we're out of targets. */
+ if (!srv_enum->t)
+ {
+ if (srv_enum->error)
+ {
+ g_propagate_error (error, srv_enum->error);
+ srv_enum->error = NULL;
+ }
+ return NULL;
+ }
+ target = srv_enum->t->data;
+
+ /* If we haven't resolved the addrs for the current target, do that */
+ if (!srv_enum->addrs)
+ {
+ GError **error_p;
+
+ error_p = (srv_enum->t == srv_enum->srv->priv->targets) ? &srv_enum->error : NULL;
+ srv_enum->addrs = g_resolver_lookup_by_name (srv_enum->resolver,
+ g_srv_target_get_hostname (target),
+ cancellable, error_p);
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return NULL;
+
+ if (srv_enum->addrs)
+ {
+ srv_enum->a = srv_enum->addrs;
+ if (srv_enum->error)
+ {
+ g_error_free (srv_enum->error);
+ srv_enum->error = NULL;
+ }
+ }
+ else
+ {
+ /* Try the next target */
+ srv_enum->t = srv_enum->t->next;
+ }
+ }
+ }
+ while (!srv_enum->addrs);
+
+ /* Return the next address for this target. If it's the last one,
+ * advance the target counter.
+ */
+ sockaddr = g_inet_socket_address_new (srv_enum->a->data,
+ g_srv_target_get_port (target));
+ g_object_unref (srv_enum->a->data);
+ srv_enum->a = srv_enum->a->next;
+
+ if (!srv_enum->a)
+ {
+ g_list_free (srv_enum->addrs);
+ srv_enum->addrs = NULL;
+ srv_enum->t = srv_enum->t->next;
+ }
+
+ return sockaddr;
+}
+
+static void next_async_resolved_targets (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data);
+static void next_async_have_targets (GNetworkServiceAddressEnumerator *srv_enum);
+static void next_async_resolved_addresses (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data);
+static void next_async_have_addresses (GNetworkServiceAddressEnumerator *srv_enum);
+
+/* The async version is basically the same as the sync, except we have
+ * to split it into multiple functions.
+ */
+static void
+g_network_service_address_enumerator_next_async (GSocketAddressEnumerator *enumerator,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GNetworkServiceAddressEnumerator *srv_enum =
+ G_NETWORK_SERVICE_ADDRESS_ENUMERATOR (enumerator);
+
+ g_return_if_fail (srv_enum->result == NULL);
+
+ srv_enum->result = g_simple_async_result_new (G_OBJECT (enumerator),
+ callback, user_data,
+ g_network_service_address_enumerator_next_async);
+ srv_enum->cancellable = cancellable;
+
+ /* If we haven't yet resolved srv, do that */
+ if (!srv_enum->srv->priv->targets)
+ {
+ g_resolver_lookup_service_async (srv_enum->resolver,
+ srv_enum->srv->priv->service,
+ srv_enum->srv->priv->protocol,
+ srv_enum->srv->priv->domain,
+ cancellable,
+ next_async_resolved_targets,
+ srv_enum);
+ }
+ else
+ next_async_have_targets (srv_enum);
+}
+
+static void
+next_async_resolved_targets (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GNetworkServiceAddressEnumerator *srv_enum = user_data;
+ GList *targets;
+ GError *error = NULL;
+
+ targets = g_resolver_lookup_service_finish (srv_enum->resolver, result, &error);
+ if (!srv_enum->srv->priv->targets)
+ {
+ if (error)
+ {
+ GSimpleAsyncResult *simple = srv_enum->result;
+
+ srv_enum->result = NULL;
+ g_simple_async_result_set_from_error (simple, error);
+ g_error_free (error);
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+ return;
+ }
+
+ srv_enum->srv->priv->targets = targets;
+ srv_enum->t = srv_enum->srv->priv->targets;
+ }
+
+ next_async_have_targets (srv_enum);
+}
+
+static void
+next_async_have_targets (GNetworkServiceAddressEnumerator *srv_enum)
+{
+ GSrvTarget *target;
+
+ /* Get the current target, check if we're already done. */
+ if (!srv_enum->t)
+ {
+ if (srv_enum->error)
+ {
+ g_simple_async_result_set_from_error (srv_enum->result, srv_enum->error);
+ g_error_free (srv_enum->error);
+ srv_enum->error = NULL;
+ }
+ g_simple_async_result_complete_in_idle (srv_enum->result);
+ g_object_unref (srv_enum->result);
+ srv_enum->result = NULL;
+ return;
+ }
+ target = srv_enum->t->data;
+
+ /* If we haven't resolved the addrs for the current target, do that */
+ if (!srv_enum->addrs)
+ {
+ g_resolver_lookup_by_name_async (srv_enum->resolver,
+ g_srv_target_get_hostname (target),
+ srv_enum->cancellable,
+ next_async_resolved_addresses,
+ srv_enum);
+ }
+ else
+ next_async_have_addresses (srv_enum);
+}
+
+static void
+next_async_resolved_addresses (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GNetworkServiceAddressEnumerator *srv_enum = user_data;
+ GError *error = NULL;
+
+ srv_enum->addrs = g_resolver_lookup_by_name_finish (srv_enum->resolver, result, &error);
+ if (srv_enum->addrs)
+ {
+ srv_enum->a = srv_enum->addrs;
+ if (srv_enum->error)
+ {
+ g_error_free (srv_enum->error);
+ srv_enum->error = NULL;
+ }
+ next_async_have_addresses (srv_enum);
+ }
+ else
+ {
+ if (g_cancellable_is_cancelled (srv_enum->cancellable))
+ {
+ GSimpleAsyncResult *simple = srv_enum->result;
+
+ srv_enum->result = NULL;
+ g_simple_async_result_set_from_error (srv_enum->result, error);
+ g_error_free (error);
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+ }
+ else
+ {
+ if (srv_enum->t == srv_enum->srv->priv->targets)
+ srv_enum->error = error;
+ else
+ g_error_free (error);
+
+ /* Try the next target */
+ srv_enum->t = srv_enum->t->next;
+ next_async_have_targets (srv_enum);
+ }
+ }
+}
+
+static void
+next_async_have_addresses (GNetworkServiceAddressEnumerator *srv_enum)
+{
+ GSocketAddress *sockaddr;
+ GSimpleAsyncResult *simple = srv_enum->result;
+
+ /* Return the next address for this target. If it's the last one,
+ * advance the target counter.
+ */
+ sockaddr = g_inet_socket_address_new (srv_enum->a->data,
+ g_srv_target_get_port (srv_enum->t->data));
+ g_object_unref (srv_enum->a->data);
+
+ srv_enum->a = srv_enum->a->next;
+ if (!srv_enum->a)
+ {
+ g_list_free (srv_enum->addrs);
+ srv_enum->addrs = NULL;
+ srv_enum->t = srv_enum->t->next;
+ }
+
+ srv_enum->result = NULL;
+ g_simple_async_result_set_op_res_gpointer (simple, sockaddr, NULL);
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+}
+
+static GSocketAddress *
+g_network_service_address_enumerator_next_finish (GSocketAddressEnumerator *enumerator,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
+ GSocketAddress *sockaddr;
+
+ sockaddr = g_simple_async_result_get_op_res_gpointer (simple);
+ return sockaddr ? g_object_ref (sockaddr) : NULL;
+}
+
+static void
+_g_network_service_address_enumerator_init (GNetworkServiceAddressEnumerator *enumerator)
+{
+}
+
+static void
+_g_network_service_address_enumerator_class_init (GNetworkServiceAddressEnumeratorClass *addrenum_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (addrenum_class);
+ GSocketAddressEnumeratorClass *enumerator_class =
+ G_SOCKET_ADDRESS_ENUMERATOR_CLASS (addrenum_class);
+
+ enumerator_class->next = g_network_service_address_enumerator_next;
+ enumerator_class->next_async = g_network_service_address_enumerator_next_async;
+ enumerator_class->next_finish = g_network_service_address_enumerator_next_finish;
+ object_class->finalize = g_network_service_address_enumerator_finalize;
+}
+
+static GSocketAddressEnumerator *
+g_network_service_connectable_enumerate (GSocketConnectable *connectable)
+{
+ GNetworkServiceAddressEnumerator *srv_enum;
+
+ srv_enum = g_object_new (G_TYPE_NETWORK_SERVICE_ADDRESS_ENUMERATOR, NULL);
+ srv_enum->srv = g_object_ref (connectable);
+ srv_enum->resolver = g_resolver_get_default ();
+
+ return (GSocketAddressEnumerator *)srv_enum;
+}
+
+#define __G_NETWORK_SERVICE_C__
+#include "gioaliasdef.c"
--- /dev/null
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2008 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.
+ */
+
+#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
+#error "Only <gio/gio.h> can be included directly."
+#endif
+
+#ifndef __G_NETWORK_SERVICE_H__
+#define __G_NETWORK_SERVICE_H__
+
+#include <gio/giotypes.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_NETWORK_SERVICE (g_network_service_get_type ())
+#define G_NETWORK_SERVICE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_NETWORK_SERVICE, GNetworkService))
+#define G_NETWORK_SERVICE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_NETWORK_SERVICE, GNetworkServiceClass))
+#define G_IS_NETWORK_SERVICE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_NETWORK_SERVICE))
+#define G_IS_NETWORK_SERVICE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_NETWORK_SERVICE))
+#define G_NETWORK_SERVICE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_NETWORK_SERVICE, GNetworkServiceClass))
+
+typedef struct _GNetworkServiceClass GNetworkServiceClass;
+typedef struct _GNetworkServicePrivate GNetworkServicePrivate;
+
+struct _GNetworkService
+{
+ GObject parent_instance;
+
+ /*< private >*/
+ GNetworkServicePrivate *priv;
+};
+
+struct _GNetworkServiceClass
+{
+ GObjectClass parent_class;
+
+};
+
+GType g_network_service_get_type (void) G_GNUC_CONST;
+
+GSocketConnectable *g_network_service_new (const gchar *service,
+ const gchar *protocol,
+ const gchar *domain);
+
+const gchar *g_network_service_get_service (GNetworkService *srv);
+const gchar *g_network_service_get_protocol (GNetworkService *srv);
+const gchar *g_network_service_get_domain (GNetworkService *srv);
+
+G_END_DECLS
+
+#endif /* __G_NETWORK_SERVICE_H__ */
+
* resolution, for hostnames (g_resolver_lookup_by_address(),
* g_resolver_lookup_by_name() and their async variants) and SRV
* (service) records (g_resolver_lookup_service()).
+ *
+ * #GNetworkAddress and #GNetworkService provide wrappers around
+ * #GResolver functionality that also implement #GSocketConnectable,
+ * making it easy to connect to a remote host/service.
**/
/**
* operation, in which case @error (if non-%NULL) will be set to
* %G_IO_ERROR_CANCELLED.
*
+ * If you are planning to connect to a socket on the resolved IP
+ * address, it may be easier to create a #GNetworkAddress and use its
+ * #GSocketConnectable interface.
+ *
* Return value: a #GList of #GInetAddress, or %NULL on error. You
* must unref each of the addresses and free the list when you are
* done with it. (You can use g_resolver_free_addresses() to do this.)
* operation, in which case @error (if non-%NULL) will be set to
* %G_IO_ERROR_CANCELLED.
*
+ * If you are planning to connect to the service, it is usually easier
+ * to create a #GNetworkService and use its #GSocketConnectable
+ * interface.
+ *
* Return value: a #GList of #GSrvTarget, or %NULL on error. You must
* free each of the targets and the list when you are done with it.
* (You can use g_resolver_free_targets() to do this.)
#include "ginetaddress.h"
#include "ginetsocketaddress.h"
#include "gnetworkingprivate.h"
+#include "gsocketaddressenumerator.h"
+#include "gsocketconnectable.h"
#include "glibintl.h"
#include "gioenumtypes.h"
PROP_FAMILY
};
-G_DEFINE_ABSTRACT_TYPE (GSocketAddress, g_socket_address, G_TYPE_OBJECT);
+static void g_socket_address_connectable_iface_init (GSocketConnectableIface *iface);
+static GSocketAddressEnumerator *g_socket_address_connectable_enumerate (GSocketConnectable *connectable);
+
+G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GSocketAddress, g_socket_address, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_SOCKET_CONNECTABLE,
+ g_socket_address_connectable_iface_init))
/**
* g_socket_address_get_family:
}
static void
+g_socket_address_connectable_iface_init (GSocketConnectableIface *connectable_iface)
+{
+ connectable_iface->enumerate = g_socket_address_connectable_enumerate;
+}
+
+static void
g_socket_address_init (GSocketAddress *address)
{
return NULL;
}
+
+#define G_TYPE_SOCKET_ADDRESS_ADDRESS_ENUMERATOR (_g_socket_address_address_enumerator_get_type ())
+#define G_SOCKET_ADDRESS_ADDRESS_ENUMERATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_SOCKET_ADDRESS_ADDRESS_ENUMERATOR, GSocketAddressAddressEnumerator))
+
+typedef struct {
+ GSocketAddressEnumerator parent_instance;
+
+ GSocketAddress *sockaddr;
+} GSocketAddressAddressEnumerator;
+
+typedef struct {
+ GSocketAddressEnumeratorClass parent_class;
+
+} GSocketAddressAddressEnumeratorClass;
+
+G_DEFINE_TYPE (GSocketAddressAddressEnumerator, _g_socket_address_address_enumerator, G_TYPE_SOCKET_ADDRESS_ENUMERATOR)
+
+static void
+g_socket_address_address_enumerator_finalize (GObject *object)
+{
+ GSocketAddressAddressEnumerator *sockaddr_enum =
+ G_SOCKET_ADDRESS_ADDRESS_ENUMERATOR (object);
+
+ if (sockaddr_enum->sockaddr)
+ g_object_unref (sockaddr_enum->sockaddr);
+
+ G_OBJECT_CLASS (_g_socket_address_address_enumerator_parent_class)->finalize (object);
+}
+
+static GSocketAddress *
+g_socket_address_address_enumerator_next (GSocketAddressEnumerator *enumerator,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GSocketAddressAddressEnumerator *sockaddr_enum =
+ G_SOCKET_ADDRESS_ADDRESS_ENUMERATOR (enumerator);
+
+ if (sockaddr_enum->sockaddr)
+ {
+ GSocketAddress *ret = sockaddr_enum->sockaddr;
+
+ sockaddr_enum->sockaddr = NULL;
+ return ret;
+ }
+ else
+ return NULL;
+}
+
+static void
+_g_socket_address_address_enumerator_init (GSocketAddressAddressEnumerator *enumerator)
+{
+}
+
+static void
+_g_socket_address_address_enumerator_class_init (GSocketAddressAddressEnumeratorClass *sockaddrenum_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (sockaddrenum_class);
+ GSocketAddressEnumeratorClass *enumerator_class =
+ G_SOCKET_ADDRESS_ENUMERATOR_CLASS (sockaddrenum_class);
+
+ enumerator_class->next = g_socket_address_address_enumerator_next;
+ object_class->finalize = g_socket_address_address_enumerator_finalize;
+}
+
+static GSocketAddressEnumerator *
+g_socket_address_connectable_enumerate (GSocketConnectable *connectable)
+{
+ GSocketAddressAddressEnumerator *sockaddr_enum;
+
+ sockaddr_enum = g_object_new (G_TYPE_SOCKET_ADDRESS_ADDRESS_ENUMERATOR, NULL);
+ sockaddr_enum->sockaddr = g_object_ref (connectable);
+
+ return (GSocketAddressEnumerator *)sockaddr_enum;
+}
+
#define __G_SOCKET_ADDRESS_C__
#include "gioaliasdef.c"
--- /dev/null
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2008 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.
+ */
+
+#include "config.h"
+#include "gsocketaddressenumerator.h"
+#include "glibintl.h"
+
+#include "gsimpleasyncresult.h"
+
+#include "gioalias.h"
+
+G_DEFINE_ABSTRACT_TYPE (GSocketAddressEnumerator, g_socket_address_enumerator, G_TYPE_OBJECT);
+
+static void g_socket_address_enumerator_real_next_async (GSocketAddressEnumerator *enumerator,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+static GSocketAddress *g_socket_address_enumerator_real_next_finish (GSocketAddressEnumerator *enumerator,
+ GAsyncResult *result,
+ GError **error);
+
+static void
+g_socket_address_enumerator_init (GSocketAddressEnumerator *enumerator)
+{
+}
+
+static void
+g_socket_address_enumerator_class_init (GSocketAddressEnumeratorClass *enumerator_class)
+{
+ enumerator_class->next_async = g_socket_address_enumerator_real_next_async;
+ enumerator_class->next_finish = g_socket_address_enumerator_real_next_finish;
+}
+
+/**
+ * g_socket_address_enumerator_next:
+ * @enumerator: a #GSocketAddressEnumerator
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @error: a #GError.
+ *
+ * Retrieves the next #GSocketAddress from @enumerator. Note that this
+ * may block for some amount of time. (Eg, a #GNetworkAddress may need
+ * to do a DNS lookup before it can return an address.) Use
+ * g_socket_address_enumerator_next_async() if you need to avoid
+ * blocking.
+ *
+ * If @enumerator is expected to yield addresses, but for some reason
+ * is unable to (eg, because of a DNS error), then the first call to
+ * g_socket_address_enumerator_next() will return an appropriate error
+ * in *@error. However, if the first call to
+ * g_socket_address_enumerator_next() succeeds, then any further
+ * internal errors (other than @cancellable being triggered) will be
+ * ignored.
+ *
+ * Return value: a #GSocketAddress (owned by the caller), or %NULL on
+ * error (in which case *@error will be set) or if there are no more
+ * addresses.
+ **/
+GSocketAddress *
+g_socket_address_enumerator_next (GSocketAddressEnumerator *enumerator,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GSocketAddressEnumeratorClass *klass;
+
+ g_return_val_if_fail (G_IS_SOCKET_ADDRESS_ENUMERATOR (enumerator), NULL);
+
+ klass = G_SOCKET_ADDRESS_ENUMERATOR_GET_CLASS (enumerator);
+
+ return (* klass->next) (enumerator, cancellable, error);
+}
+
+/* Default implementation just calls the synchronous method; this can
+ * be used if the implementation already knows all of its addresses,
+ * and so the synchronous method will never block.
+ */
+static void
+g_socket_address_enumerator_real_next_async (GSocketAddressEnumerator *enumerator,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *result;
+ GSocketAddress *address;
+ GError *error = NULL;
+
+ result = g_simple_async_result_new (G_OBJECT (enumerator),
+ callback, user_data,
+ g_socket_address_enumerator_real_next_async);
+ address = g_socket_address_enumerator_next (enumerator, cancellable, &error);
+ if (address)
+ g_simple_async_result_set_op_res_gpointer (result, address, NULL);
+ else if (error)
+ {
+ g_simple_async_result_set_from_error (result, error);
+ g_error_free (error);
+ }
+ g_simple_async_result_complete_in_idle (result);
+ g_object_unref (result);
+}
+
+/**
+ * g_socket_address_enumerator_next_async:
+ * @enumerator: a #GSocketAddressEnumerator
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: the data to pass to callback function
+ *
+ * Asynchronously retrieves the next #GSocketAddress from @enumerator
+ * and then calls @callback, which must call
+ * g_socket_address_enumerator_next_finish() to get the result.
+ **/
+void
+g_socket_address_enumerator_next_async (GSocketAddressEnumerator *enumerator,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSocketAddressEnumeratorClass *klass;
+
+ g_return_if_fail (G_IS_SOCKET_ADDRESS_ENUMERATOR (enumerator));
+
+ klass = G_SOCKET_ADDRESS_ENUMERATOR_GET_CLASS (enumerator);
+
+ (* klass->next_async) (enumerator, cancellable, callback, user_data);
+}
+
+static GSocketAddress *
+g_socket_address_enumerator_real_next_finish (GSocketAddressEnumerator *enumerator,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), NULL);
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+ g_return_val_if_fail (g_simple_async_result_get_source_tag (simple) == g_socket_address_enumerator_real_next_async, NULL);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return NULL;
+ else
+ return g_simple_async_result_get_op_res_gpointer (simple);
+}
+
+/**
+ * g_socket_address_enumerator_next_finish:
+ * @enumerator: a #GSocketAddressEnumerator
+ * @result: a #GAsyncResult.
+ * @error: a #GError.
+ *
+ * Retrieves the result of a completed call to
+ * g_socket_address_enumerator_next_async(). See
+ * g_socket_address_enumerator_next() for more information about
+ * error handling.
+ *
+ * Return value: a #GSocketAddress (owned by the caller), or %NULL on
+ * error (in which case *@error will be set) or if there are no more
+ * addresses.
+ **/
+GSocketAddress *
+g_socket_address_enumerator_next_finish (GSocketAddressEnumerator *enumerator,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSocketAddressEnumeratorClass *klass;
+
+ g_return_val_if_fail (G_IS_SOCKET_ADDRESS_ENUMERATOR (enumerator), NULL);
+
+ klass = G_SOCKET_ADDRESS_ENUMERATOR_GET_CLASS (enumerator);
+
+ return (* klass->next_finish) (enumerator, result, error);
+}
+
+#define __G_SOCKET_ADDRESS_ENUMERATOR_C__
+#include "gioaliasdef.c"
--- /dev/null
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2008 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.
+ */
+
+#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
+#error "Only <gio/gio.h> can be included directly."
+#endif
+
+#ifndef __G_SOCKET_ADDRESS_ENUMERATOR_H__
+#define __G_SOCKET_ADDRESS_ENUMERATOR_H__
+
+#include <gio/giotypes.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_SOCKET_ADDRESS_ENUMERATOR (g_socket_address_enumerator_get_type ())
+#define G_SOCKET_ADDRESS_ENUMERATOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_SOCKET_ADDRESS_ENUMERATOR, GSocketAddressEnumerator))
+#define G_SOCKET_ADDRESS_ENUMERATOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_SOCKET_ADDRESS_ENUMERATOR, GSocketAddressEnumeratorClass))
+#define G_IS_SOCKET_ADDRESS_ENUMERATOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_SOCKET_ADDRESS_ENUMERATOR))
+#define G_IS_SOCKET_ADDRESS_ENUMERATOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_SOCKET_ADDRESS_ENUMERATOR))
+#define G_SOCKET_ADDRESS_ENUMERATOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_SOCKET_ADDRESS_ENUMERATOR, GSocketAddressEnumeratorClass))
+
+/**
+ * GSocketAddressEnumerator:
+ *
+ * Enumerator type for objects that contain or generate
+ * #GSocketAddress<!-- -->es.
+ **/
+typedef struct _GSocketAddressEnumeratorClass GSocketAddressEnumeratorClass;
+
+struct _GSocketAddressEnumerator
+{
+ GObject parent_instance;
+
+};
+
+struct _GSocketAddressEnumeratorClass
+{
+ GObjectClass parent_class;
+
+ /* Virtual Table */
+
+ GSocketAddress * (* next) (GSocketAddressEnumerator *enumerator,
+ GCancellable *cancellable,
+ GError **error);
+
+ void (* next_async) (GSocketAddressEnumerator *enumerator,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+ GSocketAddress * (* next_finish) (GSocketAddressEnumerator *enumerator,
+ GAsyncResult *result,
+ GError **error);
+};
+
+GType g_socket_address_enumerator_get_type (void) G_GNUC_CONST;
+
+GSocketAddress *g_socket_address_enumerator_next (GSocketAddressEnumerator *enumerator,
+ GCancellable *cancellable,
+ GError **error);
+
+void g_socket_address_enumerator_next_async (GSocketAddressEnumerator *enumerator,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+GSocketAddress *g_socket_address_enumerator_next_finish (GSocketAddressEnumerator *enumerator,
+ GAsyncResult *result,
+ GError **error);
+
+G_END_DECLS
+
+
+#endif /* __G_SOCKET_ADDRESS_ENUMERATOR_H__ */
--- /dev/null
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2008 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.
+ */
+
+#include "config.h"
+#include "gsocketconnectable.h"
+#include "glibintl.h"
+
+#include "gioalias.h"
+
+/**
+ * SECTION:gsocketconnectable
+ * @short_description: Interface for potential socket endpoints.
+ *
+ * Objects that describe one or more potential socket endpoints
+ * implement #GSocketConnectable. Callers can then use
+ * g_socket_connectable_enumerate() to get a #GSocketAddressEnumerator
+ * to try out each socket address in turn until one succeeds, as shown
+ * in the sample code below.
+ *
+ * |[
+ * MyConnectionType *
+ * connect_to_host (const char *hostname,
+ * guint16 port,
+ * GCancellable *cancellable,
+ * GError **error)
+ * {
+ * MyConnection *conn = NULL;
+ * GSocketConnectable *addr;
+ * GSocketAddressEnumerator *enumerator;
+ * GSocketAddress *sockaddr;
+ * GError *conn_error = NULL;
+ *
+ * addr = g_network_address_new ("www.gnome.org", 80);
+ * enumerator = g_socket_connectable_enumerate (addr);
+ * g_object_unref (addr);
+ *
+ * /<!-- -->* Try each sockaddr until we succeed. Record the first
+ * * connection error, but not any further ones (since they'll probably
+ * * be basically the same as the first).
+ * *<!-- -->/
+ * while (!conn && (sockaddr = g_socket_address_enumerator_next (enumerator, cancellable, error))
+ * {
+ * conn = connect_to_sockaddr (sockaddr, conn_error ? NULL : &conn_error);
+ * g_object_unref (sockaddr);
+ * }
+ * g_object_unref (enumerator);
+ *
+ * if (conn)
+ * {
+ * if (conn_error)
+ * {
+ * /<!-- -->* We couldn't connect to the first address, but we succeeded
+ * * in connecting to a later address.
+ * *<!-- -->/
+ * g_error_free (conn_error);
+ * }
+ * return conn;
+ * }
+ * else if (error)
+ * {
+ * /<!-- -->* Either the initial lookup failed, or else the caller
+ * * cancelled us.
+ * *<!-- -->/
+ * if (conn_error)
+ * g_error_free (conn_error);
+ * return NULL;
+ * }
+ * else
+ * {
+ * g_error_propagate (error, conn_error);
+ * return NULL;
+ * }
+ * }
+ * ]|
+ **/
+
+GType
+g_socket_connectable_get_type (void)
+{
+ static volatile gsize g_define_type_id__volatile = 0;
+
+ if (g_once_init_enter (&g_define_type_id__volatile))
+ {
+ const GTypeInfo connectable_info =
+ {
+ sizeof (GSocketConnectableIface), /* class_size */
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ NULL,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ 0,
+ 0, /* n_preallocs */
+ NULL
+ };
+ GType g_define_type_id =
+ g_type_register_static (G_TYPE_INTERFACE, I_("GSocketConnectable"),
+ &connectable_info, 0);
+
+ g_type_interface_add_prerequisite (g_define_type_id, G_TYPE_OBJECT);
+
+ g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+ }
+
+ return g_define_type_id__volatile;
+}
+
+/**
+ * g_socket_connectable_enumerate:
+ * @connectable: a #GSocketConnectable
+ *
+ * Creates a #GSocketAddressEnumerator for @connectable.
+ *
+ * Return value: a new #GSocketAddressEnumerator.
+ *
+ * Since: 2.22
+ **/
+GSocketAddressEnumerator *
+g_socket_connectable_enumerate (GSocketConnectable *connectable)
+{
+ GSocketConnectableIface *iface;
+
+ g_return_val_if_fail (G_IS_SOCKET_CONNECTABLE (connectable), NULL);
+
+ iface = G_SOCKET_CONNECTABLE_GET_IFACE (connectable);
+
+ return (* iface->enumerate) (connectable);
+}
+
+#define __G_SOCKET_CONNECTABLE_C__
+#include "gioaliasdef.c"
--- /dev/null
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2008 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.
+ */
+
+#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
+#error "Only <gio/gio.h> can be included directly."
+#endif
+
+#ifndef __G_SOCKET_CONNECTABLE_H__
+#define __G_SOCKET_CONNECTABLE_H__
+
+#include <gio/giotypes.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_SOCKET_CONNECTABLE (g_socket_connectable_get_type ())
+#define G_SOCKET_CONNECTABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_SOCKET_CONNECTABLE, GSocketConnectable))
+#define G_IS_SOCKET_CONNECTABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_SOCKET_CONNECTABLE))
+#define G_SOCKET_CONNECTABLE_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), G_TYPE_SOCKET_CONNECTABLE, GSocketConnectableIface))
+
+/**
+ * GSocketConnectable:
+ *
+ * Interface for objects that contain or generate #GSocketAddress<!-- -->es.
+ **/
+typedef struct _GSocketConnectableIface GSocketConnectableIface;
+
+/**
+ * GSocketConnectableIface:
+ * @g_iface: The parent interface.
+ * @enumerate: Creates a #GSocketAddressEnumerator
+ *
+ * Provides an interface for returning a #GSocketAddressEnumerator
+ **/
+struct _GSocketConnectableIface
+{
+ GTypeInterface g_iface;
+
+ /* Virtual Table */
+
+ GSocketAddressEnumerator * (* enumerate) (GSocketConnectable *connectable);
+
+};
+
+GType g_socket_connectable_get_type (void) G_GNUC_CONST;
+
+GSocketAddressEnumerator *g_socket_connectable_enumerate (GSocketConnectable *connectable);
+
+G_END_DECLS
+
+
+#endif /* __G_SOCKET_CONNECTABLE_H__ */
* would look up the "xmpp-client" SRV record for "example.com", and
* then connect to whatever host was pointed to by that record.
*
- * Use g_resolver_lookup_service() or
+ * You can use g_resolver_lookup_service() or
* g_resolver_lookup_service_async() to find the #GSrvTarget<!-- -->s
- * for a given service.
+ * for a given service. However, if you are simply planning to connect
+ * to the remote service, you can use #GNetworkService's
+ * #GSocketConnectable interface and not need to worry about
+ * #GSrvTarget at all.
**/
struct _GSrvTarget {
filter-streams
sleepy-stream
resolver
+connectable
usage (void)
{
fprintf (stderr, "Usage: resolver [-t] [-s] [hostname | IP | service/protocol/domain ] ...\n");
+ fprintf (stderr, " resolver [-t] [-s] -c [hostname | IP | service/protocol/domain ]\n");
fprintf (stderr, " Use -t to enable threading.\n");
fprintf (stderr, " Use -s to do synchronous lookups.\n");
fprintf (stderr, " Both together will result in simultaneous lookups in multiple threads\n");
+ fprintf (stderr, " Use -c (and only a single resolvable argument) to test GSocketConnectable.\n");
exit (1);
}
}
}
+static void
+print_connectable_sockaddr (GSocketAddress *sockaddr,
+ GError *error)
+{
+ char *phys;
+
+ if (error)
+ {
+ printf ("Error: %s\n", error->message);
+ g_error_free (error);
+ }
+ else if (!G_IS_INET_SOCKET_ADDRESS (sockaddr))
+ {
+ printf ("Error: Unexpected sockaddr type '%s'\n", g_type_name_from_instance ((GTypeInstance *)sockaddr));
+ g_object_unref (sockaddr);
+ }
+ else
+ {
+ GInetSocketAddress *isa = G_INET_SOCKET_ADDRESS (sockaddr);
+ phys = g_inet_address_to_string (g_inet_socket_address_get_address (isa));
+ printf ("Address: %s%s%s:%d\n",
+ strchr (phys, ':') ? "[" : "", phys, strchr (phys, ':') ? "]" : "",
+ g_inet_socket_address_get_port (isa));
+ g_free (phys);
+ g_object_unref (sockaddr);
+ }
+}
+
+static void
+do_sync_connectable (GSocketAddressEnumerator *enumerator)
+{
+ GSocketAddress *sockaddr;
+ GError *error = NULL;
+
+ while ((sockaddr = g_socket_address_enumerator_next (enumerator, cancellable, &error)))
+ print_connectable_sockaddr (sockaddr, error);
+
+ g_object_unref (enumerator);
+ done_lookup ();
+}
+
+static void do_async_connectable (GSocketAddressEnumerator *enumerator);
+
+static void
+got_next_async (GObject *source, GAsyncResult *result, gpointer user_data)
+{
+ GSocketAddressEnumerator *enumerator = G_SOCKET_ADDRESS_ENUMERATOR (source);
+ GSocketAddress *sockaddr;
+ GError *error = NULL;
+
+ sockaddr = g_socket_address_enumerator_next_finish (enumerator, result, &error);
+ if (sockaddr || error)
+ print_connectable_sockaddr (sockaddr, error);
+ if (sockaddr)
+ do_async_connectable (enumerator);
+ else
+ {
+ g_object_unref (enumerator);
+ done_lookup ();
+ }
+}
+
+static void
+do_async_connectable (GSocketAddressEnumerator *enumerator)
+{
+ g_socket_address_enumerator_next_async (enumerator, cancellable,
+ got_next_async, NULL);
+}
+
+static void
+do_connectable (const char *arg, gboolean synchronous)
+{
+ char **parts;
+ GSocketConnectable *connectable;
+ GSocketAddressEnumerator *enumerator;
+
+ if (strchr (arg, '/'))
+ {
+ /* service/protocol/domain */
+ parts = g_strsplit (arg, "/", 3);
+ if (!parts || !parts[2])
+ usage ();
+
+ connectable = g_network_service_new (parts[0], parts[1], parts[2]);
+ }
+ else
+ {
+ guint16 port;
+
+ parts = g_strsplit (arg, ":", 2);
+ if (parts && parts[1])
+ {
+ arg = parts[0];
+ port = strtoul (parts[1], NULL, 10);
+ }
+ else
+ port = 0;
+
+ if (g_hostname_is_ip_address (arg))
+ {
+ GInetAddress *addr = g_inet_address_new_from_string (arg);
+ GSocketAddress *sockaddr = g_inet_socket_address_new (addr, port);
+
+ g_object_unref (addr);
+ connectable = G_SOCKET_CONNECTABLE (sockaddr);
+ }
+ else
+ connectable = g_network_address_new (arg, port);
+ }
+
+ enumerator = g_socket_connectable_enumerate (connectable);
+ g_object_unref (connectable);
+
+ if (synchronous)
+ do_sync_connectable (enumerator);
+ else
+ do_async_connectable (enumerator);
+}
+
#ifdef G_OS_UNIX
static int cancel_fds[2];
main (int argc, char **argv)
{
gboolean threaded = FALSE, synchronous = FALSE;
+ gboolean use_connectable = FALSE;
#ifdef G_OS_UNIX
GIOChannel *chan;
guint watch;
}
else if (!strcmp (argv[1], "-s"))
synchronous = TRUE;
+ else if (!strcmp (argv[1], "-c"))
+ use_connectable = TRUE;
else
usage ();
}
g_type_init ();
- if (argc < 2)
+ if (argc < 2 || (argc > 2 && use_connectable))
usage ();
resolver = g_resolver_get_default ();
nlookups = argc - 1;
loop = g_main_loop_new (NULL, TRUE);
- if (threaded && synchronous)
- start_threaded_lookups (argv + 1, argc - 1);
- else if (synchronous)
- start_sync_lookups (argv + 1, argc - 1);
+ if (use_connectable)
+ do_connectable (argv[1], synchronous);
else
- start_async_lookups (argv + 1, argc - 1);
+ {
+ if (threaded && synchronous)
+ start_threaded_lookups (argv + 1, argc - 1);
+ else if (synchronous)
+ start_sync_lookups (argv + 1, argc - 1);
+ else
+ start_async_lookups (argv + 1, argc - 1);
+ }
g_main_run (loop);
g_main_loop_unref (loop);