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