1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
3 /* GIO - GLib Input, Output and Streaming Library
5 * Copyright (C) 2008 Red Hat, Inc.
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 of the License, or (at your option) any later version.
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.
17 * You should have received a copy of the GNU Lesser General
18 * Public License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20 * Boston, MA 02111-1307, USA.
35 static GResolver *resolver;
36 static GCancellable *cancellable;
37 static GMainLoop *loop;
38 static int nlookups = 0;
40 static void G_GNUC_NORETURN
43 fprintf (stderr, "Usage: resolver [-t] [-s] [hostname | IP | service/protocol/domain ] ...\n");
44 fprintf (stderr, " resolver [-t] [-s] -c NUMBER [hostname | IP | service/protocol/domain ]\n");
45 fprintf (stderr, " Use -t to enable threading.\n");
46 fprintf (stderr, " Use -s to do synchronous lookups.\n");
47 fprintf (stderr, " Both together will result in simultaneous lookups in multiple threads\n");
48 fprintf (stderr, " Use -c NUMBER(and only a single resolvable argument) to test GSocketConnectable.\n");
49 fprintf (stderr, " The given NUMBER determines how often the connectable will be enumerated.\n");
53 G_LOCK_DEFINE_STATIC (response);
61 /* In the sync case we need to make sure we don't call
62 * g_main_loop_quit before the loop is actually running...
64 g_idle_add ((GSourceFunc)g_main_loop_quit, loop);
69 print_resolved_name (const char *phys,
74 printf ("Address: %s\n", phys);
77 printf ("Error: %s\n", error->message);
82 printf ("Name: %s\n", name);
92 print_resolved_addresses (const char *name,
100 printf ("Name: %s\n", name);
103 printf ("Error: %s\n", error->message);
104 g_error_free (error);
108 for (a = addresses; a; a = a->next)
110 phys = g_inet_address_to_string (a->data);
111 printf ("Address: %s\n", phys);
113 g_object_unref (a->data);
115 g_list_free (addresses);
124 print_resolved_service (const char *service,
131 printf ("Service: %s\n", service);
134 printf ("Error: %s\n", error->message);
135 g_error_free (error);
139 for (t = targets; t; t = t->next)
141 printf ("%s:%u (pri %u, weight %u)\n",
142 g_srv_target_get_hostname (t->data),
143 g_srv_target_get_port (t->data),
144 g_srv_target_get_priority (t->data),
145 g_srv_target_get_weight (t->data));
146 g_srv_target_free (t->data);
148 g_list_free (targets);
157 lookup_one_sync (const char *arg)
159 GError *error = NULL;
161 if (strchr (arg, '/'))
164 /* service/protocol/domain */
165 char **parts = g_strsplit (arg, "/", 3);
167 if (!parts || !parts[2])
170 targets = g_resolver_lookup_service (resolver,
171 parts[0], parts[1], parts[2],
172 cancellable, &error);
173 print_resolved_service (arg, targets, error);
175 else if (g_hostname_is_ip_address (arg))
177 GInetAddress *addr = g_inet_address_new_from_string (arg);
180 name = g_resolver_lookup_by_address (resolver, addr, cancellable, &error);
181 print_resolved_name (arg, name, error);
182 g_object_unref (addr);
188 addresses = g_resolver_lookup_by_name (resolver, arg, cancellable, &error);
189 print_resolved_addresses (arg, addresses, error);
194 lookup_thread (gpointer arg)
196 lookup_one_sync (arg);
201 start_threaded_lookups (char **argv, int argc)
205 for (i = 0; i < argc; i++)
206 g_thread_create (lookup_thread, argv[i], FALSE, NULL);
210 start_sync_lookups (char **argv, int argc)
214 for (i = 0; i < argc; i++)
215 lookup_one_sync (argv[i]);
219 lookup_by_addr_callback (GObject *source, GAsyncResult *result,
222 const char *phys = user_data;
223 GError *error = NULL;
226 name = g_resolver_lookup_by_address_finish (resolver, result, &error);
227 print_resolved_name (phys, name, error);
231 lookup_by_name_callback (GObject *source, GAsyncResult *result,
234 const char *name = user_data;
235 GError *error = NULL;
238 addresses = g_resolver_lookup_by_name_finish (resolver, result, &error);
239 print_resolved_addresses (name, addresses, error);
243 lookup_service_callback (GObject *source, GAsyncResult *result,
246 const char *service = user_data;
247 GError *error = NULL;
250 targets = g_resolver_lookup_service_finish (resolver, result, &error);
251 print_resolved_service (service, targets, error);
255 start_async_lookups (char **argv, int argc)
259 for (i = 0; i < argc; i++)
261 if (strchr (argv[i], '/'))
263 /* service/protocol/domain */
264 char **parts = g_strsplit (argv[i], "/", 3);
266 if (!parts || !parts[2])
269 g_resolver_lookup_service_async (resolver,
270 parts[0], parts[1], parts[2],
272 lookup_service_callback, argv[i]);
274 else if (g_hostname_is_ip_address (argv[i]))
276 GInetAddress *addr = g_inet_address_new_from_string (argv[i]);
278 g_resolver_lookup_by_address_async (resolver, addr, cancellable,
279 lookup_by_addr_callback, argv[i]);
280 g_object_unref (addr);
284 g_resolver_lookup_by_name_async (resolver, argv[i], cancellable,
285 lookup_by_name_callback,
289 /* Stress-test the reloading code */
290 g_signal_emit_by_name (resolver, "reload");
295 print_connectable_sockaddr (GSocketAddress *sockaddr,
302 printf ("Error: %s\n", error->message);
303 g_error_free (error);
305 else if (!G_IS_INET_SOCKET_ADDRESS (sockaddr))
307 printf ("Error: Unexpected sockaddr type '%s'\n", g_type_name_from_instance ((GTypeInstance *)sockaddr));
308 g_object_unref (sockaddr);
312 GInetSocketAddress *isa = G_INET_SOCKET_ADDRESS (sockaddr);
313 phys = g_inet_address_to_string (g_inet_socket_address_get_address (isa));
314 printf ("Address: %s%s%s:%d\n",
315 strchr (phys, ':') ? "[" : "", phys, strchr (phys, ':') ? "]" : "",
316 g_inet_socket_address_get_port (isa));
318 g_object_unref (sockaddr);
323 do_sync_connectable (GSocketAddressEnumerator *enumerator)
325 GSocketAddress *sockaddr;
326 GError *error = NULL;
328 while ((sockaddr = g_socket_address_enumerator_next (enumerator, cancellable, &error)))
329 print_connectable_sockaddr (sockaddr, error);
331 g_object_unref (enumerator);
335 static void do_async_connectable (GSocketAddressEnumerator *enumerator);
338 got_next_async (GObject *source, GAsyncResult *result, gpointer user_data)
340 GSocketAddressEnumerator *enumerator = G_SOCKET_ADDRESS_ENUMERATOR (source);
341 GSocketAddress *sockaddr;
342 GError *error = NULL;
344 sockaddr = g_socket_address_enumerator_next_finish (enumerator, result, &error);
345 if (sockaddr || error)
346 print_connectable_sockaddr (sockaddr, error);
348 do_async_connectable (enumerator);
351 g_object_unref (enumerator);
357 do_async_connectable (GSocketAddressEnumerator *enumerator)
359 g_socket_address_enumerator_next_async (enumerator, cancellable,
360 got_next_async, NULL);
364 do_connectable (const char *arg, gboolean synchronous, guint count)
367 GSocketConnectable *connectable;
368 GSocketAddressEnumerator *enumerator;
370 if (strchr (arg, '/'))
372 /* service/protocol/domain */
373 parts = g_strsplit (arg, "/", 3);
374 if (!parts || !parts[2])
377 connectable = g_network_service_new (parts[0], parts[1], parts[2]);
383 parts = g_strsplit (arg, ":", 2);
384 if (parts && parts[1])
387 port = strtoul (parts[1], NULL, 10);
392 if (g_hostname_is_ip_address (arg))
394 GInetAddress *addr = g_inet_address_new_from_string (arg);
395 GSocketAddress *sockaddr = g_inet_socket_address_new (addr, port);
397 g_object_unref (addr);
398 connectable = G_SOCKET_CONNECTABLE (sockaddr);
401 connectable = g_network_address_new (arg, port);
406 enumerator = g_socket_connectable_enumerate (connectable);
409 do_sync_connectable (enumerator);
411 do_async_connectable (enumerator);
414 g_object_unref (connectable);
418 static int cancel_fds[2];
421 interrupted (int sig)
425 signal (SIGINT, SIG_DFL);
426 c = write (cancel_fds[1], "x", 1);
427 g_assert_cmpint(c, ==, 1);
431 async_cancel (GIOChannel *source, GIOCondition cond, gpointer cancel)
433 g_cancellable_cancel (cancel);
439 main (int argc, char **argv)
441 gboolean threaded = FALSE, synchronous = FALSE;
442 guint connectable_count = 0;
448 /* We can't use GOptionContext because we use the arguments to
449 * decide whether or not to call g_thread_init().
451 while (argc >= 2 && argv[1][0] == '-')
453 if (!strcmp (argv[1], "-t"))
455 g_thread_init (NULL);
458 else if (!strcmp (argv[1], "-s"))
460 else if (!strcmp (argv[1], "-c"))
462 connectable_count = atoi (argv[2]);
474 if (argc < 2 || (argc > 2 && connectable_count))
477 resolver = g_resolver_get_default ();
479 cancellable = g_cancellable_new ();
482 /* Set up cancellation; we want to cancel if the user ^C's the
483 * program, but we can't cancel directly from an interrupt.
485 signal (SIGINT, interrupted);
487 if (pipe (cancel_fds) == -1)
492 chan = g_io_channel_unix_new (cancel_fds[0]);
493 watch = g_io_add_watch (chan, G_IO_IN, async_cancel, cancellable);
494 g_io_channel_unref (chan);
498 loop = g_main_loop_new (NULL, TRUE);
500 if (connectable_count)
502 nlookups = connectable_count;
503 do_connectable (argv[1], synchronous, connectable_count);
507 if (threaded && synchronous)
508 start_threaded_lookups (argv + 1, argc - 1);
509 else if (synchronous)
510 start_sync_lookups (argv + 1, argc - 1);
512 start_async_lookups (argv + 1, argc - 1);
515 g_main_loop_run (loop);
516 g_main_loop_unref (loop);
519 g_source_remove (watch);
521 g_object_unref (cancellable);