Coverage Report

Created: 2025-07-23 08:13

/src/pango/subprojects/glib/gio/gnetworkaddress.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 <stdlib.h>
29
#include "gnetworkaddress.h"
30
#include "gasyncresult.h"
31
#include "ginetaddress.h"
32
#include "ginetsocketaddress.h"
33
#include "gnetworkingprivate.h"
34
#include "gproxyaddressenumerator.h"
35
#include "gresolver.h"
36
#include "gtask.h"
37
#include "gsocketaddressenumerator.h"
38
#include "gioerror.h"
39
#include "gsocketconnectable.h"
40
41
#include <string.h>
42
43
/* As recommended by RFC 8305 this is the time it waits for a following
44
   DNS response to come in (ipv4 waiting on ipv6 generally)
45
 */
46
0
#define HAPPY_EYEBALLS_RESOLUTION_DELAY_MS 50
47
48
/**
49
 * GNetworkAddress:
50
 *
51
 * `GNetworkAddress` provides an easy way to resolve a hostname and
52
 * then attempt to connect to that host, handling the possibility of
53
 * multiple IP addresses and multiple address families.
54
 *
55
 * The enumeration results of resolved addresses *may* be cached as long
56
 * as this object is kept alive which may have unexpected results if
57
 * alive for too long.
58
 *
59
 * See [iface@Gio.SocketConnectable] for an example of using the connectable
60
 * interface.
61
 */
62
63
struct _GNetworkAddressPrivate {
64
  gchar *hostname;
65
  guint16 port;
66
  GList *cached_sockaddrs;
67
  gchar *scheme;
68
69
  gint64 resolver_serial;
70
};
71
72
enum {
73
  PROP_0,
74
  PROP_HOSTNAME,
75
  PROP_PORT,
76
  PROP_SCHEME,
77
};
78
79
static void g_network_address_set_property (GObject      *object,
80
                                            guint         prop_id,
81
                                            const GValue *value,
82
                                            GParamSpec   *pspec);
83
static void g_network_address_get_property (GObject      *object,
84
                                            guint         prop_id,
85
                                            GValue       *value,
86
                                            GParamSpec   *pspec);
87
88
static void                      g_network_address_connectable_iface_init       (GSocketConnectableIface *iface);
89
static GSocketAddressEnumerator *g_network_address_connectable_enumerate        (GSocketConnectable      *connectable);
90
static GSocketAddressEnumerator *g_network_address_connectable_proxy_enumerate  (GSocketConnectable      *connectable);
91
static gchar                    *g_network_address_connectable_to_string        (GSocketConnectable      *connectable);
92
93
G_DEFINE_TYPE_WITH_CODE (GNetworkAddress, g_network_address, G_TYPE_OBJECT,
94
                         G_ADD_PRIVATE (GNetworkAddress)
95
                         G_IMPLEMENT_INTERFACE (G_TYPE_SOCKET_CONNECTABLE,
96
                                                g_network_address_connectable_iface_init))
97
98
static void
99
g_network_address_finalize (GObject *object)
100
0
{
101
0
  GNetworkAddress *addr = G_NETWORK_ADDRESS (object);
102
103
0
  g_free (addr->priv->hostname);
104
0
  g_free (addr->priv->scheme);
105
0
  g_list_free_full (addr->priv->cached_sockaddrs, g_object_unref);
106
107
0
  G_OBJECT_CLASS (g_network_address_parent_class)->finalize (object);
108
0
}
109
110
static void
111
g_network_address_class_init (GNetworkAddressClass *klass)
112
0
{
113
0
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
114
115
0
  gobject_class->set_property = g_network_address_set_property;
116
0
  gobject_class->get_property = g_network_address_get_property;
117
0
  gobject_class->finalize = g_network_address_finalize;
118
119
  /**
120
   * GNetworkAddress:hostname:
121
   *
122
   * Hostname to resolve.
123
   *
124
   * Since: 2.22
125
   */
126
0
  g_object_class_install_property (gobject_class, PROP_HOSTNAME,
127
0
                                   g_param_spec_string ("hostname", NULL, NULL,
128
0
                                                        NULL,
129
0
                                                        G_PARAM_READWRITE |
130
0
                                                        G_PARAM_CONSTRUCT_ONLY |
131
0
                                                        G_PARAM_STATIC_STRINGS));
132
133
  /**
134
   * GNetworkAddress:port:
135
   *
136
   * Network port.
137
   *
138
   * Since: 2.22
139
   */
140
0
  g_object_class_install_property (gobject_class, PROP_PORT,
141
0
                                   g_param_spec_uint ("port", NULL, NULL,
142
0
                                                      0, 65535, 0,
143
0
                                                      G_PARAM_READWRITE |
144
0
                                                      G_PARAM_CONSTRUCT_ONLY |
145
0
                                                      G_PARAM_STATIC_STRINGS));
146
147
  /**
148
   * GNetworkAddress:scheme:
149
   *
150
   * URI scheme.
151
   *
152
   * Since: 2.22
153
   */
154
0
  g_object_class_install_property (gobject_class, PROP_SCHEME,
155
0
                                   g_param_spec_string ("scheme", NULL, NULL,
156
0
                                                        NULL,
157
0
                                                        G_PARAM_READWRITE |
158
0
                                                        G_PARAM_CONSTRUCT_ONLY |
159
0
                                                        G_PARAM_STATIC_STRINGS));
160
0
}
161
162
static void
163
g_network_address_connectable_iface_init (GSocketConnectableIface *connectable_iface)
164
0
{
165
0
  connectable_iface->enumerate  = g_network_address_connectable_enumerate;
166
0
  connectable_iface->proxy_enumerate = g_network_address_connectable_proxy_enumerate;
167
0
  connectable_iface->to_string = g_network_address_connectable_to_string;
168
0
}
169
170
static void
171
g_network_address_init (GNetworkAddress *addr)
172
0
{
173
0
  addr->priv = g_network_address_get_instance_private (addr);
174
0
}
175
176
static void
177
g_network_address_set_property (GObject      *object,
178
                                guint         prop_id,
179
                                const GValue *value,
180
                                GParamSpec   *pspec)
