/** * soup_address_resolve_async: * @addr: a #SoupAddress * @async_context: (allow-none): the #GMainContext to call @callback from * @cancellable: a #GCancellable object, or %NULL * @callback: (scope async): callback to call with the result * @user_data: data for @callback * * Asynchronously resolves the missing half of @addr (its IP address * if it was created with soup_address_new(), or its hostname if it * was created with soup_address_new_from_sockaddr() or * soup_address_new_any().) * * If @cancellable is non-%NULL, it can be used to cancel the * resolution. @callback will still be invoked in this case, with a * status of %SOUP_STATUS_CANCELLED. * * It is safe to call this more than once on a given address, from the * same thread, with the same @async_context (and doing so will not * result in redundant DNS queries being made). But it is not safe to * call from multiple threads, or with different @async_contexts, or * mixed with calls to soup_address_resolve_sync(). **/ void soup_address_resolve_async (SoupAddress *addr, GMainContext *async_context, GCancellable *cancellable, SoupAddressCallback callback, gpointer user_data) { SoupAddressPrivate *priv; SoupAddressResolveAsyncData *res_data; GResolver *resolver; gboolean already_started; g_return_if_fail (SOUP_IS_ADDRESS (addr)); priv = SOUP_ADDRESS_GET_PRIVATE (addr); g_return_if_fail (priv->name || priv->sockaddr); /* We don't need to do locking here because the async case is * not intended to be thread-safe. */ if (priv->name && priv->sockaddr && !callback) return; res_data = g_slice_new0 (SoupAddressResolveAsyncData); 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; gia = soup_address_make_inet_address (addr); g_resolver_lookup_by_address_async (resolver, gia, cancellable, lookup_resolved, addr); g_object_unref (gia); } if (async_context) g_main_context_pop_thread_default (async_context); g_object_unref (resolver); }
static guint resolve_sync_internal (SoupAddress *addr, GCancellable *cancellable, GError **error) { SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (addr); GResolver *resolver; guint status; GError *my_err = NULL; resolver = g_resolver_get_default (); /* We could optimize this to avoid multiple lookups the same * way _resolve_async does, but we don't currently. So, first * lock the mutex to ensure we have a consistent view of * priv->sockaddr and priv->name, unlock it around the * 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; g_mutex_unlock (&priv->lock); addrs = g_resolver_lookup_by_name (resolver, priv->name, cancellable, &my_err); g_mutex_lock (&priv->lock); status = update_addrs (addr, addrs, my_err); g_resolver_free_addresses (addrs); } else if (!priv->name) { GInetAddress *gia; char *name; g_mutex_unlock (&priv->lock); gia = soup_address_make_inet_address (addr); name = g_resolver_lookup_by_address (resolver, gia, cancellable, &my_err); g_object_unref (gia); g_mutex_lock (&priv->lock); status = update_name (addr, name, my_err); g_free (name); } else status = SOUP_STATUS_OK; g_mutex_unlock (&priv->lock); if (my_err) g_propagate_error (error, my_err); g_object_unref (resolver); return status; }
/** * soup_address_get_physical: * @addr: a #SoupAddress * * Returns the physical address associated with @addr as a string. * (Eg, "127.0.0.1"). If the address is not yet known, returns %NULL. * * This method is not thread-safe; if you call it while @addr is being * resolved in another thread, it may return garbage. You can use * soup_address_is_resolved() to safely test whether or not an address * is resolved before fetching its name or address. * * Return value: (allow-none): the physical address, or %NULL **/ const char * soup_address_get_physical (SoupAddress *addr) { SoupAddressPrivate *priv; g_return_val_if_fail (SOUP_IS_ADDRESS (addr), NULL); priv = SOUP_ADDRESS_GET_PRIVATE (addr); if (!priv->sockaddr) return NULL; if (!priv->physical) { GInetAddress *gia; gia = soup_address_make_inet_address (addr); priv->physical = g_inet_address_to_string (gia); g_object_unref (gia); } return priv->physical; }