ginetaddress: fix addr/string conversions on windows
[platform/upstream/glib.git] / gio / ginetaddress.c
1 /* GIO - GLib Input, Output and Streaming Library
2  *
3  * Copyright (C) 2008 Christian Kellner, Samuel Cormier-Iijima
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Authors: Christian Kellner <gicmo@gnome.org>
21  *          Samuel Cormier-Iijima <sciyoshi@gmail.com>
22  */
23
24 #include <config.h>
25
26 #include <string.h>
27
28 #include <glib.h>
29
30 #include "ginetaddress.h"
31 #include "gioenums.h"
32 #include "gioenumtypes.h"
33 #include "glibintl.h"
34 #include "gnetworkingprivate.h"
35
36
37 /**
38  * SECTION:ginetaddress
39  * @short_description: An IPv4/IPv6 address
40  *
41  * #GInetAddress represents an IPv4 or IPv6 internet address. Use
42  * g_resolver_lookup_by_name() or g_resolver_lookup_by_name_async() to
43  * look up the #GInetAddress for a hostname. Use
44  * g_resolver_lookup_by_address() or
45  * g_resolver_lookup_by_address_async() to look up the hostname for a
46  * #GInetAddress.
47  *
48  * To actually connect to a remote host, you will need a
49  * #GInetSocketAddress (which includes a #GInetAddress as well as a
50  * port number).
51  */
52
53 /**
54  * GInetAddress:
55  *
56  * An IPv4 or IPv6 internet address.
57  */
58
59 G_DEFINE_TYPE_WITH_CODE (GInetAddress, g_inet_address, G_TYPE_OBJECT,
60                          g_networking_init ();)
61
62 struct _GInetAddressPrivate
63 {
64   GSocketFamily family;
65   union {
66     struct in_addr ipv4;
67     struct in6_addr ipv6;
68   } addr;
69 };
70
71 enum
72 {
73   PROP_0,
74   PROP_FAMILY,
75   PROP_BYTES,
76   PROP_IS_ANY,
77   PROP_IS_LOOPBACK,
78   PROP_IS_LINK_LOCAL,
79   PROP_IS_SITE_LOCAL,
80   PROP_IS_MULTICAST,
81   PROP_IS_MC_GLOBAL,
82   PROP_IS_MC_LINK_LOCAL,
83   PROP_IS_MC_NODE_LOCAL,
84   PROP_IS_MC_ORG_LOCAL,
85   PROP_IS_MC_SITE_LOCAL,
86 };
87
88 static void
89 g_inet_address_set_property (GObject      *object,
90                              guint         prop_id,
91                              const GValue *value,
92                              GParamSpec   *pspec)
93 {
94   GInetAddress *address = G_INET_ADDRESS (object);
95
96   switch (prop_id)
97     {
98     case PROP_FAMILY:
99       address->priv->family = g_value_get_enum (value);
100       break;
101
102     case PROP_BYTES:
103       memcpy (&address->priv->addr, g_value_get_pointer (value),
104               address->priv->family == AF_INET ?
105               sizeof (address->priv->addr.ipv4) :
106               sizeof (address->priv->addr.ipv6));
107       break;
108
109     default:
110       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
111       break;
112     }
113
114 }
115
116 static void
117 g_inet_address_get_property (GObject    *object,
118                              guint       prop_id,
119                              GValue     *value,
120                              GParamSpec *pspec)
121 {
122   GInetAddress *address = G_INET_ADDRESS (object);
123
124   switch (prop_id)
125     {
126     case PROP_FAMILY:
127       g_value_set_enum (value, address->priv->family);
128       break;
129
130     case PROP_BYTES:
131       g_value_set_pointer (value, &address->priv->addr);
132       break;
133
134     case PROP_IS_ANY:
135       g_value_set_boolean (value, g_inet_address_get_is_any (address));
136       break;
137
138     case PROP_IS_LOOPBACK:
139       g_value_set_boolean (value, g_inet_address_get_is_loopback (address));
140       break;
141
142     case PROP_IS_LINK_LOCAL:
143       g_value_set_boolean (value, g_inet_address_get_is_link_local (address));
144       break;
145
146     case PROP_IS_SITE_LOCAL:
147       g_value_set_boolean (value, g_inet_address_get_is_site_local (address));
148       break;
149
150     case PROP_IS_MULTICAST:
151       g_value_set_boolean (value, g_inet_address_get_is_multicast (address));
152       break;
153
154     case PROP_IS_MC_GLOBAL:
155       g_value_set_boolean (value, g_inet_address_get_is_mc_global (address));
156       break;
157
158     case PROP_IS_MC_LINK_LOCAL:
159       g_value_set_boolean (value, g_inet_address_get_is_mc_link_local (address));
160       break;
161
162     case PROP_IS_MC_NODE_LOCAL:
163       g_value_set_boolean (value, g_inet_address_get_is_mc_node_local (address));
164       break;
165
166     case PROP_IS_MC_ORG_LOCAL:
167       g_value_set_boolean (value, g_inet_address_get_is_mc_org_local (address));
168       break;
169
170     case PROP_IS_MC_SITE_LOCAL:
171       g_value_set_boolean (value, g_inet_address_get_is_mc_site_local (address));
172       break;
173
174     default:
175       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
176     }
177 }
178
179 static void
180 g_inet_address_class_init (GInetAddressClass *klass)
181 {
182   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
183
184   g_type_class_add_private (klass, sizeof (GInetAddressPrivate));
185
186   gobject_class->set_property = g_inet_address_set_property;
187   gobject_class->get_property = g_inet_address_get_property;
188
189   g_object_class_install_property (gobject_class, PROP_FAMILY,
190                                    g_param_spec_enum ("family",
191                                                       P_("Address family"),
192                                                       P_("The address family (IPv4 or IPv6)"),
193                                                       G_TYPE_SOCKET_FAMILY,
194                                                       G_SOCKET_FAMILY_INVALID,
195                                                       G_PARAM_READWRITE |
196                                                       G_PARAM_CONSTRUCT_ONLY |
197                                                       G_PARAM_STATIC_STRINGS));
198
199   g_object_class_install_property (gobject_class, PROP_BYTES,
200                                    g_param_spec_pointer ("bytes",
201                                                          P_("Bytes"),
202                                                          P_("The raw address data"),
203                                                          G_PARAM_READWRITE |
204                                                          G_PARAM_CONSTRUCT_ONLY |
205                                                          G_PARAM_STATIC_STRINGS));
206
207   /**
208    * GInetAddress:is-any:
209    *
210    * Whether this is the "any" address for its family.
211    * See g_inet_address_get_is_any().
212    *
213    * Since: 2.22
214    */
215   g_object_class_install_property (gobject_class, PROP_IS_ANY,
216                                    g_param_spec_boolean ("is-any",
217                                                          P_("Is any"),
218                                                          P_("Whether this is the \"any\" address for its family"),
219                                                          FALSE,
220                                                          G_PARAM_READABLE |
221                                                          G_PARAM_STATIC_STRINGS));
222
223   /**
224    * GInetAddress:is-link-local:
225    *
226    * Whether this is a link-local address.
227    * See g_inet_address_get_is_link_local().
228    *
229    * Since: 2.22
230    */
231   g_object_class_install_property (gobject_class, PROP_IS_LINK_LOCAL,
232                                    g_param_spec_boolean ("is-link-local",
233                                                          P_("Is link-local"),
234                                                          P_("Whether this is a link-local address"),
235                                                          FALSE,
236                                                          G_PARAM_READABLE |
237                                                          G_PARAM_STATIC_STRINGS));
238
239   /**
240    * GInetAddress:is-loopback:
241    *
242    * Whether this is the loopback address for its family.
243    * See g_inet_address_get_is_loopback().
244    *
245    * Since: 2.22
246    */
247   g_object_class_install_property (gobject_class, PROP_IS_LOOPBACK,
248                                    g_param_spec_boolean ("is-loopback",
249                                                          P_("Is loopback"),
250                                                          P_("Whether this is the loopback address for its family"),
251                                                          FALSE,
252                                                          G_PARAM_READABLE |
253                                                          G_PARAM_STATIC_STRINGS));
254
255   /**
256    * GInetAddress:is-site-local:
257    *
258    * Whether this is a site-local address.
259    * See g_inet_address_get_is_loopback().
260    *
261    * Since: 2.22
262    */
263   g_object_class_install_property (gobject_class, PROP_IS_SITE_LOCAL,
264                                    g_param_spec_boolean ("is-site-local",
265                                                          P_("Is site-local"),
266                                                          P_("Whether this is a site-local address"),
267                                                          FALSE,
268                                                          G_PARAM_READABLE |
269                                                          G_PARAM_STATIC_STRINGS));
270
271   /**
272    * GInetAddress:is-multicast:
273    *
274    * Whether this is a multicast address.
275    * See g_inet_address_get_is_multicast().
276    *
277    * Since: 2.22
278    */
279   g_object_class_install_property (gobject_class, PROP_IS_MULTICAST,
280                                    g_param_spec_boolean ("is-multicast",
281                                                          P_("Is multicast"),
282                                                          P_("Whether this is a multicast address"),
283                                                          FALSE,
284                                                          G_PARAM_READABLE |
285                                                          G_PARAM_STATIC_STRINGS));
286
287   /**
288    * GInetAddress:is-mc-global:
289    *
290    * Whether this is a global multicast address.
291    * See g_inet_address_get_is_mc_global().
292    *
293    * Since: 2.22
294    */
295   g_object_class_install_property (gobject_class, PROP_IS_MC_GLOBAL,
296                                    g_param_spec_boolean ("is-mc-global",
297                                                          P_("Is multicast global"),
298                                                          P_("Whether this is a global multicast address"),
299                                                          FALSE,
300                                                          G_PARAM_READABLE |
301                                                          G_PARAM_STATIC_STRINGS));
302
303
304   /**
305    * GInetAddress:is-mc-link-local:
306    *
307    * Whether this is a link-local multicast address.
308    * See g_inet_address_get_is_mc_link_local().
309    *
310    * Since: 2.22
311    */
312   g_object_class_install_property (gobject_class, PROP_IS_MC_LINK_LOCAL,
313                                    g_param_spec_boolean ("is-mc-link-local",
314                                                          P_("Is multicast link-local"),
315                                                          P_("Whether this is a link-local multicast address"),
316                                                          FALSE,
317                                                          G_PARAM_READABLE |
318                                                          G_PARAM_STATIC_STRINGS));
319
320   /**
321    * GInetAddress:is-mc-node-local:
322    *
323    * Whether this is a node-local multicast address.
324    * See g_inet_address_get_is_mc_node_local().
325    *
326    * Since: 2.22
327    */
328   g_object_class_install_property (gobject_class, PROP_IS_MC_NODE_LOCAL,
329                                    g_param_spec_boolean ("is-mc-node-local",
330                                                          P_("Is multicast node-local"),
331                                                          P_("Whether this is a node-local multicast address"),
332                                                          FALSE,
333                                                          G_PARAM_READABLE |
334                                                          G_PARAM_STATIC_STRINGS));
335
336   /**
337    * GInetAddress:is-mc-org-local:
338    *
339    * Whether this is an organization-local multicast address.
340    * See g_inet_address_get_is_mc_org_local().
341    *
342    * Since: 2.22
343    */
344   g_object_class_install_property (gobject_class, PROP_IS_MC_ORG_LOCAL,
345                                    g_param_spec_boolean ("is-mc-org-local",
346                                                          P_("Is multicast org-local"),
347                                                          P_("Whether this is an organization-local multicast address"),
348                                                          FALSE,
349                                                          G_PARAM_READABLE |
350                                                          G_PARAM_STATIC_STRINGS));
351
352   /**
353    * GInetAddress:is-mc-site-local:
354    *
355    * Whether this is a site-local multicast address.
356    * See g_inet_address_get_is_mc_site_local().
357    *
358    * Since: 2.22
359    */
360   g_object_class_install_property (gobject_class, PROP_IS_MC_SITE_LOCAL,
361                                    g_param_spec_boolean ("is-mc-site-local",
362                                                          P_("Is multicast site-local"),
363                                                          P_("Whether this is a site-local multicast address"),
364                                                          FALSE,
365                                                          G_PARAM_READABLE |
366                                                          G_PARAM_STATIC_STRINGS));
367 }
368
369 static void
370 g_inet_address_init (GInetAddress *address)
371 {
372   address->priv = G_TYPE_INSTANCE_GET_PRIVATE (address,
373                                                G_TYPE_INET_ADDRESS,
374                                                GInetAddressPrivate);
375 }
376
377 /**
378  * g_inet_address_new_from_string:
379  * @string: a string representation of an IP address
380  *
381  * Parses @string as an IP address and creates a new #GInetAddress.
382  *
383  * Returns: a new #GInetAddress corresponding to @string, or %NULL if
384  * @string could not be parsed.
385  *
386  * Since: 2.22
387  */
388 GInetAddress *
389 g_inet_address_new_from_string (const gchar *string)
390 {
391 #ifdef G_OS_WIN32
392   struct sockaddr_storage sa;
393   struct sockaddr_in *sin = (struct sockaddr_in *)&sa;
394   struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&sa;
395   gint len;
396 #else /* !G_OS_WIN32 */
397   struct in_addr in_addr;
398   struct in6_addr in6_addr;
399 #endif
400
401   /* If this GInetAddress is the first networking-related object to be
402    * created, then we won't have called g_networking_init() yet at
403    * this point.
404    */
405   g_networking_init ();
406
407 #ifdef G_OS_WIN32
408   /* We need to make sure to not pass a string of the form
409    * "IPv4addr:port" or "[IPv6addr]:port" to WSAStringToAddress(),
410    * since it would accept them (returning both the address and the
411    * port), but we only want to accept standalone IP addresses. (In
412    * the IPv6 case, WINE actually only checks for the ']', not the
413    * '[', which is why we do the same here.)
414    */
415   if (!strchr (string, ':'))
416     {
417       len = sizeof (sa);
418       if (WSAStringToAddress ((LPTSTR) string, AF_INET, NULL, (LPSOCKADDR) &sa, &len) == 0)
419         return g_inet_address_new_from_bytes ((guint8 *)&sin->sin_addr, AF_INET);
420     }
421
422   if (!strchr (string, ']'))
423     {
424       len = sizeof (sa);
425       if (WSAStringToAddress ((LPTSTR) string, AF_INET6, NULL, (LPSOCKADDR) &sa, &len) == 0)
426         return g_inet_address_new_from_bytes ((guint8 *)&sin6->sin6_addr, AF_INET6);
427     }
428
429 #else /* !G_OS_WIN32 */
430
431   if (inet_pton (AF_INET, string, &in_addr) > 0)
432     return g_inet_address_new_from_bytes ((guint8 *)&in_addr, AF_INET);
433   else if (inet_pton (AF_INET6, string, &in6_addr) > 0)
434     return g_inet_address_new_from_bytes ((guint8 *)&in6_addr, AF_INET6);
435 #endif
436
437   return NULL;
438 }
439
440 #define G_INET_ADDRESS_FAMILY_IS_VALID(family) ((family) == AF_INET || (family) == AF_INET6)
441
442 /**
443  * g_inet_address_new_from_bytes:
444  * @bytes: (array) (element-type guint8): raw address data
445  * @family: the address family of @bytes
446  *
447  * Creates a new #GInetAddress from the given @family and @bytes.
448  * @bytes should be 4 bytes for %G_SOCKET_FAMILY_IPV4 and 16 bytes for
449  * %G_SOCKET_FAMILY_IPV6.
450  *
451  * Returns: a new #GInetAddress corresponding to @family and @bytes.
452  *
453  * Since: 2.22
454  */
455 GInetAddress *
456 g_inet_address_new_from_bytes (const guint8         *bytes,
457                                GSocketFamily  family)
458 {
459   g_return_val_if_fail (G_INET_ADDRESS_FAMILY_IS_VALID (family), NULL);
460
461   return g_object_new (G_TYPE_INET_ADDRESS,
462                        "family", family,
463                        "bytes", bytes,
464                        NULL);
465 }
466
467 /**
468  * g_inet_address_new_loopback:
469  * @family: the address family
470  *
471  * Creates a #GInetAddress for the loopback address for @family.
472  *
473  * Returns: a new #GInetAddress corresponding to the loopback address
474  * for @family.
475  *
476  * Since: 2.22
477  */
478 GInetAddress *
479 g_inet_address_new_loopback (GSocketFamily family)
480 {
481   g_return_val_if_fail (G_INET_ADDRESS_FAMILY_IS_VALID (family), NULL);
482
483   if (family == AF_INET)
484     {    
485       guint8 addr[4] = {127, 0, 0, 1};
486
487       return g_inet_address_new_from_bytes (addr, family);
488     }
489   else
490     return g_inet_address_new_from_bytes (in6addr_loopback.s6_addr, family);
491 }
492
493 /**
494  * g_inet_address_new_any:
495  * @family: the address family
496  *
497  * Creates a #GInetAddress for the "any" address (unassigned/"don't
498  * care") for @family.
499  *
500  * Returns: a new #GInetAddress corresponding to the "any" address
501  * for @family.
502  *
503  * Since: 2.22
504  */
505 GInetAddress *
506 g_inet_address_new_any (GSocketFamily family)
507 {
508   g_return_val_if_fail (G_INET_ADDRESS_FAMILY_IS_VALID (family), NULL);
509
510   if (family == AF_INET)
511     {    
512       guint8 addr[4] = {0, 0, 0, 0};
513
514       return g_inet_address_new_from_bytes (addr, family);
515     }
516   else
517     return g_inet_address_new_from_bytes (in6addr_any.s6_addr, family);
518 }
519
520
521 /**
522  * g_inet_address_to_string:
523  * @address: a #GInetAddress
524  *
525  * Converts @address to string form.
526  *
527  * Returns: a representation of @address as a string, which should be
528  * freed after use.
529  *
530  * Since: 2.22
531  */
532 gchar *
533 g_inet_address_to_string (GInetAddress *address)
534 {
535   gchar buffer[INET6_ADDRSTRLEN];
536 #ifdef G_OS_WIN32
537   DWORD buflen = sizeof (buffer), addrlen;
538   struct sockaddr_storage sa;
539   struct sockaddr_in *sin = (struct sockaddr_in *)&sa;
540   struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&sa;
541 #endif
542
543   g_return_val_if_fail (G_IS_INET_ADDRESS (address), NULL);
544
545 #ifdef G_OS_WIN32
546   memset (&sa, 0, sizeof (sa));
547   sa.ss_family = address->priv->family;
548   if (address->priv->family == AF_INET)
549     {
550       addrlen = sizeof (*sin);
551       memcpy (&sin->sin_addr, &address->priv->addr.ipv4,
552               sizeof (sin->sin_addr));
553     }
554   else
555     {
556       addrlen = sizeof (*sin6);
557       memcpy (&sin6->sin6_addr, &address->priv->addr.ipv6,
558               sizeof (sin6->sin6_addr));
559     }
560   if (WSAAddressToString ((LPSOCKADDR) &sa, addrlen, NULL, buffer, &buflen) != 0)
561     return NULL;
562
563 #else /* !G_OS_WIN32 */
564
565   if (address->priv->family == AF_INET)
566     inet_ntop (AF_INET, &address->priv->addr.ipv4, buffer, sizeof (buffer));
567   else
568     inet_ntop (AF_INET6, &address->priv->addr.ipv6, buffer, sizeof (buffer));
569 #endif
570
571   return g_strdup (buffer);
572 }
573
574 /**
575  * g_inet_address_to_bytes: (skip)
576  * @address: a #GInetAddress
577  *
578  * Gets the raw binary address data from @address.
579  *
580  * Returns: a pointer to an internal array of the bytes in @address,
581  * which should not be modified, stored, or freed. The size of this
582  * array can be gotten with g_inet_address_get_native_size().
583  *
584  * Since: 2.22
585  */
586 const guint8 *
587 g_inet_address_to_bytes (GInetAddress *address)
588 {
589   g_return_val_if_fail (G_IS_INET_ADDRESS (address), NULL);
590
591   return (guint8 *)&address->priv->addr;
592 }
593
594 /**
595  * g_inet_address_get_native_size:
596  * @address: a #GInetAddress
597  *
598  * Gets the size of the native raw binary address for @address. This
599  * is the size of the data that you get from g_inet_address_to_bytes().
600  *
601  * Returns: the number of bytes used for the native version of @address.
602  *
603  * Since: 2.22
604  */
605 gsize
606 g_inet_address_get_native_size (GInetAddress *address)
607 {
608   if (address->priv->family == AF_INET)
609     return sizeof (address->priv->addr.ipv4);
610   return sizeof (address->priv->addr.ipv6);
611 }
612
613 /**
614  * g_inet_address_get_family:
615  * @address: a #GInetAddress
616  *
617  * Gets @address's family
618  *
619  * Returns: @address's family
620  *
621  * Since: 2.22
622  */
623 GSocketFamily
624 g_inet_address_get_family (GInetAddress *address)
625 {
626   g_return_val_if_fail (G_IS_INET_ADDRESS (address), FALSE);
627
628   return address->priv->family;
629 }
630
631 /**
632  * g_inet_address_get_is_any:
633  * @address: a #GInetAddress
634  *
635  * Tests whether @address is the "any" address for its family.
636  *
637  * Returns: %TRUE if @address is the "any" address for its family.
638  *
639  * Since: 2.22
640  */
641 gboolean
642 g_inet_address_get_is_any (GInetAddress *address)
643 {
644   g_return_val_if_fail (G_IS_INET_ADDRESS (address), FALSE);
645
646   if (address->priv->family == AF_INET)
647     {
648       guint32 addr4 = g_ntohl (address->priv->addr.ipv4.s_addr);
649
650       return addr4 == INADDR_ANY;
651     }
652   else
653     return IN6_IS_ADDR_UNSPECIFIED (&address->priv->addr.ipv6);
654 }
655
656 /**
657  * g_inet_address_get_is_loopback:
658  * @address: a #GInetAddress
659  *
660  * Tests whether @address is the loopback address for its family.
661  *
662  * Returns: %TRUE if @address is the loopback address for its family.
663  *
664  * Since: 2.22
665  */
666 gboolean
667 g_inet_address_get_is_loopback (GInetAddress *address)
668 {
669   g_return_val_if_fail (G_IS_INET_ADDRESS (address), FALSE);
670
671   if (address->priv->family == AF_INET)
672     {
673       guint32 addr4 = g_ntohl (address->priv->addr.ipv4.s_addr);
674
675       /* 127.0.0.0/8 */
676       return ((addr4 & 0xff000000) == 0x7f000000);
677     }
678   else
679     return IN6_IS_ADDR_LOOPBACK (&address->priv->addr.ipv6);
680 }
681
682 /**
683  * g_inet_address_get_is_link_local:
684  * @address: a #GInetAddress
685  *
686  * Tests whether @address is a link-local address (that is, if it
687  * identifies a host on a local network that is not connected to the
688  * Internet).
689  *
690  * Returns: %TRUE if @address is a link-local address.
691  *
692  * Since: 2.22
693  */
694 gboolean
695 g_inet_address_get_is_link_local (GInetAddress *address)
696 {
697   g_return_val_if_fail (G_IS_INET_ADDRESS (address), FALSE);
698
699   if (address->priv->family == AF_INET)
700     {
701       guint32 addr4 = g_ntohl (address->priv->addr.ipv4.s_addr);
702
703       /* 169.254.0.0/16 */
704       return ((addr4 & 0xffff0000) == 0xa9fe0000);
705     }
706   else
707     return IN6_IS_ADDR_LINKLOCAL (&address->priv->addr.ipv6);
708 }
709
710 /**
711  * g_inet_address_get_is_site_local:
712  * @address: a #GInetAddress
713  *
714  * Tests whether @address is a site-local address such as 10.0.0.1
715  * (that is, the address identifies a host on a local network that can
716  * not be reached directly from the Internet, but which may have
717  * outgoing Internet connectivity via a NAT or firewall).
718  *
719  * Returns: %TRUE if @address is a site-local address.
720  *
721  * Since: 2.22
722  */
723 gboolean
724 g_inet_address_get_is_site_local (GInetAddress *address)
725 {
726   g_return_val_if_fail (G_IS_INET_ADDRESS (address), FALSE);
727
728   if (address->priv->family == AF_INET)
729     {
730       guint32 addr4 = g_ntohl (address->priv->addr.ipv4.s_addr);
731
732       /* 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 */
733       return ((addr4 & 0xff000000) == 0x0a000000 ||
734               (addr4 & 0xfff00000) == 0xac100000 ||
735               (addr4 & 0xffff0000) == 0xc0a80000);
736     }
737   else
738     return IN6_IS_ADDR_SITELOCAL (&address->priv->addr.ipv6);
739 }
740
741 /**
742  * g_inet_address_get_is_multicast:
743  * @address: a #GInetAddress
744  *
745  * Tests whether @address is a multicast address.
746  *
747  * Returns: %TRUE if @address is a multicast address.
748  *
749  * Since: 2.22
750  */
751 gboolean
752 g_inet_address_get_is_multicast (GInetAddress *address)
753 {
754   g_return_val_if_fail (G_IS_INET_ADDRESS (address), FALSE);
755
756   if (address->priv->family == AF_INET)
757     {
758       guint32 addr4 = g_ntohl (address->priv->addr.ipv4.s_addr);
759
760       return IN_MULTICAST (addr4);
761     }
762   else
763     return IN6_IS_ADDR_MULTICAST (&address->priv->addr.ipv6);
764 }
765
766 /**
767  * g_inet_address_get_is_mc_global:
768  * @address: a #GInetAddress
769  *
770  * Tests whether @address is a global multicast address.
771  *
772  * Returns: %TRUE if @address is a global multicast address.
773  *
774  * Since: 2.22
775  */
776 gboolean
777 g_inet_address_get_is_mc_global (GInetAddress *address)
778 {
779   g_return_val_if_fail (G_IS_INET_ADDRESS (address), FALSE);
780
781   if (address->priv->family == AF_INET)
782     return FALSE;
783   else
784     return IN6_IS_ADDR_MC_GLOBAL (&address->priv->addr.ipv6);
785 }
786
787 /**
788  * g_inet_address_get_is_mc_link_local:
789  * @address: a #GInetAddress
790  *
791  * Tests whether @address is a link-local multicast address.
792  *
793  * Returns: %TRUE if @address is a link-local multicast address.
794  *
795  * Since: 2.22
796  */
797 gboolean
798 g_inet_address_get_is_mc_link_local (GInetAddress *address)
799 {
800   g_return_val_if_fail (G_IS_INET_ADDRESS (address), FALSE);
801
802   if (address->priv->family == AF_INET)
803     return FALSE;
804   else
805     return IN6_IS_ADDR_MC_LINKLOCAL (&address->priv->addr.ipv6);
806 }
807
808 /**
809  * g_inet_address_get_is_mc_node_local:
810  * @address: a #GInetAddress
811  *
812  * Tests whether @address is a node-local multicast address.
813  *
814  * Returns: %TRUE if @address is a node-local multicast address.
815  *
816  * Since: 2.22
817  */
818 gboolean
819 g_inet_address_get_is_mc_node_local (GInetAddress *address)
820 {
821   g_return_val_if_fail (G_IS_INET_ADDRESS (address), FALSE);
822
823   if (address->priv->family == AF_INET)
824     return FALSE;
825   else
826     return IN6_IS_ADDR_MC_NODELOCAL (&address->priv->addr.ipv6);
827 }
828
829 /**
830  * g_inet_address_get_is_mc_org_local:
831  * @address: a #GInetAddress
832  *
833  * Tests whether @address is an organization-local multicast address.
834  *
835  * Returns: %TRUE if @address is an organization-local multicast address.
836  *
837  * Since: 2.22
838  */
839 gboolean
840 g_inet_address_get_is_mc_org_local  (GInetAddress *address)
841 {
842   g_return_val_if_fail (G_IS_INET_ADDRESS (address), FALSE);
843
844   if (address->priv->family == AF_INET)
845     return FALSE;
846   else
847     return IN6_IS_ADDR_MC_ORGLOCAL (&address->priv->addr.ipv6);
848 }
849
850 /**
851  * g_inet_address_get_is_mc_site_local:
852  * @address: a #GInetAddress
853  *
854  * Tests whether @address is a site-local multicast address.
855  *
856  * Returns: %TRUE if @address is a site-local multicast address.
857  *
858  * Since: 2.22
859  */
860 gboolean
861 g_inet_address_get_is_mc_site_local (GInetAddress *address)
862 {
863   g_return_val_if_fail (G_IS_INET_ADDRESS (address), FALSE);
864
865   if (address->priv->family == AF_INET)
866     return FALSE;
867   else
868     return IN6_IS_ADDR_MC_SITELOCAL (&address->priv->addr.ipv6);
869 }
870
871 /**
872  * g_inet_address_equal:
873  * @address: A #GInetAddress.
874  * @other_address: Another #GInetAddress.
875  *
876  * Checks if two #GInetAddress instances are equal, e.g. the same address.
877  *
878  * Returns: %TRUE if @address and @other_address are equal, %FALSE otherwise.
879  *
880  * Since: 2.30
881  */
882 gboolean
883 g_inet_address_equal (GInetAddress *address,
884                       GInetAddress *other_address)
885 {
886   g_return_val_if_fail (G_IS_INET_ADDRESS (address), FALSE);
887   g_return_val_if_fail (G_IS_INET_ADDRESS (other_address), FALSE);
888
889   if (g_inet_address_get_family (address) != g_inet_address_get_family (other_address))
890     return FALSE;
891
892   if (memcmp (g_inet_address_to_bytes (address),
893               g_inet_address_to_bytes (other_address),
894               g_inet_address_get_native_size (address)) != 0)
895     return FALSE;
896
897   return TRUE;
898 }