/** * soup_address_equal_by_name: * @addr1: (type Soup.Address): a #SoupAddress with a resolved name * @addr2: (type Soup.Address): another #SoupAddress with a resolved * name * * Tests if @addr1 and @addr2 have the same "name". This method can be * used with soup_address_hash_by_name() to create a #GHashTable that * hashes on address "names". * * Comparing by name normally means comparing the addresses by their * hostnames. But if the address was originally created using an IP * address literal, then it will be compared by that instead. * * In particular, if "www.example.com" has the IP address 10.0.0.1, * and @addr1 was created with the name "www.example.com" and @addr2 * was created with the name "10.0.0.1", then they will compare as * unequal for purposes of soup_address_equal_by_name(). * * This would be used to distinguish hosts in situations where * different virtual hosts on the same IP address should be considered * different. Eg, for purposes of HTTP authentication or cookies, two * hosts with the same IP address but different names are considered * to be different hosts. * * See also soup_address_equal_by_ip(), which compares by IP address * rather than by name. * * Return value: whether or not @addr1 and @addr2 have the same name * * Since: 2.26 **/ gboolean soup_address_equal_by_name (gconstpointer addr1, gconstpointer addr2) { SoupAddressPrivate *priv1 = SOUP_ADDRESS_GET_PRIVATE (addr1); SoupAddressPrivate *priv2 = SOUP_ADDRESS_GET_PRIVATE (addr2); g_return_val_if_fail (priv1->name != NULL, FALSE); g_return_val_if_fail (priv2->name != NULL, FALSE); return !g_ascii_strcasecmp (priv1->name, priv2->name); }
/** * soup_address_equal_by_ip: * @addr1: (type Soup.Address): a #SoupAddress with a resolved IP * address * @addr2: (type Soup.Address): another #SoupAddress with a resolved * IP address * * Tests if @addr1 and @addr2 have the same IP address. This method * can be used with soup_address_hash_by_ip() to create a * #GHashTable that hashes on IP address. * * This would be used to distinguish hosts in situations where * different virtual hosts on the same IP address should be considered * the same. Eg, if "www.example.com" and "www.example.net" have the * same IP address, then a single connection can be used to talk * to either of them. * * See also soup_address_equal_by_name(), which compares by name * rather than by IP address. * * Return value: whether or not @addr1 and @addr2 have the same IP * address. * * Since: 2.26 **/ gboolean soup_address_equal_by_ip (gconstpointer addr1, gconstpointer addr2) { SoupAddressPrivate *priv1 = SOUP_ADDRESS_GET_PRIVATE (addr1); SoupAddressPrivate *priv2 = SOUP_ADDRESS_GET_PRIVATE (addr2); int size; g_return_val_if_fail (priv1->sockaddr != NULL, FALSE); g_return_val_if_fail (priv2->sockaddr != NULL, FALSE); size = SOUP_ADDRESS_FAMILY_SOCKADDR_SIZE (priv1->sockaddr->ss_family); return (priv1->sockaddr->ss_family == priv2->sockaddr->ss_family && !memcmp (priv1->sockaddr, priv2->sockaddr, size)); }
/** * soup_address_get_name: * @addr: a #SoupAddress * * Returns the hostname associated with @addr. * * 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 hostname, or %NULL if it is not known. **/ const char * soup_address_get_name (SoupAddress *addr) { g_return_val_if_fail (SOUP_IS_ADDRESS (addr), NULL); return SOUP_ADDRESS_GET_PRIVATE (addr)->name; }
static void soup_address_init (SoupAddress *addr) { SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (addr); g_mutex_init (&priv->lock); }
/** * 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); }
/** * soup_address_get_port: * @addr: a #SoupAddress * * Returns the port associated with @addr. * * Return value: the port **/ guint soup_address_get_port (SoupAddress *addr) { g_return_val_if_fail (SOUP_IS_ADDRESS (addr), 0); return SOUP_ADDRESS_GET_PRIVATE (addr)->port; }
static GSocketAddressEnumerator * soup_address_connectable_proxy_enumerate (GSocketConnectable *connectable) { SoupAddress *addr = SOUP_ADDRESS (connectable); SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (addr); GSocketAddressEnumerator *proxy_enum; 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 = 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_string, NULL); g_free (uri_string); soup_uri_free (uri); return proxy_enum; }
static void soup_address_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (object); switch (prop_id) { case PROP_NAME: g_value_set_string (value, priv->name); break; case PROP_FAMILY: if (priv->sockaddr) g_value_set_enum (value, SOUP_ADDRESS_GET_FAMILY (priv)); else g_value_set_enum (value, 0); break; case PROP_PORT: g_value_set_int (value, priv->port); break; case PROP_PHYSICAL: g_value_set_string (value, soup_address_get_physical (SOUP_ADDRESS (object))); break; case PROP_PROTOCOL: g_value_set_string (value, priv->protocol); break; case PROP_SOCKADDR: g_value_set_pointer (value, priv->sockaddr); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
/** * soup_address_hash_by_name: * @addr: (type Soup.Address): a #SoupAddress * * A hash function (for #GHashTable) that corresponds to * soup_address_equal_by_name(), qv * * Return value: the named-based hash value for @addr. * * Since: 2.26 **/ guint soup_address_hash_by_name (gconstpointer addr) { SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (addr); g_return_val_if_fail (priv->name != NULL, 0); return g_str_hash (priv->name); }
/** * soup_address_get_gsockaddr: * @addr: a #SoupAddress * * Creates a new #GSocketAddress corresponding to @addr (which is assumed * to only have one socket address associated with it). * * Return value: (transfer full): a new #GSocketAddress * * Since: 2.32 */ GSocketAddress * soup_address_get_gsockaddr (SoupAddress *addr) { SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (addr); return g_socket_address_new_from_native (priv->sockaddr, SOUP_ADDRESS_FAMILY_SOCKADDR_SIZE (SOUP_ADDRESS_GET_FAMILY (priv))); }
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_resolve_sync: * @addr: a #SoupAddress * @cancellable: a #GCancellable object, or %NULL * * Synchronously resolves the missing half of @addr, as with * soup_address_resolve_async(). * * If @cancellable is non-%NULL, it can be used to cancel the * resolution. soup_address_resolve_sync() will then return a status * of %SOUP_STATUS_CANCELLED. * * It is safe to call this more than once, even from different * threads, but it is not safe to mix calls to * soup_address_resolve_sync() with calls to * soup_address_resolve_async() on the same address. * * Return value: %SOUP_STATUS_OK, %SOUP_STATUS_CANT_RESOLVE, or * %SOUP_STATUS_CANCELLED. **/ guint soup_address_resolve_sync (SoupAddress *addr, GCancellable *cancellable) { SoupAddressPrivate *priv; g_return_val_if_fail (SOUP_IS_ADDRESS (addr), SOUP_STATUS_MALFORMED); priv = SOUP_ADDRESS_GET_PRIVATE (addr); g_return_val_if_fail (priv->name || priv->sockaddr, SOUP_STATUS_MALFORMED); return resolve_sync_internal (addr, cancellable, NULL); }
/** * soup_address_get_sockaddr: * @addr: a #SoupAddress * @len: return location for sockaddr length * * Returns the sockaddr associated with @addr, with its length in * *@len. If the sockaddr 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) (transfer none): the sockaddr, or %NULL **/ struct sockaddr * soup_address_get_sockaddr (SoupAddress *addr, int *len) { SoupAddressPrivate *priv; g_return_val_if_fail (SOUP_IS_ADDRESS (addr), NULL); priv = SOUP_ADDRESS_GET_PRIVATE (addr); if (priv->sockaddr && len) *len = SOUP_ADDRESS_FAMILY_SOCKADDR_SIZE (SOUP_ADDRESS_GET_FAMILY (priv)); return (struct sockaddr *)priv->sockaddr; }
/** * soup_address_hash_by_ip: * @addr: (type Soup.Address): a #SoupAddress * * A hash function (for #GHashTable) that corresponds to * soup_address_equal_by_ip(), qv * * Return value: the IP-based hash value for @addr. * * Since: 2.26 **/ guint soup_address_hash_by_ip (gconstpointer addr) { SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (addr); guint hash; g_return_val_if_fail (priv->sockaddr != NULL, 0); memcpy (&hash, SOUP_ADDRESS_GET_DATA (priv), MIN (sizeof (hash), SOUP_ADDRESS_FAMILY_DATA_SIZE (priv->sockaddr->ss_family))); return hash; }
static GInetAddress * soup_address_make_inet_address (SoupAddress *addr) { SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (addr); GSocketAddress *gsa; GInetAddress *gia; gsa = g_socket_address_new_from_native (priv->sockaddr, SOUP_ADDRESS_FAMILY_SOCKADDR_SIZE (SOUP_ADDRESS_GET_FAMILY (priv))); gia = g_inet_socket_address_get_address ((GInetSocketAddress *)gsa); g_object_ref (gia); g_object_unref (gsa); return gia; }
static void soup_address_finalize (GObject *object) { SoupAddress *addr = SOUP_ADDRESS (object); SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (addr); g_free (priv->sockaddr); g_free (priv->name); g_free (priv->physical); g_mutex_clear (&priv->lock); G_OBJECT_CLASS (soup_address_parent_class)->finalize (object); }
static GSocketAddressEnumerator * soup_address_connectable_enumerate (GSocketConnectable *connectable) { SoupAddressAddressEnumerator *addr_enum; SoupAddressPrivate *priv; addr_enum = g_object_new (SOUP_TYPE_ADDRESS_ADDRESS_ENUMERATOR, NULL); addr_enum->addr = g_object_ref (connectable); priv = SOUP_ADDRESS_GET_PRIVATE (addr_enum->addr); addr_enum->orig_offset = priv->offset; return (GSocketAddressEnumerator *)addr_enum; }
/** * soup_address_is_resolved: * @addr: a #SoupAddress * * Tests if @addr has already been resolved. Unlike the other * #SoupAddress "get" methods, this is safe to call when @addr might * be being resolved in another thread. * * Return value: %TRUE if @addr has been resolved. **/ gboolean soup_address_is_resolved (SoupAddress *addr) { SoupAddressPrivate *priv; gboolean resolved; g_return_val_if_fail (SOUP_IS_ADDRESS (addr), FALSE); priv = SOUP_ADDRESS_GET_PRIVATE (addr); g_mutex_lock (&priv->lock); resolved = priv->sockaddr && priv->name; g_mutex_unlock (&priv->lock); return resolved; }
/* 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 GSocketAddress * soup_address_address_enumerator_next (GSocketAddressEnumerator *enumerator, GCancellable *cancellable, GError **error) { SoupAddressAddressEnumerator *addr_enum = SOUP_ADDRESS_ADDRESS_ENUMERATOR (enumerator); SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (addr_enum->addr); if (!priv->sockaddr) { if (resolve_sync_internal (addr_enum->addr, cancellable, error) != SOUP_STATUS_OK) return NULL; } return next_address (addr_enum); }
static guint update_name (SoupAddress *addr, const char *name, GError *error) { SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (addr); if (error) { if (error->domain == G_IO_ERROR && error->code == G_IO_ERROR_CANCELLED) return SOUP_STATUS_CANCELLED; else return SOUP_STATUS_CANT_RESOLVE; } else if (!name) return SOUP_STATUS_CANT_RESOLVE; else if (priv->name) return SOUP_STATUS_OK; priv->name = g_strdup (name); return SOUP_STATUS_OK; }
static void soup_address_address_enumerator_next_async (GSocketAddressEnumerator *enumerator, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { SoupAddressAddressEnumerator *addr_enum = SOUP_ADDRESS_ADDRESS_ENUMERATOR (enumerator); SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (addr_enum->addr); GTask *task; task = g_task_new (enumerator, cancellable, callback, user_data); if (!priv->sockaddr) { soup_address_resolve_async (addr_enum->addr, g_main_context_get_thread_default (), cancellable, got_addresses, task); } else { g_task_return_pointer (task, next_address (addr_enum), g_object_unref); g_object_unref (task); } }
/** * 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; }
static GObject * soup_address_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { GObject *addr; SoupAddressPrivate *priv; addr = G_OBJECT_CLASS (soup_address_parent_class)->constructor ( type, n_construct_properties, construct_properties); if (!addr) return NULL; priv = SOUP_ADDRESS_GET_PRIVATE (addr); if (!priv->name && !priv->sockaddr) { g_object_unref (addr); return NULL; } return addr; }
static void complete_resolve_async (SoupAddress *addr, 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); for (l = lookups; l; l = l->next) { res_data = l->data; if (res_data->callback) { res_data->callback (addr, status, res_data->callback_data); } g_slice_free (SoupAddressResolveAsyncData, res_data); } g_slist_free (lookups); g_main_context_pop_thread_default (current_context); g_object_unref (addr); }
static void lookup_resolved (GObject *source, GAsyncResult *result, gpointer user_data) { GResolver *resolver = G_RESOLVER (source); SoupAddressResolveAsyncData *res_data = user_data; SoupAddress *addr = res_data->addr; SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (addr); GError *error = NULL; guint status; if (!priv->sockaddr) { GList *addrs; addrs = g_resolver_lookup_by_name_finish (resolver, result, &error); status = update_addrs (addr, addrs, error); g_resolver_free_addresses (addrs); } else if (!priv->name) { char *name; name = g_resolver_lookup_by_address_finish (resolver, result, &error); status = update_name (addr, name, error); g_free (name); } else status = SOUP_STATUS_OK; /* For the enumerator impl, below */ g_object_ref (addr); g_object_set_data (G_OBJECT (addr), "async-resolved-error", error); complete_resolve_async (res_data, status); g_object_set_data (G_OBJECT (addr), "async-resolved-error", NULL); g_object_unref (addr); if (error) g_error_free (error); }
static guint update_addrs (SoupAddress *addr, GList *addrs, GError *error) { SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (addr); GInetAddress *gia; GSocketAddress *gsa; int i; if (error) { if (error->domain == G_IO_ERROR && error->code == G_IO_ERROR_CANCELLED) return SOUP_STATUS_CANCELLED; else return SOUP_STATUS_CANT_RESOLVE; } else if (!addrs) return SOUP_STATUS_CANT_RESOLVE; else if (priv->sockaddr) return SOUP_STATUS_OK; priv->n_addrs = g_list_length (addrs); priv->sockaddr = g_new (struct sockaddr_storage, priv->n_addrs); for (i = 0; addrs; addrs = addrs->next, i++) { gia = addrs->data; gsa = g_inet_socket_address_new (gia, priv->port); if (!g_socket_address_to_native (gsa, &priv->sockaddr[i], 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 (gsa); } return SOUP_STATUS_OK; }
static GSocketAddressEnumerator * soup_address_connectable_proxy_enumerate (GSocketConnectable *connectable) { SoupAddress *addr = SOUP_ADDRESS (connectable); SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (addr); GSocketAddressEnumerator *proxy_enum; char *uri; /* 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); proxy_enum = g_object_new (G_TYPE_PROXY_ADDRESS_ENUMERATOR, "connectable", connectable, "uri", uri, NULL); g_free (uri); return proxy_enum; }
static void soup_address_address_enumerator_next_async (GSocketAddressEnumerator *enumerator, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { 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); if (!priv->sockaddr) { soup_address_resolve_async (addr_enum->addr, NULL, cancellable, got_addresses, simple); } else { g_simple_async_result_complete_in_idle (simple); g_object_unref (simple); } }
static GSocketAddress * next_address (SoupAddressAddressEnumerator *addr_enum) { SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (addr_enum->addr); struct sockaddr_storage *ss; int next_addr; /* If there are two addresses but the first one is unusable * (eg, it's IPv6 and we can only do IPv4), then we don't want to * try the bad one every time. So we use priv->offset to remember * the offset of the first usable address (ie, the first address * that we weren't called again after returning). */ next_addr = (addr_enum->orig_offset + addr_enum->n) % priv->n_addrs; priv->offset = next_addr; if (addr_enum->n >= priv->n_addrs) return NULL; addr_enum->n++; ss = &priv->sockaddr[next_addr]; return g_socket_address_new_from_native (ss, SOUP_ADDRESS_FAMILY_SOCKADDR_SIZE (ss->ss_family)); }