[glib] gnetworkaddress: preserve IPv6 scope ID in IP literals
- From: Dan Winship <danw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib] gnetworkaddress: preserve IPv6 scope ID in IP literals
- Date: Fri, 15 Feb 2013 14:15:28 +0000 (UTC)
commit 8a77f7bb181f3341a6866cd0e64779c35b3a3f61
Author: Dan Winship <danw gnome org>
Date: Wed Dec 12 16:12:09 2012 +0100
gnetworkaddress: preserve IPv6 scope ID in IP literals
If a GNetworkAddress is created with a hostname like "fe80::xxx%em1",
make sure that the scope_id corresponding to "em1" is present in the
GSocketAddresses it returns when used as a GSocketConnectable.
https://bugzilla.gnome.org/show_bug.cgi?id=684404
gio/gnetworkaddress.c | 88 ++++++++++++++++++++++++++++++++-------------
gio/tests/inet-address.c | 38 ++++++++++++++++++++
2 files changed, 100 insertions(+), 26 deletions(-)
---
diff --git a/gio/gnetworkaddress.c b/gio/gnetworkaddress.c
index b67a86d..44c39f1 100644
--- a/gio/gnetworkaddress.c
+++ b/gio/gnetworkaddress.c
@@ -243,6 +243,29 @@ g_network_address_set_addresses (GNetworkAddress *addr,
addr->priv->sockaddrs = g_list_reverse (addr->priv->sockaddrs);
}
+static gboolean
+g_network_address_parse_sockaddr (GNetworkAddress *addr)
+{
+ struct addrinfo hints, *res = NULL;
+ GSocketAddress *sockaddr;
+ gchar port[32];
+
+ memset (&hints, 0, sizeof (hints));
+ hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
+ g_snprintf (port, sizeof (port), "%u", addr->priv->port);
+
+ if (getaddrinfo (addr->priv->hostname, port, &hints, &res) != 0)
+ return FALSE;
+
+ sockaddr = g_socket_address_new_from_native (res->ai_addr, res->ai_addrlen);
+ freeaddrinfo (res);
+ if (!sockaddr || !G_IS_INET_SOCKET_ADDRESS (sockaddr))
+ return FALSE;
+
+ addr->priv->sockaddrs = g_list_prepend (addr->priv->sockaddrs, sockaddr);
+ return TRUE;
+}
+
/**
* g_network_address_new:
* @hostname: the hostname
@@ -820,6 +843,8 @@ g_network_address_address_enumerator_next (GSocketAddressEnumerator *enumerator
if (addr_enum->addresses == NULL)
{
if (!addr_enum->addr->priv->sockaddrs)
+ g_network_address_parse_sockaddr (addr_enum->addr);
+ if (!addr_enum->addr->priv->sockaddrs)
{
GResolver *resolver = g_resolver_get_default ();
GList *addresses;
@@ -848,29 +873,11 @@ g_network_address_address_enumerator_next (GSocketAddressEnumerator *enumerator
}
static void
-got_addresses (GObject *source_object,
- GAsyncResult *result,
- gpointer user_data)
+have_addresses (GNetworkAddressAddressEnumerator *addr_enum,
+ GTask *task, GError *error)
{
- GTask *task = user_data;
- GNetworkAddressAddressEnumerator *addr_enum = g_task_get_source_object (task);
- GResolver *resolver = G_RESOLVER (source_object);
- GList *addresses;
- GError *error = NULL;
GSocketAddress *sockaddr;
- if (!addr_enum->addr->priv->sockaddrs)
- {
- addresses = g_resolver_lookup_by_name_finish (resolver, result, &error);
-
- if (error)
- g_task_return_error (task, error);
- else
- g_network_address_set_addresses (addr_enum->addr, addresses);
- }
-
- g_object_unref (resolver);
-
addr_enum->addresses = addr_enum->addr->priv->sockaddrs;
addr_enum->next = addr_enum->addresses;
@@ -882,12 +889,35 @@ got_addresses (GObject *source_object,
else
sockaddr = NULL;
- if (!error)
+ if (error)
+ g_task_return_error (task, error);
+ else
g_task_return_pointer (task, sockaddr, g_object_unref);
g_object_unref (task);
}
static void
+got_addresses (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GTask *task = user_data;
+ GNetworkAddressAddressEnumerator *addr_enum = g_task_get_source_object (task);
+ GResolver *resolver = G_RESOLVER (source_object);
+ GList *addresses;
+ GError *error = NULL;
+
+ if (!addr_enum->addr->priv->sockaddrs)
+ {
+ addresses = g_resolver_lookup_by_name_finish (resolver, result, &error);
+
+ if (!error)
+ g_network_address_set_addresses (addr_enum->addr, addresses);
+ }
+ have_addresses (addr_enum, task, error);
+}
+
+static void
g_network_address_address_enumerator_next_async (GSocketAddressEnumerator *enumerator,
GCancellable *cancellable,
GAsyncReadyCallback callback,
@@ -904,12 +934,18 @@ g_network_address_address_enumerator_next_async (GSocketAddressEnumerator *enum
{
if (!addr_enum->addr->priv->sockaddrs)
{
- GResolver *resolver = g_resolver_get_default ();
+ if (g_network_address_parse_sockaddr (addr_enum->addr))
+ have_addresses (addr_enum, task, NULL);
+ else
+ {
+ GResolver *resolver = g_resolver_get_default ();
- g_resolver_lookup_by_name_async (resolver,
- addr_enum->addr->priv->hostname,
- cancellable,
- got_addresses, task);
+ g_resolver_lookup_by_name_async (resolver,
+ addr_enum->addr->priv->hostname,
+ cancellable,
+ got_addresses, task);
+ g_object_unref (resolver);
+ }
return;
}
diff --git a/gio/tests/inet-address.c b/gio/tests/inet-address.c
index 566078b..0e82b06 100644
--- a/gio/tests/inet-address.c
+++ b/gio/tests/inet-address.c
@@ -223,6 +223,43 @@ test_socket_address (void)
}
static void
+test_scope_id (void)
+{
+ GSocketConnectable *addr;
+ GSocketAddressEnumerator *addr_enum;
+ GSocketAddress *saddr;
+ GInetSocketAddress *isaddr;
+ GInetAddress *iaddr;
+ char *tostring;
+ GError *error = NULL;
+
+ addr = g_network_address_new ("fe80::42%1", 99);
+ addr_enum = g_socket_connectable_enumerate (addr);
+ saddr = g_socket_address_enumerator_next (addr_enum, NULL, &error);
+ g_assert_no_error (error);
+
+ g_assert (saddr != NULL);
+ g_assert (G_IS_INET_SOCKET_ADDRESS (saddr));
+
+ isaddr = G_INET_SOCKET_ADDRESS (saddr);
+ g_assert_cmpint (g_inet_socket_address_get_scope_id (isaddr), ==, 1);
+ g_assert_cmpint (g_inet_socket_address_get_port (isaddr), ==, 99);
+
+ iaddr = g_inet_socket_address_get_address (isaddr);
+ tostring = g_inet_address_to_string (iaddr);
+ g_assert_cmpstr (tostring, ==, "fe80::42");
+ g_free (tostring);
+
+ g_object_unref (saddr);
+ saddr = g_socket_address_enumerator_next (addr_enum, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (saddr == NULL);
+
+ g_object_unref (addr_enum);
+ g_object_unref (addr);
+}
+
+static void
test_mask_parse (void)
{
GInetAddressMask *mask;
@@ -355,6 +392,7 @@ main (int argc, char *argv[])
g_test_add_func ("/inet-address/bytes", test_bytes);
g_test_add_func ("/inet-address/property", test_property);
g_test_add_func ("/socket-address/basic", test_socket_address);
+ g_test_add_func ("/socket-address/scope-id", test_scope_id);
g_test_add_func ("/address-mask/parse", test_mask_parse);
g_test_add_func ("/address-mask/property", test_mask_property);
g_test_add_func ("/address-mask/equal", test_mask_equal);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]