GResolver wrappers: GNetworkAddress, GNetworkService, GSocketConnectable
[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 "gnetworkaddress.h"
28 #include "gasyncresult.h"
29 #include "ginetaddress.h"
30 #include "ginetsocketaddress.h"
31 #include "gresolver.h"
32 #include "gsimpleasyncresult.h"
33 #include "gsocketaddressenumerator.h"
34 #include "gsocketconnectable.h"
35
36 #include <string.h>
37
38 #include "gioalias.h"
39
40 /**
41  * SECTION:gnetworkaddress
42  * @short_description: a #GSocketConnectable for resolving hostnames
43  * @include: gio/gio.h
44  *
45  * #GNetworkAddress provides an easy way to resolve a hostname and
46  * then attempt to connect to that host, handling the possibility of
47  * multiple IP addresses and multiple address families.
48  *
49  * See #GSocketConnectable for and example of using the connectable
50  * interface.
51  **/
52
53 /**
54  * GNetworkAddress:
55  *
56  * A #GSocketConnectable for resolving a hostname and connecting to
57  * that host.
58  **/
59
60 struct _GNetworkAddressPrivate {
61   gchar *hostname;
62   guint16 port;
63   GList *sockaddrs;
64 };
65
66 enum {
67   PROP_0,
68   PROP_HOSTNAME,
69   PROP_PORT,
70 };
71
72 static void g_network_address_set_property (GObject      *object,
73                                             guint         prop_id,
74                                             const GValue *value,
75                                             GParamSpec   *pspec);
76 static void g_network_address_get_property (GObject      *object,
77                                             guint         prop_id,
78                                             GValue       *value,
79                                             GParamSpec   *pspec);
80
81 static void                      g_network_address_connectable_iface_init (GSocketConnectableIface *iface);
82 static GSocketAddressEnumerator *g_network_address_connectable_enumerate  (GSocketConnectable      *connectable);
83
84 G_DEFINE_TYPE_WITH_CODE (GNetworkAddress, g_network_address, G_TYPE_OBJECT,
85                          G_IMPLEMENT_INTERFACE (G_TYPE_SOCKET_CONNECTABLE,
86                                                 g_network_address_connectable_iface_init))
87
88 static void
89 g_network_address_finalize (GObject *object)
90 {
91   GNetworkAddress *addr = G_NETWORK_ADDRESS (object);
92
93   g_free (addr->priv->hostname);
94
95   if (addr->priv->sockaddrs)
96     {
97       GList *a;
98
99       for (a = addr->priv->sockaddrs; a; a = a->next)
100         g_object_unref (a->data);
101       g_list_free (addr->priv->sockaddrs);
102     }
103
104   G_OBJECT_CLASS (g_network_address_parent_class)->finalize (object);
105 }
106
107 static void
108 g_network_address_class_init (GNetworkAddressClass *klass)
109 {
110   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
111
112   g_type_class_add_private (klass, sizeof (GNetworkAddressPrivate));
113
114   gobject_class->set_property = g_network_address_set_property;
115   gobject_class->get_property = g_network_address_get_property;
116   gobject_class->finalize = g_network_address_finalize;
117
118   g_object_class_install_property (gobject_class, PROP_HOSTNAME,
119                                    g_param_spec_string ("hostname",
120                                                         P_("Hostname"),
121                                                         P_("Hostname to resolve"),
122                                                         NULL,
123                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
124   g_object_class_install_property (gobject_class, PROP_PORT,
125                                    g_param_spec_uint ("port",
126                                                       P_("Port"),
127                                                       P_("Network port"),
128                                                       0, 65535, 0,
129                                                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
130 }
131
132 static void
133 g_network_address_connectable_iface_init (GSocketConnectableIface *connectable_iface)
134 {
135   connectable_iface->enumerate  = g_network_address_connectable_enumerate;
136 }
137
138 static void
139 g_network_address_init (GNetworkAddress *addr)
140 {
141   addr->priv = G_TYPE_INSTANCE_GET_PRIVATE (addr, G_TYPE_NETWORK_ADDRESS,
142                                             GNetworkAddressPrivate);
143 }
144
145 static void
146 g_network_address_set_property (GObject      *object,
147                                 guint         prop_id,
148                                 const GValue *value,
149                                 GParamSpec   *pspec)
150 {
151   GNetworkAddress *addr = G_NETWORK_ADDRESS (object);
152
153   switch (prop_id) 
154     {
155     case PROP_HOSTNAME:
156       if (addr->priv->hostname)
157         g_free (addr->priv->hostname);
158       addr->priv->hostname = g_value_dup_string (value);
159       break;
160
161     case PROP_PORT:
162       addr->priv->port = g_value_get_uint (value);
163       break;
164
165     default:
166       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
167       break;
168     }
169
170 }
171
172 static void
173 g_network_address_get_property (GObject    *object,
174                                 guint       prop_id,
175                                 GValue     *value,
176                                 GParamSpec *pspec)
177 {
178   GNetworkAddress *addr = G_NETWORK_ADDRESS (object);
179
180   switch (prop_id)
181     { 
182     case PROP_HOSTNAME:
183       g_value_set_string (value, addr->priv->hostname);
184       break;
185
186     case PROP_PORT:
187       g_value_set_uint (value, addr->priv->port);
188       break;
189
190     default:
191       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
192       break;
193     }
194
195 }
196
197 static void
198 g_network_address_set_addresses (GNetworkAddress *addr,
199                                  GList           *addresses)
200 {
201   GList *a;
202   GSocketAddress *sockaddr;
203
204   g_return_if_fail (addresses != NULL && addr->priv->sockaddrs == NULL);
205
206   for (a = addresses; a; a = a->next)
207     {
208       sockaddr = g_inet_socket_address_new (a->data, addr->priv->port);
209       addr->priv->sockaddrs = g_list_prepend (addr->priv->sockaddrs, sockaddr);
210       g_object_unref (a->data);
211     }
212   g_list_free (addresses);
213   addr->priv->sockaddrs = g_list_reverse (addr->priv->sockaddrs);
214 }
215
216 /**
217  * g_network_address_new:
218  * @hostname: the hostname
219  * @port: the port
220  *
221  * Creates a new #GSocketConnectable for connecting to the given
222  * @hostname and @port.
223  *
224  * Return value: the new #GNetworkAddress
225  *
226  * Since: 2.22
227  **/
228 GSocketConnectable *
229 g_network_address_new (const gchar *hostname,
230                        guint16      port)
231 {
232   return g_object_new (G_TYPE_NETWORK_ADDRESS,
233                        "hostname", hostname,
234                        "port", port,
235                        NULL);
236 }
237
238 /**
239  * g_network_address_get_hostname:
240  * @addr: a #GNetworkAddress
241  *
242  * Gets @addr's hostname. This might be either UTF-8 or ASCII-encoded,
243  * depending on what @addr was created with.
244  *
245  * Return value: @addr's hostname
246  *
247  * Since: 2.22
248  **/
249 const gchar *
250 g_network_address_get_hostname (GNetworkAddress *addr)
251 {
252   g_return_val_if_fail (G_IS_NETWORK_ADDRESS (addr), NULL);
253
254   return addr->priv->hostname;
255 }
256
257 /**
258  * g_network_address_get_port:
259  * @addr: a #GNetworkAddress
260  *
261  * Gets @addr's port number
262  *
263  * Return value: @addr's port (which may be %0)
264  *
265  * Since: 2.22
266  **/
267 guint16
268 g_network_address_get_port (GNetworkAddress *addr)
269 {
270   g_return_val_if_fail (G_IS_NETWORK_ADDRESS (addr), 0);
271
272   return addr->priv->port;
273 }
274
275 #define G_TYPE_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (_g_network_address_address_enumerator_get_type ())
276 #define G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_NETWORK_ADDRESS_ADDRESS_ENUMERATOR, GNetworkAddressAddressEnumerator))
277
278 typedef struct {
279   GSocketAddressEnumerator parent_instance;
280
281   GNetworkAddress *addr;
282   GList *a;
283 } GNetworkAddressAddressEnumerator;
284
285 typedef struct {
286   GSocketAddressEnumeratorClass parent_class;
287
288 } GNetworkAddressAddressEnumeratorClass;
289
290 G_DEFINE_TYPE (GNetworkAddressAddressEnumerator, _g_network_address_address_enumerator, G_TYPE_SOCKET_ADDRESS_ENUMERATOR)
291
292 static void
293 g_network_address_address_enumerator_finalize (GObject *object)
294 {
295   GNetworkAddressAddressEnumerator *addr_enum =
296     G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (object);
297
298   g_object_unref (addr_enum->addr);
299
300   G_OBJECT_CLASS (_g_network_address_address_enumerator_parent_class)->finalize (object);
301 }
302
303 static GSocketAddress *
304 g_network_address_address_enumerator_next (GSocketAddressEnumerator  *enumerator,
305                                            GCancellable              *cancellable,
306                                            GError                   **error)
307 {
308   GNetworkAddressAddressEnumerator *addr_enum =
309     G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (enumerator);
310   GSocketAddress *sockaddr;
311
312   if (!addr_enum->addr->priv->sockaddrs)
313     {
314       GResolver *resolver = g_resolver_get_default ();
315       GList *addresses;
316
317       addresses = g_resolver_lookup_by_name (resolver,
318                                              addr_enum->addr->priv->hostname,
319                                              cancellable, error);
320       g_object_unref (resolver);
321
322       if (!addresses)
323         return NULL;
324
325       g_network_address_set_addresses (addr_enum->addr, addresses);
326       addr_enum->a = addr_enum->addr->priv->sockaddrs;
327     }
328
329   if (!addr_enum->a)
330     return NULL;
331   else
332     {
333       sockaddr = addr_enum->a->data;
334       addr_enum->a = addr_enum->a->next;
335       return g_object_ref (sockaddr);
336     }
337 }
338
339 static void
340 got_addresses (GObject      *source_object,
341                GAsyncResult *result,
342                gpointer      user_data)
343 {
344   GSimpleAsyncResult *simple = user_data;
345   GNetworkAddressAddressEnumerator *addr_enum =
346     g_simple_async_result_get_op_res_gpointer (simple);
347   GResolver *resolver = G_RESOLVER (source_object);
348   GList *addresses;
349   GError *error = NULL;
350
351   addresses = g_resolver_lookup_by_name_finish (resolver, result, &error);
352   if (!addr_enum->addr->priv->sockaddrs)
353     {
354       if (error)
355         {
356           g_simple_async_result_set_from_error (simple, error);
357           g_error_free (error);
358         }
359       else
360         {
361           g_network_address_set_addresses (addr_enum->addr, addresses);
362           addr_enum->a = addr_enum->addr->priv->sockaddrs;
363         }
364     }
365   else if (error)
366     g_error_free (error);
367
368   g_object_unref (resolver);
369
370   g_simple_async_result_complete (simple);
371   g_object_unref (simple);
372 }
373
374 static void
375 g_network_address_address_enumerator_next_async (GSocketAddressEnumerator  *enumerator,
376                                                  GCancellable              *cancellable,
377                                                  GAsyncReadyCallback        callback,
378                                                  gpointer                   user_data)
379 {
380   GNetworkAddressAddressEnumerator *addr_enum =
381     G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (enumerator);
382   GSimpleAsyncResult *simple;
383   GSocketAddress *sockaddr;
384
385   simple = g_simple_async_result_new (G_OBJECT (enumerator),
386                                       callback, user_data,
387                                       g_network_address_address_enumerator_next_async);
388
389   if (!addr_enum->addr->priv->sockaddrs)
390     {
391       GResolver *resolver = g_resolver_get_default ();
392
393       g_simple_async_result_set_op_res_gpointer (simple, g_object_ref (addr_enum), g_object_unref);
394       g_resolver_lookup_by_name_async (resolver,
395                                        addr_enum->addr->priv->hostname,
396                                        cancellable,
397                                        got_addresses, simple);
398     }
399   else
400     {
401       sockaddr = g_network_address_address_enumerator_next (enumerator, NULL, NULL);
402       if (sockaddr)
403         g_simple_async_result_set_op_res_gpointer (simple, sockaddr, g_object_unref);
404
405       g_simple_async_result_complete_in_idle (simple);
406       g_object_unref (simple);
407     }
408 }
409
410 static GSocketAddress *
411 g_network_address_address_enumerator_next_finish (GSocketAddressEnumerator  *enumerator,
412                                                   GAsyncResult              *result,
413                                                   GError                   **error)
414 {
415   GNetworkAddressAddressEnumerator *addr_enum =
416     G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (enumerator);
417   GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
418   GSocketAddress *sockaddr;
419
420   if (g_simple_async_result_propagate_error (simple, error))
421     return NULL;
422   else if (!addr_enum->a)
423     return NULL;
424   else
425     {
426       sockaddr = addr_enum->a->data;
427       addr_enum->a = addr_enum->a->next;
428       return g_object_ref (sockaddr);
429     }
430 }
431
432 static void
433 _g_network_address_address_enumerator_init (GNetworkAddressAddressEnumerator *enumerator)
434 {
435 }
436
437 static void
438 _g_network_address_address_enumerator_class_init (GNetworkAddressAddressEnumeratorClass *addrenum_class)
439 {
440   GObjectClass *object_class = G_OBJECT_CLASS (addrenum_class);
441   GSocketAddressEnumeratorClass *enumerator_class =
442     G_SOCKET_ADDRESS_ENUMERATOR_CLASS (addrenum_class);
443
444   enumerator_class->next = g_network_address_address_enumerator_next;
445   enumerator_class->next_async = g_network_address_address_enumerator_next_async;
446   enumerator_class->next_finish = g_network_address_address_enumerator_next_finish;
447   object_class->finalize = g_network_address_address_enumerator_finalize;
448 }
449
450 static GSocketAddressEnumerator *
451 g_network_address_connectable_enumerate (GSocketConnectable *connectable)
452 {
453   GNetworkAddressAddressEnumerator *addr_enum;
454
455   addr_enum = g_object_new (G_TYPE_NETWORK_ADDRESS_ADDRESS_ENUMERATOR, NULL);
456   addr_enum->addr = g_object_ref (connectable);
457
458   return (GSocketAddressEnumerator *)addr_enum;
459 }
460
461 #define __G_NETWORK_ADDRESS_C__
462 #include "gioaliasdef.c"