diff options
Diffstat (limited to 'libsoup/soup-address.c')
-rw-r--r-- | libsoup/soup-address.c | 230 |
1 files changed, 140 insertions, 90 deletions
diff --git a/libsoup/soup-address.c b/libsoup/soup-address.c index f2e698bc..b2d1647a 100644 --- a/libsoup/soup-address.c +++ b/libsoup/soup-address.c @@ -11,9 +11,11 @@ #include <string.h> +#include <gio/gnetworking.h> + #include "soup-address.h" #include "soup.h" -#include "soup-marshal.h" +#include "soup-misc-private.h" /** * SECTION:soup-address @@ -22,6 +24,10 @@ * #SoupAddress represents the address of a TCP connection endpoint: * both the IP address and the port. (It is somewhat like an * object-oriented version of struct sockaddr.) + * + * Although #SoupAddress is still used in some libsoup API's, it + * should not be used in new code; use GLib's #GNetworkAddress or + * #GSocketAddress instead. **/ enum { @@ -46,7 +52,6 @@ typedef struct { const char *protocol; GMutex lock; - GSList *async_lookups; } SoupAddressPrivate; #define SOUP_ADDRESS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_ADDRESS, SoupAddressPrivate)) @@ -555,6 +560,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) { @@ -615,55 +673,47 @@ update_name (SoupAddress *addr, const char *name, GError *error) } typedef struct { + SoupAddress *addr; SoupAddressCallback callback; gpointer callback_data; } SoupAddressResolveAsyncData; static void -complete_resolve_async (SoupAddress *addr, guint status) +complete_resolve_async (SoupAddressResolveAsyncData *res_data, guint status) { - SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (addr); - SoupAddressResolveAsyncData *res_data; - GSList *lookups, *l; GSource *current_source; GMainContext *current_context; - lookups = priv->async_lookups; - priv->async_lookups = NULL; - - /* Awful hack; to make soup_socket_connect_async() with an - * non-default async_context work correctly, we need to ensure - * that the non-default context (which we're now running in) - * is the thread-default when the callbacks are run... - */ - current_source = g_main_current_source (); - if (current_source && !g_source_is_destroyed (current_source)) - current_context = g_source_get_context (current_source); - else - current_context = NULL; - g_main_context_push_thread_default (current_context); + if (res_data->callback) { + /* Awful hack; to make soup_socket_connect_async() + * with an non-default async_context work correctly, + * we need to ensure that the non-default context + * (which we're now running in) is the thread-default + * when the callbacks are run... + */ + current_source = g_main_current_source (); + if (current_source && !g_source_is_destroyed (current_source)) + current_context = g_source_get_context (current_source); + else + current_context = NULL; + g_main_context_push_thread_default (current_context); - for (l = lookups; l; l = l->next) { - res_data = l->data; + res_data->callback (res_data->addr, status, + res_data->callback_data); - if (res_data->callback) { - res_data->callback (addr, status, - res_data->callback_data); - } - g_slice_free (SoupAddressResolveAsyncData, res_data); + g_main_context_pop_thread_default (current_context); } - g_slist_free (lookups); - g_main_context_pop_thread_default (current_context); - - g_object_unref (addr); + g_object_unref (res_data->addr); + g_slice_free (SoupAddressResolveAsyncData, res_data); } static void lookup_resolved (GObject *source, GAsyncResult *result, gpointer user_data) { GResolver *resolver = G_RESOLVER (source); - SoupAddress *addr = user_data; + SoupAddressResolveAsyncData *res_data = user_data; + SoupAddress *addr = res_data->addr; SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (addr); GError *error = NULL; guint status; @@ -689,7 +739,7 @@ lookup_resolved (GObject *source, GAsyncResult *result, gpointer user_data) g_object_ref (addr); g_object_set_data (G_OBJECT (addr), "async-resolved-error", error); - complete_resolve_async (addr, status); + complete_resolve_async (res_data, status); g_object_set_data (G_OBJECT (addr), "async-resolved-error", NULL); g_object_unref (addr); @@ -698,9 +748,9 @@ lookup_resolved (GObject *source, GAsyncResult *result, gpointer user_data) } static gboolean -idle_complete_resolve (gpointer addr) +idle_complete_resolve (gpointer res_data) { - complete_resolve_async (addr, SOUP_STATUS_OK); + complete_resolve_async (res_data, SOUP_STATUS_OK); return FALSE; } @@ -746,7 +796,6 @@ soup_address_resolve_async (SoupAddress *addr, GMainContext *async_context, SoupAddressPrivate *priv; SoupAddressResolveAsyncData *res_data; GResolver *resolver; - gboolean already_started; g_return_if_fail (SOUP_IS_ADDRESS (addr)); priv = SOUP_ADDRESS_GET_PRIVATE (addr); @@ -756,47 +805,43 @@ 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; res_data = g_slice_new0 (SoupAddressResolveAsyncData); + res_data->addr = g_object_ref (addr); res_data->callback = callback; res_data->callback_data = user_data; - already_started = priv->async_lookups != NULL; - priv->async_lookups = g_slist_prepend (priv->async_lookups, res_data); - - if (already_started) - return; - - g_object_ref (addr); - - if (priv->name && priv->sockaddr) { - soup_add_completion (async_context, idle_complete_resolve, addr); - return; - } - - resolver = g_resolver_get_default (); if (async_context) g_main_context_push_thread_default (async_context); - if (priv->name) { - g_resolver_lookup_by_name_async (resolver, priv->name, - cancellable, - lookup_resolved, addr); - } else { - GInetAddress *gia; + if (priv->name && priv->sockaddr) + soup_add_completion (async_context, idle_complete_resolve, res_data); + else { + resolver = g_resolver_get_default (); + + if (priv->name) { + g_resolver_lookup_by_name_async (resolver, priv->name, + cancellable, + lookup_resolved, res_data); + } else { + GInetAddress *gia; + + gia = soup_address_make_inet_address (addr); + g_resolver_lookup_by_address_async (resolver, gia, + cancellable, + lookup_resolved, res_data); + g_object_unref (gia); + } - gia = soup_address_make_inet_address (addr); - g_resolver_lookup_by_address_async (resolver, gia, - cancellable, - lookup_resolved, addr); - g_object_unref (gia); + g_object_unref (resolver); } if (async_context) g_main_context_pop_thread_default (async_context); - g_object_unref (resolver); } static guint @@ -816,6 +861,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; @@ -841,6 +890,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) @@ -1111,15 +1161,19 @@ soup_address_address_enumerator_next (GSocketAddressEnumerator *enumerator, static void got_addresses (SoupAddress *addr, guint status, gpointer user_data) { - GSimpleAsyncResult *simple = user_data; + GTask *task = user_data; GError *error; error = g_object_get_data (G_OBJECT (addr), "async-resolved-error"); if (error) - g_simple_async_result_set_from_error (simple, error); + g_task_return_error (task, g_error_copy (error)); + else { + GSocketAddress *addr; - g_simple_async_result_complete (simple); - g_object_unref (simple); + addr = next_address (g_task_get_source_object (task)); + g_task_return_pointer (task, addr, g_object_unref); + } + g_object_unref (task); } static void @@ -1131,18 +1185,16 @@ soup_address_address_enumerator_next_async (GSocketAddressEnumerator *enumerato SoupAddressAddressEnumerator *addr_enum = SOUP_ADDRESS_ADDRESS_ENUMERATOR (enumerator); SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (addr_enum->addr); - GSimpleAsyncResult *simple; - - simple = g_simple_async_result_new (G_OBJECT (enumerator), - callback, user_data, - soup_address_address_enumerator_next_async); + GTask *task; + task = g_task_new (enumerator, cancellable, callback, user_data); if (!priv->sockaddr) { - soup_address_resolve_async (addr_enum->addr, NULL, cancellable, - got_addresses, simple); + soup_address_resolve_async (addr_enum->addr, + g_main_context_get_thread_default (), + cancellable, got_addresses, task); } else { - g_simple_async_result_complete_in_idle (simple); - g_object_unref (simple); + g_task_return_pointer (task, next_address (addr_enum), g_object_unref); + g_object_unref (task); } } @@ -1151,14 +1203,7 @@ soup_address_address_enumerator_next_finish (GSocketAddressEnumerator *enumerat GAsyncResult *result, GError **error) { - SoupAddressAddressEnumerator *addr_enum = - SOUP_ADDRESS_ADDRESS_ENUMERATOR (enumerator); - GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result); - - if (g_simple_async_result_propagate_error (simple, error)) - return NULL; - else - return next_address (addr_enum); + return g_task_propagate_pointer (G_TASK (result), error); } static void @@ -1200,20 +1245,25 @@ soup_address_connectable_proxy_enumerate (GSocketConnectable *connectable) SoupAddress *addr = SOUP_ADDRESS (connectable); SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (addr); GSocketAddressEnumerator *proxy_enum; - char *uri; + SoupURI *uri; + char *uri_string; /* We cheerily assume "http" here because you shouldn't be * using SoupAddress any more if you're not doing HTTP anyway. */ - uri = g_strdup_printf ("%s://%s:%u", - priv->protocol ? priv->protocol : "http", - priv->name ? priv->name : soup_address_get_physical (addr), - priv->port); + uri = soup_uri_new (NULL); + soup_uri_set_scheme (uri, priv->protocol ? priv->protocol : "http"); + soup_uri_set_host (uri, priv->name ? priv->name : soup_address_get_physical (addr)); + soup_uri_set_port (uri, priv->port); + soup_uri_set_path (uri, ""); + uri_string = soup_uri_to_string_internal (uri, FALSE, TRUE); + proxy_enum = g_object_new (G_TYPE_PROXY_ADDRESS_ENUMERATOR, "connectable", connectable, - "uri", uri, + "uri", uri_string, NULL); - g_free (uri); + g_free (uri_string); + soup_uri_free (uri); return proxy_enum; } |