Commit c94d3f92 authored by Dan Winship's avatar Dan Winship

Add GResolver, a glib-ish interface to DNS

GResolver provides asynchronous (and synchronous-but-cancellable) APIs
for resolving hostnames, reverse-resolving IP addresses back to
hostnames, and resolving SRV records. Part of #548466.
parent 68fc0556
......@@ -974,6 +974,30 @@ if $glib_failed ; then
AC_MSG_ERROR([Could not determine values for AF_INET* constants])
fi
# For gio/libasyncns
if test $glib_native_win32 = no; then
AC_CHECK_FUNCS(strndup setresuid setreuid)
AC_CHECK_HEADERS(sys/prctl.h arpa/nameser_compat.h)
AC_CHECK_FUNC(res_query, ,
[AC_CHECK_LIB(resolv, res_query, [ LIBASYNCNS_LIBADD="-lresolv" ],
[ save_libs="$LIBS"
LIBS="-lresolv $LIBS"
AC_MSG_CHECKING([for res_query in -lresolv (alternate version)])
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([[#include <resolv.h>]], [[res_query(0,0,0,0,0)]])],
[ AC_MSG_RESULT(yes)
LIBASYNCNS_LIBADD="-lresolv" ],
[ AC_MSG_RESULT(no)
AC_CHECK_LIB(bind, res_query,
[ LIBASYNCNS_LIBADD="-lbind" ],
[ AC_MSG_ERROR(res_query not found) ] ) ] )
LIBS="$save_libs"
] )
]
)
AC_SUBST(LIBASYNCNS_LIBADD)
fi
dnl
dnl if statfs() takes 2 arguments (Posix) or 4 (Solaris)
dnl
......@@ -3384,6 +3408,7 @@ gthread/Makefile
gio/Makefile
gio/xdgmime/Makefile
gio/inotify/Makefile
gio/libasyncns/Makefile
gio/fen/Makefile
gio/fam/Makefile
gio/win32/Makefile
......
......@@ -43,11 +43,14 @@ IGNORE_HFILES= \
glocalvfs.h \
gnativevolumemonitor.h \
gpollfilemonitor.h \
gthreadedresolver.h \
gunionvolumemonitor.h \
gunixdrive.h \
gunixresolver.h \
gunixvolume.h \
gvolumeprivate.h \
gwin32appinfo.h \
gwin32resolver.h \
inotify-diag.h \
inotify-helper.h \
inotify-kernel.h \
......@@ -85,7 +88,8 @@ GTKDOC_LIBS = \
$(NULL)
# Extra options to supply to gtkdoc-mkdb
MKDB_OPTIONS = --output-format=xml --sgml-mode --name-space=g
MKDB_OPTIONS = --output-format=xml --sgml-mode --name-space=g \
--ignore-files=libasyncns
# Images to copy into HTML directory
HTML_IMAGES = \
......
......@@ -92,10 +92,12 @@
</chapter>
<chapter id="networking">
<title>Networking</title>
<xi:include href="xml/gresolver.xml"/>
<xi:include href="xml/ginetaddress.xml"/>
<xi:include href="xml/gsocketaddress.xml"/>
<xi:include href="xml/ginetsocketaddress.xml"/>
<xi:include href="xml/gunixsocketaddress.xml"/>
<xi:include href="xml/gsrvtarget.xml"/>
</chapter>
<chapter id="utils">
<title>Utilities</title>
......
......@@ -1404,3 +1404,55 @@ G_UNIX_SOCKET_ADDRESS_GET_CLASS
<SUBSECTION Private>
g_unix_socket_address_get_type
</SECTION>
<SECTION>
<FILE>gresolver</FILE>
<TITLE>GResolver</TITLE>
GResolver
g_resolver_get_default
g_resolver_set_default
g_resolver_lookup_by_name
g_resolver_lookup_by_name_async
g_resolver_lookup_by_name_finish
g_resolver_free_addresses
g_resolver_lookup_by_address
g_resolver_lookup_by_address_async
g_resolver_lookup_by_address_finish
g_resolver_lookup_service
g_resolver_lookup_service_async
g_resolver_lookup_service_finish
g_resolver_free_targets
<SUBSECTION>
G_RESOLVER_ERROR
GResolverError
<SUBSECTION Standard>
GResolverClass
G_IS_RESOLVER
G_IS_RESOLVER_CLASS
G_RESOLVER
G_RESOLVER_CLASS
G_RESOLVER_GET_CLASS
G_TYPE_RESOLVER
<SUBSECTION Private>
g_resolver_get_type
g_resolver_error_quark
</SECTION>
<SECTION>
<FILE>gsrvtarget</FILE>
<TITLE>GSrvTarget</TITLE>
GSrvTarget
g_srv_target_new
g_srv_target_copy
g_srv_target_free
g_srv_target_get_hostname
g_srv_target_get_port
g_srv_target_get_priority
g_srv_target_get_weight
g_srv_target_get_expires
g_srv_target_array_sort
<SUBSECTION Standard>
G_TYPE_SRV_TARGET
<SUBSECTION Private>
g_srv_target_get_type
</SECTION>
......@@ -55,6 +55,7 @@ g_native_volume_monitor_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_get_type
......
......@@ -5,7 +5,7 @@ NULL =
SUBDIRS=
if OS_UNIX
SUBDIRS += xdgmime
SUBDIRS += libasyncns xdgmime
endif
if OS_WIN32_AND_DLL_COMPILATION
......@@ -125,13 +125,15 @@ endif
if OS_UNIX
appinfo_sources += gdesktopappinfo.c gdesktopappinfo.h
platform_libadd += xdgmime/libxdgmime.la
platform_deps += xdgmime/libxdgmime.la
platform_libadd += libasyncns/libasyncns.la xdgmime/libxdgmime.la
platform_deps += libasyncns/libasyncns.la xdgmime/libxdgmime.la
unix_sources = \
gunixmount.c \
gunixmount.h \
gunixmounts.c \
gunixmounts.h \
gunixresolver.c \
gunixresolver.h \
gunixsocketaddress.c \
gunixvolume.c \
gunixvolume.h \
......@@ -154,10 +156,12 @@ endif
if OS_WIN32
appinfo_sources += gwin32appinfo.c gwin32appinfo.h
platform_libadd += -lshlwapi -lws2_32
platform_libadd += -lshlwapi -lws2_32 -ldnsapi
win32_sources = \
gwin32mount.c \
gwin32mount.h \
gwin32resolver.c \
gwin32resolver.h \
gwin32volumemonitor.c \
gwin32volumemonitor.h \
$(NULL)
......@@ -217,10 +221,14 @@ libgio_2_0_la_SOURCES = \
goutputstream.c \
gpollfilemonitor.c \
gpollfilemonitor.h \
gresolver.c \
gseekable.c \
gsimpleasyncresult.c \
gsocketaddress.c \
gsrvtarget.c \
gthemedicon.c \
gthreadedresolver.c \
gthreadedresolver.h \
gunionvolumemonitor.c \
gunionvolumemonitor.h \
gvfs.c \
......@@ -321,9 +329,11 @@ gio_headers = \
gmountoperation.h \
gnativevolumemonitor.h \
goutputstream.h \
gresolver.h \
gseekable.h \
gsimpleasyncresult.h \
gsocketaddress.h \
gsrvtarget.h \
gthemedicon.h \
gvfs.h \
gvolume.h \
......
......@@ -36,7 +36,12 @@
* SECTION:ginetaddress
* @short_description: An IPv4/IPv6 address
*
* #GInetAddress represents an IPv4 or IPv6 internet address.
* #GInetAddress represents an IPv4 or IPv6 internet address. Use
* g_resolver_lookup_by_name() or g_resolver_lookup_by_name_async() to
* look up the #GInetAddress for a hostname. Use
* g_resolver_lookup_by_address() or
* g_resolver_lookup_by_address_async() to look up the hostname for a
* #GInetAddress.
*
* To actually connect to a remote host, you will need a
* #GInetSocketAddress (which includes a #GInetAddress as well as a
......
......@@ -64,9 +64,11 @@
#include <gio/gmountoperation.h>
#include <gio/gnativevolumemonitor.h>
#include <gio/goutputstream.h>
#include <gio/gresolver.h>
#include <gio/gseekable.h>
#include <gio/gsimpleasyncresult.h>
#include <gio/gsocketaddress.h>
#include <gio/gsrvtarget.h>
#include <gio/gthemedicon.h>
#include <gio/gvfs.h>
#include <gio/gvolume.h>
......
......@@ -834,6 +834,7 @@ g_ask_password_flags_get_type G_GNUC_CONST
g_password_save_get_type G_GNUC_CONST
g_emblem_origin_get_type G_GNUC_CONST
g_socket_family_get_type G_GNUC_CONST
g_resolver_error_get_type G_GNUC_CONST
#endif
#endif
......@@ -908,3 +909,59 @@ g_socket_address_get_native_size
g_socket_address_to_native
#endif
#endif
#if IN_HEADER(__G_RESOLVER_H__)
#if IN_FILE(__G_RESOLVER_C__)
g_resolver_error_quark
g_resolver_free_addresses
g_resolver_free_targets
g_resolver_get_type G_GNUC_CONST
g_resolver_get_default
g_resolver_set_default
g_resolver_lookup_by_name
g_resolver_lookup_by_name_async
g_resolver_lookup_by_name_finish
g_resolver_lookup_by_address
g_resolver_lookup_by_address_async
g_resolver_lookup_by_address_finish
g_resolver_lookup_service
g_resolver_lookup_service_async
g_resolver_lookup_service_finish
#endif
#endif
#if IN_HEADER(__G_THREADED_RESOLVER_H__)
#if IN_FILE(__G_THREADED_RESOLVER_C__)
g_threaded_resolver_get_type G_GNUC_CONST
#endif
#endif
#if IN_HEADER(__G_UNIX_RESOLVER_H__)
#if IN_FILE(__G_UNIX_RESOLVER_C__)
#ifdef G_OS_UNIX
g_unix_resolver_get_type G_GNUC_CONST
#endif
#endif
#endif
#if IN_HEADER(__G_WIN32_RESOLVER_H__)
#if IN_FILE(__G_WIN32_RESOLVER_C__)
#ifdef G_OS_WIN32
g_win32_resolver_get_type G_GNUC_CONST
#endif
#endif
#endif
#if IN_HEADER(__G_SRV_TARGET_H__)
#if IN_FILE(__G_SRV_TARGET_C__)
g_srv_target_get_type G_GNUC_CONST
g_srv_target_new
g_srv_target_copy
g_srv_target_free
g_srv_target_get_hostname
g_srv_target_get_port
g_srv_target_get_priority
g_srv_target_get_weight
g_srv_target_list_sort
#endif
#endif
......@@ -476,6 +476,20 @@ typedef enum {
G_EMBLEM_ORIGIN_TAG
} GEmblemOrigin;
/**
* GResolverError:
* @G_RESOLVER_ERROR_NOT_FOUND: the requested name/address/service was not found
* @G_RESOLVER_ERROR_TEMPORARY_FAILURE: the requested information could not be looked up due to a network error or similar problem
* @G_RESOLVER_ERROR_INTERNAL: unknown error
*
* An error code used with %G_RESOLVER_ERROR in a #GError returned
* from a #GResolver routine.
*/
typedef enum {
G_RESOLVER_ERROR_NOT_FOUND,
G_RESOLVER_ERROR_TEMPORARY_FAILURE,
G_RESOLVER_ERROR_INTERNAL
} GResolverError;
/**
* GSocketFamily:
......
......@@ -99,12 +99,12 @@ 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 _GSrvTarget GSrvTarget;
typedef struct _GThemedIcon GThemedIcon;
typedef struct _GVfs GVfs; /* Dummy typedef */
......
......@@ -50,4 +50,36 @@
#endif
G_BEGIN_DECLS
extern struct addrinfo _g_resolver_addrinfo_hints;
GList *_g_resolver_addresses_from_addrinfo (const char *hostname,
struct addrinfo *res,
gint gai_retval,
GError **error);
void _g_resolver_address_to_sockaddr (GInetAddress *address,
struct sockaddr_storage *sa,
gsize *sa_len);
char *_g_resolver_name_from_nameinfo (GInetAddress *address,
const gchar *name,
gint gni_retval,
GError **error);
#if defined(G_OS_UNIX)
GList *_g_resolver_targets_from_res_query (const gchar *rrname,
guchar *answer,
gint len,
gint herr,
GError **error);
#elif defined(G_OS_WIN32)
GList *_g_resolver_targets_from_DnsQuery (const gchar *rrname,
DNS_STATUS status,
DNS_RECORD *results,
GError **error);
#endif
G_END_DECLS
#endif /* __G_NETWORKINGPRIVATE_H__ */
This diff is collapsed.
/* 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_RESOLVER_H__
#define __G_RESOLVER_H__
#include <gio/giotypes.h>
G_BEGIN_DECLS
#define G_TYPE_RESOLVER (g_resolver_get_type ())
#define G_RESOLVER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_RESOLVER, GResolver))
#define G_RESOLVER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_RESOLVER, GResolverClass))
#define G_IS_RESOLVER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_RESOLVER))
#define G_IS_RESOLVER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_RESOLVER))
#define G_RESOLVER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_RESOLVER, GResolverClass))
struct _GResolver {
GObject parent_instance;
};
typedef struct {
GObjectClass parent_class;
GList * ( *lookup_by_name) (GResolver *resolver,
const gchar *hostname,
GCancellable *cancellable,
GError **error);
void ( *lookup_by_name_async) (GResolver *resolver,
const gchar *hostname,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GList * ( *lookup_by_name_finish) (GResolver *resolver,
GAsyncResult *result,
GError **error);
gchar * ( *lookup_by_address) (GResolver *resolver,
GInetAddress *address,
GCancellable *cancellable,
GError **error);
void ( *lookup_by_address_async) (GResolver *resolver,
GInetAddress *address,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gchar * ( *lookup_by_address_finish) (GResolver *resolver,
GAsyncResult *result,
GError **error);
GList * ( *lookup_service) (GResolver *resolver,
const gchar *rrname,
GCancellable *cancellable,
GError **error);
void ( *lookup_service_async) (GResolver *resolver,
const gchar *rrname,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GList * ( *lookup_service_finish) (GResolver *resolver,
GAsyncResult *result,
GError **error);
/* Padding for future expansion */
void (*_g_reserved1) (void);
void (*_g_reserved2) (void);
void (*_g_reserved3) (void);
void (*_g_reserved4) (void);
void (*_g_reserved5) (void);
void (*_g_reserved6) (void);
} GResolverClass;
GType g_resolver_get_type (void) G_GNUC_CONST;
GResolver *g_resolver_get_default (void);
void g_resolver_set_default (GResolver *resolver);
GList *g_resolver_lookup_by_name (GResolver *resolver,
const gchar *hostname,
GCancellable *cancellable,
GError **error);
void g_resolver_lookup_by_name_async (GResolver *resolver,
const gchar *hostname,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GList *g_resolver_lookup_by_name_finish (GResolver *resolver,
GAsyncResult *result,
GError **error);
void g_resolver_free_addresses (GList *addresses);
gchar *g_resolver_lookup_by_address (GResolver *resolver,
GInetAddress *address,
GCancellable *cancellable,
GError **error);
void g_resolver_lookup_by_address_async (GResolver *resolver,
GInetAddress *address,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gchar *g_resolver_lookup_by_address_finish (GResolver *resolver,
GAsyncResult *result,
GError **error);
GList *g_resolver_lookup_service (GResolver *resolver,
const gchar *service,
const gchar *protocol,
const gchar *domain,
GCancellable *cancellable,
GError **error);
void g_resolver_lookup_service_async (GResolver *resolver,
const gchar *service,
const gchar *protocol,
const gchar *domain,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GList *g_resolver_lookup_service_finish (GResolver *resolver,
GAsyncResult *result,
GError **error);
void g_resolver_free_targets (GList *targets);
/**
* G_RESOLVER_ERROR:
*
* Error domain for #GResolver. Errors in this domain will be from the
* #GResolverError enumeration. See #GError for more information on
* error domains.
**/
#define G_RESOLVER_ERROR (g_resolver_error_quark ())
GQuark g_resolver_error_quark (void);
G_END_DECLS
#endif /* __G_RESOLVER_H__ */
/* -*- 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 "gsrvtarget.h"
#include <stdlib.h>
#include <string.h>
#include "gioalias.h"
/**
* SECTION:gsrvtarget
* @short_description: DNS SRV record target
* @include: gio/gio.h
*
* SRV (service) records are used by some network protocols to provide
* service-specific aliasing and load-balancing. For example, XMPP
* (Jabber) uses SRV records to locate the XMPP server for a domain;
* rather than connecting directly to "example.com" or assuming a
* specific server hostname like "xmpp.example.com", an XMPP client
* 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
* g_resolver_lookup_service_async() to find the #GSrvTarget<!-- -->s
* for a given service.
**/
struct _GSrvTarget {
gchar *hostname;
guint16 port;
guint16 priority;
guint16 weight;
};
/**
* GSrvTarget:
*
* A single target host/port that a network service is running on.
*/
GType
g_srv_target_get_type (void)
{
static volatile gsize type_volatile = 0;
if (g_once_init_enter (&type_volatile))
{
GType type = g_boxed_type_register_static (
g_intern_static_string ("GSrvTarget"),
(GBoxedCopyFunc) g_srv_target_copy,
(GBoxedFreeFunc) g_srv_target_free);
g_once_init_leave (&type_volatile, type);
}
return type_volatile;
}
/**
* g_srv_target_new:
* @hostname: the host that the service is running on
* @port: the port that the service is running on
* @priority: the target's priority
* @weight: the target's weight
*
* Creates a new #GSrvTarget with the given parameters.
*
* You should not need to use this; normally #GSrvTarget<!-- -->s are
* created by #GResolver.
*
* Return value: a new #GSrvTarget.
*
* Since: 2.22
**/
GSrvTarget *
g_srv_target_new (const gchar *hostname,
guint16 port,
guint16 priority,
guint16 weight)
{
GSrvTarget *target = g_slice_new0 (GSrvTarget);
target->hostname = g_strdup (hostname);
target->port = port;
target->priority = priority;
target->weight = weight;
return target;
}
/**
* g_srv_target_copy:
* @target: a #GSrvTarget
*
* Copies @target
*
* Return value: a copy of @target
*
* Since: 2.22
**/
GSrvTarget *
g_srv_target_copy (GSrvTarget *target)
{
return g_srv_target_new (target->hostname, target->port,
target->priority, target->weight);
}
/**
* g_srv_target_free:
* @target: a #GSrvTarget
*
* Frees @target
*
* Since: 2.22
**/
void
g_srv_target_free (GSrvTarget *target)
{
g_free (target->hostname);
g_slice_free (GSrvTarget, target);
}
/**
* g_srv_target_get_hostname:
* @target: a #GSrvTarget
*
* Gets @target's hostname (in ASCII form; if you are going to present
* this to the user, you should use g_hostname_is_ascii_encoded() to
* check if it contains encoded Unicode segments, and use
* g_hostname_to_unicode() to convert it if it does.)
*
* Return value: @target's hostname
*
* Since: 2.22
**/
const gchar *
g_srv_target_get_hostname (GSrvTarget *target)
{
return target->hostname;
}
/**
* g_srv_target_get_port:
* @target: a #GSrvTarget
*
* Gets @target's port
*
* Return value: @target's port
*
* Since: 2.22
**/
guint16
g_srv_target_get_port (GSrvTarget *target)
{
return target->port;
}
/**
* g_srv_target_get_priority:
* @target: a #GSrvTarget
*
* Gets @target's priority. You should not need to look at this;
* #GResolver already sorts the targets according to the algorithm in
* RFC 2782.
*
* Return value: @target's priority
*
* Since: 2.22
**/
guint16
g_srv_target_get_priority (GSrvTarget *target)
{
return target->priority;
}
/**
* g_srv_target_get_weight:
* @target: a #GSrvTarget
*
* Gets @target's weight. You should not need to look at this;
* #GResolver already sorts the targets according to the algorithm in
* RFC 2782.
*
* Return value: @target's weight
*
* Since: 2.22
**/
guint16
g_srv_target_get_weight (GSrvTarget *target)
{
return target->weight;
}
gint
compare_target (gconstpointer a, gconstpointer b)
{
GSrvTarget *ta = (GSrvTarget *)a;
GSrvTarget *tb = (GSrvTarget *)b;