[kdbus] Do not set body message if signature field is empty
[platform/upstream/glib.git] / gio / gnetworkaddress.c
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  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General
18  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include "config.h"
22 #include <glib.h>
23 #include "glibintl.h"
24
25 #include <stdlib.h>
26 #include "gnetworkaddress.h"
27 #include "gasyncresult.h"
28 #include "ginetaddress.h"
29 #include "ginetsocketaddress.h"
30 #include "gnetworkingprivate.h"
31 #include "gproxyaddressenumerator.h"
32 #include "gresolver.h"
33 #include "gtask.h"
34 #include "gsocketaddressenumerator.h"
35 #include "gioerror.h"
36 #include "gsocketconnectable.h"
37
38 #include <string.h>
39
40
41 /**
42  * SECTION:gnetworkaddress
43  * @short_description: A GSocketConnectable for resolving hostnames
44  * @include: gio/gio.h
45  *
46  * #GNetworkAddress provides an easy way to resolve a hostname and
47  * then attempt to connect to that host, handling the possibility of
48  * multiple IP addresses and multiple address families.
49  *
50  * See #GSocketConnectable for and example of using the connectable
51  * interface.
52  */
53
54 /**
55  * GNetworkAddress:
56  *
57  * A #GSocketConnectable for resolving a hostname and connecting to
58  * that host.
59  */
60
61 struct _GNetworkAddressPrivate {
62   gchar *hostname;
63   guint16 port;
64   GList *sockaddrs;
65   gchar *scheme;
66
67   gint64 resolver_serial;
68 };
69
70 enum {
71   PROP_0,
72   PROP_HOSTNAME,
73   PROP_PORT,
74   PROP_SCHEME,
75 };
76
77 static void g_network_address_set_property (GObject      *object,
78                                             guint         prop_id,
79                                             const GValue *value,
80                                             GParamSpec   *pspec);
81 static void g_network_address_get_property (GObject      *object,
82                                             guint         prop_id,
83                                             GValue       *value,
84                                             GParamSpec   *pspec);
85
86 static void                      g_network_address_connectable_iface_init       (GSocketConnectableIface *iface);
87 static GSocketAddressEnumerator *g_network_address_connectable_enumerate        (GSocketConnectable      *connectable);
88 static GSocketAddressEnumerator *g_network_address_connectable_proxy_enumerate  (GSocketConnectable      *connectable);
89
90 G_DEFINE_TYPE_WITH_CODE (GNetworkAddress, g_network_address, G_TYPE_OBJECT,
91                          G_ADD_PRIVATE (GNetworkAddress)
92                          G_IMPLEMENT_INTERFACE (G_TYPE_SOCKET_CONNECTABLE,
93                                                 g_network_address_connectable_iface_init))
94
95 static void
96 g_network_address_finalize (GObject *object)
97 {
98   GNetworkAddress *addr = G_NETWORK_ADDRESS (object);
99
100   g_free (addr->priv->hostname);
101   g_free (addr->priv->scheme);
102
103   if (addr->priv->sockaddrs)
104     {
105       GList *a;
106
107       for (a = addr->priv->sockaddrs; a; a = a->next)
108         g_object_unref (a->data);
109       g_list_free (addr->priv->sockaddrs);
110     }
111
112   G_OBJECT_CLASS (g_network_address_parent_class)->finalize (object);
113 }
114
115 static void
116 g_network_address_class_init (GNetworkAddressClass *klass)
117 {
118   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
119
120   gobject_class->set_property = g_network_address_set_property;
121   gobject_class->get_property = g_network_address_get_property;
122   gobject_class->finalize = g_network_address_finalize;
123
124   g_object_class_install_property (gobject_class, PROP_HOSTNAME,
125                                    g_param_spec_string ("hostname",
126                                                         P_("Hostname"),
127                                                         P_("Hostname to resolve"),
128                                                         NULL,
129                                                         G_PARAM_READWRITE |
130                                                         G_PARAM_CONSTRUCT_ONLY |
131                                                         G_PARAM_STATIC_STRINGS));
132   g_object_class_install_property (gobject_class, PROP_PORT,
133                                    g_param_spec_uint ("port",
134                                                       P_("Port"),
135                                                       P_("Network port"),
136                                                       0, 65535, 0,
137                                                       G_PARAM_READWRITE |
138                                                       G_PARAM_CONSTRUCT_ONLY |
139                                                       G_PARAM_STATIC_STRINGS));
140
141   g_object_class_install_property (gobject_class, PROP_SCHEME,
142                                    g_param_spec_string ("scheme",
143                                                         P_("Scheme"),
144                                                         P_("URI Scheme"),
145                                                         NULL,
146                                                         G_PARAM_READWRITE |
147                                                         G_PARAM_CONSTRUCT_ONLY |
148                                                         G_PARAM_STATIC_STRINGS));
149 }
150
151 static void
152 g_network_address_connectable_iface_init (GSocketConnectableIface *connectable_iface)
153 {
154   connectable_iface->enumerate  = g_network_address_connectable_enumerate;
155   connectable_iface->proxy_enumerate = g_network_address_connectable_proxy_enumerate;
156 }
157
158 static void
159 g_network_address_init (GNetworkAddress *addr)
160 {
161   addr->priv = g_network_address_get_instance_private (addr);
162 }
163
164 static void
165 g_network_address_set_property (GObject      *object,
166                                 guint         prop_id,
167                                 const GValue *value,
168                                 GParamSpec   *pspec)
169 {
170   GNetworkAddress *addr = G_NETWORK_ADDRESS (object);
171
172   switch (prop_id)
173     {
174     case PROP_HOSTNAME:
175       g_free (addr->priv->hostname);
176       addr->priv->hostname = g_value_dup_string (value);
177       break;
178
179     case PROP_PORT:
180       addr->priv->port = g_value_get_uint (value);
181       break;
182
183     case PROP_SCHEME:
184       g_free (addr->priv->scheme);
185       addr->priv->scheme = g_value_dup_string (value);
186       break;
187
188     default:
189       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
190       break;
191     }
192
193 }
194
195 static void
196 g_network_address_get_property (GObject    *object,
197                                 guint       prop_id,
198                                 GValue     *value,
199                                 GParamSpec *pspec)
200 {
201   GNetworkAddress *addr = G_NETWORK_ADDRESS (object);
202
203   switch (prop_id)
204     {
205     case PROP_HOSTNAME:
206       g_value_set_string (value, addr->priv->hostname);
207       break;
208
209     case PROP_PORT:
210       g_value_set_uint (value, addr->priv->port);
211       break;
212
213     case PROP_SCHEME:
214       g_value_set_string (value, addr->priv->scheme);
215       break;
216
217     default:
218       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
219       break;
220     }
221
222 }
223
224 static void
225 g_network_address_set_addresses (GNetworkAddress *addr,
226                                  GList           *addresses,
227                                  guint64          resolver_serial)
228 {
229   GList *a;
230   GSocketAddress *sockaddr;
231
232   g_return_if_fail (addresses != NULL && addr->priv->sockaddrs == NULL);
233
234   for (a = addresses; a; a = a->next)
235     {
236       sockaddr = g_inet_socket_address_new (a->data, addr->priv->port);
237       addr->priv->sockaddrs = g_list_prepend (addr->priv->sockaddrs, sockaddr);
238       g_object_unref (a->data);
239     }
240   g_list_free (addresses);
241   addr->priv->sockaddrs = g_list_reverse (addr->priv->sockaddrs);
242
243   addr->priv->resolver_serial = resolver_serial;
244 }
245
246 static gboolean
247 g_network_address_parse_sockaddr (GNetworkAddress *addr)
248 {
249   GSocketAddress *sockaddr;
250
251   sockaddr = g_inet_socket_address_new_from_string (addr->priv->hostname,
252                                                     addr->priv->port);
253   if (sockaddr)
254     {
255       addr->priv->sockaddrs = g_list_prepend (addr->priv->sockaddrs, sockaddr);
256       return TRUE;
257     }
258   else
259     return FALSE;
260 }
261
262 /**
263  * g_network_address_new:
264  * @hostname: the hostname
265  * @port: the port
266  *
267  * Creates a new #GSocketConnectable for connecting to the given
268  * @hostname and @port.
269  *
270  * Note that depending on the configuration of the machine, a
271  * @hostname of `localhost` may refer to the IPv4 loopback address
272  * only, or to both IPv4 and IPv6; use
273  * g_network_address_new_loopback() to create a #GNetworkAddress that
274  * is guaranteed to resolve to both addresses.
275  *
276  * Returns: (transfer full) (type GNetworkAddress): the new #GNetworkAddress
277  *
278  * Since: 2.22
279  */
280 GSocketConnectable *
281 g_network_address_new (const gchar *hostname,
282                        guint16      port)
283 {
284   return g_object_new (G_TYPE_NETWORK_ADDRESS,
285                        "hostname", hostname,
286                        "port", port,
287                        NULL);
288 }
289
290 /**
291  * g_network_address_new_loopback:
292  * @port: the port
293  *
294  * Creates a new #GSocketConnectable for connecting to the local host
295  * over a loopback connection to the given @port. This is intended for
296  * use in connecting to local services which may be running on IPv4 or
297  * IPv6.
298  *
299  * The connectable will return IPv4 and IPv6 loopback addresses,
300  * regardless of how the host resolves `localhost`. By contrast,
301  * g_network_address_new() will often only return an IPv4 address when
302  * resolving `localhost`, and an IPv6 address for `localhost6`.
303  *
304  * g_network_address_get_hostname() will always return `localhost` for
305  * #GNetworkAddresses created with this constructor.
306  *
307  * Returns: (transfer full) (type GNetworkAddress): the new #GNetworkAddress
308  *
309  * Since: 2.44
310  */
311 GSocketConnectable *
312 g_network_address_new_loopback (guint16 port)
313 {
314   GNetworkAddress *addr;
315   GList *addrs = NULL;
316
317   addr = g_object_new (G_TYPE_NETWORK_ADDRESS,
318                        "hostname", "localhost",
319                        "port", port,
320                        NULL);
321
322   addrs = g_list_append (addrs, g_inet_address_new_loopback (AF_INET6));
323   addrs = g_list_append (addrs, g_inet_address_new_loopback (AF_INET));
324   g_network_address_set_addresses (addr, addrs, 0);
325
326   return G_SOCKET_CONNECTABLE (addr);
327 }
328
329 /**
330  * g_network_address_parse:
331  * @host_and_port: the hostname and optionally a port
332  * @default_port: the default port if not in @host_and_port
333  * @error: a pointer to a #GError, or %NULL
334  *
335  * Creates a new #GSocketConnectable for connecting to the given
336  * @hostname and @port. May fail and return %NULL in case
337  * parsing @host_and_port fails.
338  *
339  * @host_and_port may be in any of a number of recognised formats; an IPv6
340  * address, an IPv4 address, or a domain name (in which case a DNS
341  * lookup is performed). Quoting with [] is supported for all address
342  * types. A port override may be specified in the usual way with a
343  * colon.
344  *
345  * If no port is specified in @host_and_port then @default_port will be
346  * used as the port number to connect to.
347  *
348  * In general, @host_and_port is expected to be provided by the user
349  * (allowing them to give the hostname, and a port overide if necessary)
350  * and @default_port is expected to be provided by the application.
351  *
352  * (The port component of @host_and_port can also be specified as a
353  * service name rather than as a numeric port, but this functionality
354  * is deprecated, because it depends on the contents of /etc/services,
355  * which is generally quite sparse on platforms other than Linux.)
356  *
357  * Returns: (transfer full): the new #GNetworkAddress, or %NULL on error
358  *
359  * Since: 2.22
360  */
361 GSocketConnectable *
362 g_network_address_parse (const gchar  *host_and_port,
363                          guint16       default_port,
364                          GError      **error)
365 {
366   GSocketConnectable *connectable;
367   const gchar *port;
368   guint16 portnum;
369   gchar *name;
370
371   g_return_val_if_fail (host_and_port != NULL, NULL);
372
373   port = NULL;
374   if (host_and_port[0] == '[')
375     /* escaped host part (to allow, eg. "[2001:db8::1]:888") */
376     {
377       const gchar *end;
378
379       end = strchr (host_and_port, ']');
380       if (end == NULL)
381         {
382           g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
383                        _("Hostname '%s' contains '[' but not ']'"), host_and_port);
384           return NULL;
385         }
386
387       if (end[1] == '\0')
388         port = NULL;
389       else if (end[1] == ':')
390         port = &end[2];
391       else
392         {
393           g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
394                        "The ']' character (in hostname '%s') must come at the"
395                        " end or be immediately followed by ':' and a port",
396                        host_and_port);
397           return NULL;
398         }
399
400       name = g_strndup (host_and_port + 1, end - host_and_port - 1);
401     }
402
403   else if ((port = strchr (host_and_port, ':')))
404     /* string has a ':' in it */
405     {
406       /* skip ':' */
407       port++;
408
409       if (strchr (port, ':'))
410         /* more than one ':' in string */
411         {
412           /* this is actually an unescaped IPv6 address */
413           name = g_strdup (host_and_port);
414           port = NULL;
415         }
416       else
417         name = g_strndup (host_and_port, port - host_and_port - 1);
418     }
419
420   else
421     /* plain hostname, no port */
422     name = g_strdup (host_and_port);
423
424   if (port != NULL)
425     {
426       if (port[0] == '\0')
427         {
428           g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
429                        "If a ':' character is given, it must be followed by a "
430                        "port (in hostname '%s').", host_and_port);
431           g_free (name);
432           return NULL;
433         }
434
435       else if ('0' <= port[0] && port[0] <= '9')
436         {
437           char *end;
438           long value;
439
440           value = strtol (port, &end, 10);
441           if (*end != '\0' || value < 0 || value > G_MAXUINT16)
442             {
443               g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
444                            "Invalid numeric port '%s' specified in hostname '%s'",
445                            port, host_and_port);
446               g_free (name);
447               return NULL;
448             }
449
450           portnum = value;
451         }
452
453       else
454         {
455           struct servent *entry;
456
457           entry = getservbyname (port, "tcp");
458           if (entry == NULL)
459             {
460               g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
461                            "Unknown service '%s' specified in hostname '%s'",
462                            port, host_and_port);
463 #ifdef HAVE_ENDSERVENT
464               endservent ();
465 #endif
466               g_free (name);
467               return NULL;
468             }
469
470           portnum = g_ntohs (entry->s_port);
471
472 #ifdef HAVE_ENDSERVENT
473           endservent ();
474 #endif
475         }
476     }
477   else
478     {
479       /* No port in host_and_port */
480       portnum = default_port;
481     }
482
483   connectable = g_network_address_new (name, portnum);
484   g_free (name);
485
486   return connectable;
487 }
488
489 /* Allowed characters outside alphanumeric for unreserved. */
490 #define G_URI_OTHER_UNRESERVED "-._~"
491
492 /* This or something equivalent will eventually go into glib/guri.h */
493 gboolean
494 _g_uri_parse_authority (const char  *uri,
495                         char       **host,
496                         guint16     *port,
497                         char       **userinfo)
498 {
499   char *tmp_str;
500   const char *start, *p, *at, *delim;
501   char c;
502
503   g_return_val_if_fail (uri != NULL, FALSE);
504
505   if (host)
506     *host = NULL;
507
508   if (port)
509     *port = 0;
510
511   if (userinfo)
512     *userinfo = NULL;
513
514   /* From RFC 3986 Decodes:
515    * URI          = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
516    * hier-part    = "//" authority path-abempty
517    * path-abempty = *( "/" segment )
518    * authority    = [ userinfo "@" ] host [ ":" port ]
519    */
520
521   /* Check we have a valid scheme */
522   tmp_str = g_uri_parse_scheme (uri);
523
524   if (tmp_str == NULL)
525     return FALSE;
526
527   g_free (tmp_str);
528
529   /* Decode hier-part:
530    *  hier-part   = "//" authority path-abempty
531    */
532   p = uri;
533   start = strstr (p, "//");
534
535   if (start == NULL)
536     return FALSE;
537
538   start += 2;
539
540   /* check if the @ sign is part of the authority before attempting to
541    * decode the userinfo */
542   delim = strpbrk (start, "/?#[]");
543   at = strchr (start, '@');
544   if (at && delim && at > delim)
545     at = NULL;
546
547   if (at != NULL)
548     {
549       /* Decode userinfo:
550        * userinfo      = *( unreserved / pct-encoded / sub-delims / ":" )
551        * unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
552        * pct-encoded   = "%" HEXDIG HEXDIG
553        */
554       p = start;
555       while (1)
556         {
557           c = *p++;
558
559           if (c == '@')
560             break;
561
562           /* pct-encoded */
563           if (c == '%')
564             {
565               if (!(g_ascii_isxdigit (p[0]) ||
566                     g_ascii_isxdigit (p[1])))
567                 return FALSE;
568
569               p++;
570
571               continue;
572             }
573
574           /* unreserved /  sub-delims / : */
575           if (!(g_ascii_isalnum (c) ||
576                 strchr (G_URI_OTHER_UNRESERVED, c) ||
577                 strchr (G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS, c) ||
578                 c == ':'))
579             return FALSE;
580         }
581
582       if (userinfo)
583         *userinfo = g_strndup (start, p - start - 1);
584
585       start = p;
586     }
587   else
588     {
589       p = start;
590     }
591
592
593   /* decode host:
594    * host          = IP-literal / IPv4address / reg-name
595    * reg-name      = *( unreserved / pct-encoded / sub-delims )
596    */
597
598   /* If IPv6 or IPvFuture */
599   if (*p == '[')
600     {
601       gboolean has_scope_id = FALSE, has_bad_scope_id = FALSE;
602
603       start++;
604       p++;
605       while (1)
606         {
607           c = *p++;
608
609           if (c == ']')
610             break;
611
612           if (c == '%' && !has_scope_id)
613             {
614               has_scope_id = TRUE;
615               if (p[0] != '2' || p[1] != '5')
616                 has_bad_scope_id = TRUE;
617               continue;
618             }
619
620           /* unreserved /  sub-delims */
621           if (!(g_ascii_isalnum (c) ||
622                 strchr (G_URI_OTHER_UNRESERVED, c) ||
623                 strchr (G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS, c) ||
624                 c == ':' ||
625                 c == '.'))
626             goto error;
627         }
628
629       if (host)
630         {
631           if (has_bad_scope_id)
632             *host = g_strndup (start, p - start - 1);
633           else
634             *host = g_uri_unescape_segment (start, p - 1, NULL);
635         }
636
637       c = *p++;
638     }
639   else
640     {
641       while (1)
642         {
643           c = *p++;
644
645           if (c == ':' ||
646               c == '/' ||
647               c == '?' ||
648               c == '#' ||
649               c == '\0')
650             break;
651
652           /* pct-encoded */
653           if (c == '%')
654             {
655               if (!(g_ascii_isxdigit (p[0]) ||
656                     g_ascii_isxdigit (p[1])))
657                 goto error;
658
659               p++;
660
661               continue;
662             }
663
664           /* unreserved /  sub-delims */
665           if (!(g_ascii_isalnum (c) ||
666                 strchr (G_URI_OTHER_UNRESERVED, c) ||
667                 strchr (G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS, c)))
668             goto error;
669         }
670
671       if (host)
672         *host = g_uri_unescape_segment (start, p - 1, NULL);
673     }
674
675   if (c == ':')
676     {
677       /* Decode port:
678        *  port          = *DIGIT
679        */
680       guint tmp = 0;
681
682       while (1)
683         {
684           c = *p++;
685
686           if (c == '/' ||
687               c == '?' ||
688               c == '#' ||
689               c == '\0')
690             break;
691
692           if (!g_ascii_isdigit (c))
693             goto error;
694
695           tmp = (tmp * 10) + (c - '0');
696
697           if (tmp > 65535)
698             goto error;
699         }
700       if (port)
701         *port = (guint16) tmp;
702     }
703
704   return TRUE;
705
706 error:
707   if (host && *host)
708     {
709       g_free (*host);
710       *host = NULL;
711     }
712
713   if (userinfo && *userinfo)
714     {
715       g_free (*userinfo);
716       *userinfo = NULL;
717     }
718
719   return FALSE;
720 }
721
722 gchar *
723 _g_uri_from_authority (const gchar *protocol,
724                        const gchar *host,
725                        guint        port,
726                        const gchar *userinfo)
727 {
728   GString *uri;
729
730   uri = g_string_new (protocol);
731   g_string_append (uri, "://");
732
733   if (userinfo)
734     {
735       g_string_append_uri_escaped (uri, userinfo, G_URI_RESERVED_CHARS_ALLOWED_IN_USERINFO, FALSE);
736       g_string_append_c (uri, '@');
737     }
738
739   if (g_hostname_is_non_ascii (host))
740     {
741       gchar *ace_encoded = g_hostname_to_ascii (host);
742
743       if (!ace_encoded)
744         {
745           g_string_free (uri, TRUE);
746           return NULL;
747         }
748       g_string_append (uri, ace_encoded);
749       g_free (ace_encoded);
750     }
751   else if (strchr (host, ':'))
752     g_string_append_printf (uri, "[%s]", host);
753   else
754     g_string_append (uri, host);
755
756   if (port != 0)
757     g_string_append_printf (uri, ":%u", port);
758
759   return g_string_free (uri, FALSE);
760 }
761
762 /**
763  * g_network_address_parse_uri:
764  * @uri: the hostname and optionally a port
765  * @default_port: The default port if none is found in the URI
766  * @error: a pointer to a #GError, or %NULL
767  *
768  * Creates a new #GSocketConnectable for connecting to the given
769  * @uri. May fail and return %NULL in case parsing @uri fails.
770  *
771  * Using this rather than g_network_address_new() or
772  * g_network_address_parse() allows #GSocketClient to determine
773  * when to use application-specific proxy protocols.
774  *
775  * Returns: (transfer full): the new #GNetworkAddress, or %NULL on error
776  *
777  * Since: 2.26
778  */
779 GSocketConnectable *
780 g_network_address_parse_uri (const gchar  *uri,
781                              guint16       default_port,
782                              GError      **error)
783 {
784   GSocketConnectable *conn;
785   gchar *scheme;
786   gchar *hostname;
787   guint16 port;
788
789   if (!_g_uri_parse_authority (uri, &hostname, &port, NULL))
790     {
791       g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
792                    "Invalid URI '%s'",
793                    uri);
794       return NULL;
795     }
796
797   if (port == 0)
798     port = default_port;
799
800   scheme = g_uri_parse_scheme (uri);
801
802   conn = g_object_new (G_TYPE_NETWORK_ADDRESS,
803                        "hostname", hostname,
804                        "port", port,
805                        "scheme", scheme,
806                        NULL);
807
808   g_free (scheme);
809   g_free (hostname);
810
811   return conn;
812 }
813
814 /**
815  * g_network_address_get_hostname:
816  * @addr: a #GNetworkAddress
817  *
818  * Gets @addr's hostname. This might be either UTF-8 or ASCII-encoded,
819  * depending on what @addr was created with.
820  *
821  * Returns: @addr's hostname
822  *
823  * Since: 2.22
824  */
825 const gchar *
826 g_network_address_get_hostname (GNetworkAddress *addr)
827 {
828   g_return_val_if_fail (G_IS_NETWORK_ADDRESS (addr), NULL);
829
830   return addr->priv->hostname;
831 }
832
833 /**
834  * g_network_address_get_port:
835  * @addr: a #GNetworkAddress
836  *
837  * Gets @addr's port number
838  *
839  * Returns: @addr's port (which may be 0)
840  *
841  * Since: 2.22
842  */
843 guint16
844 g_network_address_get_port (GNetworkAddress *addr)
845 {
846   g_return_val_if_fail (G_IS_NETWORK_ADDRESS (addr), 0);
847
848   return addr->priv->port;
849 }
850
851 /**
852  * g_network_address_get_scheme:
853  * @addr: a #GNetworkAddress
854  *
855  * Gets @addr's scheme
856  *
857  * Returns: @addr's scheme (%NULL if not built from URI)
858  *
859  * Since: 2.26
860  */
861 const gchar *
862 g_network_address_get_scheme (GNetworkAddress *addr)
863 {
864   g_return_val_if_fail (G_IS_NETWORK_ADDRESS (addr), NULL);
865
866   return addr->priv->scheme;
867 }
868
869 #define G_TYPE_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (_g_network_address_address_enumerator_get_type ())
870 #define G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_NETWORK_ADDRESS_ADDRESS_ENUMERATOR, GNetworkAddressAddressEnumerator))
871
872 typedef struct {
873   GSocketAddressEnumerator parent_instance;
874
875   GNetworkAddress *addr;
876   GList *addresses;
877   GList *next;
878 } GNetworkAddressAddressEnumerator;
879
880 typedef struct {
881   GSocketAddressEnumeratorClass parent_class;
882
883 } GNetworkAddressAddressEnumeratorClass;
884
885 static GType _g_network_address_address_enumerator_get_type (void);
886 G_DEFINE_TYPE (GNetworkAddressAddressEnumerator, _g_network_address_address_enumerator, G_TYPE_SOCKET_ADDRESS_ENUMERATOR)
887
888 static void
889 g_network_address_address_enumerator_finalize (GObject *object)
890 {
891   GNetworkAddressAddressEnumerator *addr_enum =
892     G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (object);
893
894   g_object_unref (addr_enum->addr);
895
896   G_OBJECT_CLASS (_g_network_address_address_enumerator_parent_class)->finalize (object);
897 }
898
899 static GSocketAddress *
900 g_network_address_address_enumerator_next (GSocketAddressEnumerator  *enumerator,
901                                            GCancellable              *cancellable,
902                                            GError                   **error)
903 {
904   GNetworkAddressAddressEnumerator *addr_enum =
905     G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (enumerator);
906   GSocketAddress *sockaddr;
907
908   if (addr_enum->addresses == NULL)
909     {
910       GNetworkAddress *addr = addr_enum->addr;
911       GResolver *resolver = g_resolver_get_default ();
912       gint64 serial = g_resolver_get_serial (resolver);
913
914       if (addr->priv->resolver_serial != 0 &&
915           addr->priv->resolver_serial != serial)
916         {
917           /* Resolver has reloaded, discard cached addresses */
918           g_list_free_full (addr->priv->sockaddrs, g_object_unref);
919           addr->priv->sockaddrs = NULL;
920         }
921
922       if (!addr->priv->sockaddrs)
923         g_network_address_parse_sockaddr (addr);
924       if (!addr->priv->sockaddrs)
925         {
926           GList *addresses;
927
928           addresses = g_resolver_lookup_by_name (resolver,
929                                                  addr->priv->hostname,
930                                                  cancellable, error);
931           if (!addresses)
932             {
933               g_object_unref (resolver);
934               return NULL;
935             }
936
937           g_network_address_set_addresses (addr, addresses, serial);
938         }
939           
940       addr_enum->addresses = addr->priv->sockaddrs;
941       addr_enum->next = addr_enum->addresses;
942       g_object_unref (resolver);
943     }
944
945   if (addr_enum->next == NULL)
946     return NULL;
947
948   sockaddr = addr_enum->next->data;
949   addr_enum->next = addr_enum->next->next;
950   return g_object_ref (sockaddr);
951 }
952
953 static void
954 have_addresses (GNetworkAddressAddressEnumerator *addr_enum,
955                 GTask *task, GError *error)
956 {
957   GSocketAddress *sockaddr;
958
959   addr_enum->addresses = addr_enum->addr->priv->sockaddrs;
960   addr_enum->next = addr_enum->addresses;
961
962   if (addr_enum->next)
963     {
964       sockaddr = g_object_ref (addr_enum->next->data);
965       addr_enum->next = addr_enum->next->next;
966     }
967   else
968     sockaddr = NULL;
969
970   if (error)
971     g_task_return_error (task, error);
972   else
973     g_task_return_pointer (task, sockaddr, g_object_unref);
974   g_object_unref (task);
975 }
976
977 static void
978 got_addresses (GObject      *source_object,
979                GAsyncResult *result,
980                gpointer      user_data)
981 {
982   GTask *task = user_data;
983   GNetworkAddressAddressEnumerator *addr_enum = g_task_get_source_object (task);
984   GResolver *resolver = G_RESOLVER (source_object);
985   GList *addresses;
986   GError *error = NULL;
987
988   if (!addr_enum->addr->priv->sockaddrs)
989     {
990       addresses = g_resolver_lookup_by_name_finish (resolver, result, &error);
991
992       if (!error)
993         {
994           g_network_address_set_addresses (addr_enum->addr, addresses,
995                                            g_resolver_get_serial (resolver));
996         }
997     }
998   have_addresses (addr_enum, task, error);
999 }
1000
1001 static void
1002 g_network_address_address_enumerator_next_async (GSocketAddressEnumerator  *enumerator,
1003                                                  GCancellable              *cancellable,
1004                                                  GAsyncReadyCallback        callback,
1005                                                  gpointer                   user_data)
1006 {
1007   GNetworkAddressAddressEnumerator *addr_enum =
1008     G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (enumerator);
1009   GSocketAddress *sockaddr;
1010   GTask *task;
1011
1012   task = g_task_new (addr_enum, cancellable, callback, user_data);
1013
1014   if (addr_enum->addresses == NULL)
1015     {
1016       GNetworkAddress *addr = addr_enum->addr;
1017       GResolver *resolver = g_resolver_get_default ();
1018       gint64 serial = g_resolver_get_serial (resolver);
1019
1020       if (addr->priv->resolver_serial != 0 &&
1021           addr->priv->resolver_serial != serial)
1022         {
1023           /* Resolver has reloaded, discard cached addresses */
1024           g_list_free_full (addr->priv->sockaddrs, g_object_unref);
1025           addr->priv->sockaddrs = NULL;
1026         }
1027
1028       if (!addr->priv->sockaddrs)
1029         {
1030           if (g_network_address_parse_sockaddr (addr))
1031             have_addresses (addr_enum, task, NULL);
1032           else
1033             {
1034               g_resolver_lookup_by_name_async (resolver,
1035                                                addr->priv->hostname,
1036                                                cancellable,
1037                                                got_addresses, task);
1038             }
1039           g_object_unref (resolver);
1040           return;
1041         }
1042
1043       addr_enum->addresses = addr->priv->sockaddrs;
1044       addr_enum->next = addr_enum->addresses;
1045       g_object_unref (resolver);
1046     }
1047
1048   if (addr_enum->next)
1049     {
1050       sockaddr = g_object_ref (addr_enum->next->data);
1051       addr_enum->next = addr_enum->next->next;
1052     }
1053   else
1054     sockaddr = NULL;
1055
1056   g_task_return_pointer (task, sockaddr, g_object_unref);
1057   g_object_unref (task);
1058 }
1059
1060 static GSocketAddress *
1061 g_network_address_address_enumerator_next_finish (GSocketAddressEnumerator  *enumerator,
1062                                                   GAsyncResult              *result,
1063                                                   GError                   **error)
1064 {
1065   g_return_val_if_fail (g_task_is_valid (result, enumerator), NULL);
1066
1067   return g_task_propagate_pointer (G_TASK (result), error);
1068 }
1069
1070 static void
1071 _g_network_address_address_enumerator_init (GNetworkAddressAddressEnumerator *enumerator)
1072 {
1073 }
1074
1075 static void
1076 _g_network_address_address_enumerator_class_init (GNetworkAddressAddressEnumeratorClass *addrenum_class)
1077 {
1078   GObjectClass *object_class = G_OBJECT_CLASS (addrenum_class);
1079   GSocketAddressEnumeratorClass *enumerator_class =
1080     G_SOCKET_ADDRESS_ENUMERATOR_CLASS (addrenum_class);
1081
1082   enumerator_class->next = g_network_address_address_enumerator_next;
1083   enumerator_class->next_async = g_network_address_address_enumerator_next_async;
1084   enumerator_class->next_finish = g_network_address_address_enumerator_next_finish;
1085   object_class->finalize = g_network_address_address_enumerator_finalize;
1086 }
1087
1088 static GSocketAddressEnumerator *
1089 g_network_address_connectable_enumerate (GSocketConnectable *connectable)
1090 {
1091   GNetworkAddressAddressEnumerator *addr_enum;
1092
1093   addr_enum = g_object_new (G_TYPE_NETWORK_ADDRESS_ADDRESS_ENUMERATOR, NULL);
1094   addr_enum->addr = g_object_ref (connectable);
1095
1096   return (GSocketAddressEnumerator *)addr_enum;
1097 }
1098
1099 static GSocketAddressEnumerator *
1100 g_network_address_connectable_proxy_enumerate (GSocketConnectable *connectable)
1101 {
1102   GNetworkAddress *self = G_NETWORK_ADDRESS (connectable);
1103   GSocketAddressEnumerator *proxy_enum;
1104   gchar *uri;
1105
1106   uri = _g_uri_from_authority (self->priv->scheme ? self->priv->scheme : "none",
1107                                self->priv->hostname,
1108                                self->priv->port,
1109                                NULL);
1110
1111   proxy_enum = g_object_new (G_TYPE_PROXY_ADDRESS_ENUMERATOR,
1112                              "connectable", connectable,
1113                              "uri", uri,
1114                              NULL);
1115
1116   g_free (uri);
1117
1118   return proxy_enum;
1119 }