| /* GLib testing framework examples and tests | |
| * | |
| * Copyright (C) 2010 Collabora, Ltd. | |
| * | |
| * SPDX-License-Identifier: LGPL-2.1-or-later | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General | |
| * Public License along with this library; if not, see <http://www.gnu.org/licenses/>. | |
| * | |
| * Authors: Nicolas Dufresne <nicolas.dufresne@collabora.co.uk> | |
| */ | |
| #include "config.h" | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <gio/gio.h> | |
| #include <glib.h> | |
| #include "glibintl.h" | |
| #ifdef G_OS_UNIX | |
| #include "gio/gunixsocketaddress.h" | |
| #endif | |
| static const gchar *info = NULL; | |
| static GCancellable *cancellable = NULL; | |
| static gint return_value = 0; | |
| static G_NORETURN void | |
| usage (void) | |
| { | |
| fprintf (stderr, "Usage: proxy [-s] (uri|host:port|ip:port|path|srv/protocol/domain)\n"); | |
| fprintf (stderr, " Use -t to enable threading.\n"); | |
| fprintf (stderr, " Use -s to do synchronous lookups.\n"); | |
| fprintf (stderr, " Use -c to cancel operation.\n"); | |
| fprintf (stderr, " Use -e to use enumerator.\n"); | |
| fprintf (stderr, " Use -inet to use GInetSocketAddress enumerator (ip:port).\n"); | |
| #ifdef G_OS_UNIX | |
| fprintf (stderr, " Use -unix to use GUnixSocketAddress enumerator (path).\n"); | |
| #endif | |
| fprintf (stderr, " Use -proxyaddr tp use GProxyAddress enumerator " | |
| "(ip:port:protocol:dest_host:dest_port[:username[:password]]).\n"); | |
| fprintf (stderr, " Use -netaddr to use GNetworkAddress enumerator (host:port).\n"); | |
| fprintf (stderr, " Use -neturi to use GNetworkAddress enumerator (uri).\n"); | |
| fprintf (stderr, " Use -netsrv to use GNetworkService enumerator (srv/protocol/domain).\n"); | |
| fprintf (stderr, " Use -connect to create a connection using GSocketClient object (uri).\n"); | |
| exit (1); | |
| } | |
| static void | |
| print_and_free_error (GError *error) | |
| { | |
| fprintf (stderr, "Failed to obtain proxies: %s\n", error->message); | |
| g_error_free (error); | |
| return_value = 1; | |
| } | |
| static void | |
| print_proxies (const gchar *local_info, gchar **proxies) | |
| { | |
| printf ("Proxies for URI '%s' are:\n", local_info); | |
| if (proxies == NULL || proxies[0] == NULL) | |
| printf ("\tnone\n"); | |
| else | |
| for (; proxies[0]; proxies++) | |
| printf ("\t%s\n", proxies[0]); | |
| } | |
| static void | |
| _proxy_lookup_cb (GObject *source_object, | |
| GAsyncResult *result, | |
| gpointer user_data) | |
| { | |
| GError *error = NULL; | |
| gchar **proxies; | |
| GMainLoop *loop = user_data; | |
| proxies = g_proxy_resolver_lookup_finish (G_PROXY_RESOLVER (source_object), | |
| result, | |
| &error); | |
| if (error) | |
| { | |
| print_and_free_error (error); | |
| } | |
| else | |
| { | |
| print_proxies (info, proxies); | |
| g_strfreev (proxies); | |
| } | |
| g_main_loop_quit (loop); | |
| } | |
| static void | |
| use_resolver (gboolean synchronous) | |
| { | |
| GProxyResolver *resolver; | |
| resolver = g_proxy_resolver_get_default (); | |
| if (synchronous) | |
| { | |
| GError *error = NULL; | |
| gchar **proxies; | |
| proxies = g_proxy_resolver_lookup (resolver, info, cancellable, &error); | |
| if (error) | |
| print_and_free_error (error); | |
| else | |
| print_proxies (info, proxies); | |
| g_strfreev (proxies); | |
| } | |
| else | |
| { | |
| GMainLoop *loop = g_main_loop_new (NULL, FALSE); | |
| g_proxy_resolver_lookup_async (resolver, | |
| info, | |
| cancellable, | |
| _proxy_lookup_cb, | |
| loop); | |
| g_main_loop_run (loop); | |
| g_main_loop_unref (loop); | |
| } | |
| } | |
| static void | |
| print_proxy_address (GSocketAddress *sockaddr) | |
| { | |
| GProxyAddress *proxy = NULL; | |
| if (sockaddr == NULL) | |
| { | |
| printf ("\tdirect://\n"); | |
| return; | |
| } | |
| if (G_IS_PROXY_ADDRESS (sockaddr)) | |
| { | |
| proxy = G_PROXY_ADDRESS (sockaddr); | |
| printf ("\t%s://", g_proxy_address_get_protocol(proxy)); | |
| } | |
| else | |
| { | |
| printf ("\tdirect://"); | |
| } | |
| if (G_IS_INET_SOCKET_ADDRESS (sockaddr)) | |
| { | |
| GInetAddress *inetaddr; | |
| guint port; | |
| gchar *addr; | |
| g_object_get (sockaddr, | |
| "address", &inetaddr, | |
| "port", &port, | |
| NULL); | |
| addr = g_inet_address_to_string (inetaddr); | |
| printf ("%s:%u", addr, port); | |
| g_free (addr); | |
| } | |
| if (proxy) | |
| { | |
| if (g_proxy_address_get_username(proxy)) | |
| printf (" (Username: %s Password: %s)", | |
| g_proxy_address_get_username(proxy), | |
| g_proxy_address_get_password(proxy)); | |
| printf (" (Hostname: %s, Port: %i)", | |
| g_proxy_address_get_destination_hostname (proxy), | |
| g_proxy_address_get_destination_port (proxy)); | |
| } | |
| printf ("\n"); | |
| } | |
| static void | |
| _proxy_enumerate_cb (GObject *object, | |
| GAsyncResult *result, | |
| gpointer user_data) | |
| { | |
| GError *error = NULL; | |
| GMainLoop *loop = user_data; | |
| GSocketAddressEnumerator *enumerator = G_SOCKET_ADDRESS_ENUMERATOR (object); | |
| GSocketAddress *sockaddr; | |
| sockaddr = g_socket_address_enumerator_next_finish (enumerator, | |
| result, | |
| &error); | |
| if (sockaddr) | |
| { | |
| print_proxy_address (sockaddr); | |
| g_socket_address_enumerator_next_async (enumerator, | |
| cancellable, | |
| _proxy_enumerate_cb, | |
| loop); | |
| g_object_unref (sockaddr); | |
| } | |
| else | |
| { | |
| if (error) | |
| print_and_free_error (error); | |
| g_main_loop_quit (loop); | |
| } | |
| } | |
| static void | |
| run_with_enumerator (gboolean synchronous, GSocketAddressEnumerator *enumerator) | |
| { | |
| GError *error = NULL; | |
| if (synchronous) | |
| { | |
| GSocketAddress *sockaddr; | |
| while ((sockaddr = g_socket_address_enumerator_next (enumerator, | |
| cancellable, | |
| &error))) | |
| { | |
| print_proxy_address (sockaddr); | |
| g_object_unref (sockaddr); | |
| } | |
| if (error) | |
| print_and_free_error (error); | |
| } | |
| else | |
| { | |
| GMainLoop *loop = g_main_loop_new (NULL, FALSE); | |
| g_socket_address_enumerator_next_async (enumerator, | |
| cancellable, | |
| _proxy_enumerate_cb, | |
| loop); | |
| g_main_loop_run (loop); | |
| g_main_loop_unref (loop); | |
| } | |
| } | |
| static void | |
| use_enumerator (gboolean synchronous) | |
| { | |
| GSocketAddressEnumerator *enumerator; | |
| enumerator = g_object_new (G_TYPE_PROXY_ADDRESS_ENUMERATOR, | |
| "uri", info, | |
| NULL); | |
| printf ("Proxies for URI '%s' are:\n", info); | |
| run_with_enumerator (synchronous, enumerator); | |
| g_object_unref (enumerator); | |
| } | |
| static void | |
| use_inet_address (gboolean synchronous) | |
| { | |
| GSocketAddressEnumerator *enumerator; | |
| GSocketAddress *sockaddr; | |
| GInetAddress *addr = NULL; | |
| guint port = 0; | |
| gchar **ip_and_port; | |
| ip_and_port = g_strsplit (info, ":", 2); | |
| if (ip_and_port[0]) | |
| { | |
| addr = g_inet_address_new_from_string (ip_and_port[0]); | |
| if (ip_and_port [1]) | |
| port = strtoul (ip_and_port [1], NULL, 10); | |
| } | |
| g_strfreev (ip_and_port); | |
| if (addr == NULL || port <= 0 || port >= 65535) | |
| { | |
| fprintf (stderr, "Bad 'ip:port' parameter '%s'\n", info); | |
| if (addr) | |
| g_object_unref (addr); | |
| return_value = 1; | |
| return; | |
| } | |
| sockaddr = g_inet_socket_address_new (addr, port); | |
| g_object_unref (addr); | |
| enumerator = | |
| g_socket_connectable_proxy_enumerate (G_SOCKET_CONNECTABLE (sockaddr)); | |
| g_object_unref (sockaddr); | |
| printf ("Proxies for ip and port '%s' are:\n", info); | |
| run_with_enumerator (synchronous, enumerator); | |
| g_object_unref (enumerator); | |
| } | |
| #ifdef G_OS_UNIX | |
| static void | |
| use_unix_address (gboolean synchronous) | |
| { | |
| GSocketAddressEnumerator *enumerator; | |
| GSocketAddress *sockaddr; | |
| sockaddr = g_unix_socket_address_new_with_type (info, -1, G_UNIX_SOCKET_ADDRESS_ABSTRACT); | |
| if (sockaddr == NULL) | |
| { | |
| fprintf (stderr, "Failed to create unix socket with name '%s'\n", info); | |
| return_value = 1; | |
| return; | |
| } | |
| enumerator = | |
| g_socket_connectable_proxy_enumerate (G_SOCKET_CONNECTABLE (sockaddr)); | |
| g_object_unref (sockaddr); | |
| printf ("Proxies for path '%s' are:\n", info); | |
| run_with_enumerator (synchronous, enumerator); | |
| g_object_unref (enumerator); | |
| } | |
| #endif | |
| static void | |
| use_proxy_address (gboolean synchronous) | |
| { | |
| GSocketAddressEnumerator *enumerator; | |
| GSocketAddress *sockaddr; | |
| GInetAddress *addr; | |
| guint port = 0; | |
| gchar *protocol; | |
| gchar *dest_host; | |
| guint dest_port; | |
| gchar *username = NULL; | |
| gchar *password = NULL; | |
| gchar **split_info; | |
| split_info = g_strsplit (info, ":", 7); | |
| if (!split_info[0] | |
| || !split_info[1] | |
| || !split_info[2] | |
| || !split_info[3] | |
| || !split_info[4]) | |
| { | |
| fprintf (stderr, "Bad 'ip:port:protocol:dest_host:dest_port' parameter '%s'\n", info); | |
| return_value = 1; | |
| return; | |
| } | |
| addr = g_inet_address_new_from_string (split_info[0]); | |
| port = strtoul (split_info [1], NULL, 10); | |
| protocol = g_strdup (split_info[2]); | |
| dest_host = g_strdup (split_info[3]); | |
| dest_port = strtoul (split_info[4], NULL, 10); | |
| if (split_info[5]) | |
| { | |
| username = g_strdup (split_info[5]); | |
| if (split_info[6]) | |
| password = g_strdup (split_info[6]); | |
| } | |
| g_strfreev (split_info); | |
| sockaddr = g_proxy_address_new (addr, port, | |
| protocol, dest_host, dest_port, | |
| username, password); | |
| g_object_unref (addr); | |
| g_free (protocol); | |
| g_free (dest_host); | |
| g_free (username); | |
| g_free (password); | |
| enumerator = | |
| g_socket_connectable_proxy_enumerate (G_SOCKET_CONNECTABLE (sockaddr)); | |
| g_object_unref (sockaddr); | |
| printf ("Proxies for ip and port '%s' are:\n", info); | |
| run_with_enumerator (synchronous, enumerator); | |
| g_object_unref (enumerator); | |
| } | |
| static void | |
| use_network_address (gboolean synchronous) | |
| { | |
| GError *error = NULL; | |
| GSocketAddressEnumerator *enumerator; | |
| GSocketConnectable *connectable; | |
| connectable = g_network_address_parse (info, -1, &error); | |
| if (error) | |
| { | |
| print_and_free_error (error); | |
| return; | |
| } | |
| enumerator = g_socket_connectable_proxy_enumerate (connectable); | |
| g_object_unref (connectable); | |
| printf ("Proxies for hostname and port '%s' are:\n", info); | |
| run_with_enumerator (synchronous, enumerator); | |
| g_object_unref (enumerator); | |
| } | |
| static void | |
| use_network_uri (gboolean synchronous) | |
| { | |
| GError *error = NULL; | |
| GSocketAddressEnumerator *enumerator; | |
| GSocketConnectable *connectable; | |
| connectable = g_network_address_parse_uri (info, 0, &error); | |
| if (error) | |
| { | |
| print_and_free_error (error); | |
| return; | |
| } | |
| enumerator = g_socket_connectable_proxy_enumerate (connectable); | |
| g_object_unref (connectable); | |
| printf ("Proxies for URI '%s' are:\n", info); | |
| run_with_enumerator (synchronous, enumerator); | |
| g_object_unref (enumerator); | |
| } | |
| static void | |
| use_network_service (gboolean synchronous) | |
| { | |
| GSocketAddressEnumerator *enumerator; | |
| GSocketConnectable *connectable = NULL; | |
| gchar **split; | |
| split = g_strsplit (info, "/", 3); | |
| if (split[0] && split[1] && split[2]) | |
| connectable = g_network_service_new (split[0], split[1], split[2]); | |
| g_strfreev (split); | |
| if (connectable == NULL) | |
| { | |
| fprintf (stderr, "Bad 'srv/protocol/domain' parameter '%s'\n", info); | |
| return_value = 1; | |
| return; | |
| } | |
| enumerator = g_socket_connectable_proxy_enumerate (connectable); | |
| g_object_unref (connectable); | |
| printf ("Proxies for hostname and port '%s' are:\n", info); | |
| run_with_enumerator (synchronous, enumerator); | |
| g_object_unref (enumerator); | |
| } | |
| static void | |
| _socket_connect_cb (GObject *object, | |
| GAsyncResult *result, | |
| gpointer user_data) | |
| { | |
| GError *error = NULL; | |
| GMainLoop *loop = user_data; | |
| GSocketClient *client = G_SOCKET_CLIENT (object); | |
| GSocketConnection *connection; | |
| connection = g_socket_client_connect_to_uri_finish (client, | |
| result, | |
| &error); | |
| if (connection) | |
| { | |
| GSocketAddress *proxy_addr; | |
| proxy_addr = g_socket_connection_get_remote_address (connection, NULL); | |
| print_proxy_address (proxy_addr); | |
| } | |
| else | |
| { | |
| print_and_free_error (error); | |
| } | |
| g_main_loop_quit (loop); | |
| } | |
| static void | |
| use_socket_client (gboolean synchronous) | |
| { | |
| GError *error = NULL; | |
| GSocketClient *client; | |
| client = g_socket_client_new (); | |
| printf ("Proxies for URI '%s' are:\n", info); | |
| if (synchronous) | |
| { | |
| GSocketConnection *connection; | |
| GSocketAddress *proxy_addr; | |
| connection = g_socket_client_connect_to_uri (client, | |
| info, | |
| 0, | |
| cancellable, | |
| &error); | |
| if (connection) | |
| { | |
| proxy_addr = g_socket_connection_get_remote_address (connection, NULL); | |
| print_proxy_address (proxy_addr); | |
| } | |
| else | |
| { | |
| print_and_free_error (error); | |
| } | |
| } | |
| else | |
| { | |
| GMainLoop *loop = g_main_loop_new (NULL, FALSE); | |
| g_socket_client_connect_to_uri_async (client, | |
| info, | |
| 0, | |
| cancellable, | |
| _socket_connect_cb, | |
| loop); | |
| g_main_loop_run (loop); | |
| g_main_loop_unref (loop); | |
| } | |
| g_object_unref (client); | |
| } | |
| typedef enum | |
| { | |
| USE_RESOLVER, | |
| USE_ENUMERATOR, | |
| #ifdef G_OS_UNIX | |
| USE_UNIX_SOCKET_ADDRESS, | |
| #endif | |
| USE_INET_SOCKET_ADDRESS, | |
| USE_PROXY_ADDRESS, | |
| USE_NETWORK_ADDRESS, | |
| USE_NETWORK_URI, | |
| USE_NETWORK_SERVICE, | |
| USE_SOCKET_CLIENT, | |
| } ProxyTestType; | |
| gint | |
| main (gint argc, gchar **argv) | |
| { | |
| gboolean synchronous = FALSE; | |
| gboolean cancel = FALSE; | |
| ProxyTestType type = USE_RESOLVER; | |
| while (argc >= 2 && argv[1][0] == '-') | |
| { | |
| if (!strcmp (argv[1], "-s")) | |
| synchronous = TRUE; | |
| else if (!strcmp (argv[1], "-c")) | |
| cancel = TRUE; | |
| else if (!strcmp (argv[1], "-e")) | |
| type = USE_ENUMERATOR; | |
| else if (!strcmp (argv[1], "-inet")) | |
| type = USE_INET_SOCKET_ADDRESS; | |
| #ifdef G_OS_UNIX | |
| else if (!strcmp (argv[1], "-unix")) | |
| type = USE_UNIX_SOCKET_ADDRESS; | |
| #endif | |
| else if (!strcmp (argv[1], "-proxyaddr")) | |
| type = USE_PROXY_ADDRESS; | |
| else if (!strcmp (argv[1], "-netaddr")) | |
| type = USE_NETWORK_ADDRESS; | |
| else if (!strcmp (argv[1], "-neturi")) | |
| type = USE_NETWORK_URI; | |
| else if (!strcmp (argv[1], "-netsrv")) | |
| type = USE_NETWORK_SERVICE; | |
| else if (!strcmp (argv[1], "-connect")) | |
| type = USE_SOCKET_CLIENT; | |
| else | |
| usage (); | |
| argv++; | |
| argc--; | |
| } | |
| if (argc != 2) | |
| usage (); | |
| /* Save URI for asynchronous callback */ | |
| info = argv[1]; | |
| if (cancel) | |
| { | |
| cancellable = g_cancellable_new (); | |
| g_cancellable_cancel (cancellable); | |
| } | |
| switch (type) | |
| { | |
| case USE_RESOLVER: | |
| use_resolver (synchronous); | |
| break; | |
| case USE_ENUMERATOR: | |
| use_enumerator (synchronous); | |
| break; | |
| case USE_INET_SOCKET_ADDRESS: | |
| use_inet_address (synchronous); | |
| break; | |
| #ifdef G_OS_UNIX | |
| case USE_UNIX_SOCKET_ADDRESS: | |
| use_unix_address (synchronous); | |
| break; | |
| #endif | |
| case USE_PROXY_ADDRESS: | |
| use_proxy_address (synchronous); | |
| break; | |
| case USE_NETWORK_ADDRESS: | |
| use_network_address (synchronous); | |
| break; | |
| case USE_NETWORK_URI: | |
| use_network_uri (synchronous); | |
| break; | |
| case USE_NETWORK_SERVICE: | |
| use_network_service (synchronous); | |
| break; | |
| case USE_SOCKET_CLIENT: | |
| use_socket_client (synchronous); | |
| break; | |
| } | |
| return return_value; | |
| } |