Coverage Report

Created: 2025-07-23 08:13

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