From cce3001d5d4f477643d25a7f3d300da94a5dbabf Mon Sep 17 00:00:00 2001 From: Patrick Griffis Date: Mon, 24 Mar 2025 11:01:54 -0500 Subject: [PATCH] threadedresolver: Cache network interface checks --- gio/gthreadedresolver.c | 62 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 55 insertions(+), 7 deletions(-) diff --git a/gio/gthreadedresolver.c b/gio/gthreadedresolver.c index e2e2d35d5..b7965c5d4 100644 --- a/gio/gthreadedresolver.c +++ b/gio/gthreadedresolver.c @@ -36,6 +36,7 @@ #include "gcancellable.h" #include "ginetaddress.h" #include "ginetsocketaddress.h" +#include "gnetworkmonitorbase.h" #include "gtask.h" #include "gsocketaddress.h" #include "gsrvtarget.h" @@ -90,6 +91,11 @@ struct _GThreadedResolver GResolver parent_instance; GThreadPool *thread_pool; /* (owned) */ + + GMutex interface_mutex; + GNetworkMonitor *network_monitor; /* (owned) */ + gboolean monitor_supports_caching; + int network_is_loopback_only; }; G_DEFINE_TYPE (GThreadedResolver, g_threaded_resolver, G_TYPE_RESOLVER) @@ -110,6 +116,10 @@ g_threaded_resolver_init (GThreadedResolver *self) 20, FALSE, NULL); + + self->network_is_loopback_only = -1; + + g_mutex_init (&self->interface_mutex); } static void @@ -120,6 +130,12 @@ g_threaded_resolver_finalize (GObject *object) g_thread_pool_free (self->thread_pool, TRUE, FALSE); self->thread_pool = NULL; + if (self->network_monitor) + g_signal_handlers_disconnect_by_data (self->network_monitor, object); + + g_clear_object (&self->network_monitor); + g_mutex_clear (&self->interface_mutex); + G_OBJECT_CLASS (g_threaded_resolver_parent_class)->finalize (object); } @@ -260,7 +276,7 @@ lookup_data_free (LookupData *data) } static gboolean -only_has_loopback_interfaces (void) +check_only_has_loopback_interfaces (void) { #if HAVE_GETIFADDRS struct ifaddrs *addrs; @@ -305,12 +321,42 @@ only_has_loopback_interfaces (void) #endif } +static void +network_changed_cb (GNetworkMonitor *monitor, + gboolean network_available, + GThreadedResolver *resolver) +{ + g_mutex_lock (&resolver->interface_mutex); + resolver->network_is_loopback_only = -1; + g_mutex_unlock (&resolver->interface_mutex); +} + +static gboolean +only_has_loopback_interfaces_cached (GThreadedResolver *resolver) +{ + g_mutex_lock (&resolver->interface_mutex); + + if (!resolver->network_monitor) + { + resolver->network_monitor = g_object_ref (g_network_monitor_get_default ()); + resolver->monitor_supports_caching = G_TYPE_FROM_INSTANCE (resolver->network_monitor) != G_TYPE_NETWORK_MONITOR_BASE; + g_signal_connect_object (resolver->network_monitor, "network-changed", G_CALLBACK (network_changed_cb), resolver, G_CONNECT_DEFAULT); + } + + if (!resolver->monitor_supports_caching || resolver->network_is_loopback_only == -1) + resolver->network_is_loopback_only = check_only_has_loopback_interfaces (); + + g_mutex_unlock (&resolver->interface_mutex); + + return resolver->network_is_loopback_only; +} static GList * -do_lookup_by_name (const gchar *hostname, - int address_family, - GCancellable *cancellable, - GError **error) +do_lookup_by_name (GThreadedResolver *resolver, + const gchar *hostname, + int address_family, + GCancellable *cancellable, + GError **error) { struct addrinfo *res = NULL; GList *addresses; @@ -320,7 +366,7 @@ do_lookup_by_name (const gchar *hostname, /* In general we only want IPs for valid interfaces. * However this will return nothing if you only have loopback interfaces. * Instead in this case we will manually filter out invalid IPs. */ - gboolean only_loopback = only_has_loopback_interfaces (); + gboolean only_loopback = only_has_loopback_interfaces_cached (resolver); #ifdef AI_ADDRCONFIG if (!only_loopback) @@ -1630,13 +1676,15 @@ threaded_resolver_worker_cb (gpointer task_data, GTask *task = G_TASK (g_steal_pointer (&task_data)); LookupData *data = g_task_get_task_data (task); GCancellable *cancellable = g_task_get_cancellable (task); + GThreadedResolver *resolver = G_THREADED_RESOLVER (user_data); GError *local_error = NULL; gboolean should_return; switch (data->lookup_type) { case LOOKUP_BY_NAME: { - GList *addresses = do_lookup_by_name (data->lookup_by_name.hostname, + GList *addresses = do_lookup_by_name (resolver, + data->lookup_by_name.hostname, data->lookup_by_name.address_family, cancellable, &local_error);