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