Branch data Line data Source code
1 : : /* GIO - GLib Input, Output and Streaming Library
2 : : *
3 : : * Copyright (C) 2010 Collabora, Ltd.
4 : : *
5 : : * SPDX-License-Identifier: LGPL-2.1-or-later
6 : : *
7 : : * This library is free software; you can redistribute it and/or
8 : : * modify it under the terms of the GNU Lesser General Public
9 : : * License as published by the Free Software Foundation; either
10 : : * version 2.1 of the License, or (at your option) any later version.
11 : : *
12 : : * This library is distributed in the hope that it will be useful,
13 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : * Lesser General Public License for more details.
16 : : *
17 : : * You should have received a copy of the GNU Lesser General
18 : : * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 : : *
20 : : * Author: Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
21 : : */
22 : :
23 : : #include "config.h"
24 : : #include "gproxyaddressenumerator.h"
25 : :
26 : : #include <string.h>
27 : :
28 : : #include "gasyncresult.h"
29 : : #include "ginetaddress.h"
30 : : #include "gioerror.h"
31 : : #include "glibintl.h"
32 : : #include "glib-private.h"
33 : : #include "gnetworkaddress.h"
34 : : #include "gnetworkingprivate.h"
35 : : #include "gproxy.h"
36 : : #include "gproxyaddress.h"
37 : : #include "gproxyresolver.h"
38 : : #include "gtask.h"
39 : : #include "gresolver.h"
40 : : #include "gsocketaddress.h"
41 : : #include "gsocketaddressenumerator.h"
42 : : #include "gsocketconnectable.h"
43 : :
44 : : /**
45 : : * GProxyAddressEnumerator:
46 : : *
47 : : * `GProxyAddressEnumerator` is a wrapper around
48 : : * [class@Gio.SocketAddressEnumerator] which takes the [class@Gio.SocketAddress]
49 : : * instances returned by the [class@Gio.SocketAddressEnumerator]
50 : : * and wraps them in [class@Gio.ProxyAddress] instances, using the given
51 : : * [property@Gio.ProxyAddressEnumerator:proxy-resolver].
52 : : *
53 : : * This enumerator will be returned (for example, by
54 : : * [method@Gio.SocketConnectable.enumerate]) as appropriate when a proxy is
55 : : * configured; there should be no need to manually wrap a
56 : : * [class@Gio.SocketAddressEnumerator] instance with one.
57 : : */
58 : :
59 : : #define GET_PRIVATE(o) (G_PROXY_ADDRESS_ENUMERATOR (o)->priv)
60 : :
61 : : enum
62 : : {
63 : : PROP_0,
64 : : PROP_URI,
65 : : PROP_DEFAULT_PORT,
66 : : PROP_CONNECTABLE,
67 : : PROP_PROXY_RESOLVER
68 : : };
69 : :
70 : : struct _GProxyAddressEnumeratorPrivate
71 : : {
72 : : /* Destination address */
73 : : GSocketConnectable *connectable;
74 : : gchar *dest_uri;
75 : : guint16 default_port;
76 : : gchar *dest_hostname;
77 : : guint16 dest_port;
78 : : GList *dest_ips;
79 : :
80 : : /* Proxy enumeration */
81 : : GProxyResolver *proxy_resolver;
82 : : gchar **proxies;
83 : : gchar **next_proxy;
84 : : GSocketAddressEnumerator *addr_enum;
85 : : GSocketAddress *proxy_address;
86 : : const gchar *proxy_uri;
87 : : gchar *proxy_type;
88 : : gchar *proxy_username;
89 : : gchar *proxy_password;
90 : : gboolean supports_hostname;
91 : : GList *next_dest_ip;
92 : : GError *last_error;
93 : :
94 : : /* ever_enumerated is TRUE after we've returned a result for the first time
95 : : * via g_proxy_address_enumerator_next() or _next_async(). If FALSE, we have
96 : : * never returned yet, and should return an error if returning NULL because
97 : : * it does not make sense for a proxy resolver to return NULL except on error.
98 : : * (Whereas a DNS resolver would return NULL with no error to indicate "no
99 : : * results", a proxy resolver would want to return "direct://" instead, so
100 : : * NULL without error does not make sense for us.)
101 : : *
102 : : * But if ever_enumerated is TRUE, then we must not report any further errors
103 : : * (except for G_IO_ERROR_CANCELLED), because this is an API contract of
104 : : * GSocketAddressEnumerator.
105 : : */
106 : : gboolean ever_enumerated;
107 : : };
108 : :
109 : 4479 : G_DEFINE_TYPE_WITH_PRIVATE (GProxyAddressEnumerator, g_proxy_address_enumerator, G_TYPE_SOCKET_ADDRESS_ENUMERATOR)
110 : :
111 : : static void
112 : 28 : save_userinfo (GProxyAddressEnumeratorPrivate *priv,
113 : : const gchar *proxy)
114 : : {
115 : 28 : g_clear_pointer (&priv->proxy_username, g_free);
116 : 28 : g_clear_pointer (&priv->proxy_password, g_free);
117 : :
118 : 28 : g_uri_split_with_user (proxy, G_URI_FLAGS_HAS_PASSWORD, NULL,
119 : : &priv->proxy_username, &priv->proxy_password,
120 : : NULL, NULL, NULL, NULL, NULL, NULL, NULL);
121 : 28 : }
122 : :
123 : : static void
124 : 557 : next_enumerator (GProxyAddressEnumeratorPrivate *priv)
125 : : {
126 : 557 : if (priv->proxy_address)
127 : 0 : return;
128 : :
129 : 1026 : while (priv->addr_enum == NULL && *priv->next_proxy)
130 : : {
131 : 469 : GSocketConnectable *connectable = NULL;
132 : : GProxy *proxy;
133 : :
134 : 469 : priv->proxy_uri = *priv->next_proxy++;
135 : 469 : g_free (priv->proxy_type);
136 : 469 : priv->proxy_type = g_uri_parse_scheme (priv->proxy_uri);
137 : :
138 : 469 : if (priv->proxy_type == NULL)
139 : 6 : continue;
140 : :
141 : : /* Assumes hostnames are supported for unknown protocols */
142 : 463 : priv->supports_hostname = TRUE;
143 : 463 : proxy = g_proxy_get_default_for_protocol (priv->proxy_type);
144 : 463 : if (proxy)
145 : : {
146 : 28 : priv->supports_hostname = g_proxy_supports_hostname (proxy);
147 : 28 : g_object_unref (proxy);
148 : : }
149 : :
150 : 463 : if (strcmp ("direct", priv->proxy_type) == 0)
151 : : {
152 : 435 : if (priv->connectable)
153 : 435 : connectable = g_object_ref (priv->connectable);
154 : : else
155 : 0 : connectable = g_network_address_new (priv->dest_hostname,
156 : 0 : priv->dest_port);
157 : : }
158 : : else
159 : : {
160 : 28 : GError *error = NULL;
161 : : int default_port;
162 : :
163 : 28 : default_port = GLIB_PRIVATE_CALL (g_uri_get_default_scheme_port) (priv->proxy_type);
164 : 28 : if (default_port == -1)
165 : 28 : default_port = 0;
166 : :
167 : 28 : connectable = g_network_address_parse_uri (priv->proxy_uri, default_port, &error);
168 : 28 : if (error)
169 : : {
170 : 0 : g_warning ("Invalid proxy URI '%s': %s",
171 : : priv->proxy_uri, error->message);
172 : 0 : g_error_free (error);
173 : : }
174 : :
175 : 28 : save_userinfo (priv, priv->proxy_uri);
176 : : }
177 : :
178 : 463 : if (connectable)
179 : : {
180 : 463 : priv->addr_enum = g_socket_connectable_enumerate (connectable);
181 : 463 : g_object_unref (connectable);
182 : : }
183 : : }
184 : : }
185 : :
186 : : static GSocketAddress *
187 : 314 : g_proxy_address_enumerator_next (GSocketAddressEnumerator *enumerator,
188 : : GCancellable *cancellable,
189 : : GError **error)
190 : : {
191 : 314 : GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (enumerator);
192 : 314 : GSocketAddress *result = NULL;
193 : 314 : GError *first_error = NULL;
194 : :
195 : 314 : if (!priv->ever_enumerated)
196 : : {
197 : 226 : g_assert (priv->proxies == NULL);
198 : 452 : priv->proxies = g_proxy_resolver_lookup (priv->proxy_resolver,
199 : 226 : priv->dest_uri,
200 : : cancellable,
201 : : error);
202 : 226 : priv->next_proxy = priv->proxies;
203 : :
204 : 226 : if (priv->proxies == NULL)
205 : : {
206 : 0 : priv->ever_enumerated = TRUE;
207 : 0 : return NULL;
208 : : }
209 : : }
210 : :
211 : 637 : while (result == NULL && (*priv->next_proxy || priv->addr_enum))
212 : : {
213 : : gchar *dest_hostname;
214 : : gchar *dest_protocol;
215 : : GInetSocketAddress *inetsaddr;
216 : : GInetAddress *inetaddr;
217 : : guint16 port;
218 : :
219 : 323 : next_enumerator (priv);
220 : :
221 : 323 : if (!priv->addr_enum)
222 : 2 : continue;
223 : :
224 : 321 : if (priv->proxy_address == NULL)
225 : : {
226 : 321 : priv->proxy_address = g_socket_address_enumerator_next (
227 : : priv->addr_enum,
228 : : cancellable,
229 : 321 : first_error ? NULL : &first_error);
230 : : }
231 : :
232 : 321 : if (priv->proxy_address == NULL)
233 : : {
234 : 91 : g_object_unref (priv->addr_enum);
235 : 91 : priv->addr_enum = NULL;
236 : :
237 : 91 : if (priv->dest_ips)
238 : : {
239 : 7 : g_resolver_free_addresses (priv->dest_ips);
240 : 7 : priv->dest_ips = NULL;
241 : : }
242 : :
243 : 91 : continue;
244 : : }
245 : :
246 : 230 : if (strcmp ("direct", priv->proxy_type) == 0)
247 : : {
248 : 212 : result = priv->proxy_address;
249 : 212 : priv->proxy_address = NULL;
250 : 212 : continue;
251 : : }
252 : :
253 : 18 : if (!priv->supports_hostname)
254 : : {
255 : : GInetAddress *dest_ip;
256 : :
257 : 11 : if (!priv->dest_ips)
258 : : {
259 : : GResolver *resolver;
260 : :
261 : 11 : resolver = g_resolver_get_default();
262 : 11 : priv->dest_ips = g_resolver_lookup_by_name (resolver,
263 : 11 : priv->dest_hostname,
264 : : cancellable,
265 : 11 : first_error ? NULL : &first_error);
266 : 11 : g_object_unref (resolver);
267 : :
268 : 11 : if (!priv->dest_ips)
269 : : {
270 : 2 : g_object_unref (priv->proxy_address);
271 : 2 : priv->proxy_address = NULL;
272 : 2 : continue;
273 : : }
274 : : }
275 : :
276 : 9 : if (!priv->next_dest_ip)
277 : 9 : priv->next_dest_ip = priv->dest_ips;
278 : :
279 : 9 : dest_ip = G_INET_ADDRESS (priv->next_dest_ip->data);
280 : 9 : dest_hostname = g_inet_address_to_string (dest_ip);
281 : :
282 : 9 : priv->next_dest_ip = g_list_next (priv->next_dest_ip);
283 : : }
284 : : else
285 : : {
286 : 14 : dest_hostname = g_strdup (priv->dest_hostname);
287 : : }
288 : :
289 : 16 : g_assert (G_IS_INET_SOCKET_ADDRESS (priv->proxy_address));
290 : :
291 : 16 : dest_protocol = g_uri_parse_scheme (priv->dest_uri);
292 : :
293 : 16 : inetsaddr = G_INET_SOCKET_ADDRESS (priv->proxy_address);
294 : 16 : inetaddr = g_inet_socket_address_get_address (inetsaddr);
295 : 16 : port = g_inet_socket_address_get_port (inetsaddr);
296 : :
297 : 16 : result = g_object_new (G_TYPE_PROXY_ADDRESS,
298 : : "address", inetaddr,
299 : : "port", port,
300 : : "protocol", priv->proxy_type,
301 : : "destination-protocol", dest_protocol,
302 : : "destination-hostname", dest_hostname,
303 : 16 : "destination-port", priv->dest_port,
304 : : "username", priv->proxy_username,
305 : : "password", priv->proxy_password,
306 : : "uri", priv->proxy_uri,
307 : : NULL);
308 : 16 : g_free (dest_hostname);
309 : 16 : g_free (dest_protocol);
310 : :
311 : 16 : if (priv->supports_hostname || priv->next_dest_ip == NULL)
312 : : {
313 : 16 : g_object_unref (priv->proxy_address);
314 : 16 : priv->proxy_address = NULL;
315 : : }
316 : : }
317 : :
318 : 314 : if (result == NULL && first_error && (!priv->ever_enumerated || g_error_matches (first_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)))
319 : 1 : g_propagate_error (error, first_error);
320 : 313 : else if (first_error)
321 : 2 : g_error_free (first_error);
322 : :
323 : 314 : if (result == NULL && error != NULL && *error == NULL && !priv->ever_enumerated)
324 : 2 : g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Unspecified proxy lookup failure"));
325 : :
326 : 314 : priv->ever_enumerated = TRUE;
327 : :
328 : 314 : return result;
329 : : }
330 : :
331 : : static void
332 : 86 : complete_async (GTask *task)
333 : : {
334 : 86 : GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
335 : :
336 : 86 : if (priv->last_error && (!priv->ever_enumerated || g_error_matches (priv->last_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)))
337 : : {
338 : 4 : g_task_return_error (task, priv->last_error);
339 : 4 : priv->last_error = NULL;
340 : : }
341 : 82 : else if (!priv->ever_enumerated)
342 : : {
343 : 2 : g_task_return_new_error_literal (task, G_IO_ERROR, G_IO_ERROR_FAILED,
344 : 2 : _("Unspecified proxy lookup failure"));
345 : : }
346 : : else
347 : : {
348 : 80 : g_task_return_pointer (task, NULL, NULL);
349 : : }
350 : :
351 : 86 : priv->ever_enumerated = TRUE;
352 : :
353 : 86 : g_clear_error (&priv->last_error);
354 : 86 : g_object_unref (task);
355 : 86 : }
356 : :
357 : : static void
358 : 230 : return_result (GTask *task)
359 : : {
360 : 230 : GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
361 : : GSocketAddress *result;
362 : :
363 : 230 : if (strcmp ("direct", priv->proxy_type) == 0)
364 : : {
365 : 222 : result = priv->proxy_address;
366 : 222 : priv->proxy_address = NULL;
367 : : }
368 : : else
369 : : {
370 : : gchar *dest_hostname, *dest_protocol;
371 : : GInetSocketAddress *inetsaddr;
372 : : GInetAddress *inetaddr;
373 : : guint16 port;
374 : :
375 : 8 : if (!priv->supports_hostname)
376 : : {
377 : : GInetAddress *dest_ip;
378 : :
379 : 5 : if (!priv->next_dest_ip)
380 : 5 : priv->next_dest_ip = priv->dest_ips;
381 : :
382 : 5 : dest_ip = G_INET_ADDRESS (priv->next_dest_ip->data);
383 : 5 : dest_hostname = g_inet_address_to_string (dest_ip);
384 : :
385 : 5 : priv->next_dest_ip = g_list_next (priv->next_dest_ip);
386 : : }
387 : : else
388 : : {
389 : 6 : dest_hostname = g_strdup (priv->dest_hostname);
390 : : }
391 : 8 : dest_protocol = g_uri_parse_scheme (priv->dest_uri);
392 : :
393 : 8 : g_assert (G_IS_INET_SOCKET_ADDRESS (priv->proxy_address));
394 : :
395 : 8 : inetsaddr = G_INET_SOCKET_ADDRESS (priv->proxy_address);
396 : 8 : inetaddr = g_inet_socket_address_get_address (inetsaddr);
397 : 8 : port = g_inet_socket_address_get_port (inetsaddr);
398 : :
399 : 8 : result = g_object_new (G_TYPE_PROXY_ADDRESS,
400 : : "address", inetaddr,
401 : : "port", port,
402 : : "protocol", priv->proxy_type,
403 : : "destination-protocol", dest_protocol,
404 : : "destination-hostname", dest_hostname,
405 : 8 : "destination-port", priv->dest_port,
406 : : "username", priv->proxy_username,
407 : : "password", priv->proxy_password,
408 : : "uri", priv->proxy_uri,
409 : : NULL);
410 : 8 : g_free (dest_hostname);
411 : 8 : g_free (dest_protocol);
412 : :
413 : 8 : if (priv->supports_hostname || priv->next_dest_ip == NULL)
414 : : {
415 : 8 : g_object_unref (priv->proxy_address);
416 : 8 : priv->proxy_address = NULL;
417 : : }
418 : : }
419 : :
420 : 230 : priv->ever_enumerated = TRUE;
421 : 230 : g_task_return_pointer (task, result, g_object_unref);
422 : 230 : g_object_unref (task);
423 : 230 : }
424 : :
425 : : static void address_enumerate_cb (GObject *object,
426 : : GAsyncResult *result,
427 : : gpointer user_data);
428 : :
429 : : static void
430 : 86 : next_proxy (GTask *task)
431 : : {
432 : 86 : GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
433 : :
434 : 86 : if (*priv->next_proxy)
435 : : {
436 : 3 : g_object_unref (priv->addr_enum);
437 : 3 : priv->addr_enum = NULL;
438 : :
439 : 3 : if (priv->dest_ips)
440 : : {
441 : 1 : g_resolver_free_addresses (priv->dest_ips);
442 : 1 : priv->dest_ips = NULL;
443 : : }
444 : :
445 : 3 : next_enumerator (priv);
446 : :
447 : 3 : if (priv->addr_enum)
448 : : {
449 : 3 : g_socket_address_enumerator_next_async (priv->addr_enum,
450 : : g_task_get_cancellable (task),
451 : : address_enumerate_cb,
452 : : task);
453 : 3 : return;
454 : : }
455 : : }
456 : :
457 : 83 : complete_async (task);
458 : : }
459 : :
460 : : static void
461 : 7 : dest_hostname_lookup_cb (GObject *object,
462 : : GAsyncResult *result,
463 : : gpointer user_data)
464 : : {
465 : 7 : GTask *task = user_data;
466 : 7 : GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
467 : :
468 : 7 : g_clear_error (&priv->last_error);
469 : 7 : priv->dest_ips = g_resolver_lookup_by_name_finish (G_RESOLVER (object),
470 : : result,
471 : : &priv->last_error);
472 : 7 : if (priv->dest_ips)
473 : 5 : return_result (task);
474 : : else
475 : : {
476 : 2 : g_clear_object (&priv->proxy_address);
477 : 2 : next_proxy (task);
478 : : }
479 : 7 : }
480 : :
481 : : static void
482 : 316 : address_enumerate_cb (GObject *object,
483 : : GAsyncResult *result,
484 : : gpointer user_data)
485 : : {
486 : 316 : GTask *task = user_data;
487 : 316 : GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
488 : :
489 : 316 : g_clear_error (&priv->last_error);
490 : 316 : priv->proxy_address =
491 : 316 : g_socket_address_enumerator_next_finish (priv->addr_enum,
492 : : result,
493 : : &priv->last_error);
494 : 316 : if (priv->proxy_address)
495 : : {
496 : 232 : if (!priv->supports_hostname && !priv->dest_ips)
497 : : {
498 : : GResolver *resolver;
499 : 7 : resolver = g_resolver_get_default();
500 : 7 : g_resolver_lookup_by_name_async (resolver,
501 : 7 : priv->dest_hostname,
502 : : g_task_get_cancellable (task),
503 : : dest_hostname_lookup_cb,
504 : : task);
505 : 7 : g_object_unref (resolver);
506 : 7 : return;
507 : : }
508 : :
509 : 225 : return_result (task);
510 : : }
511 : : else
512 : 84 : next_proxy (task);
513 : : }
514 : :
515 : : static void
516 : 232 : proxy_lookup_cb (GObject *object,
517 : : GAsyncResult *result,
518 : : gpointer user_data)
519 : : {
520 : 232 : GTask *task = user_data;
521 : 232 : GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
522 : :
523 : 232 : g_clear_error (&priv->last_error);
524 : 232 : priv->proxies = g_proxy_resolver_lookup_finish (G_PROXY_RESOLVER (object),
525 : : result,
526 : : &priv->last_error);
527 : 232 : priv->next_proxy = priv->proxies;
528 : :
529 : 232 : if (priv->last_error)
530 : : {
531 : 1 : complete_async (task);
532 : 1 : return;
533 : : }
534 : : else
535 : : {
536 : 231 : next_enumerator (priv);
537 : 231 : if (priv->addr_enum)
538 : : {
539 : 229 : g_socket_address_enumerator_next_async (priv->addr_enum,
540 : : g_task_get_cancellable (task),
541 : : address_enumerate_cb,
542 : : task);
543 : 229 : return;
544 : : }
545 : : }
546 : :
547 : 2 : complete_async (task);
548 : : }
549 : :
550 : : static void
551 : 316 : g_proxy_address_enumerator_next_async (GSocketAddressEnumerator *enumerator,
552 : : GCancellable *cancellable,
553 : : GAsyncReadyCallback callback,
554 : : gpointer user_data)
555 : : {
556 : 316 : GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (enumerator);
557 : : GTask *task;
558 : :
559 : 316 : task = g_task_new (enumerator, cancellable, callback, user_data);
560 : 316 : g_task_set_source_tag (task, g_proxy_address_enumerator_next_async);
561 : 316 : g_task_set_task_data (task, priv, NULL);
562 : :
563 : 316 : if (priv->proxies == NULL)
564 : : {
565 : 232 : g_proxy_resolver_lookup_async (priv->proxy_resolver,
566 : 232 : priv->dest_uri,
567 : : cancellable,
568 : : proxy_lookup_cb,
569 : : task);
570 : 232 : return;
571 : : }
572 : :
573 : 84 : if (priv->addr_enum)
574 : : {
575 : 84 : if (priv->proxy_address)
576 : : {
577 : 0 : return_result (task);
578 : 0 : return;
579 : : }
580 : : else
581 : : {
582 : 84 : g_socket_address_enumerator_next_async (priv->addr_enum,
583 : : cancellable,
584 : : address_enumerate_cb,
585 : : task);
586 : 84 : return;
587 : : }
588 : : }
589 : :
590 : 0 : complete_async (task);
591 : : }
592 : :
593 : : static GSocketAddress *
594 : 313 : g_proxy_address_enumerator_next_finish (GSocketAddressEnumerator *enumerator,
595 : : GAsyncResult *result,
596 : : GError **error)
597 : : {
598 : 313 : g_return_val_if_fail (g_task_is_valid (result, enumerator), NULL);
599 : :
600 : 313 : return g_task_propagate_pointer (G_TASK (result), error);
601 : : }
602 : :
603 : : static void
604 : 459 : g_proxy_address_enumerator_constructed (GObject *object)
605 : : {
606 : 459 : GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
607 : : GSocketConnectable *conn;
608 : : guint port;
609 : :
610 : 459 : if (priv->dest_uri)
611 : : {
612 : 458 : conn = g_network_address_parse_uri (priv->dest_uri, priv->default_port, NULL);
613 : 458 : if (conn)
614 : : {
615 : 458 : g_object_get (conn,
616 : : "hostname", &priv->dest_hostname,
617 : : "port", &port,
618 : : NULL);
619 : 458 : priv->dest_port = port;
620 : :
621 : 458 : g_object_unref (conn);
622 : : }
623 : : else
624 : 0 : g_warning ("Invalid URI '%s'", priv->dest_uri);
625 : : }
626 : :
627 : 459 : G_OBJECT_CLASS (g_proxy_address_enumerator_parent_class)->constructed (object);
628 : 459 : }
629 : :
630 : : static void
631 : 3 : g_proxy_address_enumerator_get_property (GObject *object,
632 : : guint property_id,
633 : : GValue *value,
634 : : GParamSpec *pspec)
635 : : {
636 : 3 : GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
637 : 3 : switch (property_id)
638 : : {
639 : 1 : case PROP_URI:
640 : 1 : g_value_set_string (value, priv->dest_uri);
641 : 1 : break;
642 : :
643 : 1 : case PROP_DEFAULT_PORT:
644 : 1 : g_value_set_uint (value, priv->default_port);
645 : 1 : break;
646 : :
647 : 1 : case PROP_CONNECTABLE:
648 : 1 : g_value_set_object (value, priv->connectable);
649 : 1 : break;
650 : :
651 : 0 : case PROP_PROXY_RESOLVER:
652 : 0 : g_value_set_object (value, priv->proxy_resolver);
653 : 0 : break;
654 : :
655 : 0 : default:
656 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
657 : : }
658 : 3 : }
659 : :
660 : : static void
661 : 1842 : g_proxy_address_enumerator_set_property (GObject *object,
662 : : guint property_id,
663 : : const GValue *value,
664 : : GParamSpec *pspec)
665 : : {
666 : 1842 : GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
667 : 1842 : switch (property_id)
668 : : {
669 : 459 : case PROP_URI:
670 : 459 : priv->dest_uri = g_value_dup_string (value);
671 : 459 : break;
672 : :
673 : 459 : case PROP_DEFAULT_PORT:
674 : 459 : priv->default_port = g_value_get_uint (value);
675 : 459 : break;
676 : :
677 : 459 : case PROP_CONNECTABLE:
678 : 459 : priv->connectable = g_value_dup_object (value);
679 : 459 : break;
680 : :
681 : 465 : case PROP_PROXY_RESOLVER:
682 : 465 : if (priv->proxy_resolver)
683 : 6 : g_object_unref (priv->proxy_resolver);
684 : 465 : priv->proxy_resolver = g_value_get_object (value);
685 : 465 : if (!priv->proxy_resolver)
686 : 459 : priv->proxy_resolver = g_proxy_resolver_get_default ();
687 : 465 : g_object_ref (priv->proxy_resolver);
688 : 465 : break;
689 : :
690 : 0 : default:
691 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
692 : : }
693 : 1842 : }
694 : :
695 : : static void
696 : 458 : g_proxy_address_enumerator_finalize (GObject *object)
697 : : {
698 : 458 : GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
699 : :
700 : 458 : if (priv->connectable)
701 : 453 : g_object_unref (priv->connectable);
702 : :
703 : 458 : if (priv->proxy_resolver)
704 : 458 : g_object_unref (priv->proxy_resolver);
705 : :
706 : 458 : g_free (priv->dest_uri);
707 : 458 : g_free (priv->dest_hostname);
708 : :
709 : 458 : if (priv->dest_ips)
710 : 6 : g_resolver_free_addresses (priv->dest_ips);
711 : :
712 : 458 : g_strfreev (priv->proxies);
713 : :
714 : 458 : if (priv->addr_enum)
715 : 368 : g_object_unref (priv->addr_enum);
716 : :
717 : 458 : g_free (priv->proxy_type);
718 : 458 : g_free (priv->proxy_username);
719 : 458 : g_free (priv->proxy_password);
720 : :
721 : 458 : g_clear_error (&priv->last_error);
722 : :
723 : 458 : G_OBJECT_CLASS (g_proxy_address_enumerator_parent_class)->finalize (object);
724 : 458 : }
725 : :
726 : : static void
727 : 459 : g_proxy_address_enumerator_init (GProxyAddressEnumerator *self)
728 : : {
729 : 459 : self->priv = g_proxy_address_enumerator_get_instance_private (self);
730 : 459 : }
731 : :
732 : : static void
733 : 8 : g_proxy_address_enumerator_class_init (GProxyAddressEnumeratorClass *proxy_enumerator_class)
734 : : {
735 : 8 : GObjectClass *object_class = G_OBJECT_CLASS (proxy_enumerator_class);
736 : 8 : GSocketAddressEnumeratorClass *enumerator_class = G_SOCKET_ADDRESS_ENUMERATOR_CLASS (proxy_enumerator_class);
737 : :
738 : 8 : object_class->constructed = g_proxy_address_enumerator_constructed;
739 : 8 : object_class->set_property = g_proxy_address_enumerator_set_property;
740 : 8 : object_class->get_property = g_proxy_address_enumerator_get_property;
741 : 8 : object_class->finalize = g_proxy_address_enumerator_finalize;
742 : :
743 : 8 : enumerator_class->next = g_proxy_address_enumerator_next;
744 : 8 : enumerator_class->next_async = g_proxy_address_enumerator_next_async;
745 : 8 : enumerator_class->next_finish = g_proxy_address_enumerator_next_finish;
746 : :
747 : : /**
748 : : * GProxyAddressEnumerator:uri:
749 : : *
750 : : * The destination URI. Use `none://` for a generic socket.
751 : : */
752 : 8 : g_object_class_install_property (object_class,
753 : : PROP_URI,
754 : : g_param_spec_string ("uri", NULL, NULL,
755 : : NULL,
756 : : G_PARAM_READWRITE |
757 : : G_PARAM_CONSTRUCT_ONLY |
758 : : G_PARAM_STATIC_STRINGS));
759 : :
760 : : /**
761 : : * GProxyAddressEnumerator:default-port:
762 : : *
763 : : * The default port to use if #GProxyAddressEnumerator:uri does not
764 : : * specify one.
765 : : *
766 : : * Since: 2.38
767 : : */
768 : 8 : g_object_class_install_property (object_class,
769 : : PROP_DEFAULT_PORT,
770 : : g_param_spec_uint ("default-port", NULL, NULL,
771 : : 0, 65535, 0,
772 : : G_PARAM_READWRITE |
773 : : G_PARAM_CONSTRUCT_ONLY |
774 : : G_PARAM_STATIC_STRINGS));
775 : :
776 : : /**
777 : : * GProxyAddressEnumerator:connectable:
778 : : *
779 : : * The connectable being enumerated.
780 : : */
781 : 8 : g_object_class_install_property (object_class,
782 : : PROP_CONNECTABLE,
783 : : g_param_spec_object ("connectable", NULL, NULL,
784 : : G_TYPE_SOCKET_CONNECTABLE,
785 : : G_PARAM_READWRITE |
786 : : G_PARAM_CONSTRUCT_ONLY |
787 : : G_PARAM_STATIC_STRINGS));
788 : :
789 : : /**
790 : : * GProxyAddressEnumerator:proxy-resolver:
791 : : *
792 : : * The proxy resolver to use.
793 : : *
794 : : * Since: 2.36
795 : : */
796 : 8 : g_object_class_install_property (object_class,
797 : : PROP_PROXY_RESOLVER,
798 : : g_param_spec_object ("proxy-resolver", NULL, NULL,
799 : : G_TYPE_PROXY_RESOLVER,
800 : : G_PARAM_READWRITE |
801 : : G_PARAM_CONSTRUCT |
802 : : G_PARAM_STATIC_STRINGS));
803 : 8 : }
|