fix only cache variable long/short
[oweals/gnunet.git] / src / gns / gnunet-gns.c
1 /*
2      This file is part of GNUnet.
3      (C) 2012-2013 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 #include "platform.h"
26 #include <gnunet_util_lib.h>
27 #include <gnunet_dnsparser_lib.h>
28 #include <gnunet_identity_service.h>
29 #include <gnunet_gnsrecord_lib.h>
30 #include <gnunet_namestore_service.h>
31 #include <gnunet_gns_service.h>
32
33 /**
34  * Configuration we are using.
35  */
36 static const struct GNUNET_CONFIGURATION_Handle *cfg;
37
38 /**
39  * Handle to GNS service.
40  */
41 static struct GNUNET_GNS_Handle *gns;
42
43 /**
44  * Desired timeout for the lookup (default is no timeout).
45  */
46 static struct GNUNET_TIME_Relative timeout;
47
48 /**
49  * GNS name to lookup. (-u option)
50  */
51 static char *lookup_name;
52
53 /**
54  * record type to look up (-t option)
55  */
56 static char *lookup_type;
57
58 /**
59  * Identity of the zone to use for the lookup (-z option)
60  */
61 static char *zone_ego_name;
62
63 /**
64  * Public key of the zone to use for the lookup (-p option)
65  */
66 static char *public_key;
67
68 /**
69  * Set to #GNUNET_YES if we must not use the DHT (only local lookup).
70  */
71 static int only_cached;
72
73 /**
74  * raw output
75  */
76 static int raw;
77
78 /**
79  * Requested record type.
80  */
81 static int rtype;
82
83 /**
84  * Handle to lookup request
85  */
86 static struct GNUNET_GNS_LookupRequest *lookup_request;
87
88 /**
89  * Lookup an ego with the identity service.
90  */
91 static struct GNUNET_IDENTITY_EgoLookup *el;
92
93 /**
94  * Handle for identity service.
95  */
96 static struct GNUNET_IDENTITY_Handle *identity;
97
98 /**
99  * Active operation on identity service.
100  */
101 static struct GNUNET_IDENTITY_Operation *id_op;
102
103
104 /**
105  * Task run on shutdown.  Cleans up everything.
106  *
107  * @param cls unused
108  * @param tc scheduler context
109  */
110 static void
111 do_shutdown (void *cls,
112              const struct GNUNET_SCHEDULER_TaskContext *tc)
113 {
114   if (NULL != el)
115   {
116     GNUNET_IDENTITY_ego_lookup_cancel (el);
117     el = NULL;
118   }
119   if (NULL != id_op)
120   {
121     GNUNET_IDENTITY_cancel (id_op);
122     id_op = NULL;
123   }
124   if (NULL != lookup_request)
125   {
126     GNUNET_GNS_lookup_cancel (lookup_request);
127     lookup_request = NULL;
128   }
129   if (NULL != identity)
130   {
131     GNUNET_IDENTITY_disconnect (identity);
132     identity = NULL;
133   }
134   if (NULL != gns)
135   {
136     GNUNET_GNS_disconnect (gns);
137     gns = NULL;
138   }
139 }
140
141
142 /**
143  * Function called with the result of a GNS lookup.
144  *
145  * @param cls the 'const char *' name that was resolved
146  * @param rd_count number of records returned
147  * @param rd array of @a rd_count records with the results
148  */
149 static void
150 process_lookup_result (void *cls, uint32_t rd_count,
151                        const struct GNUNET_GNSRECORD_Data *rd)
152 {
153   const char *name = cls;
154   uint32_t i;
155   const char *typename;
156   char* string_val;
157
158   lookup_request = NULL;
159   if (!raw)
160   {
161     if (0 == rd_count)
162       printf ("No results.\n");
163     else
164       printf ("%s:\n",
165               name);
166   }
167   for (i=0; i<rd_count; i++)
168   {
169     if ( (rd[i].record_type != rtype) &&
170          (GNUNET_GNSRECORD_TYPE_ANY != rtype) )
171       continue;
172     typename = GNUNET_GNSRECORD_number_to_typename (rd[i].record_type);
173     string_val = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
174                                                    rd[i].data,
175                                                    rd[i].data_size);
176     if (NULL == string_val)
177     {
178       fprintf (stderr,
179                "Record %u of type %d malformed, skipping\n",
180                (unsigned int) i,
181                (int) rd[i].record_type);
182       continue;
183     }
184     if (raw)
185       printf ("%s\n",
186               string_val);
187     else
188       printf ("Got `%s' record: %s\n",
189               typename,
190               string_val);
191     GNUNET_free (string_val);
192   }
193   GNUNET_SCHEDULER_shutdown ();
194 }
195
196
197 /**
198  * Perform the actual resolution, starting with the zone
199  * identified by the given public key and the shorten zone.
200  *
201  * @param pkey public key to use for the zone, can be NULL
202  * @param shorten_key private key used for shortening, can be NULL
203  */
204 static void
205 lookup_with_keys (const struct GNUNET_CRYPTO_EcdsaPublicKey *pkey,
206                   const struct GNUNET_CRYPTO_EcdsaPrivateKey *shorten_key)
207 {
208   if (NULL != lookup_type)
209     rtype = GNUNET_GNSRECORD_typename_to_number (lookup_type);
210   else
211     rtype = GNUNET_DNSPARSER_TYPE_A;
212
213   if (NULL != lookup_name)
214   {
215     lookup_request = GNUNET_GNS_lookup (gns,
216                                         lookup_name,
217                                         pkey,
218                                         rtype,
219                                         only_cached,
220                                         shorten_key,
221                                         &process_lookup_result,
222                                         lookup_name);
223   }
224   else
225   {
226     fprintf (stderr,
227              _("Please specify name to lookup!\n"));
228     GNUNET_SCHEDULER_shutdown ();
229     return;
230   }
231 }
232
233
234 /**
235  * Method called to with the ego we are to use for shortening
236  * during the lookup.
237  *
238  * @param cls closure contains the public key to use
239  * @param ego ego handle, NULL if not found
240  * @param ctx context for application to store data for this ego
241  *                 (during the lifetime of this process, initially NULL)
242  * @param name name assigned by the user for this ego,
243  *                   NULL if the user just deleted the ego and it
244  *                   must thus no longer be used
245  */
246 static void
247 identity_shorten_cb (void *cls,
248                      struct GNUNET_IDENTITY_Ego *ego,
249                      void **ctx,
250                      const char *name)
251 {
252   struct GNUNET_CRYPTO_EcdsaPublicKey *pkeym = cls;
253
254   id_op = NULL;
255   if (NULL == ego)
256     lookup_with_keys (pkeym, NULL);
257   else
258     lookup_with_keys (pkeym,
259                       GNUNET_IDENTITY_ego_get_private_key (ego));
260   GNUNET_free (pkeym);
261 }
262
263
264 /**
265  * Perform the actual resolution, starting with the zone
266  * identified by the given public key.
267  *
268  * @param pkey public key to use for the zone
269  */
270 static void
271 lookup_with_public_key (const struct GNUNET_CRYPTO_EcdsaPublicKey *pkey)
272 {
273   struct GNUNET_CRYPTO_EcdsaPublicKey *pkeym;
274
275   GNUNET_assert (NULL != pkey);
276   pkeym = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPublicKey);
277   *pkeym = *pkey;
278   GNUNET_break (NULL == id_op);
279   id_op = GNUNET_IDENTITY_get (identity,
280                                "gns-short",
281                                &identity_shorten_cb,
282                                pkeym);
283   if (NULL == id_op)
284   {
285     GNUNET_break (0);
286     lookup_with_keys (pkey, NULL);
287   }
288 }
289
290
291 /**
292  * Method called to with the ego we are to use for the lookup,
293  * when the ego is determined by a name.
294  *
295  * @param cls closure (NULL, unused)
296  * @param ego ego handle, NULL if not found
297  */
298 static void
299 identity_zone_cb (void *cls,
300                   const struct GNUNET_IDENTITY_Ego *ego)
301 {
302   struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
303
304   el = NULL;
305   if (NULL == ego)
306   {
307     fprintf (stderr,
308              _("Ego for `%s' not found, cannot perform lookup.\n"),
309              zone_ego_name);
310     GNUNET_SCHEDULER_shutdown ();
311   }
312   else
313   {
314     GNUNET_IDENTITY_ego_get_public_key (ego, &pkey);
315     lookup_with_public_key (&pkey);
316   }
317   GNUNET_free_non_null (zone_ego_name);
318   zone_ego_name = NULL;
319 }
320
321
322 /**
323  * Method called to with the ego we are to use for the lookup,
324  * when the ego is the one for the default master zone.
325  *
326  * @param cls closure (NULL, unused)
327  * @param ego ego handle, NULL if not found
328  * @param ctx context for application to store data for this ego
329  *                 (during the lifetime of this process, initially NULL)
330  * @param name name assigned by the user for this ego,
331  *                   NULL if the user just deleted the ego and it
332  *                   must thus no longer be used
333  */
334 static void
335 identity_master_cb (void *cls,
336                     struct GNUNET_IDENTITY_Ego *ego,
337                     void **ctx,
338                     const char *name)
339 {
340   struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
341   const char *dot;
342
343   id_op = NULL;
344   if (NULL == ego)
345   {
346     fprintf (stderr,
347              _("Ego for `gns-master' not found, cannot perform lookup.  Did you run gnunet-gns-import.sh?\n"));
348     GNUNET_SCHEDULER_shutdown ();
349     return;
350   }
351   GNUNET_IDENTITY_ego_get_public_key (ego, &pkey);
352   /* if the name is of the form 'label.gnu', never go to the DHT */
353   dot = strchr (lookup_name, '.');
354   if ( (NULL != dot) &&
355        (0 == strcasecmp (dot, ".gnu")) )
356     only_cached = GNUNET_YES;
357   lookup_with_public_key (&pkey);
358 }
359
360
361 /**
362  * Main function that will be run.
363  *
364  * @param cls closure
365  * @param args remaining command-line arguments
366  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
367  * @param c configuration
368  */
369 static void
370 run (void *cls, char *const *args, const char *cfgfile,
371      const struct GNUNET_CONFIGURATION_Handle *c)
372 {
373   struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
374
375   cfg = c;
376   gns = GNUNET_GNS_connect (cfg);
377   identity = GNUNET_IDENTITY_connect (cfg, NULL, NULL);
378   if (NULL == gns)
379   {
380     fprintf (stderr,
381              _("Failed to connect to GNS\n"));
382     return;
383   }
384   GNUNET_SCHEDULER_add_delayed (timeout,
385                                 &do_shutdown, NULL);
386   if (NULL != public_key)
387   {
388     if (GNUNET_OK !=
389         GNUNET_CRYPTO_ecdsa_public_key_from_string (public_key,
390                                                   strlen (public_key),
391                                                   &pkey))
392     {
393       fprintf (stderr,
394                _("Public key `%s' is not well-formed\n"),
395                public_key);
396       GNUNET_SCHEDULER_shutdown ();
397       return;
398     }
399     lookup_with_public_key (&pkey);
400     return;
401   }
402   if (NULL != zone_ego_name)
403   {
404     el = GNUNET_IDENTITY_ego_lookup (cfg,
405                                      zone_ego_name,
406                                      &identity_zone_cb,
407                                      NULL);
408     return;
409   }
410   if ( (NULL != lookup_name) &&
411        (strlen (lookup_name) > 4) &&
412        (0 == strcmp (".zkey",
413                      &lookup_name[strlen (lookup_name) - 4])) )
414   {
415     /* no zone required, use 'anonymous' zone */
416     GNUNET_CRYPTO_ecdsa_key_get_public (GNUNET_CRYPTO_ecdsa_key_get_anonymous (),
417                                       &pkey);
418     lookup_with_public_key (&pkey);
419   }
420   else
421   {
422     GNUNET_break (NULL == id_op);
423     id_op = GNUNET_IDENTITY_get (identity,
424                                  "gns-master",
425                                  &identity_master_cb,
426                                  NULL);
427     GNUNET_assert (NULL != id_op);
428   }
429 }
430
431
432 /**
433  * The main function for gnunet-gns.
434  *
435  * @param argc number of arguments from the command line
436  * @param argv command line arguments
437  * @return 0 ok, 1 on error
438  */
439 int
440 main (int argc, char *const *argv)
441 {
442   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
443     {'u', "lookup", "NAME",
444       gettext_noop ("Lookup a record for the given name"), 1,
445       &GNUNET_GETOPT_set_string, &lookup_name},
446     {'t', "type", "TYPE",
447       gettext_noop ("Specify the type of the record to lookup"), 1,
448       &GNUNET_GETOPT_set_string, &lookup_type},
449     { 'T', "timeout", "DELAY",
450       gettext_noop ("Specify timeout for the lookup"), 1,
451       &GNUNET_GETOPT_set_relative_time, &timeout },
452     {'r', "raw", NULL,
453       gettext_noop ("No unneeded output"), 0,
454       &GNUNET_GETOPT_set_one, &raw},
455     {'p', "public-key", "PKEY",
456       gettext_noop ("Specify the public key of the zone to lookup the record in"), 1,
457       &GNUNET_GETOPT_set_string, &public_key},
458     {'z', "zone", "NAME",
459       gettext_noop ("Specify the name of the ego of the zone to lookup the record in"), 1,
460       &GNUNET_GETOPT_set_string, &zone_ego_name},
461     GNUNET_GETOPT_OPTION_END
462   };
463   int ret;
464
465   timeout = GNUNET_TIME_UNIT_FOREVER_REL;
466   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
467     return 2;
468
469   GNUNET_log_setup ("gnunet-gns", "WARNING", NULL);
470   ret =
471       (GNUNET_OK ==
472        GNUNET_PROGRAM_run (argc, argv, "gnunet-gns",
473                            _("GNUnet GNS resolver tool"),
474                            options,
475                            &run, NULL)) ? 0 : 1;
476   GNUNET_free ((void*) argv);
477   return ret;
478 }
479
480 /* end of gnunet-gns.c */