Coverage Report

Created: 2025-06-13 06:55

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