Don't use deprecated GLib api
[platform/upstream/glib.git] / gio / tests / resolver.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3 /* GIO - GLib Input, Output and Streaming Library
4  * 
5  * Copyright (C) 2008 Red Hat, Inc.
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 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, write to the
19  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include "config.h"
24 #include <glib.h>
25 #include "glibintl.h"
26
27 #include <signal.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32
33 #include <gio/gio.h>
34
35 static GResolver *resolver;
36 static GCancellable *cancellable;
37 static GMainLoop *loop;
38 static int nlookups = 0;
39
40 static void
41 usage (void)
42 {
43         fprintf (stderr, "Usage: resolver [-t] [-s] [hostname | IP | service/protocol/domain ] ...\n");
44         fprintf (stderr, "       resolver [-t] [-s] -c [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 (and only a single resolvable argument) to test GSocketConnectable.\n");
49         exit (1);
50 }
51
52 G_LOCK_DEFINE_STATIC (response);
53
54 static void
55 done_lookup (void)
56 {
57   nlookups--;
58   if (nlookups == 0)
59     {
60       /* In the sync case we need to make sure we don't call
61        * g_main_loop_quit before the loop is actually running...
62        */
63       g_idle_add ((GSourceFunc)g_main_loop_quit, loop);
64     }
65 }
66
67 static void
68 print_resolved_name (const char *phys,
69                      char       *name,
70                      GError     *error)
71 {
72   G_LOCK (response);
73   printf ("Address: %s\n", phys);
74   if (error)
75     {
76       printf ("Error:   %s\n", error->message);
77       g_error_free (error);
78     }
79   else
80     {
81       printf ("Name:    %s\n", name);
82       g_free (name);
83     }
84   printf ("\n");
85
86   done_lookup ();
87   G_UNLOCK (response);
88 }
89
90 static void
91 print_resolved_addresses (const char *name,
92                           GList      *addresses,
93                           GError     *error)
94 {
95   char *phys;
96   GList *a;
97
98   G_LOCK (response);
99   printf ("Name:    %s\n", name);
100   if (error)
101     {
102       printf ("Error:   %s\n", error->message);
103       g_error_free (error);
104     }
105   else
106     {
107       for (a = addresses; a; a = a->next)
108         {
109           phys = g_inet_address_to_string (a->data);
110           printf ("Address: %s\n", phys);
111           g_free (phys);
112           g_object_unref (a->data);
113         }
114       g_list_free (addresses);
115     }
116   printf ("\n");
117
118   done_lookup ();
119   G_UNLOCK (response);
120 }
121
122 static void
123 print_resolved_service (const char *service,
124                         GList      *targets,
125                         GError     *error)
126 {
127   GList *t;  
128
129   G_LOCK (response);
130   printf ("Service: %s\n", service);
131   if (error)
132     {
133       printf ("Error: %s\n", error->message);
134       g_error_free (error);
135     }
136   else
137     {
138       for (t = targets; t; t = t->next)
139         {
140           printf ("%s:%u (pri %u, weight %u)\n",
141                   g_srv_target_get_hostname (t->data),
142                   g_srv_target_get_port (t->data),
143                   g_srv_target_get_priority (t->data),
144                   g_srv_target_get_weight (t->data));
145           g_srv_target_free (t->data);
146         }
147       g_list_free (targets);
148     }
149   printf ("\n");
150
151   done_lookup ();
152   G_UNLOCK (response);
153 }
154
155 static void
156 lookup_one_sync (const char *arg)
157 {
158   GError *error = NULL;
159
160   if (strchr (arg, '/'))
161     {
162       GList *targets;
163       /* service/protocol/domain */
164       char **parts = g_strsplit (arg, "/", 3);
165
166       if (!parts || !parts[2])
167         usage ();
168
169       targets = g_resolver_lookup_service (resolver,
170                                            parts[0], parts[1], parts[2],
171                                            cancellable, &error);
172       print_resolved_service (arg, targets, error);
173     }
174   else if (g_hostname_is_ip_address (arg))
175     {
176       GInetAddress *addr = g_inet_address_new_from_string (arg);
177       char *name;
178
179       name = g_resolver_lookup_by_address (resolver, addr, cancellable, &error);
180       print_resolved_name (arg, name, error);
181       g_object_unref (addr);
182     }
183   else
184     {
185       GList *addresses;
186
187       addresses = g_resolver_lookup_by_name (resolver, arg, cancellable, &error);
188       print_resolved_addresses (arg, addresses, error);
189     }
190 }
191
192 static gpointer
193 lookup_thread (gpointer arg)
194 {
195   lookup_one_sync (arg);
196   return NULL;
197 }
198
199 static void
200 start_threaded_lookups (char **argv, int argc)
201 {
202   int i;
203
204   for (i = 0; i < argc; i++)
205     g_thread_create (lookup_thread, argv[i], FALSE, NULL);
206 }
207
208 static void
209 start_sync_lookups (char **argv, int argc)
210 {
211   int i;
212
213   for (i = 0; i < argc; i++)
214     lookup_one_sync (argv[i]);
215 }
216
217 static void
218 lookup_by_addr_callback (GObject *source, GAsyncResult *result,
219                          gpointer user_data)
220 {
221   const char *phys = user_data;
222   GError *error = NULL;
223   char *name;
224
225   name = g_resolver_lookup_by_address_finish (resolver, result, &error);
226   print_resolved_name (phys, name, error);
227 }
228
229 static void
230 lookup_by_name_callback (GObject *source, GAsyncResult *result,
231                          gpointer user_data)
232 {
233   const char *name = user_data;
234   GError *error = NULL;
235   GList *addresses;
236
237   addresses = g_resolver_lookup_by_name_finish (resolver, result, &error);
238   print_resolved_addresses (name, addresses, error);
239 }
240
241 static void
242 lookup_service_callback (GObject *source, GAsyncResult *result,
243                          gpointer user_data)
244 {
245   const char *service = user_data;
246   GError *error = NULL;
247   GList *targets;
248
249   targets = g_resolver_lookup_service_finish (resolver, result, &error);
250   print_resolved_service (service, targets, error);
251 }
252
253 static void
254 start_async_lookups (char **argv, int argc)
255 {
256   int i;
257
258   for (i = 0; i < argc; i++)
259     {
260       if (strchr (argv[i], '/'))
261         {
262           /* service/protocol/domain */
263           char **parts = g_strsplit (argv[i], "/", 3);
264
265           if (!parts || !parts[2])
266             usage ();
267
268           g_resolver_lookup_service_async (resolver,
269                                            parts[0], parts[1], parts[2],
270                                            cancellable,
271                                            lookup_service_callback, argv[i]);
272         }
273       else if (g_hostname_is_ip_address (argv[i]))
274         {
275           GInetAddress *addr = g_inet_address_new_from_string (argv[i]);
276
277           g_resolver_lookup_by_address_async (resolver, addr, cancellable,
278                                               lookup_by_addr_callback, argv[i]);
279           g_object_unref (addr);
280         }
281       else
282         {
283           g_resolver_lookup_by_name_async (resolver, argv[i], cancellable,
284                                            lookup_by_name_callback,
285                                            argv[i]);
286         }
287     }
288 }
289
290 static void
291 print_connectable_sockaddr (GSocketAddress *sockaddr,
292                             GError         *error)
293 {
294   char *phys;
295
296   if (error)
297     {
298       printf ("Error:   %s\n", error->message);
299       g_error_free (error);
300     }
301   else if (!G_IS_INET_SOCKET_ADDRESS (sockaddr))
302     {
303       printf ("Error:   Unexpected sockaddr type '%s'\n", g_type_name_from_instance ((GTypeInstance *)sockaddr));
304       g_object_unref (sockaddr);
305     }
306   else
307     {
308       GInetSocketAddress *isa = G_INET_SOCKET_ADDRESS (sockaddr);
309       phys = g_inet_address_to_string (g_inet_socket_address_get_address (isa));
310       printf ("Address: %s%s%s:%d\n",
311               strchr (phys, ':') ? "[" : "", phys, strchr (phys, ':') ? "]" : "",
312               g_inet_socket_address_get_port (isa));
313       g_free (phys);
314       g_object_unref (sockaddr);
315     }
316 }
317
318 static void
319 do_sync_connectable (GSocketAddressEnumerator *enumerator)
320 {
321   GSocketAddress *sockaddr;
322   GError *error = NULL;
323
324   while ((sockaddr = g_socket_address_enumerator_next (enumerator, cancellable, &error)))
325     print_connectable_sockaddr (sockaddr, error);
326
327   g_object_unref (enumerator);
328   done_lookup ();
329 }
330
331 static void do_async_connectable (GSocketAddressEnumerator *enumerator);
332
333 static void
334 got_next_async (GObject *source, GAsyncResult *result, gpointer user_data)
335 {
336   GSocketAddressEnumerator *enumerator = G_SOCKET_ADDRESS_ENUMERATOR (source);
337   GSocketAddress *sockaddr;
338   GError *error = NULL;
339
340   sockaddr = g_socket_address_enumerator_next_finish (enumerator, result, &error);
341   if (sockaddr || error)
342     print_connectable_sockaddr (sockaddr, error);
343   if (sockaddr)
344     do_async_connectable (enumerator);
345   else
346     {
347       g_object_unref (enumerator);
348       done_lookup ();
349     }
350 }
351
352 static void
353 do_async_connectable (GSocketAddressEnumerator *enumerator)
354 {
355   g_socket_address_enumerator_next_async (enumerator, cancellable,
356                                           got_next_async, NULL);
357 }
358
359 static void
360 do_connectable (const char *arg, gboolean synchronous)
361 {
362   char **parts;
363   GSocketConnectable *connectable;
364   GSocketAddressEnumerator *enumerator;
365
366   if (strchr (arg, '/'))
367     {
368       /* service/protocol/domain */
369       parts = g_strsplit (arg, "/", 3);
370       if (!parts || !parts[2])
371         usage ();
372
373       connectable = g_network_service_new (parts[0], parts[1], parts[2]);
374     }
375   else
376     {
377       guint16 port;
378
379       parts = g_strsplit (arg, ":", 2);
380       if (parts && parts[1])
381         {
382           arg = parts[0];
383           port = strtoul (parts[1], NULL, 10);
384         }
385       else
386         port = 0;
387
388       if (g_hostname_is_ip_address (arg))
389         {
390           GInetAddress *addr = g_inet_address_new_from_string (arg);
391           GSocketAddress *sockaddr = g_inet_socket_address_new (addr, port);
392
393           g_object_unref (addr);
394           connectable = G_SOCKET_CONNECTABLE (sockaddr);
395         }
396       else
397         connectable = g_network_address_new (arg, port);
398     }
399
400   enumerator = g_socket_connectable_enumerate (connectable);
401   g_object_unref (connectable);
402
403   if (synchronous)
404     do_sync_connectable (enumerator);
405   else
406     do_async_connectable (enumerator);
407 }
408
409 #ifdef G_OS_UNIX
410 static int cancel_fds[2];
411
412 static void
413 interrupted (int sig)
414 {
415   signal (SIGINT, SIG_DFL);
416   write (cancel_fds[1], "x", 1);
417 }
418
419 static gboolean
420 async_cancel (GIOChannel *source, GIOCondition cond, gpointer cancellable)
421 {
422   g_cancellable_cancel (cancellable);
423   return FALSE;
424 }
425 #endif
426
427 int
428 main (int argc, char **argv)
429 {
430   gboolean threaded = FALSE, synchronous = FALSE;
431   gboolean use_connectable = FALSE;
432 #ifdef G_OS_UNIX
433   GIOChannel *chan;
434   guint watch;
435 #endif
436
437   /* We can't use GOptionContext because we use the arguments to
438    * decide whether or not to call g_thread_init().
439    */
440   while (argc >= 2 && argv[1][0] == '-')
441     {
442       if (!strcmp (argv[1], "-t"))
443         {
444           g_thread_init (NULL);
445           threaded = TRUE;
446         }
447       else if (!strcmp (argv[1], "-s"))
448         synchronous = TRUE;
449       else if (!strcmp (argv[1], "-c"))
450         use_connectable = TRUE;
451       else
452         usage ();
453
454       argv++;
455       argc--;
456     }
457   g_type_init ();
458
459   if (argc < 2 || (argc > 2 && use_connectable))
460     usage ();
461
462   resolver = g_resolver_get_default ();
463
464   cancellable = g_cancellable_new ();
465
466 #ifdef G_OS_UNIX
467   /* Set up cancellation; we want to cancel if the user ^C's the
468    * program, but we can't cancel directly from an interrupt.
469    */
470   signal (SIGINT, interrupted);
471
472   if (pipe (cancel_fds) == -1)
473     {
474       perror ("pipe");
475       exit (1);
476     }
477   chan = g_io_channel_unix_new (cancel_fds[0]);
478   watch = g_io_add_watch (chan, G_IO_IN, async_cancel, cancellable);
479   g_io_channel_unref (chan);
480 #endif
481
482   nlookups = argc - 1;
483   loop = g_main_loop_new (NULL, TRUE);
484
485   if (use_connectable)
486     do_connectable (argv[1], synchronous);
487   else
488     {
489       if (threaded && synchronous)
490         start_threaded_lookups (argv + 1, argc - 1);
491       else if (synchronous)
492         start_sync_lookups (argv + 1, argc - 1);
493       else
494         start_async_lookups (argv + 1, argc - 1);
495     }
496
497   g_main_loop_run (loop);
498   g_main_loop_unref (loop);
499
500 #ifdef G_OS_UNIX
501   g_source_remove (watch);
502 #endif
503   g_object_unref (cancellable);
504
505   return 0;
506 }