181
0
{
182
0
  GNetworkAddress *addr = G_NETWORK_ADDRESS (object);
183
184
0
  switch (prop_id)
185
0
    {
186
0
    case PROP_HOSTNAME:
187
0
      g_free (addr->priv->hostname);
188
0
      addr->priv->hostname = g_value_dup_string (value);
189
0
      break;
190
191
0
    case PROP_PORT:
192
0
      addr->priv->port = g_value_get_uint (value);
193
0
      break;
194
195
0
    case PROP_SCHEME:
196
0
      g_free (addr->priv->scheme);
197
0
      addr->priv->scheme = g_value_dup_string (value);
198
0
      break;
199
200
0
    default:
201
0
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
202
0
      break;
203
0
    }
204
205
0
}
206
207
static void
208
g_network_address_get_property (GObject    *object,
209
                                guint       prop_id,
210
                                GValue     *value,
211
                                GParamSpec *pspec)
212
0
{
213
0
  GNetworkAddress *addr = G_NETWORK_ADDRESS (object);
214
215
0
  switch (prop_id)
216
0
    {
217
0
    case PROP_HOSTNAME:
218
0
      g_value_set_string (value, addr->priv->hostname);
219
0
      break;
220
221
0
    case PROP_PORT:
222
0
      g_value_set_uint (value, addr->priv->port);
223
0
      break;
224
225
0
    case PROP_SCHEME:
226
0
      g_value_set_string (value, addr->priv->scheme);
227
0
      break;
228
229
0
    default:
230
0
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
231
0
      break;
232
0
    }
233
234
0
}
235
236
/*
237
 * inet_addresses_to_inet_socket_addresses:
238
 * @addresses: (transfer full): #GList of #GInetAddress
239
 *
240
 * Returns: (transfer full): #GList of #GInetSocketAddress
241
 */
242
static GList *
243
inet_addresses_to_inet_socket_addresses (GNetworkAddress *addr,
244
                                         GList           *addresses)
245
0
{
246
0
  GList *a, *socket_addresses = NULL;
247
248
0
  for (a = addresses; a; a = a->next)
249
0
    {
250
0
      GSocketAddress *sockaddr = g_inet_socket_address_new (a->data, addr->priv->port);
251
0
      socket_addresses = g_list_append (socket_addresses, g_steal_pointer (&sockaddr));
252
0
      g_object_unref (a->data);
253
0
    }
254
255
0
  g_list_free (addresses);
256
0
  return socket_addresses;
257
0
}
258
259
/*
260
 * g_network_address_set_cached_addresses:
261
 * @addr: A #GNetworkAddress
262
 * @addresses: (transfer full): List of #GInetAddress or #GInetSocketAddress
263
 * @resolver_serial: Serial of #GResolver used
264
 *
265
 * Consumes @addresses and uses them to replace the current internal list.
266
 */
267
static void
268
g_network_address_set_cached_addresses (GNetworkAddress *addr,
269
                                        GList           *addresses,
270
                                        guint64          resolver_serial)
271
0
{
272
0
  g_assert (addresses != NULL);
273
274
0
  if (addr->priv->cached_sockaddrs)
275
0
    g_list_free_full (addr->priv->cached_sockaddrs, g_object_unref);
276
277
0
  if (G_IS_INET_SOCKET_ADDRESS (addresses->data))
278
0
    addr->priv->cached_sockaddrs = g_steal_pointer (&addresses);
279
0
  else
280
0
    addr->priv->cached_sockaddrs = inet_addresses_to_inet_socket_addresses (addr, g_steal_pointer (&addresses));
281
0
  addr->priv->resolver_serial = resolver_serial;
282
0
}
283
284
static gboolean
285
g_network_address_parse_sockaddr (GNetworkAddress *addr)
286
0
{
287
0
  GSocketAddress *sockaddr;
288
289
0
  g_assert (addr->priv->cached_sockaddrs == NULL);
290
291
0
  sockaddr = g_inet_socket_address_new_from_string (addr->priv->hostname,
292
0
                                                    addr->priv->port);
293
0
  if (sockaddr)
294
0
    {
295
0
      addr->priv->cached_sockaddrs = g_list_append (addr->priv->cached_sockaddrs, sockaddr);
296
0
      return TRUE;
297
0
    }
298
0
  else
299
0
    return FALSE;
300
0
}
301
302
/**
303
 * g_network_address_new:
304
 * @hostname: the hostname
305
 * @port: the port
306
 *
307
 * Creates a new #GSocketConnectable for connecting to the given
308
 * @hostname and @port.
309
 *
310
 * Note that depending on the configuration of the machine, a
311
 * @hostname of `localhost` may refer to the IPv4 loopback address
312
 * only, or to both IPv4 and IPv6; use
313
 * g_network_address_new_loopback() to create a #GNetworkAddress that
314
 * is guaranteed to resolve to both addresses.
315
 *
316
 * Returns: (transfer full) (type GNetworkAddress): the new #GNetworkAddress
317
 *
318
 * Since: 2.22
319
 */
320
GSocketConnectable *
321
g_network_address_new (const gchar *hostname,
322
                       guint16      port)
323
0
{
324
0
  return g_object_new (G_TYPE_NETWORK_ADDRESS,
325
0
                       "hostname", hostname,
326
0
                       "port", port,
327
0
                       NULL);
328
0
}
329
330
/**
331
 * g_network_address_new_loopback:
332
 * @port: the port
333
 *
334
 * Creates a new #GSocketConnectable for connecting to the local host
335
 * over a loopback connection to the given @port. This is intended for
336
 * use in connecting to local services which may be running on IPv4 or
337
 * IPv6.
338
 *
339
 * The connectable will return IPv4 and IPv6 loopback addresses,
340
 * regardless of how the host resolves `localhost`. By contrast,
341
 * g_network_address_new() will often only return an IPv4 address when
342
 * resolving `localhost`, and an IPv6 address for `localhost6`.
343
 *
344
 * g_network_address_get_hostname() will always return `localhost` for
345
 * a #GNetworkAddress created with this constructor.
346
 *
347
 * Returns: (transfer full) (type GNetworkAddress): the new #GNetworkAddress
348
 *
349
 * Since: 2.44
350
 */
