Coverage Report

Created: 2025-12-08 06:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/rauc/subprojects/glib-2.76.5/gio/gresolver.c
Line
Count
Source
1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3
/* GIO - GLib Input, Output and Streaming Library
4
 *
5
 * Copyright (C) 2008 Red Hat, Inc.
6
 * Copyright (C) 2018 Igalia S.L.
7
 *
8
 * SPDX-License-Identifier: LGPL-2.1-or-later
9
 *
10
 * This library is free software; you can redistribute it and/or
11
 * modify it under the terms of the GNU Lesser General Public
12
 * License as published by the Free Software Foundation; either
13
 * version 2.1 of the License, or (at your option) any later version.
14
 *
15
 * This library is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18
 * Lesser General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU Lesser General
21
 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
22
 */
23
24
#include "config.h"
25
#include <glib.h>
26
#include "glibintl.h"
27
28
#include "gresolver.h"
29
#include "gnetworkingprivate.h"
30
#include "gasyncresult.h"
31
#include "ginetaddress.h"
32
#include "gtask.h"
33
#include "gsrvtarget.h"
34
#include "gthreadedresolver.h"
35
#include "gioerror.h"
36
#include "gcancellable.h"
37
38
#ifdef G_OS_UNIX
39
#include <sys/stat.h>
40
#endif
41
42
#include <stdlib.h>
43
44
45
/**
46
 * SECTION:gresolver
47
 * @short_description: Asynchronous and cancellable DNS resolver
48
 * @include: gio/gio.h
49
 *
50
 * #GResolver provides cancellable synchronous and asynchronous DNS
51
 * resolution, for hostnames (g_resolver_lookup_by_address(),
52
 * g_resolver_lookup_by_name() and their async variants) and SRV
53
 * (service) records (g_resolver_lookup_service()).
54
 *
55
 * #GNetworkAddress and #GNetworkService provide wrappers around
56
 * #GResolver functionality that also implement #GSocketConnectable,
57
 * making it easy to connect to a remote host/service.
58
 */
59
60
enum {
61
  RELOAD,
62
  LAST_SIGNAL
63
};
64
65
static guint signals[LAST_SIGNAL] = { 0 };
66
67
struct _GResolverPrivate {
68
#ifdef G_OS_UNIX
69
  GMutex mutex;
70
  time_t resolv_conf_timestamp;  /* protected by @mutex */
71
#else
72
  int dummy;
73
#endif
74
};
75
76
/**
77
 * GResolver:
78
 *
79
 * The object that handles DNS resolution. Use g_resolver_get_default()
80
 * to get the default resolver.
81
 *
82
 * This is an abstract type; subclasses of it implement different resolvers for
83
 * different platforms and situations.
84
 */
85
0
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GResolver, g_resolver, G_TYPE_OBJECT,
86
0
                                  G_ADD_PRIVATE (GResolver)
87
0
                                  g_networking_init ();)
88
0
89
0
static GList *
90
0
srv_records_to_targets (GList *records)
91
0
{
92
0
  const gchar *hostname;
93
0
  guint16 port, priority, weight;
94
0
  GSrvTarget *target;
95
0
  GList *l;
96
97
0
  for (l = records; l != NULL; l = g_list_next (l))
98
0
    {
99
0
      g_variant_get (l->data, "(qqq&s)", &priority, &weight, &port, &hostname);
100
0
      target = g_srv_target_new (hostname, port, priority, weight);
101
0
      g_variant_unref (l->data);
102
0
      l->data = target;
103
0
    }
104
105
0
  return g_srv_target_list_sort (records);
106
0
}
107
108
static GList *
109
g_resolver_real_lookup_service (GResolver            *resolver,
110
                                const gchar          *rrname,
111
                                GCancellable         *cancellable,
112
                                GError              **error)
113
0
{
114
0
  GList *records;
115
116
0
  records = G_RESOLVER_GET_CLASS (resolver)->lookup_records (resolver,
117
0
                                                             rrname,
118
0
                                                             G_RESOLVER_RECORD_SRV,
119
0
                                                             cancellable,
120
0
                                                             error);
121
122
0
  return srv_records_to_targets (records);
123
0
}
124
125
static void
126
g_resolver_real_lookup_service_async (GResolver            *resolver,
127
                                      const gchar          *rrname,
128
                                      GCancellable         *cancellable,
129
                                      GAsyncReadyCallback   callback,
130
                                      gpointer              user_data)
131
0
{
132
0
  G_RESOLVER_GET_CLASS (resolver)->lookup_records_async (resolver,
133
0
                                                         rrname,
134
0
                                                         G_RESOLVER_RECORD_SRV,
135
0
                                                         cancellable,
136
0
                                                         callback,
137
0
                                                         user_data);
138
0
}
139
140
static GList *
141
g_resolver_real_lookup_service_finish (GResolver            *resolver,
142
                                       GAsyncResult         *result,
143
                                       GError              **error)
