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