351
GSocketConnectable *
352
g_network_address_new_loopback (guint16 port)
353
0
{
354
0
  GNetworkAddress *addr;
355
0
  GList *addrs = NULL;
356
357
0
  addr = g_object_new (G_TYPE_NETWORK_ADDRESS,
358
0
                       "hostname", "localhost",
359
0
                       "port", port,
360
0
                       NULL);
361
362
0
  addrs = g_list_append (addrs, g_inet_address_new_loopback (AF_INET6));
363
0
  addrs = g_list_append (addrs, g_inet_address_new_loopback (AF_INET));
364
0
  g_network_address_set_cached_addresses (addr, g_steal_pointer (&addrs), 0);
365
366
0
  return G_SOCKET_CONNECTABLE (addr);
367
0
}
368
369
/**
370
 * g_network_address_parse:
371
 * @host_and_port: the hostname and optionally a port
372
 * @default_port: the default port if not in @host_and_port
373
 * @error: a pointer to a #GError, or %NULL
374
 *
375
 * Creates a new #GSocketConnectable for connecting to the given
376
 * @hostname and @port. May fail and return %NULL in case
377
 * parsing @host_and_port fails.
378
 *
379
 * @host_and_port may be in any of a number of recognised formats; an IPv6
380
 * address, an IPv4 address, or a domain name (in which case a DNS
381
 * lookup is performed). Quoting with [] is supported for all address
382
 * types. A port override may be specified in the usual way with a
383
 * colon.
384
 *
385
 * If no port is specified in @host_and_port then @default_port will be
386
 * used as the port number to connect to.
387
 *
388
 * In general, @host_and_port is expected to be provided by the user
389
 * (allowing them to give the hostname, and a port override if necessary)
390
 * and @default_port is expected to be provided by the application.
391
 *
392
 * (The port component of @host_and_port can also be specified as a
393
 * service name rather than as a numeric port, but this functionality
394
 * is deprecated, because it depends on the contents of /etc/services,
395
 * which is generally quite sparse on platforms other than Linux.)
396
 *
397
 * Returns: (transfer full) (type GNetworkAddress): the new
398
 *   #GNetworkAddress, or %NULL on error
399
 *
400
 * Since: 2.22
401
 */
402
GSocketConnectable *
403
g_network_address_parse (const gchar  *host_and_port,
404
                         guint16       default_port,
405
                         GError      **error)
406
0
{
407
0
  GSocketConnectable *connectable;
408
0
  const gchar *port;
409
0
  guint16 portnum;
410
0
  gchar *name;
411
412
0
  g_return_val_if_fail (host_and_port != NULL, NULL);
413
414
0
  port = NULL;
415
0
  if (host_and_port[0] == '[')
416
    /* escaped host part (to allow, eg. "[2001:db8::1]:888") */
417
0
    {
418
0
      const gchar *end;
419
420
0
      end = strchr (host_and_port, ']');
421
0
      if (end == NULL)
422
0
        {
423
0
          g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
424
0
                       _("Hostname “%s” contains “[” but not “]”"), host_and_port);
425
0
          return NULL;
426
0
        }
427
428
0
      if (end[1] == '\0')
429
0
        port = NULL;
430
0
      else if (end[1] == ':')
431
0
        port = &end[2];
432
0
      else
433
0
        {
434
0
          g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
435
0
                       "The ']' character (in hostname '%s') must come at the"
436
0
                       " end or be immediately followed by ':' and a port",
437
0
                       host_and_port);
438
0
          return NULL;
439
0
        }
440
441
0
      name = g_strndup (host_and_port + 1, end - host_and_port - 1);
442
0
    }
443
444
0
  else if ((port = strchr (host_and_port, ':')))
445
    /* string has a ':' in it */
446
0
    {
447
      /* skip ':' */
448
0
      port++;
449
450
0
      if (strchr (port, ':'))
451
        /* more than one ':' in string */
452
0
        {
453
          /* this is actually an unescaped IPv6 address */
454
0
          name = g_strdup (host_and_port);
455
0
          port = NULL;
456
0
        }
457
0
      else
458
0
        name = g_strndup (host_and_port, port - host_and_port - 1);
459
0
    }
460
461
0
  else
462
    /* plain hostname, no port */
463
0
    name = g_strdup (host_and_port);
464
465
0
  if (port != NULL)
466
0
    {
467
0
      if (port[0] == '\0')
468
0
        {
469
0
          g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
470
0
                       "If a ':' character is given, it must be followed by a "
471
0
                       "port (in hostname '%s').", host_and_port);
472
0
          g_free (name);
473
0
          return NULL;
474
0
        }
475
476
0
      else if ('0' <= port[0] && port[0] <= '9')
477
0
        {
478
0
          char *end;
479
0
          long value;
480
481
0
          value = strtol (port, &end, 10);
482
0
          if (*end != '\0' || value < 0 || value > G_MAXUINT16)
483
0
            {
484
0
              g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
485
0
                           "Invalid numeric port '%s' specified in hostname '%s'",
486
0
                           port, host_and_port);
487
0
              g_free (name);
488
0
              return NULL;
489
0
            }
490
491
0
          portnum = value;
492
0
        }
493
494
0
      else
495
0
        {
496
0
          if (!g_getservbyname_ntohs (port, "tcp", &portnum))
497
0
            {
498
0
              g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
499
0
                           "Unknown service '%s' specified in hostname '%s'",
500
0
                           port, host_and_port);
501
0
#ifdef HAVE_ENDSERVENT
502
0
              endservent ();
503
0
#endif
504
0
              g_free (name);
505
0
              return NULL;
506
0
            }
