Misc gtk-doc fix-ups
[platform/upstream/libsoup.git] / libsoup / soup-address.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * soup-address.c: Internet address handing
4  *
5  * Copyright (C) 2000-2003, Ximian, Inc.
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include <config.h>
10 #endif
11
12 #include <unistd.h>
13 #include <errno.h>
14 #include <fcntl.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <sys/types.h>
18
19 #include "soup-address.h"
20 #include "soup-dns.h"
21 #include "soup-enum-types.h"
22 #include "soup-marshal.h"
23 #include "soup-misc.h"
24
25 #ifndef INET_ADDRSTRLEN
26 #  define INET_ADDRSTRLEN 16
27 #  define INET6_ADDRSTRLEN 46
28 #endif
29
30 #ifndef INADDR_NONE
31 #define INADDR_NONE -1
32 #endif
33
34 /**
35  * SECTION:soup-address
36  * @short_description: DNS support
37  *
38  * #SoupAddress represents the address of a TCP connection endpoint:
39  * both the IP address and the port. (It is somewhat like an
40  * object-oriented version of struct sockaddr.)
41  *
42  * If libsoup was built with IPv6 support, #SoupAddress will allow
43  * both IPv4 and IPv6 addresses.
44  **/
45
46 enum {
47         PROP_0,
48
49         PROP_NAME,
50         PROP_FAMILY,
51         PROP_PORT,
52         PROP_PHYSICAL,
53         PROP_SOCKADDR,
54
55         LAST_PROP
56 };
57
58 typedef struct {
59         struct sockaddr *sockaddr;
60
61         char *name, *physical;
62         guint port;
63
64         SoupDNSLookup *lookup;
65         guint timeout_id;
66 } SoupAddressPrivate;
67 #define SOUP_ADDRESS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_ADDRESS, SoupAddressPrivate))
68
69 /* sockaddr generic macros */
70 #define SOUP_SIN(priv) ((struct sockaddr_in *)priv->sockaddr)
71 #ifdef HAVE_IPV6
72 #define SOUP_SIN6(priv) ((struct sockaddr_in6 *)priv->sockaddr)
73 #endif
74
75 /* sockaddr family macros */
76 #define SOUP_ADDRESS_GET_FAMILY(priv) (priv->sockaddr->sa_family)
77 #define SOUP_ADDRESS_SET_FAMILY(priv, family) \
78         (priv->sockaddr->sa_family = family)
79 #ifdef HAVE_IPV6
80 #define SOUP_ADDRESS_FAMILY_IS_VALID(family) \
81         (family == AF_INET || family == AF_INET6)
82 #define SOUP_ADDRESS_FAMILY_SOCKADDR_SIZE(family) \
83         (family == AF_INET ? sizeof (struct sockaddr_in) : \
84                              sizeof (struct sockaddr_in6))
85 #define SOUP_ADDRESS_FAMILY_DATA_SIZE(family) \
86         (family == AF_INET ? sizeof (struct in_addr) : \
87                              sizeof (struct in6_addr))
88 #else
89 #define SOUP_ADDRESS_FAMILY_IS_VALID(family) (family == AF_INET)
90 #define SOUP_ADDRESS_FAMILY_SOCKADDR_SIZE(family) sizeof (struct sockaddr_in)
91 #define SOUP_ADDRESS_FAMILY_DATA_SIZE(family) sizeof (struct in_addr)
92 #endif
93
94 /* sockaddr port macros */
95 #define SOUP_ADDRESS_PORT_IS_VALID(port) (port >= 0 && port <= 65535)
96 #ifdef HAVE_IPV6
97 #define SOUP_ADDRESS_GET_PORT(priv) \
98         (priv->sockaddr->sa_family == AF_INET ? \
99                 SOUP_SIN(priv)->sin_port : \
100                 SOUP_SIN6(priv)->sin6_port)
101 #define SOUP_ADDRESS_SET_PORT(priv, port) \
102         G_STMT_START {                                  \
103         if (priv->sockaddr->sa_family == AF_INET)       \
104                 SOUP_SIN(priv)->sin_port = port;        \
105         else                                            \
106                 SOUP_SIN6(priv)->sin6_port = port;      \
107         } G_STMT_END
108 #else
109 #define SOUP_ADDRESS_GET_PORT(priv) (SOUP_SIN(priv)->sin_port)
110 #define SOUP_ADDRESS_SET_PORT(priv, port) (SOUP_SIN(priv)->sin_port = port)
111 #endif
112
113 /* sockaddr data macros */
114 #ifdef HAVE_IPV6
115 #define SOUP_ADDRESS_GET_DATA(priv) \
116         (priv->sockaddr->sa_family == AF_INET ? \
117                 (gpointer)&SOUP_SIN(priv)->sin_addr : \
118                 (gpointer)&SOUP_SIN6(priv)->sin6_addr)
119 #else
120 #define SOUP_ADDRESS_GET_DATA(priv) ((gpointer)&SOUP_SIN(priv)->sin_addr)
121 #endif
122 #define SOUP_ADDRESS_SET_DATA(priv, data, length) \
123         memcpy (SOUP_ADDRESS_GET_DATA (priv), data, length)
124
125
126 static GObject *constructor (GType                  type,
127                              guint                  n_construct_properties,
128                              GObjectConstructParam *construct_properties);
129 static void set_property (GObject *object, guint prop_id,
130                           const GValue *value, GParamSpec *pspec);
131 static void get_property (GObject *object, guint prop_id,
132                           GValue *value, GParamSpec *pspec);
133
134 G_DEFINE_TYPE (SoupAddress, soup_address, G_TYPE_OBJECT)
135
136 static void
137 soup_address_init (SoupAddress *addr)
138 {
139 }
140
141 static void
142 finalize (GObject *object)
143 {
144         SoupAddress *addr = SOUP_ADDRESS (object);
145         SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (addr);
146
147         if (priv->sockaddr)
148                 g_free (priv->sockaddr);
149         if (priv->name)
150                 g_free (priv->name);
151         if (priv->physical)
152                 g_free (priv->physical);
153
154         if (priv->lookup)
155                 soup_dns_lookup_free (priv->lookup);
156         if (priv->timeout_id)
157                 g_source_remove (priv->timeout_id);
158
159         G_OBJECT_CLASS (soup_address_parent_class)->finalize (object);
160 }
161
162 static void
163 soup_address_class_init (SoupAddressClass *address_class)
164 {
165         GObjectClass *object_class = G_OBJECT_CLASS (address_class);
166
167         soup_dns_init ();
168
169         g_type_class_add_private (address_class, sizeof (SoupAddressPrivate));
170
171         /* virtual method override */
172         object_class->constructor = constructor;
173         object_class->finalize = finalize;
174         object_class->set_property = set_property;
175         object_class->get_property = get_property;
176
177         /* properties */
178         g_object_class_install_property (
179                 object_class, PROP_NAME,
180                 g_param_spec_string (SOUP_ADDRESS_NAME,
181                                      "Name",
182                                      "Hostname for this address",
183                                      NULL,
184                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
185         g_object_class_install_property (
186                 object_class, PROP_FAMILY,
187                 g_param_spec_enum (SOUP_ADDRESS_FAMILY,
188                                    "Family",
189                                    "Address family for this address",
190                                    SOUP_TYPE_ADDRESS_FAMILY,
191                                    SOUP_ADDRESS_FAMILY_INVALID,
192                                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
193         g_object_class_install_property (
194                 object_class, PROP_PORT,
195                 g_param_spec_int (SOUP_ADDRESS_PORT,
196                                   "Port",
197                                   "Port for this address",
198                                   -1, 65535, -1,
199                                   G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
200         g_object_class_install_property (
201                 object_class, PROP_PHYSICAL,
202                 g_param_spec_string (SOUP_ADDRESS_PHYSICAL,
203                                      "Physical address",
204                                      "IP address for this address",
205                                      NULL,
206                                      G_PARAM_READABLE));
207         g_object_class_install_property (
208                 object_class, PROP_SOCKADDR,
209                 g_param_spec_pointer (SOUP_ADDRESS_SOCKADDR,
210                                       "sockaddr",
211                                       "struct sockaddr for this address",
212                                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
213
214 #ifdef G_OS_WIN32
215         /* This hopefully is a good place to call WSAStartup */
216         {
217                 WSADATA wsadata;
218                 if (WSAStartup (MAKEWORD (2, 0), &wsadata) != 0)
219                         g_error ("Windows Sockets could not be initialized");
220         }
221 #endif
222 }
223
224 static GObject *
225 constructor (GType                  type,
226              guint                  n_construct_properties,
227              GObjectConstructParam *construct_properties)
228 {
229         GObject *addr;
230         SoupAddressPrivate *priv;
231
232         addr = G_OBJECT_CLASS (soup_address_parent_class)->constructor (
233                 type, n_construct_properties, construct_properties);
234         if (!addr)
235                 return NULL;
236         priv = SOUP_ADDRESS_GET_PRIVATE (addr);
237
238         if (priv->name) {
239                 if (!priv->sockaddr)
240                         priv->lookup = soup_dns_lookup_name (priv->name);
241         } else if (priv->sockaddr)
242                 priv->lookup = soup_dns_lookup_address (priv->sockaddr);
243         else {
244                 g_object_unref (addr);
245                 return NULL;
246         }
247
248         return addr;
249 }
250
251 static void
252 set_property (GObject *object, guint prop_id,
253               const GValue *value, GParamSpec *pspec)
254 {
255         SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (object);
256         SoupAddressFamily family;
257         struct sockaddr *sa;
258         int len, port;
259
260         /* This is a mess because the properties are mostly orthogonal,
261          * but g_object_constructor wants to set a default value for each
262          * of them.
263          */
264
265         switch (prop_id) {
266         case PROP_NAME:
267                 priv->name = g_value_dup_string (value);
268                 break;
269
270         case PROP_FAMILY:
271                 family = g_value_get_enum (value);
272                 if (family == SOUP_ADDRESS_FAMILY_INVALID)
273                         return;
274                 g_return_if_fail (SOUP_ADDRESS_FAMILY_IS_VALID (family));
275                 g_return_if_fail (priv->sockaddr == NULL);
276
277                 priv->sockaddr = g_malloc0 (SOUP_ADDRESS_FAMILY_SOCKADDR_SIZE (family));
278                 SOUP_ADDRESS_SET_FAMILY (priv, family);
279                 SOUP_ADDRESS_SET_PORT (priv, htons (priv->port));
280                 break;
281
282         case PROP_PORT:
283                 port = g_value_get_int (value);
284                 if (port == -1)
285                         return;
286                 g_return_if_fail (SOUP_ADDRESS_PORT_IS_VALID (port));
287
288                 priv->port = port;
289                 if (priv->sockaddr)
290                         SOUP_ADDRESS_SET_PORT (priv, htons (port));
291                 break;
292
293         case PROP_SOCKADDR:
294                 sa = g_value_get_pointer (value);
295                 if (!sa)
296                         return;
297                 g_return_if_fail (priv->sockaddr == NULL);
298
299                 len = SOUP_ADDRESS_FAMILY_SOCKADDR_SIZE (sa->sa_family);
300                 priv->sockaddr = g_memdup (sa, len);
301                 priv->port = ntohs (SOUP_ADDRESS_GET_PORT (priv));
302                 break;
303         default:
304                 break;
305         }
306 }
307
308 static void
309 get_property (GObject *object, guint prop_id,
310               GValue *value, GParamSpec *pspec)
311 {
312         SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (object);
313
314         switch (prop_id) {
315         case PROP_NAME:
316                 g_value_set_string (value, priv->name);
317                 break;
318         case PROP_FAMILY:
319                 if (priv->sockaddr)
320                         g_value_set_enum (value, SOUP_ADDRESS_GET_FAMILY (priv));
321                 else
322                         g_value_set_enum (value, 0);
323                 break;
324         case PROP_PORT:
325                 g_value_set_int (value, priv->port);
326                 break;
327         case PROP_PHYSICAL:
328                 g_value_set_string (value, soup_address_get_physical (SOUP_ADDRESS (object)));
329                 break;
330         case PROP_SOCKADDR:
331                 g_value_set_pointer (value, priv->sockaddr);
332                 break;
333         default:
334                 break;
335         }
336 }
337
338 /**
339  * soup_address_new:
340  * @name: a hostname or physical address
341  * @port: a port number
342  *
343  * Creates a #SoupAddress from @name and @port. The #SoupAddress's IP
344  * address may not be available right away; the caller can call
345  * soup_address_resolve_async() or soup_address_resolve_sync() to
346  * force a DNS resolution.
347  *
348  * Return value: a #SoupAddress
349  **/
350 SoupAddress *
351 soup_address_new (const char *name, guint port)
352 {
353         g_return_val_if_fail (name != NULL, NULL);
354         g_return_val_if_fail (SOUP_ADDRESS_PORT_IS_VALID (port), NULL);
355
356         return g_object_new (SOUP_TYPE_ADDRESS,
357                              SOUP_ADDRESS_NAME, name,
358                              SOUP_ADDRESS_PORT, port,
359                              NULL);
360 }
361
362 /**
363  * soup_address_new_from_sockaddr:
364  * @sa: a pointer to a sockaddr
365  * @len: size of @sa
366  *
367  * Returns a #SoupAddress equivalent to @sa (or %NULL if @sa's
368  * address family isn't supported)
369  *
370  * Return value: the new #SoupAddress
371  **/
372 SoupAddress *
373 soup_address_new_from_sockaddr (struct sockaddr *sa, int len)
374 {
375         g_return_val_if_fail (sa != NULL, NULL);
376         g_return_val_if_fail (SOUP_ADDRESS_FAMILY_IS_VALID (sa->sa_family), NULL);
377         g_return_val_if_fail (len == SOUP_ADDRESS_FAMILY_SOCKADDR_SIZE (sa->sa_family), NULL);
378
379         return g_object_new (SOUP_TYPE_ADDRESS,
380                              SOUP_ADDRESS_SOCKADDR, sa,
381                              NULL);
382 }
383
384 /**
385  * SoupAddressFamily:
386  * @SOUP_ADDRESS_FAMILY_INVALID: an invalid %SoupAddress
387  * @SOUP_ADDRESS_FAMILY_IPV4: an IPv4 address
388  * @SOUP_ADDRESS_FAMILY_IPV6: an IPv6 address
389  *
390  * The supported address families. Note that the
391  * %SOUP_ADDRESS_FAMILY_IPV6 constant is available even if libsoup was
392  * built without IPv6 support, but attempting to create an IPv6
393  * address will fail in that case.
394  **/
395
396 /**
397  * SOUP_ADDRESS_ANY_PORT:
398  *
399  * This can be passed to any #SoupAddress method that expects a port,
400  * to indicate that you don't care what port is used.
401  **/
402
403 /**
404  * soup_address_new_any:
405  * @family: the address family
406  * @port: the port number (usually %SOUP_ADDRESS_ANY_PORT)
407  *
408  * Returns a #SoupAddress corresponding to the "any" address
409  * for @family (or %NULL if @family isn't supported), suitable for
410  * passing to soup_socket_server_new().
411  *
412  * Return value: the new #SoupAddress
413  **/
414 SoupAddress *
415 soup_address_new_any (SoupAddressFamily family, guint port)
416 {
417         g_return_val_if_fail (SOUP_ADDRESS_FAMILY_IS_VALID (family), NULL);
418         g_return_val_if_fail (SOUP_ADDRESS_PORT_IS_VALID (port), NULL);
419
420         return g_object_new (SOUP_TYPE_ADDRESS,
421                              SOUP_ADDRESS_FAMILY, family,
422                              SOUP_ADDRESS_PORT, port,
423                              NULL);
424 }
425
426 /**
427  * soup_address_get_name:
428  * @addr: a #SoupAddress
429  *
430  * Returns the hostname associated with @addr.
431  *
432  * Return value: the hostname, or %NULL if it is not known.
433  **/
434 const char *
435 soup_address_get_name (SoupAddress *addr)
436 {
437         g_return_val_if_fail (SOUP_IS_ADDRESS (addr), NULL);
438
439         return SOUP_ADDRESS_GET_PRIVATE (addr)->name;
440 }
441
442 /**
443  * soup_address_get_sockaddr:
444  * @addr: a #SoupAddress
445  * @len: return location for sockaddr length
446  *
447  * Returns the sockaddr associated with @addr, with its length in
448  * *@len. If the sockaddr is not yet known, returns %NULL.
449  *
450  * Return value: the sockaddr, or %NULL
451  **/
452 struct sockaddr *
453 soup_address_get_sockaddr (SoupAddress *addr, int *len)
454 {
455         SoupAddressPrivate *priv;
456
457         g_return_val_if_fail (SOUP_IS_ADDRESS (addr), NULL);
458         priv = SOUP_ADDRESS_GET_PRIVATE (addr);
459
460         if (priv->sockaddr && len)
461                 *len = SOUP_ADDRESS_FAMILY_SOCKADDR_SIZE (SOUP_ADDRESS_GET_FAMILY (priv));
462
463         return priv->sockaddr;
464 }
465
466 /**
467  * soup_address_get_physical:
468  * @addr: a #SoupAddress
469  *
470  * Returns the physical address associated with @addr as a string.
471  * (Eg, "127.0.0.1"). If the address is not yet known, returns %NULL.
472  *
473  * Return value: the physical address, or %NULL
474  **/
475 const char *
476 soup_address_get_physical (SoupAddress *addr)
477 {
478         SoupAddressPrivate *priv;
479
480         g_return_val_if_fail (SOUP_IS_ADDRESS (addr), NULL);
481         priv = SOUP_ADDRESS_GET_PRIVATE (addr);
482
483         if (!priv->sockaddr)
484                 return NULL;
485
486         if (!priv->physical)
487                 priv->physical = soup_dns_ntop (priv->sockaddr);
488
489         return priv->physical;
490 }
491
492 /**
493  * soup_address_get_port:
494  * @addr: a #SoupAddress
495  *
496  * Returns the port associated with @addr.
497  *
498  * Return value: the port
499  **/
500 guint
501 soup_address_get_port (SoupAddress *addr)
502 {
503         g_return_val_if_fail (SOUP_IS_ADDRESS (addr), 0);
504
505         return SOUP_ADDRESS_GET_PRIVATE (addr)->port;
506 }
507
508
509 static void
510 update_address (SoupAddress *addr, SoupDNSLookup *lookup)
511 {
512         SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (addr);
513
514         if (!priv->name)
515                 priv->name = soup_dns_lookup_get_hostname (lookup);
516
517         if (!priv->sockaddr) {
518                 priv->sockaddr = soup_dns_lookup_get_address (lookup);
519                 SOUP_ADDRESS_SET_PORT (priv, htons (priv->port));
520         }
521 }
522
523 typedef struct {
524         SoupAddress         *addr;
525         SoupAddressCallback  callback;
526         gpointer             callback_data;
527 } SoupAddressResolveAsyncData;
528
529 static void
530 lookup_resolved (SoupDNSLookup *lookup, guint status, gpointer user_data)
531 {
532         SoupAddressResolveAsyncData *res_data = user_data;
533         SoupAddress *addr;
534         SoupAddressCallback callback;
535         gpointer callback_data;
536
537         addr = res_data->addr;
538         callback = res_data->callback;
539         callback_data = res_data->callback_data;
540         g_free (res_data);
541
542         if (status == SOUP_STATUS_OK)
543                 update_address (addr, lookup);
544
545         if (callback)
546                 callback (addr, status, callback_data);
547
548         g_object_unref (addr);
549 }
550
551 /**
552  * SoupAddressCallback:
553  * @addr: the #SoupAddress that was resolved
554  * @status: %SOUP_STATUS_OK, %SOUP_STATUS_CANT_RESOLVE, or
555  * %SOUP_STATUS_CANCELLED
556  * @data: the user data that was passed to
557  * soup_address_resolve_async()
558  *
559  * The callback function passed to soup_address_resolve_async().
560  **/
561
562 /**
563  * soup_address_resolve_async:
564  * @addr: a #SoupAddress
565  * @async_context: the #GMainContext to call @callback from
566  * @cancellable: a #GCancellable object, or %NULL
567  * @callback: callback to call with the result
568  * @user_data: data for @callback
569  *
570  * Asynchronously resolves the missing half of @addr (its IP address
571  * if it was created with soup_address_new(), or its hostname if it
572  * was created with soup_address_new_from_sockaddr() or
573  * soup_address_new_any().)
574  *
575  * If @cancellable is non-%NULL, it can be used to cancel the
576  * resolution. @callback will still be invoked in this case, with a
577  * status of %SOUP_STATUS_CANCELLED.
578  **/
579 void
580 soup_address_resolve_async (SoupAddress *addr, GMainContext *async_context,
581                             GCancellable *cancellable,
582                             SoupAddressCallback callback, gpointer user_data)
583 {
584         SoupAddressPrivate *priv;
585         SoupAddressResolveAsyncData *res_data;
586
587         g_return_if_fail (SOUP_IS_ADDRESS (addr));
588         priv = SOUP_ADDRESS_GET_PRIVATE (addr);
589
590         res_data = g_new (SoupAddressResolveAsyncData, 1);
591         res_data->addr          = addr;
592         res_data->callback      = callback;
593         res_data->callback_data = user_data;
594
595         g_object_ref (addr);
596         soup_dns_lookup_resolve_async (priv->lookup, async_context, cancellable,
597                                        lookup_resolved, res_data);
598 }
599
600 /**
601  * soup_address_resolve_sync:
602  * @addr: a #SoupAddress
603  * @cancellable: a #GCancellable object, or %NULL
604  *
605  * Synchronously resolves the missing half of @addr, as with
606  * soup_address_resolve_async().
607  *
608  * If @cancellable is non-%NULL, it can be used to cancel the
609  * resolution. soup_address_resolve_sync() will then return a status
610  * of %SOUP_STATUS_CANCELLED.
611  *
612  * Return value: %SOUP_STATUS_OK, %SOUP_STATUS_CANT_RESOLVE, or
613  * %SOUP_STATUS_CANCELLED.
614  **/
615 guint
616 soup_address_resolve_sync (SoupAddress *addr, GCancellable *cancellable)
617 {
618         SoupAddressPrivate *priv;
619         guint status;
620
621         g_return_val_if_fail (SOUP_IS_ADDRESS (addr), SOUP_STATUS_MALFORMED);
622         priv = SOUP_ADDRESS_GET_PRIVATE (addr);
623
624         g_object_ref (addr);
625         status = soup_dns_lookup_resolve (priv->lookup, cancellable);
626         if (status == SOUP_STATUS_OK)
627                 update_address (addr, priv->lookup);
628         g_object_unref (addr);
629         return status;
630 }