gresolver: Add g_resolver_lookup_by_name_with_flags{_async,_finish,}

This allows higher levels to have more control over resolving
(ipv4 or ipv6 for now) which allows for optimizations such
as requesting both in parallel as RFC 8305 recommends.
This commit is contained in:
Patrick Griffis 2018-10-17 11:14:10 -04:00 committed by Patrick Griffis
parent af39a37312
commit d6afa6c988
4 changed files with 589 additions and 223 deletions

View File

@ -1917,6 +1917,10 @@ g_resolver_set_default
g_resolver_lookup_by_name
g_resolver_lookup_by_name_async
g_resolver_lookup_by_name_finish
GResolverNameLookupFlags
g_resolver_lookup_by_name_with_flags
g_resolver_lookup_by_name_with_flags_async
g_resolver_lookup_by_name_with_flags_finish
g_resolver_free_addresses
g_resolver_lookup_by_address
g_resolver_lookup_by_address_async

View File

@ -3,6 +3,7 @@
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright (C) 2008 Red Hat, Inc.
* Copyright (C) 2018 Igalia S.L.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -30,6 +31,7 @@
#include "gsrvtarget.h"
#include "gthreadedresolver.h"
#include "gioerror.h"
#include "gcancellable.h"
#ifdef G_OS_UNIX
#include <sys/stat.h>
@ -347,6 +349,60 @@ handle_ip_address (const char *hostname,
return FALSE;
}
static GList *
lookup_by_name_real (GResolver *resolver,
const gchar *hostname,
GResolverNameLookupFlags flags,
GCancellable *cancellable,
GError **error)
{
GList *addrs;
gchar *ascii_hostname = NULL;
g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
g_return_val_if_fail (hostname != NULL, NULL);
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
/* Check if @hostname is just an IP address */
if (handle_ip_address (hostname, &addrs, error))
return addrs;
if (g_hostname_is_non_ascii (hostname))
hostname = ascii_hostname = g_hostname_to_ascii (hostname);
if (!hostname)
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
_("Invalid hostname"));
return NULL;
}
g_resolver_maybe_reload (resolver);
if (flags != G_RESOLVER_NAME_LOOKUP_FLAGS_DEFAULT)
{
if (!G_RESOLVER_GET_CLASS (resolver)->lookup_by_name_with_flags)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
/* Translators: The placeholder is for a function name. */
_("%s not implemented"), "lookup_by_name_with_flags");
g_free (ascii_hostname);
return NULL;
}
addrs = G_RESOLVER_GET_CLASS (resolver)->
lookup_by_name_with_flags (resolver, hostname, flags, cancellable, error);
}
else
addrs = G_RESOLVER_GET_CLASS (resolver)->
lookup_by_name (resolver, hostname, cancellable, error);
remove_duplicates (addrs);
g_free (ascii_hostname);
return addrs;
}
/**
* g_resolver_lookup_by_name:
* @resolver: a #GResolver
@ -391,36 +447,187 @@ g_resolver_lookup_by_name (GResolver *resolver,
GCancellable *cancellable,
GError **error)
{
GList *addrs;
gchar *ascii_hostname = NULL;
return lookup_by_name_real (resolver,
hostname,
G_RESOLVER_NAME_LOOKUP_FLAGS_DEFAULT,
cancellable,
error);
}
g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
g_return_val_if_fail (hostname != NULL, NULL);
/**
* g_resolver_lookup_by_name_with_flags:
* @resolver: a #GResolver
* @hostname: the hostname to look up
* @flags: extra #GResolverNameLookupFlags for the lookup
* @cancellable: (nullable): a #GCancellable, or %NULL
* @error: (nullable): return location for a #GError, or %NULL
*
* This differs from g_resolver_lookup_by_name() in that you can modify
* the lookup behavior with @flags. For example this can be used to limit
* results with #G_RESOLVER_NAME_LOOKUP_FLAGS_IPV4_ONLY.
*
* Returns: (element-type GInetAddress) (transfer full): a non-empty #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.)
*
* Since: 2.60
*/
GList *
g_resolver_lookup_by_name_with_flags (GResolver *resolver,
const gchar *hostname,
GResolverNameLookupFlags flags,
GCancellable *cancellable,
GError **error)
{
return lookup_by_name_real (resolver,
hostname,
flags,
cancellable,
error);
}
static void
lookup_by_name_async_real (GResolver *resolver,
const gchar *hostname,
GResolverNameLookupFlags flags,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
gchar *ascii_hostname = NULL;
GList *addrs;
GError *error = NULL;
g_return_if_fail (G_IS_RESOLVER (resolver));
g_return_if_fail (hostname != NULL);
g_return_if_fail (!(flags & G_RESOLVER_NAME_LOOKUP_FLAGS_IPV4_ONLY && flags & G_RESOLVER_NAME_LOOKUP_FLAGS_IPV6_ONLY));
/* Check if @hostname is just an IP address */
if (handle_ip_address (hostname, &addrs, error))
return addrs;
if (handle_ip_address (hostname, &addrs, &error))
{
GTask *task;
task = g_task_new (resolver, cancellable, callback, user_data);
g_task_set_source_tag (task, lookup_by_name_async_real);
if (addrs)
g_task_return_pointer (task, addrs, (GDestroyNotify) g_resolver_free_addresses);
else
g_task_return_error (task, error);
g_object_unref (task);
return;
}
if (g_hostname_is_non_ascii (hostname))
hostname = ascii_hostname = g_hostname_to_ascii (hostname);
if (!hostname)
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
GTask *task;
g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED,
_("Invalid hostname"));
return NULL;
task = g_task_new (resolver, cancellable, callback, user_data);
g_task_set_source_tag (task, lookup_by_name_async_real);
g_task_return_error (task, error);
g_object_unref (task);
return;
}
g_resolver_maybe_reload (resolver);
addrs = G_RESOLVER_GET_CLASS (resolver)->
lookup_by_name (resolver, hostname, cancellable, error);
if (flags != G_RESOLVER_NAME_LOOKUP_FLAGS_DEFAULT)
{
if (G_RESOLVER_GET_CLASS (resolver)->lookup_by_name_with_flags_async == NULL)
{
GTask *task;
g_set_error (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
/* Translators: The placeholder is for a function name. */
_("%s not implemented"), "lookup_by_name_with_flags_async");
task = g_task_new (resolver, cancellable, callback, user_data);
g_task_set_source_tag (task, lookup_by_name_async_real);
g_task_return_error (task, error);
g_object_unref (task);
}
else
G_RESOLVER_GET_CLASS (resolver)->
lookup_by_name_with_flags_async (resolver, hostname, flags, cancellable, callback, user_data);
}
else
G_RESOLVER_GET_CLASS (resolver)->
lookup_by_name_async (resolver, hostname, cancellable, callback, user_data);
g_free (ascii_hostname);
}
static GList *
lookup_by_name_finish_real (GResolver *resolver,
GAsyncResult *result,
GError **error,
gboolean with_flags)
{
GList *addrs;
g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
if (g_async_result_legacy_propagate_error (result, error))
return NULL;
else if (g_async_result_is_tagged (result, lookup_by_name_async_real))
{
/* Handle the stringified-IP-addr case */
return g_task_propagate_pointer (G_TASK (result), error);
}
if (with_flags)
{
g_assert (G_RESOLVER_GET_CLASS (resolver)->lookup_by_name_with_flags_finish != NULL);
addrs = G_RESOLVER_GET_CLASS (resolver)->
lookup_by_name_with_flags_finish (resolver, result, error);
}
else
addrs = G_RESOLVER_GET_CLASS (resolver)->
lookup_by_name_finish (resolver, result, error);
remove_duplicates (addrs);
g_free (ascii_hostname);
return addrs;
}
/**
* g_resolver_lookup_by_name_with_flags_async:
* @resolver: a #GResolver
* @hostname: the hostname to look up the address of
* @flags: extra #GResolverNameLookupFlags for the lookup
* @cancellable: (nullable): a #GCancellable, or %NULL
* @callback: (scope async): callback to call after resolution completes
* @user_data: (closure): data for @callback
*
* Begins asynchronously resolving @hostname to determine its
* associated IP address(es), and eventually calls @callback, which
* must call g_resolver_lookup_by_name_with_flags_finish() to get the result.
* See g_resolver_lookup_by_name() for more details.
*
* Since: 2.60
*/
void
g_resolver_lookup_by_name_with_flags_async (GResolver *resolver,
const gchar *hostname,
GResolverNameLookupFlags flags,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
lookup_by_name_async_real (resolver,
hostname,
flags,
cancellable,
callback,
user_data);
}
/**
* g_resolver_lookup_by_name_async:
* @resolver: a #GResolver
@ -443,49 +650,12 @@ g_resolver_lookup_by_name_async (GResolver *resolver,
GAsyncReadyCallback callback,
gpointer user_data)
{
gchar *ascii_hostname = NULL;
GList *addrs;
GError *error = NULL;
g_return_if_fail (G_IS_RESOLVER (resolver));
g_return_if_fail (hostname != NULL);
/* Check if @hostname is just an IP address */
if (handle_ip_address (hostname, &addrs, &error))
{
GTask *task;
task = g_task_new (resolver, cancellable, callback, user_data);
g_task_set_source_tag (task, g_resolver_lookup_by_name_async);
if (addrs)
g_task_return_pointer (task, addrs, (GDestroyNotify) g_resolver_free_addresses);
else
g_task_return_error (task, error);
g_object_unref (task);
return;
}
if (g_hostname_is_non_ascii (hostname))
hostname = ascii_hostname = g_hostname_to_ascii (hostname);
if (!hostname)
{
GTask *task;
g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED,
_("Invalid hostname"));
task = g_task_new (resolver, cancellable, callback, user_data);
g_task_set_source_tag (task, g_resolver_lookup_by_name_async);
g_task_return_error (task, error);
g_object_unref (task);
return;
}
g_resolver_maybe_reload (resolver);
G_RESOLVER_GET_CLASS (resolver)->
lookup_by_name_async (resolver, hostname, cancellable, callback, user_data);
g_free (ascii_hostname);
lookup_by_name_async_real (resolver,
hostname,
0,
cancellable,
callback,
user_data);
}
/**
@ -512,24 +682,40 @@ g_resolver_lookup_by_name_finish (GResolver *resolver,
GAsyncResult *result,
GError **error)
{
GList *addrs;
return lookup_by_name_finish_real (resolver,
result,
error,
FALSE);
}
g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
if (g_async_result_legacy_propagate_error (result, error))
return NULL;
else if (g_async_result_is_tagged (result, g_resolver_lookup_by_name_async))
{
/* Handle the stringified-IP-addr case */
return g_task_propagate_pointer (G_TASK (result), error);
}
addrs = G_RESOLVER_GET_CLASS (resolver)->
lookup_by_name_finish (resolver, result, error);
remove_duplicates (addrs);
return addrs;
/**
* g_resolver_lookup_by_name_with_flags_finish:
* @resolver: a #GResolver
* @result: the result passed to your #GAsyncReadyCallback
* @error: return location for a #GError, or %NULL
*
* Retrieves the result of a call to
* g_resolver_lookup_by_name_with_flags_async().
*
* If the DNS resolution failed, @error (if non-%NULL) will be set to
* a value from #GResolverError. If the operation was cancelled,
* @error will be set to %G_IO_ERROR_CANCELLED.
*
* Returns: (element-type GInetAddress) (transfer full): a #GList
* of #GInetAddress, or %NULL on error. See g_resolver_lookup_by_name()
* for more details.
*
* Since: 2.60
*/
GList *
g_resolver_lookup_by_name_with_flags_finish (GResolver *resolver,
GAsyncResult *result,
GError **error)
{
return lookup_by_name_finish_real (resolver,
result,
error,
TRUE);
}
/**

View File

@ -1,6 +1,7 @@
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright (C) 2008 Red Hat, Inc.
* Copyright (C) 2018 Igalia S.L.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -43,158 +44,237 @@ struct _GResolver {
GResolverPrivate *priv;
};
/**
* GResolverNameLookupFlags:
* @G_RESOLVER_NAME_LOOKUP_FLAGS_DEFAULT: default behavior (same as g_resolver_lookup_by_name())
* @G_RESOLVER_NAME_LOOKUP_FLAGS_IPV4_ONLY: only resolve ipv4 addresses
* @G_RESOLVER_NAME_LOOKUP_FLAGS_IPV6_ONLY: only resolve ipv6 addresses
*
* Flags to modify lookup behavior.
*
* Since: 2.60
*/
typedef enum {
G_RESOLVER_NAME_LOOKUP_FLAGS_DEFAULT = 0,
G_RESOLVER_NAME_LOOKUP_FLAGS_IPV4_ONLY = 1 << 0,
G_RESOLVER_NAME_LOOKUP_FLAGS_IPV6_ONLY = 1 << 1,
} GResolverNameLookupFlags;
struct _GResolverClass {
GObjectClass parent_class;
/* Signals */
void ( *reload) (GResolver *resolver);
void ( *reload) (GResolver *resolver);
/* Virtual methods */
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);
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);
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);
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);
GList * ( *lookup_records) (GResolver *resolver,
const gchar *rrname,
GResolverRecordType record_type,
GCancellable *cancellable,
GError **error);
GList * ( *lookup_records) (GResolver *resolver,
const gchar *rrname,
GResolverRecordType record_type,
GCancellable *cancellable,
GError **error);
void ( *lookup_records_async) (GResolver *resolver,
const gchar *rrname,
GResolverRecordType record_type,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
void ( *lookup_records_async) (GResolver *resolver,
const gchar *rrname,
GResolverRecordType record_type,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GList * ( *lookup_records_finish) (GResolver *resolver,
GAsyncResult *result,
GError **error);
/* Padding for future expansion */
void (*_g_reserved4) (void);
void (*_g_reserved5) (void);
void (*_g_reserved6) (void);
GList * ( *lookup_records_finish) (GResolver *resolver,
GAsyncResult *result,
GError **error);
/**
* GResolverClass::lookup_by_name_with_flags_async:
* @resolver: a #GResolver
* @hostname: the hostname to resolve
* @flags: extra #GResolverNameLookupFlags to modify the lookup
* @cancellable: (nullable): a #GCancellable
* @callback: (scope async): a #GAsyncReadyCallback to call when completed
* @user_data: (closure): data to pass to @callback
*
* Asynchronous version of GResolverClass::lookup_by_name_with_flags
*
* GResolverClass::lookup_by_name_with_flags_finish will be called to get
* the result.
*
* Since: 2.60
*/
void ( *lookup_by_name_with_flags_async) (GResolver *resolver,
const gchar *hostname,
GResolverNameLookupFlags flags,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
/**
* GResolverClass::lookup_by_name_with_flags_finish:
* @resolver: a #GResolver
* @result: a #GAsyncResult
* @error: (nullable): a pointer to a %NULL #GError
*
* Gets the result from GResolverClass::lookup_by_name_with_flags_async
*
* Returns: (element-type GInetAddress) (transfer full): List of #GInetAddress.
* Since: 2.60
*/
GList * ( *lookup_by_name_with_flags_finish) (GResolver *resolver,
GAsyncResult *result,
GError **error);
/**
* GResolverClass::lookup_by_name_with_flags:
* @resolver: a #GResolver
* @hostname: the hostname to resolve
* @flags: extra #GResolverNameLookupFlags to modify the lookup
* @cancellable: (nullable): a #GCancellable
* @error: (nullable): a pointer to a %NULL #GError
*
* This is identical to GResolverClass::lookup_by_name except it takes
* @flags which modifies the behavior of the lookup. See #GResolverNameLookupFlags
* for more details.
*
* Returns: (element-type GInetAddress) (transfer full): List of #GInetAddress.
* Since: 2.60
*/
GList * ( *lookup_by_name_with_flags) (GResolver *resolver,
const gchar *hostname,
GResolverNameLookupFlags flags,
GCancellable *cancellable,
GError **error);
};
GLIB_AVAILABLE_IN_ALL
GType g_resolver_get_type (void) G_GNUC_CONST;
GType g_resolver_get_type (void) G_GNUC_CONST;
GLIB_AVAILABLE_IN_ALL
GResolver *g_resolver_get_default (void);
GResolver *g_resolver_get_default (void);
GLIB_AVAILABLE_IN_ALL
void g_resolver_set_default (GResolver *resolver);
void g_resolver_set_default (GResolver *resolver);
GLIB_AVAILABLE_IN_ALL
GList *g_resolver_lookup_by_name (GResolver *resolver,
const gchar *hostname,
GCancellable *cancellable,
GError **error);
GList *g_resolver_lookup_by_name (GResolver *resolver,
const gchar *hostname,
GCancellable *cancellable,
GError **error);
GLIB_AVAILABLE_IN_ALL
void g_resolver_lookup_by_name_async (GResolver *resolver,
const gchar *hostname,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
void g_resolver_lookup_by_name_async (GResolver *resolver,
const gchar *hostname,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GLIB_AVAILABLE_IN_ALL
GList *g_resolver_lookup_by_name_finish (GResolver *resolver,
GAsyncResult *result,
GError **error);
GList *g_resolver_lookup_by_name_finish (GResolver *resolver,
GAsyncResult *result,
GError **error);
GLIB_AVAILABLE_IN_2_60
void g_resolver_lookup_by_name_with_flags_async (GResolver *resolver,
const gchar *hostname,
GResolverNameLookupFlags flags,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GLIB_AVAILABLE_IN_2_60
GList *g_resolver_lookup_by_name_with_flags_finish (GResolver *resolver,
GAsyncResult *result,
GError **error);
GLIB_AVAILABLE_IN_2_60
GList *g_resolver_lookup_by_name_with_flags (GResolver *resolver,
const gchar *hostname,
GResolverNameLookupFlags flags,
GCancellable *cancellable,
GError **error);
GLIB_AVAILABLE_IN_ALL
void g_resolver_free_addresses (GList *addresses);
void g_resolver_free_addresses (GList *addresses);
GLIB_AVAILABLE_IN_ALL
gchar *g_resolver_lookup_by_address (GResolver *resolver,
GInetAddress *address,
GCancellable *cancellable,
GError **error);
gchar *g_resolver_lookup_by_address (GResolver *resolver,
GInetAddress *address,
GCancellable *cancellable,
GError **error);
GLIB_AVAILABLE_IN_ALL
void g_resolver_lookup_by_address_async (GResolver *resolver,
GInetAddress *address,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
void g_resolver_lookup_by_address_async (GResolver *resolver,
GInetAddress *address,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GLIB_AVAILABLE_IN_ALL
gchar *g_resolver_lookup_by_address_finish (GResolver *resolver,
GAsyncResult *result,
GError **error);
gchar *g_resolver_lookup_by_address_finish (GResolver *resolver,
GAsyncResult *result,
GError **error);
GLIB_AVAILABLE_IN_ALL
GList *g_resolver_lookup_service (GResolver *resolver,
const gchar *service,
const gchar *protocol,
const gchar *domain,
GCancellable *cancellable,
GError **error);
GList *g_resolver_lookup_service (GResolver *resolver,
const gchar *service,
const gchar *protocol,
const gchar *domain,
GCancellable *cancellable,
GError **error);
GLIB_AVAILABLE_IN_ALL
void g_resolver_lookup_service_async (GResolver *resolver,
const gchar *service,
const gchar *protocol,
const gchar *domain,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
void g_resolver_lookup_service_async (GResolver *resolver,
const gchar *service,
const gchar *protocol,
const gchar *domain,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GLIB_AVAILABLE_IN_ALL
GList *g_resolver_lookup_service_finish (GResolver *resolver,
GAsyncResult *result,
GError **error);
GList *g_resolver_lookup_service_finish (GResolver *resolver,
GAsyncResult *result,
GError **error);
GLIB_AVAILABLE_IN_2_34
GList *g_resolver_lookup_records (GResolver *resolver,
const gchar *rrname,
GResolverRecordType record_type,
GCancellable *cancellable,
GError **error);
GList *g_resolver_lookup_records (GResolver *resolver,
const gchar *rrname,
GResolverRecordType record_type,
GCancellable *cancellable,
GError **error);
GLIB_AVAILABLE_IN_2_34
void g_resolver_lookup_records_async (GResolver *resolver,
const gchar *rrname,
GResolverRecordType record_type,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
void g_resolver_lookup_records_async (GResolver *resolver,
const gchar *rrname,
GResolverRecordType record_type,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GLIB_AVAILABLE_IN_2_34
GList *g_resolver_lookup_records_finish (GResolver *resolver,
GAsyncResult *result,
GError **error);
GList *g_resolver_lookup_records_finish (GResolver *resolver,
GAsyncResult *result,
GError **error);
GLIB_AVAILABLE_IN_ALL
void g_resolver_free_targets (GList *targets);
void g_resolver_free_targets (GList *targets);
/**
* G_RESOLVER_ERROR:

View File

@ -3,6 +3,7 @@
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright (C) 2008 Red Hat, Inc.
* Copyright (C) 2018 Igalia S.L.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -63,7 +64,27 @@ g_resolver_error_from_addrinfo_error (gint err)
}
}
static struct addrinfo addrinfo_hints;
typedef struct {
char *hostname;
int address_family;
} LookupData;
static LookupData *
lookup_data_new (const char *hostname,
int address_family)
{
LookupData *data = g_new (LookupData, 1);
data->hostname = g_strdup (hostname);
data->address_family = address_family;
return data;
}
static void
lookup_data_free (LookupData *data)
{
g_free (data->hostname);
g_free (data);
}
static void
do_lookup_by_name (GTask *task,
@ -71,11 +92,24 @@ do_lookup_by_name (GTask *task,
gpointer task_data,
GCancellable *cancellable)
{
const char *hostname = task_data;
LookupData *lookup_data = task_data;
const char *hostname = lookup_data->hostname;
struct addrinfo *res = NULL;
GList *addresses;
gint retval;
struct addrinfo addrinfo_hints = { 0 };
#ifdef AI_ADDRCONFIG
addrinfo_hints.ai_flags = AI_ADDRCONFIG;
#endif
/* socktype and protocol don't actually matter, they just get copied into the
* returned addrinfo structures (and then we ignore them). But if
* we leave them unset, we'll get back duplicate answers.
*/
addrinfo_hints.ai_socktype = SOCK_STREAM;
addrinfo_hints.ai_protocol = IPPROTO_TCP;
addrinfo_hints.ai_family = lookup_data->address_family;
retval = getaddrinfo (hostname, NULL, &addrinfo_hints, &res);
if (retval == 0)
@ -139,10 +173,53 @@ lookup_by_name (GResolver *resolver,
{
GTask *task;
GList *addresses;
LookupData *data;
data = lookup_data_new (hostname, AF_UNSPEC);
task = g_task_new (resolver, cancellable, NULL, NULL);
g_task_set_source_tag (task, lookup_by_name);
g_task_set_task_data (task, g_strdup (hostname), g_free);
g_task_set_task_data (task, data, (GDestroyNotify)lookup_data_free);
g_task_set_return_on_cancel (task, TRUE);
g_task_run_in_thread_sync (task, do_lookup_by_name);
addresses = g_task_propagate_pointer (task, error);
g_object_unref (task);
return addresses;
}
static int
flags_to_family (GResolverNameLookupFlags flags)
{
int address_family = AF_UNSPEC;
if (flags & G_RESOLVER_NAME_LOOKUP_FLAGS_IPV4_ONLY)
address_family = AF_INET;
if (flags & G_RESOLVER_NAME_LOOKUP_FLAGS_IPV6_ONLY)
{
address_family = AF_INET6;
/* You can only filter by one family at a time */
g_return_val_if_fail (!(flags & G_RESOLVER_NAME_LOOKUP_FLAGS_IPV4_ONLY), address_family);
}
return address_family;
}
static GList *
lookup_by_name_with_flags (GResolver *resolver,
const gchar *hostname,
GResolverNameLookupFlags flags,
GCancellable *cancellable,
GError **error)
{
GTask *task;
GList *addresses;
LookupData *data;
data = lookup_data_new (hostname, AF_UNSPEC);
task = g_task_new (resolver, cancellable, NULL, NULL);
g_task_set_source_tag (task, lookup_by_name_with_flags);
g_task_set_task_data (task, data, (GDestroyNotify)lookup_data_free);
g_task_set_return_on_cancel (task, TRUE);
g_task_run_in_thread_sync (task, do_lookup_by_name);
addresses = g_task_propagate_pointer (task, error);
@ -151,6 +228,26 @@ lookup_by_name (GResolver *resolver,
return addresses;
}
static void
lookup_by_name_with_flags_async (GResolver *resolver,
const gchar *hostname,
GResolverNameLookupFlags flags,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task;
LookupData *data;
data = lookup_data_new (hostname, flags_to_family (flags));
task = g_task_new (resolver, cancellable, callback, user_data);
g_task_set_source_tag (task, lookup_by_name_with_flags_async);
g_task_set_task_data (task, data, (GDestroyNotify)lookup_data_free);
g_task_set_return_on_cancel (task, TRUE);
g_task_run_in_thread (task, do_lookup_by_name);
g_object_unref (task);
}
static void
lookup_by_name_async (GResolver *resolver,
const gchar *hostname,
@ -158,14 +255,12 @@ lookup_by_name_async (GResolver *resolver,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task;
task = g_task_new (resolver, cancellable, callback, user_data);
g_task_set_source_tag (task, lookup_by_name_async);
g_task_set_task_data (task, g_strdup (hostname), g_free);
g_task_set_return_on_cancel (task, TRUE);
g_task_run_in_thread (task, do_lookup_by_name);
g_object_unref (task);
lookup_by_name_with_flags_async (resolver,
hostname,
G_RESOLVER_NAME_LOOKUP_FLAGS_DEFAULT,
cancellable,
callback,
user_data);
}
static GList *
@ -178,6 +273,15 @@ lookup_by_name_finish (GResolver *resolver,
return g_task_propagate_pointer (G_TASK (result), error);
}
static GList *
lookup_by_name_with_flags_finish (GResolver *resolver,
GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (g_task_is_valid (result, resolver), NULL);
return g_task_propagate_pointer (G_TASK (result), error);
}
static void
do_lookup_by_address (GTask *task,
@ -970,24 +1074,16 @@ g_threaded_resolver_class_init (GThreadedResolverClass *threaded_class)
{
GResolverClass *resolver_class = G_RESOLVER_CLASS (threaded_class);
resolver_class->lookup_by_name = lookup_by_name;
resolver_class->lookup_by_name_async = lookup_by_name_async;
resolver_class->lookup_by_name_finish = lookup_by_name_finish;
resolver_class->lookup_by_address = lookup_by_address;
resolver_class->lookup_by_address_async = lookup_by_address_async;
resolver_class->lookup_by_address_finish = lookup_by_address_finish;
resolver_class->lookup_records = lookup_records;
resolver_class->lookup_records_async = lookup_records_async;
resolver_class->lookup_records_finish = lookup_records_finish;
/* Initialize addrinfo_hints */
#ifdef AI_ADDRCONFIG
addrinfo_hints.ai_flags |= AI_ADDRCONFIG;
#endif
/* These two don't actually matter, they just get copied into the
* returned addrinfo structures (and then we ignore them). But if
* we leave them unset, we'll get back duplicate answers.
*/
addrinfo_hints.ai_socktype = SOCK_STREAM;
addrinfo_hints.ai_protocol = IPPROTO_TCP;
resolver_class->lookup_by_name = lookup_by_name;
resolver_class->lookup_by_name_async = lookup_by_name_async;
resolver_class->lookup_by_name_finish = lookup_by_name_finish;
resolver_class->lookup_by_name_with_flags = lookup_by_name_with_flags;
resolver_class->lookup_by_name_with_flags_async = lookup_by_name_with_flags_async;
resolver_class->lookup_by_name_with_flags_finish = lookup_by_name_with_flags_finish;
resolver_class->lookup_by_address = lookup_by_address;
resolver_class->lookup_by_address_async = lookup_by_address_async;
resolver_class->lookup_by_address_finish = lookup_by_address_finish;
resolver_class->lookup_records = lookup_records;
resolver_class->lookup_records_async = lookup_records_async;
resolver_class->lookup_records_finish = lookup_records_finish;
}