507
508
0
#ifdef HAVE_ENDSERVENT
509
0
          endservent ();
510
0
#endif
511
0
        }
512
0
    }
513
0
  else
514
0
    {
515
      /* No port in host_and_port */
516
0
      portnum = default_port;
517
0
    }
518
519
0
  connectable = g_network_address_new (name, portnum);
520
0
  g_free (name);
521
522
0
  return connectable;
523
0
}
524
525
/**
526
 * g_network_address_parse_uri:
527
 * @uri: the hostname and optionally a port
528
 * @default_port: The default port if none is found in the URI
529
 * @error: a pointer to a #GError, or %NULL
530
 *
531
 * Creates a new #GSocketConnectable for connecting to the given
532
 * @uri. May fail and return %NULL in case parsing @uri fails.
533
 *
534
 * Using this rather than g_network_address_new() or
535
 * g_network_address_parse() allows #GSocketClient to determine
536
 * when to use application-specific proxy protocols.
537
 *
538
 * Returns: (transfer full) (type GNetworkAddress): the new
539
 *   #GNetworkAddress, or %NULL on error
540
 *
541
 * Since: 2.26
542
 */
543
GSocketConnectable *
544
g_network_address_parse_uri (const gchar  *uri,
545
               guint16       default_port,
546
           GError      **error)
547
0
{
548
0
  GSocketConnectable *conn = NULL;
549
0
  gchar *scheme = NULL;
550
0
  gchar *hostname = NULL;
551
0
  gint port;
552
553
0
  if (!g_uri_split_network (uri, G_URI_FLAGS_NONE,
554
0
                            &scheme, &hostname, &port, NULL))
555
0
    {
556
0
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
557
0
                   "Invalid URI ‘%s’", uri);
558
0
      return NULL;
559
0
    }
560
561
0
  if (port <= 0)
562
0
    port = default_port;
563
564
0
  conn = g_object_new (G_TYPE_NETWORK_ADDRESS,
565
0
                       "hostname", hostname,
566
0
                       "port", (guint) port,
567
0
                       "scheme", scheme,
568
0
                       NULL);
569
0
  g_free (scheme);
570
0
  g_free (hostname);
571
572
0
  return conn;
573
0
}
574
575
/**
576
 * g_network_address_get_hostname:
577
 * @addr: a #GNetworkAddress
578
 *
579
 * Gets @addr's hostname. This might be either UTF-8 or ASCII-encoded,
580
 * depending on what @addr was created with.
581
 *
582
 * Returns: @addr's hostname
583
 *
584
 * Since: 2.22
585
 */
586
const gchar *
587
g_network_address_get_hostname (GNetworkAddress *addr)
588
0
{
589
0
  g_return_val_if_fail (G_IS_NETWORK_ADDRESS (addr), NULL);
590
591
0
  return addr->priv->hostname;
592
0
}
593
594
/**
595
 * g_network_address_get_port:
596
 * @addr: a #GNetworkAddress
597
 *
598
 * Gets @addr's port number
599
 *
600
 * Returns: @addr's port (which may be 0)
601
 *
602
 * Since: 2.22
603
 */
604
guint16
605
g_network_address_get_port (GNetworkAddress *addr)
606
0
{
607
0
  g_return_val_if_fail (G_IS_NETWORK_ADDRESS (addr), 0);
608
609
0
  return addr->priv->port;
610
0
}
611
612
/**
613
 * g_network_address_get_scheme:
614
 * @addr: a #GNetworkAddress
615
 *
616
 * Gets @addr's scheme
617
 *
618
 * Returns: (nullable): @addr's scheme (%NULL if not built from URI)
619
 *
620
 * Since: 2.26
621
 */
622
const gchar *
623
g_network_address_get_scheme (GNetworkAddress *addr)
624
0
{
625
0
  g_return_val_if_fail (G_IS_NETWORK_ADDRESS (addr), NULL);
626
627
0
  return addr->priv->scheme;
628
0
}
629
630
0
#define G_TYPE_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (_g_network_address_address_enumerator_get_type ())
631
0
#define G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_NETWORK_ADDRESS_ADDRESS_ENUMERATOR, GNetworkAddressAddressEnumerator))
632
633
typedef enum {
634
  RESOLVE_STATE_NONE = 0,
635
  RESOLVE_STATE_WAITING_ON_IPV4 = 1 << 0,
636
  RESOLVE_STATE_WAITING_ON_IPV6 = 1 << 1,
637
} ResolveState;
638
639
typedef struct {
640
  GSocketAddressEnumerator parent_instance;
641
642
  GNetworkAddress *addr; /* (owned) */
643
  GList *addresses; /* (owned) (nullable) */
644
  GList *current_item; /* (unowned) (nullable) */
645
  GTask *queued_task; /* (owned) (nullable) */
646
  GTask *waiting_task; /* (owned) (nullable) */
647
  GError *last_error; /* (owned) (nullable) */
648
  GSource *wait_source; /* (owned) (nullable) */
649
  GMainContext *context; /* (owned) (nullable) */
650
  ResolveState state;
651
} GNetworkAddressAddressEnumerator;
652
653
typedef struct {
654
  GSocketAddressEnumeratorClass parent_class;
655
656
} GNetworkAddressAddressEnumeratorClass;
657
658
static GType _g_network_address_address_enumerator_get_type (void);
659
G_DEFINE_TYPE (GNetworkAddressAddressEnumerator, _g_network_address_address_enumerator, G_TYPE_SOCKET_ADDRESS_ENUMERATOR)
660
661
static void
662
g_network_address_address_enumerator_finalize (GObject *object)
663
0
{
664
0
  GNetworkAddressAddressEnumerator *addr_enum =
665
0
    G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (object);
666
667
0
  if (addr_enum->wait_source)
668
0
    {
669
0
      g_source_destroy (addr_enum->wait_source);
670
0
      g_clear_pointer (&addr_enum->wait_source, g_source_unref);
671
0
    }
672
0
  g_clear_object (&addr_enum->queued_task);
673
0
  g_clear_object (&addr_enum->waiting_task);
674
0
  g_clear_error (&addr_enum->last_error);
675
0
  g_object_unref (addr_enum->addr);
676
0
  g_clear_pointer (&addr_enum->context, g_main_context_unref);
677
0
  g_list_free_full (addr_enum->addresses, g_object_unref);
678
679
0
  G_OBJECT_CLASS (_g_network_address_address_enumerator_parent_class)->finalize (object);
680
0
}
681
682
static inline GSocketFamily
683
get_address_family (GInetSocketAddress *address)
684
0
{
685
0
  return g_inet_address_get_family (g_inet_socket_address_get_address (address));
686
0
}
687
688
static void
689
list_split_families (GList  *list,
690
                     GList **out_ipv4,
691
                     GList **out_ipv6)
