add convenience API to gnunetgns lib
[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
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      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      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
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  * Set to GNUNET_GNS_LO_LOCAL_MASTER if we are looking up in the master zone.
54  */
55 static enum GNUNET_GNS_LocalOptions local_options;
56
57 /**
58  * raw output
59  */
60 static int raw;
61
62 /**
63  * Desired record type.
64  */
65 static uint32_t rtype;
66
67 /**
68  * Handle to lookup request
69  */
70 static struct GNUNET_GNS_LookupWithTldRequest *lr;
71
72 /**
73  * Global return value.
74  * 0 on success (default),
75  * 1 on internal failures, 2 on launch failure,
76  * 3 if the name is not a GNS-supported TLD,
77  */
78 static int global_ret;
79
80
81 /**
82  * Task run on shutdown.  Cleans up everything.
83  *
84  * @param cls unused
85  */
86 static void
87 do_shutdown (void *cls)
88 {
89   (void) cls;
90   if (NULL != lr)
91   {
92     GNUNET_GNS_lookup_with_tld_cancel (lr);
93     lr = NULL;
94   }
95   if (NULL != gns)
96   {
97     GNUNET_GNS_disconnect (gns);
98     gns = NULL;
99   }
100 }
101
102
103 /**
104  * Function called with the result of a GNS lookup.
105  *
106  * @param cls the 'const char *' name that was resolved
107  * @param was_gns #GNUNET_NO if TLD did not indicate use of GNS
108  * @param rd_count number of records returned
109  * @param rd array of @a rd_count records with the results
110  */
111 static void
112 process_lookup_result (void *cls,
113                        int was_gns,
114                        uint32_t rd_count,
115                        const struct GNUNET_GNSRECORD_Data *rd)
116 {
117   const char *name = cls;
118   const char *typename;
119   char* string_val;
120
121   lr = NULL;
122   if (GNUNET_NO == was_gns)
123   {
124     global_ret = 3;
125     GNUNET_SCHEDULER_shutdown ();
126     return;
127   }
128   if (! raw)
129   {
130     if (0 == rd_count)
131       printf ("No results.\n");
132     else
133       printf ("%s:\n",
134               name);
135   }
136   for (uint32_t i=0; i<rd_count; i++)
137   {
138     if ( (rd[i].record_type != rtype) &&
139          (GNUNET_GNSRECORD_TYPE_ANY != rtype) )
140       continue;
141     typename = GNUNET_GNSRECORD_number_to_typename (rd[i].record_type);
142     string_val = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
143                                                    rd[i].data,
144                                                    rd[i].data_size);
145     if (NULL == string_val)
146     {
147       fprintf (stderr,
148                "Record %u of type %d malformed, skipping\n",
149                (unsigned int) i,
150                (int) rd[i].record_type);
151       continue;
152     }
153     if (raw)
154       printf ("%s\n",
155               string_val);
156     else
157       printf ("Got `%s' record: %s\n",
158               typename,
159               string_val);
160     GNUNET_free (string_val);
161   }
162   GNUNET_SCHEDULER_shutdown ();
163 }
164
165
166 /**
167  * Main function that will be run.
168  *
169  * @param cls closure
170  * @param args remaining command-line arguments
171  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
172  * @param c configuration
173  */
174 static void
175 run (void *cls,
176      char *const *args,
177      const char *cfgfile,
178      const struct GNUNET_CONFIGURATION_Handle *c)
179 {
180   (void) cls;
181   (void) args;
182   (void) cfgfile;
183   
184   cfg = c;
185   gns = GNUNET_GNS_connect (cfg);
186   if (NULL == gns)
187   {
188     fprintf (stderr,
189              _("Failed to connect to GNS\n"));
190     global_ret = 2;
191     return;
192   }
193   
194   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
195                                  NULL);
196
197   if (NULL != lookup_type)
198     rtype = GNUNET_GNSRECORD_typename_to_number (lookup_type);
199   else
200     rtype = GNUNET_DNSPARSER_TYPE_A;
201   if (UINT32_MAX == rtype)
202   {
203     fprintf (stderr,
204              _("Invalid typename specified, assuming `ANY'\n"));
205     rtype = GNUNET_GNSRECORD_TYPE_ANY;
206   }
207   lr = GNUNET_GNS_lookup_with_tld (gns,
208                                    lookup_name,
209                                    rtype,
210                                    local_options,
211                                    &process_lookup_result,
212                                    NULL);
213   if (NULL == lr)
214   {
215     global_ret = 2;
216     GNUNET_SCHEDULER_shutdown ();
217     return;
218   }  
219 }
220
221
222 /**
223  * The main function for gnunet-gns.
224  *
225  * @param argc number of arguments from the command line
226  * @param argv command line arguments
227  * @return 0 ok, 1 on error
228  */
229 int
230 main (int argc,
231       char *const *argv)
232 {
233   struct GNUNET_GETOPT_CommandLineOption options[] = {
234     GNUNET_GETOPT_option_mandatory
235     (GNUNET_GETOPT_option_string ('u',
236                                   "lookup",
237                                   "NAME",
238                                   gettext_noop ("Lookup a record for the given name"),
239                                   &lookup_name)),
240     GNUNET_GETOPT_option_string ('t',
241                                  "type",
242                                  "TYPE",
243                                  gettext_noop ("Specify the type of the record to lookup"),
244                                  &lookup_type),
245     GNUNET_GETOPT_option_flag ('r',
246                                "raw",
247                                gettext_noop ("No unneeded output"),
248                                &raw),
249     GNUNET_GETOPT_OPTION_END
250   };
251   int ret;
252
253   if (GNUNET_OK !=
254       GNUNET_STRINGS_get_utf8_args (argc, argv,
255                                     &argc, &argv))
256     return 2;
257
258   GNUNET_log_setup ("gnunet-gns",
259                     "WARNING",
260                     NULL);
261   ret = GNUNET_PROGRAM_run (argc, argv,
262                             "gnunet-gns",
263                             _("GNUnet GNS resolver tool"),
264                             options,
265                             &run, NULL);
266   GNUNET_free ((void*) argv);
267   if (GNUNET_OK != ret)
268     return 1;
269   return global_ret;
270 }
271
272 /* end of gnunet-gns.c */