| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* GIO - GLib Input, Output and Streaming Library
 | 
					
						
							| 
									
										
										
										
											2009-05-03 18:04:31 -04:00
										 |  |  |  |  * | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  |  * Copyright (C) 2008 Red Hat, Inc. | 
					
						
							| 
									
										
										
										
											2018-10-17 11:14:10 -04:00
										 |  |  |  |  * Copyright (C) 2018 Igalia S.L. | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  |  * | 
					
						
							| 
									
										
										
										
											2022-05-18 09:12:45 +01:00
										 |  |  |  |  * SPDX-License-Identifier: LGPL-2.1-or-later | 
					
						
							|  |  |  |  |  * | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  |  * This library is free software; you can redistribute it and/or | 
					
						
							|  |  |  |  |  * modify it under the terms of the GNU Lesser General Public | 
					
						
							|  |  |  |  |  * License as published by the Free Software Foundation; either | 
					
						
							| 
									
										
										
										
											2017-05-27 18:21:30 +02:00
										 |  |  |  |  * version 2.1 of the License, or (at your option) any later version. | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  |  * | 
					
						
							|  |  |  |  |  * This library is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
					
						
							|  |  |  |  |  * Lesser General Public License for more details. | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * You should have received a copy of the GNU Lesser General | 
					
						
							| 
									
										
										
										
											2014-01-23 12:58:29 +01:00
										 |  |  |  |  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
 | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  |  */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #include "config.h"
 | 
					
						
							|  |  |  |  | #include <glib.h>
 | 
					
						
							|  |  |  |  | #include "glibintl.h"
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  |  | #include <string.h>
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-25 17:26:28 +01:00
										 |  |  |  | #include "glib/glib-private.h"
 | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | #include "gthreadedresolver.h"
 | 
					
						
							| 
									
										
										
										
											2024-02-09 10:05:56 +00:00
										 |  |  |  | #include "gthreadedresolver-private.h"
 | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | #include "gnetworkingprivate.h"
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #include "gcancellable.h"
 | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  | #include "ginetaddress.h"
 | 
					
						
							|  |  |  |  | #include "ginetsocketaddress.h"
 | 
					
						
							| 
									
										
										
										
											2025-03-24 11:01:54 -05:00
										 |  |  |  | #include "gnetworkmonitorbase.h"
 | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  | #include "gtask.h"
 | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | #include "gsocketaddress.h"
 | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  | #include "gsrvtarget.h"
 | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-23 14:07:12 -05:00
										 |  |  |  | #if HAVE_GETIFADDRS
 | 
					
						
							|  |  |  |  | #include <ifaddrs.h>
 | 
					
						
							|  |  |  |  | #endif
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-25 17:27:22 +01:00
										 |  |  |  | /*
 | 
					
						
							|  |  |  |  |  * GThreadedResolver is a threaded wrapper around the system libc’s | 
					
						
							|  |  |  |  |  * `getaddrinfo()`. | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * It has to be threaded, as `getaddrinfo()` is synchronous. libc does provide | 
					
						
							|  |  |  |  |  * `getaddrinfo_a()` as an asynchronous version of `getaddrinfo()`, but it does | 
					
						
							|  |  |  |  |  * not integrate with a poll loop. It requires use of sigevent to notify of | 
					
						
							|  |  |  |  |  * completion of an asynchronous operation. That either emits a signal, or calls | 
					
						
							|  |  |  |  |  * a callback function in a newly spawned thread. | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * A signal (`SIGEV_SIGNAL`) can’t be used for completion as (aside from being | 
					
						
							|  |  |  |  |  * another expensive round trip into the kernel) GLib cannot pick a `SIG*` | 
					
						
							|  |  |  |  |  * number which is guaranteed to not be in use elsewhere in the process. Various | 
					
						
							|  |  |  |  |  * other things could be interfering with signal dispositions, such as gdb or | 
					
						
							|  |  |  |  |  * other libraries in the process. Using a `signalfd()` | 
					
						
							|  |  |  |  |  * [cannot improve this situation](https://ldpreload.com/blog/signalfd-is-useless).
 | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * A callback function in a newly spawned thread (`SIGEV_THREAD`) could be used, | 
					
						
							|  |  |  |  |  * but that is very expensive. Internally, glibc currently also just implements | 
					
						
							|  |  |  |  |  * `getaddrinfo_a()` | 
					
						
							|  |  |  |  |  * [using its own thread pool](https://github.com/bminor/glibc/blob/master/resolv/gai_misc.c),
 | 
					
						
							|  |  |  |  |  * and then | 
					
						
							|  |  |  |  |  * [spawns an additional thread for each completion callback](https://github.com/bminor/glibc/blob/master/resolv/gai_notify.c).
 | 
					
						
							|  |  |  |  |  * That is very expensive. | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * No other appropriate sigevent callback types | 
					
						
							|  |  |  |  |  * [currently exist](https://sourceware.org/bugzilla/show_bug.cgi?id=30287), and
 | 
					
						
							|  |  |  |  |  * [others agree that sigevent is not great](http://davmac.org/davpage/linux/async-io.html#posixaio).
 | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * Hence, #GThreadedResolver calls the normal synchronous `getaddrinfo()` in its | 
					
						
							|  |  |  |  |  * own thread pool. Previously, #GThreadedResolver used the thread pool which is | 
					
						
							|  |  |  |  |  * internal to #GTask by calling g_task_run_in_thread(). That lead to exhaustion | 
					
						
							|  |  |  |  |  * of the #GTask thread pool in some situations, though, as DNS lookups are | 
					
						
							|  |  |  |  |  * quite frequent leaf operations in some use cases. Now, #GThreadedResolver | 
					
						
							|  |  |  |  |  * uses its own private thread pool. | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * This is similar to what | 
					
						
							|  |  |  |  |  * [libasyncns](http://git.0pointer.net/libasyncns.git/tree/libasyncns/asyncns.h)
 | 
					
						
							|  |  |  |  |  * and other multi-threaded users of `getaddrinfo()` do. | 
					
						
							|  |  |  |  |  */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-30 12:02:40 +01:00
										 |  |  |  | struct _GThreadedResolver | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   GResolver parent_instance; | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   GThreadPool *thread_pool;  /* (owned) */ | 
					
						
							| 
									
										
										
										
											2025-03-24 11:01:54 -05:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   GMutex interface_mutex; | 
					
						
							|  |  |  |  |   GNetworkMonitor *network_monitor; /* (owned) */ | 
					
						
							|  |  |  |  |   gboolean monitor_supports_caching; | 
					
						
							|  |  |  |  |   int network_is_loopback_only; | 
					
						
							| 
									
										
										
										
											2023-03-30 12:02:40 +01:00
										 |  |  |  | }; | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | G_DEFINE_TYPE (GThreadedResolver, g_threaded_resolver, G_TYPE_RESOLVER) | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  | static void run_task_in_thread_pool_async (GThreadedResolver *self, | 
					
						
							|  |  |  |  |                                            GTask             *task); | 
					
						
							|  |  |  |  | static void run_task_in_thread_pool_sync (GThreadedResolver *self, | 
					
						
							|  |  |  |  |                                           GTask             *task); | 
					
						
							|  |  |  |  | static void threaded_resolver_worker_cb (gpointer task_data, | 
					
						
							|  |  |  |  |                                          gpointer user_data); | 
					
						
							| 
									
										
										
										
											2023-03-30 13:42:19 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | static void | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  | g_threaded_resolver_init (GThreadedResolver *self) | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  |   self->thread_pool = g_thread_pool_new_full (threaded_resolver_worker_cb, | 
					
						
							|  |  |  |  |                                               self, | 
					
						
							|  |  |  |  |                                               (GDestroyNotify) g_object_unref, | 
					
						
							|  |  |  |  |                                               20, | 
					
						
							|  |  |  |  |                                               FALSE, | 
					
						
							|  |  |  |  |                                               NULL); | 
					
						
							| 
									
										
										
										
											2025-03-24 11:01:54 -05:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   self->network_is_loopback_only = -1; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   g_mutex_init (&self->interface_mutex); | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static void | 
					
						
							|  |  |  |  | g_threaded_resolver_finalize (GObject *object) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   GThreadedResolver *self = G_THREADED_RESOLVER (object); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   g_thread_pool_free (self->thread_pool, TRUE, FALSE); | 
					
						
							|  |  |  |  |   self->thread_pool = NULL; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-24 11:01:54 -05:00
										 |  |  |  |   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); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  |   G_OBJECT_CLASS (g_threaded_resolver_parent_class)->finalize (object); | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  | static GResolverError | 
					
						
							|  |  |  |  | g_resolver_error_from_addrinfo_error (gint err) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   switch (err) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |     case EAI_FAIL: | 
					
						
							|  |  |  |  | #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
 | 
					
						
							|  |  |  |  |     case EAI_NODATA: | 
					
						
							|  |  |  |  | #endif
 | 
					
						
							|  |  |  |  |     case EAI_NONAME: | 
					
						
							|  |  |  |  |       return G_RESOLVER_ERROR_NOT_FOUND; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     case EAI_AGAIN: | 
					
						
							|  |  |  |  |       return G_RESOLVER_ERROR_TEMPORARY_FAILURE; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     default: | 
					
						
							|  |  |  |  |       return G_RESOLVER_ERROR_INTERNAL; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-17 11:14:10 -04:00
										 |  |  |  | typedef struct { | 
					
						
							| 
									
										
										
										
											2023-04-25 15:56:47 +01:00
										 |  |  |  |   enum { | 
					
						
							|  |  |  |  |     LOOKUP_BY_NAME, | 
					
						
							|  |  |  |  |     LOOKUP_BY_ADDRESS, | 
					
						
							|  |  |  |  |     LOOKUP_RECORDS, | 
					
						
							|  |  |  |  |   } lookup_type; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   union { | 
					
						
							|  |  |  |  |     struct { | 
					
						
							|  |  |  |  |       char *hostname; | 
					
						
							|  |  |  |  |       int address_family; | 
					
						
							|  |  |  |  |     } lookup_by_name; | 
					
						
							|  |  |  |  |     struct { | 
					
						
							|  |  |  |  |       GInetAddress *address;  /* (owned) */ | 
					
						
							|  |  |  |  |     } lookup_by_address; | 
					
						
							|  |  |  |  |     struct { | 
					
						
							|  |  |  |  |       char *rrname; | 
					
						
							|  |  |  |  |       GResolverRecordType record_type; | 
					
						
							|  |  |  |  |     } lookup_records; | 
					
						
							|  |  |  |  |   }; | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   GCond cond;  /* used for signalling completion of the task when running it sync */ | 
					
						
							|  |  |  |  |   GMutex lock; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-25 17:26:28 +01:00
										 |  |  |  |   GSource *timeout_source;  /* (nullable) (owned) */ | 
					
						
							|  |  |  |  |   GSource *cancellable_source;  /* (nullable) (owned) */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  |   /* This enum indicates that a particular code path has claimed the
 | 
					
						
							|  |  |  |  |    * task and is shortly about to call g_task_return_*() on it. | 
					
						
							|  |  |  |  |    * This must be accessed with GThreadedResolver.lock held. */ | 
					
						
							|  |  |  |  |   enum | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       NOT_YET, | 
					
						
							|  |  |  |  |       COMPLETED,  /* libc lookup call has completed successfully or errored */ | 
					
						
							| 
									
										
										
										
											2023-04-25 17:26:28 +01:00
										 |  |  |  |       TIMED_OUT, | 
					
						
							|  |  |  |  |       CANCELLED, | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  |     } will_return; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   /* Whether the thread pool thread executing this lookup has finished executing
 | 
					
						
							|  |  |  |  |    * it and g_task_return_*() has been called on it already. | 
					
						
							|  |  |  |  |    * This must be accessed with GThreadedResolver.lock held. */ | 
					
						
							|  |  |  |  |   gboolean has_returned; | 
					
						
							| 
									
										
										
										
											2018-10-17 11:14:10 -04:00
										 |  |  |  | } LookupData; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static LookupData * | 
					
						
							| 
									
										
										
										
											2023-04-25 15:56:47 +01:00
										 |  |  |  | lookup_data_new_by_name (const char *hostname, | 
					
						
							|  |  |  |  |                          int         address_family) | 
					
						
							| 
									
										
										
										
											2018-10-17 11:14:10 -04:00
										 |  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-04-25 15:56:47 +01:00
										 |  |  |  |   LookupData *data = g_new0 (LookupData, 1); | 
					
						
							|  |  |  |  |   data->lookup_type = LOOKUP_BY_NAME; | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  |   g_cond_init (&data->cond); | 
					
						
							|  |  |  |  |   g_mutex_init (&data->lock); | 
					
						
							| 
									
										
										
										
											2023-04-25 15:56:47 +01:00
										 |  |  |  |   data->lookup_by_name.hostname = g_strdup (hostname); | 
					
						
							|  |  |  |  |   data->lookup_by_name.address_family = address_family; | 
					
						
							|  |  |  |  |   return g_steal_pointer (&data); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static LookupData * | 
					
						
							|  |  |  |  | lookup_data_new_by_address (GInetAddress *address) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   LookupData *data = g_new0 (LookupData, 1); | 
					
						
							|  |  |  |  |   data->lookup_type = LOOKUP_BY_ADDRESS; | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  |   g_cond_init (&data->cond); | 
					
						
							|  |  |  |  |   g_mutex_init (&data->lock); | 
					
						
							| 
									
										
										
										
											2023-04-25 15:56:47 +01:00
										 |  |  |  |   data->lookup_by_address.address = g_object_ref (address); | 
					
						
							|  |  |  |  |   return g_steal_pointer (&data); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static LookupData * | 
					
						
							|  |  |  |  | lookup_data_new_records (const gchar         *rrname, | 
					
						
							|  |  |  |  |                          GResolverRecordType  record_type) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   LookupData *data = g_new0 (LookupData, 1); | 
					
						
							|  |  |  |  |   data->lookup_type = LOOKUP_RECORDS; | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  |   g_cond_init (&data->cond); | 
					
						
							|  |  |  |  |   g_mutex_init (&data->lock); | 
					
						
							| 
									
										
										
										
											2023-04-25 15:56:47 +01:00
										 |  |  |  |   data->lookup_records.rrname = g_strdup (rrname); | 
					
						
							|  |  |  |  |   data->lookup_records.record_type = record_type; | 
					
						
							|  |  |  |  |   return g_steal_pointer (&data); | 
					
						
							| 
									
										
										
										
											2018-10-17 11:14:10 -04:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static void | 
					
						
							|  |  |  |  | lookup_data_free (LookupData *data) | 
					
						
							|  |  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-04-25 15:56:47 +01:00
										 |  |  |  |   switch (data->lookup_type) { | 
					
						
							|  |  |  |  |   case LOOKUP_BY_NAME: | 
					
						
							|  |  |  |  |     g_free (data->lookup_by_name.hostname); | 
					
						
							|  |  |  |  |     break; | 
					
						
							|  |  |  |  |   case LOOKUP_BY_ADDRESS: | 
					
						
							|  |  |  |  |     g_clear_object (&data->lookup_by_address.address); | 
					
						
							|  |  |  |  |     break; | 
					
						
							|  |  |  |  |   case LOOKUP_RECORDS: | 
					
						
							|  |  |  |  |     g_free (data->lookup_records.rrname); | 
					
						
							|  |  |  |  |     break; | 
					
						
							|  |  |  |  |   default: | 
					
						
							|  |  |  |  |     g_assert_not_reached (); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-25 17:26:28 +01:00
										 |  |  |  |   if (data->timeout_source != NULL) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       g_source_destroy (data->timeout_source); | 
					
						
							|  |  |  |  |       g_clear_pointer (&data->timeout_source, g_source_unref); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   if (data->cancellable_source != NULL) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       g_source_destroy (data->cancellable_source); | 
					
						
							|  |  |  |  |       g_clear_pointer (&data->cancellable_source, g_source_unref); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  |   g_mutex_clear (&data->lock); | 
					
						
							|  |  |  |  |   g_cond_clear (&data->cond); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-17 11:14:10 -04:00
										 |  |  |  |   g_free (data); | 
					
						
							|  |  |  |  | } | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-23 14:07:12 -05:00
										 |  |  |  | static gboolean | 
					
						
							| 
									
										
										
										
											2025-03-24 11:01:54 -05:00
										 |  |  |  | check_only_has_loopback_interfaces (void) | 
					
						
							| 
									
										
										
										
											2025-03-23 14:07:12 -05:00
										 |  |  |  | { | 
					
						
							|  |  |  |  | #if HAVE_GETIFADDRS
 | 
					
						
							|  |  |  |  |   struct ifaddrs *addrs; | 
					
						
							|  |  |  |  |   gboolean only_loopback = TRUE; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   if (getifaddrs (&addrs) != 0) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       int saved_errno = errno; | 
					
						
							|  |  |  |  |       g_debug ("getifaddrs() failed: %s", g_strerror (saved_errno)); | 
					
						
							|  |  |  |  |       return FALSE; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   for (struct ifaddrs *addr = addrs; addr; addr = addr->ifa_next) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       struct sockaddr *sa = addr->ifa_addr; | 
					
						
							| 
									
										
										
										
											2025-04-10 15:36:59 -05:00
										 |  |  |  |       GSocketAddress *saddr; | 
					
						
							|  |  |  |  |       if (!sa) | 
					
						
							|  |  |  |  |         continue; | 
					
						
							| 
									
										
										
										
											2025-03-23 14:07:12 -05:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-10 15:36:59 -05:00
										 |  |  |  |       saddr = g_socket_address_new_from_native (sa, sizeof (struct sockaddr)); | 
					
						
							| 
									
										
										
										
											2025-03-23 14:07:12 -05:00
										 |  |  |  |       if (!saddr) | 
					
						
							|  |  |  |  |         continue; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       if (!G_IS_INET_SOCKET_ADDRESS (saddr)) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |           g_object_unref (saddr); | 
					
						
							|  |  |  |  |           continue; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       GInetAddress *inetaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (saddr)); | 
					
						
							|  |  |  |  |       if (!g_inet_address_get_is_loopback (inetaddr)) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |           only_loopback = FALSE; | 
					
						
							|  |  |  |  |           g_object_unref (saddr); | 
					
						
							|  |  |  |  |           break; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       g_object_unref (saddr); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   freeifaddrs (addrs); | 
					
						
							|  |  |  |  |   return only_loopback; | 
					
						
							|  |  |  |  | #else /* FIXME: Check GetAdaptersAddresses() on win32. */
 | 
					
						
							|  |  |  |  |   return FALSE; | 
					
						
							|  |  |  |  | #endif
 | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-24 11:01:54 -05:00
										 |  |  |  | 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; | 
					
						
							|  |  |  |  | } | 
					
						
							| 
									
										
										
										
											2025-03-23 14:07:12 -05:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-30 13:42:19 +01:00
										 |  |  |  | static GList * | 
					
						
							| 
									
										
										
										
											2025-03-24 11:01:54 -05:00
										 |  |  |  | do_lookup_by_name (GThreadedResolver  *resolver, | 
					
						
							|  |  |  |  |                    const gchar        *hostname, | 
					
						
							|  |  |  |  |                    int                 address_family, | 
					
						
							|  |  |  |  |                    GCancellable       *cancellable, | 
					
						
							|  |  |  |  |                    GError            **error) | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | { | 
					
						
							|  |  |  |  |   struct addrinfo *res = NULL; | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  |   GList *addresses; | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  |   gint retval; | 
					
						
							| 
									
										
										
										
											2018-10-17 11:14:10 -04:00
										 |  |  |  |   struct addrinfo addrinfo_hints = { 0 }; | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-23 14:07:12 -05:00
										 |  |  |  |   /* 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. */ | 
					
						
							| 
									
										
										
										
											2025-03-24 11:01:54 -05:00
										 |  |  |  |   gboolean only_loopback = only_has_loopback_interfaces_cached (resolver); | 
					
						
							| 
									
										
										
										
											2025-03-23 14:07:12 -05:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-17 11:14:10 -04:00
										 |  |  |  | #ifdef AI_ADDRCONFIG
 | 
					
						
							| 
									
										
										
										
											2025-03-23 14:07:12 -05:00
										 |  |  |  |   if (!only_loopback) | 
					
						
							|  |  |  |  |     addrinfo_hints.ai_flags = AI_ADDRCONFIG; | 
					
						
							| 
									
										
										
										
											2018-10-17 11:14:10 -04:00
										 |  |  |  | #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; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-30 13:42:19 +01:00
										 |  |  |  |   addrinfo_hints.ai_family = address_family; | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |   retval = getaddrinfo (hostname, NULL, &addrinfo_hints, &res); | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |   if (retval == 0) | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  |     { | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |       addresses = NULL; | 
					
						
							| 
									
										
										
										
											2025-03-23 13:44:35 -05:00
										 |  |  |  |       for (struct addrinfo *ai = res; ai; ai = ai->ai_next) | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |         { | 
					
						
							| 
									
										
										
										
											2025-03-23 13:44:35 -05:00
										 |  |  |  |           GInetAddress *addr; | 
					
						
							|  |  |  |  |           GSocketAddress *sockaddr = g_socket_address_new_from_native (ai->ai_addr, ai->ai_addrlen); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-22 14:08:00 -04:00
										 |  |  |  |           if (!sockaddr) | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |             continue; | 
					
						
							| 
									
										
										
										
											2014-07-22 14:08:00 -04:00
										 |  |  |  |           if (!G_IS_INET_SOCKET_ADDRESS (sockaddr)) | 
					
						
							|  |  |  |  |             { | 
					
						
							|  |  |  |  |               g_clear_object (&sockaddr); | 
					
						
							|  |  |  |  |               continue; | 
					
						
							|  |  |  |  |             } | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-23 14:07:12 -05:00
										 |  |  |  |           addr = g_inet_socket_address_get_address ((GInetSocketAddress *) sockaddr); | 
					
						
							|  |  |  |  |           if (only_loopback && !g_inet_address_get_is_loopback (addr)) | 
					
						
							|  |  |  |  |             { | 
					
						
							|  |  |  |  |               g_object_unref (sockaddr); | 
					
						
							|  |  |  |  |               continue; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |           addresses = g_list_prepend (addresses, g_object_ref (addr)); | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |           g_object_unref (sockaddr); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-30 13:42:19 +01:00
										 |  |  |  |       g_clear_pointer (&res, freeaddrinfo); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-24 09:26:12 +01:00
										 |  |  |  |       if (addresses != NULL) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |           addresses = g_list_reverse (addresses); | 
					
						
							| 
									
										
										
										
											2023-03-30 13:42:19 +01:00
										 |  |  |  |           return g_steal_pointer (&addresses); | 
					
						
							| 
									
										
										
										
											2014-04-24 09:26:12 +01:00
										 |  |  |  |         } | 
					
						
							|  |  |  |  |       else | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |           /* All addresses failed to be converted to GSocketAddresses. */ | 
					
						
							| 
									
										
										
										
											2023-03-30 13:42:19 +01:00
										 |  |  |  |           g_set_error (error, | 
					
						
							|  |  |  |  |                        G_RESOLVER_ERROR, | 
					
						
							|  |  |  |  |                        G_RESOLVER_ERROR_NOT_FOUND, | 
					
						
							|  |  |  |  |                        _("Error resolving “%s”: %s"), | 
					
						
							|  |  |  |  |                        hostname, | 
					
						
							|  |  |  |  |                        _("No valid addresses were found")); | 
					
						
							|  |  |  |  |           return NULL; | 
					
						
							| 
									
										
										
										
											2014-04-24 09:26:12 +01:00
										 |  |  |  |         } | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  |   else | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |     { | 
					
						
							| 
									
										
										
										
											2019-03-21 11:51:37 +00:00
										 |  |  |  | #ifdef G_OS_WIN32
 | 
					
						
							|  |  |  |  |       gchar *error_message = g_win32_error_message (WSAGetLastError ()); | 
					
						
							|  |  |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2019-03-22 13:30:43 +00:00
										 |  |  |  |       gchar *error_message = g_locale_to_utf8 (gai_strerror (retval), -1, NULL, NULL, NULL); | 
					
						
							|  |  |  |  |       if (error_message == NULL) | 
					
						
							|  |  |  |  |         error_message = g_strdup ("[Invalid UTF-8]"); | 
					
						
							| 
									
										
										
										
											2019-03-21 11:51:37 +00:00
										 |  |  |  | #endif
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-30 13:42:19 +01:00
										 |  |  |  |       g_clear_pointer (&res, freeaddrinfo); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       g_set_error (error, | 
					
						
							|  |  |  |  |                    G_RESOLVER_ERROR, | 
					
						
							|  |  |  |  |                    g_resolver_error_from_addrinfo_error (retval), | 
					
						
							|  |  |  |  |                    _("Error resolving “%s”: %s"), | 
					
						
							|  |  |  |  |                    hostname, error_message); | 
					
						
							| 
									
										
										
										
											2019-03-21 11:51:37 +00:00
										 |  |  |  |       g_free (error_message); | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-30 13:42:19 +01:00
										 |  |  |  |       return NULL; | 
					
						
							|  |  |  |  |     } | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static GList * | 
					
						
							|  |  |  |  | lookup_by_name (GResolver     *resolver, | 
					
						
							|  |  |  |  |                 const gchar   *hostname, | 
					
						
							|  |  |  |  |                 GCancellable  *cancellable, | 
					
						
							|  |  |  |  |                 GError       **error) | 
					
						
							|  |  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  |   GThreadedResolver *self = G_THREADED_RESOLVER (resolver); | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  |   GTask *task; | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  |   GList *addresses; | 
					
						
							| 
									
										
										
										
											2018-10-17 11:14:10 -04:00
										 |  |  |  |   LookupData *data; | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-25 15:56:47 +01:00
										 |  |  |  |   data = lookup_data_new_by_name (hostname, AF_UNSPEC); | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  |   task = g_task_new (resolver, cancellable, NULL, NULL); | 
					
						
							| 
									
										
										
										
											2016-06-16 19:39:38 -04:00
										 |  |  |  |   g_task_set_source_tag (task, lookup_by_name); | 
					
						
							| 
									
										
										
										
											2020-06-25 23:36:08 +01:00
										 |  |  |  |   g_task_set_name (task, "[gio] resolver lookup"); | 
					
						
							| 
									
										
										
										
											2023-04-25 15:56:47 +01:00
										 |  |  |  |   g_task_set_task_data (task, g_steal_pointer (&data), (GDestroyNotify) lookup_data_free); | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   run_task_in_thread_pool_sync (self, task); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-17 11:14:10 -04:00
										 |  |  |  |   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 */ | 
					
						
							|  |  |  |  |       g_return_val_if_fail (!(flags & G_RESOLVER_NAME_LOOKUP_FLAGS_IPV4_ONLY), address_family); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   return address_family; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static GList * | 
					
						
							|  |  |  |  | lookup_by_name_with_flags (GResolver                 *resolver, | 
					
						
							|  |  |  |  |                            const gchar               *hostname, | 
					
						
							|  |  |  |  |                            GResolverNameLookupFlags   flags, | 
					
						
							|  |  |  |  |                            GCancellable              *cancellable, | 
					
						
							|  |  |  |  |                            GError                   **error) | 
					
						
							|  |  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  |   GThreadedResolver *self = G_THREADED_RESOLVER (resolver); | 
					
						
							| 
									
										
										
										
											2018-10-17 11:14:10 -04:00
										 |  |  |  |   GTask *task; | 
					
						
							|  |  |  |  |   GList *addresses; | 
					
						
							|  |  |  |  |   LookupData *data; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-25 15:56:47 +01:00
										 |  |  |  |   data = lookup_data_new_by_name (hostname, flags_to_family (flags)); | 
					
						
							| 
									
										
										
										
											2018-10-17 11:14:10 -04:00
										 |  |  |  |   task = g_task_new (resolver, cancellable, NULL, NULL); | 
					
						
							|  |  |  |  |   g_task_set_source_tag (task, lookup_by_name_with_flags); | 
					
						
							| 
									
										
										
										
											2020-06-25 23:36:08 +01:00
										 |  |  |  |   g_task_set_name (task, "[gio] resolver lookup"); | 
					
						
							| 
									
										
										
										
											2023-04-25 15:56:47 +01:00
										 |  |  |  |   g_task_set_task_data (task, g_steal_pointer (&data), (GDestroyNotify) lookup_data_free); | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   run_task_in_thread_pool_sync (self, task); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  |   addresses = g_task_propagate_pointer (task, error); | 
					
						
							|  |  |  |  |   g_object_unref (task); | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   return addresses; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static void | 
					
						
							| 
									
										
										
										
											2018-10-17 11:14:10 -04:00
										 |  |  |  | lookup_by_name_with_flags_async (GResolver                *resolver, | 
					
						
							|  |  |  |  |                                  const gchar              *hostname, | 
					
						
							|  |  |  |  |                                  GResolverNameLookupFlags  flags, | 
					
						
							|  |  |  |  |                                  GCancellable             *cancellable, | 
					
						
							|  |  |  |  |                                  GAsyncReadyCallback       callback, | 
					
						
							|  |  |  |  |                                  gpointer                  user_data) | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  |   GThreadedResolver *self = G_THREADED_RESOLVER (resolver); | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  |   GTask *task; | 
					
						
							| 
									
										
										
										
											2018-10-17 11:14:10 -04:00
										 |  |  |  |   LookupData *data; | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-25 15:56:47 +01:00
										 |  |  |  |   data = lookup_data_new_by_name (hostname, flags_to_family (flags)); | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  |   task = g_task_new (resolver, cancellable, callback, user_data); | 
					
						
							| 
									
										
										
										
											2023-04-24 16:30:45 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   g_debug ("%s: starting new lookup for %s with GTask %p, LookupData %p", | 
					
						
							|  |  |  |  |            G_STRFUNC, hostname, task, data); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-17 11:14:10 -04:00
										 |  |  |  |   g_task_set_source_tag (task, lookup_by_name_with_flags_async); | 
					
						
							| 
									
										
										
										
											2020-06-25 23:36:08 +01:00
										 |  |  |  |   g_task_set_name (task, "[gio] resolver lookup"); | 
					
						
							| 
									
										
										
										
											2023-04-25 15:56:47 +01:00
										 |  |  |  |   g_task_set_task_data (task, g_steal_pointer (&data), (GDestroyNotify) lookup_data_free); | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   run_task_in_thread_pool_async (self, task); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  |   g_object_unref (task); | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-17 11:14:10 -04:00
										 |  |  |  | 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); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | static GList * | 
					
						
							|  |  |  |  | lookup_by_name_finish (GResolver     *resolver, | 
					
						
							|  |  |  |  |                        GAsyncResult  *result, | 
					
						
							|  |  |  |  |                        GError       **error) | 
					
						
							|  |  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  |   g_return_val_if_fail (g_task_is_valid (result, resolver), NULL); | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  |   return g_task_propagate_pointer (G_TASK (result), error); | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-17 11:14:10 -04:00
										 |  |  |  | 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); | 
					
						
							|  |  |  |  | } | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-30 13:42:19 +01:00
										 |  |  |  | static gchar * | 
					
						
							|  |  |  |  | do_lookup_by_address (GInetAddress  *address, | 
					
						
							|  |  |  |  |                       GCancellable  *cancellable, | 
					
						
							|  |  |  |  |                       GError       **error) | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | { | 
					
						
							| 
									
										
										
										
											2022-01-19 17:39:45 +01:00
										 |  |  |  |   struct sockaddr_storage sockaddr_address; | 
					
						
							|  |  |  |  |   gsize sockaddr_address_size; | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |   GSocketAddress *gsockaddr; | 
					
						
							|  |  |  |  |   gchar name[NI_MAXHOST]; | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  |   gint retval; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |   gsockaddr = g_inet_socket_address_new (address, 0); | 
					
						
							| 
									
										
										
										
											2022-01-19 17:39:45 +01:00
										 |  |  |  |   g_socket_address_to_native (gsockaddr, (struct sockaddr *)&sockaddr_address, | 
					
						
							|  |  |  |  |                               sizeof (sockaddr_address), NULL); | 
					
						
							|  |  |  |  |   sockaddr_address_size = g_socket_address_get_native_size (gsockaddr); | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |   g_object_unref (gsockaddr); | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-19 17:39:45 +01:00
										 |  |  |  |   retval = getnameinfo ((struct sockaddr *) &sockaddr_address, sockaddr_address_size, | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |                         name, sizeof (name), NULL, 0, NI_NAMEREQD); | 
					
						
							|  |  |  |  |   if (retval == 0) | 
					
						
							| 
									
										
										
										
											2023-03-30 13:42:19 +01:00
										 |  |  |  |     return g_strdup (name); | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  |   else | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |     { | 
					
						
							|  |  |  |  |       gchar *phys; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-21 11:51:37 +00:00
										 |  |  |  | #ifdef G_OS_WIN32
 | 
					
						
							|  |  |  |  |       gchar *error_message = g_win32_error_message (WSAGetLastError ()); | 
					
						
							|  |  |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2019-03-22 13:30:43 +00:00
										 |  |  |  |       gchar *error_message = g_locale_to_utf8 (gai_strerror (retval), -1, NULL, NULL, NULL); | 
					
						
							|  |  |  |  |       if (error_message == NULL) | 
					
						
							|  |  |  |  |         error_message = g_strdup ("[Invalid UTF-8]"); | 
					
						
							| 
									
										
										
										
											2019-03-21 11:51:37 +00:00
										 |  |  |  | #endif
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |       phys = g_inet_address_to_string (address); | 
					
						
							| 
									
										
										
										
											2023-03-30 13:42:19 +01:00
										 |  |  |  |       g_set_error (error, | 
					
						
							|  |  |  |  |                    G_RESOLVER_ERROR, | 
					
						
							|  |  |  |  |                    g_resolver_error_from_addrinfo_error (retval), | 
					
						
							|  |  |  |  |                    _("Error reverse-resolving “%s”: %s"), | 
					
						
							|  |  |  |  |                    phys ? phys : "(unknown)", | 
					
						
							|  |  |  |  |                    error_message); | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |       g_free (phys); | 
					
						
							| 
									
										
										
										
											2019-03-21 11:51:37 +00:00
										 |  |  |  |       g_free (error_message); | 
					
						
							| 
									
										
										
										
											2023-03-30 13:42:19 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |       return NULL; | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |     } | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static gchar * | 
					
						
							|  |  |  |  | lookup_by_address (GResolver        *resolver, | 
					
						
							|  |  |  |  |                    GInetAddress     *address, | 
					
						
							|  |  |  |  |                    GCancellable     *cancellable, | 
					
						
							|  |  |  |  |                    GError          **error) | 
					
						
							|  |  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  |   GThreadedResolver *self = G_THREADED_RESOLVER (resolver); | 
					
						
							| 
									
										
										
										
											2023-04-25 15:56:47 +01:00
										 |  |  |  |   LookupData *data = NULL; | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  |   GTask *task; | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  |   gchar *name; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-25 15:56:47 +01:00
										 |  |  |  |   data = lookup_data_new_by_address (address); | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  |   task = g_task_new (resolver, cancellable, NULL, NULL); | 
					
						
							| 
									
										
										
										
											2016-06-16 19:39:38 -04:00
										 |  |  |  |   g_task_set_source_tag (task, lookup_by_address); | 
					
						
							| 
									
										
										
										
											2020-06-25 23:36:08 +01:00
										 |  |  |  |   g_task_set_name (task, "[gio] resolver lookup"); | 
					
						
							| 
									
										
										
										
											2023-04-25 15:56:47 +01:00
										 |  |  |  |   g_task_set_task_data (task, g_steal_pointer (&data), (GDestroyNotify) lookup_data_free); | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   run_task_in_thread_pool_sync (self, task); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  |   name = g_task_propagate_pointer (task, error); | 
					
						
							|  |  |  |  |   g_object_unref (task); | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   return name; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static void | 
					
						
							|  |  |  |  | lookup_by_address_async (GResolver           *resolver, | 
					
						
							|  |  |  |  |                          GInetAddress        *address, | 
					
						
							|  |  |  |  |                          GCancellable        *cancellable, | 
					
						
							|  |  |  |  |                          GAsyncReadyCallback  callback, | 
					
						
							|  |  |  |  |                          gpointer             user_data) | 
					
						
							|  |  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  |   GThreadedResolver *self = G_THREADED_RESOLVER (resolver); | 
					
						
							| 
									
										
										
										
											2023-04-25 15:56:47 +01:00
										 |  |  |  |   LookupData *data = NULL; | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  |   GTask *task; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-25 15:56:47 +01:00
										 |  |  |  |   data = lookup_data_new_by_address (address); | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  |   task = g_task_new (resolver, cancellable, callback, user_data); | 
					
						
							| 
									
										
										
										
											2016-06-16 19:39:38 -04:00
										 |  |  |  |   g_task_set_source_tag (task, lookup_by_address_async); | 
					
						
							| 
									
										
										
										
											2020-06-25 23:36:08 +01:00
										 |  |  |  |   g_task_set_name (task, "[gio] resolver lookup"); | 
					
						
							| 
									
										
										
										
											2023-04-25 15:56:47 +01:00
										 |  |  |  |   g_task_set_task_data (task, g_steal_pointer (&data), (GDestroyNotify) lookup_data_free); | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   run_task_in_thread_pool_async (self, task); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  |   g_object_unref (task); | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static gchar * | 
					
						
							|  |  |  |  | lookup_by_address_finish (GResolver     *resolver, | 
					
						
							|  |  |  |  |                           GAsyncResult  *result, | 
					
						
							|  |  |  |  |                           GError       **error) | 
					
						
							|  |  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  |   g_return_val_if_fail (g_task_is_valid (result, resolver), NULL); | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  |   return g_task_propagate_pointer (G_TASK (result), error); | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  | #if defined(G_OS_UNIX)
 | 
					
						
							| 
									
										
										
										
											2012-11-28 16:55:54 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-12 23:29:00 -04:00
										 |  |  |  | #if defined __BIONIC__ && !defined BIND_4_COMPAT
 | 
					
						
							| 
									
										
										
										
											2012-11-28 16:55:54 +01:00
										 |  |  |  | /* Copy from bionic/libc/private/arpa_nameser_compat.h
 | 
					
						
							|  |  |  |  |  * and bionic/libc/private/arpa_nameser.h */ | 
					
						
							|  |  |  |  | typedef struct { | 
					
						
							|  |  |  |  | 	unsigned	id :16;		/* query identification number */ | 
					
						
							|  |  |  |  | #if BYTE_ORDER == BIG_ENDIAN
 | 
					
						
							|  |  |  |  | 			/* fields in third byte */ | 
					
						
							|  |  |  |  | 	unsigned	qr: 1;		/* response flag */ | 
					
						
							|  |  |  |  | 	unsigned	opcode: 4;	/* purpose of message */ | 
					
						
							| 
									
										
										
										
											2020-06-12 14:02:30 +01:00
										 |  |  |  | 	unsigned	aa: 1;		/* authoritative answer */ | 
					
						
							| 
									
										
										
										
											2012-11-28 16:55:54 +01:00
										 |  |  |  | 	unsigned	tc: 1;		/* truncated message */ | 
					
						
							|  |  |  |  | 	unsigned	rd: 1;		/* recursion desired */ | 
					
						
							|  |  |  |  | 			/* fields in fourth byte */ | 
					
						
							|  |  |  |  | 	unsigned	ra: 1;		/* recursion available */ | 
					
						
							|  |  |  |  | 	unsigned	unused :1;	/* unused bits (MBZ as of 4.9.3a3) */ | 
					
						
							|  |  |  |  | 	unsigned	ad: 1;		/* authentic data from named */ | 
					
						
							|  |  |  |  | 	unsigned	cd: 1;		/* checking disabled by resolver */ | 
					
						
							|  |  |  |  | 	unsigned	rcode :4;	/* response code */ | 
					
						
							|  |  |  |  | #endif
 | 
					
						
							|  |  |  |  | #if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN
 | 
					
						
							|  |  |  |  | 			/* fields in third byte */ | 
					
						
							|  |  |  |  | 	unsigned	rd :1;		/* recursion desired */ | 
					
						
							|  |  |  |  | 	unsigned	tc :1;		/* truncated message */ | 
					
						
							| 
									
										
										
										
											2020-06-12 14:02:30 +01:00
										 |  |  |  | 	unsigned	aa :1;		/* authoritative answer */ | 
					
						
							| 
									
										
										
										
											2012-11-28 16:55:54 +01:00
										 |  |  |  | 	unsigned	opcode :4;	/* purpose of message */ | 
					
						
							|  |  |  |  | 	unsigned	qr :1;		/* response flag */ | 
					
						
							|  |  |  |  | 			/* fields in fourth byte */ | 
					
						
							|  |  |  |  | 	unsigned	rcode :4;	/* response code */ | 
					
						
							|  |  |  |  | 	unsigned	cd: 1;		/* checking disabled by resolver */ | 
					
						
							|  |  |  |  | 	unsigned	ad: 1;		/* authentic data from named */ | 
					
						
							|  |  |  |  | 	unsigned	unused :1;	/* unused bits (MBZ as of 4.9.3a3) */ | 
					
						
							|  |  |  |  | 	unsigned	ra :1;		/* recursion available */ | 
					
						
							|  |  |  |  | #endif
 | 
					
						
							|  |  |  |  | 			/* remaining bytes */ | 
					
						
							|  |  |  |  | 	unsigned	qdcount :16;	/* number of question entries */ | 
					
						
							|  |  |  |  | 	unsigned	ancount :16;	/* number of answer entries */ | 
					
						
							|  |  |  |  | 	unsigned	nscount :16;	/* number of authority entries */ | 
					
						
							|  |  |  |  | 	unsigned	arcount :16;	/* number of resource entries */ | 
					
						
							|  |  |  |  | } HEADER; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #define NS_INT32SZ	4	/* #/bytes of data in a uint32_t */
 | 
					
						
							|  |  |  |  | #define NS_INT16SZ	2	/* #/bytes of data in a uint16_t */
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #define NS_GET16(s, cp) do { \
 | 
					
						
							|  |  |  |  | 	const u_char *t_cp = (const u_char *)(cp); \ | 
					
						
							|  |  |  |  | 	(s) = ((uint16_t)t_cp[0] << 8) \ | 
					
						
							|  |  |  |  | 	    | ((uint16_t)t_cp[1]) \ | 
					
						
							|  |  |  |  | 	    ; \ | 
					
						
							|  |  |  |  | 	(cp) += NS_INT16SZ; \ | 
					
						
							|  |  |  |  | } while (/*CONSTCOND*/0) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #define NS_GET32(l, cp) do { \
 | 
					
						
							|  |  |  |  | 	const u_char *t_cp = (const u_char *)(cp); \ | 
					
						
							|  |  |  |  | 	(l) = ((uint32_t)t_cp[0] << 24) \ | 
					
						
							|  |  |  |  | 	    | ((uint32_t)t_cp[1] << 16) \ | 
					
						
							|  |  |  |  | 	    | ((uint32_t)t_cp[2] << 8) \ | 
					
						
							|  |  |  |  | 	    | ((uint32_t)t_cp[3]) \ | 
					
						
							|  |  |  |  | 	    ; \ | 
					
						
							|  |  |  |  | 	(cp) += NS_INT32SZ; \ | 
					
						
							|  |  |  |  | } while (/*CONSTCOND*/0) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #define	GETSHORT		NS_GET16
 | 
					
						
							|  |  |  |  | #define	GETLONG			NS_GET32
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #define C_IN 1
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* From bionic/libc/private/resolv_private.h */ | 
					
						
							|  |  |  |  | int dn_expand(const u_char *, const u_char *, const u_char *, char *, int); | 
					
						
							|  |  |  |  | #define dn_skipname __dn_skipname
 | 
					
						
							|  |  |  |  | int dn_skipname(const u_char *, const u_char *); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* From bionic/libc/private/arpa_nameser_compat.h */ | 
					
						
							|  |  |  |  | #define T_MX		ns_t_mx
 | 
					
						
							|  |  |  |  | #define T_TXT		ns_t_txt
 | 
					
						
							|  |  |  |  | #define T_SOA		ns_t_soa
 | 
					
						
							|  |  |  |  | #define T_NS		ns_t_ns
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* From bionic/libc/private/arpa_nameser.h */ | 
					
						
							|  |  |  |  | typedef enum __ns_type { | 
					
						
							|  |  |  |  | 	ns_t_invalid = 0,	/* Cookie. */ | 
					
						
							|  |  |  |  | 	ns_t_a = 1,		/* Host address. */ | 
					
						
							|  |  |  |  | 	ns_t_ns = 2,		/* Authoritative server. */ | 
					
						
							|  |  |  |  | 	ns_t_md = 3,		/* Mail destination. */ | 
					
						
							|  |  |  |  | 	ns_t_mf = 4,		/* Mail forwarder. */ | 
					
						
							|  |  |  |  | 	ns_t_cname = 5,		/* Canonical name. */ | 
					
						
							|  |  |  |  | 	ns_t_soa = 6,		/* Start of authority zone. */ | 
					
						
							|  |  |  |  | 	ns_t_mb = 7,		/* Mailbox domain name. */ | 
					
						
							|  |  |  |  | 	ns_t_mg = 8,		/* Mail group member. */ | 
					
						
							|  |  |  |  | 	ns_t_mr = 9,		/* Mail rename name. */ | 
					
						
							|  |  |  |  | 	ns_t_null = 10,		/* Null resource record. */ | 
					
						
							|  |  |  |  | 	ns_t_wks = 11,		/* Well known service. */ | 
					
						
							|  |  |  |  | 	ns_t_ptr = 12,		/* Domain name pointer. */ | 
					
						
							|  |  |  |  | 	ns_t_hinfo = 13,	/* Host information. */ | 
					
						
							|  |  |  |  | 	ns_t_minfo = 14,	/* Mailbox information. */ | 
					
						
							|  |  |  |  | 	ns_t_mx = 15,		/* Mail routing information. */ | 
					
						
							|  |  |  |  | 	ns_t_txt = 16,		/* Text strings. */ | 
					
						
							|  |  |  |  | 	ns_t_rp = 17,		/* Responsible person. */ | 
					
						
							|  |  |  |  | 	ns_t_afsdb = 18,	/* AFS cell database. */ | 
					
						
							|  |  |  |  | 	ns_t_x25 = 19,		/* X_25 calling address. */ | 
					
						
							|  |  |  |  | 	ns_t_isdn = 20,		/* ISDN calling address. */ | 
					
						
							|  |  |  |  | 	ns_t_rt = 21,		/* Router. */ | 
					
						
							|  |  |  |  | 	ns_t_nsap = 22,		/* NSAP address. */ | 
					
						
							|  |  |  |  | 	ns_t_nsap_ptr = 23,	/* Reverse NSAP lookup (deprecated). */ | 
					
						
							|  |  |  |  | 	ns_t_sig = 24,		/* Security signature. */ | 
					
						
							|  |  |  |  | 	ns_t_key = 25,		/* Security key. */ | 
					
						
							|  |  |  |  | 	ns_t_px = 26,		/* X.400 mail mapping. */ | 
					
						
							|  |  |  |  | 	ns_t_gpos = 27,		/* Geographical position (withdrawn). */ | 
					
						
							|  |  |  |  | 	ns_t_aaaa = 28,		/* Ip6 Address. */ | 
					
						
							|  |  |  |  | 	ns_t_loc = 29,		/* Location Information. */ | 
					
						
							|  |  |  |  | 	ns_t_nxt = 30,		/* Next domain (security). */ | 
					
						
							|  |  |  |  | 	ns_t_eid = 31,		/* Endpoint identifier. */ | 
					
						
							|  |  |  |  | 	ns_t_nimloc = 32,	/* Nimrod Locator. */ | 
					
						
							|  |  |  |  | 	ns_t_srv = 33,		/* Server Selection. */ | 
					
						
							|  |  |  |  | 	ns_t_atma = 34,		/* ATM Address */ | 
					
						
							|  |  |  |  | 	ns_t_naptr = 35,	/* Naming Authority PoinTeR */ | 
					
						
							|  |  |  |  | 	ns_t_kx = 36,		/* Key Exchange */ | 
					
						
							|  |  |  |  | 	ns_t_cert = 37,		/* Certification record */ | 
					
						
							|  |  |  |  | 	ns_t_a6 = 38,		/* IPv6 address (deprecates AAAA) */ | 
					
						
							|  |  |  |  | 	ns_t_dname = 39,	/* Non-terminal DNAME (for IPv6) */ | 
					
						
							| 
									
										
										
										
											2020-06-12 14:02:30 +01:00
										 |  |  |  | 	ns_t_sink = 40,		/* Kitchen sink (experimental) */ | 
					
						
							| 
									
										
										
										
											2012-11-28 16:55:54 +01:00
										 |  |  |  | 	ns_t_opt = 41,		/* EDNS0 option (meta-RR) */ | 
					
						
							|  |  |  |  | 	ns_t_apl = 42,		/* Address prefix list (RFC 3123) */ | 
					
						
							|  |  |  |  | 	ns_t_tkey = 249,	/* Transaction key */ | 
					
						
							|  |  |  |  | 	ns_t_tsig = 250,	/* Transaction signature. */ | 
					
						
							|  |  |  |  | 	ns_t_ixfr = 251,	/* Incremental zone transfer. */ | 
					
						
							|  |  |  |  | 	ns_t_axfr = 252,	/* Transfer zone of authority. */ | 
					
						
							|  |  |  |  | 	ns_t_mailb = 253,	/* Transfer mailbox records. */ | 
					
						
							|  |  |  |  | 	ns_t_maila = 254,	/* Transfer mail agent records. */ | 
					
						
							|  |  |  |  | 	ns_t_any = 255,		/* Wildcard match. */ | 
					
						
							|  |  |  |  | 	ns_t_zxfr = 256,	/* BIND-specific, nonstandard. */ | 
					
						
							|  |  |  |  | 	ns_t_max = 65536 | 
					
						
							|  |  |  |  | } ns_type; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #endif /* __BIONIC__ */
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-18 15:53:18 +00:00
										 |  |  |  | /* Wrapper around dn_expand() which does associated length checks and returns
 | 
					
						
							|  |  |  |  |  * errors as #GError. */ | 
					
						
							|  |  |  |  | static gboolean | 
					
						
							|  |  |  |  | expand_name (const gchar   *rrname, | 
					
						
							|  |  |  |  |              const guint8  *answer, | 
					
						
							|  |  |  |  |              const guint8  *end, | 
					
						
							|  |  |  |  |              const guint8 **p, | 
					
						
							|  |  |  |  |              gchar         *namebuf, | 
					
						
							|  |  |  |  |              gsize          namebuf_len, | 
					
						
							|  |  |  |  |              GError       **error) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   int expand_result; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   expand_result = dn_expand (answer, end, *p, namebuf, namebuf_len); | 
					
						
							|  |  |  |  |   if (expand_result < 0 || end - *p < expand_result) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_INTERNAL, | 
					
						
							|  |  |  |  |                    /* Translators: the placeholder is a DNS record type, such as ‘MX’ or ‘SRV’ */ | 
					
						
							|  |  |  |  |                    _("Error parsing DNS %s record: malformed DNS packet"), rrname); | 
					
						
							|  |  |  |  |       return FALSE; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   *p += expand_result; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   return TRUE; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  | static GVariant * | 
					
						
							| 
									
										
										
										
											2021-12-15 16:55:57 +00:00
										 |  |  |  | parse_res_srv (const guint8  *answer, | 
					
						
							|  |  |  |  |                const guint8  *end, | 
					
						
							| 
									
										
										
										
											2022-03-18 15:53:18 +00:00
										 |  |  |  |                const guint8 **p, | 
					
						
							|  |  |  |  |                GError       **error) | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  | { | 
					
						
							|  |  |  |  |   gchar namebuf[1024]; | 
					
						
							|  |  |  |  |   guint16 priority, weight, port; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-18 15:53:18 +00:00
										 |  |  |  |   if (end - *p < 6) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_INTERNAL, | 
					
						
							|  |  |  |  |                    /* Translators: the placeholder is a DNS record type, such as ‘MX’ or ‘SRV’ */ | 
					
						
							|  |  |  |  |                    _("Error parsing DNS %s record: malformed DNS packet"), "SRV"); | 
					
						
							|  |  |  |  |       return NULL; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |   GETSHORT (priority, *p); | 
					
						
							|  |  |  |  |   GETSHORT (weight, *p); | 
					
						
							|  |  |  |  |   GETSHORT (port, *p); | 
					
						
							| 
									
										
										
										
											2022-03-18 15:53:18 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-17 12:45:19 +01:00
										 |  |  |  |   /* RFC 2782 says (on page 4) that “Unless and until permitted by future
 | 
					
						
							|  |  |  |  |    * standards action, name compression is not to be used for this field.”, so | 
					
						
							|  |  |  |  |    * technically we shouldn’t be expanding names here for SRV records. | 
					
						
							|  |  |  |  |    * | 
					
						
							|  |  |  |  |    * However, other DNS resolvers (such as systemd[1]) do, and it seems in | 
					
						
							|  |  |  |  |    * keeping with the principle of being liberal in what you accept and strict | 
					
						
							|  |  |  |  |    * in what you emit. It also seems harmless. | 
					
						
							|  |  |  |  |    * | 
					
						
							|  |  |  |  |    * An earlier version of the RFC, RFC 2052 (now obsolete) specified that name | 
					
						
							|  |  |  |  |    * compression *was* to be used for SRV targets[2]. | 
					
						
							|  |  |  |  |    * | 
					
						
							|  |  |  |  |    * See discussion on https://gitlab.gnome.org/GNOME/glib/-/issues/2622.
 | 
					
						
							|  |  |  |  |    * | 
					
						
							|  |  |  |  |    * [1]: https://github.com/yuwata/systemd/blob/2d23cc3c07c49722ce93170737b3efd2692a2d08/src/resolve/resolved-dns-packet.c#L1674
 | 
					
						
							|  |  |  |  |    * [2]: https://datatracker.ietf.org/doc/html/rfc2052#page-3
 | 
					
						
							|  |  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2022-03-18 15:53:18 +00:00
										 |  |  |  |   if (!expand_name ("SRV", answer, end, p, namebuf, sizeof (namebuf), error)) | 
					
						
							|  |  |  |  |     return NULL; | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   return g_variant_new ("(qqqs)", | 
					
						
							|  |  |  |  |                         priority, | 
					
						
							|  |  |  |  |                         weight, | 
					
						
							|  |  |  |  |                         port, | 
					
						
							|  |  |  |  |                         namebuf); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static GVariant * | 
					
						
							| 
									
										
										
										
											2021-12-15 16:55:57 +00:00
										 |  |  |  | parse_res_soa (const guint8  *answer, | 
					
						
							|  |  |  |  |                const guint8  *end, | 
					
						
							| 
									
										
										
										
											2022-03-18 15:53:18 +00:00
										 |  |  |  |                const guint8 **p, | 
					
						
							|  |  |  |  |                GError       **error) | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  | { | 
					
						
							|  |  |  |  |   gchar mnamebuf[1024]; | 
					
						
							|  |  |  |  |   gchar rnamebuf[1024]; | 
					
						
							|  |  |  |  |   guint32 serial, refresh, retry, expire, ttl; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-18 15:53:18 +00:00
										 |  |  |  |   if (!expand_name ("SOA", answer, end, p, mnamebuf, sizeof (mnamebuf), error)) | 
					
						
							|  |  |  |  |     return NULL; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   if (!expand_name ("SOA", answer, end, p, rnamebuf, sizeof (rnamebuf), error)) | 
					
						
							|  |  |  |  |     return NULL; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   if (end - *p < 20) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_INTERNAL, | 
					
						
							|  |  |  |  |                    /* Translators: the placeholder is a DNS record type, such as ‘MX’ or ‘SRV’ */ | 
					
						
							|  |  |  |  |                    _("Error parsing DNS %s record: malformed DNS packet"), "SOA"); | 
					
						
							|  |  |  |  |       return NULL; | 
					
						
							|  |  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   GETLONG (serial, *p); | 
					
						
							|  |  |  |  |   GETLONG (refresh, *p); | 
					
						
							|  |  |  |  |   GETLONG (retry, *p); | 
					
						
							|  |  |  |  |   GETLONG (expire, *p); | 
					
						
							|  |  |  |  |   GETLONG (ttl, *p); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   return g_variant_new ("(ssuuuuu)", | 
					
						
							|  |  |  |  |                         mnamebuf, | 
					
						
							|  |  |  |  |                         rnamebuf, | 
					
						
							|  |  |  |  |                         serial, | 
					
						
							|  |  |  |  |                         refresh, | 
					
						
							|  |  |  |  |                         retry, | 
					
						
							|  |  |  |  |                         expire, | 
					
						
							|  |  |  |  |                         ttl); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static GVariant * | 
					
						
							| 
									
										
										
										
											2021-12-15 16:55:57 +00:00
										 |  |  |  | parse_res_ns (const guint8  *answer, | 
					
						
							|  |  |  |  |               const guint8  *end, | 
					
						
							| 
									
										
										
										
											2022-03-18 15:53:18 +00:00
										 |  |  |  |               const guint8 **p, | 
					
						
							|  |  |  |  |               GError       **error) | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  | { | 
					
						
							|  |  |  |  |   gchar namebuf[1024]; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-18 15:53:18 +00:00
										 |  |  |  |   if (!expand_name ("NS", answer, end, p, namebuf, sizeof (namebuf), error)) | 
					
						
							|  |  |  |  |     return NULL; | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   return g_variant_new ("(s)", namebuf); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static GVariant * | 
					
						
							| 
									
										
										
										
											2021-12-15 16:55:57 +00:00
										 |  |  |  | parse_res_mx (const guint8  *answer, | 
					
						
							|  |  |  |  |               const guint8  *end, | 
					
						
							| 
									
										
										
										
											2022-03-18 15:53:18 +00:00
										 |  |  |  |               const guint8 **p, | 
					
						
							|  |  |  |  |               GError       **error) | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  | { | 
					
						
							|  |  |  |  |   gchar namebuf[1024]; | 
					
						
							|  |  |  |  |   guint16 preference; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-18 15:53:18 +00:00
										 |  |  |  |   if (end - *p < 2) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_INTERNAL, | 
					
						
							|  |  |  |  |                    /* Translators: the placeholder is a DNS record type, such as ‘MX’ or ‘SRV’ */ | 
					
						
							|  |  |  |  |                    _("Error parsing DNS %s record: malformed DNS packet"), "MX"); | 
					
						
							|  |  |  |  |       return NULL; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |   GETSHORT (preference, *p); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-18 15:53:18 +00:00
										 |  |  |  |   if (!expand_name ("MX", answer, end, p, namebuf, sizeof (namebuf), error)) | 
					
						
							|  |  |  |  |     return NULL; | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   return g_variant_new ("(qs)", | 
					
						
							|  |  |  |  |                         preference, | 
					
						
							|  |  |  |  |                         namebuf); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static GVariant * | 
					
						
							| 
									
										
										
										
											2021-12-15 16:55:57 +00:00
										 |  |  |  | parse_res_txt (const guint8  *answer, | 
					
						
							|  |  |  |  |                const guint8  *end, | 
					
						
							| 
									
										
										
										
											2022-03-18 15:53:18 +00:00
										 |  |  |  |                const guint8 **p, | 
					
						
							|  |  |  |  |                GError       **error) | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  | { | 
					
						
							|  |  |  |  |   GVariant *record; | 
					
						
							|  |  |  |  |   GPtrArray *array; | 
					
						
							| 
									
										
										
										
											2021-12-15 16:55:57 +00:00
										 |  |  |  |   const guint8 *at = *p; | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |   gsize len; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-18 15:53:18 +00:00
										 |  |  |  |   if (end - *p == 0) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_INTERNAL, | 
					
						
							|  |  |  |  |                    /* Translators: the placeholder is a DNS record type, such as ‘MX’ or ‘SRV’ */ | 
					
						
							|  |  |  |  |                    _("Error parsing DNS %s record: malformed DNS packet"), "TXT"); | 
					
						
							|  |  |  |  |       return NULL; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |   array = g_ptr_array_new_with_free_func (g_free); | 
					
						
							|  |  |  |  |   while (at < end) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       len = *(at++); | 
					
						
							| 
									
										
										
										
											2020-09-26 11:11:44 -04:00
										 |  |  |  |       if (len > (gsize) (end - at)) | 
					
						
							| 
									
										
										
										
											2022-03-18 15:53:18 +00:00
										 |  |  |  |         { | 
					
						
							|  |  |  |  |           g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_INTERNAL, | 
					
						
							|  |  |  |  |                        /* Translators: the placeholder is a DNS record type, such as ‘MX’ or ‘SRV’ */ | 
					
						
							|  |  |  |  |                        _("Error parsing DNS %s record: malformed DNS packet"), "TXT"); | 
					
						
							|  |  |  |  |           g_ptr_array_free (array, TRUE); | 
					
						
							|  |  |  |  |           return NULL; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |       g_ptr_array_add (array, g_strndup ((gchar *)at, len)); | 
					
						
							|  |  |  |  |       at += len; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   *p = at; | 
					
						
							|  |  |  |  |   record = g_variant_new ("(@as)", | 
					
						
							|  |  |  |  |                           g_variant_new_strv ((const gchar **)array->pdata, array->len)); | 
					
						
							|  |  |  |  |   g_ptr_array_free (array, TRUE); | 
					
						
							|  |  |  |  |   return record; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-21 17:45:17 +00:00
										 |  |  |  | gint | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  | g_resolver_record_type_to_rrtype (GResolverRecordType type) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   switch (type) | 
					
						
							|  |  |  |  |   { | 
					
						
							|  |  |  |  |     case G_RESOLVER_RECORD_SRV: | 
					
						
							|  |  |  |  |       return T_SRV; | 
					
						
							|  |  |  |  |     case G_RESOLVER_RECORD_TXT: | 
					
						
							|  |  |  |  |       return T_TXT; | 
					
						
							|  |  |  |  |     case G_RESOLVER_RECORD_SOA: | 
					
						
							|  |  |  |  |       return T_SOA; | 
					
						
							|  |  |  |  |     case G_RESOLVER_RECORD_NS: | 
					
						
							|  |  |  |  |       return T_NS; | 
					
						
							|  |  |  |  |     case G_RESOLVER_RECORD_MX: | 
					
						
							|  |  |  |  |       return T_MX; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  |   g_return_val_if_reached (-1); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-15 16:53:41 +00:00
										 |  |  |  | GList * | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  | g_resolver_records_from_res_query (const gchar      *rrname, | 
					
						
							|  |  |  |  |                                    gint              rrtype, | 
					
						
							| 
									
										
										
										
											2021-12-15 16:55:57 +00:00
										 |  |  |  |                                    const guint8     *answer, | 
					
						
							|  |  |  |  |                                    gssize            len, | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |                                    gint              herr, | 
					
						
							|  |  |  |  |                                    GError          **error) | 
					
						
							|  |  |  |  | { | 
					
						
							| 
									
										
										
										
											2022-03-21 14:51:08 +00:00
										 |  |  |  |   uint16_t count; | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |   gchar namebuf[1024]; | 
					
						
							| 
									
										
										
										
											2021-12-15 16:55:57 +00:00
										 |  |  |  |   const guint8 *end, *p; | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |   guint16 type, qclass, rdlength; | 
					
						
							| 
									
										
										
										
											2021-12-15 16:55:57 +00:00
										 |  |  |  |   const HEADER *header; | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |   GList *records; | 
					
						
							|  |  |  |  |   GVariant *record; | 
					
						
							| 
									
										
										
										
											2022-03-18 15:49:33 +00:00
										 |  |  |  |   gsize len_unsigned; | 
					
						
							| 
									
										
										
										
											2022-03-18 15:53:18 +00:00
										 |  |  |  |   GError *parsing_error = NULL; | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   if (len <= 0) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       if (len == 0 || herr == HOST_NOT_FOUND || herr == NO_DATA) | 
					
						
							|  |  |  |  |         { | 
					
						
							| 
									
										
										
										
											2013-12-08 14:22:51 -05:00
										 |  |  |  |           g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND, | 
					
						
							| 
									
										
										
										
											2016-09-30 05:47:15 +02:00
										 |  |  |  |                        _("No DNS record of the requested type for “%s”"), rrname); | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |         } | 
					
						
							|  |  |  |  |       else if (herr == TRY_AGAIN) | 
					
						
							|  |  |  |  |         { | 
					
						
							| 
									
										
										
										
											2013-12-08 14:22:51 -05:00
										 |  |  |  |           g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_TEMPORARY_FAILURE, | 
					
						
							| 
									
										
										
										
											2016-09-30 05:47:15 +02:00
										 |  |  |  |                        _("Temporarily unable to resolve “%s”"), rrname); | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |         } | 
					
						
							|  |  |  |  |       else | 
					
						
							|  |  |  |  |         { | 
					
						
							| 
									
										
										
										
											2013-12-08 14:22:51 -05:00
										 |  |  |  |           g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_INTERNAL, | 
					
						
							| 
									
										
										
										
											2016-09-30 05:47:15 +02:00
										 |  |  |  |                        _("Error resolving “%s”"), rrname); | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       return NULL; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-18 15:49:33 +00:00
										 |  |  |  |   /* We know len ≥ 0 now. */ | 
					
						
							|  |  |  |  |   len_unsigned = (gsize) len; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   if (len_unsigned < sizeof (HEADER)) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_INTERNAL, | 
					
						
							|  |  |  |  |                    /* Translators: the first placeholder is a domain name, the
 | 
					
						
							|  |  |  |  |                     * second is an error message */ | 
					
						
							|  |  |  |  |                    _("Error resolving “%s”: %s"), rrname, _("Malformed DNS packet")); | 
					
						
							|  |  |  |  |       return NULL; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |   records = NULL; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   header = (HEADER *)answer; | 
					
						
							|  |  |  |  |   p = answer + sizeof (HEADER); | 
					
						
							| 
									
										
										
										
											2022-03-18 15:49:33 +00:00
										 |  |  |  |   end = answer + len_unsigned; | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   /* Skip query */ | 
					
						
							|  |  |  |  |   count = ntohs (header->qdcount); | 
					
						
							|  |  |  |  |   while (count-- && p < end) | 
					
						
							|  |  |  |  |     { | 
					
						
							| 
									
										
										
										
											2022-03-18 15:51:20 +00:00
										 |  |  |  |       int expand_result; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       expand_result = dn_expand (answer, end, p, namebuf, sizeof (namebuf)); | 
					
						
							|  |  |  |  |       if (expand_result < 0 || end - p < expand_result + 4) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |           /* Not possible to recover parsing as the length of the rest of the
 | 
					
						
							|  |  |  |  |            * record is unknown or is too short. */ | 
					
						
							|  |  |  |  |           g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_INTERNAL, | 
					
						
							|  |  |  |  |                        /* Translators: the first placeholder is a domain name, the
 | 
					
						
							|  |  |  |  |                         * second is an error message */ | 
					
						
							|  |  |  |  |                        _("Error resolving “%s”: %s"), rrname, _("Malformed DNS packet")); | 
					
						
							|  |  |  |  |           return NULL; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       p += expand_result; | 
					
						
							|  |  |  |  |       p += 4;  /* skip TYPE and CLASS */ | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |       /* To silence gcc warnings */ | 
					
						
							|  |  |  |  |       namebuf[0] = namebuf[1]; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   /* Read answers */ | 
					
						
							|  |  |  |  |   count = ntohs (header->ancount); | 
					
						
							|  |  |  |  |   while (count-- && p < end) | 
					
						
							|  |  |  |  |     { | 
					
						
							| 
									
										
										
										
											2022-03-18 15:51:20 +00:00
										 |  |  |  |       int expand_result; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       expand_result = dn_expand (answer, end, p, namebuf, sizeof (namebuf)); | 
					
						
							|  |  |  |  |       if (expand_result < 0 || end - p < expand_result + 10) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |           /* Not possible to recover parsing as the length of the rest of the
 | 
					
						
							|  |  |  |  |            * record is unknown or is too short. */ | 
					
						
							| 
									
										
										
										
											2022-03-18 15:53:18 +00:00
										 |  |  |  |           g_set_error (&parsing_error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_INTERNAL, | 
					
						
							|  |  |  |  |                        /* Translators: the first placeholder is a domain name, the
 | 
					
						
							|  |  |  |  |                         * second is an error message */ | 
					
						
							|  |  |  |  |                        _("Error resolving “%s”: %s"), rrname, _("Malformed DNS packet")); | 
					
						
							|  |  |  |  |           break; | 
					
						
							| 
									
										
										
										
											2022-03-18 15:51:20 +00:00
										 |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       p += expand_result; | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |       GETSHORT (type, p); | 
					
						
							|  |  |  |  |       GETSHORT (qclass, p); | 
					
						
							| 
									
										
										
										
											2015-03-19 23:06:28 -04:00
										 |  |  |  |       p += 4; /* ignore the ttl (type=long) value */ | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |       GETSHORT (rdlength, p); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-18 16:19:44 +00:00
										 |  |  |  |       if (end - p < rdlength) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |           g_set_error (&parsing_error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_INTERNAL, | 
					
						
							|  |  |  |  |                        /* Translators: the first placeholder is a domain name, the
 | 
					
						
							|  |  |  |  |                         * second is an error message */ | 
					
						
							|  |  |  |  |                        _("Error resolving “%s”: %s"), rrname, _("Malformed DNS packet")); | 
					
						
							|  |  |  |  |           break; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |       if (type != rrtype || qclass != C_IN) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |           p += rdlength; | 
					
						
							|  |  |  |  |           continue; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       switch (rrtype) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |         case T_SRV: | 
					
						
							| 
									
										
										
										
											2022-03-18 16:19:44 +00:00
										 |  |  |  |           record = parse_res_srv (answer, p + rdlength, &p, &parsing_error); | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |           break; | 
					
						
							|  |  |  |  |         case T_MX: | 
					
						
							| 
									
										
										
										
											2022-03-18 16:19:44 +00:00
										 |  |  |  |           record = parse_res_mx (answer, p + rdlength, &p, &parsing_error); | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |           break; | 
					
						
							|  |  |  |  |         case T_SOA: | 
					
						
							| 
									
										
										
										
											2022-03-18 16:19:44 +00:00
										 |  |  |  |           record = parse_res_soa (answer, p + rdlength, &p, &parsing_error); | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |           break; | 
					
						
							|  |  |  |  |         case T_NS: | 
					
						
							| 
									
										
										
										
											2022-03-18 16:19:44 +00:00
										 |  |  |  |           record = parse_res_ns (answer, p + rdlength, &p, &parsing_error); | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |           break; | 
					
						
							|  |  |  |  |         case T_TXT: | 
					
						
							| 
									
										
										
										
											2022-03-18 15:53:18 +00:00
										 |  |  |  |           record = parse_res_txt (answer, p + rdlength, &p, &parsing_error); | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |           break; | 
					
						
							|  |  |  |  |         default: | 
					
						
							| 
									
										
										
										
											2024-03-27 12:07:42 +00:00
										 |  |  |  |           g_debug ("Unrecognized DNS record type %u", rrtype); | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |           record = NULL; | 
					
						
							|  |  |  |  |           break; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       if (record != NULL) | 
					
						
							| 
									
										
										
										
											2024-06-13 11:43:00 -07:00
										 |  |  |  |         records = g_list_prepend (records, g_variant_ref_sink (record)); | 
					
						
							| 
									
										
										
										
											2022-03-18 15:53:18 +00:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |       if (parsing_error != NULL) | 
					
						
							|  |  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-18 15:53:18 +00:00
										 |  |  |  |   if (parsing_error != NULL) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       g_propagate_prefixed_error (error, parsing_error, _("Failed to parse DNS response for “%s”: "), rrname); | 
					
						
							|  |  |  |  |       g_list_free_full (records, (GDestroyNotify)g_variant_unref); | 
					
						
							|  |  |  |  |       return NULL; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |   else if (records == NULL) | 
					
						
							| 
									
										
										
										
											2013-03-29 15:39:26 +01:00
										 |  |  |  |     { | 
					
						
							|  |  |  |  |       g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND, | 
					
						
							| 
									
										
										
										
											2016-09-30 05:47:15 +02:00
										 |  |  |  |                    _("No DNS record of the requested type for “%s”"), rrname); | 
					
						
							| 
									
										
										
										
											2013-03-29 15:39:26 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |       return NULL; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |   else | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |     return records; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #elif defined(G_OS_WIN32)
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static GVariant * | 
					
						
							| 
									
										
										
										
											2023-10-05 09:21:08 +02:00
										 |  |  |  | parse_dns_srv (DNS_RECORDA *rec) | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  | { | 
					
						
							|  |  |  |  |   return g_variant_new ("(qqqs)", | 
					
						
							|  |  |  |  |                         (guint16)rec->Data.SRV.wPriority, | 
					
						
							|  |  |  |  |                         (guint16)rec->Data.SRV.wWeight, | 
					
						
							|  |  |  |  |                         (guint16)rec->Data.SRV.wPort, | 
					
						
							|  |  |  |  |                         rec->Data.SRV.pNameTarget); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static GVariant * | 
					
						
							| 
									
										
										
										
											2023-10-05 09:21:08 +02:00
										 |  |  |  | parse_dns_soa (DNS_RECORDA *rec) | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  | { | 
					
						
							|  |  |  |  |   return g_variant_new ("(ssuuuuu)", | 
					
						
							|  |  |  |  |                         rec->Data.SOA.pNamePrimaryServer, | 
					
						
							|  |  |  |  |                         rec->Data.SOA.pNameAdministrator, | 
					
						
							|  |  |  |  |                         (guint32)rec->Data.SOA.dwSerialNo, | 
					
						
							|  |  |  |  |                         (guint32)rec->Data.SOA.dwRefresh, | 
					
						
							|  |  |  |  |                         (guint32)rec->Data.SOA.dwRetry, | 
					
						
							|  |  |  |  |                         (guint32)rec->Data.SOA.dwExpire, | 
					
						
							|  |  |  |  |                         (guint32)rec->Data.SOA.dwDefaultTtl); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static GVariant * | 
					
						
							| 
									
										
										
										
											2023-10-05 09:21:08 +02:00
										 |  |  |  | parse_dns_ns (DNS_RECORDA *rec) | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  | { | 
					
						
							|  |  |  |  |   return g_variant_new ("(s)", rec->Data.NS.pNameHost); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static GVariant * | 
					
						
							| 
									
										
										
										
											2023-10-05 09:21:08 +02:00
										 |  |  |  | parse_dns_mx (DNS_RECORDA *rec) | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  | { | 
					
						
							|  |  |  |  |   return g_variant_new ("(qs)", | 
					
						
							|  |  |  |  |                         (guint16)rec->Data.MX.wPreference, | 
					
						
							|  |  |  |  |                         rec->Data.MX.pNameExchange); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static GVariant * | 
					
						
							| 
									
										
										
										
											2023-10-05 09:21:08 +02:00
										 |  |  |  | parse_dns_txt (DNS_RECORDA *rec) | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  | { | 
					
						
							|  |  |  |  |   GVariant *record; | 
					
						
							|  |  |  |  |   GPtrArray *array; | 
					
						
							|  |  |  |  |   DWORD i; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   array = g_ptr_array_new (); | 
					
						
							|  |  |  |  |   for (i = 0; i < rec->Data.TXT.dwStringCount; i++) | 
					
						
							|  |  |  |  |     g_ptr_array_add (array, rec->Data.TXT.pStringArray[i]); | 
					
						
							|  |  |  |  |   record = g_variant_new ("(@as)", | 
					
						
							|  |  |  |  |                           g_variant_new_strv ((const gchar **)array->pdata, array->len)); | 
					
						
							|  |  |  |  |   g_ptr_array_free (array, TRUE); | 
					
						
							|  |  |  |  |   return record; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static WORD | 
					
						
							|  |  |  |  | g_resolver_record_type_to_dnstype (GResolverRecordType type) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   switch (type) | 
					
						
							|  |  |  |  |   { | 
					
						
							|  |  |  |  |     case G_RESOLVER_RECORD_SRV: | 
					
						
							|  |  |  |  |       return DNS_TYPE_SRV; | 
					
						
							|  |  |  |  |     case G_RESOLVER_RECORD_TXT: | 
					
						
							|  |  |  |  |       return DNS_TYPE_TEXT; | 
					
						
							|  |  |  |  |     case G_RESOLVER_RECORD_SOA: | 
					
						
							|  |  |  |  |       return DNS_TYPE_SOA; | 
					
						
							|  |  |  |  |     case G_RESOLVER_RECORD_NS: | 
					
						
							|  |  |  |  |       return DNS_TYPE_NS; | 
					
						
							|  |  |  |  |     case G_RESOLVER_RECORD_MX: | 
					
						
							|  |  |  |  |       return DNS_TYPE_MX; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  |   g_return_val_if_reached (-1); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static GList * | 
					
						
							|  |  |  |  | g_resolver_records_from_DnsQuery (const gchar  *rrname, | 
					
						
							|  |  |  |  |                                   WORD          dnstype, | 
					
						
							|  |  |  |  |                                   DNS_STATUS    status, | 
					
						
							| 
									
										
										
										
											2023-10-05 09:21:08 +02:00
										 |  |  |  |                                   DNS_RECORDA  *results, | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |                                   GError      **error) | 
					
						
							|  |  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-10-05 09:21:08 +02:00
										 |  |  |  |   DNS_RECORDA *rec; | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |   gpointer record; | 
					
						
							|  |  |  |  |   GList *records; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   if (status != ERROR_SUCCESS) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       if (status == DNS_ERROR_RCODE_NAME_ERROR) | 
					
						
							|  |  |  |  |         { | 
					
						
							| 
									
										
										
										
											2013-12-08 14:22:51 -05:00
										 |  |  |  |           g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND, | 
					
						
							| 
									
										
										
										
											2016-09-30 05:47:15 +02:00
										 |  |  |  |                        _("No DNS record of the requested type for “%s”"), rrname); | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |         } | 
					
						
							|  |  |  |  |       else if (status == DNS_ERROR_RCODE_SERVER_FAILURE) | 
					
						
							|  |  |  |  |         { | 
					
						
							| 
									
										
										
										
											2013-12-08 14:22:51 -05:00
										 |  |  |  |           g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_TEMPORARY_FAILURE, | 
					
						
							| 
									
										
										
										
											2016-09-30 05:47:15 +02:00
										 |  |  |  |                        _("Temporarily unable to resolve “%s”"), rrname); | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |         } | 
					
						
							|  |  |  |  |       else | 
					
						
							|  |  |  |  |         { | 
					
						
							| 
									
										
										
										
											2013-12-08 14:22:51 -05:00
										 |  |  |  |           g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_INTERNAL, | 
					
						
							| 
									
										
										
										
											2016-09-30 05:47:15 +02:00
										 |  |  |  |                        _("Error resolving “%s”"), rrname); | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       return NULL; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   records = NULL; | 
					
						
							|  |  |  |  |   for (rec = results; rec; rec = rec->pNext) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       if (rec->wType != dnstype) | 
					
						
							|  |  |  |  |         continue; | 
					
						
							|  |  |  |  |       switch (dnstype) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |         case DNS_TYPE_SRV: | 
					
						
							|  |  |  |  |           record = parse_dns_srv (rec); | 
					
						
							|  |  |  |  |           break; | 
					
						
							|  |  |  |  |         case DNS_TYPE_SOA: | 
					
						
							|  |  |  |  |           record = parse_dns_soa (rec); | 
					
						
							|  |  |  |  |           break; | 
					
						
							|  |  |  |  |         case DNS_TYPE_NS: | 
					
						
							|  |  |  |  |           record = parse_dns_ns (rec); | 
					
						
							|  |  |  |  |           break; | 
					
						
							|  |  |  |  |         case DNS_TYPE_MX: | 
					
						
							|  |  |  |  |           record = parse_dns_mx (rec); | 
					
						
							|  |  |  |  |           break; | 
					
						
							|  |  |  |  |         case DNS_TYPE_TEXT: | 
					
						
							|  |  |  |  |           record = parse_dns_txt (rec); | 
					
						
							|  |  |  |  |           break; | 
					
						
							|  |  |  |  |         default: | 
					
						
							|  |  |  |  |           g_warn_if_reached (); | 
					
						
							|  |  |  |  |           record = NULL; | 
					
						
							|  |  |  |  |           break; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |       if (record != NULL) | 
					
						
							|  |  |  |  |         records = g_list_prepend (records, g_variant_ref_sink (record)); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-29 15:39:26 +01:00
										 |  |  |  |   if (records == NULL) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND, | 
					
						
							| 
									
										
										
										
											2016-09-30 05:47:15 +02:00
										 |  |  |  |                    _("No DNS record of the requested type for “%s”"), rrname); | 
					
						
							| 
									
										
										
										
											2013-03-29 15:39:26 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |       return NULL; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |   else | 
					
						
							|  |  |  |  |     return records; | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #endif
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-09 11:38:08 -05:00
										 |  |  |  | static void | 
					
						
							|  |  |  |  | free_records (GList *records) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   g_list_free_full (records, (GDestroyNotify) g_variant_unref); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-28 16:55:54 +01:00
										 |  |  |  | #if defined(G_OS_UNIX)
 | 
					
						
							|  |  |  |  | #ifdef __BIONIC__
 | 
					
						
							| 
									
										
										
										
											2018-06-09 01:15:18 +02:00
										 |  |  |  | #ifndef C_IN
 | 
					
						
							| 
									
										
										
										
											2012-11-28 16:55:54 +01:00
										 |  |  |  | #define C_IN 1
 | 
					
						
							| 
									
										
										
										
											2018-06-09 01:15:18 +02:00
										 |  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2012-11-28 16:55:54 +01:00
										 |  |  |  | int res_query(const char *, int, int, u_char *, int); | 
					
						
							|  |  |  |  | #endif
 | 
					
						
							|  |  |  |  | #endif
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-30 13:42:19 +01:00
										 |  |  |  | static GList * | 
					
						
							|  |  |  |  | do_lookup_records (const gchar          *rrname, | 
					
						
							|  |  |  |  |                    GResolverRecordType   record_type, | 
					
						
							|  |  |  |  |                    GCancellable         *cancellable, | 
					
						
							|  |  |  |  |                    GError              **error) | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-11-09 11:38:08 -05:00
										 |  |  |  |   GList *records; | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | #if defined(G_OS_UNIX)
 | 
					
						
							| 
									
										
										
											
												Add support for MX, TXT, NS and SOA records to GResolver
 * Add resolver functions for looking up DNS records of
   various types. Currently implemented: MX, TXT, SOA, SRV, NS
 * Return records as GVariant tuples.
 * Make the GSrvTarget lookups a wrapper over this new
   functionality.
 * Rework the resolver test so that it has support for
   looking up MX, NS, SOA, TXT records, and uses GOptionContext
https://bugzilla.gnome.org/show_bug.cgi?id=672944
											
										 
											2012-04-04 17:13:10 +02:00
										 |  |  |  |   gint len = 512; | 
					
						
							|  |  |  |  |   gint herr; | 
					
						
							|  |  |  |  |   GByteArray *answer; | 
					
						
							|  |  |  |  |   gint rrtype; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												gio: Port GThreadedResolver to use res_nquery() to fix thread-safety
res_query() uses global state in the form of the struct __res_state
which contains the contents of resolv.conf (and other things). On Linux,
this state seems to be thread-local, so there is no problem. On OS X,
however, it is not, and hence multiple res_query() calls from parallel
threads will compete and return bogus results.
The fix for this is to use res_nquery(), introduced in BIND 8.2, which
takes an explicit state argument. This allows us to manually store the
state thread-locally. If res_nquery() isn’t available, we fall back to
res_query(). It should be available on OS X though. As a data point,
it’s available on Fedora 27.
There’s a slight complication in the fact that OS X requires the state
to be freed using res_ndestroy() rather than res_nclose(). Linux uses
res_nclose().
(See, for example, the NetBSD man page:
https://www.unix.com/man-page/netbsd/3/res_ninit/. The Linux one is
incomplete and not so useful:
http://man7.org/linux/man-pages/man3/resolver.3.html.)
The new code will call res_ninit() once per res_nquery() task. This is
not optimal, but no worse than before — since res_query() was being
called in a worker thread, on Linux, it would implicitly initialise the
thread-local struct __res_state when it was called. We’ve essentially
just made that explicit. In practical terms, this means a
stat("/etc/resolv.conf") call per res_nquery() task.
In future, we could improve this by using an explicit thread pool with
some manually-created worker threads, each of which initialises a struct
__res_state on spawning, and only updates it on receiving
the #GResolver::reload signal.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
https://bugzilla.gnome.org/show_bug.cgi?id=792050
											
										 
											2018-01-05 14:26:35 +00:00
										 |  |  |  | #ifdef HAVE_RES_NQUERY
 | 
					
						
							|  |  |  |  |   /* Load the resolver state. This is done once per worker thread, and the
 | 
					
						
							|  |  |  |  |    * #GResolver::reload signal is ignored (since we always reload). This could | 
					
						
							|  |  |  |  |    * be improved by having an explicit worker thread pool, with each thread | 
					
						
							|  |  |  |  |    * containing some state which is initialised at thread creation time and | 
					
						
							|  |  |  |  |    * updated in response to #GResolver::reload. | 
					
						
							|  |  |  |  |    * | 
					
						
							|  |  |  |  |    * What we have currently is not particularly worse than using res_query() in | 
					
						
							|  |  |  |  |    * worker threads, since it would transparently call res_init() for each new | 
					
						
							|  |  |  |  |    * worker thread. (Although the workers would get reused by the | 
					
						
							| 
									
										
										
										
											2019-02-25 11:22:45 +00:00
										 |  |  |  |    * #GThreadPool.) | 
					
						
							|  |  |  |  |    * | 
					
						
							|  |  |  |  |    * FreeBSD requires the state to be zero-filled before calling res_ninit(). */ | 
					
						
							|  |  |  |  |   struct __res_state res = { 0, }; | 
					
						
							| 
									
										
											  
											
												gio: Port GThreadedResolver to use res_nquery() to fix thread-safety
res_query() uses global state in the form of the struct __res_state
which contains the contents of resolv.conf (and other things). On Linux,
this state seems to be thread-local, so there is no problem. On OS X,
however, it is not, and hence multiple res_query() calls from parallel
threads will compete and return bogus results.
The fix for this is to use res_nquery(), introduced in BIND 8.2, which
takes an explicit state argument. This allows us to manually store the
state thread-locally. If res_nquery() isn’t available, we fall back to
res_query(). It should be available on OS X though. As a data point,
it’s available on Fedora 27.
There’s a slight complication in the fact that OS X requires the state
to be freed using res_ndestroy() rather than res_nclose(). Linux uses
res_nclose().
(See, for example, the NetBSD man page:
https://www.unix.com/man-page/netbsd/3/res_ninit/. The Linux one is
incomplete and not so useful:
http://man7.org/linux/man-pages/man3/resolver.3.html.)
The new code will call res_ninit() once per res_nquery() task. This is
not optimal, but no worse than before — since res_query() was being
called in a worker thread, on Linux, it would implicitly initialise the
thread-local struct __res_state when it was called. We’ve essentially
just made that explicit. In practical terms, this means a
stat("/etc/resolv.conf") call per res_nquery() task.
In future, we could improve this by using an explicit thread pool with
some manually-created worker threads, each of which initialises a struct
__res_state on spawning, and only updates it on receiving
the #GResolver::reload signal.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
https://bugzilla.gnome.org/show_bug.cgi?id=792050
											
										 
											2018-01-05 14:26:35 +00:00
										 |  |  |  |   if (res_ninit (&res) != 0) | 
					
						
							|  |  |  |  |     { | 
					
						
							| 
									
										
										
										
											2023-03-30 13:42:19 +01:00
										 |  |  |  |       g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_INTERNAL, | 
					
						
							|  |  |  |  |                    _("Error resolving “%s”"), rrname); | 
					
						
							|  |  |  |  |       return NULL; | 
					
						
							| 
									
										
											  
											
												gio: Port GThreadedResolver to use res_nquery() to fix thread-safety
res_query() uses global state in the form of the struct __res_state
which contains the contents of resolv.conf (and other things). On Linux,
this state seems to be thread-local, so there is no problem. On OS X,
however, it is not, and hence multiple res_query() calls from parallel
threads will compete and return bogus results.
The fix for this is to use res_nquery(), introduced in BIND 8.2, which
takes an explicit state argument. This allows us to manually store the
state thread-locally. If res_nquery() isn’t available, we fall back to
res_query(). It should be available on OS X though. As a data point,
it’s available on Fedora 27.
There’s a slight complication in the fact that OS X requires the state
to be freed using res_ndestroy() rather than res_nclose(). Linux uses
res_nclose().
(See, for example, the NetBSD man page:
https://www.unix.com/man-page/netbsd/3/res_ninit/. The Linux one is
incomplete and not so useful:
http://man7.org/linux/man-pages/man3/resolver.3.html.)
The new code will call res_ninit() once per res_nquery() task. This is
not optimal, but no worse than before — since res_query() was being
called in a worker thread, on Linux, it would implicitly initialise the
thread-local struct __res_state when it was called. We’ve essentially
just made that explicit. In practical terms, this means a
stat("/etc/resolv.conf") call per res_nquery() task.
In future, we could improve this by using an explicit thread pool with
some manually-created worker threads, each of which initialises a struct
__res_state on spawning, and only updates it on receiving
the #GResolver::reload signal.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
https://bugzilla.gnome.org/show_bug.cgi?id=792050
											
										 
											2018-01-05 14:26:35 +00:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  | #endif
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-25 15:56:47 +01:00
										 |  |  |  |   rrtype = g_resolver_record_type_to_rrtype (record_type); | 
					
						
							| 
									
										
										
											
												Add support for MX, TXT, NS and SOA records to GResolver
 * Add resolver functions for looking up DNS records of
   various types. Currently implemented: MX, TXT, SOA, SRV, NS
 * Return records as GVariant tuples.
 * Make the GSrvTarget lookups a wrapper over this new
   functionality.
 * Rework the resolver test so that it has support for
   looking up MX, NS, SOA, TXT records, and uses GOptionContext
https://bugzilla.gnome.org/show_bug.cgi?id=672944
											
										 
											2012-04-04 17:13:10 +02:00
										 |  |  |  |   answer = g_byte_array_new (); | 
					
						
							|  |  |  |  |   for (;;) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       g_byte_array_set_size (answer, len * 2); | 
					
						
							| 
									
										
											  
											
												gio: Port GThreadedResolver to use res_nquery() to fix thread-safety
res_query() uses global state in the form of the struct __res_state
which contains the contents of resolv.conf (and other things). On Linux,
this state seems to be thread-local, so there is no problem. On OS X,
however, it is not, and hence multiple res_query() calls from parallel
threads will compete and return bogus results.
The fix for this is to use res_nquery(), introduced in BIND 8.2, which
takes an explicit state argument. This allows us to manually store the
state thread-locally. If res_nquery() isn’t available, we fall back to
res_query(). It should be available on OS X though. As a data point,
it’s available on Fedora 27.
There’s a slight complication in the fact that OS X requires the state
to be freed using res_ndestroy() rather than res_nclose(). Linux uses
res_nclose().
(See, for example, the NetBSD man page:
https://www.unix.com/man-page/netbsd/3/res_ninit/. The Linux one is
incomplete and not so useful:
http://man7.org/linux/man-pages/man3/resolver.3.html.)
The new code will call res_ninit() once per res_nquery() task. This is
not optimal, but no worse than before — since res_query() was being
called in a worker thread, on Linux, it would implicitly initialise the
thread-local struct __res_state when it was called. We’ve essentially
just made that explicit. In practical terms, this means a
stat("/etc/resolv.conf") call per res_nquery() task.
In future, we could improve this by using an explicit thread pool with
some manually-created worker threads, each of which initialises a struct
__res_state on spawning, and only updates it on receiving
the #GResolver::reload signal.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
https://bugzilla.gnome.org/show_bug.cgi?id=792050
											
										 
											2018-01-05 14:26:35 +00:00
										 |  |  |  | #if defined(HAVE_RES_NQUERY)
 | 
					
						
							| 
									
										
										
										
											2023-04-25 15:56:47 +01:00
										 |  |  |  |       len = res_nquery (&res, rrname, C_IN, rrtype, answer->data, answer->len); | 
					
						
							| 
									
										
											  
											
												gio: Port GThreadedResolver to use res_nquery() to fix thread-safety
res_query() uses global state in the form of the struct __res_state
which contains the contents of resolv.conf (and other things). On Linux,
this state seems to be thread-local, so there is no problem. On OS X,
however, it is not, and hence multiple res_query() calls from parallel
threads will compete and return bogus results.
The fix for this is to use res_nquery(), introduced in BIND 8.2, which
takes an explicit state argument. This allows us to manually store the
state thread-locally. If res_nquery() isn’t available, we fall back to
res_query(). It should be available on OS X though. As a data point,
it’s available on Fedora 27.
There’s a slight complication in the fact that OS X requires the state
to be freed using res_ndestroy() rather than res_nclose(). Linux uses
res_nclose().
(See, for example, the NetBSD man page:
https://www.unix.com/man-page/netbsd/3/res_ninit/. The Linux one is
incomplete and not so useful:
http://man7.org/linux/man-pages/man3/resolver.3.html.)
The new code will call res_ninit() once per res_nquery() task. This is
not optimal, but no worse than before — since res_query() was being
called in a worker thread, on Linux, it would implicitly initialise the
thread-local struct __res_state when it was called. We’ve essentially
just made that explicit. In practical terms, this means a
stat("/etc/resolv.conf") call per res_nquery() task.
In future, we could improve this by using an explicit thread pool with
some manually-created worker threads, each of which initialises a struct
__res_state on spawning, and only updates it on receiving
the #GResolver::reload signal.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
https://bugzilla.gnome.org/show_bug.cgi?id=792050
											
										 
											2018-01-05 14:26:35 +00:00
										 |  |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2023-04-25 15:56:47 +01:00
										 |  |  |  |       len = res_query (rrname, C_IN, rrtype, answer->data, answer->len); | 
					
						
							| 
									
										
											  
											
												gio: Port GThreadedResolver to use res_nquery() to fix thread-safety
res_query() uses global state in the form of the struct __res_state
which contains the contents of resolv.conf (and other things). On Linux,
this state seems to be thread-local, so there is no problem. On OS X,
however, it is not, and hence multiple res_query() calls from parallel
threads will compete and return bogus results.
The fix for this is to use res_nquery(), introduced in BIND 8.2, which
takes an explicit state argument. This allows us to manually store the
state thread-locally. If res_nquery() isn’t available, we fall back to
res_query(). It should be available on OS X though. As a data point,
it’s available on Fedora 27.
There’s a slight complication in the fact that OS X requires the state
to be freed using res_ndestroy() rather than res_nclose(). Linux uses
res_nclose().
(See, for example, the NetBSD man page:
https://www.unix.com/man-page/netbsd/3/res_ninit/. The Linux one is
incomplete and not so useful:
http://man7.org/linux/man-pages/man3/resolver.3.html.)
The new code will call res_ninit() once per res_nquery() task. This is
not optimal, but no worse than before — since res_query() was being
called in a worker thread, on Linux, it would implicitly initialise the
thread-local struct __res_state when it was called. We’ve essentially
just made that explicit. In practical terms, this means a
stat("/etc/resolv.conf") call per res_nquery() task.
In future, we could improve this by using an explicit thread pool with
some manually-created worker threads, each of which initialises a struct
__res_state on spawning, and only updates it on receiving
the #GResolver::reload signal.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
https://bugzilla.gnome.org/show_bug.cgi?id=792050
											
										 
											2018-01-05 14:26:35 +00:00
										 |  |  |  | #endif
 | 
					
						
							| 
									
										
										
											
												Add support for MX, TXT, NS and SOA records to GResolver
 * Add resolver functions for looking up DNS records of
   various types. Currently implemented: MX, TXT, SOA, SRV, NS
 * Return records as GVariant tuples.
 * Make the GSrvTarget lookups a wrapper over this new
   functionality.
 * Rework the resolver test so that it has support for
   looking up MX, NS, SOA, TXT records, and uses GOptionContext
https://bugzilla.gnome.org/show_bug.cgi?id=672944
											
										 
											2012-04-04 17:13:10 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |       /* If answer fit in the buffer then we're done */ | 
					
						
							|  |  |  |  |       if (len < 0 || len < (gint)answer->len) | 
					
						
							|  |  |  |  |         break; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       /*
 | 
					
						
							|  |  |  |  |        * On overflow some res_query's return the length needed, others | 
					
						
							|  |  |  |  |        * return the full length entered. This code works in either case. | 
					
						
							|  |  |  |  |        */ | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  |     } | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   herr = h_errno; | 
					
						
							| 
									
										
										
										
											2023-03-30 13:42:19 +01:00
										 |  |  |  |   records = g_resolver_records_from_res_query (rrname, rrtype, answer->data, len, herr, error); | 
					
						
							| 
									
										
										
											
												Add support for MX, TXT, NS and SOA records to GResolver
 * Add resolver functions for looking up DNS records of
   various types. Currently implemented: MX, TXT, SOA, SRV, NS
 * Return records as GVariant tuples.
 * Make the GSrvTarget lookups a wrapper over this new
   functionality.
 * Rework the resolver test so that it has support for
   looking up MX, NS, SOA, TXT records, and uses GOptionContext
https://bugzilla.gnome.org/show_bug.cgi?id=672944
											
										 
											2012-04-04 17:13:10 +02:00
										 |  |  |  |   g_byte_array_free (answer, TRUE); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-22 19:41:00 +00:00
										 |  |  |  | #ifdef HAVE_RES_NQUERY
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												gio: Port GThreadedResolver to use res_nquery() to fix thread-safety
res_query() uses global state in the form of the struct __res_state
which contains the contents of resolv.conf (and other things). On Linux,
this state seems to be thread-local, so there is no problem. On OS X,
however, it is not, and hence multiple res_query() calls from parallel
threads will compete and return bogus results.
The fix for this is to use res_nquery(), introduced in BIND 8.2, which
takes an explicit state argument. This allows us to manually store the
state thread-locally. If res_nquery() isn’t available, we fall back to
res_query(). It should be available on OS X though. As a data point,
it’s available on Fedora 27.
There’s a slight complication in the fact that OS X requires the state
to be freed using res_ndestroy() rather than res_nclose(). Linux uses
res_nclose().
(See, for example, the NetBSD man page:
https://www.unix.com/man-page/netbsd/3/res_ninit/. The Linux one is
incomplete and not so useful:
http://man7.org/linux/man-pages/man3/resolver.3.html.)
The new code will call res_ninit() once per res_nquery() task. This is
not optimal, but no worse than before — since res_query() was being
called in a worker thread, on Linux, it would implicitly initialise the
thread-local struct __res_state when it was called. We’ve essentially
just made that explicit. In practical terms, this means a
stat("/etc/resolv.conf") call per res_nquery() task.
In future, we could improve this by using an explicit thread pool with
some manually-created worker threads, each of which initialises a struct
__res_state on spawning, and only updates it on receiving
the #GResolver::reload signal.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
https://bugzilla.gnome.org/show_bug.cgi?id=792050
											
										 
											2018-01-05 14:26:35 +00:00
										 |  |  |  | #if defined(HAVE_RES_NDESTROY)
 | 
					
						
							|  |  |  |  |   res_ndestroy (&res); | 
					
						
							|  |  |  |  | #elif defined(HAVE_RES_NCLOSE)
 | 
					
						
							|  |  |  |  |   res_nclose (&res); | 
					
						
							|  |  |  |  | #elif defined(HAVE_RES_NINIT)
 | 
					
						
							| 
									
										
										
										
											2018-05-31 23:44:02 +02:00
										 |  |  |  | #error "Your platform has res_ninit() but not res_nclose() or res_ndestroy(). Please file a bug at https://gitlab.gnome.org/GNOME/glib/issues/new"
 | 
					
						
							| 
									
										
											  
											
												gio: Port GThreadedResolver to use res_nquery() to fix thread-safety
res_query() uses global state in the form of the struct __res_state
which contains the contents of resolv.conf (and other things). On Linux,
this state seems to be thread-local, so there is no problem. On OS X,
however, it is not, and hence multiple res_query() calls from parallel
threads will compete and return bogus results.
The fix for this is to use res_nquery(), introduced in BIND 8.2, which
takes an explicit state argument. This allows us to manually store the
state thread-locally. If res_nquery() isn’t available, we fall back to
res_query(). It should be available on OS X though. As a data point,
it’s available on Fedora 27.
There’s a slight complication in the fact that OS X requires the state
to be freed using res_ndestroy() rather than res_nclose(). Linux uses
res_nclose().
(See, for example, the NetBSD man page:
https://www.unix.com/man-page/netbsd/3/res_ninit/. The Linux one is
incomplete and not so useful:
http://man7.org/linux/man-pages/man3/resolver.3.html.)
The new code will call res_ninit() once per res_nquery() task. This is
not optimal, but no worse than before — since res_query() was being
called in a worker thread, on Linux, it would implicitly initialise the
thread-local struct __res_state when it was called. We’ve essentially
just made that explicit. In practical terms, this means a
stat("/etc/resolv.conf") call per res_nquery() task.
In future, we could improve this by using an explicit thread pool with
some manually-created worker threads, each of which initialises a struct
__res_state on spawning, and only updates it on receiving
the #GResolver::reload signal.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
https://bugzilla.gnome.org/show_bug.cgi?id=792050
											
										 
											2018-01-05 14:26:35 +00:00
										 |  |  |  | #endif
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-22 19:41:00 +00:00
										 |  |  |  | #endif  /* HAVE_RES_NQUERY */
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  | #else
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
											
												Add support for MX, TXT, NS and SOA records to GResolver
 * Add resolver functions for looking up DNS records of
   various types. Currently implemented: MX, TXT, SOA, SRV, NS
 * Return records as GVariant tuples.
 * Make the GSrvTarget lookups a wrapper over this new
   functionality.
 * Rework the resolver test so that it has support for
   looking up MX, NS, SOA, TXT records, and uses GOptionContext
https://bugzilla.gnome.org/show_bug.cgi?id=672944
											
										 
											2012-04-04 17:13:10 +02:00
										 |  |  |  |   DNS_STATUS status; | 
					
						
							| 
									
										
										
										
											2023-10-05 09:21:08 +02:00
										 |  |  |  |   DNS_RECORDA *results = NULL; | 
					
						
							| 
									
										
										
											
												Add support for MX, TXT, NS and SOA records to GResolver
 * Add resolver functions for looking up DNS records of
   various types. Currently implemented: MX, TXT, SOA, SRV, NS
 * Return records as GVariant tuples.
 * Make the GSrvTarget lookups a wrapper over this new
   functionality.
 * Rework the resolver test so that it has support for
   looking up MX, NS, SOA, TXT records, and uses GOptionContext
https://bugzilla.gnome.org/show_bug.cgi?id=672944
											
										 
											2012-04-04 17:13:10 +02:00
										 |  |  |  |   WORD dnstype; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-05 09:21:08 +02:00
										 |  |  |  |   /* Work around differences in Windows SDK and mingw-w64 headers */ | 
					
						
							|  |  |  |  | #ifdef _MSC_VER
 | 
					
						
							|  |  |  |  |   typedef DNS_RECORDW * PDNS_RECORD_UTF8_; | 
					
						
							|  |  |  |  | #else
 | 
					
						
							|  |  |  |  |   typedef DNS_RECORDA * PDNS_RECORD_UTF8_; | 
					
						
							|  |  |  |  | #endif
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-25 15:56:47 +01:00
										 |  |  |  |   dnstype = g_resolver_record_type_to_dnstype (record_type); | 
					
						
							| 
									
										
										
										
											2023-10-05 09:21:08 +02:00
										 |  |  |  |   status = DnsQuery_UTF8 (rrname, dnstype, DNS_QUERY_STANDARD, NULL, (PDNS_RECORD_UTF8_*)&results, NULL); | 
					
						
							| 
									
										
										
										
											2023-03-30 13:42:19 +01:00
										 |  |  |  |   records = g_resolver_records_from_DnsQuery (rrname, dnstype, status, results, error); | 
					
						
							| 
									
										
										
											
												Add support for MX, TXT, NS and SOA records to GResolver
 * Add resolver functions for looking up DNS records of
   various types. Currently implemented: MX, TXT, SOA, SRV, NS
 * Return records as GVariant tuples.
 * Make the GSrvTarget lookups a wrapper over this new
   functionality.
 * Rework the resolver test so that it has support for
   looking up MX, NS, SOA, TXT records, and uses GOptionContext
https://bugzilla.gnome.org/show_bug.cgi?id=672944
											
										 
											2012-04-04 17:13:10 +02:00
										 |  |  |  |   if (results != NULL) | 
					
						
							|  |  |  |  |     DnsRecordListFree (results, DnsFreeRecordList); | 
					
						
							| 
									
										
										
										
											2011-12-29 11:25:07 -05:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-30 13:42:19 +01:00
										 |  |  |  |   return g_steal_pointer (&records); | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static GList * | 
					
						
							| 
									
										
										
											
												Add support for MX, TXT, NS and SOA records to GResolver
 * Add resolver functions for looking up DNS records of
   various types. Currently implemented: MX, TXT, SOA, SRV, NS
 * Return records as GVariant tuples.
 * Make the GSrvTarget lookups a wrapper over this new
   functionality.
 * Rework the resolver test so that it has support for
   looking up MX, NS, SOA, TXT records, and uses GOptionContext
https://bugzilla.gnome.org/show_bug.cgi?id=672944
											
										 
											2012-04-04 17:13:10 +02:00
										 |  |  |  | lookup_records (GResolver              *resolver, | 
					
						
							|  |  |  |  |                 const gchar            *rrname, | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  |                 GResolverRecordType     record_type, | 
					
						
							|  |  |  |  |                 GCancellable           *cancellable, | 
					
						
							|  |  |  |  |                 GError                **error) | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  |   GThreadedResolver *self = G_THREADED_RESOLVER (resolver); | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  |   GTask *task; | 
					
						
							| 
									
										
										
										
											2012-11-09 11:38:08 -05:00
										 |  |  |  |   GList *records; | 
					
						
							| 
									
										
										
										
											2023-04-25 15:56:47 +01:00
										 |  |  |  |   LookupData *data = NULL; | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  |   task = g_task_new (resolver, cancellable, NULL, NULL); | 
					
						
							| 
									
										
										
										
											2016-06-16 19:39:38 -04:00
										 |  |  |  |   g_task_set_source_tag (task, lookup_records); | 
					
						
							| 
									
										
										
										
											2020-06-25 23:36:08 +01:00
										 |  |  |  |   g_task_set_name (task, "[gio] resolver lookup records"); | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-25 15:56:47 +01:00
										 |  |  |  |   data = lookup_data_new_records (rrname, record_type); | 
					
						
							|  |  |  |  |   g_task_set_task_data (task, g_steal_pointer (&data), (GDestroyNotify) lookup_data_free); | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  |   run_task_in_thread_pool_sync (self, task); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-09 11:38:08 -05:00
										 |  |  |  |   records = g_task_propagate_pointer (task, error); | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  |   g_object_unref (task); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-09 11:38:08 -05:00
										 |  |  |  |   return records; | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static void | 
					
						
							| 
									
										
										
											
												Add support for MX, TXT, NS and SOA records to GResolver
 * Add resolver functions for looking up DNS records of
   various types. Currently implemented: MX, TXT, SOA, SRV, NS
 * Return records as GVariant tuples.
 * Make the GSrvTarget lookups a wrapper over this new
   functionality.
 * Rework the resolver test so that it has support for
   looking up MX, NS, SOA, TXT records, and uses GOptionContext
https://bugzilla.gnome.org/show_bug.cgi?id=672944
											
										 
											2012-04-04 17:13:10 +02:00
										 |  |  |  | lookup_records_async (GResolver           *resolver, | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  |                       const char          *rrname, | 
					
						
							| 
									
										
										
											
												Add support for MX, TXT, NS and SOA records to GResolver
 * Add resolver functions for looking up DNS records of
   various types. Currently implemented: MX, TXT, SOA, SRV, NS
 * Return records as GVariant tuples.
 * Make the GSrvTarget lookups a wrapper over this new
   functionality.
 * Rework the resolver test so that it has support for
   looking up MX, NS, SOA, TXT records, and uses GOptionContext
https://bugzilla.gnome.org/show_bug.cgi?id=672944
											
										 
											2012-04-04 17:13:10 +02:00
										 |  |  |  |                       GResolverRecordType  record_type, | 
					
						
							|  |  |  |  |                       GCancellable        *cancellable, | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  |                       GAsyncReadyCallback  callback, | 
					
						
							| 
									
										
										
											
												Add support for MX, TXT, NS and SOA records to GResolver
 * Add resolver functions for looking up DNS records of
   various types. Currently implemented: MX, TXT, SOA, SRV, NS
 * Return records as GVariant tuples.
 * Make the GSrvTarget lookups a wrapper over this new
   functionality.
 * Rework the resolver test so that it has support for
   looking up MX, NS, SOA, TXT records, and uses GOptionContext
https://bugzilla.gnome.org/show_bug.cgi?id=672944
											
										 
											2012-04-04 17:13:10 +02:00
										 |  |  |  |                       gpointer             user_data) | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  |   GThreadedResolver *self = G_THREADED_RESOLVER (resolver); | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  |   GTask *task; | 
					
						
							| 
									
										
										
										
											2023-04-25 15:56:47 +01:00
										 |  |  |  |   LookupData *data = NULL; | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   task = g_task_new (resolver, cancellable, callback, user_data); | 
					
						
							| 
									
										
										
										
											2016-06-16 19:39:38 -04:00
										 |  |  |  |   g_task_set_source_tag (task, lookup_records_async); | 
					
						
							| 
									
										
										
										
											2020-06-25 23:36:08 +01:00
										 |  |  |  |   g_task_set_name (task, "[gio] resolver lookup records"); | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-25 15:56:47 +01:00
										 |  |  |  |   data = lookup_data_new_records (rrname, record_type); | 
					
						
							|  |  |  |  |   g_task_set_task_data (task, g_steal_pointer (&data), (GDestroyNotify) lookup_data_free); | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  |   run_task_in_thread_pool_async (self, task); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  |   g_object_unref (task); | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static GList * | 
					
						
							| 
									
										
										
											
												Add support for MX, TXT, NS and SOA records to GResolver
 * Add resolver functions for looking up DNS records of
   various types. Currently implemented: MX, TXT, SOA, SRV, NS
 * Return records as GVariant tuples.
 * Make the GSrvTarget lookups a wrapper over this new
   functionality.
 * Rework the resolver test so that it has support for
   looking up MX, NS, SOA, TXT records, and uses GOptionContext
https://bugzilla.gnome.org/show_bug.cgi?id=672944
											
										 
											2012-04-04 17:13:10 +02:00
										 |  |  |  | lookup_records_finish (GResolver     *resolver, | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  |                        GAsyncResult  *result, | 
					
						
							| 
									
										
										
											
												Add support for MX, TXT, NS and SOA records to GResolver
 * Add resolver functions for looking up DNS records of
   various types. Currently implemented: MX, TXT, SOA, SRV, NS
 * Return records as GVariant tuples.
 * Make the GSrvTarget lookups a wrapper over this new
   functionality.
 * Rework the resolver test so that it has support for
   looking up MX, NS, SOA, TXT records, and uses GOptionContext
https://bugzilla.gnome.org/show_bug.cgi?id=672944
											
										 
											2012-04-04 17:13:10 +02:00
										 |  |  |  |                        GError       **error) | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  |   g_return_val_if_fail (g_task_is_valid (result, resolver), NULL); | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-11 14:57:35 -04:00
										 |  |  |  |   return g_task_propagate_pointer (G_TASK (result), error); | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-25 17:26:28 +01:00
										 |  |  |  | /* Will be called in the GLib worker thread, so must lock all accesses to shared
 | 
					
						
							|  |  |  |  |  * data. */ | 
					
						
							|  |  |  |  | static gboolean | 
					
						
							|  |  |  |  | timeout_cb (gpointer user_data) | 
					
						
							|  |  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-09-11 16:02:15 +01:00
										 |  |  |  |   GWeakRef *weak_task = user_data; | 
					
						
							|  |  |  |  |   GTask *task = NULL;  /* (owned) */ | 
					
						
							|  |  |  |  |   LookupData *data; | 
					
						
							| 
									
										
										
										
											2023-04-25 17:26:28 +01:00
										 |  |  |  |   gboolean should_return; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-11 16:02:15 +01:00
										 |  |  |  |   task = g_weak_ref_get (weak_task); | 
					
						
							|  |  |  |  |   if (task == NULL) | 
					
						
							|  |  |  |  |     return G_SOURCE_REMOVE; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   data = g_task_get_task_data (task); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-25 17:26:28 +01:00
										 |  |  |  |   g_mutex_lock (&data->lock); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   should_return = g_atomic_int_compare_and_exchange (&data->will_return, NOT_YET, TIMED_OUT); | 
					
						
							|  |  |  |  |   g_clear_pointer (&data->timeout_source, g_source_unref); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   g_mutex_unlock (&data->lock); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   if (should_return) | 
					
						
							| 
									
										
										
										
											2023-12-19 21:03:28 +01:00
										 |  |  |  |     { | 
					
						
							|  |  |  |  |       g_task_return_new_error_literal (task, G_IO_ERROR, G_IO_ERROR_TIMED_OUT, | 
					
						
							|  |  |  |  |                                        _("Socket I/O timed out")); | 
					
						
							|  |  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-04-25 17:26:28 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   /* Signal completion of the task. */ | 
					
						
							|  |  |  |  |   g_mutex_lock (&data->lock); | 
					
						
							|  |  |  |  |   data->has_returned = TRUE; | 
					
						
							|  |  |  |  |   g_cond_broadcast (&data->cond); | 
					
						
							|  |  |  |  |   g_mutex_unlock (&data->lock); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-11 16:02:15 +01:00
										 |  |  |  |   g_object_unref (task); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-25 17:26:28 +01:00
										 |  |  |  |   return G_SOURCE_REMOVE; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* Will be called in the GLib worker thread, so must lock all accesses to shared
 | 
					
						
							|  |  |  |  |  * data. */ | 
					
						
							|  |  |  |  | static gboolean | 
					
						
							|  |  |  |  | cancelled_cb (GCancellable *cancellable, | 
					
						
							|  |  |  |  |               gpointer      user_data) | 
					
						
							|  |  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-09-11 16:02:15 +01:00
										 |  |  |  |   GWeakRef *weak_task = user_data; | 
					
						
							|  |  |  |  |   GTask *task = NULL;  /* (owned) */ | 
					
						
							|  |  |  |  |   LookupData *data; | 
					
						
							| 
									
										
										
										
											2023-04-25 17:26:28 +01:00
										 |  |  |  |   gboolean should_return; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-11 16:02:15 +01:00
										 |  |  |  |   task = g_weak_ref_get (weak_task); | 
					
						
							|  |  |  |  |   if (task == NULL) | 
					
						
							|  |  |  |  |     return G_SOURCE_REMOVE; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   data = g_task_get_task_data (task); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-25 17:26:28 +01:00
										 |  |  |  |   g_mutex_lock (&data->lock); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   g_assert (g_cancellable_is_cancelled (cancellable)); | 
					
						
							|  |  |  |  |   should_return = g_atomic_int_compare_and_exchange (&data->will_return, NOT_YET, CANCELLED); | 
					
						
							|  |  |  |  |   g_clear_pointer (&data->cancellable_source, g_source_unref); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   g_mutex_unlock (&data->lock); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   if (should_return) | 
					
						
							|  |  |  |  |     g_task_return_error_if_cancelled (task); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   /* Signal completion of the task. */ | 
					
						
							|  |  |  |  |   g_mutex_lock (&data->lock); | 
					
						
							|  |  |  |  |   data->has_returned = TRUE; | 
					
						
							|  |  |  |  |   g_cond_broadcast (&data->cond); | 
					
						
							|  |  |  |  |   g_mutex_unlock (&data->lock); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-11 16:02:15 +01:00
										 |  |  |  |   g_object_unref (task); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-25 17:26:28 +01:00
										 |  |  |  |   return G_SOURCE_REMOVE; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-11 16:02:15 +01:00
										 |  |  |  | static void | 
					
						
							|  |  |  |  | weak_ref_clear_and_free (GWeakRef *weak_ref) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   g_weak_ref_clear (weak_ref); | 
					
						
							|  |  |  |  |   g_free (weak_ref); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-30 13:42:19 +01:00
										 |  |  |  | static void | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  | run_task_in_thread_pool_async (GThreadedResolver *self, | 
					
						
							|  |  |  |  |                                GTask             *task) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   LookupData *data = g_task_get_task_data (task); | 
					
						
							| 
									
										
										
										
											2023-04-25 17:26:28 +01:00
										 |  |  |  |   guint timeout_ms = g_resolver_get_timeout (G_RESOLVER (self)); | 
					
						
							|  |  |  |  |   GCancellable *cancellable = g_task_get_cancellable (task); | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   g_mutex_lock (&data->lock); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   g_thread_pool_push (self->thread_pool, g_object_ref (task), NULL); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-25 17:26:28 +01:00
										 |  |  |  |   if (timeout_ms != 0) | 
					
						
							|  |  |  |  |     { | 
					
						
							| 
									
										
										
										
											2023-09-11 16:02:15 +01:00
										 |  |  |  |       GWeakRef *weak_task = g_new0 (GWeakRef, 1); | 
					
						
							|  |  |  |  |       g_weak_ref_set (weak_task, task); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-25 17:26:28 +01:00
										 |  |  |  |       data->timeout_source = g_timeout_source_new (timeout_ms); | 
					
						
							|  |  |  |  |       g_source_set_static_name (data->timeout_source, "[gio] threaded resolver timeout"); | 
					
						
							| 
									
										
										
										
											2023-09-11 16:02:15 +01:00
										 |  |  |  |       g_source_set_callback (data->timeout_source, G_SOURCE_FUNC (timeout_cb), g_steal_pointer (&weak_task), (GDestroyNotify) weak_ref_clear_and_free); | 
					
						
							| 
									
										
										
										
											2023-04-25 17:26:28 +01:00
										 |  |  |  |       g_source_attach (data->timeout_source, GLIB_PRIVATE_CALL (g_get_worker_context) ()); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   if (cancellable != NULL) | 
					
						
							|  |  |  |  |     { | 
					
						
							| 
									
										
										
										
											2023-09-11 16:02:15 +01:00
										 |  |  |  |       GWeakRef *weak_task = g_new0 (GWeakRef, 1); | 
					
						
							|  |  |  |  |       g_weak_ref_set (weak_task, task); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-25 17:26:28 +01:00
										 |  |  |  |       data->cancellable_source = g_cancellable_source_new (cancellable); | 
					
						
							|  |  |  |  |       g_source_set_static_name (data->cancellable_source, "[gio] threaded resolver cancellable"); | 
					
						
							| 
									
										
										
										
											2023-09-11 16:02:15 +01:00
										 |  |  |  |       g_source_set_callback (data->cancellable_source, G_SOURCE_FUNC (cancelled_cb), g_steal_pointer (&weak_task), (GDestroyNotify) weak_ref_clear_and_free); | 
					
						
							| 
									
										
										
										
											2023-04-25 17:26:28 +01:00
										 |  |  |  |       g_source_attach (data->cancellable_source, GLIB_PRIVATE_CALL (g_get_worker_context) ()); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  |   g_mutex_unlock (&data->lock); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static void | 
					
						
							|  |  |  |  | run_task_in_thread_pool_sync (GThreadedResolver *self, | 
					
						
							|  |  |  |  |                               GTask             *task) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   LookupData *data = g_task_get_task_data (task); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   run_task_in_thread_pool_async (self, task); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   g_mutex_lock (&data->lock); | 
					
						
							|  |  |  |  |   while (!data->has_returned) | 
					
						
							|  |  |  |  |     g_cond_wait (&data->cond, &data->lock); | 
					
						
							|  |  |  |  |   g_mutex_unlock (&data->lock); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static void | 
					
						
							|  |  |  |  | threaded_resolver_worker_cb (gpointer task_data, | 
					
						
							|  |  |  |  |                              gpointer user_data) | 
					
						
							| 
									
										
										
										
											2023-03-30 13:42:19 +01:00
										 |  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  |   GTask *task = G_TASK (g_steal_pointer (&task_data)); | 
					
						
							|  |  |  |  |   LookupData *data = g_task_get_task_data (task); | 
					
						
							|  |  |  |  |   GCancellable *cancellable = g_task_get_cancellable (task); | 
					
						
							| 
									
										
										
										
											2025-03-24 11:01:54 -05:00
										 |  |  |  |   GThreadedResolver *resolver = G_THREADED_RESOLVER (user_data); | 
					
						
							| 
									
										
										
										
											2023-03-30 13:42:19 +01:00
										 |  |  |  |   GError *local_error = NULL; | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  |   gboolean should_return; | 
					
						
							| 
									
										
										
										
											2023-03-30 13:42:19 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   switch (data->lookup_type) { | 
					
						
							|  |  |  |  |   case LOOKUP_BY_NAME: | 
					
						
							|  |  |  |  |     { | 
					
						
							| 
									
										
										
										
											2025-03-24 11:01:54 -05:00
										 |  |  |  |       GList *addresses = do_lookup_by_name (resolver, | 
					
						
							|  |  |  |  |                                             data->lookup_by_name.hostname, | 
					
						
							| 
									
										
										
										
											2023-03-30 13:42:19 +01:00
										 |  |  |  |                                             data->lookup_by_name.address_family, | 
					
						
							|  |  |  |  |                                             cancellable, | 
					
						
							|  |  |  |  |                                             &local_error); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  |       g_mutex_lock (&data->lock); | 
					
						
							|  |  |  |  |       should_return = g_atomic_int_compare_and_exchange (&data->will_return, NOT_YET, COMPLETED); | 
					
						
							|  |  |  |  |       g_mutex_unlock (&data->lock); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       if (should_return) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |           if (addresses != NULL) | 
					
						
							|  |  |  |  |             g_task_return_pointer (task, g_steal_pointer (&addresses), (GDestroyNotify) g_resolver_free_addresses); | 
					
						
							|  |  |  |  |           else | 
					
						
							|  |  |  |  |             g_task_return_error (task, g_steal_pointer (&local_error)); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       g_clear_pointer (&addresses, g_resolver_free_addresses); | 
					
						
							| 
									
										
										
										
											2024-01-30 09:53:00 +00:00
										 |  |  |  |       g_clear_error (&local_error); | 
					
						
							| 
									
										
										
										
											2023-03-30 13:42:19 +01:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  |     break; | 
					
						
							|  |  |  |  |   case LOOKUP_BY_ADDRESS: | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       gchar *name = do_lookup_by_address (data->lookup_by_address.address, | 
					
						
							|  |  |  |  |                                           cancellable, | 
					
						
							|  |  |  |  |                                           &local_error); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  |       g_mutex_lock (&data->lock); | 
					
						
							|  |  |  |  |       should_return = g_atomic_int_compare_and_exchange (&data->will_return, NOT_YET, COMPLETED); | 
					
						
							|  |  |  |  |       g_mutex_unlock (&data->lock); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       if (should_return) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |           if (name != NULL) | 
					
						
							|  |  |  |  |             g_task_return_pointer (task, g_steal_pointer (&name), g_free); | 
					
						
							|  |  |  |  |           else | 
					
						
							|  |  |  |  |             g_task_return_error (task, g_steal_pointer (&local_error)); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       g_clear_pointer (&name, g_free); | 
					
						
							| 
									
										
										
										
											2024-01-30 09:53:00 +00:00
										 |  |  |  |       g_clear_error (&local_error); | 
					
						
							| 
									
										
										
										
											2023-03-30 13:42:19 +01:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  |     break; | 
					
						
							|  |  |  |  |   case LOOKUP_RECORDS: | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       GList *records = do_lookup_records (data->lookup_records.rrname, | 
					
						
							|  |  |  |  |                                           data->lookup_records.record_type, | 
					
						
							|  |  |  |  |                                           cancellable, | 
					
						
							|  |  |  |  |                                           &local_error); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  |       g_mutex_lock (&data->lock); | 
					
						
							|  |  |  |  |       should_return = g_atomic_int_compare_and_exchange (&data->will_return, NOT_YET, COMPLETED); | 
					
						
							|  |  |  |  |       g_mutex_unlock (&data->lock); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       if (should_return) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |           if (records != NULL) | 
					
						
							|  |  |  |  |             g_task_return_pointer (task, g_steal_pointer (&records), (GDestroyNotify) free_records); | 
					
						
							|  |  |  |  |           else | 
					
						
							|  |  |  |  |             g_task_return_error (task, g_steal_pointer (&local_error)); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       g_clear_pointer (&records, free_records); | 
					
						
							| 
									
										
										
										
											2024-01-30 09:53:00 +00:00
										 |  |  |  |       g_clear_error (&local_error); | 
					
						
							| 
									
										
										
										
											2023-03-30 13:42:19 +01:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  |     break; | 
					
						
							|  |  |  |  |   default: | 
					
						
							|  |  |  |  |     g_assert_not_reached (); | 
					
						
							|  |  |  |  |   } | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   /* Signal completion of a task. */ | 
					
						
							|  |  |  |  |   g_mutex_lock (&data->lock); | 
					
						
							|  |  |  |  |   data->has_returned = TRUE; | 
					
						
							|  |  |  |  |   g_cond_broadcast (&data->cond); | 
					
						
							|  |  |  |  |   g_mutex_unlock (&data->lock); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   g_object_unref (task); | 
					
						
							| 
									
										
										
										
											2023-03-30 13:42:19 +01:00
										 |  |  |  | } | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | static void | 
					
						
							|  |  |  |  | g_threaded_resolver_class_init (GThreadedResolverClass *threaded_class) | 
					
						
							|  |  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  |   GObjectClass *object_class = G_OBJECT_CLASS (threaded_class); | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  |   GResolverClass *resolver_class = G_RESOLVER_CLASS (threaded_class); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-25 15:58:46 +01:00
										 |  |  |  |   object_class->finalize = g_threaded_resolver_finalize; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-17 11:14:10 -04:00
										 |  |  |  |   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; | 
					
						
							| 
									
										
										
										
											2008-12-29 12:53:47 -05:00
										 |  |  |  | } |