692
0
{
693
0
  g_assert (out_ipv4);
694
0
  g_assert (out_ipv6);
695
696
0
  while (list)
697
0
    {
698
0
      GSocketFamily family = get_address_family (list->data);
699
0
      switch (family)
700
0
        {
701
0
          case G_SOCKET_FAMILY_IPV4:
702
0
            *out_ipv4 = g_list_prepend (*out_ipv4, list->data);
703
0
            break;
704
0
          case G_SOCKET_FAMILY_IPV6:
705
0
            *out_ipv6 = g_list_prepend (*out_ipv6, list->data);
706
0
            break;
707
0
          case G_SOCKET_FAMILY_INVALID:
708
0
          case G_SOCKET_FAMILY_UNIX:
709
0
            g_assert_not_reached ();
710
0
        }
711
712
0
      list = g_list_next (list);
713
0
    }
714
715
0
  *out_ipv4 = g_list_reverse (*out_ipv4);
716
0
  *out_ipv6 = g_list_reverse (*out_ipv6);
717
0
}
718
719
static GList *
720
list_interleave_families (GList *list1,
721
                          GList *list2)
722
0
{
723
0
  GList *interleaved = NULL;
724
725
0
  while (list1 || list2)
726
0
    {
727
0
      if (list1)
728
0
        {
729
0
          interleaved = g_list_append (interleaved, list1->data);
730
0
          list1 = g_list_delete_link (list1, list1);
731
0
        }
732
0
      if (list2)
733
0
        {
734
0
          interleaved = g_list_append (interleaved, list2->data);
735
0
          list2 = g_list_delete_link (list2, list2);
736
0
        }
737
0
    }
738
739
0
  return interleaved;
740
0
}
741
742
/* list_copy_interleaved:
743
 * @list: (transfer container): List to copy
744
 *
745
 * Does a shallow copy of a list with address families interleaved.
746
 *
747
 * For example:
748
 *   Input: [ipv6, ipv6, ipv4, ipv4]
749
 *   Output: [ipv6, ipv4, ipv6, ipv4]
750
 *
751
 * Returns: (transfer container): A new list
752
 */
753
static GList *
754
list_copy_interleaved (GList *list)
755
0
{
756
0
  GList *ipv4 = NULL, *ipv6 = NULL;
757
758
0
  list_split_families (list, &ipv4, &ipv6);
759
0
  return list_interleave_families (ipv6, ipv4);
760
0
}
761
762
/* list_concat_interleaved:
763
 * @parent_list: (transfer container): Already existing list
764
 * @current_item: (transfer container): Item after which to resort
765
 * @new_list: (transfer container): New list to be interleaved and concatenated
766
 *
767
 * This differs from g_list_concat() + list_copy_interleaved() in that it sorts
768
 * items in the previous list starting from @current_item and concats the results
769
 * to @parent_list.
770
 *
771
 * Returns: (transfer container): New start of list
772
 */
773
static GList *
774
list_concat_interleaved (GList *parent_list,
775
                         GList *current_item,
776
                         GList *new_list)
777
0
{
778
0
  GList *ipv4 = NULL, *ipv6 = NULL, *interleaved, *trailing = NULL;
779
0
  GSocketFamily last_family = G_SOCKET_FAMILY_IPV4; /* Default to starting with ipv6 */
780
781
0
  if (current_item)
782
0
    {
783
0
      last_family = get_address_family (current_item->data);
784
785
      /* Unused addresses will get removed, resorted, then readded */
786
0
      trailing = g_list_next (current_item);
787
0
      current_item->next = NULL;
788
0
    }
789
790
0
  list_split_families (trailing, &ipv4, &ipv6);
791
0
  list_split_families (new_list, &ipv4, &ipv6);
792
0
  g_list_free (new_list);
793
794
0
  if (trailing)
795
0
    g_list_free (trailing);
796
797
0
  if (last_family == G_SOCKET_FAMILY_IPV4)
798
0
    interleaved = list_interleave_families (ipv6, ipv4);
799
0
  else
800
0
    interleaved = list_interleave_families (ipv4, ipv6);
801
802
0
  return g_list_concat (parent_list, interleaved);
803
0
}
804
805
static void
806
maybe_update_address_cache (GNetworkAddressAddressEnumerator *addr_enum,
807
                            GResolver                        *resolver)
808
0
{
809
0
  GList *addresses, *p;
810
811
  /* Only cache complete results */
812
0
  if (addr_enum->state & RESOLVE_STATE_WAITING_ON_IPV4 || addr_enum->state & RESOLVE_STATE_WAITING_ON_IPV6)
813
0
    return;
814
815
  /* The enumerators list will not necessarily be fully sorted */
816
0
  addresses = list_copy_interleaved (addr_enum->addresses);
817
0
  for (p = addresses; p; p = p->next)
818
0
    g_object_ref (p->data);
819
820
0
  g_network_address_set_cached_addresses (addr_enum->addr, g_steal_pointer (&addresses), g_resolver_get_serial (resolver));
821
0
}
822
823
static void
824
g_network_address_address_enumerator_add_addresses (GNetworkAddressAddressEnumerator *addr_enum,
825
                                                    GList                            *addresses,
826
                                                    GResolver                        *resolver)
