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