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));
304 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
310 get_property (GObject *object, guint prop_id,
311 GValue *value, GParamSpec *pspec)
313 SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (object);
317 g_value_set_string (value, priv->name);
321 g_value_set_enum (value, SOUP_ADDRESS_GET_FAMILY (priv));
323 g_value_set_enum (value, 0);
326 g_value_set_int (value, priv->port);
329 g_value_set_string (value, soup_address_get_physical (SOUP_ADDRESS (object)));
332 g_value_set_pointer (value, priv->sockaddr);
335 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
342 * @name: a hostname or physical address
343 * @port: a port number
345 * Creates a #SoupAddress from @name and @port. The #SoupAddress's IP
346 * address may not be available right away; the caller can call
347 * soup_address_resolve_async() or soup_address_resolve_sync() to
348 * force a DNS resolution.
350 * Return value: a #SoupAddress
353 soup_address_new (const char *name, guint port)
355 g_return_val_if_fail (name != NULL, NULL);
356 g_return_val_if_fail (SOUP_ADDRESS_PORT_IS_VALID (port), NULL);
358 return g_object_new (SOUP_TYPE_ADDRESS,
359 SOUP_ADDRESS_NAME, name,
360 SOUP_ADDRESS_PORT, port,
365 * soup_address_new_from_sockaddr:
366 * @sa: a pointer to a sockaddr
369 * Returns a #SoupAddress equivalent to @sa (or %NULL if @sa's
370 * address family isn't supported)
372 * Return value: the new #SoupAddress
375 soup_address_new_from_sockaddr (struct sockaddr *sa, int len)
377 g_return_val_if_fail (sa != NULL, NULL);
378 g_return_val_if_fail (SOUP_ADDRESS_FAMILY_IS_VALID (sa->sa_family), NULL);
379 g_return_val_if_fail (len == SOUP_ADDRESS_FAMILY_SOCKADDR_SIZE (sa->sa_family), NULL);
381 return g_object_new (SOUP_TYPE_ADDRESS,
382 SOUP_ADDRESS_SOCKADDR, sa,
388 * @SOUP_ADDRESS_FAMILY_INVALID: an invalid %SoupAddress
389 * @SOUP_ADDRESS_FAMILY_IPV4: an IPv4 address
390 * @SOUP_ADDRESS_FAMILY_IPV6: an IPv6 address
392 * The supported address families. Note that the
393 * %SOUP_ADDRESS_FAMILY_IPV6 constant is available even if libsoup was
394 * built without IPv6 support, but attempting to create an IPv6
395 * address will fail in that case.
399 * SOUP_ADDRESS_ANY_PORT:
401 * This can be passed to any #SoupAddress method that expects a port,
402 * to indicate that you don't care what port is used.
406 * soup_address_new_any:
407 * @family: the address family
408 * @port: the port number (usually %SOUP_ADDRESS_ANY_PORT)
410 * Returns a #SoupAddress corresponding to the "any" address
411 * for @family (or %NULL if @family isn't supported), suitable for
412 * passing to soup_socket_server_new().
414 * Return value: the new #SoupAddress
417 soup_address_new_any (SoupAddressFamily family, guint port)
419 g_return_val_if_fail (SOUP_ADDRESS_FAMILY_IS_VALID (family), NULL);
420 g_return_val_if_fail (SOUP_ADDRESS_PORT_IS_VALID (port), NULL);
422 return g_object_new (SOUP_TYPE_ADDRESS,
423 SOUP_ADDRESS_FAMILY, family,
424 SOUP_ADDRESS_PORT, port,
429 * soup_address_get_name:
430 * @addr: a #SoupAddress
432 * Returns the hostname associated with @addr.
434 * Return value: the hostname, or %NULL if it is not known.
437 soup_address_get_name (SoupAddress *addr)
439 g_return_val_if_fail (SOUP_IS_ADDRESS (addr), NULL);
441 return SOUP_ADDRESS_GET_PRIVATE (addr)->name;
445 * soup_address_get_sockaddr:
446 * @addr: a #SoupAddress
447 * @len: return location for sockaddr length
449 * Returns the sockaddr associated with @addr, with its length in
450 * *@len. If the sockaddr is not yet known, returns %NULL.
452 * Return value: the sockaddr, or %NULL
455 soup_address_get_sockaddr (SoupAddress *addr, int *len)
457 SoupAddressPrivate *priv;
459 g_return_val_if_fail (SOUP_IS_ADDRESS (addr), NULL);
460 priv = SOUP_ADDRESS_GET_PRIVATE (addr);
462 if (priv->sockaddr && len)
463 *len = SOUP_ADDRESS_FAMILY_SOCKADDR_SIZE (SOUP_ADDRESS_GET_FAMILY (priv));
465 return priv->sockaddr;
469 * soup_address_get_physical:
470 * @addr: a #SoupAddress
472 * Returns the physical address associated with @addr as a string.
473 * (Eg, "127.0.0.1"). If the address is not yet known, returns %NULL.
475 * Return value: the physical address, or %NULL
478 soup_address_get_physical (SoupAddress *addr)
480 SoupAddressPrivate *priv;
482 g_return_val_if_fail (SOUP_IS_ADDRESS (addr), NULL);
483 priv = SOUP_ADDRESS_GET_PRIVATE (addr);
489 priv->physical = soup_dns_ntop (priv->sockaddr);
491 return priv->physical;
495 * soup_address_get_port:
496 * @addr: a #SoupAddress
498 * Returns the port associated with @addr.
500 * Return value: the port
503 soup_address_get_port (SoupAddress *addr)
505 g_return_val_if_fail (SOUP_IS_ADDRESS (addr), 0);
507 return SOUP_ADDRESS_GET_PRIVATE (addr)->port;
512 update_address (SoupAddress *addr, SoupDNSLookup *lookup)
514 SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (addr);
517 priv->name = soup_dns_lookup_get_hostname (lookup);
519 if (!priv->sockaddr) {
520 priv->sockaddr = soup_dns_lookup_get_address (lookup);
521 SOUP_ADDRESS_SET_PORT (priv, htons (priv->port));
527 SoupAddressCallback callback;
528 gpointer callback_data;
529 } SoupAddressResolveAsyncData;
532 lookup_resolved (SoupDNSLookup *lookup, guint status, gpointer user_data)
534 SoupAddressResolveAsyncData *res_data = user_data;
536 SoupAddressCallback callback;
537 gpointer callback_data;
539 addr = res_data->addr;
540 callback = res_data->callback;
541 callback_data = res_data->callback_data;
544 if (status == SOUP_STATUS_OK)
545 update_address (addr, lookup);
548 callback (addr, status, callback_data);
550 g_object_unref (addr);
554 * SoupAddressCallback:
555 * @addr: the #SoupAddress that was resolved
556 * @status: %SOUP_STATUS_OK, %SOUP_STATUS_CANT_RESOLVE, or
557 * %SOUP_STATUS_CANCELLED
558 * @data: the user data that was passed to
559 * soup_address_resolve_async()
561 * The callback function passed to soup_address_resolve_async().
565 * soup_address_resolve_async:
566 * @addr: a #SoupAddress
567 * @async_context: the #GMainContext to call @callback from
568 * @cancellable: a #GCancellable object, or %NULL
569 * @callback: callback to call with the result
570 * @user_data: data for @callback
572 * Asynchronously resolves the missing half of @addr (its IP address
573 * if it was created with soup_address_new(), or its hostname if it
574 * was created with soup_address_new_from_sockaddr() or
575 * soup_address_new_any().)
577 * If @cancellable is non-%NULL, it can be used to cancel the
578 * resolution. @callback will still be invoked in this case, with a
579 * status of %SOUP_STATUS_CANCELLED.
582 soup_address_resolve_async (SoupAddress *addr, GMainContext *async_context,
583 GCancellable *cancellable,
584 SoupAddressCallback callback, gpointer user_data)
586 SoupAddressPrivate *priv;
587 SoupAddressResolveAsyncData *res_data;
589 g_return_if_fail (SOUP_IS_ADDRESS (addr));
590 priv = SOUP_ADDRESS_GET_PRIVATE (addr);
592 res_data = g_new (SoupAddressResolveAsyncData, 1);
593 res_data->addr = addr;
594 res_data->callback = callback;
595 res_data->callback_data = user_data;
598 soup_dns_lookup_resolve_async (priv->lookup, async_context, cancellable,
599 lookup_resolved, res_data);
603 * soup_address_resolve_sync:
604 * @addr: a #SoupAddress
605 * @cancellable: a #GCancellable object, or %NULL
607 * Synchronously resolves the missing half of @addr, as with
608 * soup_address_resolve_async().
610 * If @cancellable is non-%NULL, it can be used to cancel the
611 * resolution. soup_address_resolve_sync() will then return a status
612 * of %SOUP_STATUS_CANCELLED.
614 * Return value: %SOUP_STATUS_OK, %SOUP_STATUS_CANT_RESOLVE, or
615 * %SOUP_STATUS_CANCELLED.
618 soup_address_resolve_sync (SoupAddress *addr, GCancellable *cancellable)
620 SoupAddressPrivate *priv;
623 g_return_val_if_fail (SOUP_IS_ADDRESS (addr), SOUP_STATUS_MALFORMED);
624 priv = SOUP_ADDRESS_GET_PRIVATE (addr);
627 status = soup_dns_lookup_resolve (priv->lookup, cancellable);
628 if (status == SOUP_STATUS_OK)
629 update_address (addr, priv->lookup);
630 g_object_unref (addr);