827
0
{
828
0
  GList *new_addresses = inet_addresses_to_inet_socket_addresses (addr_enum->addr, addresses);
829
830
0
  if (addr_enum->addresses == NULL)
831
0
    addr_enum->addresses = g_steal_pointer (&new_addresses);
832
0
  else
833
0
    addr_enum->addresses = list_concat_interleaved (addr_enum->addresses, addr_enum->current_item, g_steal_pointer (&new_addresses));
834
835
0
  maybe_update_address_cache (addr_enum, resolver);
836
0
}
837
838
static gpointer
839
copy_object (gconstpointer src,
840
             gpointer      user_data)
841
0
{
842
0
  return g_object_ref (G_OBJECT (src));
843
0
}
844
845
static GSocketAddress *
846
init_and_query_next_address (GNetworkAddressAddressEnumerator *addr_enum)
847
0
{
848
0
  GList *next_item;
849
850
0
  if (addr_enum->addresses == NULL)
851
0
    addr_enum->addresses = g_list_copy_deep (addr_enum->addr->priv->cached_sockaddrs,
852
0
                                             copy_object, NULL);
853
854
  /* We always want to look at the next item at call time to get the latest results.
855
     That means that sometimes ->next is NULL this call but is valid next call.
856
   */
857
0
  if (addr_enum->current_item == NULL)
858
0
    next_item = addr_enum->current_item = addr_enum->addresses;
859
0
  else
860
0
    next_item = g_list_next (addr_enum->current_item);
861
862
0
  if (next_item)
863
0
    {
864
0
      addr_enum->current_item = next_item;
865
0
      return g_object_ref (addr_enum->current_item->data);
866
0
    }
867
0
  else
868
0
    return NULL;
869
0
}
870
871
static GSocketAddress *
872
g_network_address_address_enumerator_next (GSocketAddressEnumerator  *enumerator,
873
                                           GCancellable              *cancellable,
874
                                           GError                   **error)
875
0
{
876
0
  GNetworkAddressAddressEnumerator *addr_enum =
877
0
    G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (enumerator);
878
879
0
  if (addr_enum->addresses == NULL)
880
0
    {
881
0
      GNetworkAddress *addr = addr_enum->addr;
882
0
      GResolver *resolver = g_resolver_get_default ();
883
0
      gint64 serial = g_resolver_get_serial (resolver);
884
885
0
      if (addr->priv->resolver_serial != 0 &&
886
0
          addr->priv->resolver_serial != serial)
887
0
        {
888
          /* Resolver has reloaded, discard cached addresses */
889
0
          g_list_free_full (addr->priv->cached_sockaddrs, g_object_unref);
890
0
          addr->priv->cached_sockaddrs = NULL;
891
0
        }
892
893
0
      if (!addr->priv->cached_sockaddrs)
894
0
        g_network_address_parse_sockaddr (addr);
895
0
      if (!addr->priv->cached_sockaddrs)
896
0
        {
897
0
          GList *addresses;
898
899
0
          addresses = g_resolver_lookup_by_name (resolver,
900
0
                                                 addr->priv->hostname,
901
0
                                                 cancellable, error);
902
0
          if (!addresses)
903
0
            {
904
0
              g_object_unref (resolver);
905
0
              return NULL;
906
0
            }
907
908
0
          g_network_address_set_cached_addresses (addr, g_steal_pointer (&addresses), serial);
909
0
        }
910
911
0
      g_object_unref (resolver);
912
0
    }
913
914
0
  return init_and_query_next_address (addr_enum);
915
0
}
916
917
static void
918
complete_queued_task (GNetworkAddressAddressEnumerator *addr_enum,
919
                      GTask                            *task,
920
                      GError                           *error)
921
0
{
922
0
  if (error)
923
0
    g_task_return_error (task, error);
924
0
  else
925
0
    {
926
0
      GSocketAddress *sockaddr = init_and_query_next_address (addr_enum);
927
0
      g_task_return_pointer (task, g_steal_pointer (&sockaddr), g_object_unref);
928
0
    }
929
0
  g_object_unref (task);
930
0
}
931
932
static int
933
on_address_timeout (gpointer user_data)
934
0
{
935
0
  GNetworkAddressAddressEnumerator *addr_enum = user_data;
936
937
  /* Upon completion it may get unref'd by the owner */
938
0
  g_object_ref (addr_enum);
939
940
0
  if (addr_enum->queued_task != NULL)
941
0
      complete_queued_task (addr_enum, g_steal_pointer (&addr_enum->queued_task),
942
0
                            g_steal_pointer (&addr_enum->last_error));
943
0
  else if (addr_enum->waiting_task != NULL)
944
0
      complete_queued_task (addr_enum, g_steal_pointer (&addr_enum->waiting_task),
945
0
                            NULL);
946
947
0
  g_clear_pointer (&addr_enum->wait_source, g_source_unref);
948
0
  g_object_unref (addr_enum);
949
950
0
  return G_SOURCE_REMOVE;
951
0
}
952
953
static void
954
got_ipv6_addresses (GObject      *source_object,
955
                    GAsyncResult *result,
956
                    gpointer      user_data)
