1 | /* GLib testing framework examples and tests |
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.1 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 | * Authors: Nicolas Dufresne <nicolas.dufresne@collabora.co.uk> |
19 | */ |
20 | |
21 | #include "config.h" |
22 | |
23 | #include <stdio.h> |
24 | #include <stdlib.h> |
25 | #include <string.h> |
26 | |
27 | #include <gio/gio.h> |
28 | #include <glib.h> |
29 | |
30 | #include "glibintl.h" |
31 | |
32 | #ifdef G_OS_UNIX |
33 | #include "gio/gunixsocketaddress.h" |
34 | #endif |
35 | |
36 | static const gchar *info = NULL; |
37 | static GCancellable *cancellable = NULL; |
38 | static gint return_value = 0; |
39 | |
40 | static G_NORETURN void |
41 | usage (void) |
42 | { |
43 | fprintf (stderr, format: "Usage: proxy [-s] (uri|host:port|ip:port|path|srv/protocol/domain)\n" ); |
44 | fprintf (stderr, format: " Use -t to enable threading.\n" ); |
45 | fprintf (stderr, format: " Use -s to do synchronous lookups.\n" ); |
46 | fprintf (stderr, format: " Use -c to cancel operation.\n" ); |
47 | fprintf (stderr, format: " Use -e to use enumerator.\n" ); |
48 | fprintf (stderr, format: " Use -inet to use GInetSocketAddress enumerator (ip:port).\n" ); |
49 | #ifdef G_OS_UNIX |
50 | fprintf (stderr, format: " Use -unix to use GUnixSocketAddress enumerator (path).\n" ); |
51 | #endif |
52 | fprintf (stderr, format: " Use -proxyaddr tp use GProxyAddress enumerator " |
53 | "(ip:port:protocol:dest_host:dest_port[:username[:password]]).\n" ); |
54 | fprintf (stderr, format: " Use -netaddr to use GNetworkAddress enumerator (host:port).\n" ); |
55 | fprintf (stderr, format: " Use -neturi to use GNetworkAddress enumerator (uri).\n" ); |
56 | fprintf (stderr, format: " Use -netsrv to use GNetworkService enumerator (srv/protocol/domain).\n" ); |
57 | fprintf (stderr, format: " Use -connect to create a connection using GSocketClient object (uri).\n" ); |
58 | exit (status: 1); |
59 | } |
60 | |
61 | static void |
62 | print_and_free_error (GError *error) |
63 | { |
64 | fprintf (stderr, format: "Failed to obtain proxies: %s\n" , error->message); |
65 | g_error_free (error); |
66 | return_value = 1; |
67 | } |
68 | |
69 | static void |
70 | print_proxies (const gchar *info, gchar **proxies) |
71 | { |
72 | printf (format: "Proxies for URI '%s' are:\n" , info); |
73 | |
74 | if (proxies == NULL || proxies[0] == NULL) |
75 | printf (format: "\tnone\n" ); |
76 | else |
77 | for (; proxies[0]; proxies++) |
78 | printf (format: "\t%s\n" , proxies[0]); |
79 | } |
80 | |
81 | static void |
82 | _proxy_lookup_cb (GObject *source_object, |
83 | GAsyncResult *result, |
84 | gpointer user_data) |
85 | { |
86 | GError *error = NULL; |
87 | gchar **proxies; |
88 | GMainLoop *loop = user_data; |
89 | |
90 | proxies = g_proxy_resolver_lookup_finish (G_PROXY_RESOLVER (source_object), |
91 | result, |
92 | error: &error); |
93 | if (error) |
94 | { |
95 | print_and_free_error (error); |
96 | } |
97 | else |
98 | { |
99 | print_proxies (info, proxies); |
100 | g_strfreev (str_array: proxies); |
101 | } |
102 | |
103 | g_main_loop_quit (loop); |
104 | } |
105 | |
106 | static void |
107 | use_resolver (gboolean synchronous) |
108 | { |
109 | GProxyResolver *resolver; |
110 | |
111 | resolver = g_proxy_resolver_get_default (); |
112 | |
113 | if (synchronous) |
114 | { |
115 | GError *error = NULL; |
116 | gchar **proxies; |
117 | |
118 | proxies = g_proxy_resolver_lookup (resolver, uri: info, cancellable, error: &error); |
119 | |
120 | if (error) |
121 | print_and_free_error (error); |
122 | else |
123 | print_proxies (info, proxies); |
124 | |
125 | g_strfreev (str_array: proxies); |
126 | } |
127 | else |
128 | { |
129 | GMainLoop *loop = g_main_loop_new (NULL, FALSE); |
130 | |
131 | g_proxy_resolver_lookup_async (resolver, |
132 | uri: info, |
133 | cancellable, |
134 | callback: _proxy_lookup_cb, |
135 | user_data: loop); |
136 | |
137 | g_main_loop_run (loop); |
138 | g_main_loop_unref (loop); |
139 | } |
140 | } |
141 | |
142 | static void |
143 | print_proxy_address (GSocketAddress *sockaddr) |
144 | { |
145 | GProxyAddress *proxy = NULL; |
146 | |
147 | if (sockaddr == NULL) |
148 | { |
149 | printf (format: "\tdirect://\n" ); |
150 | return; |
151 | } |
152 | |
153 | if (G_IS_PROXY_ADDRESS (sockaddr)) |
154 | { |
155 | proxy = G_PROXY_ADDRESS (sockaddr); |
156 | printf (format: "\t%s://" , g_proxy_address_get_protocol(proxy)); |
157 | } |
158 | else |
159 | { |
160 | printf (format: "\tdirect://" ); |
161 | } |
162 | |
163 | if (G_IS_INET_SOCKET_ADDRESS (sockaddr)) |
164 | { |
165 | GInetAddress *inetaddr; |
166 | guint port; |
167 | gchar *addr; |
168 | |
169 | g_object_get (object: sockaddr, |
170 | first_property_name: "address" , &inetaddr, |
171 | "port" , &port, |
172 | NULL); |
173 | |
174 | addr = g_inet_address_to_string (address: inetaddr); |
175 | |
176 | printf (format: "%s:%u" , addr, port); |
177 | |
178 | g_free (mem: addr); |
179 | } |
180 | |
181 | if (proxy) |
182 | { |
183 | if (g_proxy_address_get_username(proxy)) |
184 | printf (format: " (Username: %s Password: %s)" , |
185 | g_proxy_address_get_username(proxy), |
186 | g_proxy_address_get_password(proxy)); |
187 | printf (format: " (Hostname: %s, Port: %i)" , |
188 | g_proxy_address_get_destination_hostname (proxy), |
189 | g_proxy_address_get_destination_port (proxy)); |
190 | } |
191 | |
192 | printf (format: "\n" ); |
193 | } |
194 | |
195 | static void |
196 | _proxy_enumerate_cb (GObject *object, |
197 | GAsyncResult *result, |
198 | gpointer user_data) |
199 | { |
200 | GError *error = NULL; |
201 | GMainLoop *loop = user_data; |
202 | GSocketAddressEnumerator *enumerator = G_SOCKET_ADDRESS_ENUMERATOR (object); |
203 | GSocketAddress *sockaddr; |
204 | |
205 | sockaddr = g_socket_address_enumerator_next_finish (enumerator, |
206 | result, |
207 | error: &error); |
208 | if (sockaddr) |
209 | { |
210 | print_proxy_address (sockaddr); |
211 | g_socket_address_enumerator_next_async (enumerator, |
212 | cancellable, |
213 | callback: _proxy_enumerate_cb, |
214 | user_data: loop); |
215 | g_object_unref (object: sockaddr); |
216 | } |
217 | else |
218 | { |
219 | if (error) |
220 | print_and_free_error (error); |
221 | |
222 | g_main_loop_quit (loop); |
223 | } |
224 | } |
225 | |
226 | static void |
227 | run_with_enumerator (gboolean synchronous, GSocketAddressEnumerator *enumerator) |
228 | { |
229 | GError *error = NULL; |
230 | |
231 | if (synchronous) |
232 | { |
233 | GSocketAddress *sockaddr; |
234 | |
235 | while ((sockaddr = g_socket_address_enumerator_next (enumerator, |
236 | cancellable, |
237 | error: &error))) |
238 | { |
239 | print_proxy_address (sockaddr); |
240 | g_object_unref (object: sockaddr); |
241 | } |
242 | |
243 | if (error) |
244 | print_and_free_error (error); |
245 | } |
246 | else |
247 | { |
248 | GMainLoop *loop = g_main_loop_new (NULL, FALSE); |
249 | |
250 | g_socket_address_enumerator_next_async (enumerator, |
251 | cancellable, |
252 | callback: _proxy_enumerate_cb, |
253 | user_data: loop); |
254 | g_main_loop_run (loop); |
255 | g_main_loop_unref (loop); |
256 | } |
257 | } |
258 | |
259 | static void |
260 | use_enumerator (gboolean synchronous) |
261 | { |
262 | GSocketAddressEnumerator *enumerator; |
263 | |
264 | enumerator = g_object_new (G_TYPE_PROXY_ADDRESS_ENUMERATOR, |
265 | first_property_name: "uri" , info, |
266 | NULL); |
267 | |
268 | printf (format: "Proxies for URI '%s' are:\n" , info); |
269 | run_with_enumerator (synchronous, enumerator); |
270 | |
271 | g_object_unref (object: enumerator); |
272 | } |
273 | |
274 | static void |
275 | use_inet_address (gboolean synchronous) |
276 | { |
277 | GSocketAddressEnumerator *enumerator; |
278 | GSocketAddress *sockaddr; |
279 | GInetAddress *addr = NULL; |
280 | guint port = 0; |
281 | gchar **ip_and_port; |
282 | |
283 | ip_and_port = g_strsplit (string: info, delimiter: ":" , max_tokens: 2); |
284 | |
285 | if (ip_and_port[0]) |
286 | { |
287 | addr = g_inet_address_new_from_string (string: ip_and_port[0]); |
288 | if (ip_and_port [1]) |
289 | port = strtoul (nptr: ip_and_port [1], NULL, base: 10); |
290 | } |
291 | |
292 | g_strfreev (str_array: ip_and_port); |
293 | |
294 | if (addr == NULL || port <= 0 || port >= 65535) |
295 | { |
296 | fprintf (stderr, format: "Bad 'ip:port' parameter '%s'\n" , info); |
297 | if (addr) |
298 | g_object_unref (object: addr); |
299 | return_value = 1; |
300 | return; |
301 | } |
302 | |
303 | sockaddr = g_inet_socket_address_new (address: addr, port); |
304 | g_object_unref (object: addr); |
305 | |
306 | enumerator = |
307 | g_socket_connectable_proxy_enumerate (G_SOCKET_CONNECTABLE (sockaddr)); |
308 | g_object_unref (object: sockaddr); |
309 | |
310 | printf (format: "Proxies for ip and port '%s' are:\n" , info); |
311 | run_with_enumerator (synchronous, enumerator); |
312 | |
313 | g_object_unref (object: enumerator); |
314 | } |
315 | |
316 | #ifdef G_OS_UNIX |
317 | static void |
318 | use_unix_address (gboolean synchronous) |
319 | { |
320 | GSocketAddressEnumerator *enumerator; |
321 | GSocketAddress *sockaddr; |
322 | |
323 | sockaddr = g_unix_socket_address_new_with_type (path: info, path_len: -1, type: G_UNIX_SOCKET_ADDRESS_ABSTRACT); |
324 | |
325 | if (sockaddr == NULL) |
326 | { |
327 | fprintf (stderr, format: "Failed to create unix socket with name '%s'\n" , info); |
328 | return_value = 1; |
329 | return; |
330 | } |
331 | |
332 | enumerator = |
333 | g_socket_connectable_proxy_enumerate (G_SOCKET_CONNECTABLE (sockaddr)); |
334 | g_object_unref (object: sockaddr); |
335 | |
336 | printf (format: "Proxies for path '%s' are:\n" , info); |
337 | run_with_enumerator (synchronous, enumerator); |
338 | |
339 | g_object_unref (object: enumerator); |
340 | } |
341 | #endif |
342 | |
343 | static void |
344 | use_proxy_address (gboolean synchronous) |
345 | { |
346 | GSocketAddressEnumerator *enumerator; |
347 | GSocketAddress *sockaddr; |
348 | GInetAddress *addr; |
349 | guint port = 0; |
350 | gchar *protocol; |
351 | gchar *dest_host; |
352 | guint dest_port; |
353 | gchar *username = NULL; |
354 | gchar *password = NULL; |
355 | gchar **split_info; |
356 | |
357 | split_info = g_strsplit (string: info, delimiter: ":" , max_tokens: 7); |
358 | |
359 | if (!split_info[0] |
360 | || !split_info[1] |
361 | || !split_info[2] |
362 | || !split_info[3] |
363 | || !split_info[4]) |
364 | { |
365 | fprintf (stderr, format: "Bad 'ip:port:protocol:dest_host:dest_port' parameter '%s'\n" , info); |
366 | return_value = 1; |
367 | return; |
368 | } |
369 | |
370 | addr = g_inet_address_new_from_string (string: split_info[0]); |
371 | port = strtoul (nptr: split_info [1], NULL, base: 10); |
372 | protocol = g_strdup (str: split_info[2]); |
373 | dest_host = g_strdup (str: split_info[3]); |
374 | dest_port = strtoul (nptr: split_info[4], NULL, base: 10); |
375 | |
376 | if (split_info[5]) |
377 | { |
378 | username = g_strdup (str: split_info[5]); |
379 | if (split_info[6]) |
380 | password = g_strdup (str: split_info[6]); |
381 | } |
382 | |
383 | g_strfreev (str_array: split_info); |
384 | |
385 | sockaddr = g_proxy_address_new (inetaddr: addr, port, |
386 | protocol, dest_hostname: dest_host, dest_port, |
387 | username, password); |
388 | |
389 | g_object_unref (object: addr); |
390 | g_free (mem: protocol); |
391 | g_free (mem: dest_host); |
392 | g_free (mem: username); |
393 | g_free (mem: password); |
394 | |
395 | enumerator = |
396 | g_socket_connectable_proxy_enumerate (G_SOCKET_CONNECTABLE (sockaddr)); |
397 | g_object_unref (object: sockaddr); |
398 | |
399 | printf (format: "Proxies for ip and port '%s' are:\n" , info); |
400 | run_with_enumerator (synchronous, enumerator); |
401 | |
402 | g_object_unref (object: enumerator); |
403 | } |
404 | |
405 | static void |
406 | use_network_address (gboolean synchronous) |
407 | { |
408 | GError *error = NULL; |
409 | GSocketAddressEnumerator *enumerator; |
410 | GSocketConnectable *connectable; |
411 | |
412 | connectable = g_network_address_parse (host_and_port: info, default_port: -1, error: &error); |
413 | |
414 | if (error) |
415 | { |
416 | print_and_free_error (error); |
417 | return; |
418 | } |
419 | |
420 | enumerator = g_socket_connectable_proxy_enumerate (connectable); |
421 | g_object_unref (object: connectable); |
422 | |
423 | printf (format: "Proxies for hostname and port '%s' are:\n" , info); |
424 | run_with_enumerator (synchronous, enumerator); |
425 | |
426 | g_object_unref (object: enumerator); |
427 | } |
428 | |
429 | static void |
430 | use_network_uri (gboolean synchronous) |
431 | { |
432 | GError *error = NULL; |
433 | GSocketAddressEnumerator *enumerator; |
434 | GSocketConnectable *connectable; |
435 | |
436 | connectable = g_network_address_parse_uri (uri: info, default_port: 0, error: &error); |
437 | |
438 | if (error) |
439 | { |
440 | print_and_free_error (error); |
441 | return; |
442 | } |
443 | |
444 | enumerator = g_socket_connectable_proxy_enumerate (connectable); |
445 | g_object_unref (object: connectable); |
446 | |
447 | printf (format: "Proxies for URI '%s' are:\n" , info); |
448 | run_with_enumerator (synchronous, enumerator); |
449 | |
450 | g_object_unref (object: enumerator); |
451 | } |
452 | |
453 | static void |
454 | use_network_service (gboolean synchronous) |
455 | { |
456 | GSocketAddressEnumerator *enumerator; |
457 | GSocketConnectable *connectable = NULL; |
458 | gchar **split; |
459 | |
460 | split = g_strsplit (string: info, delimiter: "/" , max_tokens: 3); |
461 | |
462 | if (split[0] && split[1] && split[2]) |
463 | connectable = g_network_service_new (service: split[0], protocol: split[1], domain: split[2]); |
464 | |
465 | g_strfreev (str_array: split); |
466 | |
467 | if (connectable == NULL) |
468 | { |
469 | fprintf (stderr, format: "Bad 'srv/protocol/domain' parameter '%s'\n" , info); |
470 | return_value = 1; |
471 | return; |
472 | } |
473 | |
474 | enumerator = g_socket_connectable_proxy_enumerate (connectable); |
475 | g_object_unref (object: connectable); |
476 | |
477 | printf (format: "Proxies for hostname and port '%s' are:\n" , info); |
478 | run_with_enumerator (synchronous, enumerator); |
479 | |
480 | g_object_unref (object: enumerator); |
481 | } |
482 | |
483 | static void |
484 | _socket_connect_cb (GObject *object, |
485 | GAsyncResult *result, |
486 | gpointer user_data) |
487 | { |
488 | GError *error = NULL; |
489 | GMainLoop *loop = user_data; |
490 | GSocketClient *client = G_SOCKET_CLIENT (object); |
491 | GSocketConnection *connection; |
492 | |
493 | connection = g_socket_client_connect_to_uri_finish (client, |
494 | result, |
495 | error: &error); |
496 | if (connection) |
497 | { |
498 | GSocketAddress *proxy_addr; |
499 | proxy_addr = g_socket_connection_get_remote_address (connection, NULL); |
500 | print_proxy_address (sockaddr: proxy_addr); |
501 | } |
502 | else |
503 | { |
504 | print_and_free_error (error); |
505 | } |
506 | |
507 | g_main_loop_quit (loop); |
508 | } |
509 | |
510 | static void |
511 | use_socket_client (gboolean synchronous) |
512 | { |
513 | GError *error = NULL; |
514 | GSocketClient *client; |
515 | |
516 | client = g_socket_client_new (); |
517 | |
518 | printf (format: "Proxies for URI '%s' are:\n" , info); |
519 | |
520 | if (synchronous) |
521 | { |
522 | GSocketConnection *connection; |
523 | GSocketAddress *proxy_addr; |
524 | |
525 | connection = g_socket_client_connect_to_uri (client, |
526 | uri: info, |
527 | default_port: 0, |
528 | cancellable, |
529 | error: &error); |
530 | |
531 | if (connection) |
532 | { |
533 | proxy_addr = g_socket_connection_get_remote_address (connection, NULL); |
534 | print_proxy_address (sockaddr: proxy_addr); |
535 | } |
536 | else |
537 | { |
538 | print_and_free_error (error); |
539 | } |
540 | } |
541 | else |
542 | { |
543 | GMainLoop *loop = g_main_loop_new (NULL, FALSE); |
544 | |
545 | g_socket_client_connect_to_uri_async (client, |
546 | uri: info, |
547 | default_port: 0, |
548 | cancellable, |
549 | callback: _socket_connect_cb, |
550 | user_data: loop); |
551 | |
552 | g_main_loop_run (loop); |
553 | g_main_loop_unref (loop); |
554 | } |
555 | |
556 | g_object_unref (object: client); |
557 | } |
558 | |
559 | typedef enum |
560 | { |
561 | USE_RESOLVER, |
562 | USE_ENUMERATOR, |
563 | #ifdef G_OS_UNIX |
564 | USE_UNIX_SOCKET_ADDRESS, |
565 | #endif |
566 | USE_INET_SOCKET_ADDRESS, |
567 | USE_PROXY_ADDRESS, |
568 | USE_NETWORK_ADDRESS, |
569 | USE_NETWORK_URI, |
570 | USE_NETWORK_SERVICE, |
571 | USE_SOCKET_CLIENT, |
572 | } ProxyTestType; |
573 | |
574 | gint |
575 | main (gint argc, gchar **argv) |
576 | { |
577 | gboolean synchronous = FALSE; |
578 | gboolean cancel = FALSE; |
579 | ProxyTestType type = USE_RESOLVER; |
580 | |
581 | while (argc >= 2 && argv[1][0] == '-') |
582 | { |
583 | if (!strcmp (s1: argv[1], s2: "-s" )) |
584 | synchronous = TRUE; |
585 | else if (!strcmp (s1: argv[1], s2: "-c" )) |
586 | cancel = TRUE; |
587 | else if (!strcmp (s1: argv[1], s2: "-e" )) |
588 | type = USE_ENUMERATOR; |
589 | else if (!strcmp (s1: argv[1], s2: "-inet" )) |
590 | type = USE_INET_SOCKET_ADDRESS; |
591 | #ifdef G_OS_UNIX |
592 | else if (!strcmp (s1: argv[1], s2: "-unix" )) |
593 | type = USE_UNIX_SOCKET_ADDRESS; |
594 | #endif |
595 | else if (!strcmp (s1: argv[1], s2: "-proxyaddr" )) |
596 | type = USE_PROXY_ADDRESS; |
597 | else if (!strcmp (s1: argv[1], s2: "-netaddr" )) |
598 | type = USE_NETWORK_ADDRESS; |
599 | else if (!strcmp (s1: argv[1], s2: "-neturi" )) |
600 | type = USE_NETWORK_URI; |
601 | else if (!strcmp (s1: argv[1], s2: "-netsrv" )) |
602 | type = USE_NETWORK_SERVICE; |
603 | else if (!strcmp (s1: argv[1], s2: "-connect" )) |
604 | type = USE_SOCKET_CLIENT; |
605 | else |
606 | usage (); |
607 | |
608 | argv++; |
609 | argc--; |
610 | } |
611 | |
612 | if (argc != 2) |
613 | usage (); |
614 | |
615 | /* Save URI for asynchronous callback */ |
616 | info = argv[1]; |
617 | |
618 | if (cancel) |
619 | { |
620 | cancellable = g_cancellable_new (); |
621 | g_cancellable_cancel (cancellable); |
622 | } |
623 | |
624 | switch (type) |
625 | { |
626 | case USE_RESOLVER: |
627 | use_resolver (synchronous); |
628 | break; |
629 | case USE_ENUMERATOR: |
630 | use_enumerator (synchronous); |
631 | break; |
632 | case USE_INET_SOCKET_ADDRESS: |
633 | use_inet_address (synchronous); |
634 | break; |
635 | #ifdef G_OS_UNIX |
636 | case USE_UNIX_SOCKET_ADDRESS: |
637 | use_unix_address (synchronous); |
638 | break; |
639 | #endif |
640 | case USE_PROXY_ADDRESS: |
641 | use_proxy_address (synchronous); |
642 | break; |
643 | case USE_NETWORK_ADDRESS: |
644 | use_network_address (synchronous); |
645 | break; |
646 | case USE_NETWORK_URI: |
647 | use_network_uri (synchronous); |
648 | break; |
649 | case USE_NETWORK_SERVICE: |
650 | use_network_service (synchronous); |
651 | break; |
652 | case USE_SOCKET_CLIENT: |
653 | use_socket_client (synchronous); |
654 | break; |
655 | } |
656 | |
657 | return return_value; |
658 | } |
659 | |