Use g_simple_async_result_{new_,}take_error
[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, write to the
19  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include "config.h"
24 #include <glib.h>
25 #include "glibintl.h"
26
27 #include <stdlib.h>
28 #include "gnetworkaddress.h"
29 #include "gasyncresult.h"
30 #include "ginetaddress.h"
31 #include "ginetsocketaddress.h"
32 #include "gnetworkingprivate.h"
33 #include "gproxyaddressenumerator.h"
34 #include "gresolver.h"
35 #include "gsimpleasyncresult.h"
36 #include "gsocketaddressenumerator.h"
37 #include "gioerror.h"
38 #include "gsocketconnectable.h"
39
40 #include <string.h>
41
42
43 /**
44  * SECTION:gnetworkaddress
45  * @short_description: A GSocketConnectable for resolving hostnames
46  * @include: gio/gio.h
47  *
48  * #GNetworkAddress provides an easy way to resolve a hostname and
49  * then attempt to connect to that host, handling the possibility of
50  * multiple IP addresses and multiple address families.
51  *
52  * See #GSocketConnectable for and example of using the connectable
53  * interface.
54  */
55
56 /**
57  * GNetworkAddress:
58  *
59  * A #GSocketConnectable for resolving a hostname and connecting to
60  * that host.
61  */
62
63 struct _GNetworkAddressPrivate {
64   gchar *hostname;
65   guint16 port;
66   GList *sockaddrs;
67   gchar *scheme;
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_IMPLEMENT_INTERFACE (G_TYPE_SOCKET_CONNECTABLE,
92                                                 g_network_address_connectable_iface_init))
93
94 static void
95 g_network_address_finalize (GObject *object)
96 {
97   GNetworkAddress *addr = G_NETWORK_ADDRESS (object);
98
99   g_free (addr->priv->hostname);
100   g_free (addr->priv->scheme);
101
102   if (addr->priv->sockaddrs)
103     {
104       GList *a;
105
106       for (a = addr->priv->sockaddrs; a; a = a->next)
107         g_object_unref (a->data);
108       g_list_free (addr->priv->sockaddrs);
109     }
110
111   G_OBJECT_CLASS (g_network_address_parent_class)->finalize (object);
112 }
113
114 static void
115 g_network_address_class_init (GNetworkAddressClass *klass)
116 {
117   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
118
119   g_type_class_add_private (klass, sizeof (GNetworkAddressPrivate));
120
121   gobject_class->set_property = g_network_address_set_property;
122   gobject_class->get_property = g_network_address_get_property;
123   gobject_class->finalize = g_network_address_finalize;
124
125   g_object_class_install_property (gobject_class, PROP_HOSTNAME,
126                                    g_param_spec_string ("hostname",
127                                                         P_("Hostname"),
128                                                         P_("Hostname to resolve"),
129                                                         NULL,
130                                                         G_PARAM_READWRITE |
131                                                         G_PARAM_CONSTRUCT_ONLY |
132                                                         G_PARAM_STATIC_STRINGS));
133   g_object_class_install_property (gobject_class, PROP_PORT,
134                                    g_param_spec_uint ("port",
135                                                       P_("Port"),
136                                                       P_("Network port"),
137                                                       0, 65535, 0,
138                                                       G_PARAM_READWRITE |
139                                                       G_PARAM_CONSTRUCT_ONLY |
140                                                       G_PARAM_STATIC_STRINGS));
141
142   g_object_class_install_property (gobject_class, PROP_SCHEME,
143                                    g_param_spec_string ("scheme",
144                                                         P_("Scheme"),
145                                                         P_("URI Scheme"),
146                                                         NULL,
147                                                         G_PARAM_READWRITE |
148                                                         G_PARAM_CONSTRUCT_ONLY |
149                                                         G_PARAM_STATIC_STRINGS));
150 }
151
152 static void
153 g_network_address_connectable_iface_init (GSocketConnectableIface *connectable_iface)
154 {
155   connectable_iface->enumerate  = g_network_address_connectable_enumerate;
156   connectable_iface->proxy_enumerate = g_network_address_connectable_proxy_enumerate;
157 }
158
159 static void
160 g_network_address_init (GNetworkAddress *addr)
161 {
162   addr->priv = G_TYPE_INSTANCE_GET_PRIVATE (addr, G_TYPE_NETWORK_ADDRESS,
163                                             GNetworkAddressPrivate);
164 }
165
166 static void
167 g_network_address_set_property (GObject      *object,
168                                 guint         prop_id,
169                                 const GValue *value,
170                                 GParamSpec   *pspec)
171 {
172   GNetworkAddress *addr = G_NETWORK_ADDRESS (object);
173
174   switch (prop_id)
175     {
176     case PROP_HOSTNAME:
177       g_free (addr->priv->hostname);
178       addr->priv->hostname = g_value_dup_string (value);
179       break;
180
181     case PROP_PORT:
182       addr->priv->port = g_value_get_uint (value);
183       break;
184
185     case PROP_SCHEME:
186       if (addr->priv->scheme)
187         g_free (addr->priv->scheme);
188       addr->priv->scheme = g_value_dup_string (value);
189       break;
190
191     default:
192       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
193       break;
194     }
195
196 }
197
198 static void
199 g_network_address_get_property (GObject    *object,
200                                 guint       prop_id,
201                                 GValue     *value,
202                                 GParamSpec *pspec)
203 {
204   GNetworkAddress *addr = G_NETWORK_ADDRESS (object);
205
206   switch (prop_id)
207     {
208     case PROP_HOSTNAME:
209       g_value_set_string (value, addr->priv->hostname);
210       break;
211
212     case PROP_PORT:
213       g_value_set_uint (value, addr->priv->port);
214       break;
215
216     case PROP_SCHEME:
217       g_value_set_string (value, addr->priv->scheme);
218       break;
219
220     default:
221       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
222       break;
223     }
224
225 }
226
227 static void
228 g_network_address_set_addresses (GNetworkAddress *addr,
229                                  GList           *addresses)
230 {
231   GList *a;
232   GSocketAddress *sockaddr;
233
234   g_return_if_fail (addresses != NULL && addr->priv->sockaddrs == NULL);
235
236   for (a = addresses; a; a = a->next)
237     {
238       sockaddr = g_inet_socket_address_new (a->data, addr->priv->port);
239       addr->priv->sockaddrs = g_list_prepend (addr->priv->sockaddrs, sockaddr);
240       g_object_unref (a->data);
241     }
242   g_list_free (addresses);
243   addr->priv->sockaddrs = g_list_reverse (addr->priv->sockaddrs);
244 }
245
246 /**
247  * g_network_address_new:
248  * @hostname: the hostname
249  * @port: the port
250  *
251  * Creates a new #GSocketConnectable for connecting to the given
252  * @hostname and @port.
253  *
254  * Return value: (transfer full): the new #GNetworkAddress
255  *
256  * Since: 2.22
257  */
258 GSocketConnectable *
259 g_network_address_new (const gchar *hostname,
260                        guint16      port)
261 {
262   return g_object_new (G_TYPE_NETWORK_ADDRESS,
263                        "hostname", hostname,
264                        "port", port,
265                        NULL);
266 }
267
268 /**
269  * g_network_address_parse:
270  * @host_and_port: the hostname and optionally a port
271  * @default_port: the default port if not in @host_and_port
272  * @error: a pointer to a #GError, or %NULL
273  *
274  * Creates a new #GSocketConnectable for connecting to the given
275  * @hostname and @port. May fail and return %NULL in case
276  * parsing @host_and_port fails.
277  *
278  * @host_and_port may be in any of a number of recognised formats; an IPv6
279  * address, an IPv4 address, or a domain name (in which case a DNS
280  * lookup is performed). Quoting with [] is supported for all address
281  * types. A port override may be specified in the usual way with a
282  * colon. Ports may be given as decimal numbers or symbolic names (in
283  * which case an /etc/services lookup is performed).
284  *
285  * If no port is specified in @host_and_port then @default_port will be
286  * used as the port number to connect to.
287  *
288  * In general, @host_and_port is expected to be provided by the user
289  * (allowing them to give the hostname, and a port overide if necessary)
290  * and @default_port is expected to be provided by the application.
291  *
292  * Return value: (transfer full): the new #GNetworkAddress, or %NULL on error
293  *
294  * Since: 2.22
295  */
296 GSocketConnectable *
297 g_network_address_parse (const gchar  *host_and_port,
298                          guint16       default_port,
299                          GError      **error)
300 {
301   GSocketConnectable *connectable;
302   const gchar *port;
303   guint16 portnum;
304   gchar *name;
305
306   g_return_val_if_fail (host_and_port != NULL, NULL);
307
308   port = NULL;
309   if (host_and_port[0] == '[')
310     /* escaped host part (to allow, eg. "[2001:db8::1]:888") */
311     {
312       const gchar *end;
313
314       end = strchr (host_and_port, ']');
315       if (end == NULL)
316         {
317           g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
318                        _("Hostname '%s' contains '[' but not ']'"), host_and_port);
319           return NULL;
320         }
321
322       if (end[1] == '\0')
323         port = NULL;
324       else if (end[1] == ':')
325         port = &end[2];
326       else
327         {
328           g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
329                        "The ']' character (in hostname '%s') must come at the"
330                        " end or be immediately followed by ':' and a port",
331                        host_and_port);
332           return NULL;
333         }
334
335       name = g_strndup (host_and_port + 1, end - host_and_port - 1);
336     }
337
338   else if ((port = strchr (host_and_port, ':')))
339     /* string has a ':' in it */
340     {
341       /* skip ':' */
342       port++;
343
344       if (strchr (port, ':'))
345         /* more than one ':' in string */
346         {
347           /* this is actually an unescaped IPv6 address */
348           name = g_strdup (host_and_port);
349           port = NULL;
350         }
351       else
352         name = g_strndup (host_and_port, port - host_and_port - 1);
353     }
354
355   else
356     /* plain hostname, no port */
357     name = g_strdup (host_and_port);
358
359   if (port != NULL)
360     {
361       if (port[0] == '\0')
362         {
363           g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
364                        "If a ':' character is given, it must be followed by a "
365                        "port (in hostname '%s').", host_and_port);
366           g_free (name);
367           return NULL;
368         }
369
370       else if ('0' <= port[0] && port[0] <= '9')
371         {
372           char *end;
373           long value;
374
375           value = strtol (port, &end, 10);
376           if (*end != '\0' || value < 0 || value > G_MAXUINT16)
377             {
378               g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
379                            "Invalid numeric port '%s' specified in hostname '%s'",
380                            port, host_and_port);
381               g_free (name);
382               return NULL;
383             }
384
385           portnum = value;
386         }
387
388       else
389         {
390           struct servent *entry;
391
392           entry = getservbyname (port, "tcp");
393           if (entry == NULL)
394             {
395               g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
396                            "Unknown service '%s' specified in hostname '%s'",
397                            port, host_and_port);
398 #ifdef HAVE_ENDSERVENT
399               endservent ();
400 #endif
401               g_free (name);
402               return NULL;
403             }
404
405           portnum = g_ntohs (entry->s_port);
406
407 #ifdef HAVE_ENDSERVENT
408           endservent ();
409 #endif
410         }
411     }
412   else
413     {
414       /* No port in host_and_port */
415       portnum = default_port;
416     }
417
418   connectable = g_network_address_new (name, portnum);
419   g_free (name);
420
421   return connectable;
422 }
423
424 /* Allowed characters outside alphanumeric for unreserved. */
425 #define G_URI_OTHER_UNRESERVED "-._~"
426
427 /* This or something equivalent will eventually go into glib/guri.h */
428 gboolean
429 _g_uri_parse_authority (const char  *uri,
430                         char       **host,
431                         guint16     *port,
432                         char       **userinfo)
433 {
434   char *tmp_str;
435   const char *start, *p;
436   char c;
437
438   g_return_val_if_fail (uri != NULL, FALSE);
439
440   if (host)
441     *host = NULL;
442
443   if (port)
444     *port = 0;
445
446   if (userinfo)
447     *userinfo = NULL;
448
449   /* From RFC 3986 Decodes:
450    * URI          = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
451    * hier-part    = "//" authority path-abempty
452    * path-abempty = *( "/" segment )
453    * authority    = [ userinfo "@" ] host [ ":" port ]
454    */
455
456   /* Check we have a valid scheme */
457   tmp_str = g_uri_parse_scheme (uri);
458
459   if (tmp_str == NULL)
460     return FALSE;
461
462   g_free (tmp_str);
463
464   /* Decode hier-part:
465    *  hier-part   = "//" authority path-abempty
466    */
467   p = uri;
468   start = strstr (p, "//");
469
470   if (start == NULL)
471     return FALSE;
472
473   start += 2;
474   p = strchr (start, '@');
475
476   if (p != NULL)
477     {
478       /* Decode userinfo:
479        * userinfo      = *( unreserved / pct-encoded / sub-delims / ":" )
480        * unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
481        * pct-encoded   = "%" HEXDIG HEXDIG
482        */
483       while (1)
484         {
485           c = *p++;
486
487           if (c == '@')
488             break;
489
490           /* pct-encoded */
491           if (c == '%')
492             {
493               if (!(g_ascii_isxdigit (p[0]) ||
494                     g_ascii_isxdigit (p[1])))
495                 return FALSE;
496
497               p++;
498
499               continue;
500             }
501
502           /* unreserved /  sub-delims / : */
503           if (!(g_ascii_isalnum(c) ||
504                 strchr (G_URI_OTHER_UNRESERVED, c) ||
505                 strchr (G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS, c) ||
506                 c == ':'))
507             return FALSE;
508         }
509
510       if (userinfo)
511         *userinfo = g_strndup (start, p - start - 1);
512
513       start = p;
514     }
515   else
516     {
517       p = start;
518     }
519
520
521   /* decode host:
522    * host          = IP-literal / IPv4address / reg-name
523    * reg-name      = *( unreserved / pct-encoded / sub-delims )
524    */
525
526   /* If IPv6 or IPvFuture */
527   if (*p == '[')
528     {
529       start++;
530       p++;
531       while (1)
532         {
533           c = *p++;
534
535           if (c == ']')
536             break;
537
538           /* unreserved /  sub-delims */
539           if (!(g_ascii_isalnum(c) ||
540                 strchr (G_URI_OTHER_UNRESERVED, c) ||
541                 strchr (G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS, c) ||
542                 c == ':' ||
543                 c == '.'))
544             goto error;
545         }
546     }
547   else
548     {
549       while (1)
550         {
551           c = *p++;
552
553           if (c == ':' ||
554               c == '/' ||
555               c == '?' ||
556               c == '#' ||
557               c == '\0')
558             break;
559
560           /* pct-encoded */
561           if (c == '%')
562             {
563               if (!(g_ascii_isxdigit (p[0]) ||
564                     g_ascii_isxdigit (p[1])))
565                 goto error;
566
567               p++;
568
569               continue;
570             }
571
572           /* unreserved /  sub-delims */
573           if (!(g_ascii_isalnum(c) ||
574                 strchr (G_URI_OTHER_UNRESERVED, c) ||
575                 strchr (G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS, c)))
576             goto error;
577         }
578     }
579
580   if (host)
581     *host = g_uri_unescape_segment (start, p - 1, NULL);
582
583   if (c == ':')
584     {
585       /* Decode pot:
586        *  port          = *DIGIT
587        */
588       guint tmp = 0;
589
590       while (1)
591         {
592           c = *p++;
593
594           if (c == '/' ||
595               c == '?' ||
596               c == '#' ||
597               c == '\0')
598             break;
599
600           if (!g_ascii_isdigit (c))
601             goto error;
602
603           tmp = (tmp * 10) + (c - '0');
604
605           if (tmp > 65535)
606             goto error;
607         }
608       if (port)
609         *port = (guint16) tmp;
610     }
611
612   return TRUE;
613
614 error:
615   if (host && *host)
616     {
617       g_free (*host);
618       *host = NULL;
619     }
620
621   if (userinfo && *userinfo)
622     {
623       g_free (*userinfo);
624       *userinfo = NULL;
625     }
626
627   return FALSE;
628 }
629
630 gchar *
631 _g_uri_from_authority (const gchar *protocol,
632                        const gchar *host,
633                        guint        port,
634                        const gchar *userinfo)
635 {
636   GString *uri;
637
638   uri = g_string_new (protocol);
639   g_string_append (uri, "://");
640
641   if (userinfo)
642     {
643       g_string_append_uri_escaped (uri, userinfo, G_URI_RESERVED_CHARS_ALLOWED_IN_USERINFO, FALSE);
644       g_string_append_c (uri, '@');
645     }
646
647   if (g_hostname_is_non_ascii (host))
648     {
649       gchar *ace_encoded = g_hostname_to_ascii (host);
650
651       if (!ace_encoded)
652         {
653           g_string_free (uri, TRUE);
654           return NULL;
655         }
656       g_string_append (uri, ace_encoded);
657       g_free (ace_encoded);
658     }
659   else if (strchr (host, ':'))
660     g_string_append_printf (uri, "[%s]", host);
661   else
662     g_string_append (uri, host);
663
664   if (port != 0)
665     g_string_append_printf (uri, ":%u", port);
666
667   return g_string_free (uri, FALSE);
668 }
669
670 /**
671  * g_network_address_parse_uri:
672  * @uri: the hostname and optionally a port
673  * @default_port: The default port if none is found in the URI
674  * @error: a pointer to a #GError, or %NULL
675  *
676  * Creates a new #GSocketConnectable for connecting to the given
677  * @uri. May fail and return %NULL in case parsing @uri fails.
678  *
679  * Using this rather than g_network_address_new() or
680  * g_network_address_parse_host() allows #GSocketClient to determine
681  * when to use application-specific proxy protocols.
682  *
683  * Return value: (transfer full): the new #GNetworkAddress, or %NULL on error
684  *
685  * Since: 2.26
686  */
687 GSocketConnectable *
688 g_network_address_parse_uri (const gchar  *uri,
689                              guint16       default_port,
690                              GError      **error)
691 {
692   GSocketConnectable *conn;
693   gchar *scheme;
694   gchar *hostname;
695   guint16 port;
696
697   if (!_g_uri_parse_authority (uri, &hostname, &port, NULL))
698     {
699       g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
700                    "Invalid URI '%s'",
701                    uri);
702       return NULL;
703     }
704
705   if (port == 0)
706     port = default_port;
707
708   scheme = g_uri_parse_scheme (uri);
709
710   conn = g_object_new (G_TYPE_NETWORK_ADDRESS,
711                        "hostname", hostname,
712                        "port", port,
713                        "scheme", scheme,
714                        NULL);
715
716   g_free (scheme);
717   g_free (hostname);
718
719   return conn;
720 }
721
722 /**
723  * g_network_address_get_hostname:
724  * @addr: a #GNetworkAddress
725  *
726  * Gets @addr's hostname. This might be either UTF-8 or ASCII-encoded,
727  * depending on what @addr was created with.
728  *
729  * Return value: @addr's hostname
730  *
731  * Since: 2.22
732  */
733 const gchar *
734 g_network_address_get_hostname (GNetworkAddress *addr)
735 {
736   g_return_val_if_fail (G_IS_NETWORK_ADDRESS (addr), NULL);
737
738   return addr->priv->hostname;
739 }
740
741 /**
742  * g_network_address_get_port:
743  * @addr: a #GNetworkAddress
744  *
745  * Gets @addr's port number
746  *
747  * Return value: @addr's port (which may be 0)
748  *
749  * Since: 2.22
750  */
751 guint16
752 g_network_address_get_port (GNetworkAddress *addr)
753 {
754   g_return_val_if_fail (G_IS_NETWORK_ADDRESS (addr), 0);
755
756   return addr->priv->port;
757 }
758
759 /**
760  * g_network_address_get_scheme:
761  * @addr: a #GNetworkAddress
762  *
763  * Gets @addr's scheme
764  *
765  * Return value: @addr's scheme (%NULL if not built from URI)
766  *
767  * Since: 2.26
768  */
769 const gchar *
770 g_network_address_get_scheme (GNetworkAddress *addr)
771 {
772   g_return_val_if_fail (G_IS_NETWORK_ADDRESS (addr), NULL);
773
774   return addr->priv->scheme;
775 }
776
777 #define G_TYPE_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (_g_network_address_address_enumerator_get_type ())
778 #define G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_NETWORK_ADDRESS_ADDRESS_ENUMERATOR, GNetworkAddressAddressEnumerator))
779
780 typedef struct {
781   GSocketAddressEnumerator parent_instance;
782
783   GNetworkAddress *addr;
784   GList *a;
785 } GNetworkAddressAddressEnumerator;
786
787 typedef struct {
788   GSocketAddressEnumeratorClass parent_class;
789
790 } GNetworkAddressAddressEnumeratorClass;
791
792 G_DEFINE_TYPE (GNetworkAddressAddressEnumerator, _g_network_address_address_enumerator, G_TYPE_SOCKET_ADDRESS_ENUMERATOR)
793
794 static void
795 g_network_address_address_enumerator_finalize (GObject *object)
796 {
797   GNetworkAddressAddressEnumerator *addr_enum =
798     G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (object);
799
800   g_object_unref (addr_enum->addr);
801
802   G_OBJECT_CLASS (_g_network_address_address_enumerator_parent_class)->finalize (object);
803 }
804
805 static GSocketAddress *
806 g_network_address_address_enumerator_next (GSocketAddressEnumerator  *enumerator,
807                                            GCancellable              *cancellable,
808                                            GError                   **error)
809 {
810   GNetworkAddressAddressEnumerator *addr_enum =
811     G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (enumerator);
812   GSocketAddress *sockaddr;
813
814   if (!addr_enum->addr->priv->sockaddrs)
815     {
816       GResolver *resolver = g_resolver_get_default ();
817       GList *addresses;
818
819       addresses = g_resolver_lookup_by_name (resolver,
820                                              addr_enum->addr->priv->hostname,
821                                              cancellable, error);
822       g_object_unref (resolver);
823
824       if (!addresses)
825         return NULL;
826
827       g_network_address_set_addresses (addr_enum->addr, addresses);
828       addr_enum->a = addr_enum->addr->priv->sockaddrs;
829     }
830
831   if (!addr_enum->a)
832     return NULL;
833   else
834     {
835       sockaddr = addr_enum->a->data;
836       addr_enum->a = addr_enum->a->next;
837       return g_object_ref (sockaddr);
838     }
839 }
840
841 static void
842 got_addresses (GObject      *source_object,
843                GAsyncResult *result,
844                gpointer      user_data)
845 {
846   GSimpleAsyncResult *simple = user_data;
847   GNetworkAddressAddressEnumerator *addr_enum =
848     g_simple_async_result_get_op_res_gpointer (simple);
849   GResolver *resolver = G_RESOLVER (source_object);
850   GList *addresses;
851   GError *error = NULL;
852
853   addresses = g_resolver_lookup_by_name_finish (resolver, result, &error);
854   if (!addr_enum->addr->priv->sockaddrs)
855     {
856       if (error)
857         {
858           g_simple_async_result_take_error (simple, error);
859         }
860       else
861         {
862           g_network_address_set_addresses (addr_enum->addr, addresses);
863           addr_enum->a = addr_enum->addr->priv->sockaddrs;
864         }
865     }
866   else if (error)
867     g_error_free (error);
868
869   g_object_unref (resolver);
870
871   g_simple_async_result_complete (simple);
872   g_object_unref (simple);
873 }
874
875 static void
876 g_network_address_address_enumerator_next_async (GSocketAddressEnumerator  *enumerator,
877                                                  GCancellable              *cancellable,
878                                                  GAsyncReadyCallback        callback,
879                                                  gpointer                   user_data)
880 {
881   GNetworkAddressAddressEnumerator *addr_enum =
882     G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (enumerator);
883   GSimpleAsyncResult *simple;
884
885   simple = g_simple_async_result_new (G_OBJECT (enumerator),
886                                       callback, user_data,
887                                       g_network_address_address_enumerator_next_async);
888
889   if (!addr_enum->addr->priv->sockaddrs)
890     {
891       GResolver *resolver = g_resolver_get_default ();
892
893       g_simple_async_result_set_op_res_gpointer (simple, g_object_ref (addr_enum), g_object_unref);
894       g_resolver_lookup_by_name_async (resolver,
895                                        addr_enum->addr->priv->hostname,
896                                        cancellable,
897                                        got_addresses, simple);
898     }
899   else
900     {
901       g_simple_async_result_complete_in_idle (simple);
902       g_object_unref (simple);
903     }
904 }
905
906 static GSocketAddress *
907 g_network_address_address_enumerator_next_finish (GSocketAddressEnumerator  *enumerator,
908                                                   GAsyncResult              *result,
909                                                   GError                   **error)
910 {
911   GNetworkAddressAddressEnumerator *addr_enum =
912     G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (enumerator);
913   GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
914   GSocketAddress *sockaddr;
915
916   if (g_simple_async_result_propagate_error (simple, error))
917     return NULL;
918   else if (!addr_enum->a)
919     return NULL;
920   else
921     {
922       sockaddr = addr_enum->a->data;
923       addr_enum->a = addr_enum->a->next;
924       return g_object_ref (sockaddr);
925     }
926 }
927
928 static void
929 _g_network_address_address_enumerator_init (GNetworkAddressAddressEnumerator *enumerator)
930 {
931 }
932
933 static void
934 _g_network_address_address_enumerator_class_init (GNetworkAddressAddressEnumeratorClass *addrenum_class)
935 {
936   GObjectClass *object_class = G_OBJECT_CLASS (addrenum_class);
937   GSocketAddressEnumeratorClass *enumerator_class =
938     G_SOCKET_ADDRESS_ENUMERATOR_CLASS (addrenum_class);
939
940   enumerator_class->next = g_network_address_address_enumerator_next;
941   enumerator_class->next_async = g_network_address_address_enumerator_next_async;
942   enumerator_class->next_finish = g_network_address_address_enumerator_next_finish;
943   object_class->finalize = g_network_address_address_enumerator_finalize;
944 }
945
946 static GSocketAddressEnumerator *
947 g_network_address_connectable_enumerate (GSocketConnectable *connectable)
948 {
949   GNetworkAddressAddressEnumerator *addr_enum;
950
951   addr_enum = g_object_new (G_TYPE_NETWORK_ADDRESS_ADDRESS_ENUMERATOR, NULL);
952   addr_enum->addr = g_object_ref (connectable);
953
954   return (GSocketAddressEnumerator *)addr_enum;
955 }
956
957 static GSocketAddressEnumerator *
958 g_network_address_connectable_proxy_enumerate (GSocketConnectable *connectable)
959 {
960   GNetworkAddress *self = G_NETWORK_ADDRESS (connectable);
961   GSocketAddressEnumerator *proxy_enum;
962   gchar *uri;
963
964   uri = _g_uri_from_authority (self->priv->scheme ? self->priv->scheme : "none",
965                                self->priv->hostname,
966                                self->priv->port,
967                                NULL);
968
969   proxy_enum = g_object_new (G_TYPE_PROXY_ADDRESS_ENUMERATOR,
970                              "connectable", connectable,
971                              "uri", uri,
972                              NULL);
973
974   g_free (uri);
975
976   return proxy_enum;
977 }