[glib/wip/tingping/happy-eyeballs: 3/6] gresolver: Add g_resolver_lookup_by_name_with_flags{_async, _finish, }



commit fdc75ecd00d54d6caf295ce4b87c2f63c6cac087
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         | 312 ++++++++++++++++++++++++++++++++++++++----------
 gio/gresolver.h         | 288 +++++++++++++++++++++++++-------------------
 gio/gthreadedresolver.c | 163 ++++++++++++++++++++-----
 3 files changed, 543 insertions(+), 220 deletions(-)
---
diff --git a/gio/gresolver.c b/gio/gresolver.c
index b60544a20..5615e0a1c 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
@@ -347,6 +348,59 @@ handle_ip_address (const char  *hostname,
   return FALSE;
 }
 
+static GList *
+lookup_by_name_real (GResolver                 *resolver,
+                     const gchar               *hostname,
+                     GResolverNameLookupFlags   flags,
+                     gboolean                   with_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);
+
+  /* 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 (with_flags)
+    {
+      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 +445,52 @@ 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, FALSE,
+                              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: 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.
+ * See g_resolver_lookup_by_name() for more information.
  *
- * 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, TRUE,
+                              cancellable,
+                              error);
+}
+
+static void
+lookup_by_name_async_real (GResolver                *resolver,
+                           const gchar              *hostname,
+                           GResolverNameLookupFlags  flags,
+                           gboolean                  with_flags,
+                           GCancellable             *cancellable,
+                           GAsyncReadyCallback       callback,
+                           gpointer                  user_data)
 {
   gchar *ascii_hostname = NULL;
   GList *addrs;
@@ -456,7 +505,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 +524,138 @@ 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 (with_flags)
+    {
+      if (G_RESOLVER_GET_CLASS (resolver)->lookup_by_name_with_flags_async == NULL)
+        {
+          GTask *task;
+
+          g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                               _("lookup_by_name_with_flags_async not implemented"));
+          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);
+
+  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_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                               _("lookup_by_name_with_flags_finish not implemented"));
+          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, TRUE,
+                             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, FALSE,
+                             cancellable,
+                             callback,
+                             user_data);
+}
+
 /**
  * g_resolver_lookup_by_name_finish:
  * @resolver: a #GResolver
@@ -512,24 +680,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..5ba762989 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,193 @@ struct _GResolver {
   GResolverPrivate *priv;
 };
 
+/**
+ * GResolverNameLookupFlags:
+ * @G_RESOLVER_NAME_LOOKUP_FLAGS_DEFAULT: lookup behavior is unchanged
+ * @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.
+ */
+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);
+  void    ( *lookup_by_name_with_flags_async)  (GResolver                 *resolver,
+                                                const gchar               *hostname,
+                                                GResolverNameLookupFlags   flags,
+                                                GCancellable              *cancellable,
+                                                GAsyncReadyCallback        callback,
+                                                gpointer                   user_data);
+  GList * ( *lookup_by_name_with_flags_finish) (GResolver                 *resolver,
+                                                GAsyncResult              *result,
+                                                GError                   **error);
+  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..8e88be552 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,43 @@ g_resolver_error_from_addrinfo_error (gint err)
     }
 }
 
-static struct addrinfo addrinfo_hints;
+#ifndef AI_ADDRCONFIG
+#define G_ADDRCONFIG 0
+#else
+#define G_ADDRCONFIG 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.
+ */
+#define ADDRINFO_INIT { \
+  .ai_flags = G_ADDRCONFIG, \
+  .ai_socktype = SOCK_STREAM, \
+  .ai_protocol = IPPROTO_TCP, \
+}
+
+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 +108,14 @@ 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 = ADDRINFO_INIT;
 
+  addrinfo_hints.ai_family = lookup_data->address_family;
   retval = getaddrinfo (hostname, NULL, &addrinfo_hints, &res);
 
   if (retval == 0)
@@ -139,10 +179,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_warning ("G_RESOLVER_NAME_LOOKUP_FLAGS_IPV4_ONLY ignored because 
G_RESOLVER_NAME_LOOKUP_FLAGS_IPV6_ONLY set");
+    }
+
+  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 +236,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 +280,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 +1081,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]