Esempio n. 1
0
/**
 * 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);
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
/**
 * 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;
}