1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * soup-address.c: Internet address handing
5 * Copyright (C) 2000-2003, Ximian, Inc.
17 #include <sys/types.h>
19 #include "soup-address.h"
21 #include "soup-enum-types.h"
22 #include "soup-marshal.h"
23 #include "soup-misc.h"
25 #ifndef INET_ADDRSTRLEN
26 # define INET_ADDRSTRLEN 16
27 # define INET6_ADDRSTRLEN 46
31 #define INADDR_NONE -1
35 * SECTION:soup-address
36 * @short_description: DNS support
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.)
42 * If libsoup was built with IPv6 support, #SoupAddress will allow
43 * both IPv4 and IPv6 addresses.
59 struct sockaddr *sockaddr;
61 char *name, *physical;
64 SoupDNSLookup *lookup;
67 #define SOUP_ADDRESS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_ADDRESS, SoupAddressPrivate))
69 /* sockaddr generic macros */
70 #define SOUP_SIN(priv) ((struct sockaddr_in *)priv->sockaddr)
72 #define SOUP_SIN6(priv) ((struct sockaddr_in6 *)priv->sockaddr)
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)
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))
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)
94 /* sockaddr port macros */
95 #define SOUP_ADDRESS_PORT_IS_VALID(port) (port >= 0 && port <= 65535)
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) \
103 if (priv->sockaddr->sa_family == AF_INET) \
104 SOUP_SIN(priv)->sin_port = port; \
106 SOUP_SIN6(priv)->sin6_port = port; \
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)
113 /* sockaddr data macros */
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)
120 #define SOUP_ADDRESS_GET_DATA(priv) ((gpointer)&SOUP_SIN(priv)->sin_addr)
122 #define SOUP_ADDRESS_SET_DATA(priv, data, length) \
123 memcpy (SOUP_ADDRESS_GET_DATA (priv), data, length)
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);
134 G_DEFINE_TYPE (SoupAddress, soup_address, G_TYPE_OBJECT)
137 soup_address_init (SoupAddress *addr)
142 finalize (GObject *object)
144 SoupAddress *addr = SOUP_ADDRESS (object);
145 SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (addr);
148 g_free (priv->sockaddr);
152 g_free (priv->physical);
155 soup_dns_lookup_free (priv->lookup);
156 if (priv->timeout_id)
157 g_source_remove (priv->timeout_id);
159 G_OBJECT_CLASS (soup_address_parent_class)->finalize (object);
163 soup_address_class_init (SoupAddressClass *address_class)
165 GObjectClass *object_class = G_OBJECT_CLASS (address_class);
169 g_type_class_add_private (address_class, sizeof (SoupAddressPrivate));
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;
178 g_object_class_install_property (
179 object_class, PROP_NAME,
180 g_param_spec_string (SOUP_ADDRESS_NAME,
182 "Hostname for this address",
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,
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,
197 "Port for this address",
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,
204 "IP address for this address",
207 g_object_class_install_property (
208 object_class, PROP_SOCKADDR,
209 g_param_spec_pointer (SOUP_ADDRESS_SOCKADDR,
211 "struct sockaddr for this address",
212 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
215 /* This hopefully is a good place to call WSAStartup */
218 if (WSAStartup (MAKEWORD (2, 0), &wsadata) != 0)
219 g_error ("Windows Sockets could not be initialized");
225 constructor (GType type,
226 guint n_construct_properties,
227 GObjectConstructParam *construct_properties)
230 SoupAddressPrivate *priv;
232 addr = G_OBJECT_CLASS (soup_address_parent_class)->constructor (
233 type, n_construct_properties, construct_properties);
236 priv = SOUP_ADDRESS_GET_PRIVATE (addr);
240 priv->lookup = soup_dns_lookup_name (priv->name);
241 } else if (priv->sockaddr)
242 priv->lookup = soup_dns_lookup_address (priv->sockaddr);
244 g_object_unref (addr);
252 set_property (GObject *object, guint prop_id,
253 const GValue *value, GParamSpec *pspec)
255 SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (object);
256 SoupAddressFamily family;
260 /* This is a mess because the properties are mostly orthogonal,
261 * but g_object_constructor wants to set a default value for each
267 priv->name = g_value_dup_string (value);
271 family = g_value_get_enum (value);
272 if (family == SOUP_ADDRESS_FAMILY_INVALID)
274 g_return_if_fail (SOUP_ADDRESS_FAMILY_IS_VALID (family));
275 g_return_if_fail (priv->sockaddr == NULL);
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));
283 port = g_value_get_int (value);
286 g_return_if_fail (SOUP_ADDRESS_PORT_IS_VALID (port));
290 SOUP_ADDRESS_SET_PORT (priv, htons (port));
294 sa = g_value_get_pointer (value);
297 g_return_if_fail (priv->sockaddr == NULL);
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));
309 get_property (GObject *object, guint prop_id,
310 GValue *value, GParamSpec *pspec)
312 SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (object);
316 g_value_set_string (value, priv->name);
320 g_value_set_enum (value, SOUP_ADDRESS_GET_FAMILY (priv));
322 g_value_set_enum (value, 0);
325 g_value_set_int (value, priv->port);
328 g_value_set_string (value, soup_address_get_physical (SOUP_ADDRESS (object)));
331 g_value_set_pointer (value, priv->sockaddr);
340 * @name: a hostname or physical address
341 * @port: a port number
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.
348 * Return value: a #SoupAddress
351 soup_address_new (const char *name, guint port)
353 g_return_val_if_fail (name != NULL, NULL);
354 g_return_val_if_fail (SOUP_ADDRESS_PORT_IS_VALID (port), NULL);
356 return g_object_new (SOUP_TYPE_ADDRESS,
357 SOUP_ADDRESS_NAME, name,
358 SOUP_ADDRESS_PORT, port,
363 * soup_address_new_from_sockaddr:
364 * @sa: a pointer to a sockaddr
367 * Returns a #SoupAddress equivalent to @sa (or %NULL if @sa's
368 * address family isn't supported)
370 * Return value: the new #SoupAddress
373 soup_address_new_from_sockaddr (struct sockaddr *sa, int len)
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);
379 return g_object_new (SOUP_TYPE_ADDRESS,
380 SOUP_ADDRESS_SOCKADDR, sa,
386 * @SOUP_ADDRESS_FAMILY_INVALID: an invalid %SoupAddress
387 * @SOUP_ADDRESS_FAMILY_IPV4: an IPv4 address
388 * @SOUP_ADDRESS_FAMILY_IPV6: an IPv6 address
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.
397 * SOUP_ADDRESS_ANY_PORT:
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.
404 * soup_address_new_any:
405 * @family: the address family
406 * @port: the port number (usually %SOUP_ADDRESS_ANY_PORT)
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().
412 * Return value: the new #SoupAddress
415 soup_address_new_any (SoupAddressFamily family, guint port)
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);
420 return g_object_new (SOUP_TYPE_ADDRESS,
421 SOUP_ADDRESS_FAMILY, family,
422 SOUP_ADDRESS_PORT, port,
427 * soup_address_get_name:
428 * @addr: a #SoupAddress
430 * Returns the hostname associated with @addr.
432 * Return value: the hostname, or %NULL if it is not known.
435 soup_address_get_name (SoupAddress *addr)
437 g_return_val_if_fail (SOUP_IS_ADDRESS (addr), NULL);
439 return SOUP_ADDRESS_GET_PRIVATE (addr)->name;
443 * soup_address_get_sockaddr:
444 * @addr: a #SoupAddress
445 * @len: return location for sockaddr length
447 * Returns the sockaddr associated with @addr, with its length in
448 * *@len. If the sockaddr is not yet known, returns %NULL.
450 * Return value: the sockaddr, or %NULL
453 soup_address_get_sockaddr (SoupAddress *addr, int *len)
455 SoupAddressPrivate *priv;
457 g_return_val_if_fail (SOUP_IS_ADDRESS (addr), NULL);
458 priv = SOUP_ADDRESS_GET_PRIVATE (addr);
460 if (priv->sockaddr && len)
461 *len = SOUP_ADDRESS_FAMILY_SOCKADDR_SIZE (SOUP_ADDRESS_GET_FAMILY (priv));
463 return priv->sockaddr;
467 * soup_address_get_physical:
468 * @addr: a #SoupAddress
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.
473 * Return value: the physical address, or %NULL
476 soup_address_get_physical (SoupAddress *addr)
478 SoupAddressPrivate *priv;
480 g_return_val_if_fail (SOUP_IS_ADDRESS (addr), NULL);
481 priv = SOUP_ADDRESS_GET_PRIVATE (addr);
487 priv->physical = soup_dns_ntop (priv->sockaddr);
489 return priv->physical;
493 * soup_address_get_port:
494 * @addr: a #SoupAddress
496 * Returns the port associated with @addr.
498 * Return value: the port
501 soup_address_get_port (SoupAddress *addr)
503 g_return_val_if_fail (SOUP_IS_ADDRESS (addr), 0);
505 return SOUP_ADDRESS_GET_PRIVATE (addr)->port;
510 update_address (SoupAddress *addr, SoupDNSLookup *lookup)
512 SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (addr);
515 priv->name = soup_dns_lookup_get_hostname (lookup);
517 if (!priv->sockaddr) {
518 priv->sockaddr = soup_dns_lookup_get_address (lookup);
519 SOUP_ADDRESS_SET_PORT (priv, htons (priv->port));
525 SoupAddressCallback callback;
526 gpointer callback_data;
527 } SoupAddressResolveAsyncData;
530 lookup_resolved (SoupDNSLookup *lookup, guint status, gpointer user_data)
532 SoupAddressResolveAsyncData *res_data = user_data;
534 SoupAddressCallback callback;
535 gpointer callback_data;
537 addr = res_data->addr;
538 callback = res_data->callback;
539 callback_data = res_data->callback_data;
542 if (status == SOUP_STATUS_OK)
543 update_address (addr, lookup);
546 callback (addr, status, callback_data);
548 g_object_unref (addr);
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()
559 * The callback function passed to soup_address_resolve_async().
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
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().)
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.
580 soup_address_resolve_async (SoupAddress *addr, GMainContext *async_context,
581 GCancellable *cancellable,
582 SoupAddressCallback callback, gpointer user_data)
584 SoupAddressPrivate *priv;
585 SoupAddressResolveAsyncData *res_data;
587 g_return_if_fail (SOUP_IS_ADDRESS (addr));
588 priv = SOUP_ADDRESS_GET_PRIVATE (addr);
590 res_data = g_new (SoupAddressResolveAsyncData, 1);
591 res_data->addr = addr;
592 res_data->callback = callback;
593 res_data->callback_data = user_data;
596 soup_dns_lookup_resolve_async (priv->lookup, async_context, cancellable,
597 lookup_resolved, res_data);
601 * soup_address_resolve_sync:
602 * @addr: a #SoupAddress
603 * @cancellable: a #GCancellable object, or %NULL
605 * Synchronously resolves the missing half of @addr, as with
606 * soup_address_resolve_async().
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.
612 * Return value: %SOUP_STATUS_OK, %SOUP_STATUS_CANT_RESOLVE, or
613 * %SOUP_STATUS_CANCELLED.
616 soup_address_resolve_sync (SoupAddress *addr, GCancellable *cancellable)
618 SoupAddressPrivate *priv;
621 g_return_val_if_fail (SOUP_IS_ADDRESS (addr), SOUP_STATUS_MALFORMED);
622 priv = SOUP_ADDRESS_GET_PRIVATE (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);