144
0
{
145
0
  GList *records;
146
147
0
  records = G_RESOLVER_GET_CLASS (resolver)->lookup_records_finish (resolver,
148
0
                                                                    result,
149
0
                                                                    error);
150
151
0
  return srv_records_to_targets (records);
152
0
}
153
154
static void
155
g_resolver_finalize (GObject *object)
156
0
{
157
0
#ifdef G_OS_UNIX
158
0
  GResolver *resolver = G_RESOLVER (object);
159
160
0
  g_mutex_clear (&resolver->priv->mutex);
161
0
#endif
162
163
0
  G_OBJECT_CLASS (g_resolver_parent_class)->finalize (object);
164
0
}
165
166
static void
167
g_resolver_class_init (GResolverClass *resolver_class)
168
0
{
169
0
  GObjectClass *object_class = G_OBJECT_CLASS (resolver_class);
170
171
0
  object_class->finalize = g_resolver_finalize;
172
173
  /* Automatically pass these over to the lookup_records methods */
174
0
  resolver_class->lookup_service = g_resolver_real_lookup_service;
175
0
  resolver_class->lookup_service_async = g_resolver_real_lookup_service_async;
176
0
  resolver_class->lookup_service_finish = g_resolver_real_lookup_service_finish;
177
178
  /**
179
   * GResolver::reload:
180
   * @resolver: a #GResolver
181
   *
182
   * Emitted when the resolver notices that the system resolver
183
   * configuration has changed.
184
   **/
185
0
  signals[RELOAD] =
186
0
    g_signal_new (I_("reload"),
187
0
      G_TYPE_RESOLVER,
188
0
      G_SIGNAL_RUN_LAST,
189
0
      G_STRUCT_OFFSET (GResolverClass, reload),
190
0
      NULL, NULL,
191
0
      NULL,
192
0
      G_TYPE_NONE, 0);
193
0
}
194
195
static void
196
g_resolver_init (GResolver *resolver)
197
0
{
198
0
#ifdef G_OS_UNIX
199
0
  struct stat st;
200
0
#endif
201
202
0
  resolver->priv = g_resolver_get_instance_private (resolver);
203
204
0
#ifdef G_OS_UNIX
205
0
  if (stat (_PATH_RESCONF, &st) == 0)
206
0
    resolver->priv->resolv_conf_timestamp = st.st_mtime;
207
208
0
  g_mutex_init (&resolver->priv->mutex);
209
0
#endif
210
0
}
211
212
G_LOCK_DEFINE_STATIC (default_resolver);
213
static GResolver *default_resolver;
214
215
/**
216
 * g_resolver_get_default:
217
 *
218
 * Gets the default #GResolver. You should unref it when you are done
219
 * with it. #GResolver may use its reference count as a hint about how
220
 * many threads it should allocate for concurrent DNS resolutions.
221
 *
222
 * Returns: (transfer full): the default #GResolver.
223
 *
224
 * Since: 2.22
225
 */
226
GResolver *
227
g_resolver_get_default (void)
228
0
{
229
0
  GResolver *ret;
230
231
0
  G_LOCK (default_resolver);
232
0
  if (!default_resolver)
233
0
    default_resolver = g_object_new (G_TYPE_THREADED_RESOLVER, NULL);
234
0
  ret = g_object_ref (default_resolver);
235
0
  G_UNLOCK (default_resolver);
236
237
0
  return ret;
238
0
}
239
240
/**
241
 * g_resolver_set_default:
242
 * @resolver: the new default #GResolver
243
 *
244
 * Sets @resolver to be the application's default resolver (reffing
245
 * @resolver, and unreffing the previous default resolver, if any).
246
 * Future calls to g_resolver_get_default() will return this resolver.
247
 *
248
 * This can be used if an application wants to perform any sort of DNS
249
 * caching or "pinning"; it can implement its own #GResolver that
250
 * calls the original default resolver for DNS operations, and
251
 * implements its own cache policies on top of that, and then set
252
 * itself as the default resolver for all later code to use.
253
 *
254
 * Since: 2.22
255
 */
256
void
257
g_resolver_set_default (GResolver *resolver)
258
0
{
259
0
  G_LOCK (default_resolver);
260
0
  if (default_resolver)
261
0
    g_object_unref (default_resolver);
262
0
  default_resolver = g_object_ref (resolver);
263
0
  G_UNLOCK (default_resolver);
264
0
}
265
266
static void
267
maybe_emit_reload (GResolver *resolver)
268
0
{
269
0
#ifdef G_OS_UNIX
270
0
  struct stat st;
271
272
0
  if (stat (_PATH_RESCONF, &st) == 0)
273
0
    {
274
0
      g_mutex_lock (&resolver->priv->mutex);
275
0
      if (st.st_mtime != resolver->priv->resolv_conf_timestamp)
276
0
        {
277
0
          resolver->priv->resolv_conf_timestamp = st.st_mtime;
278
0
          g_mutex_unlock (&resolver->priv->mutex);
279
0
          g_signal_emit (resolver, signals[RELOAD], 0);
280
0
        }
281
0
      else
282
0
        g_mutex_unlock (&resolver->priv->mutex);
283
0
    }
284
0
#endif
285
0
}
286
287
/* filter out duplicates, cf. https://bugzilla.gnome.org/show_bug.cgi?id=631379 */
288
static void
289
remove_duplicates (GList *addrs)
290
0
{
291
0
  GList *l;
292
0
  GList *ll;
293
0
  GList *lll;
294
295
  /* TODO: if this is too slow (it's O(n^2) but n is typically really
296
   * small), we can do something more clever but note that we must not
297
   * change the order of elements...
298
   */
299
0
  for (l = addrs; l != NULL; l = l->next)
300
0
    {
301
0
      GInetAddress *address = G_INET_ADDRESS (l->data);
302
0
      for (ll = l->next; ll != NULL; ll = lll)
303
0
        {
304
0
          GInetAddress *other_address = G_INET_ADDRESS (ll->data);
305
0
          lll = ll->next;
306
0
          if (g_inet_address_equal (address, other_address))
307
0
            {
308
0
              g_object_unref (other_address);
309
              /* we never return the first element */
310
0
              g_warn_if_fail (g_list_delete_link (addrs, ll) == addrs);
311
0
            }
312
0
        }
313
0
    }
314
0
}
315
316
static gboolean
317
hostname_is_localhost (const char *hostname)
318
0
{
319
0
  size_t len = strlen (hostname);
320
0
  const char *p;
321
322
  /* Match "localhost", "localhost.", "*.localhost" and "*.localhost." */
323
0
  if (len < strlen ("localhost"))
324
0
    return FALSE;
325
326
0
  if (hostname[len - 1] == '.')
327
0
      len--;
328
329
  /* Scan backwards in @hostname to find the right-most dot (excluding the final dot, if it exists, as it was chopped off above).
330
   * We can’t use strrchr() because because we need to operate with string lengths.
331
   * End with @p pointing to the character after the right-most dot. */
332
0
  p = hostname + len - 1;
333
0
  while (p >= hostname)
334
0
    {
335
0
      if (*p == '.')
336
0
       {
337
0
         p++;
338
0
         break;
339
0
       }
340
0
      else if (p == hostname)
341
0
        break;
342
0
      p--;
343
0
    }
344
345
0
  len -= p - hostname;
346
347
0
  return g_ascii_strncasecmp (p, "localhost", MAX (len, strlen ("localhost"))) == 0;
348
0
}
349
350
/* Note that this does not follow the "FALSE means @error is set"
351
 * convention. The return value tells the caller whether it should
352
 * return @addrs and @error to the caller right away, or if it should
353
 * continue and trying to resolve the name as a hostname.
354
 */
