[glib] GInetAddressMask: new type for internet address range matching
- From: Dan Winship <danw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib] GInetAddressMask: new type for internet address range matching
- Date: Mon, 14 Nov 2011 19:00:20 +0000 (UTC)
commit eb9755dc9c765cd0381f8b6d897e6ff4f7582a0a
Author: Dan Winship <danw gnome org>
Date: Sat Oct 1 08:31:54 2011 -0400
GInetAddressMask: new type for internet address range matching
Eg, for matching a GInetAddress to a range like "10.0.0.0/8" or
"fe80::/10"
https://bugzilla.gnome.org/show_bug.cgi?id=620932
docs/reference/gio/gio-docs.xml | 1 +
docs/reference/gio/gio-sections.txt | 25 ++
gio/Makefile.am | 2 +
gio/ginetaddressmask.c | 463 +++++++++++++++++++++++++++++++++++
gio/ginetaddressmask.h | 78 ++++++
gio/gio.h | 1 +
gio/gio.symbols | 9 +
gio/giotypes.h | 1 +
8 files changed, 580 insertions(+), 0 deletions(-)
---
diff --git a/docs/reference/gio/gio-docs.xml b/docs/reference/gio/gio-docs.xml
index 496602d..fd408aa 100644
--- a/docs/reference/gio/gio-docs.xml
+++ b/docs/reference/gio/gio-docs.xml
@@ -107,6 +107,7 @@
<title>Lowlevel network support</title>
<xi:include href="xml/gsocket.xml"/>
<xi:include href="xml/ginetaddress.xml"/>
+ <xi:include href="xml/ginetaddressmask.xml"/>
<xi:include href="xml/gsocketaddress.xml"/>
<xi:include href="xml/ginetsocketaddress.xml"/>
<xi:include href="xml/gunixsocketaddress.xml"/>
diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt
index 49ac6b1..33287c0 100644
--- a/docs/reference/gio/gio-sections.txt
+++ b/docs/reference/gio/gio-sections.txt
@@ -1538,6 +1538,31 @@ g_inet_address_get_type
</SECTION>
<SECTION>
+<FILE>ginetaddressmask</FILE>
+<TITLE>GInetAddressMask</TITLE>
+GInetAddressMask
+g_inet_address_mask_new
+g_inet_address_mask_new_from_string
+g_inet_address_mask_to_string
+g_inet_address_mask_get_family
+g_inet_address_mask_get_address
+g_inet_address_mask_get_length
+g_inet_address_mask_matches
+g_inet_address_mask_equal
+<SUBSECTION Standard>
+GInetAddressMaskClass
+GInetAddressMaskPrivate
+G_INET_ADDRESS_MASK
+G_INET_ADDRESS_MASK_CLASS
+G_INET_ADDRESS_MASK_GET_CLASS
+G_IS_INET_ADDRESS_MASK
+G_IS_INET_ADDRESS_MASK_CLASS
+G_TYPE_INET_ADDRESS_MASK
+<SUBSECTION Private>
+g_inet_address_mask_get_type
+</SECTION>
+
+<SECTION>
<FILE>gsocketaddress</FILE>
<TITLE>GSocketAddress</TITLE>
GSocketAddress
diff --git a/gio/Makefile.am b/gio/Makefile.am
index b715e3c..249cc7b 100644
--- a/gio/Makefile.am
+++ b/gio/Makefile.am
@@ -313,6 +313,7 @@ libgio_2_0_la_SOURCES = \
gfilteroutputstream.c \
gicon.c \
ginetaddress.c \
+ ginetaddressmask.c \
ginetsocketaddress.c \
ginitable.c \
ginputstream.c \
@@ -479,6 +480,7 @@ gio_headers = \
gfilteroutputstream.h \
gicon.h \
ginetaddress.h \
+ ginetaddressmask.h \
ginetsocketaddress.h \
ginputstream.h \
ginitable.h \
diff --git a/gio/ginetaddressmask.c b/gio/ginetaddressmask.c
new file mode 100644
index 0000000..5794a56
--- /dev/null
+++ b/gio/ginetaddressmask.c
@@ -0,0 +1,463 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright 2011 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "ginetaddressmask.h"
+#include "ginetaddress.h"
+#include "ginitable.h"
+#include "gioerror.h"
+#include "gioenumtypes.h"
+#include "glibintl.h"
+
+/**
+ * SECTION:ginetaddressmask
+ * @short_description: An IPv4/IPv6 address mask
+ *
+ * #GInetAddressMask represents a range of IPv4 or IPv6 addresses
+ * described by a base address and a length indicating how many bits
+ * of the base address are relevant for matching purposes. These are
+ * often given in string form. Eg, "10.0.0.0/8", or "fe80::/10".
+ */
+
+/**
+ * GInetAddressMask:
+ *
+ * A combination of an IPv4 or IPv6 base address and a length,
+ * representing a range of IP addresses.
+ *
+ * Since: 2.32
+ */
+
+static void g_inet_address_mask_initable_iface_init (GInitableIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GInetAddressMask, g_inet_address_mask, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
+ g_inet_address_mask_initable_iface_init));
+
+struct _GInetAddressMaskPrivate
+{
+ GInetAddress *addr;
+ guint length;
+};
+
+enum
+{
+ PROP_0,
+ PROP_FAMILY,
+ PROP_ADDRESS,
+ PROP_LENGTH
+};
+
+static void
+g_inet_address_mask_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GInetAddressMask *mask = G_INET_ADDRESS_MASK (object);
+
+ switch (prop_id)
+ {
+ case PROP_ADDRESS:
+ if (mask->priv->addr)
+ g_object_unref (mask->priv->addr);
+ mask->priv->addr = g_value_dup_object (value);
+ break;
+
+ case PROP_LENGTH:
+ mask->priv->length = g_value_get_uint (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+
+}
+
+static void
+g_inet_address_mask_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GInetAddressMask *mask = G_INET_ADDRESS_MASK (object);
+
+ switch (prop_id)
+ {
+ case PROP_FAMILY:
+ g_value_set_enum (value, g_inet_address_get_family (mask->priv->addr));
+ break;
+
+ case PROP_ADDRESS:
+ g_value_set_object (value, mask->priv->addr);
+ break;
+
+ case PROP_LENGTH:
+ g_value_set_uint (value, mask->priv->length);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+g_inet_address_mask_class_init (GInetAddressMaskClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (GInetAddressMaskPrivate));
+
+ gobject_class->set_property = g_inet_address_mask_set_property;
+ gobject_class->get_property = g_inet_address_mask_get_property;
+
+ g_object_class_install_property (gobject_class, PROP_FAMILY,
+ g_param_spec_enum ("family",
+ P_("Address family"),
+ P_("The address family (IPv4 or IPv6)"),
+ G_TYPE_SOCKET_FAMILY,
+ G_SOCKET_FAMILY_INVALID,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_ADDRESS,
+ g_param_spec_object ("address",
+ P_("Address"),
+ P_("The base address"),
+ G_TYPE_INET_ADDRESS,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_LENGTH,
+ g_param_spec_uint ("length",
+ P_("Length"),
+ P_("The prefix length"),
+ 0, 128, 0,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+}
+
+static gboolean
+g_inet_address_mask_initable_init (GInitable *initable,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GInetAddressMask *mask = G_INET_ADDRESS_MASK (initable);
+ guint addrlen, nbytes, nbits;
+ const guint8 *bytes;
+ gboolean ok;
+
+ if (!mask->priv->addr)
+ {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
+ _("No address specified"));
+ return FALSE;
+ }
+
+ addrlen = g_inet_address_get_native_size (mask->priv->addr);
+ if (mask->priv->length > addrlen * 8)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
+ _("Length %u is too long for address"),
+ mask->priv->length);
+ return FALSE;
+ }
+
+ /* Make sure all the bits after @length are 0 */
+ bytes = g_inet_address_to_bytes (mask->priv->addr);
+ ok = TRUE;
+
+ nbytes = mask->priv->length / 8;
+ bytes += nbytes;
+ addrlen -= nbytes;
+
+ nbits = mask->priv->length % 8;
+ if (nbits)
+ {
+ if (bytes[0] & (0xFF >> nbits))
+ ok = FALSE;
+ bytes++;
+ addrlen--;
+ }
+
+ while (addrlen)
+ {
+ if (bytes[0])
+ ok = FALSE;
+ bytes++;
+ addrlen--;
+ }
+
+ if (!ok)
+ {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
+ _("Address has bits set beyond prefix length"));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+g_inet_address_mask_initable_iface_init (GInitableIface *iface)
+{
+ iface->init = g_inet_address_mask_initable_init;
+}
+
+static void
+g_inet_address_mask_init (GInetAddressMask *mask)
+{
+ mask->priv = G_TYPE_INSTANCE_GET_PRIVATE (mask,
+ G_TYPE_INET_ADDRESS_MASK,
+ GInetAddressMaskPrivate);
+}
+
+/**
+ * g_inet_address_mask_new:
+ * @addr: a #GInetAddress
+ * @length: number of bits of @addr to use
+ * @error: return location for #GError, or %NULL
+ *
+ * Creates a new #GInetAddressMask representing all addresses whose
+ * first @length bits match @addr.
+ *
+ * Returns: a new #GInetAddressMask, or %NULL on error
+ *
+ * Since: 2.32
+ */
+GInetAddressMask *
+g_inet_address_mask_new (GInetAddress *addr,
+ guint length,
+ GError **error)
+{
+ return g_initable_new (G_TYPE_INET_ADDRESS_MASK, NULL, error,
+ "address", addr,
+ "length", length,
+ NULL);
+}
+
+/**
+ * g_inet_address_mask_new_from_string:
+ * @mask_string: an IP address or address/length string
+ * @error: return location for #GError, or %NULL
+ *
+ * Parses @mask_string as an IP address and (optional) length, and
+ * creates a new #GInetAddressMask. The length, if present, is
+ * delimited by a "/". If it is not present, then the length is
+ * assumed to be the full length of the address.
+ *
+ * Returns: a new #GInetAddressMask corresponding to @string, or %NULL
+ * on error.
+ *
+ * Since: 2.32
+ */
+GInetAddressMask *
+g_inet_address_mask_new_from_string (const gchar *mask_string,
+ GError **error)
+{
+ GInetAddressMask *mask;
+ GInetAddress *addr;
+ gchar *slash;
+ guint length;
+
+ slash = strchr (mask_string, '/');
+ if (slash)
+ {
+ gchar *address, *end;
+
+ length = strtoul (slash + 1, &end, 10);
+ if (*end || !*(slash + 1))
+ {
+ parse_error:
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
+ _("Could not parse '%s' as IP address mask"),
+ mask_string);
+ return NULL;
+ }
+
+ address = g_strndup (mask_string, slash - mask_string);
+ addr = g_inet_address_new_from_string (address);
+ g_free (address);
+
+ if (!addr)
+ goto parse_error;
+ }
+ else
+ {
+ addr = g_inet_address_new_from_string (mask_string);
+ if (!addr)
+ goto parse_error;
+
+ length = g_inet_address_get_native_size (addr) * 8;
+ }
+
+ mask = g_inet_address_mask_new (addr, length, error);
+ g_object_unref (addr);
+
+ return mask;
+}
+
+/**
+ * g_inet_address_mask_to_string:
+ * @mask: a #GInetAddressMask
+ *
+ * Converts @mask back to its corresponding string form.
+ *
+ * Return value: a string corresponding to @mask.
+ *
+ * Since: 2.32
+ */
+gchar *
+g_inet_address_mask_to_string (GInetAddressMask *mask)
+{
+ gchar *addr_string, *mask_string;
+
+ g_return_val_if_fail (G_IS_INET_ADDRESS_MASK (mask), NULL);
+
+ addr_string = g_inet_address_to_string (mask->priv->addr);
+
+ if (mask->priv->length == (g_inet_address_get_native_size (mask->priv->addr) * 8))
+ return addr_string;
+
+ mask_string = g_strdup_printf ("%s/%u", addr_string, mask->priv->length);
+ g_free (addr_string);
+
+ return mask_string;
+}
+
+/**
+ * g_inet_address_mask_get_family:
+ * @mask: a #GInetAddressMask
+ *
+ * Gets the #GSocketFamily of @mask's address
+ *
+ * Return value: the #GSocketFamily of @mask's address
+ *
+ * Since: 2.32
+ */
+GSocketFamily
+g_inet_address_mask_get_family (GInetAddressMask *mask)
+{
+ g_return_val_if_fail (G_IS_INET_ADDRESS_MASK (mask), G_SOCKET_FAMILY_INVALID);
+
+ return g_inet_address_get_family (mask->priv->addr);
+}
+
+/**
+ * g_inet_address_mask_get_address:
+ * @mask: a #GInetAddressMask
+ *
+ * Gets @mask's base address
+ *
+ * Return value: (transfer none): @mask's base address
+ *
+ * Since: 2.32
+ */
+GInetAddress *
+g_inet_address_mask_get_address (GInetAddressMask *mask)
+{
+ g_return_val_if_fail (G_IS_INET_ADDRESS_MASK (mask), NULL);
+
+ return mask->priv->addr;
+}
+
+/**
+ * g_inet_address_mask_get_length:
+ * @mask: a #GInetAddressMask
+ *
+ * Gets @mask's length
+ *
+ * Return value: @mask's length
+ *
+ * Since: 2.32
+ */
+guint
+g_inet_address_mask_get_length (GInetAddressMask *mask)
+{
+ g_return_val_if_fail (G_IS_INET_ADDRESS_MASK (mask), 0);
+
+ return mask->priv->length;
+}
+
+/**
+ * g_inet_address_mask_matches:
+ * @mask: a #GInetAddressMask
+ * @address: a #GInetAddress
+ *
+ * Tests if @address falls within the range described by @mask.
+ *
+ * Return value: whether @address falls within the range described by
+ * @mask.
+ *
+ * Since: 2.32
+ */
+gboolean
+g_inet_address_mask_matches (GInetAddressMask *mask,
+ GInetAddress *address)
+{
+ const guint8 *maskbytes, *addrbytes;
+ int nbytes, nbits;
+
+ g_return_val_if_fail (G_IS_INET_ADDRESS_MASK (mask), FALSE);
+ g_return_val_if_fail (G_IS_INET_ADDRESS (address), FALSE);
+
+ if (g_inet_address_get_family (mask->priv->addr) !=
+ g_inet_address_get_family (address))
+ return FALSE;
+
+ if (mask->priv->length == 0)
+ return TRUE;
+
+ maskbytes = g_inet_address_to_bytes (mask->priv->addr);
+ addrbytes = g_inet_address_to_bytes (address);
+
+ nbytes = mask->priv->length / 8;
+ if (nbytes != 0 && memcmp (maskbytes, addrbytes, nbytes) != 0)
+ return FALSE;
+
+ nbits = mask->priv->length % 8;
+ if (nbits == 0)
+ return TRUE;
+
+ return maskbytes[nbytes] == (addrbytes[nbytes] & (0xFF << (8 - nbits)));
+}
+
+
+/**
+ * g_inet_address_mask_equal:
+ * @mask: a #GInetAddressMask
+ * @mask2: another #GInetAddressMask
+ *
+ * Tests if @mask and @mask2 are the same mask.
+ *
+ * Return value: whether @mask and @mask2 are the same mask
+ *
+ * Since: 2.32
+ */
+gboolean
+g_inet_address_mask_equal (GInetAddressMask *mask,
+ GInetAddressMask *mask2)
+{
+ return ((mask->priv->length == mask2->priv->length) &&
+ g_inet_address_equal (mask->priv->addr, mask2->priv->addr));
+}
diff --git a/gio/ginetaddressmask.h b/gio/ginetaddressmask.h
new file mode 100644
index 0000000..17d00ca
--- /dev/null
+++ b/gio/ginetaddressmask.h
@@ -0,0 +1,78 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright 2011 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
+#error "Only <gio/gio.h> can be included directly."
+#endif
+
+#ifndef __G_INET_ADDRESS_MASK_H__
+#define __G_INET_ADDRESS_MASK_H__
+
+#include <gio/giotypes.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_INET_ADDRESS_MASK (g_inet_address_mask_get_type ())
+#define G_INET_ADDRESS_MASK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_INET_ADDRESS_MASK, GInetAddressMask))
+#define G_INET_ADDRESS_MASK_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_INET_ADDRESS_MASK, GInetAddressMaskClass))
+#define G_IS_INET_ADDRESS_MASK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_INET_ADDRESS_MASK))
+#define G_IS_INET_ADDRESS_MASK_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_INET_ADDRESS_MASK))
+#define G_INET_ADDRESS_MASK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_INET_ADDRESS_MASK, GInetAddressMaskClass))
+
+typedef struct _GInetAddressMaskClass GInetAddressMaskClass;
+typedef struct _GInetAddressMaskPrivate GInetAddressMaskPrivate;
+
+struct _GInetAddressMask
+{
+ GObject parent_instance;
+
+ /*< private >*/
+ GInetAddressMaskPrivate *priv;
+};
+
+struct _GInetAddressMaskClass
+{
+ GObjectClass parent_class;
+
+};
+
+GType g_inet_address_mask_get_type (void) G_GNUC_CONST;
+
+GInetAddressMask *g_inet_address_mask_new (GInetAddress *addr,
+ guint length,
+ GError **error);
+
+GInetAddressMask *g_inet_address_mask_new_from_string (const gchar *mask_string,
+ GError **error);
+gchar *g_inet_address_mask_to_string (GInetAddressMask *mask);
+
+GSocketFamily g_inet_address_mask_get_family (GInetAddressMask *mask);
+GInetAddress *g_inet_address_mask_get_address (GInetAddressMask *mask);
+guint g_inet_address_mask_get_length (GInetAddressMask *mask);
+
+gboolean g_inet_address_mask_matches (GInetAddressMask *mask,
+ GInetAddress *address);
+gboolean g_inet_address_mask_equal (GInetAddressMask *mask,
+ GInetAddressMask *mask2);
+
+G_END_DECLS
+
+#endif /* __G_INET_ADDRESS_MASK_H__ */
+
diff --git a/gio/gio.h b/gio/gio.h
index f0bc550..ab65b1b 100644
--- a/gio/gio.h
+++ b/gio/gio.h
@@ -75,6 +75,7 @@
#include <gio/gfilteroutputstream.h>
#include <gio/gicon.h>
#include <gio/ginetaddress.h>
+#include <gio/ginetaddressmask.h>
#include <gio/ginetsocketaddress.h>
#include <gio/ginitable.h>
#include <gio/ginputstream.h>
diff --git a/gio/gio.symbols b/gio/gio.symbols
index a96b827..9ac949f 100644
--- a/gio/gio.symbols
+++ b/gio/gio.symbols
@@ -827,6 +827,15 @@ g_inet_address_to_bytes
g_inet_address_get_native_size
g_inet_address_to_string
g_inet_address_equal
+g_inet_address_mask_new
+g_inet_address_mask_new_from_string
+g_inet_address_mask_to_string
+g_inet_address_mask_get_family
+g_inet_address_mask_get_address
+g_inet_address_mask_get_length
+g_inet_address_mask_get_type
+g_inet_address_mask_matches
+g_inet_address_mask_equal
g_inet_socket_address_get_address
g_inet_socket_address_get_port
g_inet_socket_address_get_type
diff --git a/gio/giotypes.h b/gio/giotypes.h
index d37bcef..6081322 100644
--- a/gio/giotypes.h
+++ b/gio/giotypes.h
@@ -96,6 +96,7 @@ typedef struct _GFilenameCompleter GFilenameCompleter;
typedef struct _GIcon GIcon; /* Dummy typedef */
typedef struct _GInetAddress GInetAddress;
+typedef struct _GInetAddressMask GInetAddressMask;
typedef struct _GInetSocketAddress GInetSocketAddress;
typedef struct _GInputStream GInputStream;
typedef struct _GInitable GInitable;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]