[glib] GNetworkAddress: drop cached addresses on resolver reload



commit c6c11665668c47841011258e5dbca07ad3d8aba0
Author: Dan Winship <danw gnome org>
Date:   Tue Feb 19 15:19:22 2013 -0500

    GNetworkAddress: drop cached addresses on resolver reload
    
    If the resolver reloads (ie, if /etc/resolv.conf changes),
    GNetworkAddress needs to re-resolve its addresses the next time it's
    enumerated. Otherwise hosts that have different IP addresses inside
    and outside a VPN won't work correctly if you hold on to a
    GNetworkAddress for them for a long time.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=694181

 gio/gnetworkaddress.c    |   70 +++++++++++++++++++++++++++++++++------------
 gio/gnetworkingprivate.h |    2 +
 gio/gresolver.c          |   14 +++++++++
 3 files changed, 67 insertions(+), 19 deletions(-)
---
diff --git a/gio/gnetworkaddress.c b/gio/gnetworkaddress.c
index 1335d94..2e4042c 100644
--- a/gio/gnetworkaddress.c
+++ b/gio/gnetworkaddress.c
@@ -65,6 +65,8 @@ struct _GNetworkAddressPrivate {
   guint16 port;
   GList *sockaddrs;
   gchar *scheme;
+
+  gint64 resolver_serial;
 };
 
 enum {
@@ -226,7 +228,8 @@ g_network_address_get_property (GObject    *object,
 
 static void
 g_network_address_set_addresses (GNetworkAddress *addr,
-                                 GList           *addresses)
+                                 GList           *addresses,
+                                 guint64          resolver_serial)
 {
   GList *a;
   GSocketAddress *sockaddr;
@@ -241,6 +244,8 @@ g_network_address_set_addresses (GNetworkAddress *addr,
     }
   g_list_free (addresses);
   addr->priv->sockaddrs = g_list_reverse (addr->priv->sockaddrs);
+
+  addr->priv->resolver_serial = resolver_serial;
 }
 
 static gboolean
@@ -846,26 +851,39 @@ g_network_address_address_enumerator_next (GSocketAddressEnumerator  *enumerator
 
   if (addr_enum->addresses == NULL)
     {
-      if (!addr_enum->addr->priv->sockaddrs)
-        g_network_address_parse_sockaddr (addr_enum->addr);
-      if (!addr_enum->addr->priv->sockaddrs)
+      GNetworkAddress *addr = addr_enum->addr;
+      GResolver *resolver = g_resolver_get_default ();
+      gint64 serial = g_resolver_get_serial (resolver);
+
+      if (addr->priv->resolver_serial != 0 &&
+          addr->priv->resolver_serial != serial)
+        {
+          /* Resolver has reloaded, discard cached addresses */
+          g_list_free_full (addr->priv->sockaddrs, g_object_unref);
+          addr->priv->sockaddrs = NULL;
+        }
+
+      if (!addr->priv->sockaddrs)
+        g_network_address_parse_sockaddr (addr);
+      if (!addr->priv->sockaddrs)
         {
-          GResolver *resolver = g_resolver_get_default ();
           GList *addresses;
 
           addresses = g_resolver_lookup_by_name (resolver,
-                                                 addr_enum->addr->priv->hostname,
+                                                 addr->priv->hostname,
                                                  cancellable, error);
-          g_object_unref (resolver);
-
           if (!addresses)
-            return NULL;
+            {
+              g_object_unref (resolver);
+              return NULL;
+            }
 
-          g_network_address_set_addresses (addr_enum->addr, addresses);
+          g_network_address_set_addresses (addr, addresses, serial);
         }
           
-      addr_enum->addresses = addr_enum->addr->priv->sockaddrs;
+      addr_enum->addresses = addr->priv->sockaddrs;
       addr_enum->next = addr_enum->addresses;
+      g_object_unref (resolver);
     }
 
   if (addr_enum->next == NULL)
@@ -916,7 +934,10 @@ got_addresses (GObject      *source_object,
       addresses = g_resolver_lookup_by_name_finish (resolver, result, &error);
 
       if (!error)
-        g_network_address_set_addresses (addr_enum->addr, addresses);
+        {
+          g_network_address_set_addresses (addr_enum->addr, addresses,
+                                           g_resolver_get_serial (resolver));
+        }
     }
   have_addresses (addr_enum, task, error);
 }
@@ -936,25 +957,36 @@ g_network_address_address_enumerator_next_async (GSocketAddressEnumerator  *enum
 
   if (addr_enum->addresses == NULL)
     {
-      if (!addr_enum->addr->priv->sockaddrs)
+      GNetworkAddress *addr = addr_enum->addr;
+      GResolver *resolver = g_resolver_get_default ();
+      gint64 serial = g_resolver_get_serial (resolver);
+
+      if (addr->priv->resolver_serial != 0 &&
+          addr->priv->resolver_serial != serial)
+        {
+          /* Resolver has reloaded, discard cached addresses */
+          g_list_free_full (addr->priv->sockaddrs, g_object_unref);
+          addr->priv->sockaddrs = NULL;
+        }
+
+      if (!addr->priv->sockaddrs)
         {
-          if (g_network_address_parse_sockaddr (addr_enum->addr))
+          if (g_network_address_parse_sockaddr (addr))
             have_addresses (addr_enum, task, NULL);
           else
             {
-              GResolver *resolver = g_resolver_get_default ();
-
               g_resolver_lookup_by_name_async (resolver,
-                                               addr_enum->addr->priv->hostname,
+                                               addr->priv->hostname,
                                                cancellable,
                                                got_addresses, task);
-              g_object_unref (resolver);
             }
+          g_object_unref (resolver);
           return;
         }
 
-      addr_enum->addresses = addr_enum->addr->priv->sockaddrs;
+      addr_enum->addresses = addr->priv->sockaddrs;
       addr_enum->next = addr_enum->addresses;
+      g_object_unref (resolver);
     }
 
   if (addr_enum->next)
diff --git a/gio/gnetworkingprivate.h b/gio/gnetworkingprivate.h
index 1a299c9..4341dc7 100644
--- a/gio/gnetworkingprivate.h
+++ b/gio/gnetworkingprivate.h
@@ -34,6 +34,8 @@ gchar *  _g_uri_from_authority             (const gchar      *protocol,
                                            guint             port,
                                            const gchar      *userinfo);
 
+guint64  g_resolver_get_serial             (GResolver        *resolver);
+
 gint g_socket (gint     domain,
                gint     type,
                gint     protocol,
diff --git a/gio/gresolver.c b/gio/gresolver.c
index 589e324..5549e4f 100644
--- a/gio/gresolver.c
+++ b/gio/gresolver.c
@@ -846,6 +846,20 @@ g_resolver_lookup_records_finish (GResolver     *resolver,
     lookup_records_finish (resolver, result, error);
 }
 
+guint64
+g_resolver_get_serial (GResolver *resolver)
+{
+  g_return_val_if_fail (G_IS_RESOLVER (resolver), 0);
+
+  g_resolver_maybe_reload (resolver);
+
+#ifdef G_OS_UNIX
+  return (guint64) resolver->priv->resolv_conf_timestamp;
+#else
+  return 1;
+#endif
+}
+
 /**
  * g_resolver_error_quark:
  *


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]