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 #define SOUP_ADDRESS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_ADDRESS, SoupAddressPrivate))
66 /* sockaddr generic macros */
67 #define SOUP_SIN(priv) ((struct sockaddr_in *)priv->sockaddr)
69 #define SOUP_SIN6(priv) ((struct sockaddr_in6 *)priv->sockaddr)
72 /* sockaddr family macros */
73 #define SOUP_ADDRESS_GET_FAMILY(priv) (priv->sockaddr->sa_family)
74 #define SOUP_ADDRESS_SET_FAMILY(priv, family) \
75 (priv->sockaddr->sa_family = family)
77 #define SOUP_ADDRESS_FAMILY_IS_VALID(family) \
78 (family == AF_INET || family == AF_INET6)
79 #define SOUP_ADDRESS_FAMILY_SOCKADDR_SIZE(family) \
80 (family == AF_INET ? sizeof (struct sockaddr_in) : \
81 sizeof (struct sockaddr_in6))
82 #define SOUP_ADDRESS_FAMILY_DATA_SIZE(family) \
83 (family == AF_INET ? sizeof (struct in_addr) : \
84 sizeof (struct in6_addr))
86 #define SOUP_ADDRESS_FAMILY_IS_VALID(family) (family == AF_INET)
87 #define SOUP_ADDRESS_FAMILY_SOCKADDR_SIZE(family) sizeof (struct sockaddr_in)
88 #define SOUP_ADDRESS_FAMILY_DATA_SIZE(family) sizeof (struct in_addr)
91 /* sockaddr port macros */
92 #define SOUP_ADDRESS_PORT_IS_VALID(port) (port >= 0 && port <= 65535)
94 #define SOUP_ADDRESS_GET_PORT(priv) \
95 (priv->sockaddr->sa_family == AF_INET ? \
96 SOUP_SIN(priv)->sin_port : \
97 SOUP_SIN6(priv)->sin6_port)
98 #define SOUP_ADDRESS_SET_PORT(priv, port) \
100 if (priv->sockaddr->sa_family == AF_INET) \
101 SOUP_SIN(priv)->sin_port = port; \
103 SOUP_SIN6(priv)->sin6_port = port; \
106 #define SOUP_ADDRESS_GET_PORT(priv) (SOUP_SIN(priv)->sin_port)
107 #define SOUP_ADDRESS_SET_PORT(priv, port) (SOUP_SIN(priv)->sin_port = port)
110 /* sockaddr data macros */
112 #define SOUP_ADDRESS_GET_DATA(priv) \
113 (priv->sockaddr->sa_family == AF_INET ? \
114 (gpointer)&SOUP_SIN(priv)->sin_addr : \
115 (gpointer)&SOUP_SIN6(priv)->sin6_addr)
117 #define SOUP_ADDRESS_GET_DATA(priv) ((gpointer)&SOUP_SIN(priv)->sin_addr)
119 #define SOUP_ADDRESS_SET_DATA(priv, data, length) \
120 memcpy (SOUP_ADDRESS_GET_DATA (priv), data, length)
123 static GObject *constructor (GType type,
124 guint n_construct_properties,
125 GObjectConstructParam *construct_properties);
126 static void set_property (GObject *object, guint prop_id,
127 const GValue *value, GParamSpec *pspec);
128 static void get_property (GObject *object, guint prop_id,
129 GValue *value, GParamSpec *pspec);
131 G_DEFINE_TYPE (SoupAddress, soup_address, G_TYPE_OBJECT)
134 soup_address_init (SoupAddress *addr)
139 finalize (GObject *object)
141 SoupAddress *addr = SOUP_ADDRESS (object);
142 SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (addr);
145 g_free (priv->sockaddr);
149 g_free (priv->physical);
151 G_OBJECT_CLASS (soup_address_parent_class)->finalize (object);
155 soup_address_class_init (SoupAddressClass *address_class)
157 GObjectClass *object_class = G_OBJECT_CLASS (address_class);
161 g_type_class_add_private (address_class, sizeof (SoupAddressPrivate));
163 /* virtual method override */
164 object_class->constructor = constructor;
165 object_class->finalize = finalize;
166 object_class->set_property = set_property;
167 object_class->get_property = get_property;
170 g_object_class_install_property (
171 object_class, PROP_NAME,
172 g_param_spec_string (SOUP_ADDRESS_NAME,
174 "Hostname for this address",
176 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
177 g_object_class_install_property (
178 object_class, PROP_FAMILY,
179 g_param_spec_enum (SOUP_ADDRESS_FAMILY,
181 "Address family for this address",
182 SOUP_TYPE_ADDRESS_FAMILY,
183 SOUP_ADDRESS_FAMILY_INVALID,
184 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
185 g_object_class_install_property (
186 object_class, PROP_PORT,
187 g_param_spec_int (SOUP_ADDRESS_PORT,
189 "Port for this address",
191 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
192 g_object_class_install_property (
193 object_class, PROP_PHYSICAL,
194 g_param_spec_string (SOUP_ADDRESS_PHYSICAL,
196 "IP address for this address",
199 g_object_class_install_property (
200 object_class, PROP_SOCKADDR,
201 g_param_spec_pointer (SOUP_ADDRESS_SOCKADDR,
203 "struct sockaddr for this address",
204 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
207 /* This hopefully is a good place to call WSAStartup */
210 if (WSAStartup (MAKEWORD (2, 0), &wsadata) != 0)
211 g_error ("Windows Sockets could not be initialized");
217 constructor (GType type,
218 guint n_construct_properties,
219 GObjectConstructParam *construct_properties)
222 SoupAddressPrivate *priv;
224 addr = G_OBJECT_CLASS (soup_address_parent_class)->constructor (
225 type, n_construct_properties, construct_properties);
228 priv = SOUP_ADDRESS_GET_PRIVATE (addr);
230 if (!priv->name && !priv->sockaddr) {
231 g_object_unref (addr);
239 set_property (GObject *object, guint prop_id,
240 const GValue *value, GParamSpec *pspec)
242 SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (object);
243 SoupAddressFamily family;
247 /* This is a mess because the properties are mostly orthogonal,
248 * but g_object_constructor wants to set a default value for each
254 priv->name = g_value_dup_string (value);
258 family = g_value_get_enum (value);
259 if (family == SOUP_ADDRESS_FAMILY_INVALID)
261 g_return_if_fail (SOUP_ADDRESS_FAMILY_IS_VALID (family));
262 g_return_if_fail (priv->sockaddr == NULL);
264 priv->sockaddr = g_malloc0 (SOUP_ADDRESS_FAMILY_SOCKADDR_SIZE (family));
265 SOUP_ADDRESS_SET_FAMILY (priv, family);
266 SOUP_ADDRESS_SET_PORT (priv, htons (priv->port));
270 port = g_value_get_int (value);
273 g_return_if_fail (SOUP_ADDRESS_PORT_IS_VALID (port));
277 SOUP_ADDRESS_SET_PORT (priv, htons (port));
281 sa = g_value_get_pointer (value);
284 g_return_if_fail (priv->sockaddr == NULL);
286 len = SOUP_ADDRESS_FAMILY_SOCKADDR_SIZE (sa->sa_family);
287 priv->sockaddr = g_memdup (sa, len);
288 priv->port = ntohs (SOUP_ADDRESS_GET_PORT (priv));
291 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
297 get_property (GObject *object, guint prop_id,
298 GValue *value, GParamSpec *pspec)
300 SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (object);
304 g_value_set_string (value, priv->name);
308 g_value_set_enum (value, SOUP_ADDRESS_GET_FAMILY (priv));
310 g_value_set_enum (value, 0);
313 g_value_set_int (value, priv->port);
316 g_value_set_string (value, soup_address_get_physical (SOUP_ADDRESS (object)));
319 g_value_set_pointer (value, priv->sockaddr);
322 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
329 * @name: a hostname or physical address
330 * @port: a port number
332 * Creates a #SoupAddress from @name and @port. The #SoupAddress's IP
333 * address may not be available right away; the caller can call
334 * soup_address_resolve_async() or soup_address_resolve_sync() to
335 * force a DNS resolution.
337 * Return value: a #SoupAddress
340 soup_address_new (const char *name, guint port)
342 g_return_val_if_fail (name != NULL, NULL);
343 g_return_val_if_fail (SOUP_ADDRESS_PORT_IS_VALID (port), NULL);
345 return g_object_new (SOUP_TYPE_ADDRESS,
346 SOUP_ADDRESS_NAME, name,
347 SOUP_ADDRESS_PORT, port,
352 * soup_address_new_from_sockaddr:
353 * @sa: a pointer to a sockaddr
356 * Returns a #SoupAddress equivalent to @sa (or %NULL if @sa's
357 * address family isn't supported)
359 * Return value: the new #SoupAddress
362 soup_address_new_from_sockaddr (struct sockaddr *sa, int len)
364 g_return_val_if_fail (sa != NULL, NULL);
365 g_return_val_if_fail (SOUP_ADDRESS_FAMILY_IS_VALID (sa->sa_family), NULL);
366 g_return_val_if_fail (len == SOUP_ADDRESS_FAMILY_SOCKADDR_SIZE (sa->sa_family), NULL);
368 return g_object_new (SOUP_TYPE_ADDRESS,
369 SOUP_ADDRESS_SOCKADDR, sa,
375 * @SOUP_ADDRESS_FAMILY_INVALID: an invalid %SoupAddress
376 * @SOUP_ADDRESS_FAMILY_IPV4: an IPv4 address
377 * @SOUP_ADDRESS_FAMILY_IPV6: an IPv6 address
379 * The supported address families. Note that the
380 * %SOUP_ADDRESS_FAMILY_IPV6 constant is available even if libsoup was
381 * built without IPv6 support, but attempting to create an IPv6
382 * address will fail in that case.
386 * SOUP_ADDRESS_ANY_PORT:
388 * This can be passed to any #SoupAddress method that expects a port,
389 * to indicate that you don't care what port is used.
393 * soup_address_new_any:
394 * @family: the address family
395 * @port: the port number (usually %SOUP_ADDRESS_ANY_PORT)
397 * Returns a #SoupAddress corresponding to the "any" address
398 * for @family (or %NULL if @family isn't supported), suitable for
399 * passing to soup_socket_server_new().
401 * Return value: the new #SoupAddress
404 soup_address_new_any (SoupAddressFamily family, guint port)
406 g_return_val_if_fail (SOUP_ADDRESS_FAMILY_IS_VALID (family), NULL);
407 g_return_val_if_fail (SOUP_ADDRESS_PORT_IS_VALID (port), NULL);
409 return g_object_new (SOUP_TYPE_ADDRESS,
410 SOUP_ADDRESS_FAMILY, family,
411 SOUP_ADDRESS_PORT, port,
416 * soup_address_get_name:
417 * @addr: a #SoupAddress
419 * Returns the hostname associated with @addr.
421 * Return value: the hostname, or %NULL if it is not known.
424 soup_address_get_name (SoupAddress *addr)
426 g_return_val_if_fail (SOUP_IS_ADDRESS (addr), NULL);
428 return SOUP_ADDRESS_GET_PRIVATE (addr)->name;
432 * soup_address_get_sockaddr:
433 * @addr: a #SoupAddress
434 * @len: return location for sockaddr length
436 * Returns the sockaddr associated with @addr, with its length in
437 * *@len. If the sockaddr is not yet known, returns %NULL.
439 * Return value: the sockaddr, or %NULL
442 soup_address_get_sockaddr (SoupAddress *addr, int *len)
444 SoupAddressPrivate *priv;
446 g_return_val_if_fail (SOUP_IS_ADDRESS (addr), NULL);
447 priv = SOUP_ADDRESS_GET_PRIVATE (addr);
449 if (priv->sockaddr && len)
450 *len = SOUP_ADDRESS_FAMILY_SOCKADDR_SIZE (SOUP_ADDRESS_GET_FAMILY (priv));
452 return priv->sockaddr;
456 * soup_address_get_physical:
457 * @addr: a #SoupAddress
459 * Returns the physical address associated with @addr as a string.
460 * (Eg, "127.0.0.1"). If the address is not yet known, returns %NULL.
462 * Return value: the physical address, or %NULL
465 soup_address_get_physical (SoupAddress *addr)
467 SoupAddressPrivate *priv;
469 g_return_val_if_fail (SOUP_IS_ADDRESS (addr), NULL);
470 priv = SOUP_ADDRESS_GET_PRIVATE (addr);
476 priv->physical = soup_dns_ntop (priv->sockaddr);
478 return priv->physical;
482 * soup_address_get_port:
483 * @addr: a #SoupAddress
485 * Returns the port associated with @addr.
487 * Return value: the port
490 soup_address_get_port (SoupAddress *addr)
492 g_return_val_if_fail (SOUP_IS_ADDRESS (addr), 0);
494 return SOUP_ADDRESS_GET_PRIVATE (addr)->port;
499 update_address (SoupAddress *addr, SoupDNSLookup *lookup)
501 SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (addr);
504 priv->name = soup_dns_lookup_get_hostname (lookup);
506 if (!priv->sockaddr) {
507 priv->sockaddr = soup_dns_lookup_get_address (lookup);
508 SOUP_ADDRESS_SET_PORT (priv, htons (priv->port));
514 SoupAddressCallback callback;
515 gpointer callback_data;
516 } SoupAddressResolveAsyncData;
519 lookup_resolved (SoupDNSLookup *lookup, guint status, gpointer user_data)
521 SoupAddressResolveAsyncData *res_data = user_data;
523 SoupAddressCallback callback;
524 gpointer callback_data;
526 addr = res_data->addr;
527 callback = res_data->callback;
528 callback_data = res_data->callback_data;
531 if (status == SOUP_STATUS_OK)
532 update_address (addr, lookup);
535 callback (addr, status, callback_data);
537 g_object_unref (addr);
538 soup_dns_lookup_free (lookup);
542 * SoupAddressCallback:
543 * @addr: the #SoupAddress that was resolved
544 * @status: %SOUP_STATUS_OK, %SOUP_STATUS_CANT_RESOLVE, or
545 * %SOUP_STATUS_CANCELLED
546 * @data: the user data that was passed to
547 * soup_address_resolve_async()
549 * The callback function passed to soup_address_resolve_async().
553 * soup_address_resolve_async:
554 * @addr: a #SoupAddress
555 * @async_context: the #GMainContext to call @callback from
556 * @cancellable: a #GCancellable object, or %NULL
557 * @callback: callback to call with the result
558 * @user_data: data for @callback
560 * Asynchronously resolves the missing half of @addr (its IP address
561 * if it was created with soup_address_new(), or its hostname if it
562 * was created with soup_address_new_from_sockaddr() or
563 * soup_address_new_any().)
565 * If @cancellable is non-%NULL, it can be used to cancel the
566 * resolution. @callback will still be invoked in this case, with a
567 * status of %SOUP_STATUS_CANCELLED.
570 soup_address_resolve_async (SoupAddress *addr, GMainContext *async_context,
571 GCancellable *cancellable,
572 SoupAddressCallback callback, gpointer user_data)
574 SoupAddressPrivate *priv;
575 SoupAddressResolveAsyncData *res_data;
576 SoupDNSLookup *lookup;
578 g_return_if_fail (SOUP_IS_ADDRESS (addr));
579 priv = SOUP_ADDRESS_GET_PRIVATE (addr);
581 res_data = g_new (SoupAddressResolveAsyncData, 1);
582 res_data->addr = g_object_ref (addr);
583 res_data->callback = callback;
584 res_data->callback_data = user_data;
587 lookup = soup_dns_lookup_name (priv->name);
589 lookup = soup_dns_lookup_address (priv->sockaddr);
590 soup_dns_lookup_resolve_async (lookup, async_context, cancellable,
591 lookup_resolved, res_data);
595 * soup_address_resolve_sync:
596 * @addr: a #SoupAddress
597 * @cancellable: a #GCancellable object, or %NULL
599 * Synchronously resolves the missing half of @addr, as with
600 * soup_address_resolve_async().
602 * If @cancellable is non-%NULL, it can be used to cancel the
603 * resolution. soup_address_resolve_sync() will then return a status
604 * of %SOUP_STATUS_CANCELLED.
606 * Return value: %SOUP_STATUS_OK, %SOUP_STATUS_CANT_RESOLVE, or
607 * %SOUP_STATUS_CANCELLED.
610 soup_address_resolve_sync (SoupAddress *addr, GCancellable *cancellable)
612 SoupAddressPrivate *priv;
613 SoupDNSLookup *lookup;
616 g_return_val_if_fail (SOUP_IS_ADDRESS (addr), SOUP_STATUS_MALFORMED);
617 priv = SOUP_ADDRESS_GET_PRIVATE (addr);
621 lookup = soup_dns_lookup_name (priv->name);
623 lookup = soup_dns_lookup_address (priv->sockaddr);
624 status = soup_dns_lookup_resolve (lookup, cancellable);
625 if (status == SOUP_STATUS_OK)
626 update_address (addr, lookup);
627 g_object_unref (addr);
628 soup_dns_lookup_free (lookup);
633 soup_address_is_resolved (SoupAddress *addr)
635 SoupAddressPrivate *priv;
637 g_return_val_if_fail (SOUP_IS_ADDRESS (addr), FALSE);
638 priv = SOUP_ADDRESS_GET_PRIVATE (addr);
640 return priv->sockaddr && priv->name;
644 * soup_address_hash_by_name:
645 * @addr: a #SoupAddress
647 * A hash function (for #GHashTable) that corresponds to
648 * soup_address_equal_by_name(), qv
650 * Return value: the named-based hash value for @addr.
653 soup_address_hash_by_name (gconstpointer addr)
655 SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (addr);
657 g_return_val_if_fail (priv->name != NULL, 0);
658 return g_str_hash (priv->name);
662 * soup_address_equal_by_name:
663 * @addr1: a #SoupAddress with a resolved name
664 * @addr2: another #SoupAddress with a resolved name
666 * Tests if @addr1 and @addr2 have the same "name". This method can be
667 * used with soup_address_hash_by_name() to create a #GHashTable that
668 * hashes on address "names".
670 * Comparing by name normally means comparing the addresses by their
671 * hostnames. But if the address was originally created using an IP
672 * address literal, then it will be compared by that instead.
674 * In particular, if "www.example.com" has the IP address 10.0.0.1,
675 * and @addr1 was created with the name "www.example.com" and @addr2
676 * was created with the name "10.0.0.1", then they will compare as
677 * unequal for purposes of soup_address_equal_by_name().
679 * This would be used to distinguish hosts in situations where
680 * different virtual hosts on the same IP address should be considered
681 * different. Eg, for purposes of HTTP authentication or cookies, two
682 * hosts with the same IP address but different names are considered
683 * to be different hosts.
685 * See also soup_address_equal_by_ip(), which compares by IP address
686 * rather than by name.
688 * Return value: whether or not @addr1 and @addr2 have the same name
691 soup_address_equal_by_name (gconstpointer addr1, gconstpointer addr2)
693 SoupAddressPrivate *priv1 = SOUP_ADDRESS_GET_PRIVATE (addr1);
694 SoupAddressPrivate *priv2 = SOUP_ADDRESS_GET_PRIVATE (addr2);
696 g_return_val_if_fail (priv1->name != NULL, FALSE);
697 g_return_val_if_fail (priv2->name != NULL, FALSE);
698 return !g_ascii_strcasecmp (priv1->name, priv2->name);
702 * soup_address_hash_by_ip:
703 * @addr: a #SoupAddress
705 * A hash function (for #GHashTable) that corresponds to
706 * soup_address_equal_by_ip(), qv
708 * Return value: the IP-based hash value for @addr.
711 soup_address_hash_by_ip (gconstpointer addr)
713 SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (addr);
716 g_return_val_if_fail (priv->sockaddr != NULL, 0);
718 memcpy (&hash, SOUP_ADDRESS_GET_DATA (priv),
719 MIN (sizeof (hash), SOUP_ADDRESS_FAMILY_DATA_SIZE (priv->sockaddr->sa_family)));
724 * soup_address_equal_by_ip:
725 * @addr1: a #SoupAddress with a resolved IP address
726 * @addr2: another #SoupAddress with a resolved IP address
728 * Tests if @addr1 and @addr2 have the same IP address. This method
729 * can be used with soup_address_hash_by_ip() to create a
730 * #GHashTable that hashes on IP address.
732 * This would be used to distinguish hosts in situations where
733 * different virtual hosts on the same IP address should be considered
734 * the same. Eg, if "www.example.com" and "www.example.net" have the
735 * same IP address, then a single #SoupConnection can be used to talk
738 * See also soup_address_equal_by_name(), which compares by name
739 * rather than by IP address.
741 * Return value: whether or not @addr1 and @addr2 have the same IP
745 soup_address_equal_by_ip (gconstpointer addr1, gconstpointer addr2)
747 SoupAddressPrivate *priv1 = SOUP_ADDRESS_GET_PRIVATE (addr1);
748 SoupAddressPrivate *priv2 = SOUP_ADDRESS_GET_PRIVATE (addr2);
751 g_return_val_if_fail (priv1->sockaddr != NULL, FALSE);
752 g_return_val_if_fail (priv2->sockaddr != NULL, FALSE);
754 size = SOUP_ADDRESS_FAMILY_SOCKADDR_SIZE (priv1->sockaddr->sa_family);
755 return (priv1->sockaddr->sa_family ==
756 priv2->sockaddr->sa_family &&
757 !memcmp (priv1->sockaddr, priv2->sockaddr, size));