GResolver wrappers: GNetworkAddress, GNetworkService, GSocketConnectable

Higher-level wrappers around GResolver. GSocketConnectable provides an
interface for synchronously or asynchronously iterating multiple
socket addresses, with GNetworkAddress and GNetworkService providing
interfaces based on hostname and SRV record resolution.
Part of #548466.
This commit is contained in:
Dan Winship 2008-12-29 13:38:28 -05:00
parent c94d3f9288
commit 9a3d18d2a6
20 changed files with 2121 additions and 9 deletions

View File

@ -98,6 +98,9 @@
<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>

View File

@ -1456,3 +1456,74 @@ G_TYPE_SRV_TARGET
<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>

View File

@ -52,13 +52,17 @@ g_mount_operation_get_type
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

View File

@ -217,7 +217,9 @@ libgio_2_0_la_SOURCES = \
gmountoperation.c \
gnativevolumemonitor.c \
gnativevolumemonitor.h \
gnetworkaddress.c \
gnetworkingprivate.h \
gnetworkservice.c \
goutputstream.c \
gpollfilemonitor.c \
gpollfilemonitor.h \
@ -225,6 +227,8 @@ libgio_2_0_la_SOURCES = \
gseekable.c \
gsimpleasyncresult.c \
gsocketaddress.c \
gsocketaddressenumerator.c \
gsocketconnectable.c \
gsrvtarget.c \
gthemedicon.c \
gthreadedresolver.c \
@ -328,11 +332,15 @@ gio_headers = \
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 \

View File

@ -63,11 +63,15 @@
#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>

View File

@ -965,3 +965,38 @@ g_srv_target_get_weight
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

View File

@ -99,11 +99,15 @@ typedef struct _GMemoryOutputStream GMemoryOutputStream;
**/
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 */

462
gio/gnetworkaddress.c Normal file
View File

@ -0,0 +1,462 @@
/* -*- 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"

65
gio/gnetworkaddress.h Normal file
View File

@ -0,0 +1,65 @@
/* 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__ */

658
gio/gnetworkservice.c Normal file
View File

@ -0,0 +1,658 @@
/* -*- 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"

69
gio/gnetworkservice.h Normal file
View File

@ -0,0 +1,69 @@
/* 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__ */

View File

@ -52,6 +52,10 @@
* 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.
**/
/**
@ -169,6 +173,10 @@ g_resolver_set_default (GResolver *resolver)
* 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.)
@ -470,6 +478,10 @@ g_resolver_get_service_rrname (const char *service,
* 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.)

View File

@ -28,6 +28,8 @@
#include "ginetaddress.h"
#include "ginetsocketaddress.h"
#include "gnetworkingprivate.h"
#include "gsocketaddressenumerator.h"
#include "gsocketconnectable.h"
#include "glibintl.h"
#include "gioenumtypes.h"
@ -61,7 +63,12 @@ enum
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:
@ -114,6 +121,12 @@ g_socket_address_class_init (GSocketAddressClass *klass)
G_PARAM_READABLE | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NAME));
}
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)
{
@ -229,5 +242,80 @@ g_socket_address_new_from_native (gpointer native,
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"

View File

@ -0,0 +1,191 @@
/* 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"

View File

@ -0,0 +1,89 @@
/* 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__ */

148
gio/gsocketconnectable.c Normal file
View File

@ -0,0 +1,148 @@
/* 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"

68
gio/gsocketconnectable.h Normal file
View File

@ -0,0 +1,68 @@
/* 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__ */

View File

@ -44,9 +44,12 @@
* 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 {

View File

@ -13,3 +13,4 @@ memory-output-stream
filter-streams
sleepy-stream
resolver
connectable

View File

@ -41,9 +41,11 @@ static void
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);
}
@ -285,6 +287,125 @@ start_async_lookups (char **argv, int argc)
}
}
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];
@ -307,6 +428,7 @@ int
main (int argc, char **argv)
{
gboolean threaded = FALSE, synchronous = FALSE;
gboolean use_connectable = FALSE;
#ifdef G_OS_UNIX
GIOChannel *chan;
guint watch;
@ -324,6 +446,8 @@ main (int argc, char **argv)
}
else if (!strcmp (argv[1], "-s"))
synchronous = TRUE;
else if (!strcmp (argv[1], "-c"))
use_connectable = TRUE;
else
usage ();
@ -332,7 +456,7 @@ main (int argc, char **argv)
}
g_type_init ();
if (argc < 2)
if (argc < 2 || (argc > 2 && use_connectable))
usage ();
resolver = g_resolver_get_default ();
@ -358,12 +482,17 @@ main (int argc, char **argv)
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);