summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Winship <danw@gnome.org>2013-08-19 13:26:19 -0400
committerDan Winship <danw@gnome.org>2013-08-19 13:26:19 -0400
commitfbc47c33a98e5b3ff4d38daab348d70c7aafa042 (patch)
treecf4855f6d10197128789121d83aff876475ef1ad
parente3705dc057a0deb80a58f93351f145c267349c4d (diff)
downloadlibsoup-fbc47c33a98e5b3ff4d38daab348d70c7aafa042.tar.gz
soup-address: handle IPv6 literals with scope IDs
Use GNetworkAddress to try to parse IPv6 addresses with scope IDs, rather than just letting the scope ID get dropped. Part of https://bugzilla.gnome.org/show_bug.cgi?id=669724
-rw-r--r--libsoup/soup-address.c60
1 files changed, 60 insertions, 0 deletions
diff --git a/libsoup/soup-address.c b/libsoup/soup-address.c
index e2a06912..d698234e 100644
--- a/libsoup/soup-address.c
+++ b/libsoup/soup-address.c
@@ -561,6 +561,59 @@ soup_address_get_port (SoupAddress *addr)
}
+/* Tries to resolve priv->name as an IP address, possibly including an
+ * IPv6 scope id.
+ */
+static void
+maybe_resolve_ip (SoupAddress *addr)
+{
+ SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (addr);
+ const char *pct, *ip;
+ char *tmp = NULL;
+ GSocketConnectable *gaddr;
+ GSocketAddressEnumerator *sa_enum;
+ GSocketAddress *saddr;
+
+ if (priv->sockaddr || !priv->name)
+ return;
+
+ pct = strchr (priv->name, '%');
+ if (pct)
+ ip = tmp = g_strndup (priv->name, pct - priv->name);
+ else
+ ip = priv->name;
+
+ if (!g_hostname_is_ip_address (ip)) {
+ g_free (tmp);
+ return;
+ }
+ g_free (tmp);
+
+ gaddr = g_network_address_new (priv->name, priv->port);
+ if (!gaddr)
+ return;
+
+ sa_enum = g_socket_connectable_enumerate (gaddr);
+ saddr = g_socket_address_enumerator_next (sa_enum, NULL, NULL);
+ if (saddr) {
+ priv->n_addrs = 1;
+ priv->sockaddr = g_new (struct sockaddr_storage, 1);
+ if (!g_socket_address_to_native (saddr, priv->sockaddr,
+ sizeof (struct sockaddr_storage),
+ NULL)) {
+ /* can't happen: We know the address format is supported
+ * and the buffer is large enough
+ */
+ g_warn_if_reached ();
+ }
+ g_object_unref (saddr);
+ }
+
+ g_object_unref (sa_enum);
+ g_object_unref (gaddr);
+}
+
+
static guint
update_addrs (SoupAddress *addr, GList *addrs, GError *error)
{
@@ -762,6 +815,8 @@ soup_address_resolve_async (SoupAddress *addr, GMainContext *async_context,
* not intended to be thread-safe.
*/
+ if (priv->name && !priv->sockaddr)
+ maybe_resolve_ip (addr);
if (priv->name && priv->sockaddr && !callback)
return;
@@ -822,6 +877,10 @@ resolve_sync_internal (SoupAddress *addr, GCancellable *cancellable, GError **er
* blocking op, and then re-lock it to modify @addr.
*/
g_mutex_lock (&priv->lock);
+
+ if (priv->name && !priv->sockaddr)
+ maybe_resolve_ip (addr);
+
if (!priv->sockaddr) {
GList *addrs;
@@ -847,6 +906,7 @@ resolve_sync_internal (SoupAddress *addr, GCancellable *cancellable, GError **er
g_free (name);
} else
status = SOUP_STATUS_OK;
+
g_mutex_unlock (&priv->lock);
if (my_err)