355
static gboolean
356
handle_ip_address_or_localhost (const char                *hostname,
357
                                GList                    **addrs,
358
                                GResolverNameLookupFlags   flags,
359
                                GError                   **error)
360
0
{
361
0
  GInetAddress *addr;
362
363
0
#ifndef G_OS_WIN32
364
0
  struct in_addr ip4addr;
365
0
#endif
366
367
0
  addr = g_inet_address_new_from_string (hostname);
368
0
  if (addr)
369
0
    {
370
0
      *addrs = g_list_append (NULL, addr);
371
0
      return TRUE;
372
0
    }
373
374
0
  *addrs = NULL;
375
376
#ifdef G_OS_WIN32
377
378
  /* Reject IPv6 addresses that have brackets ('[' or ']') and/or port numbers,
379
   * as no valid addresses should contain these at this point.
380
   * Non-standard IPv4 addresses would be rejected during the call to
381
   * getaddrinfo() later.
382
   */
383
  if (strrchr (hostname, '[') != NULL ||
384
      strrchr (hostname, ']') != NULL)
385
#else
386
387
  /* Reject non-standard IPv4 numbers-and-dots addresses.
388
   * g_inet_address_new_from_string() will have accepted any "real" IP
389
   * address, so if inet_aton() succeeds, then it's an address we want
390
   * to reject.
391
   */
392
0
  if (inet_aton (hostname, &ip4addr))
393
0
#endif
394
0
    {
395
#ifdef G_OS_WIN32
396
      gchar *error_message = g_win32_error_message (WSAHOST_NOT_FOUND);
397
#else
398
0
      gchar *error_message = g_locale_to_utf8 (gai_strerror (EAI_NONAME), -1, NULL, NULL, NULL);
399
0
      if (error_message == NULL)
400
0
        error_message = g_strdup ("[Invalid UTF-8]");
401
0
#endif
402
0
      g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND,
403
0
                   _("Error resolving “%s”: %s"),
404
0
                   hostname, error_message);
405
0
      g_free (error_message);
406
407
0
      return TRUE;
408
0
    }
409
410
  /* Always resolve localhost to a loopback address so it can be reliably considered secure.
411
     This behavior is being adopted by browsers:
412
     - https://w3c.github.io/webappsec-secure-contexts/
413
     - https://groups.google.com/a/chromium.org/forum/#!msg/blink-dev/RC9dSw-O3fE/E3_0XaT0BAAJ
414
     - https://chromium.googlesource.com/chromium/src.git/+/8da2a80724a9b896890602ff77ef2216cb951399
415
     - https://bugs.webkit.org/show_bug.cgi?id=171934
416
     - https://tools.ietf.org/html/draft-west-let-localhost-be-localhost-06
417
  */
418
0
  if (hostname_is_localhost (hostname))
419
0
    {
420
0
      if (flags & G_RESOLVER_NAME_LOOKUP_FLAGS_IPV6_ONLY)
421
0
        *addrs = g_list_append (*addrs, g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV6)); 
422
0
      if (flags & G_RESOLVER_NAME_LOOKUP_FLAGS_IPV4_ONLY)
423
0
        *addrs = g_list_append (*addrs, g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV4));
424
0
      if (*addrs == NULL)
425
0
        {
426
0
          *addrs = g_list_append (*addrs, g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV6));
427
0
          *addrs = g_list_append (*addrs, g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV4));
428
0
        }
429
0
      return TRUE;
430
0
    }
431
432
0
  return FALSE;
433
0
}
434
435
static GList *
436
lookup_by_name_real (GResolver                 *resolver,
437
                     const gchar               *hostname,
438
                     GResolverNameLookupFlags   flags,
439
                     GCancellable              *cancellable,
440
                     GError                    **error)
441
0
{
442
0
  GList *addrs;
443
0
  gchar *ascii_hostname = NULL;
444
445
0
  g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
446
0
  g_return_val_if_fail (hostname != NULL, NULL);
447
0
  g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
448
0
  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
449
450
  /* Check if @hostname is just an IP address */
451
0
  if (handle_ip_address_or_localhost (hostname, &addrs, flags, error))
452
0
    return addrs;
453
454
0
  if (g_hostname_is_non_ascii (hostname))
455
0
    hostname = ascii_hostname = g_hostname_to_ascii (hostname);
456
457
0
  if (!hostname)
458
0
    {
459
0
      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
460
0
                           _("Invalid hostname"));
461
0
      return NULL;
462
0
    }
463
464
0
  maybe_emit_reload (resolver);
465
466
0
  if (flags != G_RESOLVER_NAME_LOOKUP_FLAGS_DEFAULT)
467
0
    {
468
0
      if (!G_RESOLVER_GET_CLASS (resolver)->lookup_by_name_with_flags)
469
0
        {
470
0
          g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
471
                       /* Translators: The placeholder is for a function name. */
472
0
                       _("%s not implemented"), "lookup_by_name_with_flags");
473
0
          g_free (ascii_hostname);
474
0
          return NULL;
475
0
        }
476
0
      addrs = G_RESOLVER_GET_CLASS (resolver)->
477
0
        lookup_by_name_with_flags (resolver, hostname, flags, cancellable, error);
478
0
    }
479
0
  else
480
0
    addrs = G_RESOLVER_GET_CLASS (resolver)->
481
0
      lookup_by_name (resolver, hostname, cancellable, error);
482
483
0
  remove_duplicates (addrs);
484
485
0
  g_free (ascii_hostname);
486
0
  return addrs;