957
0
{
958
0
  GNetworkAddressAddressEnumerator *addr_enum = user_data;
959
0
  GResolver *resolver = G_RESOLVER (source_object);
960
0
  GList *addresses;
961
0
  GError *error = NULL;
962
963
0
  addr_enum->state ^= RESOLVE_STATE_WAITING_ON_IPV6;
964
965
0
  addresses = g_resolver_lookup_by_name_with_flags_finish (resolver, result, &error);
966
0
  if (!error)
967
0
    g_network_address_address_enumerator_add_addresses (addr_enum, g_steal_pointer (&addresses), resolver);
968
0
  else
969
0
    g_debug ("IPv6 DNS error: %s", error->message);
970
971
  /* If ipv4 was first and waiting on us it can stop waiting */
972
0
  if (addr_enum->wait_source)
973
0
    {
974
0
      g_source_destroy (addr_enum->wait_source);
975
0
      g_clear_pointer (&addr_enum->wait_source, g_source_unref);
976
0
    }
977
978
  /* If we got an error before ipv4 then let its response handle it.
979
   * If we get ipv6 response first or error second then
980
   * immediately complete the task.
981
   */
982
0
  if (error != NULL && !addr_enum->last_error && (addr_enum->state & RESOLVE_STATE_WAITING_ON_IPV4))
983
0
    {
984
      /* ipv6 lookup failed, but ipv4 is still outstanding.  wait. */
985
0
      addr_enum->last_error = g_steal_pointer (&error);
986
0
    }
987
0
  else if (addr_enum->waiting_task != NULL)
988
0
    {
989
0
      complete_queued_task (addr_enum, g_steal_pointer (&addr_enum->waiting_task), NULL);
990
0
    }
991
0
  else if (addr_enum->queued_task != NULL)
992
0
    {
993
0
      GError *task_error = NULL;
994
995
      /* If both errored just use the ipv6 one,
996
         but if ipv6 errored and ipv4 didn't we don't error */
997
0
      if (error != NULL && addr_enum->last_error)
998
0
          task_error = g_steal_pointer (&error);
999
1000
0
      g_clear_error (&addr_enum->last_error);
1001
0
      complete_queued_task (addr_enum, g_steal_pointer (&addr_enum->queued_task),
1002
0
                            g_steal_pointer (&task_error));
1003
0
    }
1004
1005
0
  g_clear_error (&error);
1006
0
  g_object_unref (addr_enum);
1007
0
}
1008
1009
static void
1010
got_ipv4_addresses (GObject      *source_object,
1011
                    GAsyncResult *result,
1012
                    gpointer      user_data)
1013
0
{
1014
0
  GNetworkAddressAddressEnumerator *addr_enum = user_data;
1015
0
  GResolver *resolver = G_RESOLVER (source_object);
1016
0
  GList *addresses;
1017
0
  GError *error = NULL;
1018
1019
0
  addr_enum->state ^= RESOLVE_STATE_WAITING_ON_IPV4;
1020
1021
0
  addresses = g_resolver_lookup_by_name_with_flags_finish (resolver, result, &error);
1022
0
  if (!error)
1023
0
    g_network_address_address_enumerator_add_addresses (addr_enum, g_steal_pointer (&addresses), resolver);
1024
0
  else
1025
0
    g_debug ("IPv4 DNS error: %s", error->message);
1026
1027
0
  if (addr_enum->wait_source)
1028
0
    {
1029
0
      g_source_destroy (addr_enum->wait_source);
1030
0
      g_clear_pointer (&addr_enum->wait_source, g_source_unref);
1031
0
    }
1032
1033
  /* If ipv6 already came in and errored then we return.
1034
   * If ipv6 returned successfully then we don't need to do anything unless
1035
   * another enumeration was waiting on us.
1036
   * If ipv6 hasn't come we should wait a short while for it as RFC 8305 suggests.
1037
   */
1038
0
  if (addr_enum->last_error)
1039
0
    {
1040
0
      g_assert (addr_enum->queued_task);
1041
0
      g_clear_error (&addr_enum->last_error);
1042
0
      complete_queued_task (addr_enum, g_steal_pointer (&addr_enum->queued_task),
1043
0
                            g_steal_pointer (&error));
1044
0
    }
1045
0
  else if (addr_enum->waiting_task != NULL)
1046
0
    {
1047
0
      complete_queued_task (addr_enum, g_steal_pointer (&addr_enum->waiting_task), NULL);
1048
0
    }
1049
0
  else if (addr_enum->queued_task != NULL)
1050
0
    {
1051
0
      addr_enum->last_error = g_steal_pointer (&error);
1052
0
      addr_enum->wait_source = g_timeout_source_new (HAPPY_EYEBALLS_RESOLUTION_DELAY_MS);
1053
0
      g_source_set_callback (addr_enum->wait_source,
1054
0
                             on_address_timeout,
1055
0
                             addr_enum, NULL);
1056
0
      g_source_attach (addr_enum->wait_source, addr_enum->context);
1057
0
    }
1058
1059
0
  g_clear_error (&error);
1060
0
  g_object_unref (addr_enum);
1061
0
}
1062
1063
static void
1064
g_network_address_address_enumerator_next_async (GSocketAddressEnumerator  *enumerator,
1065
                                                 GCancellable              *cancellable,
1066
                                                 GAsyncReadyCallback        callback,
1067
                                                 gpointer                   user_data)
