GInetSocketAddress: add IPv6 flowinfo and scope_id fields
authorDan Winship <danw@gnome.org>
Thu, 29 Dec 2011 14:42:25 +0000 (09:42 -0500)
committerDan Winship <danw@gnome.org>
Mon, 16 Jan 2012 18:37:02 +0000 (13:37 -0500)
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
gio/ginetsocketaddress.c
gio/ginetsocketaddress.h
gio/gio.symbols
gio/gsocketaddress.c
gio/tests/socket.c

index 96b8b321b082e4bf9ab98127851996bb6ce1ce82..5f50e24acdfa960d4534194156c90131ce86e178 100644 (file)
@@ -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
 <SUBSECTION Standard>
 GInetSocketAddressClass
 GInetSocketAddressPrivate
index 071c49ff3432f1f18664f6e53e7b0a8d285ae4ef..490c311b886e0dedbf12616dd514945c7b65a82b 100644 (file)
@@ -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 <literal>sin6_flowinfo</literal> 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 <literal>sin6_scope_id</literal> 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 <literal>sin6_flowinfo</literal> 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 <literal>sin6_scope_id</literal> 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;
+}
index b455ac57d026d7e4c604b5065fb3f1c4d63204aa..94caec8b548c1251ae37e67d043329c59686c6a9 100644 (file)
@@ -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
 
index 94391d55271f4c3aa7e00d799ac1f0712f77610e..8e62cf28b87b0392aa1dc15091f996b9f6c8ae26 100644 (file)
@@ -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
index 477f7203b2477570c486a7b13f94c8e0b3f89abb..83414fc89ab92dbb2a1a81b4b07ffd1092b8f099 100644 (file)
@@ -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;
     }
index d2919b86ca268d9feebb5f7695bcb4bca14a51ae..bdd445aaf6998589e0f7fa14ec1d5ac7173f66ea 100644 (file)
@@ -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);