tighten formatting rules
[oweals/gnunet.git] / src / gns / gnunet-gns.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2012-2013, 2017-2018 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      Affero General Public License for more details.
14
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
19  */
20 /**
21  * @file gnunet-gns.c
22  * @brief command line tool to access distributed GNS
23  * @author Christian Grothoff
24  */
25 #include "platform.h"
26 #include <gnunet_util_lib.h>
27 #include <gnunet_dnsparser_lib.h>
28 #include <gnunet_gnsrecord_lib.h>
29 #include <gnunet_namestore_service.h>
30 #include <gnunet_gns_service.h>
31
32 /**
33  * Configuration we are using.
34  */
35 static const struct GNUNET_CONFIGURATION_Handle *cfg;
36
37 /**
38  * Handle to GNS service.
39  */
40 static struct GNUNET_GNS_Handle *gns;
41
42 /**
43  * GNS name to lookup. (-u option)
44  */
45 static char *lookup_name;
46
47 /**
48  * record type to look up (-t option)
49  */
50 static char *lookup_type;
51
52 /**
53  * raw output
54  */
55 static int raw;
56
57 /**
58  * Desired record type.
59  */
60 static uint32_t rtype;
61
62 /**
63  * Timeout for lookup
64  */
65 static struct GNUNET_TIME_Relative timeout;
66
67 /**
68  * Timeout task
69  */
70 static struct GNUNET_SCHEDULER_Task *to_task;
71
72 /**
73  * Handle to lookup request
74  */
75 static struct GNUNET_GNS_LookupWithTldRequest *lr;
76
77 /**
78  * Global return value.
79  * 0 on success (default),
80  * 1 on internal failures
81  * 2 on launch failure,
82  * 4 if the name is not a GNS-supported TLD,
83  */
84 static int global_ret;
85
86
87 /**
88  * Task run on shutdown.  Cleans up everything.
89  *
90  * @param cls unused
91  */
92 static void
93 do_shutdown (void *cls)
94 {
95   (void) cls;
96   if (NULL != to_task)
97   {
98     GNUNET_SCHEDULER_cancel (to_task);
99     to_task = NULL;
100   }
101   if (NULL != lr)
102   {
103     GNUNET_GNS_lookup_with_tld_cancel (lr);
104     lr = NULL;
105   }
106   if (NULL != gns)
107   {
108     GNUNET_GNS_disconnect (gns);
109     gns = NULL;
110   }
111 }
112
113
114 /**
115  * Task to run on timeout
116  *
117  * @param cls unused
118  */
119 static void
120 do_timeout (void*cls)
121 {
122   to_task = NULL;
123   global_ret = 3; // Timeout
124   GNUNET_SCHEDULER_shutdown ();
125 }
126
127
128 /**
129  * Function called with the result of a GNS lookup.
130  *
131  * @param cls the 'const char *' name that was resolved
132  * @param was_gns #GNUNET_NO if TLD did not indicate use of GNS
133  * @param rd_count number of records returned
134  * @param rd array of @a rd_count records with the results
135  */
136 static void
137 process_lookup_result (void *cls,
138                        int was_gns,
139                        uint32_t rd_count,
140                        const struct GNUNET_GNSRECORD_Data *rd)
141 {
142   const char *name = cls;
143   const char *typename;
144   char *string_val;
145
146   lr = NULL;
147   if (GNUNET_NO == was_gns)
148   {
149     global_ret = 4;   /* not for GNS */
150     GNUNET_SCHEDULER_shutdown ();
151     return;
152   }
153   if (! raw)
154   {
155     if (0 == rd_count)
156       printf ("No results.\n");
157     else
158       printf ("%s:\n", name);
159   }
160   for (uint32_t i = 0; i < rd_count; i++)
161   {
162     if ((rd[i].record_type != rtype) && (GNUNET_GNSRECORD_TYPE_ANY != rtype))
163       continue;
164     typename = GNUNET_GNSRECORD_number_to_typename (rd[i].record_type);
165     string_val = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
166                                                    rd[i].data,
167                                                    rd[i].data_size);
168     if (NULL == string_val)
169     {
170       fprintf (stderr,
171                "Record %u of type %d malformed, skipping\n",
172                (unsigned int) i,
173                (int) rd[i].record_type);
174       continue;
175     }
176     if (raw)
177       printf ("%s\n", string_val);
178     else
179       printf ("Got `%s' record: %s\n", typename, string_val);
180     GNUNET_free (string_val);
181   }
182   GNUNET_SCHEDULER_shutdown ();
183 }
184
185
186 /**
187  * Main function that will be run.
188  *
189  * @param cls closure
190  * @param args remaining command-line arguments
191  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
192  * @param c configuration
193  */
194 static void
195 run (void *cls,
196      char *const *args,
197      const char *cfgfile,
198      const struct GNUNET_CONFIGURATION_Handle *c)
199 {
200   (void) cls;
201   (void) args;
202   (void) cfgfile;
203
204   cfg = c;
205   to_task = NULL;
206   {
207     char *colon;
208
209     if (NULL != (colon = strchr (lookup_name, ':')))
210       *colon = '\0';
211   }
212   if (GNUNET_OK != GNUNET_DNSPARSER_check_name (lookup_name))
213   {
214     fprintf (stderr,
215              _ ("`%s' is not a valid domain name\n"),
216              lookup_name);
217     global_ret = 3;
218     return;
219   }
220   if (GNUNET_YES !=
221       GNUNET_CLIENT_test (cfg,
222                           "arm"))
223   {
224     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
225                 _ ("Cannot resolve using GNS: GNUnet peer not running\n"));
226     global_ret = 2;
227     return;
228   }
229   to_task = GNUNET_SCHEDULER_add_delayed (timeout,
230                                           &do_timeout,
231                                           NULL);
232   gns = GNUNET_GNS_connect (cfg);
233   if (NULL == gns)
234   {
235     fprintf (stderr,
236              _ ("Failed to connect to GNS\n"));
237     global_ret = 2;
238     return;
239   }
240   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
241                                  NULL);
242   if (NULL != lookup_type)
243     rtype = GNUNET_GNSRECORD_typename_to_number (lookup_type);
244   else
245     rtype = GNUNET_DNSPARSER_TYPE_A;
246   if (UINT32_MAX == rtype)
247   {
248     fprintf (stderr,
249              _ ("Invalid typename specified, assuming `ANY'\n"));
250     rtype = GNUNET_GNSRECORD_TYPE_ANY;
251   }
252   lr = GNUNET_GNS_lookup_with_tld (gns,
253                                    lookup_name,
254                                    rtype,
255                                    GNUNET_GNS_LO_DEFAULT,
256                                    &process_lookup_result,
257                                    lookup_name);
258   if (NULL == lr)
259   {
260     global_ret = 2;
261     GNUNET_SCHEDULER_shutdown ();
262     return;
263   }
264 }
265
266
267 /**
268  * The main function for gnunet-gns.
269  *
270  * @param argc number of arguments from the command line
271  * @param argv command line arguments
272  * @return 0 ok, 1 on error
273  */
274 int
275 main (int argc, char *const *argv)
276 {
277   timeout = GNUNET_TIME_UNIT_FOREVER_REL;
278   struct GNUNET_GETOPT_CommandLineOption options[] =
279   { GNUNET_GETOPT_option_mandatory (
280       GNUNET_GETOPT_option_string ('u',
281                                    "lookup",
282                                    "NAME",
283                                    gettext_noop (
284                                      "Lookup a record for the given name"),
285                                    &lookup_name)),
286     GNUNET_GETOPT_option_string ('t',
287                                  "type",
288                                  "TYPE",
289                                  gettext_noop (
290                                    "Specify the type of the record to lookup"),
291                                  &lookup_type),
292     GNUNET_GETOPT_option_relative_time ('T',
293                                         "timeout",
294                                         "TIMEOUT",
295                                         gettext_noop (
296                                           "Specify a timeout for the lookup"),
297                                         &timeout),
298     GNUNET_GETOPT_option_flag ('r',
299                                "raw",
300                                gettext_noop ("No unneeded output"),
301                                &raw),
302     GNUNET_GETOPT_OPTION_END };
303   int ret;
304
305   if (GNUNET_OK !=
306       GNUNET_STRINGS_get_utf8_args (argc, argv,
307                                     &argc, &argv))
308     return 2;
309
310   GNUNET_log_setup ("gnunet-gns", "WARNING", NULL);
311   ret = GNUNET_PROGRAM_run (argc,
312                             argv,
313                             "gnunet-gns",
314                             _ ("GNUnet GNS resolver tool"),
315                             options,
316                             &run,
317                             NULL);
318   GNUNET_free ((void *) argv);
319   if (GNUNET_OK != ret)
320     return 1;
321   return global_ret;
322 }
323
324
325 /* end of gnunet-gns.c */