487
0
}
488
489
/**
490
 * g_resolver_lookup_by_name:
491
 * @resolver: a #GResolver
492
 * @hostname: the hostname to look up
493
 * @cancellable: (nullable): a #GCancellable, or %NULL
494
 * @error: return location for a #GError, or %NULL
495
 *
496
 * Synchronously resolves @hostname to determine its associated IP
497
 * address(es). @hostname may be an ASCII-only or UTF-8 hostname, or
498
 * the textual form of an IP address (in which case this just becomes
499
 * a wrapper around g_inet_address_new_from_string()).
500
 *
501
 * On success, g_resolver_lookup_by_name() will return a non-empty #GList of
502
 * #GInetAddress, sorted in order of preference and guaranteed to not
503
 * contain duplicates. That is, if using the result to connect to
504
 * @hostname, you should attempt to connect to the first address
505
 * first, then the second if the first fails, etc. If you are using
506
 * the result to listen on a socket, it is appropriate to add each
507
 * result using e.g. g_socket_listener_add_address().
508
 *
509
 * If the DNS resolution fails, @error (if non-%NULL) will be set to a
510
 * value from #GResolverError and %NULL will be returned.
511
 *
512
 * If @cancellable is non-%NULL, it can be used to cancel the
513
 * operation, in which case @error (if non-%NULL) will be set to
514
 * %G_IO_ERROR_CANCELLED.
515
 *
516
 * If you are planning to connect to a socket on the resolved IP
517
 * address, it may be easier to create a #GNetworkAddress and use its
518
 * #GSocketConnectable interface.
519
 *
520
 * Returns: (element-type GInetAddress) (transfer full): a non-empty #GList
521
 * of #GInetAddress, or %NULL on error. You
522
 * must unref each of the addresses and free the list when you are
523
 * done with it. (You can use g_resolver_free_addresses() to do this.)
524
 *
525
 * Since: 2.22
526
 */
527
GList *
528
g_resolver_lookup_by_name (GResolver     *resolver,
529
                           const gchar   *hostname,
530
                           GCancellable  *cancellable,
531
                           GError       **error)
532
0
{
533
0
  return lookup_by_name_real (resolver,
534
0
                              hostname,
535
0
                              G_RESOLVER_NAME_LOOKUP_FLAGS_DEFAULT,
536
0
                              cancellable,
537
0
                              error);
538
0
}
539
540
/**
541
 * g_resolver_lookup_by_name_with_flags:
542
 * @resolver: a #GResolver
543
 * @hostname: the hostname to look up
544
 * @flags: extra #GResolverNameLookupFlags for the lookup
545
 * @cancellable: (nullable): a #GCancellable, or %NULL
546
 * @error: (nullable): return location for a #GError, or %NULL
547
 *
548
 * This differs from g_resolver_lookup_by_name() in that you can modify
549
 * the lookup behavior with @flags. For example this can be used to limit
550
 * results with %G_RESOLVER_NAME_LOOKUP_FLAGS_IPV4_ONLY.
551
 *
552
 * Returns: (element-type GInetAddress) (transfer full): a non-empty #GList
553
 * of #GInetAddress, or %NULL on error. You
554
 * must unref each of the addresses and free the list when you are
555
 * done with it. (You can use g_resolver_free_addresses() to do this.)
556
 *
557
 * Since: 2.60
558
 */
559
GList *
560
g_resolver_lookup_by_name_with_flags (GResolver                 *resolver,
561
                                      const gchar               *hostname,
562
                                      GResolverNameLookupFlags   flags,
563
                                      GCancellable              *cancellable,
564
                                      GError                   **error)
565
0
{
566
0
  return lookup_by_name_real (resolver,
567
0
                              hostname,
568
0
                              flags,
569
0
                              cancellable,
570
0
                              error);
571
0
}
572
573
static void
574
lookup_by_name_async_real (GResolver                *resolver,
575
                           const gchar              *hostname,
576
                           GResolverNameLookupFlags  flags,
577
                           GCancellable             *cancellable,
578
                           GAsyncReadyCallback       callback,
579
                           gpointer                  user_data)
580
0
{
581
0
  gchar *ascii_hostname = NULL;
582
0
  GList *addrs;
583
0
  GError *error = NULL;
584
585
0
  g_return_if_fail (G_IS_RESOLVER (resolver));
586
0
  g_return_if_fail (hostname != NULL);
587
0
  g_return_if_fail (!(flags & G_RESOLVER_NAME_LOOKUP_FLAGS_IPV4_ONLY && flags & G_RESOLVER_NAME_LOOKUP_FLAGS_IPV6_ONLY));
588
589
  /* Check if @hostname is just an IP address */
590
0
  if (handle_ip_address_or_localhost (hostname, &addrs, flags, &error))
591
0
    {
592
0
      GTask *task;
593
594
0
      task = g_task_new (resolver, cancellable, callback, user_data);
595
0
      g_task_set_source_tag (task, lookup_by_name_async_real);
596
0
      g_task_set_name (task, "[gio] resolver lookup");
597
0
      if (addrs)
598
0
        g_task_return_pointer (task, addrs, (GDestroyNotify) g_resolver_free_addresses);
599
0
      else
600
0
        g_task_return_error (task, error);
601
0
      g_object_unref (task);
602
0
      return;
603
0
    }
604
605
0
  if (g_hostname_is_non_ascii (hostname))
606
0
    hostname = ascii_hostname = g_hostname_to_ascii (hostname);
607
608
0
  if (!hostname)
609
0
    {
610
0
      GTask *task;
611
612
0
      g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED,
613
0
                           _("Invalid hostname"));
614
0
      task = g_task_new (resolver, cancellable, callback, user_data);
615
0
      g_task_set_source_tag (task, lookup_by_name_async_real);
616
0
      g_task_set_name (task, "[gio] resolver lookup");
617
0
      g_task_return_error (task, error);
618
0
      g_object_unref (task);
619
0
      return;
620
0
    }
621
622
0
  maybe_emit_reload (resolver);
623
624
0
  if (flags != G_RESOLVER_NAME_LOOKUP_FLAGS_DEFAULT)
625
0
    {
626
0
      if (G_RESOLVER_GET_CLASS (resolver)->lookup_by_name_with_flags_async == NULL)
627
0
        {
628
0
          GTask *task;
629
630
0
          g_set_error (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
631
                       /* Translators: The placeholder is for a function name. */
632
0
                       _("%s not implemented"), "lookup_by_name_with_flags_async");
633
0
          task = g_task_new (resolver, cancellable, callback, user_data);
634
0
          g_task_set_source_tag (task, lookup_by_name_async_real);
635
0
          g_task_set_name (task, "[gio] resolver lookup");
636
0
          g_task_return_error (task, error);
637
0
          g_object_unref (task);
638
0
        }
639
0
      else
640
0
        G_RESOLVER_GET_CLASS (resolver)->
641
0
          lookup_by_name_with_flags_async (resolver, hostname, flags, cancellable, callback, user_data);
642
0
    }
