Make sure compiled resources only have / as dirsep
[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  * Returns: (transfer full) (type GNetworkAddress): the new #GNetworkAddress
271  *
272  * Since: 2.22
273  */
274 GSocketConnectable *
275 g_network_address_new (const gchar *hostname,
276                        guint16      port)
277 {
278   return g_object_new (G_TYPE_NETWORK_ADDRESS,
279                        "hostname", hostname,
280                        "port", port,
281                        NULL);
282 }
283
284 /**
285  * g_network_address_parse:
286  * @host_and_port: the hostname and optionally a port
287  * @default_port: the default port if not in @host_and_port
288  * @error: a pointer to a #GError, or %NULL
289  *
290  * Creates a new #GSocketConnectable for connecting to the given
291  * @hostname and @port. May fail and return %NULL in case
292  * parsing @host_and_port fails.
293  *
294  * @host_and_port may be in any of a number of recognised formats; an IPv6
295  * address, an IPv4 address, or a domain name (in which case a DNS
296  * lookup is performed). Quoting with [] is supported for all address
297  * types. A port override may be specified in the usual way with a
298  * colon.
299  *
300  * If no port is specified in @host_and_port then @default_port will be
301  * used as the port number to connect to.
302  *
303  * In general, @host_and_port is expected to be provided by the user
304  * (allowing them to give the hostname, and a port overide if necessary)
305  * and @default_port is expected to be provided by the application.
306  *
307  * (The port component of @host_and_port can also be specified as a
308  * service name rather than as a numeric port, but this functionality
309  * is deprecated, because it depends on the contents of /etc/services,
310  * which is generally quite sparse on platforms other than Linux.)
311  *
312  * Returns: (transfer full): the new #GNetworkAddress, or %NULL on error
313  *
314  * Since: 2.22
315  */
316 GSocketConnectable *
317 g_network_address_parse (const gchar  *host_and_port,
318                          guint16       default_port,
319                          GError      **error)
320 {
321   GSocketConnectable *connectable;
322   const gchar *port;
323   guint16 portnum;
324   gchar *name;
325
326   g_return_val_if_fail (host_and_port != NULL, NULL);
327
328   port = NULL;
329   if (host_and_port[0] == '[')
330     /* escaped host part (to allow, eg. "[2001:db8::1]:888") */
331     {
332       const gchar *end;
333
334       end = strchr (host_and_port, ']');
335       if (end == NULL)
336         {
337           g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
338                        _("Hostname '%s' contains '[' but not ']'"), host_and_port);
339           return NULL;
340         }
341
342       if (end[1] == '\0')
343         port = NULL;
344       else if (end[1] == ':')
345         port = &end[2];
346       else
347         {
348           g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
349                        "The ']' character (in hostname '%s') must come at the"
350                        " end or be immediately followed by ':' and a port",
351                        host_and_port);
352           return NULL;
353         }
354
355       name = g_strndup (host_and_port + 1, end - host_and_port - 1);
356     }
357
358   else if ((port = strchr (host_and_port, ':')))
359     /* string has a ':' in it */
360     {
361       /* skip ':' */
362       port++;
363
364       if (strchr (port, ':'))
365         /* more than one ':' in string */
366         {
367           /* this is actually an unescaped IPv6 address */
368           name = g_strdup (host_and_port);
369           port = NULL;
370         }
371       else
372         name = g_strndup (host_and_port, port - host_and_port - 1);
373     }
374
375   else
376     /* plain hostname, no port */
377     name = g_strdup (host_and_port);
378
379   if (port != NULL)
380     {
381       if (port[0] == '\0')
382         {
383           g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
384                        "If a ':' character is given, it must be followed by a "
385                        "port (in hostname '%s').", host_and_port);
386           g_free (name);
387           return NULL;
388         }
389
390       else if ('0' <= port[0] && port[0] <= '9')
391         {
392           char *end;
393           long value;
394
395           value = strtol (port, &end, 10);
396           if (*end != '\0' || value < 0 || value > G_MAXUINT16)
397             {
398               g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
399                            "Invalid numeric port '%s' specified in hostname '%s'",
400                            port, host_and_port);
401               g_free (name);
402               return NULL;
403             }
404
405           portnum = value;
406         }
407
408       else
409         {
410           struct servent *entry;
411
412           entry = getservbyname (port, "tcp");
413           if (entry == NULL)
414             {
415               g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
416                            "Unknown service '%s' specified in hostname '%s'",
417                            port, host_and_port);
418 #ifdef HAVE_ENDSERVENT
419               endservent ();
420 #endif
421               g_free (name);
422               return NULL;
423             }
424
425           portnum = g_ntohs (entry->s_port);
426
427 #ifdef HAVE_ENDSERVENT
428           endservent ();
429 #endif
430         }
431     }
432   else
433     {
434       /* No port in host_and_port */
435       portnum = default_port;
436     }
437
438   connectable = g_network_address_new (name, portnum);
439   g_free (name);
440
441   return connectable;
442 }
443
444 /* Allowed characters outside alphanumeric for unreserved. */
445 #define G_URI_OTHER_UNRESERVED "-._~"
446
447 /* This or something equivalent will eventually go into glib/guri.h */
448 gboolean
449 _g_uri_parse_authority (const char  *uri,
450                         char       **host,
451                         guint16     *port,
452                         char       **userinfo)
453 {
454   char *tmp_str;
455   const char *start, *p, *at, *delim;
456   char c;
457
458   g_return_val_if_fail (uri != NULL, FALSE);
459
460   if (host)
461     *host = NULL;
462
463   if (port)
464     *port = 0;
465
466   if (userinfo)
467     *userinfo = NULL;
468
469   /* From RFC 3986 Decodes:
470    * URI          = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
471    * hier-part    = "//" authority path-abempty
472    * path-abempty = *( "/" segment )
473    * authority    = [ userinfo "@" ] host [ ":" port ]
474    */
475
476   /* Check we have a valid scheme */
477   tmp_str = g_uri_parse_scheme (uri);
478
479   if (tmp_str == NULL)
480     return FALSE;
481
482   g_free (tmp_str);
483
484   /* Decode hier-part:
485    *  hier-part   = "//" authority path-abempty
486    */
487   p = uri;
488   start = strstr (p, "//");
489
490   if (start == NULL)
491     return FALSE;
492
493   start += 2;
494
495   /* check if the @ sign is part of the authority before attempting to
496    * decode the userinfo */
497   delim = strpbrk (start, "/?#[]");
498   at = strchr (start, '@');
499   if (at && delim && at > delim)
500     at = NULL;
501
502   if (at != NULL)
503     {
504       /* Decode userinfo:
505        * userinfo      = *( unreserved / pct-encoded / sub-delims / ":" )
506        * unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
507        * pct-encoded   = "%" HEXDIG HEXDIG
508        */
509       p = start;
510       while (1)
511         {
512           c = *p++;
513
514           if (c == '@')
515             break;
516
517           /* pct-encoded */
518           if (c == '%')
519             {
520               if (!(g_ascii_isxdigit (p[0]) ||
521                     g_ascii_isxdigit (p[1])))
522                 return FALSE;
523
524               p++;
525
526               continue;
527             }
528
529           /* unreserved /  sub-delims / : */
530           if (!(g_ascii_isalnum (c) ||
531                 strchr (G_URI_OTHER_UNRESERVED, c) ||
532                 strchr (G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS, c) ||
533                 c == ':'))
534             return FALSE;
535         }
536
537       if (userinfo)
538         *userinfo = g_strndup (start, p - start - 1);
539
540       start = p;
541     }
542   else
543     {
544       p = start;
545     }
546
547
548   /* decode host:
549    * host          = IP-literal / IPv4address / reg-name
550    * reg-name      = *( unreserved / pct-encoded / sub-delims )
551    */
552
553   /* If IPv6 or IPvFuture */
554   if (*p == '[')
555     {
556       gboolean has_scope_id = FALSE, has_bad_scope_id = FALSE;
557
558       start++;
559       p++;
560       while (1)
561         {
562           c = *p++;
563
564           if (c == ']')
565             break;
566
567           if (c == '%' && !has_scope_id)
568             {
569               has_scope_id = TRUE;
570               if (p[0] != '2' || p[1] != '5')
571                 has_bad_scope_id = TRUE;
572               continue;
573             }
574
575           /* unreserved /  sub-delims */
576           if (!(g_ascii_isalnum (c) ||
577                 strchr (G_URI_OTHER_UNRESERVED, c) ||
578                 strchr (G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS, c) ||
579                 c == ':' ||
580                 c == '.'))
581             goto error;
582         }
583
584       if (host)
585         {
586           if (has_bad_scope_id)
587             *host = g_strndup (start, p - start - 1);
588           else
589             *host = g_uri_unescape_segment (start, p - 1, NULL);
590         }
591
592       c = *p++;
593     }
594   else
595     {
596       while (1)
597         {
598           c = *p++;
599
600           if (c == ':' ||
601               c == '/' ||
602               c == '?' ||
603               c == '#' ||
604               c == '\0')
605             break;
606
607           /* pct-encoded */
608           if (c == '%')
609             {
610               if (!(g_ascii_isxdigit (p[0]) ||
611                     g_ascii_isxdigit (p[1])))
612                 goto error;
613
614               p++;
615
616               continue;
617             }
618
619           /* unreserved /  sub-delims */
620           if (!(g_ascii_isalnum (c) ||
621                 strchr (G_URI_OTHER_UNRESERVED, c) ||
622                 strchr (G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS, c)))
623             goto error;
624         }
625
626       if (host)
627         *host = g_uri_unescape_segment (start, p - 1, NULL);
628     }
629
630   if (c == ':')
631     {
632       /* Decode port:
633        *  port          = *DIGIT
634        */
635       guint tmp = 0;
636
637       while (1)
638         {
639           c = *p++;
640
641           if (c == '/' ||
642               c == '?' ||
643               c == '#' ||
644               c == '\0')
645             break;
646
647           if (!g_ascii_isdigit (c))
648             goto error;
649
650           tmp = (tmp * 10) + (c - '0');
651
652           if (tmp > 65535)
653             goto error;
654         }
655       if (port)
656         *port = (guint16) tmp;
657     }
658
659   return TRUE;
660
661 error:
662   if (host && *host)
663     {
664       g_free (*host);
665       *host = NULL;
666     }
667
668   if (userinfo && *userinfo)
669     {
670       g_free (*userinfo);
671       *userinfo = NULL;
672     }
673
674   return FALSE;
675 }
676
677 gchar *
678 _g_uri_from_authority (const gchar *protocol,
679                        const gchar *host,
680                        guint        port,
681                        const gchar *userinfo)
682 {
683   GString *uri;
684
685   uri = g_string_new (protocol);
686   g_string_append (uri, "://");
687
688   if (userinfo)
689     {
690       g_string_append_uri_escaped (uri, userinfo, G_URI_RESERVED_CHARS_ALLOWED_IN_USERINFO, FALSE);
691       g_string_append_c (uri, '@');
692     }
693
694   if (g_hostname_is_non_ascii (host))
695     {
696       gchar *ace_encoded = g_hostname_to_ascii (host);
697
698       if (!ace_encoded)
699         {
700           g_string_free (uri, TRUE);
701           return NULL;
702         }
703       g_string_append (uri, ace_encoded);
704       g_free (ace_encoded);
705     }
706   else if (strchr (host, ':'))
707     g_string_append_printf (uri, "[%s]", host);
708   else
709     g_string_append (uri, host);
710
711   if (port != 0)
712     g_string_append_printf (uri, ":%u", port);
713
714   return g_string_free (uri, FALSE);
715 }
716
717 /**
718  * g_network_address_parse_uri:
719  * @uri: the hostname and optionally a port
720  * @default_port: The default port if none is found in the URI
721  * @error: a pointer to a #GError, or %NULL
722  *
723  * Creates a new #GSocketConnectable for connecting to the given
724  * @uri. May fail and return %NULL in case parsing @uri fails.
725  *
726  * Using this rather than g_network_address_new() or
727  * g_network_address_parse() allows #GSocketClient to determine
728  * when to use application-specific proxy protocols.
729  *
730  * Returns: (transfer full): the new #GNetworkAddress, or %NULL on error
731  *
732  * Since: 2.26
733  */
734 GSocketConnectable *
735 g_network_address_parse_uri (const gchar  *uri,
736                              guint16       default_port,
737                              GError      **error)
738 {
739   GSocketConnectable *conn;
740   gchar *scheme;
741   gchar *hostname;
742   guint16 port;
743
744   if (!_g_uri_parse_authority (uri, &hostname, &port, NULL))
745     {
746       g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
747                    "Invalid URI '%s'",
748                    uri);
749       return NULL;
750     }
751
752   if (port == 0)
753     port = default_port;
754
755   scheme = g_uri_parse_scheme (uri);
756
757   conn = g_object_new (G_TYPE_NETWORK_ADDRESS,
758                        "hostname", hostname,
759                        "port", port,
760                        "scheme", scheme,
761                        NULL);
762
763   g_free (scheme);
764   g_free (hostname);
765
766   return conn;
767 }
768
769 /**
770  * g_network_address_get_hostname:
771  * @addr: a #GNetworkAddress
772  *
773  * Gets @addr's hostname. This might be either UTF-8 or ASCII-encoded,
774  * depending on what @addr was created with.
775  *
776  * Returns: @addr's hostname
777  *
778  * Since: 2.22
779  */
780 const gchar *
781 g_network_address_get_hostname (GNetworkAddress *addr)
782 {
783   g_return_val_if_fail (G_IS_NETWORK_ADDRESS (addr), NULL);
784
785   return addr->priv->hostname;
786 }
787
788 /**
789  * g_network_address_get_port:
790  * @addr: a #GNetworkAddress
791  *
792  * Gets @addr's port number
793  *
794  * Returns: @addr's port (which may be 0)
795  *
796  * Since: 2.22
797  */
798 guint16
799 g_network_address_get_port (GNetworkAddress *addr)
800 {
801   g_return_val_if_fail (G_IS_NETWORK_ADDRESS (addr), 0);
802
803   return addr->priv->port;
804 }
805
806 /**
807  * g_network_address_get_scheme:
808  * @addr: a #GNetworkAddress
809  *
810  * Gets @addr's scheme
811  *
812  * Returns: @addr's scheme (%NULL if not built from URI)
813  *
814  * Since: 2.26
815  */
816 const gchar *
817 g_network_address_get_scheme (GNetworkAddress *addr)
818 {
819   g_return_val_if_fail (G_IS_NETWORK_ADDRESS (addr), NULL);
820
821   return addr->priv->scheme;
822 }
823
824 #define G_TYPE_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (_g_network_address_address_enumerator_get_type ())
825 #define G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_NETWORK_ADDRESS_ADDRESS_ENUMERATOR, GNetworkAddressAddressEnumerator))
826
827 typedef struct {
828   GSocketAddressEnumerator parent_instance;
829
830   GNetworkAddress *addr;
831   GList *addresses;
832   GList *next;
833 } GNetworkAddressAddressEnumerator;
834
835 typedef struct {
836   GSocketAddressEnumeratorClass parent_class;
837
838 } GNetworkAddressAddressEnumeratorClass;
839
840 static GType _g_network_address_address_enumerator_get_type (void);
841 G_DEFINE_TYPE (GNetworkAddressAddressEnumerator, _g_network_address_address_enumerator, G_TYPE_SOCKET_ADDRESS_ENUMERATOR)
842
843 static void
844 g_network_address_address_enumerator_finalize (GObject *object)
845 {
846   GNetworkAddressAddressEnumerator *addr_enum =
847     G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (object);
848
849   g_object_unref (addr_enum->addr);
850
851   G_OBJECT_CLASS (_g_network_address_address_enumerator_parent_class)->finalize (object);
852 }
853
854 static GSocketAddress *
855 g_network_address_address_enumerator_next (GSocketAddressEnumerator  *enumerator,
856                                            GCancellable              *cancellable,
857                                            GError                   **error)
858 {
859   GNetworkAddressAddressEnumerator *addr_enum =
860     G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (enumerator);
861   GSocketAddress *sockaddr;
862
863   if (addr_enum->addresses == NULL)
864     {
865       GNetworkAddress *addr = addr_enum->addr;
866       GResolver *resolver = g_resolver_get_default ();
867       gint64 serial = g_resolver_get_serial (resolver);
868
869       if (addr->priv->resolver_serial != 0 &&
870           addr->priv->resolver_serial != serial)
871         {
872           /* Resolver has reloaded, discard cached addresses */
873           g_list_free_full (addr->priv->sockaddrs, g_object_unref);
874           addr->priv->sockaddrs = NULL;
875         }
876
877       if (!addr->priv->sockaddrs)
878         g_network_address_parse_sockaddr (addr);
879       if (!addr->priv->sockaddrs)
880         {
881           GList *addresses;
882
883           addresses = g_resolver_lookup_by_name (resolver,
884                                                  addr->priv->hostname,
885                                                  cancellable, error);
886           if (!addresses)
887             {
888               g_object_unref (resolver);
889               return NULL;
890             }
891
892           g_network_address_set_addresses (addr, addresses, serial);
893         }
894           
895       addr_enum->addresses = addr->priv->sockaddrs;
896       addr_enum->next = addr_enum->addresses;
897       g_object_unref (resolver);
898     }
899
900   if (addr_enum->next == NULL)
901     return NULL;
902
903   sockaddr = addr_enum->next->data;
904   addr_enum->next = addr_enum->next->next;
905   return g_object_ref (sockaddr);
906 }
907
908 static void
909 have_addresses (GNetworkAddressAddressEnumerator *addr_enum,
910                 GTask *task, GError *error)
911 {
912   GSocketAddress *sockaddr;
913
914   addr_enum->addresses = addr_enum->addr->priv->sockaddrs;
915   addr_enum->next = addr_enum->addresses;
916
917   if (addr_enum->next)
918     {
919       sockaddr = g_object_ref (addr_enum->next->data);
920       addr_enum->next = addr_enum->next->next;
921     }
922   else
923     sockaddr = NULL;
924
925   if (error)
926     g_task_return_error (task, error);
927   else
928     g_task_return_pointer (task, sockaddr, g_object_unref);
929   g_object_unref (task);
930 }
931
932 static void
933 got_addresses (GObject      *source_object,
934                GAsyncResult *result,
935                gpointer      user_data)
936 {
937   GTask *task = user_data;
938   GNetworkAddressAddressEnumerator *addr_enum = g_task_get_source_object (task);
939   GResolver *resolver = G_RESOLVER (source_object);
940   GList *addresses;
941   GError *error = NULL;
942
943   if (!addr_enum->addr->priv->sockaddrs)
944     {
945       addresses = g_resolver_lookup_by_name_finish (resolver, result, &error);
946
947       if (!error)
948         {
949           g_network_address_set_addresses (addr_enum->addr, addresses,
950                                            g_resolver_get_serial (resolver));
951         }
952     }
953   have_addresses (addr_enum, task, error);
954 }
955
956 static void
957 g_network_address_address_enumerator_next_async (GSocketAddressEnumerator  *enumerator,
958                                                  GCancellable              *cancellable,
959                                                  GAsyncReadyCallback        callback,
960                                                  gpointer                   user_data)
961 {
962   GNetworkAddressAddressEnumerator *addr_enum =
963     G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (enumerator);
964   GSocketAddress *sockaddr;
965   GTask *task;
966
967   task = g_task_new (addr_enum, cancellable, callback, user_data);
968
969   if (addr_enum->addresses == NULL)
970     {
971       GNetworkAddress *addr = addr_enum->addr;
972       GResolver *resolver = g_resolver_get_default ();
973       gint64 serial = g_resolver_get_serial (resolver);
974
975       if (addr->priv->resolver_serial != 0 &&
976           addr->priv->resolver_serial != serial)
977         {
978           /* Resolver has reloaded, discard cached addresses */
979           g_list_free_full (addr->priv->sockaddrs, g_object_unref);
980           addr->priv->sockaddrs = NULL;
981         }
982
983       if (!addr->priv->sockaddrs)
984         {
985           if (g_network_address_parse_sockaddr (addr))
986             have_addresses (addr_enum, task, NULL);
987           else
988             {
989               g_resolver_lookup_by_name_async (resolver,
990                                                addr->priv->hostname,
991                                                cancellable,
992                                                got_addresses, task);
993             }
994           g_object_unref (resolver);
995           return;
996         }
997
998       addr_enum->addresses = addr->priv->sockaddrs;
999       addr_enum->next = addr_enum->addresses;
1000       g_object_unref (resolver);
1001     }
1002
1003   if (addr_enum->next)
1004     {
1005       sockaddr = g_object_ref (addr_enum->next->data);
1006       addr_enum->next = addr_enum->next->next;
1007     }
1008   else
1009     sockaddr = NULL;
1010
1011   g_task_return_pointer (task, sockaddr, g_object_unref);
1012   g_object_unref (task);
1013 }
1014
1015 static GSocketAddress *
1016 g_network_address_address_enumerator_next_finish (GSocketAddressEnumerator  *enumerator,
1017                                                   GAsyncResult              *result,
1018                                                   GError                   **error)
1019 {
1020   g_return_val_if_fail (g_task_is_valid (result, enumerator), NULL);
1021
1022   return g_task_propagate_pointer (G_TASK (result), error);
1023 }
1024
1025 static void
1026 _g_network_address_address_enumerator_init (GNetworkAddressAddressEnumerator *enumerator)
1027 {
1028 }
1029
1030 static void
1031 _g_network_address_address_enumerator_class_init (GNetworkAddressAddressEnumeratorClass *addrenum_class)
1032 {
1033   GObjectClass *object_class = G_OBJECT_CLASS (addrenum_class);
1034   GSocketAddressEnumeratorClass *enumerator_class =
1035     G_SOCKET_ADDRESS_ENUMERATOR_CLASS (addrenum_class);
1036
1037   enumerator_class->next = g_network_address_address_enumerator_next;
1038   enumerator_class->next_async = g_network_address_address_enumerator_next_async;
1039   enumerator_class->next_finish = g_network_address_address_enumerator_next_finish;
1040   object_class->finalize = g_network_address_address_enumerator_finalize;
1041 }
1042
1043 static GSocketAddressEnumerator *
1044 g_network_address_connectable_enumerate (GSocketConnectable *connectable)
1045 {
1046   GNetworkAddressAddressEnumerator *addr_enum;
1047
1048   addr_enum = g_object_new (G_TYPE_NETWORK_ADDRESS_ADDRESS_ENUMERATOR, NULL);
1049   addr_enum->addr = g_object_ref (connectable);
1050
1051   return (GSocketAddressEnumerator *)addr_enum;
1052 }
1053
1054 static GSocketAddressEnumerator *
1055 g_network_address_connectable_proxy_enumerate (GSocketConnectable *connectable)
1056 {
1057   GNetworkAddress *self = G_NETWORK_ADDRESS (connectable);
1058   GSocketAddressEnumerator *proxy_enum;
1059   gchar *uri;
1060
1061   uri = _g_uri_from_authority (self->priv->scheme ? self->priv->scheme : "none",
1062                                self->priv->hostname,
1063                                self->priv->port,
1064                                NULL);
1065
1066   proxy_enum = g_object_new (G_TYPE_PROXY_ADDRESS_ENUMERATOR,
1067                              "connectable", connectable,
1068                              "uri", uri,
1069                              NULL);
1070
1071   g_free (uri);
1072
1073   return proxy_enum;
1074 }