nexmon – Blame information for rev 1

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