643
0
  else
644
0
    G_RESOLVER_GET_CLASS (resolver)->
645
0
      lookup_by_name_async (resolver, hostname, cancellable, callback, user_data);
646
647
0
  g_free (ascii_hostname);
648
0
}
649
650
static GList *
651
lookup_by_name_finish_real (GResolver     *resolver,
652
                            GAsyncResult  *result,
653
                            GError       **error,
654
                            gboolean       with_flags)
655
0
{
656
0
  GList *addrs;
657
658
0
  g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
659
0
  g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
660
0
  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
661
662
0
  if (g_async_result_legacy_propagate_error (result, error))
663
0
    return NULL;
664
0
  else if (g_async_result_is_tagged (result, lookup_by_name_async_real))
665
0
    {
666
      /* Handle the stringified-IP-addr case */
667
0
      return g_task_propagate_pointer (G_TASK (result), error);
668
0
    }
669
670
0
  if (with_flags)
671
0
    {
672
0
      g_assert (G_RESOLVER_GET_CLASS (resolver)->lookup_by_name_with_flags_finish != NULL);
673
0
      addrs = G_RESOLVER_GET_CLASS (resolver)->
674
0
        lookup_by_name_with_flags_finish (resolver, result, error);
675
0
    }
676
0
  else
677
0
    addrs = G_RESOLVER_GET_CLASS (resolver)->
678
0
      lookup_by_name_finish (resolver, result, error);
679
680
0
  remove_duplicates (addrs);
681
682
0
  return addrs;
683
0
}
684
685
/**
686
 * g_resolver_lookup_by_name_with_flags_async:
687
 * @resolver: a #GResolver
688
 * @hostname: the hostname to look up the address of
689
 * @flags: extra #GResolverNameLookupFlags for the lookup
690
 * @cancellable: (nullable): a #GCancellable, or %NULL
691
 * @callback: (scope async): callback to call after resolution completes
692
 * @user_data: (closure): data for @callback
693
 *
694
 * Begins asynchronously resolving @hostname to determine its
695
 * associated IP address(es), and eventually calls @callback, which
696
 * must call g_resolver_lookup_by_name_with_flags_finish() to get the result.
697
 * See g_resolver_lookup_by_name() for more details.
698
 *
699
 * Since: 2.60
700
 */
701
void
702
g_resolver_lookup_by_name_with_flags_async (GResolver                *resolver,
703
                                            const gchar              *hostname,
704
                                            GResolverNameLookupFlags  flags,
705
                                            GCancellable             *cancellable,
706
                                            GAsyncReadyCallback       callback,
707
                                            gpointer                  user_data)
708
0
{
709
0
  lookup_by_name_async_real (resolver,
710
0
                             hostname,
711
0
                             flags,
712
0
                             cancellable,
713
0
                             callback,
714
0
                             user_data);
715
0
}
716
717
/**
718
 * g_resolver_lookup_by_name_async:
719
 * @resolver: a #GResolver
720
 * @hostname: the hostname to look up the address of
721
 * @cancellable: (nullable): a #GCancellable, or %NULL
722
 * @callback: (scope async): callback to call after resolution completes
723
 * @user_data: (closure): data for @callback
724
 *
725
 * Begins asynchronously resolving @hostname to determine its
726
 * associated IP address(es), and eventually calls @callback, which
727
 * must call g_resolver_lookup_by_name_finish() to get the result.
728
 * See g_resolver_lookup_by_name() for more details.
729
 *
730
 * Since: 2.22
731
 */
732
void
733
g_resolver_lookup_by_name_async (GResolver           *resolver,
734
                                 const gchar         *hostname,
735
                                 GCancellable        *cancellable,
736
                                 GAsyncReadyCallback  callback,
737
                                 gpointer             user_data)
738
0
{
739
0
  lookup_by_name_async_real (resolver,
740
0
                             hostname,
741
0
                             0,
742
0
                             cancellable,
743
0
                             callback,
744
0
                             user_data);
745
0
}
746
747
/**
748
 * g_resolver_lookup_by_name_finish:
749
 * @resolver: a #GResolver
750
 * @result: the result passed to your #GAsyncReadyCallback
751
 * @error: return location for a #GError, or %NULL
752
 *
753
 * Retrieves the result of a call to
754
 * g_resolver_lookup_by_name_async().
755
 *
756
 * If the DNS resolution failed, @error (if non-%NULL) will be set to
757
 * a value from #GResolverError. If the operation was cancelled,
758
 * @error will be set to %G_IO_ERROR_CANCELLED.
759
 *
760
 * Returns: (element-type GInetAddress) (transfer full): a #GList
761
 * of #GInetAddress, or %NULL on error. See g_resolver_lookup_by_name()
762
 * for more details.
763
 *
764
 * Since: 2.22
765
 */
766
GList *
767
g_resolver_lookup_by_name_finish (GResolver     *resolver,
768
                                  GAsyncResult  *result,
769
                                  GError       **error)
770
0
{
771
0
  return lookup_by_name_finish_real (resolver,
772
0
                                     result,
773
0
                                     error,
774
0
                                     FALSE);
775
0
}
776
777
/**
778
 * g_resolver_lookup_by_name_with_flags_finish:
779
 * @resolver: a #GResolver
780
 * @result: the result passed to your #GAsyncReadyCallback
781
 * @error: return location for a #GError, or %NULL
782
 *
783
 * Retrieves the result of a call to
784
 * g_resolver_lookup_by_name_with_flags_async().
785
 *
786
 * If the DNS resolution failed, @error (if non-%NULL) will be set to
787
 * a value from #GResolverError. If the operation was cancelled,
788
 * @error will be set to %G_IO_ERROR_CANCELLED.
789
 *
790
 * Returns: (element-type GInetAddress) (transfer full): a #GList
791
 * of #GInetAddress, or %NULL on error. See g_resolver_lookup_by_name()
792
 * for more details.
793
 *
794
 * Since: 2.60
795
 */
