threadedresolver: Cache network interface checks

This commit is contained in:
Patrick Griffis 2025-03-24 11:01:54 -05:00
parent fe0139ee98
commit cce3001d5d

View File

@ -36,6 +36,7 @@
#include "gcancellable.h" #include "gcancellable.h"
#include "ginetaddress.h" #include "ginetaddress.h"
#include "ginetsocketaddress.h" #include "ginetsocketaddress.h"
#include "gnetworkmonitorbase.h"
#include "gtask.h" #include "gtask.h"
#include "gsocketaddress.h" #include "gsocketaddress.h"
#include "gsrvtarget.h" #include "gsrvtarget.h"
@ -90,6 +91,11 @@ struct _GThreadedResolver
GResolver parent_instance; GResolver parent_instance;
GThreadPool *thread_pool; /* (owned) */ 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) G_DEFINE_TYPE (GThreadedResolver, g_threaded_resolver, G_TYPE_RESOLVER)
@ -110,6 +116,10 @@ g_threaded_resolver_init (GThreadedResolver *self)
20, 20,
FALSE, FALSE,
NULL); NULL);
self->network_is_loopback_only = -1;
g_mutex_init (&self->interface_mutex);
} }
static void static void
@ -120,6 +130,12 @@ g_threaded_resolver_finalize (GObject *object)
g_thread_pool_free (self->thread_pool, TRUE, FALSE); g_thread_pool_free (self->thread_pool, TRUE, FALSE);
self->thread_pool = NULL; 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); G_OBJECT_CLASS (g_threaded_resolver_parent_class)->finalize (object);
} }
@ -260,7 +276,7 @@ lookup_data_free (LookupData *data)
} }
static gboolean static gboolean
only_has_loopback_interfaces (void) check_only_has_loopback_interfaces (void)
{ {
#if HAVE_GETIFADDRS #if HAVE_GETIFADDRS
struct ifaddrs *addrs; struct ifaddrs *addrs;
@ -305,12 +321,42 @@ only_has_loopback_interfaces (void)
#endif #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 * static GList *
do_lookup_by_name (const gchar *hostname, do_lookup_by_name (GThreadedResolver *resolver,
int address_family, const gchar *hostname,
GCancellable *cancellable, int address_family,
GError **error) GCancellable *cancellable,
GError **error)
{ {
struct addrinfo *res = NULL; struct addrinfo *res = NULL;
GList *addresses; GList *addresses;
@ -320,7 +366,7 @@ do_lookup_by_name (const gchar *hostname,
/* In general we only want IPs for valid interfaces. /* In general we only want IPs for valid interfaces.
* However this will return nothing if you only have loopback interfaces. * However this will return nothing if you only have loopback interfaces.
* Instead in this case we will manually filter out invalid IPs. */ * 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 #ifdef AI_ADDRCONFIG
if (!only_loopback) if (!only_loopback)
@ -1630,13 +1676,15 @@ threaded_resolver_worker_cb (gpointer task_data,
GTask *task = G_TASK (g_steal_pointer (&task_data)); GTask *task = G_TASK (g_steal_pointer (&task_data));
LookupData *data = g_task_get_task_data (task); LookupData *data = g_task_get_task_data (task);
GCancellable *cancellable = g_task_get_cancellable (task); GCancellable *cancellable = g_task_get_cancellable (task);
GThreadedResolver *resolver = G_THREADED_RESOLVER (user_data);
GError *local_error = NULL; GError *local_error = NULL;
gboolean should_return; gboolean should_return;
switch (data->lookup_type) { switch (data->lookup_type) {
case LOOKUP_BY_NAME: 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, data->lookup_by_name.address_family,
cancellable, cancellable,
&local_error); &local_error);