[glib/wip/tingping/happy-eyeballs: 1/4] gresolver: Add g_resolver_lookup_by_name_with_flags{_async, _finish, }
- From: Patrick Griffis <pgriffis src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/wip/tingping/happy-eyeballs: 1/4] gresolver: Add g_resolver_lookup_by_name_with_flags{_async, _finish, }
- Date: Fri, 9 Nov 2018 14:10:30 +0000 (UTC)
commit 6385165d26b090505537c82ad111b9f668339d5e
Author: Patrick Griffis <pgriffis igalia com>
Date: Wed Oct 17 11:14:10 2018 -0400
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.
gio/gresolver.c | 320 ++++++++++++++++++++++++++++++++++++----------
gio/gresolver.h | 332 ++++++++++++++++++++++++++++++------------------
gio/gthreadedresolver.c | 157 ++++++++++++++++++-----
3 files changed, 589 insertions(+), 220 deletions(-)
---
diff --git a/gio/gresolver.c b/gio/gresolver.c
index b60544a20..a7ba08146 100644
--- a/gio/gresolver.c
+++ b/gio/gresolver.c
@@ -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_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("lookup_by_name_with_flags not implemented"));
+ 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,57 +447,53 @@ g_resolver_lookup_by_name (GResolver *resolver,
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);
-
- /* 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);
- addrs = G_RESOLVER_GET_CLASS (resolver)->
- lookup_by_name (resolver, hostname, cancellable, error);
-
- remove_duplicates (addrs);
-
- g_free (ascii_hostname);
- return addrs;
+ return lookup_by_name_real (resolver,
+ hostname,
+ 0,
+ cancellable,
+ error);
}
/**
- * g_resolver_lookup_by_name_async:
+ * g_resolver_lookup_by_name_with_flags:
* @resolver: a #GResolver
- * @hostname: the hostname to look up the address of
+ * @hostname: the hostname to look up
+ * @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
+ * @error: (nullable): return location for a #GError, or %NULL
*
- * Begins asynchronously resolving @hostname to determine its
- * associated IP address(es), and eventually calls @callback, which
- * must call g_resolver_lookup_by_name_finish() to get the result.
- * See g_resolver_lookup_by_name() for more details.
+ * 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.
*
- * Since: 2.22
+ * 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
*/
-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_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;
@@ -449,6 +501,7 @@ g_resolver_lookup_by_name_async (GResolver *resolver,
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))
@@ -456,7 +509,7 @@ g_resolver_lookup_by_name_async (GResolver *resolver,
GTask *task;
task = g_task_new (resolver, cancellable, callback, user_data);
- g_task_set_source_tag (task, g_resolver_lookup_by_name_async);
+ 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
@@ -475,19 +528,142 @@ g_resolver_lookup_by_name_async (GResolver *resolver,
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_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);
- G_RESOLVER_GET_CLASS (resolver)->
- lookup_by_name_async (resolver, hostname, cancellable, callback, user_data);
+
+ 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)
+ {
+ if (G_RESOLVER_GET_CLASS (resolver)->lookup_by_name_with_flags_finish == NULL)
+ {
+ 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_finish");
+ return 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);
+
+ 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
+ * @hostname: the hostname to look up the address of
+ * @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_finish() to get the result.
+ * See g_resolver_lookup_by_name() for more details.
+ *
+ * Since: 2.22
+ */
+void
+g_resolver_lookup_by_name_async (GResolver *resolver,
+ const gchar *hostname,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ lookup_by_name_async_real (resolver,
+ hostname,
+ 0,
+ cancellable,
+ callback,
+ user_data);
+}
+
/**
* g_resolver_lookup_by_name_finish:
* @resolver: a #GResolver
@@ -512,24 +688,40 @@ g_resolver_lookup_by_name_finish (GResolver *resolver,
GAsyncResult *result,
GError **error)
{
- GList *addrs;
-
- 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 lookup_by_name_finish_real (resolver,
+ result,
+ error,
+ FALSE);
+}
- 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);
}
/**
diff --git a/gio/gresolver.h b/gio/gresolver.h
index a39e8f7fd..dc4ba59a1 100644
--- a/gio/gresolver.h
+++ b/gio/gresolver.h
@@ -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);
-
- 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_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);
-
- 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_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);
+
+ 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);
+
+ 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:
diff --git a/gio/gthreadedresolver.c b/gio/gthreadedresolver.c
index 9e110cd0b..639cb8084 100644
--- a/gio/gthreadedresolver.c
+++ b/gio/gthreadedresolver.c
@@ -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,54 @@ 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 */
+ if (flags & G_RESOLVER_NAME_LOOKUP_FLAGS_IPV4_ONLY)
+ g_assert_not_reached ();
+ }
+
+ 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);
@@ -152,22 +230,40 @@ lookup_by_name (GResolver *resolver,
}
static void
-lookup_by_name_async (GResolver *resolver,
- const gchar *hostname,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
+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_async);
- g_task_set_task_data (task, g_strdup (hostname), g_free);
+ 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,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ lookup_by_name_with_flags_async (resolver,
+ hostname,
+ G_RESOLVER_NAME_LOOKUP_FLAGS_DEFAULT,
+ cancellable,
+ callback,
+ user_data);
+}
+
static GList *
lookup_by_name_finish (GResolver *resolver,
GAsyncResult *result,
@@ -178,6 +274,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 +1075,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;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]