misc doc fixes
[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 } SoupAddressPrivate;
64 #define SOUP_ADDRESS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_ADDRESS, SoupAddressPrivate))
65
66 /* sockaddr generic macros */
67 #define SOUP_SIN(priv) ((struct sockaddr_in *)priv->sockaddr)
68 #ifdef HAVE_IPV6
69 #define SOUP_SIN6(priv) ((struct sockaddr_in6 *)priv->sockaddr)
70 #endif
71
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)
76 #ifdef HAVE_IPV6
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))
85 #else
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)
89 #endif
90
91 /* sockaddr port macros */
92 #define SOUP_ADDRESS_PORT_IS_VALID(port) (port >= 0 && port <= 65535)
93 #ifdef HAVE_IPV6
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) \
99         G_STMT_START {                                  \
100         if (priv->sockaddr->sa_family == AF_INET)       \
101                 SOUP_SIN(priv)->sin_port = port;        \
102         else                                            \
103                 SOUP_SIN6(priv)->sin6_port = port;      \
104         } G_STMT_END
105 #else
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)
108 #endif
109
110 /* sockaddr data macros */
111 #ifdef HAVE_IPV6
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)
116 #else
117 #define SOUP_ADDRESS_GET_DATA(priv) ((gpointer)&SOUP_SIN(priv)->sin_addr)
118 #endif
119 #define SOUP_ADDRESS_SET_DATA(priv, data, length) \
120         memcpy (SOUP_ADDRESS_GET_DATA (priv), data, length)
121
122
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);
130
131 G_DEFINE_TYPE (SoupAddress, soup_address, G_TYPE_OBJECT)
132
133 static void
134 soup_address_init (SoupAddress *addr)
135 {
136 }
137
138 static void
139 finalize (GObject *object)
140 {
141         SoupAddress *addr = SOUP_ADDRESS (object);
142         SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (addr);
143
144         if (priv->sockaddr)
145                 g_free (priv->sockaddr);
146         if (priv->name)
147                 g_free (priv->name);
148         if (priv->physical)
149                 g_free (priv->physical);
150
151         G_OBJECT_CLASS (soup_address_parent_class)->finalize (object);
152 }
153
154 static void
155 soup_address_class_init (SoupAddressClass *address_class)
156 {
157         GObjectClass *object_class = G_OBJECT_CLASS (address_class);
158
159         soup_dns_init ();
160
161         g_type_class_add_private (address_class, sizeof (SoupAddressPrivate));
162
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;
168
169         /* properties */
170         g_object_class_install_property (
171                 object_class, PROP_NAME,
172                 g_param_spec_string (SOUP_ADDRESS_NAME,
173                                      "Name",
174                                      "Hostname for this address",
175                                      NULL,
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,
180                                    "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,
188                                   "Port",
189                                   "Port for this address",
190                                   -1, 65535, -1,
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,
195                                      "Physical address",
196                                      "IP address for this address",
197                                      NULL,
198                                      G_PARAM_READABLE));
199         g_object_class_install_property (
200                 object_class, PROP_SOCKADDR,
201                 g_param_spec_pointer (SOUP_ADDRESS_SOCKADDR,
202                                       "sockaddr",
203                                       "struct sockaddr for this address",
204                                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
205
206 #ifdef G_OS_WIN32
207         /* This hopefully is a good place to call WSAStartup */
208         {
209                 WSADATA wsadata;
210                 if (WSAStartup (MAKEWORD (2, 0), &wsadata) != 0)
211                         g_error ("Windows Sockets could not be initialized");
212         }
213 #endif
214 }
215
216 static GObject *
217 constructor (GType                  type,
218              guint                  n_construct_properties,
219              GObjectConstructParam *construct_properties)
220 {
221         GObject *addr;
222         SoupAddressPrivate *priv;
223
224         addr = G_OBJECT_CLASS (soup_address_parent_class)->constructor (
225                 type, n_construct_properties, construct_properties);
226         if (!addr)
227                 return NULL;
228         priv = SOUP_ADDRESS_GET_PRIVATE (addr);
229
230         if (!priv->name && !priv->sockaddr) {
231                 g_object_unref (addr);
232                 return NULL;
233         }
234
235         return addr;
236 }
237
238 static void
239 set_property (GObject *object, guint prop_id,
240               const GValue *value, GParamSpec *pspec)
241 {
242         SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (object);
243         SoupAddressFamily family;
244         struct sockaddr *sa;
245         int len, port;
246
247         /* This is a mess because the properties are mostly orthogonal,
248          * but g_object_constructor wants to set a default value for each
249          * of them.
250          */
251
252         switch (prop_id) {
253         case PROP_NAME:
254                 priv->name = g_value_dup_string (value);
255                 break;
256
257         case PROP_FAMILY:
258                 family = g_value_get_enum (value);
259                 if (family == SOUP_ADDRESS_FAMILY_INVALID)
260                         return;
261                 g_return_if_fail (SOUP_ADDRESS_FAMILY_IS_VALID (family));
262                 g_return_if_fail (priv->sockaddr == NULL);
263
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));
267                 break;
268
269         case PROP_PORT:
270                 port = g_value_get_int (value);
271                 if (port == -1)
272                         return;
273                 g_return_if_fail (SOUP_ADDRESS_PORT_IS_VALID (port));
274
275                 priv->port = port;
276                 if (priv->sockaddr)
277                         SOUP_ADDRESS_SET_PORT (priv, htons (port));
278                 break;
279
280         case PROP_SOCKADDR:
281                 sa = g_value_get_pointer (value);
282                 if (!sa)
283                         return;
284                 g_return_if_fail (priv->sockaddr == NULL);
285
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));
289                 break;
290         default:
291                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
292                 break;
293         }
294 }
295
296 static void
297 get_property (GObject *object, guint prop_id,
298               GValue *value, GParamSpec *pspec)
299 {
300         SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (object);
301
302         switch (prop_id) {
303         case PROP_NAME:
304                 g_value_set_string (value, priv->name);
305                 break;
306         case PROP_FAMILY:
307                 if (priv->sockaddr)
308                         g_value_set_enum (value, SOUP_ADDRESS_GET_FAMILY (priv));
309                 else
310                         g_value_set_enum (value, 0);
311                 break;
312         case PROP_PORT:
313                 g_value_set_int (value, priv->port);
314                 break;
315         case PROP_PHYSICAL:
316                 g_value_set_string (value, soup_address_get_physical (SOUP_ADDRESS (object)));
317                 break;
318         case PROP_SOCKADDR:
319                 g_value_set_pointer (value, priv->sockaddr);
320                 break;
321         default:
322                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
323                 break;
324         }
325 }
326
327 /**
328  * soup_address_new:
329  * @name: a hostname or physical address
330  * @port: a port number
331  *
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.
336  *
337  * Return value: a #SoupAddress
338  **/
339 SoupAddress *
340 soup_address_new (const char *name, guint port)
341 {
342         g_return_val_if_fail (name != NULL, NULL);
343         g_return_val_if_fail (SOUP_ADDRESS_PORT_IS_VALID (port), NULL);
344
345         return g_object_new (SOUP_TYPE_ADDRESS,
346                              SOUP_ADDRESS_NAME, name,
347                              SOUP_ADDRESS_PORT, port,
348                              NULL);
349 }
350
351 /**
352  * soup_address_new_from_sockaddr:
353  * @sa: a pointer to a sockaddr
354  * @len: size of @sa
355  *
356  * Returns a #SoupAddress equivalent to @sa (or %NULL if @sa's
357  * address family isn't supported)
358  *
359  * Return value: the new #SoupAddress
360  **/
361 SoupAddress *
362 soup_address_new_from_sockaddr (struct sockaddr *sa, int len)
363 {
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);
367
368         return g_object_new (SOUP_TYPE_ADDRESS,
369                              SOUP_ADDRESS_SOCKADDR, sa,
370                              NULL);
371 }
372
373 /**
374  * SoupAddressFamily:
375  * @SOUP_ADDRESS_FAMILY_INVALID: an invalid %SoupAddress
376  * @SOUP_ADDRESS_FAMILY_IPV4: an IPv4 address
377  * @SOUP_ADDRESS_FAMILY_IPV6: an IPv6 address
378  *
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.
383  **/
384
385 /**
386  * SOUP_ADDRESS_ANY_PORT:
387  *
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.
390  **/
391
392 /**
393  * soup_address_new_any:
394  * @family: the address family
395  * @port: the port number (usually %SOUP_ADDRESS_ANY_PORT)
396  *
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().
400  *
401  * Return value: the new #SoupAddress
402  **/
403 SoupAddress *
404 soup_address_new_any (SoupAddressFamily family, guint port)
405 {
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);
408
409         return g_object_new (SOUP_TYPE_ADDRESS,
410                              SOUP_ADDRESS_FAMILY, family,
411                              SOUP_ADDRESS_PORT, port,
412                              NULL);
413 }
414
415 /**
416  * soup_address_get_name:
417  * @addr: a #SoupAddress
418  *
419  * Returns the hostname associated with @addr.
420  *
421  * Return value: the hostname, or %NULL if it is not known.
422  **/
423 const char *
424 soup_address_get_name (SoupAddress *addr)
425 {
426         g_return_val_if_fail (SOUP_IS_ADDRESS (addr), NULL);
427
428         return SOUP_ADDRESS_GET_PRIVATE (addr)->name;
429 }
430
431 /**
432  * soup_address_get_sockaddr:
433  * @addr: a #SoupAddress
434  * @len: return location for sockaddr length
435  *
436  * Returns the sockaddr associated with @addr, with its length in
437  * *@len. If the sockaddr is not yet known, returns %NULL.
438  *
439  * Return value: the sockaddr, or %NULL
440  **/
441 struct sockaddr *
442 soup_address_get_sockaddr (SoupAddress *addr, int *len)
443 {
444         SoupAddressPrivate *priv;
445
446         g_return_val_if_fail (SOUP_IS_ADDRESS (addr), NULL);
447         priv = SOUP_ADDRESS_GET_PRIVATE (addr);
448
449         if (priv->sockaddr && len)
450                 *len = SOUP_ADDRESS_FAMILY_SOCKADDR_SIZE (SOUP_ADDRESS_GET_FAMILY (priv));
451
452         return priv->sockaddr;
453 }
454
455 /**
456  * soup_address_get_physical:
457  * @addr: a #SoupAddress
458  *
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.
461  *
462  * Return value: the physical address, or %NULL
463  **/
464 const char *
465 soup_address_get_physical (SoupAddress *addr)
466 {
467         SoupAddressPrivate *priv;
468
469         g_return_val_if_fail (SOUP_IS_ADDRESS (addr), NULL);
470         priv = SOUP_ADDRESS_GET_PRIVATE (addr);
471
472         if (!priv->sockaddr)
473                 return NULL;
474
475         if (!priv->physical)
476                 priv->physical = soup_dns_ntop (priv->sockaddr);
477
478         return priv->physical;
479 }
480
481 /**
482  * soup_address_get_port:
483  * @addr: a #SoupAddress
484  *
485  * Returns the port associated with @addr.
486  *
487  * Return value: the port
488  **/
489 guint
490 soup_address_get_port (SoupAddress *addr)
491 {
492         g_return_val_if_fail (SOUP_IS_ADDRESS (addr), 0);
493
494         return SOUP_ADDRESS_GET_PRIVATE (addr)->port;
495 }
496
497
498 static void
499 update_address (SoupAddress *addr, SoupDNSLookup *lookup)
500 {
501         SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (addr);
502
503         if (!priv->name)
504                 priv->name = soup_dns_lookup_get_hostname (lookup);
505
506         if (!priv->sockaddr) {
507                 priv->sockaddr = soup_dns_lookup_get_address (lookup);
508                 SOUP_ADDRESS_SET_PORT (priv, htons (priv->port));
509         }
510 }
511
512 typedef struct {
513         SoupAddress         *addr;
514         SoupAddressCallback  callback;
515         gpointer             callback_data;
516 } SoupAddressResolveAsyncData;
517
518 static void
519 lookup_resolved (SoupDNSLookup *lookup, guint status, gpointer user_data)
520 {
521         SoupAddressResolveAsyncData *res_data = user_data;
522         SoupAddress *addr;
523         SoupAddressCallback callback;
524         gpointer callback_data;
525
526         addr = res_data->addr;
527         callback = res_data->callback;
528         callback_data = res_data->callback_data;
529         g_free (res_data);
530
531         if (status == SOUP_STATUS_OK)
532                 update_address (addr, lookup);
533
534         if (callback)
535                 callback (addr, status, callback_data);
536
537         g_object_unref (addr);
538         soup_dns_lookup_free (lookup);
539 }
540
541 /**
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()
548  *
549  * The callback function passed to soup_address_resolve_async().
550  **/
551
552 /**
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
559  *
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().)
564  *
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.
568  **/
569 void
570 soup_address_resolve_async (SoupAddress *addr, GMainContext *async_context,
571                             GCancellable *cancellable,
572                             SoupAddressCallback callback, gpointer user_data)
573 {
574         SoupAddressPrivate *priv;
575         SoupAddressResolveAsyncData *res_data;
576         SoupDNSLookup *lookup;
577
578         g_return_if_fail (SOUP_IS_ADDRESS (addr));
579         priv = SOUP_ADDRESS_GET_PRIVATE (addr);
580
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;
585
586         if (priv->name)
587                 lookup = soup_dns_lookup_name (priv->name);
588         else
589                 lookup = soup_dns_lookup_address (priv->sockaddr);
590         soup_dns_lookup_resolve_async (lookup, async_context, cancellable,
591                                        lookup_resolved, res_data);
592 }
593
594 /**
595  * soup_address_resolve_sync:
596  * @addr: a #SoupAddress
597  * @cancellable: a #GCancellable object, or %NULL
598  *
599  * Synchronously resolves the missing half of @addr, as with
600  * soup_address_resolve_async().
601  *
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.
605  *
606  * Return value: %SOUP_STATUS_OK, %SOUP_STATUS_CANT_RESOLVE, or
607  * %SOUP_STATUS_CANCELLED.
608  **/
609 guint
610 soup_address_resolve_sync (SoupAddress *addr, GCancellable *cancellable)
611 {
612         SoupAddressPrivate *priv;
613         SoupDNSLookup *lookup;
614         guint status;
615
616         g_return_val_if_fail (SOUP_IS_ADDRESS (addr), SOUP_STATUS_MALFORMED);
617         priv = SOUP_ADDRESS_GET_PRIVATE (addr);
618
619         g_object_ref (addr);
620         if (priv->name)
621                 lookup = soup_dns_lookup_name (priv->name);
622         else
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);
629         return status;
630 }
631
632 /**
633  * soup_address_is_resolved:
634  * @addr: a #SoupAddress
635  *
636  * Tests if @addr has already been resolved.
637  *
638  * Return value: %TRUE if @addr has been resolved.
639  **/
640 gboolean
641 soup_address_is_resolved (SoupAddress *addr)
642 {
643         SoupAddressPrivate *priv;
644
645         g_return_val_if_fail (SOUP_IS_ADDRESS (addr), FALSE);
646         priv = SOUP_ADDRESS_GET_PRIVATE (addr);
647
648         return priv->sockaddr && priv->name;
649 }
650
651 /**
652  * soup_address_hash_by_name:
653  * @addr: a #SoupAddress
654  *
655  * A hash function (for #GHashTable) that corresponds to
656  * soup_address_equal_by_name(), qv
657  *
658  * Return value: the named-based hash value for @addr.
659  **/
660 guint
661 soup_address_hash_by_name (gconstpointer addr)
662 {
663         SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (addr);
664
665         g_return_val_if_fail (priv->name != NULL, 0);
666         return g_str_hash (priv->name);
667 }
668
669 /**
670  * soup_address_equal_by_name:
671  * @addr1: a #SoupAddress with a resolved name
672  * @addr2: another #SoupAddress with a resolved name
673  *
674  * Tests if @addr1 and @addr2 have the same "name". This method can be
675  * used with soup_address_hash_by_name() to create a #GHashTable that
676  * hashes on address "names".
677  *
678  * Comparing by name normally means comparing the addresses by their
679  * hostnames. But if the address was originally created using an IP
680  * address literal, then it will be compared by that instead.
681  *
682  * In particular, if "www.example.com" has the IP address 10.0.0.1,
683  * and @addr1 was created with the name "www.example.com" and @addr2
684  * was created with the name "10.0.0.1", then they will compare as
685  * unequal for purposes of soup_address_equal_by_name().
686  *
687  * This would be used to distinguish hosts in situations where
688  * different virtual hosts on the same IP address should be considered
689  * different. Eg, for purposes of HTTP authentication or cookies, two
690  * hosts with the same IP address but different names are considered
691  * to be different hosts.
692  *
693  * See also soup_address_equal_by_ip(), which compares by IP address
694  * rather than by name.
695  *
696  * Return value: whether or not @addr1 and @addr2 have the same name
697  **/
698 gboolean
699 soup_address_equal_by_name (gconstpointer addr1, gconstpointer addr2)
700 {
701         SoupAddressPrivate *priv1 = SOUP_ADDRESS_GET_PRIVATE (addr1);
702         SoupAddressPrivate *priv2 = SOUP_ADDRESS_GET_PRIVATE (addr2);
703
704         g_return_val_if_fail (priv1->name != NULL, FALSE);
705         g_return_val_if_fail (priv2->name != NULL, FALSE);
706         return !g_ascii_strcasecmp (priv1->name, priv2->name);
707 }
708
709 /**
710  * soup_address_hash_by_ip:
711  * @addr: a #SoupAddress
712  *
713  * A hash function (for #GHashTable) that corresponds to
714  * soup_address_equal_by_ip(), qv
715  *
716  * Return value: the IP-based hash value for @addr.
717  **/
718 guint
719 soup_address_hash_by_ip (gconstpointer addr)
720 {
721         SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (addr);
722         guint hash;
723
724         g_return_val_if_fail (priv->sockaddr != NULL, 0);
725
726         memcpy (&hash, SOUP_ADDRESS_GET_DATA (priv),
727                 MIN (sizeof (hash), SOUP_ADDRESS_FAMILY_DATA_SIZE (priv->sockaddr->sa_family)));
728         return hash;
729 }
730
731 /**
732  * soup_address_equal_by_ip:
733  * @addr1: a #SoupAddress with a resolved IP address
734  * @addr2: another #SoupAddress with a resolved IP address
735  *
736  * Tests if @addr1 and @addr2 have the same IP address. This method
737  * can be used with soup_address_hash_by_ip() to create a
738  * #GHashTable that hashes on IP address.
739  *
740  * This would be used to distinguish hosts in situations where
741  * different virtual hosts on the same IP address should be considered
742  * the same. Eg, if "www.example.com" and "www.example.net" have the
743  * same IP address, then a single #SoupConnection can be used to talk
744  * to either of them.
745  *
746  * See also soup_address_equal_by_name(), which compares by name
747  * rather than by IP address.
748  *
749  * Return value: whether or not @addr1 and @addr2 have the same IP
750  * address.
751  **/
752 gboolean
753 soup_address_equal_by_ip (gconstpointer addr1, gconstpointer addr2)
754 {
755         SoupAddressPrivate *priv1 = SOUP_ADDRESS_GET_PRIVATE (addr1);
756         SoupAddressPrivate *priv2 = SOUP_ADDRESS_GET_PRIVATE (addr2);
757         int size;
758
759         g_return_val_if_fail (priv1->sockaddr != NULL, FALSE);
760         g_return_val_if_fail (priv2->sockaddr != NULL, FALSE);
761
762         size = SOUP_ADDRESS_FAMILY_SOCKADDR_SIZE (priv1->sockaddr->sa_family);
763         return (priv1->sockaddr->sa_family ==
764                 priv2->sockaddr->sa_family &&
765                 !memcmp (priv1->sockaddr, priv2->sockaddr, size));
766 }