From bf7408c30bac5b0a20202be5aaa850dd0ca1e671 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Thu, 29 Dec 2011 09:42:25 -0500 Subject: [PATCH] GInetSocketAddress: add IPv6 flowinfo and scope_id fields struct sin6_addr has two additional fields that struct sin_addr doesn't. Add support for those to GInetSocketAddress, and make sure they don't get lost when converting between glib and native types. https://bugzilla.gnome.org/show_bug.cgi?id=635554 --- docs/reference/gio/gio-sections.txt | 2 + gio/ginetsocketaddress.c | 109 ++++++++++++++++++++++++++++++++++-- gio/ginetsocketaddress.h | 12 ++-- gio/gio.symbols | 2 + gio/gsocketaddress.c | 7 ++- gio/tests/socket.c | 40 +++++++++++++ 6 files changed, 162 insertions(+), 10 deletions(-) diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt index 96b8b32..5f50e24 100644 --- a/docs/reference/gio/gio-sections.txt +++ b/docs/reference/gio/gio-sections.txt @@ -1594,6 +1594,8 @@ GInetSocketAddress g_inet_socket_address_new g_inet_socket_address_get_address g_inet_socket_address_get_port +g_inet_socket_address_get_flowinfo +g_inet_socket_address_get_scope_id GInetSocketAddressClass GInetSocketAddressPrivate diff --git a/gio/ginetsocketaddress.c b/gio/ginetsocketaddress.c index 071c49f..490c311 100644 --- a/gio/ginetsocketaddress.c +++ b/gio/ginetsocketaddress.c @@ -51,13 +51,17 @@ G_DEFINE_TYPE (GInetSocketAddress, g_inet_socket_address, G_TYPE_SOCKET_ADDRESS) enum { PROP_0, PROP_ADDRESS, - PROP_PORT + PROP_PORT, + PROP_FLOWINFO, + PROP_SCOPE_ID }; struct _GInetSocketAddressPrivate { GInetAddress *address; guint16 port; + guint32 flowinfo; + guint32 scope_id; }; static void @@ -98,6 +102,16 @@ g_inet_socket_address_get_property (GObject *object, g_value_set_uint (value, address->priv->port); break; + case PROP_FLOWINFO: + g_return_if_fail (g_inet_address_get_family (address->priv->address) == G_SOCKET_FAMILY_IPV6); + g_value_set_uint (value, address->priv->flowinfo); + break; + + case PROP_SCOPE_ID: + g_return_if_fail (g_inet_address_get_family (address->priv->address) == G_SOCKET_FAMILY_IPV6); + g_value_set_uint (value, address->priv->scope_id); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -121,6 +135,17 @@ g_inet_socket_address_set_property (GObject *object, address->priv->port = (guint16) g_value_get_uint (value); break; + case PROP_FLOWINFO: + /* We can't test that address->priv->address is IPv6 here, + * since this property might get set before PROP_ADDRESS. + */ + address->priv->flowinfo = g_value_get_uint (value); + break; + + case PROP_SCOPE_ID: + address->priv->scope_id = g_value_get_uint (value); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -202,6 +227,8 @@ g_inet_socket_address_to_native (GSocketAddress *address, memset (sock, 0, sizeof (*sock)); sock->sin6_family = AF_INET6; sock->sin6_port = g_htons (addr->priv->port); + sock->sin6_flowinfo = g_htonl (addr->priv->flowinfo); + sock->sin6_scope_id = g_htonl (addr->priv->scope_id); memcpy (&(sock->sin6_addr.s6_addr), g_inet_address_to_bytes (addr->priv->address), sizeof (sock->sin6_addr)); return TRUE; } @@ -249,6 +276,42 @@ g_inet_socket_address_class_init (GInetSocketAddressClass *klass) G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GInetSocketAddress:flowinfo: + * + * The sin6_flowinfo field, for IPv6 addresses. + * + * Since: 2.32 + */ + g_object_class_install_property (gobject_class, PROP_FLOWINFO, + g_param_spec_uint ("flowinfo", + P_("Flow info"), + P_("IPv6 flow info"), + 0, + G_MAXUINT32, + 0, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * GInetSocketAddress:scope_id: + * + * The sin6_scope_id field, for IPv6 addresses. + * + * Since: 2.32 + */ + g_object_class_install_property (gobject_class, PROP_SCOPE_ID, + g_param_spec_uint ("scope-id", + P_("Scope ID"), + P_("IPv6 scope ID"), + 0, + G_MAXUINT32, + 0, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); } static void @@ -257,9 +320,6 @@ g_inet_socket_address_init (GInetSocketAddress *address) address->priv = G_TYPE_INSTANCE_GET_PRIVATE (address, G_TYPE_INET_SOCKET_ADDRESS, GInetSocketAddressPrivate); - - address->priv->address = NULL; - address->priv->port = 0; } /** @@ -319,3 +379,44 @@ g_inet_socket_address_get_port (GInetSocketAddress *address) return address->priv->port; } + + +/** + * g_inet_socket_address_get_flowinfo: + * @address: a %G_SOCKET_FAMILY_IPV6 #GInetSocketAddress + * + * Gets the sin6_flowinfo field from @address, + * which must be an IPv6 address. + * + * Return value: the flowinfo field + * + * Since: 2.32 + */ +guint32 +g_inet_socket_address_get_flowinfo (GInetSocketAddress *address) +{ + g_return_val_if_fail (G_IS_INET_SOCKET_ADDRESS (address), 0); + g_return_val_if_fail (g_inet_address_get_family (address->priv->address) == G_SOCKET_FAMILY_IPV6, 0); + + return address->priv->flowinfo; +} + +/** + * g_inet_address_get_scope_id: + * @address: a %G_SOCKET_FAMILY_IPV6 #GInetAddress + * + * Gets the sin6_scope_id field from @address, + * which must be an IPv6 address. + * + * Return value: the scope id field + * + * Since: 2.32 + */ +guint32 +g_inet_socket_address_get_scope_id (GInetSocketAddress *address) +{ + g_return_val_if_fail (G_IS_INET_SOCKET_ADDRESS (address), 0); + g_return_val_if_fail (g_inet_address_get_family (address->priv->address) == G_SOCKET_FAMILY_IPV6, 0); + + return address->priv->scope_id; +} diff --git a/gio/ginetsocketaddress.h b/gio/ginetsocketaddress.h index b455ac5..94caec8 100644 --- a/gio/ginetsocketaddress.h +++ b/gio/ginetsocketaddress.h @@ -55,14 +55,16 @@ struct _GInetSocketAddressClass GSocketAddressClass parent_class; }; -GType g_inet_socket_address_get_type (void) G_GNUC_CONST; +GType g_inet_socket_address_get_type (void) G_GNUC_CONST; -GSocketAddress *g_inet_socket_address_new (GInetAddress *address, - guint16 port); +GSocketAddress *g_inet_socket_address_new (GInetAddress *address, + guint16 port); -GInetAddress * g_inet_socket_address_get_address (GInetSocketAddress *address); +GInetAddress * g_inet_socket_address_get_address (GInetSocketAddress *address); +guint16 g_inet_socket_address_get_port (GInetSocketAddress *address); -guint16 g_inet_socket_address_get_port (GInetSocketAddress *address); +guint32 g_inet_socket_address_get_flowinfo (GInetSocketAddress *address); +guint32 g_inet_socket_address_get_scope_id (GInetSocketAddress *address); G_END_DECLS diff --git a/gio/gio.symbols b/gio/gio.symbols index 94391d5..8e62cf2 100644 --- a/gio/gio.symbols +++ b/gio/gio.symbols @@ -842,7 +842,9 @@ 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_flowinfo g_inet_socket_address_get_port +g_inet_socket_address_get_scope_id g_inet_socket_address_get_type g_inet_socket_address_new #ifdef G_OS_UNIX diff --git a/gio/gsocketaddress.c b/gio/gsocketaddress.c index 477f720..83414fc 100644 --- a/gio/gsocketaddress.c +++ b/gio/gsocketaddress.c @@ -256,7 +256,12 @@ g_socket_address_new_from_native (gpointer native, iaddr = g_inet_address_new_from_bytes ((guint8 *) &(addr->sin6_addr), AF_INET6); } - sockaddr = g_inet_socket_address_new (iaddr, g_ntohs (addr->sin6_port)); + sockaddr = g_object_new (G_TYPE_INET_SOCKET_ADDRESS, + "address", iaddr, + "port", g_ntohs (addr->sin6_port), + "flowinfo", g_ntohl (addr->sin6_flowinfo), + "scope_id", g_ntohl (addr->sin6_scope_id), + NULL); g_object_unref (iaddr); return sockaddr; } diff --git a/gio/tests/socket.c b/gio/tests/socket.c index d2919b8..bdd445a 100644 --- a/gio/tests/socket.c +++ b/gio/tests/socket.c @@ -499,6 +499,45 @@ test_ipv6_v4mapped (void) } #endif +static void +test_sockaddr (void) +{ + struct sockaddr_in6 sin6, gsin6; + GSocketAddress *saddr; + GInetSocketAddress *isaddr; + GInetAddress *iaddr; + GError *error = NULL; + + memset (&sin6, 0, sizeof (sin6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_addr = in6addr_loopback; + sin6.sin6_port = g_htons (42); + sin6.sin6_scope_id = g_htonl (17); + sin6.sin6_flowinfo = g_htonl (1729); + + saddr = g_socket_address_new_from_native (&sin6, sizeof (sin6)); + g_assert (G_IS_INET_SOCKET_ADDRESS (saddr)); + + isaddr = G_INET_SOCKET_ADDRESS (saddr); + iaddr = g_inet_socket_address_get_address (isaddr); + g_assert_cmpint (g_inet_address_get_family (iaddr), ==, G_SOCKET_FAMILY_IPV6); + g_assert (g_inet_address_get_is_loopback (iaddr)); + + g_assert_cmpint (g_inet_socket_address_get_port (isaddr), ==, 42); + g_assert_cmpint (g_inet_socket_address_get_scope_id (isaddr), ==, 17); + g_assert_cmpint (g_inet_socket_address_get_flowinfo (isaddr), ==, 1729); + + g_socket_address_to_native (saddr, &gsin6, sizeof (gsin6), &error); + g_assert_no_error (error); + + g_assert (memcmp (&sin6.sin6_addr, &gsin6.sin6_addr, sizeof (struct in6_addr)) == 0); + g_assert_cmpint (sin6.sin6_port, ==, gsin6.sin6_port); + g_assert_cmpint (sin6.sin6_scope_id, ==, gsin6.sin6_scope_id); + g_assert_cmpint (sin6.sin6_flowinfo, ==, gsin6.sin6_flowinfo); + + g_object_unref (saddr); +} + #ifdef G_OS_UNIX static void test_unix_from_fd (void) @@ -654,6 +693,7 @@ main (int argc, #if defined (IPPROTO_IPV6) && defined (IPV6_V6ONLY) g_test_add_func ("/socket/ipv6_v4mapped", test_ipv6_v4mapped); #endif + g_test_add_func ("/socket/address", test_sockaddr); #ifdef G_OS_UNIX g_test_add_func ("/socket/unix-from-fd", test_unix_from_fd); g_test_add_func ("/socket/unix-connection", test_unix_connection); -- 2.7.4