-fix gns cli hang, fix help
[oweals/gnunet.git] / src / gns / gnunet-gns.c
1 /*
2      This file is part of GNUnet.
3      (C) 2012 Christian Grothoff (and other contributing authors)
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., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20 /**
21  * @file gnunet-gns.c
22  * @brief command line tool to access distributed GNS
23  * @author Christian Grothoff
24  *
25  */
26 #include "platform.h"
27 #include <gnunet_util_lib.h>
28 #include <gnunet_dnsparser_lib.h>
29 #include <gnunet_namestore_service.h>
30 #include <gnunet_gns_service.h>
31
32 /**
33  * Handle to GNS service.
34  */
35 static struct GNUNET_GNS_Handle *gns;
36
37 /**
38  * GNS name to shorten. (-s option)
39  */
40 static char *shorten_name;
41
42 /**
43  * GNS name to lookup. (-u option)
44  */
45 static char *lookup_name;
46
47
48 /**
49  * record type to look up (-t option)
50  */
51 static char *lookup_type;
52
53 /**
54  * name to look up authority for (-a option)
55  */
56 static char *auth_name;
57
58 /**
59  * raw output
60  */
61 static int raw = 0;
62
63 static enum GNUNET_GNS_RecordType rtype;
64
65 /* Handle to lookup request */
66 static struct GNUNET_GNS_LookupRequest *lookup_request;
67
68 /* Handle to shorten request */
69 static struct GNUNET_GNS_ShortenRequest *shorten_request;
70
71 /* Handle to get authority request */
72 static struct GNUNET_GNS_GetAuthRequest *getauth_request;
73
74 /* shutdown task */
75 static GNUNET_SCHEDULER_TaskIdentifier shutdown_task;
76
77 /**
78  * Task run on shutdown.  Cleans up everything.
79  *
80  * @param cls unused
81  * @param tc scheduler context
82  */
83 static void
84 do_shutdown (void *cls,
85              const struct GNUNET_SCHEDULER_TaskContext *tc)
86 {
87   if (NULL != lookup_request)
88     GNUNET_GNS_cancel_lookup_request (lookup_request);
89
90   if (NULL != shorten_request)
91     GNUNET_GNS_cancel_shorten_request (shorten_request);
92
93   if (NULL != getauth_request)
94     GNUNET_GNS_cancel_get_auth_request (getauth_request);
95
96   if (NULL != gns)
97     GNUNET_GNS_disconnect (gns);
98 }
99
100
101 static void
102 process_shorten_result(void* cls, const char* nshort)
103 {
104   shorten_request = NULL;
105   if (raw)
106     printf("%s", nshort);
107   else
108     printf("%s shortened to %s\n", (char*) cls, nshort);
109   GNUNET_SCHEDULER_cancel (shutdown_task);
110   GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
111 }
112
113 static void
114 process_lookup_result(void* cls, uint32_t rd_count,
115                       const struct GNUNET_NAMESTORE_RecordData *rd)
116 {
117   int i;
118   char* name = (char*) cls;
119   const char* typename;
120   char* string_val;
121   lookup_request = NULL;
122   
123   if (!raw) {
124     if (rd_count == 0)
125       printf("No results.\n");
126     else
127       printf("%s:\n", name);
128   }
129
130
131
132   for (i=0; i<rd_count; i++)
133   {
134     typename = GNUNET_NAMESTORE_number_to_typename (rd[i].record_type);
135     string_val = GNUNET_NAMESTORE_value_to_string(rd[i].record_type,
136                                                   rd[i].data,
137                                                   rd[i].data_size);
138     if (raw)
139       printf("%s\n", string_val);
140     else
141       printf("Got %s record: %s\n", typename, string_val);
142
143   }
144   GNUNET_SCHEDULER_cancel (shutdown_task);
145   GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
146 }
147
148 static void
149 process_auth_result(void* cls, const char* auth)
150 {
151   getauth_request = NULL;
152   printf ("%s\n", auth);
153   GNUNET_SCHEDULER_cancel (shutdown_task);
154   GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
155 }
156
157 /**
158  * Main function that will be run.
159  *
160  * @param cls closure
161  * @param args remaining command-line arguments
162  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
163  * @param cfg configuration
164  */
165 static void
166 run (void *cls, char *const *args, const char *cfgfile,
167      const struct GNUNET_CONFIGURATION_Handle *cfg)
168 {
169   char* keyfile;
170   struct GNUNET_CRYPTO_RsaPrivateKey *key = NULL;
171   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey;
172   struct GNUNET_CRYPTO_ShortHashCode *zone = NULL;
173   struct GNUNET_CRYPTO_ShortHashCode user_zone;
174   struct GNUNET_CRYPTO_ShortHashAsciiEncoded zonename;
175   struct GNUNET_CRYPTO_RsaPrivateKey *shorten_key = NULL;
176   struct GNUNET_CRYPTO_RsaPrivateKey *private_key = NULL;
177   struct GNUNET_CRYPTO_ShortHashCode *private_zone = NULL;
178   struct GNUNET_CRYPTO_ShortHashCode *shorten_zone = NULL;
179
180   shorten_request = NULL;
181   lookup_request = NULL;
182   getauth_request = NULL;
183
184   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns",
185                                                            "ZONEKEY", &keyfile))
186   {
187     if (!raw)
188       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
189                   "No private key for root zone found, using default!\n");
190     zone = NULL;
191   }
192   else
193   {
194     if (GNUNET_YES == GNUNET_DISK_file_test (keyfile))
195     {
196       key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
197       GNUNET_CRYPTO_rsa_key_get_public (key, &pkey);
198       GNUNET_CRYPTO_short_hash(&pkey,
199                          sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
200                          &user_zone);
201       zone = &user_zone;
202       GNUNET_CRYPTO_short_hash_to_enc (zone, &zonename);
203       if (!raw)
204         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
205                     "Using zone: %s!\n", &zonename);
206       GNUNET_CRYPTO_rsa_key_free(key);
207     }
208     GNUNET_free(keyfile);
209   }
210   
211   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns",
212                                                    "SHORTEN_ZONEKEY", &keyfile))
213   {
214     if (!raw)
215       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
216                   "No shorten key found!\n");
217     shorten_key = NULL;
218   }
219   else
220   {
221     if (GNUNET_YES == GNUNET_DISK_file_test (keyfile))
222     {
223       shorten_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
224       GNUNET_CRYPTO_rsa_key_get_public (shorten_key, &pkey);
225       shorten_zone = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_ShortHashCode));
226       GNUNET_CRYPTO_short_hash(&pkey,
227                          sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
228                          shorten_zone);
229       GNUNET_CRYPTO_short_hash_to_enc (shorten_zone, &zonename);
230       if (!raw)
231         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
232                     "Using shorten zone: %s!\n", &zonename);
233
234     }
235     GNUNET_free(keyfile);
236   }
237   
238   
239   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns",
240                                                             "PRIVATE_ZONEKEY", &keyfile))
241   {
242     if (!raw)
243       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
244                   "No private zone key file name specified in configuration!\n");
245     shorten_key = NULL;
246   }
247   else
248   {
249     if (GNUNET_YES == GNUNET_DISK_file_test (keyfile))
250     {
251       private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
252       GNUNET_CRYPTO_rsa_key_get_public (private_key, &pkey);
253       private_zone = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_ShortHashCode));
254       GNUNET_CRYPTO_short_hash(&pkey,
255                          sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
256                          private_zone);
257       GNUNET_CRYPTO_short_hash_to_enc (private_zone, &zonename);
258       if (!raw)
259         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
260                     "Using private zone: %s!\n", &zonename);
261     }
262     else
263     {
264       /* FIXME: shouldn't we just create the private key in this case? */
265       if (!raw)
266         fprintf (stderr,
267                  _("Key file `%s' for private zone does not exist!\n"),
268                  keyfile);
269
270     }
271     GNUNET_free(keyfile);
272     if (NULL != private_key)
273     {
274       GNUNET_CRYPTO_rsa_key_free (private_key);
275       private_key = NULL;
276     }
277   }
278   
279   
280   gns = GNUNET_GNS_connect (cfg);
281   if (NULL != lookup_type)
282     rtype = GNUNET_NAMESTORE_typename_to_number (lookup_type);
283   else
284     rtype = GNUNET_GNS_RECORD_A;
285
286   if (NULL == gns)
287   {
288     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
289                 _("Failed to connect to GNS\n"));
290     return;
291   }
292   
293   if (NULL != shorten_name)
294   {
295     shorten_request = GNUNET_GNS_shorten_zone (gns, shorten_name,
296                              private_zone,
297                              shorten_zone,
298                              zone,
299                              &process_shorten_result,
300                              shorten_name);
301   }
302
303   if (NULL != lookup_name)
304   {
305     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
306                 "Lookup\n");
307     lookup_request = GNUNET_GNS_lookup_zone (gns, lookup_name,
308                             zone,
309                             rtype,
310                             GNUNET_NO, //Use DHT
311                             shorten_key,
312                             &process_lookup_result, lookup_name);
313   }
314
315   if (NULL != auth_name)
316   {
317     getauth_request = GNUNET_GNS_get_authority(gns, auth_name,
318                                                &process_auth_result, auth_name);
319   }
320
321   if (NULL != shorten_key)
322     GNUNET_CRYPTO_rsa_key_free (shorten_key);
323
324   if (NULL != shorten_zone)
325     GNUNET_free (shorten_zone);
326
327   if (NULL != private_zone)
328     GNUNET_free (private_zone);
329   
330   if ((NULL == auth_name) &&
331       (NULL == shorten_name) &&
332       (NULL == lookup_name))
333   {
334     if (!raw)
335       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
336                  "Please specify lookup, shorten or authority operation!\n");
337     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
338   }
339
340   shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
341                                                 &do_shutdown, NULL);
342 }
343
344
345 /**
346  * The main function for gnunet-gns.
347  *
348  * @param argc number of arguments from the command line
349  * @param argv command line arguments
350  * @return 0 ok, 1 on error
351  */
352 int
353 main (int argc, char *const *argv)
354 {
355   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
356     {'s', "shorten", NULL,
357      gettext_noop ("try to shorten a given name"), 1,
358      &GNUNET_GETOPT_set_string, &shorten_name},
359     {'u', "lookup", NULL,
360       gettext_noop ("Lookup a record for the given name"), 1,
361       &GNUNET_GETOPT_set_string, &lookup_name},
362     {'a', "authority", NULL,
363       gettext_noop ("Get the authority of a particular name"), 1,
364       &GNUNET_GETOPT_set_string, &auth_name},
365     {'t', "type", NULL,
366       gettext_noop ("Specify the type of the record to lookup"), 1,
367       &GNUNET_GETOPT_set_string, &lookup_type},
368     {'r', "raw", NULL,
369       gettext_noop ("No unneeded output"), 0,
370       &GNUNET_GETOPT_set_one, &raw},
371     GNUNET_GETOPT_OPTION_END
372   };
373
374   int ret;
375
376   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
377     return 2;
378
379   GNUNET_log_setup ("gnunet-gns", "WARNING", NULL);
380   ret =
381       (GNUNET_OK ==
382        GNUNET_PROGRAM_run (argc, argv, "gnunet-gns",
383                            _("GNUnet GNS access tool"), 
384                            options,
385                            &run, NULL)) ? 0 : 1;
386
387   return ret;
388 }
389
390 /* end of gnunet-gns.c */