1068
0
{
1069
0
  GNetworkAddressAddressEnumerator *addr_enum =
1070
0
    G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (enumerator);
1071
0
  GSocketAddress *sockaddr;
1072
0
  GTask *task;
1073
1074
0
  task = g_task_new (addr_enum, cancellable, callback, user_data);
1075
0
  g_task_set_source_tag (task, g_network_address_address_enumerator_next_async);
1076
1077
0
  if (addr_enum->addresses == NULL && addr_enum->state == RESOLVE_STATE_NONE)
1078
0
    {
1079
0
      GNetworkAddress *addr = addr_enum->addr;
1080
0
      GResolver *resolver = g_resolver_get_default ();
1081
0
      gint64 serial = g_resolver_get_serial (resolver);
1082
1083
0
      if (addr->priv->resolver_serial != 0 &&
1084
0
          addr->priv->resolver_serial != serial)
1085
0
        {
1086
          /* Resolver has reloaded, discard cached addresses */
1087
0
          g_list_free_full (addr->priv->cached_sockaddrs, g_object_unref);
1088
0
          addr->priv->cached_sockaddrs = NULL;
1089
0
        }
1090
1091
0
      if (addr->priv->cached_sockaddrs == NULL)
1092
0
        {
1093
0
          if (g_network_address_parse_sockaddr (addr))
1094
0
            complete_queued_task (addr_enum, task, NULL);
1095
0
          else
1096
0
            {
1097
              /* It does not make sense for this to be called multiple
1098
               * times before the initial callback has been called */
1099
0
              g_assert (addr_enum->queued_task == NULL);
1100
1101
0
              addr_enum->state = RESOLVE_STATE_WAITING_ON_IPV4 | RESOLVE_STATE_WAITING_ON_IPV6;
1102
0
              addr_enum->queued_task = g_steal_pointer (&task);
1103
              /* Look up in parallel as per RFC 8305 */
1104
0
              g_resolver_lookup_by_name_with_flags_async (resolver,
1105
0
                                                          addr->priv->hostname,
1106
0
                                                          G_RESOLVER_NAME_LOOKUP_FLAGS_IPV6_ONLY,
1107
0
                                                          cancellable,
1108
0
                                                          got_ipv6_addresses, g_object_ref (addr_enum));
1109
0
              g_resolver_lookup_by_name_with_flags_async (resolver,
1110
0
                                                          addr->priv->hostname,
1111
0
                                                          G_RESOLVER_NAME_LOOKUP_FLAGS_IPV4_ONLY,
1112
0
                                                          cancellable,
1113
0
                                                          got_ipv4_addresses, g_object_ref (addr_enum));
1114
0
            }
1115
0
          g_object_unref (resolver);
1116
0
          return;
1117
0
        }
1118
1119
0
      g_object_unref (resolver);
1120
0
    }
1121
1122
0
  sockaddr = init_and_query_next_address (addr_enum);
1123
0
  if (sockaddr == NULL && (addr_enum->state & RESOLVE_STATE_WAITING_ON_IPV4 ||
1124
0
                           addr_enum->state & RESOLVE_STATE_WAITING_ON_IPV6))
1125
0
    {
1126
0
      addr_enum->waiting_task = task;
1127
0
    }
1128
0
  else
1129
0
    {
1130
0
      g_task_return_pointer (task, sockaddr, g_object_unref);
1131
0
      g_object_unref (task);
1132
0
    }
1133
0
}
1134
1135
static GSocketAddress *
1136
g_network_address_address_enumerator_next_finish (GSocketAddressEnumerator  *enumerator,
1137
                                                  GAsyncResult              *result,
1138
                                                  GError                   **error)
1139
0
{
1140
0
  g_return_val_if_fail (g_task_is_valid (result, enumerator), NULL);
1141
1142
0
  return g_task_propagate_pointer (G_TASK (result), error);
1143
0
}
1144
1145
static void
1146
_g_network_address_address_enumerator_init (GNetworkAddressAddressEnumerator *enumerator)
1147
0
{
1148
0
  enumerator->context = g_main_context_ref_thread_default ();
1149
0
}
1150
1151
static void
1152
_g_network_address_address_enumerator_class_init (GNetworkAddressAddressEnumeratorClass *addrenum_class)
1153
0
{
1154
0
  GObjectClass *object_class = G_OBJECT_CLASS (addrenum_class);
1155
0
  GSocketAddressEnumeratorClass *enumerator_class =
1156
0
    G_SOCKET_ADDRESS_ENUMERATOR_CLASS (addrenum_class);
1157
1158
0
  enumerator_class->next = g_network_address_address_enumerator_next;
1159
0
  enumerator_class->next_async = g_network_address_address_enumerator_next_async;
1160
0
  enumerator_class->next_finish = g_network_address_address_enumerator_next_finish;
1161
0
  object_class->finalize = g_network_address_address_enumerator_finalize;
1162
0
}
1163
1164
static GSocketAddressEnumerator *
1165
g_network_address_connectable_enumerate (GSocketConnectable *connectable)
1166
0
{
1167
0
  GNetworkAddressAddressEnumerator *addr_enum;
1168
1169
0
  addr_enum = g_object_new (G_TYPE_NETWORK_ADDRESS_ADDRESS_ENUMERATOR, NULL);
1170
0
  addr_enum->addr = g_object_ref (G_NETWORK_ADDRESS (connectable));
1171
1172
0
  return (GSocketAddressEnumerator *)addr_enum;
1173
0
}
1174
1175
static GSocketAddressEnumerator *
1176
g_network_address_connectable_proxy_enumerate (GSocketConnectable *connectable)
1177
0
{
1178
0
  GNetworkAddress *self = G_NETWORK_ADDRESS (connectable);
1179
0
  GSocketAddressEnumerator *proxy_enum;
1180
0
  gchar *uri;
1181
1182
0
  uri = g_uri_join (G_URI_FLAGS_NONE,
1183
0
                    self->priv->scheme ? self->priv->scheme : "none",
1184
0
                    NULL,
1185
0
                    self->priv->hostname,
1186
0
                    self->priv->port,
1187
0
                    "",
1188
0
                    NULL,
1189
0
                    NULL);
1190
1191
0
  proxy_enum = g_object_new (G_TYPE_PROXY_ADDRESS_ENUMERATOR,
1192
0
                             "connectable", connectable,
1193
0
                             "uri", uri,
1194
0
                             NULL);
1195
1196
0
  g_free (uri);
1197
1198
0
  return proxy_enum;
1199
0
}
1200
1201
static gchar *
1202
g_network_address_connectable_to_string (GSocketConnectable *connectable)
1203
0
{
1204
0
  GNetworkAddress *addr;
1205
0
  const gchar *scheme;
1206
0
  guint16 port;
1207
0
  GString *out;  /* owned */
1208
1209
0
  addr = G_NETWORK_ADDRESS (connectable);
1210
0
  out = g_string_new ("");
1211
1212
0
  scheme = g_network_address_get_scheme (addr);
1213
0
  if (scheme != NULL)
1214
0
    g_string_append_printf (out, "%s:", scheme);
1215
1216
0
  g_string_append (out, g_network_address_get_hostname (addr));
1217
1218
0
  port = g_network_address_get_port (addr);
1219
0
  if (port != 0)
1220
0
    g_string_append_printf (out, ":%u", port);
1221
1222
0
  return g_string_free (out, FALSE);
1223
0
}