796
GList *
797
g_resolver_lookup_by_name_with_flags_finish (GResolver     *resolver,
798
                                             GAsyncResult  *result,
799
                                             GError       **error)
800
0
{
801
0
  return lookup_by_name_finish_real (resolver,
802
0
                                     result,
803
0
                                     error,
804
0
                                     TRUE);
805
0
}
806
807
/**
808
 * g_resolver_free_addresses: (skip)
809
 * @addresses: a #GList of #GInetAddress
810
 *
811
 * Frees @addresses (which should be the return value from
812
 * g_resolver_lookup_by_name() or g_resolver_lookup_by_name_finish()).
813
 * (This is a convenience method; you can also simply free the results
814
 * by hand.)
815
 *
816
 * Since: 2.22
817
 */
818
void
819
g_resolver_free_addresses (GList *addresses)
820
0
{
821
0
  GList *a;
822
823
0
  for (a = addresses; a; a = a->next)
824
0
    g_object_unref (a->data);
825
0
  g_list_free (addresses);
826
0
}
827
828
/**
829
 * g_resolver_lookup_by_address:
830
 * @resolver: a #GResolver
831
 * @address: the address to reverse-resolve
832
 * @cancellable: (nullable): a #GCancellable, or %NULL
833
 * @error: return location for a #GError, or %NULL
834
 *
835
 * Synchronously reverse-resolves @address to determine its
836
 * associated hostname.
837
 *
838
 * If the DNS resolution fails, @error (if non-%NULL) will be set to
839
 * a value from #GResolverError.
840
 *
841
 * If @cancellable is non-%NULL, it can be used to cancel the
842
 * operation, in which case @error (if non-%NULL) will be set to
843
 * %G_IO_ERROR_CANCELLED.
844
 *
845
 * Returns: a hostname (either ASCII-only, or in ASCII-encoded
846
 *     form), or %NULL on error.
847
 *
848
 * Since: 2.22
849
 */
850
gchar *
851
g_resolver_lookup_by_address (GResolver     *resolver,
852
                              GInetAddress  *address,
853
                              GCancellable  *cancellable,
854
                              GError       **error)
855
0
{
856
0
  g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
857
0
  g_return_val_if_fail (G_IS_INET_ADDRESS (address), NULL);
858
859
0
  maybe_emit_reload (resolver);
860
0
  return G_RESOLVER_GET_CLASS (resolver)->
861
0
    lookup_by_address (resolver, address, cancellable, error);
862
0
}
863
864
/**
865
 * g_resolver_lookup_by_address_async:
866
 * @resolver: a #GResolver
867
 * @address: the address to reverse-resolve
868
 * @cancellable: (nullable): a #GCancellable, or %NULL
869
 * @callback: (scope async): callback to call after resolution completes
870
 * @user_data: (closure): data for @callback
871
 *
872
 * Begins asynchronously reverse-resolving @address to determine its
873
 * associated hostname, and eventually calls @callback, which must
874
 * call g_resolver_lookup_by_address_finish() to get the final result.
875
 *
876
 * Since: 2.22
877
 */
878
void
879
g_resolver_lookup_by_address_async (GResolver           *resolver,
880
                                    GInetAddress        *address,
881
                                    GCancellable        *cancellable,
882
                                    GAsyncReadyCallback  callback,
883
                                    gpointer             user_data)
884
0
{
885
0
  g_return_if_fail (G_IS_RESOLVER (resolver));
886
0
  g_return_if_fail (G_IS_INET_ADDRESS (address));
887
888
0
  maybe_emit_reload (resolver);
889
0
  G_RESOLVER_GET_CLASS (resolver)->
890
0
    lookup_by_address_async (resolver, address, cancellable, callback, user_data);
891
0
}
892
893
/**
894
 * g_resolver_lookup_by_address_finish:
895
 * @resolver: a #GResolver
896
 * @result: the result passed to your #GAsyncReadyCallback
897
 * @error: return location for a #GError, or %NULL
898
 *
899
 * Retrieves the result of a previous call to
900
 * g_resolver_lookup_by_address_async().
901
 *
902
 * If the DNS resolution failed, @error (if non-%NULL) will be set to
903
 * a value from #GResolverError. If the operation was cancelled,
904
 * @error will be set to %G_IO_ERROR_CANCELLED.
905
 *
906
 * Returns: a hostname (either ASCII-only, or in ASCII-encoded
907
 * form), or %NULL on error.
908
 *
909
 * Since: 2.22
910
 */
911
gchar *
912
g_resolver_lookup_by_address_finish (GResolver     *resolver,
913
                                     GAsyncResult  *result,
914
                                     GError       **error)
915
0
{
916
0
  g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
917
918
0
  if (g_async_result_legacy_propagate_error (result, error))
919
0
    return NULL;
920
921
0
  return G_RESOLVER_GET_CLASS (resolver)->
922
0
    lookup_by_address_finish (resolver, result, error);
923
0
}
924
925
static gchar *
926
g_resolver_get_service_rrname (const char *service,
927
                               const char *protocol,
928
                               const char *domain)
929
0
{
930
0
  gchar *rrname, *ascii_domain = NULL;
931
932
0
  if (g_hostname_is_non_ascii (domain))
933
0
    domain = ascii_domain = g_hostname_to_ascii (domain);
934
0
  if (!domain)
935
0
    return NULL;
936
937
0
  rrname = g_strdup_printf ("_%s._%s.%s", service, protocol, domain);
938
939
0
  g_free (ascii_domain);
940
0
  return rrname;
941
0
}
942
943
/**
944
 * g_resolver_lookup_service:
945
 * @resolver: a #GResolver
946
 * @service: the service type to look up (eg, "ldap")
947
 * @protocol: the networking protocol to use for @service (eg, "tcp")
948
 * @domain: the DNS domain to look up the service in
949
 * @cancellable: (nullable): a #GCancellable, or %NULL
950
 * @error: return location for a #GError, or %NULL
951
 *
952
 * Synchronously performs a DNS SRV lookup for the given @service and
953
 * @protocol in the given @domain and returns an array of #GSrvTarget.
954
 * @domain may be an ASCII-only or UTF-8 hostname. Note also that the
955
 * @service and @protocol arguments do not include the leading underscore
956
 * that appears in the actual DNS entry.
957
 *
958
 * On success, g_resolver_lookup_service() will return a non-empty #GList of
959
 * #GSrvTarget, sorted in order of preference. (That is, you should
960
 * attempt to connect to the first target first, then the second if
961
 * the first fails, etc.)
962
 *
963
 * If the DNS resolution fails, @error (if non-%NULL) will be set to
964
 * a value from #GResolverError and %NULL will be returned.
965
 *
966
 * If @cancellable is non-%NULL, it can be used to cancel the
967
 * operation, in which case @error (if non-%NULL) will be set to
968
 * %G_IO_ERROR_CANCELLED.
969
 *
970
 * If you are planning to connect to the service, it is usually easier
971
 * to create a #GNetworkService and use its #GSocketConnectable
972
 * interface.
973
 *
974
 * Returns: (element-type GSrvTarget) (transfer full): a non-empty #GList of
975
 * #GSrvTarget, or %NULL on error. You must free each of the targets and the
976
 * list when you are done with it. (You can use g_resolver_free_targets() to do
977
 * this.)
978
 *
979
 * Since: 2.22
980
 */
