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