• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * soup-address.c: Internet address handing
4  *
5  * Copyright (C) 2010 Red Hat, Inc.
6  */
7 
8 #ifdef HAVE_CONFIG_H
9 #include <config.h>
10 #endif
11 
12 #include <string.h>
13 
14 #include <gio/gnetworking.h>
15 
16 #include "soup-address.h"
17 #include "soup.h"
18 #include "soup-misc-private.h"
19 
20 /**
21  * SECTION:soup-address
22  * @short_description: DNS support
23  *
24  * #SoupAddress represents the address of a TCP connection endpoint:
25  * both the IP address and the port. (It is somewhat like an
26  * object-oriented version of struct sockaddr.)
27  *
28  * Although #SoupAddress is still used in some libsoup API's, it
29  * should not be used in new code; use GLib's #GNetworkAddress or
30  * #GSocketAddress instead.
31  **/
32 
33 enum {
34 	PROP_0,
35 
36 	PROP_NAME,
37 	PROP_FAMILY,
38 	PROP_PORT,
39 	PROP_PROTOCOL,
40 	PROP_PHYSICAL,
41 	PROP_SOCKADDR,
42 
43 	LAST_PROP
44 };
45 
46 typedef struct {
47 	struct sockaddr_storage *sockaddr;
48 	int n_addrs, offset;
49 
50 	char *name, *physical;
51 	guint port;
52 	const char *protocol;
53 
54 	GMutex lock;
55 } SoupAddressPrivate;
56 
57 /* sockaddr generic macros */
58 #define SOUP_SIN(priv) ((struct sockaddr_in *)priv->sockaddr)
59 #define SOUP_SIN6(priv) ((struct sockaddr_in6 *)priv->sockaddr)
60 
61 /* sockaddr family macros */
62 #define SOUP_ADDRESS_GET_FAMILY(priv) (priv->sockaddr->ss_family)
63 #define SOUP_ADDRESS_SET_FAMILY(priv, family) \
64 	(priv->sockaddr->ss_family = family)
65 #define SOUP_ADDRESS_FAMILY_IS_VALID(family) \
66 	(family == AF_INET || family == AF_INET6)
67 #define SOUP_ADDRESS_FAMILY_SOCKADDR_SIZE(family) \
68 	(family == AF_INET ? sizeof (struct sockaddr_in) : \
69 			     sizeof (struct sockaddr_in6))
70 #define SOUP_ADDRESS_FAMILY_DATA_SIZE(family) \
71 	(family == AF_INET ? sizeof (struct in_addr) : \
72 			     sizeof (struct in6_addr))
73 
74 /* sockaddr port macros */
75 #define SOUP_ADDRESS_PORT_IS_VALID(port) (((gint) port) >= 0 && port <= 65535)
76 #define SOUP_ADDRESS_GET_PORT(priv) \
77 	(priv->sockaddr->ss_family == AF_INET ? \
78 		SOUP_SIN(priv)->sin_port : \
79 		SOUP_SIN6(priv)->sin6_port)
80 #define SOUP_ADDRESS_SET_PORT(priv, port) \
81 	G_STMT_START {					\
82 	if (priv->sockaddr->ss_family == AF_INET)	\
83 		SOUP_SIN(priv)->sin_port = port;	\
84 	else						\
85 		SOUP_SIN6(priv)->sin6_port = port;	\
86 	} G_STMT_END
87 
88 /* sockaddr data macros */
89 #define SOUP_ADDRESS_GET_DATA(priv) \
90 	(priv->sockaddr->ss_family == AF_INET ? \
91 		(gpointer)&SOUP_SIN(priv)->sin_addr : \
92 		(gpointer)&SOUP_SIN6(priv)->sin6_addr)
93 #define SOUP_ADDRESS_SET_DATA(priv, data, length) \
94 	memcpy (SOUP_ADDRESS_GET_DATA (priv), data, length)
95 
96 
97 static void soup_address_connectable_iface_init (GSocketConnectableIface *connectable_iface);
98 
G_DEFINE_TYPE_WITH_CODE(SoupAddress,soup_address,G_TYPE_OBJECT,G_ADD_PRIVATE (SoupAddress)G_IMPLEMENT_INTERFACE (G_TYPE_SOCKET_CONNECTABLE,soup_address_connectable_iface_init))99 G_DEFINE_TYPE_WITH_CODE (SoupAddress, soup_address, G_TYPE_OBJECT,
100                          G_ADD_PRIVATE (SoupAddress)
101 			 G_IMPLEMENT_INTERFACE (G_TYPE_SOCKET_CONNECTABLE,
102 						soup_address_connectable_iface_init))
103 
104 static void
105 soup_address_init (SoupAddress *addr)
106 {
107 	SoupAddressPrivate *priv = soup_address_get_instance_private (addr);
108 
109 	g_mutex_init (&priv->lock);
110 }
111 
112 static void
soup_address_finalize(GObject * object)113 soup_address_finalize (GObject *object)
114 {
115 	SoupAddress *addr = SOUP_ADDRESS (object);
116 	SoupAddressPrivate *priv = soup_address_get_instance_private (addr);
117 
118 	g_free (priv->sockaddr);
119 	g_free (priv->name);
120 	g_free (priv->physical);
121 
122 	g_mutex_clear (&priv->lock);
123 
124 	G_OBJECT_CLASS (soup_address_parent_class)->finalize (object);
125 }
126 
127 static GObject *
soup_address_constructor(GType type,guint n_construct_properties,GObjectConstructParam * construct_properties)128 soup_address_constructor (GType                  type,
129 			  guint                  n_construct_properties,
130 			  GObjectConstructParam *construct_properties)
131 {
132 	GObject *addr;
133 	SoupAddressPrivate *priv;
134 
135 	addr = G_OBJECT_CLASS (soup_address_parent_class)->constructor (
136 		type, n_construct_properties, construct_properties);
137 	if (!addr)
138 		return NULL;
139 	priv = soup_address_get_instance_private (SOUP_ADDRESS (addr));
140 
141 	if (!priv->name && !priv->sockaddr) {
142 		g_object_unref (addr);
143 		return NULL;
144 	}
145 
146 	return addr;
147 }
148 
149 static void
soup_address_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)150 soup_address_set_property (GObject *object, guint prop_id,
151 			   const GValue *value, GParamSpec *pspec)
152 {
153 	SoupAddressPrivate *priv = soup_address_get_instance_private (SOUP_ADDRESS (object));
154 	SoupAddressFamily family;
155 	struct sockaddr *sa;
156 	int len, port;
157 
158 	/* This is a mess because the properties are mostly orthogonal,
159 	 * but g_object_constructor wants to set a default value for each
160 	 * of them.
161 	 */
162 
163 	switch (prop_id) {
164 	case PROP_NAME:
165 		priv->name = g_value_dup_string (value);
166 		break;
167 
168 	case PROP_FAMILY:
169 		family = g_value_get_enum (value);
170 		if (family == SOUP_ADDRESS_FAMILY_INVALID)
171 			return;
172 		g_return_if_fail (SOUP_ADDRESS_FAMILY_IS_VALID (family));
173 		g_return_if_fail (priv->sockaddr == NULL);
174 
175 		priv->sockaddr = g_malloc0 (SOUP_ADDRESS_FAMILY_SOCKADDR_SIZE (family));
176 		SOUP_ADDRESS_SET_FAMILY (priv, family);
177 		SOUP_ADDRESS_SET_PORT (priv, htons (priv->port));
178 		priv->n_addrs = 1;
179 		break;
180 
181 	case PROP_PORT:
182 		port = g_value_get_int (value);
183 		if (port == -1)
184 			return;
185 		g_return_if_fail (SOUP_ADDRESS_PORT_IS_VALID (port));
186 
187 		priv->port = port;
188 		if (priv->sockaddr)
189 			SOUP_ADDRESS_SET_PORT (priv, htons (port));
190 		break;
191 
192 	case PROP_PROTOCOL:
193 		priv->protocol = g_intern_string (g_value_get_string (value));
194 		break;
195 
196 	case PROP_SOCKADDR:
197 		sa = g_value_get_pointer (value);
198 		if (!sa)
199 			return;
200 		g_return_if_fail (priv->sockaddr == NULL);
201 
202 		len = SOUP_ADDRESS_FAMILY_SOCKADDR_SIZE (sa->sa_family);
203 		priv->sockaddr = g_memdup (sa, len);
204 		priv->n_addrs = 1;
205 		priv->port = ntohs (SOUP_ADDRESS_GET_PORT (priv));
206 		break;
207 	default:
208 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
209 		break;
210 	}
211 }
212 
213 static void
soup_address_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)214 soup_address_get_property (GObject *object, guint prop_id,
215 			   GValue *value, GParamSpec *pspec)
216 {
217 	SoupAddressPrivate *priv = soup_address_get_instance_private (SOUP_ADDRESS (object));
218 
219 	switch (prop_id) {
220 	case PROP_NAME:
221 		g_value_set_string (value, priv->name);
222 		break;
223 	case PROP_FAMILY:
224 		if (priv->sockaddr)
225 			g_value_set_enum (value, SOUP_ADDRESS_GET_FAMILY (priv));
226 		else
227 			g_value_set_enum (value, 0);
228 		break;
229 	case PROP_PORT:
230 		g_value_set_int (value, priv->port);
231 		break;
232 	case PROP_PHYSICAL:
233 		g_value_set_string (value, soup_address_get_physical (SOUP_ADDRESS (object)));
234 		break;
235 	case PROP_PROTOCOL:
236 		g_value_set_string (value, priv->protocol);
237 		break;
238 	case PROP_SOCKADDR:
239 		g_value_set_pointer (value, priv->sockaddr);
240 		break;
241 	default:
242 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
243 		break;
244 	}
245 }
246 
247 static void
soup_address_class_init(SoupAddressClass * address_class)248 soup_address_class_init (SoupAddressClass *address_class)
249 {
250 	GObjectClass *object_class = G_OBJECT_CLASS (address_class);
251 
252 	/* virtual method override */
253 	object_class->constructor  = soup_address_constructor;
254 	object_class->finalize     = soup_address_finalize;
255 	object_class->set_property = soup_address_set_property;
256 	object_class->get_property = soup_address_get_property;
257 
258 	/* properties */
259 	/**
260 	 * SOUP_ADDRESS_NAME:
261 	 *
262 	 * Alias for the #SoupAddress:name property. (The hostname for
263 	 * this address.)
264 	 **/
265 	g_object_class_install_property (
266 		object_class, PROP_NAME,
267 		g_param_spec_string (SOUP_ADDRESS_NAME,
268 				     "Name",
269 				     "Hostname for this address",
270 				     NULL,
271 				     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
272 				     G_PARAM_STATIC_STRINGS));
273 	/**
274 	 * SOUP_ADDRESS_FAMILY:
275 	 *
276 	 * Alias for the #SoupAddress:family property. (The
277 	 * #SoupAddressFamily for this address.)
278 	 **/
279 	g_object_class_install_property (
280 		object_class, PROP_FAMILY,
281 		g_param_spec_enum (SOUP_ADDRESS_FAMILY,
282 				   "Family",
283 				   "Address family for this address",
284 				   SOUP_TYPE_ADDRESS_FAMILY,
285 				   SOUP_ADDRESS_FAMILY_INVALID,
286 				   G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
287 				   G_PARAM_STATIC_STRINGS));
288 	/**
289 	 * SOUP_ADDRESS_PORT:
290 	 *
291 	 * An alias for the #SoupAddress:port property. (The port for
292 	 * this address.)
293 	 **/
294 	g_object_class_install_property (
295 		object_class, PROP_PORT,
296 		g_param_spec_int (SOUP_ADDRESS_PORT,
297 				  "Port",
298 				  "Port for this address",
299 				  -1, 65535, -1,
300 				  G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
301 				  G_PARAM_STATIC_STRINGS));
302 	/**
303 	 * SOUP_ADDRESS_PROTOCOL:
304 	 *
305 	 * Alias for the #SoupAddress:protocol property. (The URI scheme
306 	 * used with this address.)
307 	 **/
308 	g_object_class_install_property (
309 		object_class, PROP_PROTOCOL,
310 		g_param_spec_string (SOUP_ADDRESS_PROTOCOL,
311 				     "Protocol",
312 				     "URI scheme for this address",
313 				     NULL,
314 				     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
315 				     G_PARAM_STATIC_STRINGS));
316 	/**
317 	 * SOUP_ADDRESS_PHYSICAL:
318 	 *
319 	 * An alias for the #SoupAddress:physical property. (The
320 	 * stringified IP address for this address.)
321 	 **/
322 	g_object_class_install_property (
323 		object_class, PROP_PHYSICAL,
324 		g_param_spec_string (SOUP_ADDRESS_PHYSICAL,
325 				     "Physical address",
326 				     "IP address for this address",
327 				     NULL,
328 				     G_PARAM_READABLE |
329 				     G_PARAM_STATIC_STRINGS));
330 	/**
331 	 * SOUP_ADDRESS_SOCKADDR:
332 	 *
333 	 * An alias for the #SoupAddress:sockaddr property. (A pointer
334 	 * to the struct sockaddr for this address.)
335 	 **/
336 	g_object_class_install_property (
337 		object_class, PROP_SOCKADDR,
338 		g_param_spec_pointer (SOUP_ADDRESS_SOCKADDR,
339 				      "sockaddr",
340 				      "struct sockaddr for this address",
341 				      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
342 				      G_PARAM_STATIC_STRINGS));
343 }
344 
345 /**
346  * soup_address_new:
347  * @name: a hostname or physical address
348  * @port: a port number
349  *
350  * Creates a #SoupAddress from @name and @port. The #SoupAddress's IP
351  * address may not be available right away; the caller can call
352  * soup_address_resolve_async() or soup_address_resolve_sync() to
353  * force a DNS resolution.
354  *
355  * Return value: a #SoupAddress
356  **/
357 SoupAddress *
soup_address_new(const char * name,guint port)358 soup_address_new (const char *name, guint port)
359 {
360 	g_return_val_if_fail (name != NULL, NULL);
361 	g_return_val_if_fail (SOUP_ADDRESS_PORT_IS_VALID (port), NULL);
362 
363 	return g_object_new (SOUP_TYPE_ADDRESS,
364 			     SOUP_ADDRESS_NAME, name,
365 			     SOUP_ADDRESS_PORT, port,
366 			     NULL);
367 }
368 
369 /**
370  * soup_address_new_from_sockaddr:
371  * @sa: a pointer to a sockaddr
372  * @len: size of @sa
373  *
374  * Returns a #SoupAddress equivalent to @sa (or %NULL if @sa's
375  * address family isn't supported)
376  *
377  * Return value: (nullable): the new #SoupAddress
378  **/
379 SoupAddress *
soup_address_new_from_sockaddr(struct sockaddr * sa,int len)380 soup_address_new_from_sockaddr (struct sockaddr *sa, int len)
381 {
382 	g_return_val_if_fail (sa != NULL, NULL);
383 	g_return_val_if_fail (SOUP_ADDRESS_FAMILY_IS_VALID (sa->sa_family), NULL);
384 	g_return_val_if_fail (len == SOUP_ADDRESS_FAMILY_SOCKADDR_SIZE (sa->sa_family), NULL);
385 
386 	return g_object_new (SOUP_TYPE_ADDRESS,
387 			     SOUP_ADDRESS_SOCKADDR, sa,
388 			     NULL);
389 }
390 
391 SoupAddress *
soup_address_new_from_gsockaddr(GSocketAddress * addr)392 soup_address_new_from_gsockaddr (GSocketAddress *addr)
393 {
394 	struct sockaddr_storage sa;
395 
396 	g_socket_address_to_native (addr, &sa, sizeof (sa), NULL);
397 	return g_object_new (SOUP_TYPE_ADDRESS,
398 			     SOUP_ADDRESS_SOCKADDR, &sa,
399 			     NULL);
400 }
401 
402 /**
403  * SoupAddressFamily:
404  * @SOUP_ADDRESS_FAMILY_INVALID: an invalid %SoupAddress
405  * @SOUP_ADDRESS_FAMILY_IPV4: an IPv4 address
406  * @SOUP_ADDRESS_FAMILY_IPV6: an IPv6 address
407  *
408  * The supported address families.
409  **/
410 
411 /**
412  * SOUP_ADDRESS_ANY_PORT:
413  *
414  * This can be passed to any #SoupAddress method that expects a port,
415  * to indicate that you don't care what port is used.
416  **/
417 
418 /**
419  * soup_address_new_any:
420  * @family: the address family
421  * @port: the port number (usually %SOUP_ADDRESS_ANY_PORT)
422  *
423  * Returns a #SoupAddress corresponding to the "any" address
424  * for @family (or %NULL if @family isn't supported), suitable for
425  * using as a listening #SoupSocket.
426  *
427  * Return value: (nullable): the new #SoupAddress
428  **/
429 SoupAddress *
soup_address_new_any(SoupAddressFamily family,guint port)430 soup_address_new_any (SoupAddressFamily family, guint port)
431 {
432 	g_return_val_if_fail (SOUP_ADDRESS_FAMILY_IS_VALID (family), NULL);
433 	g_return_val_if_fail (SOUP_ADDRESS_PORT_IS_VALID (port), NULL);
434 
435 	return g_object_new (SOUP_TYPE_ADDRESS,
436 			     SOUP_ADDRESS_FAMILY, family,
437 			     SOUP_ADDRESS_PORT, port,
438 			     NULL);
439 }
440 
441 /**
442  * soup_address_get_name:
443  * @addr: a #SoupAddress
444  *
445  * Returns the hostname associated with @addr.
446  *
447  * This method is not thread-safe; if you call it while @addr is being
448  * resolved in another thread, it may return garbage. You can use
449  * soup_address_is_resolved() to safely test whether or not an address
450  * is resolved before fetching its name or address.
451  *
452  * Return value: (nullable): the hostname, or %NULL if it is not known.
453  **/
454 const char *
soup_address_get_name(SoupAddress * addr)455 soup_address_get_name (SoupAddress *addr)
456 {
457 	SoupAddressPrivate *priv;
458 
459 	g_return_val_if_fail (SOUP_IS_ADDRESS (addr), NULL);
460 	priv = soup_address_get_instance_private (addr);
461 
462 	return priv->name;
463 }
464 
465 /**
466  * soup_address_get_sockaddr:
467  * @addr: a #SoupAddress
468  * @len: return location for sockaddr length
469  *
470  * Returns the sockaddr associated with @addr, with its length in
471  * *@len. If the sockaddr is not yet known, returns %NULL.
472  *
473  * This method is not thread-safe; if you call it while @addr is being
474  * resolved in another thread, it may return garbage. You can use
475  * soup_address_is_resolved() to safely test whether or not an address
476  * is resolved before fetching its name or address.
477  *
478  * Return value: (nullable) (transfer none): the sockaddr, or %NULL
479  **/
480 struct sockaddr *
soup_address_get_sockaddr(SoupAddress * addr,int * len)481 soup_address_get_sockaddr (SoupAddress *addr, int *len)
482 {
483 	SoupAddressPrivate *priv;
484 
485 	g_return_val_if_fail (SOUP_IS_ADDRESS (addr), NULL);
486 	priv = soup_address_get_instance_private (addr);
487 
488 	if (priv->sockaddr && len)
489 		*len = SOUP_ADDRESS_FAMILY_SOCKADDR_SIZE (SOUP_ADDRESS_GET_FAMILY (priv));
490 	return (struct sockaddr *)priv->sockaddr;
491 }
492 
493 /**
494  * soup_address_get_gsockaddr:
495  * @addr: a #SoupAddress
496  *
497  * Creates a new #GSocketAddress corresponding to @addr (which is assumed
498  * to only have one socket address associated with it).
499  *
500  * Return value: (transfer full): a new #GSocketAddress
501  *
502  * Since: 2.32
503  */
504 GSocketAddress *
soup_address_get_gsockaddr(SoupAddress * addr)505 soup_address_get_gsockaddr (SoupAddress *addr)
506 {
507 	SoupAddressPrivate *priv = soup_address_get_instance_private (addr);
508 
509 	return g_socket_address_new_from_native (priv->sockaddr,
510 						 SOUP_ADDRESS_FAMILY_SOCKADDR_SIZE (SOUP_ADDRESS_GET_FAMILY (priv)));
511 }
512 
513 static GInetAddress *
soup_address_make_inet_address(SoupAddress * addr)514 soup_address_make_inet_address (SoupAddress *addr)
515 {
516 	SoupAddressPrivate *priv = soup_address_get_instance_private (addr);
517 	GSocketAddress *gsa;
518 	GInetAddress *gia;
519 
520 	gsa = g_socket_address_new_from_native (priv->sockaddr,
521 						SOUP_ADDRESS_FAMILY_SOCKADDR_SIZE (SOUP_ADDRESS_GET_FAMILY (priv)));
522 	gia = g_inet_socket_address_get_address ((GInetSocketAddress *)gsa);
523 	g_object_ref (gia);
524 	g_object_unref (gsa);
525 	return gia;
526 }
527 
528 /**
529  * soup_address_get_physical:
530  * @addr: a #SoupAddress
531  *
532  * Returns the physical address associated with @addr as a string.
533  * (Eg, "127.0.0.1"). If the address is not yet known, returns %NULL.
534  *
535  * This method is not thread-safe; if you call it while @addr is being
536  * resolved in another thread, it may return garbage. You can use
537  * soup_address_is_resolved() to safely test whether or not an address
538  * is resolved before fetching its name or address.
539  *
540  * Return value: (nullable): the physical address, or %NULL
541  **/
542 const char *
soup_address_get_physical(SoupAddress * addr)543 soup_address_get_physical (SoupAddress *addr)
544 {
545 	SoupAddressPrivate *priv;
546 
547 	g_return_val_if_fail (SOUP_IS_ADDRESS (addr), NULL);
548 	priv = soup_address_get_instance_private (addr);
549 
550 	if (!priv->sockaddr)
551 		return NULL;
552 
553 	if (!priv->physical) {
554 		GInetAddress *gia;
555 
556 		gia = soup_address_make_inet_address (addr);
557 		priv->physical = g_inet_address_to_string (gia);
558 		g_object_unref (gia);
559 	}
560 
561 	return priv->physical;
562 }
563 
564 /**
565  * soup_address_get_port:
566  * @addr: a #SoupAddress
567  *
568  * Returns the port associated with @addr.
569  *
570  * Return value: the port
571  **/
572 guint
soup_address_get_port(SoupAddress * addr)573 soup_address_get_port (SoupAddress *addr)
574 {
575 	SoupAddressPrivate *priv;
576 
577 	g_return_val_if_fail (SOUP_IS_ADDRESS (addr), 0);
578 	priv = soup_address_get_instance_private (addr);
579 
580 	return priv->port;
581 }
582 
583 
584 /* Tries to resolve priv->name as an IP address, possibly including an
585  * IPv6 scope id.
586  */
587 static void
maybe_resolve_ip(SoupAddress * addr)588 maybe_resolve_ip (SoupAddress *addr)
589 {
590 	SoupAddressPrivate *priv = soup_address_get_instance_private (addr);
591 	const char *pct, *ip;
592 	char *tmp = NULL;
593 	GSocketConnectable *gaddr;
594 	GSocketAddressEnumerator *sa_enum;
595 	GSocketAddress *saddr;
596 
597 	if (priv->sockaddr || !priv->name)
598 		return;
599 
600 	pct = strchr (priv->name, '%');
601 	if (pct)
602 		ip = tmp = g_strndup (priv->name, pct - priv->name);
603 	else
604 		ip = priv->name;
605 
606 	if (!g_hostname_is_ip_address (ip)) {
607 		g_free (tmp);
608 		return;
609 	}
610 	g_free (tmp);
611 
612 	gaddr = g_network_address_new (priv->name, priv->port);
613 	if (!gaddr)
614 		return;
615 
616 	sa_enum = g_socket_connectable_enumerate (gaddr);
617 	saddr = g_socket_address_enumerator_next (sa_enum, NULL, NULL);
618 	if (saddr) {
619 		priv->n_addrs = 1;
620 		priv->sockaddr = g_new (struct sockaddr_storage, 1);
621 		if (!g_socket_address_to_native (saddr, priv->sockaddr,
622 						 sizeof (struct sockaddr_storage),
623 						 NULL)) {
624 			/* can't happen: We know the address format is supported
625 			 * and the buffer is large enough
626 			 */
627 			g_warn_if_reached ();
628 		}
629 		g_object_unref (saddr);
630 	}
631 
632 	g_object_unref (sa_enum);
633 	g_object_unref (gaddr);
634 }
635 
636 
637 static guint
update_addrs(SoupAddress * addr,GList * addrs,GError * error)638 update_addrs (SoupAddress *addr, GList *addrs, GError *error)
639 {
640 	SoupAddressPrivate *priv = soup_address_get_instance_private (addr);
641 	GInetAddress *gia;
642 	GSocketAddress *gsa;
643 	int i;
644 
645 	if (error) {
646 		if (error->domain == G_IO_ERROR &&
647 		    error->code == G_IO_ERROR_CANCELLED)
648 			return SOUP_STATUS_CANCELLED;
649 		else
650 			return SOUP_STATUS_CANT_RESOLVE;
651 	} else if (!addrs)
652 		return SOUP_STATUS_CANT_RESOLVE;
653 	else if (priv->sockaddr)
654 		return SOUP_STATUS_OK;
655 
656 	priv->n_addrs = g_list_length (addrs);
657 	priv->sockaddr = g_new (struct sockaddr_storage, priv->n_addrs);
658 	for (i = 0; addrs; addrs = addrs->next, i++) {
659 		gia = addrs->data;
660 		gsa = g_inet_socket_address_new (gia, priv->port);
661 
662 		if (!g_socket_address_to_native (gsa, &priv->sockaddr[i],
663 						 sizeof (struct sockaddr_storage),
664 						 NULL)) {
665 			/* can't happen: We know the address format is supported
666 			 * and the buffer is large enough
667 			 */
668 			g_warn_if_reached ();
669 		}
670 		g_object_unref (gsa);
671 	}
672 
673 	return SOUP_STATUS_OK;
674 }
675 
676 static guint
update_name(SoupAddress * addr,const char * name,GError * error)677 update_name (SoupAddress *addr, const char *name, GError *error)
678 {
679 	SoupAddressPrivate *priv = soup_address_get_instance_private (addr);
680 
681 	if (error) {
682 		if (error->domain == G_IO_ERROR &&
683 		    error->code == G_IO_ERROR_CANCELLED)
684 			return SOUP_STATUS_CANCELLED;
685 		else
686 			return SOUP_STATUS_CANT_RESOLVE;
687 	} else if (!name)
688 		return SOUP_STATUS_CANT_RESOLVE;
689 	else if (priv->name)
690 		return SOUP_STATUS_OK;
691 
692 	priv->name = g_strdup (name);
693 	return SOUP_STATUS_OK;
694 }
695 
696 typedef struct {
697 	SoupAddress         *addr;
698 	SoupAddressCallback  callback;
699 	gpointer             callback_data;
700 } SoupAddressResolveAsyncData;
701 
702 static void
complete_resolve_async(SoupAddressResolveAsyncData * res_data,guint status)703 complete_resolve_async (SoupAddressResolveAsyncData *res_data, guint status)
704 {
705 	GSource *current_source;
706 	GMainContext *current_context;
707 
708 	if (res_data->callback) {
709 		/* Awful hack; to make soup_socket_connect_async()
710 		 * with an non-default async_context work correctly,
711 		 * we need to ensure that the non-default context
712 		 * (which we're now running in) is the thread-default
713 		 * when the callbacks are run...
714 		 */
715 		current_source = g_main_current_source ();
716 		if (current_source && !g_source_is_destroyed (current_source))
717 			current_context = g_source_get_context (current_source);
718 		else
719 			current_context = NULL;
720 		g_main_context_push_thread_default (current_context);
721 
722 		res_data->callback (res_data->addr, status,
723 				    res_data->callback_data);
724 
725 		g_main_context_pop_thread_default (current_context);
726 	}
727 
728 	g_object_unref (res_data->addr);
729 	g_slice_free (SoupAddressResolveAsyncData, res_data);
730 }
731 
732 static void
lookup_resolved(GObject * source,GAsyncResult * result,gpointer user_data)733 lookup_resolved (GObject *source, GAsyncResult *result, gpointer user_data)
734 {
735 	GResolver *resolver = G_RESOLVER (source);
736 	SoupAddressResolveAsyncData *res_data = user_data;
737 	SoupAddress *addr = res_data->addr;
738 	SoupAddressPrivate *priv = soup_address_get_instance_private (addr);
739 	GError *error = NULL;
740 	guint status;
741 
742 	if (!priv->sockaddr) {
743 		GList *addrs;
744 
745 		addrs = g_resolver_lookup_by_name_finish (resolver, result,
746 							  &error);
747 		status = update_addrs (addr, addrs, error);
748 		g_resolver_free_addresses (addrs);
749 	} else if (!priv->name) {
750 		char *name;
751 
752 		name = g_resolver_lookup_by_address_finish (resolver, result,
753 							    &error);
754 		status = update_name (addr, name, error);
755 		g_free (name);
756 	} else
757 		status = SOUP_STATUS_OK;
758 
759 	/* For the enumerator impl, below */
760 	g_object_ref (addr);
761 	g_object_set_data (G_OBJECT (addr), "async-resolved-error", error);
762 
763 	complete_resolve_async (res_data, status);
764 
765 	g_object_set_data (G_OBJECT (addr), "async-resolved-error", NULL);
766 	g_object_unref (addr);
767 	if (error)
768 		g_error_free (error);
769 }
770 
771 static gboolean
idle_complete_resolve(gpointer res_data)772 idle_complete_resolve (gpointer res_data)
773 {
774 	complete_resolve_async (res_data, SOUP_STATUS_OK);
775 	return FALSE;
776 }
777 
778 /**
779  * SoupAddressCallback:
780  * @addr: the #SoupAddress that was resolved
781  * @status: %SOUP_STATUS_OK, %SOUP_STATUS_CANT_RESOLVE, or
782  * %SOUP_STATUS_CANCELLED
783  * @user_data: the user data that was passed to
784  * soup_address_resolve_async()
785  *
786  * The callback function passed to soup_address_resolve_async().
787  **/
788 
789 /**
790  * soup_address_resolve_async:
791  * @addr: a #SoupAddress
792  * @async_context: (allow-none): the #GMainContext to call @callback from
793  * @cancellable: a #GCancellable object, or %NULL
794  * @callback: (scope async): callback to call with the result
795  * @user_data: data for @callback
796  *
797  * Asynchronously resolves the missing half of @addr (its IP address
798  * if it was created with soup_address_new(), or its hostname if it
799  * was created with soup_address_new_from_sockaddr() or
800  * soup_address_new_any().)
801  *
802  * If @cancellable is non-%NULL, it can be used to cancel the
803  * resolution. @callback will still be invoked in this case, with a
804  * status of %SOUP_STATUS_CANCELLED.
805  *
806  * It is safe to call this more than once on a given address, from the
807  * same thread, with the same @async_context (and doing so will not
808  * result in redundant DNS queries being made). But it is not safe to
809  * call from multiple threads, or with different @async_contexts, or
810  * mixed with calls to soup_address_resolve_sync().
811  **/
812 void
soup_address_resolve_async(SoupAddress * addr,GMainContext * async_context,GCancellable * cancellable,SoupAddressCallback callback,gpointer user_data)813 soup_address_resolve_async (SoupAddress *addr, GMainContext *async_context,
814 			    GCancellable *cancellable,
815 			    SoupAddressCallback callback, gpointer user_data)
816 {
817 	SoupAddressPrivate *priv;
818 	SoupAddressResolveAsyncData *res_data;
819 	GResolver *resolver;
820 
821 	g_return_if_fail (SOUP_IS_ADDRESS (addr));
822 	priv = soup_address_get_instance_private (addr);
823 	g_return_if_fail (priv->name || priv->sockaddr);
824 
825 	/* We don't need to do locking here because the async case is
826 	 * not intended to be thread-safe.
827 	 */
828 
829 	if (priv->name && !priv->sockaddr)
830 		maybe_resolve_ip (addr);
831 	if (priv->name && priv->sockaddr && !callback)
832 		return;
833 
834 	res_data = g_slice_new0 (SoupAddressResolveAsyncData);
835 	res_data->addr = g_object_ref (addr);
836 	res_data->callback = callback;
837 	res_data->callback_data = user_data;
838 
839 	if (async_context)
840 		g_main_context_push_thread_default (async_context);
841 
842 	if (priv->name && priv->sockaddr)
843 		soup_add_completion (async_context, idle_complete_resolve, res_data);
844 	else {
845 		resolver = g_resolver_get_default ();
846 
847 		if (priv->name) {
848 			g_resolver_lookup_by_name_async (resolver, priv->name,
849 							 cancellable,
850 							 lookup_resolved, res_data);
851 		} else {
852 			GInetAddress *gia;
853 
854 			gia = soup_address_make_inet_address (addr);
855 			g_resolver_lookup_by_address_async (resolver, gia,
856 							    cancellable,
857 							    lookup_resolved, res_data);
858 			g_object_unref (gia);
859 		}
860 
861 		g_object_unref (resolver);
862 	}
863 
864 	if (async_context)
865 		g_main_context_pop_thread_default (async_context);
866 }
867 
868 static guint
resolve_sync_internal(SoupAddress * addr,GCancellable * cancellable,GError ** error)869 resolve_sync_internal (SoupAddress *addr, GCancellable *cancellable, GError **error)
870 {
871 	SoupAddressPrivate *priv = soup_address_get_instance_private (addr);
872 	GResolver *resolver;
873 	guint status;
874 	GError *my_err = NULL;
875 
876 	resolver = g_resolver_get_default ();
877 
878 	/* We could optimize this to avoid multiple lookups the same
879 	 * way _resolve_async does, but we don't currently. So, first
880 	 * lock the mutex to ensure we have a consistent view of
881 	 * priv->sockaddr and priv->name, unlock it around the
882 	 * blocking op, and then re-lock it to modify @addr.
883 	 */
884 	g_mutex_lock (&priv->lock);
885 
886 	if (priv->name && !priv->sockaddr)
887 		maybe_resolve_ip (addr);
888 
889 	if (!priv->sockaddr) {
890 		GList *addrs;
891 
892 		g_mutex_unlock (&priv->lock);
893 		addrs = g_resolver_lookup_by_name (resolver, priv->name,
894 						   cancellable, &my_err);
895 		g_mutex_lock (&priv->lock);
896 
897 		status = update_addrs (addr, addrs, my_err);
898 		g_resolver_free_addresses (addrs);
899 	} else if (!priv->name) {
900 		GInetAddress *gia;
901 		char *name;
902 
903 		g_mutex_unlock (&priv->lock);
904 		gia = soup_address_make_inet_address (addr);
905 		name = g_resolver_lookup_by_address (resolver, gia,
906 						     cancellable, &my_err);
907 		g_object_unref (gia);
908 		g_mutex_lock (&priv->lock);
909 
910 		status = update_name (addr, name, my_err);
911 		g_free (name);
912 	} else
913 		status = SOUP_STATUS_OK;
914 
915 	g_mutex_unlock (&priv->lock);
916 
917 	if (my_err)
918 		g_propagate_error (error, my_err);
919 	g_object_unref (resolver);
920 
921 	return status;
922 }
923 
924 /**
925  * soup_address_resolve_sync:
926  * @addr: a #SoupAddress
927  * @cancellable: a #GCancellable object, or %NULL
928  *
929  * Synchronously resolves the missing half of @addr, as with
930  * soup_address_resolve_async().
931  *
932  * If @cancellable is non-%NULL, it can be used to cancel the
933  * resolution. soup_address_resolve_sync() will then return a status
934  * of %SOUP_STATUS_CANCELLED.
935  *
936  * It is safe to call this more than once, even from different
937  * threads, but it is not safe to mix calls to
938  * soup_address_resolve_sync() with calls to
939  * soup_address_resolve_async() on the same address.
940  *
941  * Return value: %SOUP_STATUS_OK, %SOUP_STATUS_CANT_RESOLVE, or
942  * %SOUP_STATUS_CANCELLED.
943  **/
944 guint
soup_address_resolve_sync(SoupAddress * addr,GCancellable * cancellable)945 soup_address_resolve_sync (SoupAddress *addr, GCancellable *cancellable)
946 {
947 	SoupAddressPrivate *priv;
948 
949 	g_return_val_if_fail (SOUP_IS_ADDRESS (addr), SOUP_STATUS_MALFORMED);
950 	priv = soup_address_get_instance_private (addr);
951 	g_return_val_if_fail (priv->name || priv->sockaddr, SOUP_STATUS_MALFORMED);
952 
953 	return resolve_sync_internal (addr, cancellable, NULL);
954 }
955 
956 /**
957  * soup_address_is_resolved:
958  * @addr: a #SoupAddress
959  *
960  * Tests if @addr has already been resolved. Unlike the other
961  * #SoupAddress "get" methods, this is safe to call when @addr might
962  * be being resolved in another thread.
963  *
964  * Return value: %TRUE if @addr has been resolved.
965  **/
966 gboolean
soup_address_is_resolved(SoupAddress * addr)967 soup_address_is_resolved (SoupAddress *addr)
968 {
969 	SoupAddressPrivate *priv;
970 	gboolean resolved;
971 
972 	g_return_val_if_fail (SOUP_IS_ADDRESS (addr), FALSE);
973 	priv = soup_address_get_instance_private (addr);
974 
975 	g_mutex_lock (&priv->lock);
976 	resolved = priv->sockaddr && priv->name;
977 	g_mutex_unlock (&priv->lock);
978 
979 	return resolved;
980 }
981 
982 /**
983  * soup_address_hash_by_name:
984  * @addr: (type Soup.Address): a #SoupAddress
985  *
986  * A hash function (for #GHashTable) that corresponds to
987  * soup_address_equal_by_name(), qv
988  *
989  * Return value: the named-based hash value for @addr.
990  *
991  * Since: 2.26
992  **/
993 guint
soup_address_hash_by_name(gconstpointer addr)994 soup_address_hash_by_name (gconstpointer addr)
995 {
996 	SoupAddressPrivate *priv = soup_address_get_instance_private (SOUP_ADDRESS (addr));
997 
998 	g_return_val_if_fail (priv->name != NULL, 0);
999 	return g_str_hash (priv->name);
1000 }
1001 
1002 /**
1003  * soup_address_equal_by_name:
1004  * @addr1: (type Soup.Address): a #SoupAddress with a resolved name
1005  * @addr2: (type Soup.Address): another #SoupAddress with a resolved
1006  *   name
1007  *
1008  * Tests if @addr1 and @addr2 have the same "name". This method can be
1009  * used with soup_address_hash_by_name() to create a #GHashTable that
1010  * hashes on address "names".
1011  *
1012  * Comparing by name normally means comparing the addresses by their
1013  * hostnames. But if the address was originally created using an IP
1014  * address literal, then it will be compared by that instead.
1015  *
1016  * In particular, if "www.example.com" has the IP address 10.0.0.1,
1017  * and @addr1 was created with the name "www.example.com" and @addr2
1018  * was created with the name "10.0.0.1", then they will compare as
1019  * unequal for purposes of soup_address_equal_by_name().
1020  *
1021  * This would be used to distinguish hosts in situations where
1022  * different virtual hosts on the same IP address should be considered
1023  * different. Eg, for purposes of HTTP authentication or cookies, two
1024  * hosts with the same IP address but different names are considered
1025  * to be different hosts.
1026  *
1027  * See also soup_address_equal_by_ip(), which compares by IP address
1028  * rather than by name.
1029  *
1030  * Return value: whether or not @addr1 and @addr2 have the same name
1031  *
1032  * Since: 2.26
1033  **/
1034 gboolean
soup_address_equal_by_name(gconstpointer addr1,gconstpointer addr2)1035 soup_address_equal_by_name (gconstpointer addr1, gconstpointer addr2)
1036 {
1037 	SoupAddressPrivate *priv1 = soup_address_get_instance_private (SOUP_ADDRESS (addr1));
1038 	SoupAddressPrivate *priv2 = soup_address_get_instance_private (SOUP_ADDRESS (addr2));
1039 
1040 	g_return_val_if_fail (priv1->name != NULL, FALSE);
1041 	g_return_val_if_fail (priv2->name != NULL, FALSE);
1042 	return !g_ascii_strcasecmp (priv1->name, priv2->name);
1043 }
1044 
1045 /**
1046  * soup_address_hash_by_ip:
1047  * @addr: (type Soup.Address): a #SoupAddress
1048  *
1049  * A hash function (for #GHashTable) that corresponds to
1050  * soup_address_equal_by_ip(), qv
1051  *
1052  * Return value: the IP-based hash value for @addr.
1053  *
1054  * Since: 2.26
1055  **/
1056 guint
soup_address_hash_by_ip(gconstpointer addr)1057 soup_address_hash_by_ip (gconstpointer addr)
1058 {
1059 	SoupAddressPrivate *priv = soup_address_get_instance_private (SOUP_ADDRESS (addr));
1060 	guint hash;
1061 
1062 	g_return_val_if_fail (priv->sockaddr != NULL, 0);
1063 
1064 	memcpy (&hash, SOUP_ADDRESS_GET_DATA (priv),
1065 		MIN (sizeof (hash), SOUP_ADDRESS_FAMILY_DATA_SIZE (priv->sockaddr->ss_family)));
1066 	return hash;
1067 }
1068 
1069 /**
1070  * soup_address_equal_by_ip:
1071  * @addr1: (type Soup.Address): a #SoupAddress with a resolved IP
1072  *   address
1073  * @addr2: (type Soup.Address): another #SoupAddress with a resolved
1074  *   IP address
1075  *
1076  * Tests if @addr1 and @addr2 have the same IP address. This method
1077  * can be used with soup_address_hash_by_ip() to create a
1078  * #GHashTable that hashes on IP address.
1079  *
1080  * This would be used to distinguish hosts in situations where
1081  * different virtual hosts on the same IP address should be considered
1082  * the same. Eg, if "www.example.com" and "www.example.net" have the
1083  * same IP address, then a single connection can be used to talk
1084  * to either of them.
1085  *
1086  * See also soup_address_equal_by_name(), which compares by name
1087  * rather than by IP address.
1088  *
1089  * Return value: whether or not @addr1 and @addr2 have the same IP
1090  * address.
1091  *
1092  * Since: 2.26
1093  **/
1094 gboolean
soup_address_equal_by_ip(gconstpointer addr1,gconstpointer addr2)1095 soup_address_equal_by_ip (gconstpointer addr1, gconstpointer addr2)
1096 {
1097 	SoupAddressPrivate *priv1 = soup_address_get_instance_private (SOUP_ADDRESS (addr1));
1098 	SoupAddressPrivate *priv2 = soup_address_get_instance_private (SOUP_ADDRESS (addr2));
1099 	int size;
1100 
1101 	g_return_val_if_fail (priv1->sockaddr != NULL, FALSE);
1102 	g_return_val_if_fail (priv2->sockaddr != NULL, FALSE);
1103 
1104 	size = SOUP_ADDRESS_FAMILY_SOCKADDR_SIZE (priv1->sockaddr->ss_family);
1105 	return (priv1->sockaddr->ss_family ==
1106 		priv2->sockaddr->ss_family &&
1107 		!memcmp (priv1->sockaddr, priv2->sockaddr, size));
1108 }
1109 
1110 
1111 #define SOUP_TYPE_ADDRESS_ADDRESS_ENUMERATOR (_soup_address_address_enumerator_get_type ())
1112 #define SOUP_ADDRESS_ADDRESS_ENUMERATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SOUP_TYPE_ADDRESS_ADDRESS_ENUMERATOR, SoupAddressAddressEnumerator))
1113 
1114 typedef struct {
1115 	GSocketAddressEnumerator parent_instance;
1116 
1117 	SoupAddress *addr;
1118 	int orig_offset;
1119 	int n;
1120 } SoupAddressAddressEnumerator;
1121 
1122 typedef struct {
1123 	GSocketAddressEnumeratorClass parent_class;
1124 
1125 } SoupAddressAddressEnumeratorClass;
1126 
1127 GType _soup_address_address_enumerator_get_type (void);
G_DEFINE_TYPE(SoupAddressAddressEnumerator,_soup_address_address_enumerator,G_TYPE_SOCKET_ADDRESS_ENUMERATOR)1128 G_DEFINE_TYPE (SoupAddressAddressEnumerator, _soup_address_address_enumerator, G_TYPE_SOCKET_ADDRESS_ENUMERATOR)
1129 
1130 static void
1131 soup_address_address_enumerator_finalize (GObject *object)
1132 {
1133 	SoupAddressAddressEnumerator *addr_enum =
1134 		SOUP_ADDRESS_ADDRESS_ENUMERATOR (object);
1135 
1136 	g_object_unref (addr_enum->addr);
1137 
1138 	G_OBJECT_CLASS (_soup_address_address_enumerator_parent_class)->finalize (object);
1139 }
1140 
1141 static GSocketAddress *
next_address(SoupAddressAddressEnumerator * addr_enum)1142 next_address (SoupAddressAddressEnumerator *addr_enum)
1143 {
1144 	SoupAddressPrivate *priv = soup_address_get_instance_private (addr_enum->addr);
1145 	struct sockaddr_storage *ss;
1146 	int next_addr;
1147 
1148 	/* If there are two addresses but the first one is unusable
1149 	 * (eg, it's IPv6 and we can only do IPv4), then we don't want to
1150 	 * try the bad one every time. So we use priv->offset to remember
1151 	 * the offset of the first usable address (ie, the first address
1152 	 * that we weren't called again after returning).
1153 	 */
1154 	next_addr = (addr_enum->orig_offset + addr_enum->n) % priv->n_addrs;
1155 	priv->offset = next_addr;
1156 
1157 	if (addr_enum->n >= priv->n_addrs)
1158 		return NULL;
1159 	addr_enum->n++;
1160 
1161 	ss = &priv->sockaddr[next_addr];
1162 	return g_socket_address_new_from_native (ss, SOUP_ADDRESS_FAMILY_SOCKADDR_SIZE (ss->ss_family));
1163 }
1164 
1165 static GSocketAddress *
soup_address_address_enumerator_next(GSocketAddressEnumerator * enumerator,GCancellable * cancellable,GError ** error)1166 soup_address_address_enumerator_next (GSocketAddressEnumerator  *enumerator,
1167 				      GCancellable              *cancellable,
1168 				      GError                   **error)
1169 {
1170 	SoupAddressAddressEnumerator *addr_enum =
1171 		SOUP_ADDRESS_ADDRESS_ENUMERATOR (enumerator);
1172 	SoupAddressPrivate *priv = soup_address_get_instance_private (addr_enum->addr);
1173 
1174 	if (!priv->sockaddr) {
1175 		if (resolve_sync_internal (addr_enum->addr, cancellable, error) != SOUP_STATUS_OK)
1176 			return NULL;
1177 	}
1178 
1179 	return next_address (addr_enum);
1180 }
1181 
1182 static void
got_addresses(SoupAddress * addr,guint status,gpointer user_data)1183 got_addresses (SoupAddress *addr, guint status, gpointer user_data)
1184 {
1185 	GTask *task = user_data;
1186 	GError *error;
1187 
1188 	error = g_object_get_data (G_OBJECT (addr), "async-resolved-error");
1189 	if (error)
1190 		g_task_return_error (task, g_error_copy (error));
1191 	else {
1192 		GSocketAddress *socket_addr;
1193 
1194 		socket_addr = next_address (g_task_get_source_object (task));
1195 		g_task_return_pointer (task, socket_addr, g_object_unref);
1196 	}
1197 	g_object_unref (task);
1198 }
1199 
1200 static void
soup_address_address_enumerator_next_async(GSocketAddressEnumerator * enumerator,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1201 soup_address_address_enumerator_next_async (GSocketAddressEnumerator  *enumerator,
1202 					    GCancellable              *cancellable,
1203 					    GAsyncReadyCallback        callback,
1204 					    gpointer                   user_data)
1205 {
1206 	SoupAddressAddressEnumerator *addr_enum =
1207 		SOUP_ADDRESS_ADDRESS_ENUMERATOR (enumerator);
1208 	SoupAddressPrivate *priv = soup_address_get_instance_private (addr_enum->addr);
1209 	GTask *task;
1210 
1211 	task = g_task_new (enumerator, cancellable, callback, user_data);
1212 	if (!priv->sockaddr) {
1213 		soup_address_resolve_async (addr_enum->addr,
1214 					    g_main_context_get_thread_default (),
1215 					    cancellable, got_addresses, task);
1216 	} else {
1217 		g_task_return_pointer (task, next_address (addr_enum), g_object_unref);
1218 		g_object_unref (task);
1219 	}
1220 }
1221 
1222 static GSocketAddress *
soup_address_address_enumerator_next_finish(GSocketAddressEnumerator * enumerator,GAsyncResult * result,GError ** error)1223 soup_address_address_enumerator_next_finish (GSocketAddressEnumerator  *enumerator,
1224 					     GAsyncResult              *result,
1225 					     GError                   **error)
1226 {
1227 	return g_task_propagate_pointer (G_TASK (result), error);
1228 }
1229 
1230 static void
_soup_address_address_enumerator_init(SoupAddressAddressEnumerator * enumerator)1231 _soup_address_address_enumerator_init (SoupAddressAddressEnumerator *enumerator)
1232 {
1233 }
1234 
1235 static void
_soup_address_address_enumerator_class_init(SoupAddressAddressEnumeratorClass * addrenum_class)1236 _soup_address_address_enumerator_class_init (SoupAddressAddressEnumeratorClass *addrenum_class)
1237 {
1238 	GObjectClass *object_class = G_OBJECT_CLASS (addrenum_class);
1239 	GSocketAddressEnumeratorClass *enumerator_class =
1240 		G_SOCKET_ADDRESS_ENUMERATOR_CLASS (addrenum_class);
1241 
1242 	enumerator_class->next = soup_address_address_enumerator_next;
1243 	enumerator_class->next_async = soup_address_address_enumerator_next_async;
1244 	enumerator_class->next_finish = soup_address_address_enumerator_next_finish;
1245 	object_class->finalize = soup_address_address_enumerator_finalize;
1246 }
1247 
1248 static GSocketAddressEnumerator *
soup_address_connectable_enumerate(GSocketConnectable * connectable)1249 soup_address_connectable_enumerate (GSocketConnectable *connectable)
1250 {
1251 	SoupAddressAddressEnumerator *addr_enum;
1252 	SoupAddressPrivate *priv;
1253 
1254 	addr_enum = g_object_new (SOUP_TYPE_ADDRESS_ADDRESS_ENUMERATOR, NULL);
1255 	addr_enum->addr = g_object_ref (SOUP_ADDRESS (connectable));
1256 
1257 	priv = soup_address_get_instance_private (addr_enum->addr);
1258 	addr_enum->orig_offset = priv->offset;
1259 
1260 	return (GSocketAddressEnumerator *)addr_enum;
1261 }
1262 
1263 static GSocketAddressEnumerator *
soup_address_connectable_proxy_enumerate(GSocketConnectable * connectable)1264 soup_address_connectable_proxy_enumerate (GSocketConnectable *connectable)
1265 {
1266 	SoupAddress *addr = SOUP_ADDRESS (connectable);
1267 	SoupAddressPrivate *priv = soup_address_get_instance_private (addr);
1268 	GSocketAddressEnumerator *proxy_enum;
1269 	SoupURI *uri;
1270 	char *uri_string;
1271 
1272 	/* We cheerily assume "http" here because you shouldn't be
1273 	 * using SoupAddress any more if you're not doing HTTP anyway.
1274 	 */
1275 	uri = soup_uri_new (NULL);
1276 	soup_uri_set_scheme (uri, priv->protocol ? priv->protocol : "http");
1277 	soup_uri_set_host (uri, priv->name ? priv->name : soup_address_get_physical (addr));
1278 	soup_uri_set_port (uri, priv->port);
1279 	soup_uri_set_path (uri, "");
1280 	uri_string = soup_uri_to_string_internal (uri, FALSE, FALSE, TRUE);
1281 
1282 	proxy_enum = g_object_new (G_TYPE_PROXY_ADDRESS_ENUMERATOR,
1283 				   "connectable", connectable,
1284 				   "uri", uri_string,
1285 				   NULL);
1286 	g_free (uri_string);
1287 	soup_uri_free (uri);
1288 
1289 	return proxy_enum;
1290 }
1291 
1292 static void
soup_address_connectable_iface_init(GSocketConnectableIface * connectable_iface)1293 soup_address_connectable_iface_init (GSocketConnectableIface *connectable_iface)
1294 {
1295   connectable_iface->enumerate       = soup_address_connectable_enumerate;
1296   connectable_iface->proxy_enumerate = soup_address_connectable_proxy_enumerate;
1297 }
1298