981
GList *
982
g_resolver_lookup_service (GResolver     *resolver,
983
                           const gchar   *service,
984
                           const gchar   *protocol,
985
                           const gchar   *domain,
986
                           GCancellable  *cancellable,
987
                           GError       **error)
988
0
{
989
0
  GList *targets;
990
0
  gchar *rrname;
991
992
0
  g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
993
0
  g_return_val_if_fail (service != NULL, NULL);
994
0
  g_return_val_if_fail (protocol != NULL, NULL);
995
0
  g_return_val_if_fail (domain != NULL, NULL);
996
997
0
  rrname = g_resolver_get_service_rrname (service, protocol, domain);
998
0
  if (!rrname)
999
0
    {
1000
0
      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1001
0
                           _("Invalid domain"));
1002
0
      return NULL;
1003
0
    }
1004
1005
0
  maybe_emit_reload (resolver);
1006
0
  targets = G_RESOLVER_GET_CLASS (resolver)->
1007
0
    lookup_service (resolver, rrname, cancellable, error);
1008
1009
0
  g_free (rrname);
1010
0
  return targets;
1011
0
}
1012
1013
/**
1014
 * g_resolver_lookup_service_async:
1015
 * @resolver: a #GResolver
1016
 * @service: the service type to look up (eg, "ldap")
1017
 * @protocol: the networking protocol to use for @service (eg, "tcp")
1018
 * @domain: the DNS domain to look up the service in
1019
 * @cancellable: (nullable): a #GCancellable, or %NULL
1020
 * @callback: (scope async): callback to call after resolution completes
1021
 * @user_data: (closure): data for @callback
1022
 *
1023
 * Begins asynchronously performing a DNS SRV lookup for the given
1024
 * @service and @protocol in the given @domain, and eventually calls
1025
 * @callback, which must call g_resolver_lookup_service_finish() to
1026
 * get the final result. See g_resolver_lookup_service() for more
1027
 * details.
1028
 *
1029
 * Since: 2.22
1030
 */
1031
void
1032
g_resolver_lookup_service_async (GResolver           *resolver,
1033
                                 const gchar         *service,
1034
                                 const gchar         *protocol,
1035
                                 const gchar         *domain,
1036
                                 GCancellable        *cancellable,
1037
                                 GAsyncReadyCallback  callback,
1038
                                 gpointer             user_data)
1039
0
{
1040
0
  gchar *rrname;
1041
1042
0
  g_return_if_fail (G_IS_RESOLVER (resolver));
1043
0
  g_return_if_fail (service != NULL);
1044
0
  g_return_if_fail (protocol != NULL);
1045
0
  g_return_if_fail (domain != NULL);
1046
1047
0
  rrname = g_resolver_get_service_rrname (service, protocol, domain);
1048
0
  if (!rrname)
1049
0
    {
1050
0
      g_task_report_new_error (resolver, callback, user_data,
1051
0
                               g_resolver_lookup_service_async,
1052
0
                               G_IO_ERROR, G_IO_ERROR_FAILED,
1053
0
                               _("Invalid domain"));
1054
0
      return;
1055
0
    }
1056
1057
0
  maybe_emit_reload (resolver);
1058
0
  G_RESOLVER_GET_CLASS (resolver)->
1059
0
    lookup_service_async (resolver, rrname, cancellable, callback, user_data);
1060
1061
0
  g_free (rrname);
1062
0
}
1063
1064
/**
1065
 * g_resolver_lookup_service_finish:
1066
 * @resolver: a #GResolver
1067
 * @result: the result passed to your #GAsyncReadyCallback
1068
 * @error: return location for a #GError, or %NULL
1069
 *
1070
 * Retrieves the result of a previous call to
1071
 * g_resolver_lookup_service_async().
1072
 *
1073
 * If the DNS resolution failed, @error (if non-%NULL) will be set to
1074
 * a value from #GResolverError. If the operation was cancelled,
1075
 * @error will be set to %G_IO_ERROR_CANCELLED.
1076
 *
1077
 * Returns: (element-type GSrvTarget) (transfer full): a non-empty #GList of
1078
 * #GSrvTarget, or %NULL on error. See g_resolver_lookup_service() for more
1079
 * details.
1080
 *
1081
 * Since: 2.22
1082
 */
1083
GList *
1084
g_resolver_lookup_service_finish (GResolver     *resolver,
1085
                                  GAsyncResult  *result,
1086
                                  GError       **error)
1087
0
{
1088
0
  g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
1089
1090
0
  if (g_async_result_legacy_propagate_error (result, error))
1091
0
    return NULL;
1092
1093
0
  return G_RESOLVER_GET_CLASS (resolver)->
1094
0
    lookup_service_finish (resolver, result, error);
1095
0
}
1096
1097
/**
1098
 * g_resolver_free_targets: (skip)
1099
 * @targets: a #GList of #GSrvTarget
1100
 *
1101
 * Frees @targets (which should be the return value from
1102
 * g_resolver_lookup_service() or g_resolver_lookup_service_finish()).
1103
 * (This is a convenience method; you can also simply free the
1104
 * results by hand.)
1105
 *
1106
 * Since: 2.22
1107
 */
