Merge remote branch 'gvdb/master'
[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 "gresolver.h"
34 #include "gsimpleasyncresult.h"
35 #include "gsocketaddressenumerator.h"
36 #include "gioerror.h"
37 #include "gsocketconnectable.h"
38
39 #include <string.h>
40
41 #include "gioalias.h"
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 };
68
69 enum {
70   PROP_0,
71   PROP_HOSTNAME,
72   PROP_PORT,
73 };
74
75 static void g_network_address_set_property (GObject      *object,
76                                             guint         prop_id,
77                                             const GValue *value,
78                                             GParamSpec   *pspec);
79 static void g_network_address_get_property (GObject      *object,
80                                             guint         prop_id,
81                                             GValue       *value,
82                                             GParamSpec   *pspec);
83
84 static void                      g_network_address_connectable_iface_init (GSocketConnectableIface *iface);
85 static GSocketAddressEnumerator *g_network_address_connectable_enumerate  (GSocketConnectable      *connectable);
86
87 G_DEFINE_TYPE_WITH_CODE (GNetworkAddress, g_network_address, G_TYPE_OBJECT,
88                          G_IMPLEMENT_INTERFACE (G_TYPE_SOCKET_CONNECTABLE,
89                                                 g_network_address_connectable_iface_init))
90
91 static void
92 g_network_address_finalize (GObject *object)
93 {
94   GNetworkAddress *addr = G_NETWORK_ADDRESS (object);
95
96   g_free (addr->priv->hostname);
97
98   if (addr->priv->sockaddrs)
99     {
100       GList *a;
101
102       for (a = addr->priv->sockaddrs; a; a = a->next)
103         g_object_unref (a->data);
104       g_list_free (addr->priv->sockaddrs);
105     }
106
107   G_OBJECT_CLASS (g_network_address_parent_class)->finalize (object);
108 }
109
110 static void
111 g_network_address_class_init (GNetworkAddressClass *klass)
112 {
113   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
114
115   g_type_class_add_private (klass, sizeof (GNetworkAddressPrivate));
116
117   gobject_class->set_property = g_network_address_set_property;
118   gobject_class->get_property = g_network_address_get_property;
119   gobject_class->finalize = g_network_address_finalize;
120
121   g_object_class_install_property (gobject_class, PROP_HOSTNAME,
122                                    g_param_spec_string ("hostname",
123                                                         P_("Hostname"),
124                                                         P_("Hostname to resolve"),
125                                                         NULL,
126                                                         G_PARAM_READWRITE |
127                                                         G_PARAM_CONSTRUCT_ONLY |
128                                                         G_PARAM_STATIC_STRINGS));
129   g_object_class_install_property (gobject_class, PROP_PORT,
130                                    g_param_spec_uint ("port",
131                                                       P_("Port"),
132                                                       P_("Network port"),
133                                                       0, 65535, 0,
134                                                       G_PARAM_READWRITE |
135                                                       G_PARAM_CONSTRUCT_ONLY |
136                                                       G_PARAM_STATIC_STRINGS));
137 }
138
139 static void
140 g_network_address_connectable_iface_init (GSocketConnectableIface *connectable_iface)
141 {
142   connectable_iface->enumerate  = g_network_address_connectable_enumerate;
143 }
144
145 static void
146 g_network_address_init (GNetworkAddress *addr)
147 {
148   addr->priv = G_TYPE_INSTANCE_GET_PRIVATE (addr, G_TYPE_NETWORK_ADDRESS,
149                                             GNetworkAddressPrivate);
150 }
151
152 static void
153 g_network_address_set_property (GObject      *object,
154                                 guint         prop_id,
155                                 const GValue *value,
156                                 GParamSpec   *pspec)
157 {
158   GNetworkAddress *addr = G_NETWORK_ADDRESS (object);
159
160   switch (prop_id)
161     {
162     case PROP_HOSTNAME:
163       if (addr->priv->hostname)
164         g_free (addr->priv->hostname);
165       addr->priv->hostname = g_value_dup_string (value);
166       break;
167
168     case PROP_PORT:
169       addr->priv->port = g_value_get_uint (value);
170       break;
171
172     default:
173       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
174       break;
175     }
176
177 }
178
179 static void
180 g_network_address_get_property (GObject    *object,
181                                 guint       prop_id,
182                                 GValue     *value,
183                                 GParamSpec *pspec)
184 {
185   GNetworkAddress *addr = G_NETWORK_ADDRESS (object);
186
187   switch (prop_id)
188     {
189     case PROP_HOSTNAME:
190       g_value_set_string (value, addr->priv->hostname);
191       break;
192
193     case PROP_PORT:
194       g_value_set_uint (value, addr->priv->port);
195       break;
196
197     default:
198       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
199       break;
200     }
201
202 }
203
204 static void
205 g_network_address_set_addresses (GNetworkAddress *addr,
206                                  GList           *addresses)
207 {
208   GList *a;
209   GSocketAddress *sockaddr;
210
211   g_return_if_fail (addresses != NULL && addr->priv->sockaddrs == NULL);
212
213   for (a = addresses; a; a = a->next)
214     {
215       sockaddr = g_inet_socket_address_new (a->data, addr->priv->port);
216       addr->priv->sockaddrs = g_list_prepend (addr->priv->sockaddrs, sockaddr);
217       g_object_unref (a->data);
218     }
219   g_list_free (addresses);
220   addr->priv->sockaddrs = g_list_reverse (addr->priv->sockaddrs);
221 }
222
223 /**
224  * g_network_address_new:
225  * @hostname: the hostname
226  * @port: the port
227  *
228  * Creates a new #GSocketConnectable for connecting to the given
229  * @hostname and @port.
230  *
231  * Return value: the new #GNetworkAddress
232  *
233  * Since: 2.22
234  */
235 GSocketConnectable *
236 g_network_address_new (const gchar *hostname,
237                        guint16      port)
238 {
239   return g_object_new (G_TYPE_NETWORK_ADDRESS,
240                        "hostname", hostname,
241                        "port", port,
242                        NULL);
243 }
244
245 /**
246  * g_network_address_parse:
247  * @host_and_port: the hostname and optionally a port
248  * @default_port: the default port if not in @host_and_port
249  * @error: a pointer to a #GError, or %NULL
250  *
251  * Creates a new #GSocketConnectable for connecting to the given
252  * @hostname and @port. May fail and return %NULL in case
253  * parsing @host_and_port fails.
254  *
255  * @host_and_port may be in any of a number of recognised formats: an IPv6
256  * address, an IPv4 address, or a domain name (in which case a DNS
257  * lookup is performed). Quoting with [] is supported for all address
258  * types. A port override may be specified in the usual way with a
259  * colon. Ports may be given as decimal numbers or symbolic names (in
260  * which case an /etc/services lookup is performed).
261  *
262  * If no port is specified in @host_and_port then @default_port will be
263  * used as the port number to connect to.
264  *
265  * In general, @host_and_port is expected to be provided by the user
266  * (allowing them to give the hostname, and a port overide if necessary)
267  * and @default_port is expected to be provided by the application.
268  *
269  * Return value: the new #GNetworkAddress, or %NULL on error
270  *
271  * Since: 2.22
272  */
273 GSocketConnectable *
274 g_network_address_parse (const gchar  *host_and_port,
275                          guint16       default_port,
276                          GError      **error)
277 {
278   GSocketConnectable *connectable;
279   const gchar *port;
280   guint16 portnum;
281   gchar *name;
282
283   g_return_val_if_fail (host_and_port != NULL, NULL);
284
285   port = NULL;
286   if (host_and_port[0] == '[')
287     /* escaped host part (to allow, eg. "[2001:db8::1]:888") */
288     {
289       const gchar *end;
290
291       end = strchr (host_and_port, ']');
292       if (end == NULL)
293         {
294           g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
295                        _("Hostname '%s' contains '[' but not ']'"), host_and_port);
296           return NULL;
297         }
298
299       if (end[1] == '\0')
300         port = NULL;
301       else if (end[1] == ':')
302         port = &end[2];
303       else
304         {
305           g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
306                        "The ']' character (in hostname '%s') must come at the"
307                        " end or be immediately followed by ':' and a port",
308                        host_and_port);
309           return NULL;
310         }
311
312       name = g_strndup (host_and_port + 1, end - host_and_port - 1);
313     }
314
315   else if ((port = strchr (host_and_port, ':')))
316     /* string has a ':' in it */
317     {
318       /* skip ':' */
319       port++;
320
321       if (strchr (port, ':'))
322         /* more than one ':' in string */
323         {
324           /* this is actually an unescaped IPv6 address */
325           name = g_strdup (host_and_port);
326           port = NULL;
327         }
328       else
329         name = g_strndup (host_and_port, port - host_and_port - 1);
330     }
331
332   else
333     /* plain hostname, no port */
334     name = g_strdup (host_and_port);
335
336   if (port != NULL)
337     {
338       if (port[0] == '\0')
339         {
340           g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
341                        "If a ':' character is given, it must be followed by a "
342                        "port (in hostname '%s').", host_and_port);
343           g_free (name);
344           return NULL;
345         }
346
347       else if ('0' <= port[0] && port[0] <= '9')
348         {
349           char *end;
350           long value;
351
352           value = strtol (port, &end, 10);
353           if (*end != '\0' || value < 0 || value > G_MAXUINT16)
354             {
355               g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
356                            "Invalid numeric port '%s' specified in hostname '%s'",
357                            port, host_and_port);
358               g_free (name);
359               return NULL;
360             }
361
362           portnum = value;
363         }
364
365       else
366         {
367           struct servent *entry;
368
369           entry = getservbyname (port, "tcp");
370           if (entry == NULL)
371             {
372               g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
373                            "Unknown service '%s' specified in hostname '%s'",
374                            port, host_and_port);
375 #ifdef HAVE_ENDSERVENT
376               endservent ();
377 #endif
378               g_free (name);
379               return NULL;
380             }
381
382           portnum = g_ntohs (entry->s_port);
383
384 #ifdef HAVE_ENDSERVENT
385           endservent ();
386 #endif
387         }
388     }
389   else
390     {
391       /* No port in host_and_port */
392       portnum = default_port;
393     }
394
395   connectable = g_network_address_new (name, portnum);
396   g_free (name);
397
398   return connectable;
399 }
400
401 /**
402  * g_network_address_get_hostname:
403  * @addr: a #GNetworkAddress
404  *
405  * Gets @addr's hostname. This might be either UTF-8 or ASCII-encoded,
406  * depending on what @addr was created with.
407  *
408  * Return value: @addr's hostname
409  *
410  * Since: 2.22
411  */
412 const gchar *
413 g_network_address_get_hostname (GNetworkAddress *addr)
414 {
415   g_return_val_if_fail (G_IS_NETWORK_ADDRESS (addr), NULL);
416
417   return addr->priv->hostname;
418 }
419
420 /**
421  * g_network_address_get_port:
422  * @addr: a #GNetworkAddress
423  *
424  * Gets @addr's port number
425  *
426  * Return value: @addr's port (which may be 0)
427  *
428  * Since: 2.22
429  */
430 guint16
431 g_network_address_get_port (GNetworkAddress *addr)
432 {
433   g_return_val_if_fail (G_IS_NETWORK_ADDRESS (addr), 0);
434
435   return addr->priv->port;
436 }
437
438 #define G_TYPE_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (_g_network_address_address_enumerator_get_type ())
439 #define G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_NETWORK_ADDRESS_ADDRESS_ENUMERATOR, GNetworkAddressAddressEnumerator))
440
441 typedef struct {
442   GSocketAddressEnumerator parent_instance;
443
444   GNetworkAddress *addr;
445   GList *a;
446 } GNetworkAddressAddressEnumerator;
447
448 typedef struct {
449   GSocketAddressEnumeratorClass parent_class;
450
451 } GNetworkAddressAddressEnumeratorClass;
452
453 G_DEFINE_TYPE (GNetworkAddressAddressEnumerator, _g_network_address_address_enumerator, G_TYPE_SOCKET_ADDRESS_ENUMERATOR)
454
455 static void
456 g_network_address_address_enumerator_finalize (GObject *object)
457 {
458   GNetworkAddressAddressEnumerator *addr_enum =
459     G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (object);
460
461   g_object_unref (addr_enum->addr);
462
463   G_OBJECT_CLASS (_g_network_address_address_enumerator_parent_class)->finalize (object);
464 }
465
466 static GSocketAddress *
467 g_network_address_address_enumerator_next (GSocketAddressEnumerator  *enumerator,
468                                            GCancellable              *cancellable,
469                                            GError                   **error)
470 {
471   GNetworkAddressAddressEnumerator *addr_enum =
472     G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (enumerator);
473   GSocketAddress *sockaddr;
474
475   if (!addr_enum->addr->priv->sockaddrs)
476     {
477       GResolver *resolver = g_resolver_get_default ();
478       GList *addresses;
479
480       addresses = g_resolver_lookup_by_name (resolver,
481                                              addr_enum->addr->priv->hostname,
482                                              cancellable, error);
483       g_object_unref (resolver);
484
485       if (!addresses)
486         return NULL;
487
488       g_network_address_set_addresses (addr_enum->addr, addresses);
489       addr_enum->a = addr_enum->addr->priv->sockaddrs;
490     }
491
492   if (!addr_enum->a)
493     return NULL;
494   else
495     {
496       sockaddr = addr_enum->a->data;
497       addr_enum->a = addr_enum->a->next;
498       return g_object_ref (sockaddr);
499     }
500 }
501
502 static void
503 got_addresses (GObject      *source_object,
504                GAsyncResult *result,
505                gpointer      user_data)
506 {
507   GSimpleAsyncResult *simple = user_data;
508   GNetworkAddressAddressEnumerator *addr_enum =
509     g_simple_async_result_get_op_res_gpointer (simple);
510   GResolver *resolver = G_RESOLVER (source_object);
511   GList *addresses;
512   GError *error = NULL;
513
514   addresses = g_resolver_lookup_by_name_finish (resolver, result, &error);
515   if (!addr_enum->addr->priv->sockaddrs)
516     {
517       if (error)
518         {
519           g_simple_async_result_set_from_error (simple, error);
520           g_error_free (error);
521         }
522       else
523         {
524           g_network_address_set_addresses (addr_enum->addr, addresses);
525           addr_enum->a = addr_enum->addr->priv->sockaddrs;
526         }
527     }
528   else if (error)
529     g_error_free (error);
530
531   g_object_unref (resolver);
532
533   g_simple_async_result_complete (simple);
534   g_object_unref (simple);
535 }
536
537 static void
538 g_network_address_address_enumerator_next_async (GSocketAddressEnumerator  *enumerator,
539                                                  GCancellable              *cancellable,
540                                                  GAsyncReadyCallback        callback,
541                                                  gpointer                   user_data)
542 {
543   GNetworkAddressAddressEnumerator *addr_enum =
544     G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (enumerator);
545   GSimpleAsyncResult *simple;
546
547   simple = g_simple_async_result_new (G_OBJECT (enumerator),
548                                       callback, user_data,
549                                       g_network_address_address_enumerator_next_async);
550
551   if (!addr_enum->addr->priv->sockaddrs)
552     {
553       GResolver *resolver = g_resolver_get_default ();
554
555       g_simple_async_result_set_op_res_gpointer (simple, g_object_ref (addr_enum), g_object_unref);
556       g_resolver_lookup_by_name_async (resolver,
557                                        addr_enum->addr->priv->hostname,
558                                        cancellable,
559                                        got_addresses, simple);
560     }
561   else
562     {
563       g_simple_async_result_complete_in_idle (simple);
564       g_object_unref (simple);
565     }
566 }
567
568 static GSocketAddress *
569 g_network_address_address_enumerator_next_finish (GSocketAddressEnumerator  *enumerator,
570                                                   GAsyncResult              *result,
571                                                   GError                   **error)
572 {
573   GNetworkAddressAddressEnumerator *addr_enum =
574     G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (enumerator);
575   GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
576   GSocketAddress *sockaddr;
577
578   if (g_simple_async_result_propagate_error (simple, error))
579     return NULL;
580   else if (!addr_enum->a)
581     return NULL;
582   else
583     {
584       sockaddr = addr_enum->a->data;
585       addr_enum->a = addr_enum->a->next;
586       return g_object_ref (sockaddr);
587     }
588 }
589
590 static void
591 _g_network_address_address_enumerator_init (GNetworkAddressAddressEnumerator *enumerator)
592 {
593 }
594
595 static void
596 _g_network_address_address_enumerator_class_init (GNetworkAddressAddressEnumeratorClass *addrenum_class)
597 {
598   GObjectClass *object_class = G_OBJECT_CLASS (addrenum_class);
599   GSocketAddressEnumeratorClass *enumerator_class =
600     G_SOCKET_ADDRESS_ENUMERATOR_CLASS (addrenum_class);
601
602   enumerator_class->next = g_network_address_address_enumerator_next;
603   enumerator_class->next_async = g_network_address_address_enumerator_next_async;
604   enumerator_class->next_finish = g_network_address_address_enumerator_next_finish;
605   object_class->finalize = g_network_address_address_enumerator_finalize;
606 }
607
608 static GSocketAddressEnumerator *
609 g_network_address_connectable_enumerate (GSocketConnectable *connectable)
610 {
611   GNetworkAddressAddressEnumerator *addr_enum;
612
613   addr_enum = g_object_new (G_TYPE_NETWORK_ADDRESS_ADDRESS_ENUMERATOR, NULL);
614   addr_enum->addr = g_object_ref (connectable);
615
616   return (GSocketAddressEnumerator *)addr_enum;
617 }
618
619 #define __G_NETWORK_ADDRESS_C__
620 #include "gioaliasdef.c"