1108
void
1109
g_resolver_free_targets (GList *targets)
1110
0
{
1111
0
  GList *t;
1112
1113
0
  for (t = targets; t; t = t->next)
1114
0
    g_srv_target_free (t->data);
1115
0
  g_list_free (targets);
1116
0
}
1117
1118
/**
1119
 * g_resolver_lookup_records:
1120
 * @resolver: a #GResolver
1121
 * @rrname: the DNS name to look up the record for
1122
 * @record_type: the type of DNS record to look up
1123
 * @cancellable: (nullable): a #GCancellable, or %NULL
1124
 * @error: return location for a #GError, or %NULL
1125
 *
1126
 * Synchronously performs a DNS record lookup for the given @rrname and returns
1127
 * a list of records as #GVariant tuples. See #GResolverRecordType for
1128
 * information on what the records contain for each @record_type.
1129
 *
1130
 * If the DNS resolution fails, @error (if non-%NULL) will be set to
1131
 * a value from #GResolverError and %NULL will be returned.
1132
 *
1133
 * If @cancellable is non-%NULL, it can be used to cancel the
1134
 * operation, in which case @error (if non-%NULL) will be set to
1135
 * %G_IO_ERROR_CANCELLED.
1136
 *
1137
 * Returns: (element-type GVariant) (transfer full): a non-empty #GList of
1138
 * #GVariant, or %NULL on error. You must free each of the records and the list
1139
 * when you are done with it. (You can use g_list_free_full() with
1140
 * g_variant_unref() to do this.)
1141
 *
1142
 * Since: 2.34
1143
 */
1144
GList *
1145
g_resolver_lookup_records (GResolver            *resolver,
1146
                           const gchar          *rrname,
1147
                           GResolverRecordType   record_type,
1148
                           GCancellable         *cancellable,
1149
                           GError              **error)
1150
0
{
1151
0
  GList *records;
1152
1153
0
  g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
1154
0
  g_return_val_if_fail (rrname != NULL, NULL);
1155
1156
0
  maybe_emit_reload (resolver);
1157
0
  records = G_RESOLVER_GET_CLASS (resolver)->
1158
0
    lookup_records (resolver, rrname, record_type, cancellable, error);
1159
1160
0
  return records;
1161
0
}
1162
1163
/**
1164
 * g_resolver_lookup_records_async:
1165
 * @resolver: a #GResolver
1166
 * @rrname: the DNS name to look up the record for
1167
 * @record_type: the type of DNS record to look up
1168
 * @cancellable: (nullable): a #GCancellable, or %NULL
1169
 * @callback: (scope async): callback to call after resolution completes
1170
 * @user_data: (closure): data for @callback
1171
 *
1172
 * Begins asynchronously performing a DNS lookup for the given
1173
 * @rrname, and eventually calls @callback, which must call
1174
 * g_resolver_lookup_records_finish() to get the final result. See
1175
 * g_resolver_lookup_records() for more details.
1176
 *
1177
 * Since: 2.34
1178
 */
1179
void
1180
g_resolver_lookup_records_async (GResolver           *resolver,
1181
                                 const gchar         *rrname,
1182
                                 GResolverRecordType  record_type,
1183
                                 GCancellable        *cancellable,
1184
                                 GAsyncReadyCallback  callback,
1185
                                 gpointer             user_data)
1186
0
{
1187
0
  g_return_if_fail (G_IS_RESOLVER (resolver));
1188
0
  g_return_if_fail (rrname != NULL);
1189
1190
0
  maybe_emit_reload (resolver);
1191
0
  G_RESOLVER_GET_CLASS (resolver)->
1192
0
    lookup_records_async (resolver, rrname, record_type, cancellable, callback, user_data);
1193
0
}
1194
1195
/**
1196
 * g_resolver_lookup_records_finish:
1197
 * @resolver: a #GResolver
1198
 * @result: the result passed to your #GAsyncReadyCallback
1199
 * @error: return location for a #GError, or %NULL
1200
 *
1201
 * Retrieves the result of a previous call to
1202
 * g_resolver_lookup_records_async(). Returns a non-empty list of records as
1203
 * #GVariant tuples. See #GResolverRecordType for information on what the
1204
 * records contain.
1205
 *
1206
 * If the DNS resolution failed, @error (if non-%NULL) will be set to
1207
 * a value from #GResolverError. If the operation was cancelled,
1208
 * @error will be set to %G_IO_ERROR_CANCELLED.
1209
 *
1210
 * Returns: (element-type GVariant) (transfer full): a non-empty #GList of
1211
 * #GVariant, or %NULL on error. You must free each of the records and the list
1212
 * when you are done with it. (You can use g_list_free_full() with
1213
 * g_variant_unref() to do this.)
1214
 *
1215
 * Since: 2.34
1216
 */
1217
GList *
1218
g_resolver_lookup_records_finish (GResolver     *resolver,
1219
                                  GAsyncResult  *result,
1220
                                  GError       **error)
1221
0
{
1222
0
  g_return_val_if_fail (G_IS_RESOLVER (resolver), NULL);
1223
0
  return G_RESOLVER_GET_CLASS (resolver)->
1224
0
    lookup_records_finish (resolver, result, error);
1225
0
}
1226
1227
guint64
1228
g_resolver_get_serial (GResolver *resolver)
1229
0
{
1230
0
  guint64 result;
1231
1232
0
  g_return_val_if_fail (G_IS_RESOLVER (resolver), 0);
1233
1234
0
  maybe_emit_reload (resolver);
1235
1236
0
#ifdef G_OS_UNIX
1237
0
  g_mutex_lock (&resolver->priv->mutex);
1238
0
  result = resolver->priv->resolv_conf_timestamp;
1239
0
  g_mutex_unlock (&resolver->priv->mutex);
1240
#else
1241
  result = 1;
1242
#endif
1243
1244
0
  return result;
1245
0
}
1246
1247
/**
1248
 * g_resolver_error_quark:
1249
 *
1250
 * Gets the #GResolver Error Quark.
1251
 *
1252
 * Returns: a #GQuark.
1253
 *
1254
 * Since: 2.22
1255
 */
1256
G_DEFINE_QUARK (g-resolver-error-quark, g_resolver_error)