fix compiler warning for format string
[oweals/gnunet.git] / src / gns / gnunet-service-gns_reverser.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009-2013 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 gns/gnunet-service-gns_reverser.c
22  * @brief GNUnet GNS service
23  * @author Martin Schanzenbach
24  */
25
26
27 #include "platform.h"
28 #include "gnunet_gns_service.h"
29 #include "gnunet-service-gns_resolver.h"
30 #include "gnunet-service-gns_reverser.h"
31
32 struct ReverseRecordEntry
33 {
34   /**
35    * DLL
36    */
37   struct ReverseRecordEntry *next;
38
39   /**
40    * DLL
41    */
42   struct ReverseRecordEntry *prev;
43
44   /**
45    * ReverseRecord
46    */
47   struct GNUNET_GNSRECORD_ReverseRecord *record;
48
49   /**
50    * Record length
51    */
52   size_t record_len;
53
54 };
55
56 struct IteratorHandle
57 {
58   /**
59    * Records found
60    */
61   struct ReverseRecordEntry *records_head;
62
63   /**
64    * Records found
65    */
66   struct ReverseRecordEntry *records_tail;
67
68   /**
69    * Record count
70    */
71   uint64_t record_count;
72
73   /**
74    * Current delegation to expect
75    */
76   struct GNUNET_CRYPTO_EcdsaPublicKey target;
77
78   /**
79    * Queue entry
80    */
81   struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
82
83 };
84
85 struct ReverseTreeNode
86 {
87   /**
88    * DLL
89    */
90   struct ReverseTreeNode *next;
91
92   /**
93    * DLL
94    */
95   struct ReverseTreeNode *prev;
96
97   /**
98    * Resolved name until now
99    */
100   char *name;
101
102   /**
103    * Depth of the resolution at this node
104    */
105   uint8_t depth;
106
107   /**
108    * The pkey of the namespace
109    */
110   struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
111
112 };
113
114
115 struct GNS_ReverserHandle
116 {
117   /**
118    * GNS resolver handle
119    */
120   struct GNS_ResolverHandle *rh;
121
122   /**
123    * The authority to look for
124    */
125   struct GNUNET_CRYPTO_EcdsaPublicKey authority;
126
127   /**
128    * Resolution candidate queue
129    */
130   struct ReverseTreeNode *node_queue_head;
131
132   /**
133    * Resolution candidate queue
134    */
135   struct ReverseTreeNode *node_queue_tail;
136
137   /**
138    * Max depth for the resolution
139    */
140   uint8_t max_depth;
141
142   /**
143    * Result callback
144    */
145   GNS_ReverseResultProcessor proc;
146
147   /**
148    * Callback closure
149    */
150   void *proc_cls;
151 };
152
153 /**
154  * Reverse record collection task
155  */
156 static struct GNUNET_SCHEDULER_Task *reverse_record_check_task;
157
158 /**
159  * NS iterator task
160  */
161 static struct GNUNET_SCHEDULER_Task *it_task;
162
163 /**
164  * GNS lookup handle
165  */
166 static struct GNS_ResolverHandle *gns_lookup_reverse;
167
168 /**
169  * NS handle
170  */
171 static struct GNUNET_NAMESTORE_Handle *ns;
172
173 /**
174  * NS Iterator
175  */
176 static struct GNUNET_NAMESTORE_ZoneIterator *namestore_iter;
177
178 /**
179  * The zone target for reverse record resolution
180  */
181 static struct GNUNET_CRYPTO_EcdsaPublicKey myzone;
182
183 /**
184  * The zone target for reverse record resolution
185  */
186 static struct GNUNET_CRYPTO_EcdsaPrivateKey pzone;
187
188 /**
189  * The nick of our zone
190  */
191 static char *mynick;
192
193
194 static void
195 cleanup_handle (struct GNS_ReverserHandle *rh)
196 {
197   struct ReverseTreeNode *rtn;
198
199   for (rtn = rh->node_queue_head; NULL != rtn; rtn = rh->node_queue_head)
200   {
201     if (NULL != rtn->name)
202       GNUNET_free (rtn->name);
203         GNUNET_CONTAINER_DLL_remove (rh->node_queue_head,
204                                  rh->node_queue_tail,
205                                  rtn);
206         GNUNET_free (rtn);
207   }
208   GNUNET_free (rh);
209 }
210
211 static void
212 handle_gns_result (void *cls,
213                    uint32_t rd_count,
214                    const struct GNUNET_GNSRECORD_Data *rd)
215 {
216   struct GNS_ReverserHandle *rh = cls;
217   const struct GNUNET_GNSRECORD_ReverseRecord *rr;
218   struct ReverseTreeNode *rtn;
219   char *result;
220   const char *name;
221   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
222               "Got result (%d)\n", rd_count);
223
224   for (int i = 0; i < rd_count; i++)
225   {
226     /**
227      * Check if we are in the delegation set
228      */
229     if (GNUNET_GNSRECORD_TYPE_REVERSE != rd[i].record_type)
230       continue;
231     rr = rd[i].data;
232     name = (const char*) &rr[1];
233     if (0 == memcmp (&rh->authority,
234                      &rr->pkey,
235                      sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
236     {
237       //Found!
238       GNUNET_asprintf (&result,
239                        "%s.%s.gnu",
240                        rh->node_queue_head->name,
241                        name);
242       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
243                   "Found path from %s\n", result);
244
245       rh->proc (rh->proc_cls, result);
246       cleanup_handle (rh);
247       GNUNET_free (result);
248       return;
249     } else {
250       if (rh->node_queue_head->depth >= rh->max_depth)
251         break;
252       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
253                   "Found REVERSE from %s\n", name);
254
255       rtn = GNUNET_new (struct ReverseTreeNode);
256       if (NULL == rh->node_queue_head->name)
257         rtn->name = GNUNET_strdup (name);
258       else
259         GNUNET_asprintf (&rtn->name,
260                          "%s.%s",
261                          rh->node_queue_head->name,
262                          name);
263       rtn->depth = rh->node_queue_head->depth + 1;
264       rtn->pkey = rr->pkey;
265       GNUNET_CONTAINER_DLL_insert_tail (rh->node_queue_head,
266                                         rh->node_queue_tail,
267                                         rtn);
268     }
269   }
270
271   /**
272    * Done here remove node from queue
273    */
274   rtn = rh->node_queue_head;
275   if (NULL != rtn)
276     GNUNET_CONTAINER_DLL_remove (rh->node_queue_head,
277                                  rh->node_queue_tail,
278                                  rtn);
279   if (NULL == rh->node_queue_head)
280   {
281     //No luck
282     rh->proc (rh->proc_cls, NULL);
283     cleanup_handle (rh);
284     return;
285   }
286   rh->rh = GNS_resolver_lookup (&rh->node_queue_head->pkey,
287                                 GNUNET_GNSRECORD_TYPE_REVERSE,
288                                 "+.gnu",
289                                 NULL,
290                                 GNUNET_GNS_LO_DEFAULT,
291                                 &handle_gns_result,
292                                 rh);
293 }
294
295 /**
296  * Reverse lookup of a specific zone
297  * calls RecordLookupProcessor on result or timeout
298  *
299  * @param target the zone to perform the lookup in
300  * @param authority the authority
301  * @param proc the processor to call
302  * @param proc_cls the closure to pass to @a proc
303  * @return handle to cancel operation
304  */
305 struct GNS_ReverserHandle *
306 GNS_reverse_lookup (const struct GNUNET_CRYPTO_EcdsaPublicKey *target,
307                     const struct GNUNET_CRYPTO_EcdsaPublicKey *authority,
308                     GNS_ReverseResultProcessor proc,
309                     void *proc_cls)
310 {
311   struct GNS_ReverserHandle *rh;
312   struct ReverseTreeNode *rtn;
313
314   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
315               "Starting reverse resolution\n");
316   rh = GNUNET_new (struct GNS_ReverserHandle);
317   rh->proc = proc;
318   rh->proc_cls = proc_cls;
319   rtn = GNUNET_new (struct ReverseTreeNode);
320   rtn->name = NULL;
321   rtn->pkey = *target;
322   rtn->depth = 0;
323   GNUNET_CONTAINER_DLL_insert (rh->node_queue_head,
324                                rh->node_queue_tail,
325                                rtn);
326   rh->authority = *authority;
327   rh->max_depth = 3; //TODO make argument
328   rh->rh = GNS_resolver_lookup (target,
329                                 GNUNET_GNSRECORD_TYPE_REVERSE,
330                                 "+.gnu",
331                                 NULL,
332                                 GNUNET_GNS_LO_DEFAULT,
333                                 &handle_gns_result,
334                                 rh);
335   return rh;
336 }
337
338 /**
339  * Cancel active resolution (i.e. client disconnected).
340  *
341  * @param rh resolution to abort
342  */
343 void
344 GNS_reverse_lookup_cancel (struct GNS_ReverserHandle *rh)
345 {
346   cleanup_handle (rh);
347   return;
348 }
349
350 /********************************************
351  * Reverse iterator
352  * ******************************************/
353
354
355 static void
356 next_it (void *cls);
357
358 static void
359 handle_gns_result_iter (void *cls,
360                         uint32_t rd_count,
361                         const struct GNUNET_GNSRECORD_Data *rd)
362 {
363   struct IteratorHandle *ith = cls;
364   struct ReverseRecordEntry *rr;
365   gns_lookup_reverse = NULL;
366   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
367               "GNS for REVERSE (%s)\n", mynick);
368
369
370   if ((rd_count != 1) ||
371       (GNUNET_GNSRECORD_TYPE_PKEY != rd->record_type))
372   {
373     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
374                 "GNS invalid REVERSE (%s)\n", mynick);
375     gns_lookup_reverse = NULL;
376     it_task = GNUNET_SCHEDULER_add_now (&next_it, ith);
377     return;
378   }
379
380
381   rr = GNUNET_new (struct ReverseRecordEntry);
382   rr->record_len = sizeof (struct GNUNET_GNSRECORD_ReverseRecord)
383     + strlen (mynick) + 1;
384   rr->record = GNUNET_malloc (rr->record_len);
385   rr->record->pkey = ith->target;
386   rr->record->expiration.abs_value_us = rd->expiration_time;
387   GNUNET_memcpy ((char*)&rr->record[1],
388                  mynick,
389                  strlen (mynick));
390   GNUNET_CONTAINER_DLL_insert (ith->records_head,
391                                ith->records_tail,
392                                rr);
393   ith->record_count++;
394   it_task = GNUNET_SCHEDULER_add_now (&next_it, ith);
395 }
396
397 static void
398 next_it (void *cls)
399 {
400   it_task = NULL;
401   GNUNET_assert (NULL != namestore_iter);
402   GNUNET_NAMESTORE_zone_iterator_next (namestore_iter);
403 }
404
405 static void
406 iterator_cb (void *cls,
407              const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
408              const char *label,
409              unsigned int rd_count,
410              const struct GNUNET_GNSRECORD_Data *rd)
411 {
412   struct IteratorHandle *ith = cls;
413   struct GNUNET_CRYPTO_EcdsaPublicKey zone;
414   char *name;
415
416   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
417               "iterating for REVERSE (%s / %s)\n",
418               label,
419               mynick);
420
421
422   if ((rd_count != 1) ||
423       (GNUNET_GNSRECORD_TYPE_PKEY != rd->record_type))
424   {
425     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
426                 "wrong format (%s)\n", mynick);
427
428
429     it_task = GNUNET_SCHEDULER_add_now (&next_it, ith);
430     return;
431   }
432   GNUNET_CRYPTO_ecdsa_key_get_public (key,
433                                       &zone);
434   if (0 != memcmp (&zone, &myzone,
435                    sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
436   {
437     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
438                 "wrong zone (%s)\n", mynick);
439
440
441     it_task = GNUNET_SCHEDULER_add_now (&next_it, ith);
442     return;
443   }
444   ith->target = *((struct GNUNET_CRYPTO_EcdsaPublicKey *) rd->data);
445   GNUNET_asprintf (&name,
446                   "%s.gnu",
447                   mynick);
448   gns_lookup_reverse = GNS_resolver_lookup (&ith->target,
449                                             GNUNET_GNSRECORD_TYPE_PKEY,
450                                             name,
451                                             NULL,
452                                             GNUNET_GNS_LO_DEFAULT,
453                                             &handle_gns_result_iter,
454                                             ith);
455   GNUNET_free (name);
456 }
457
458 static void check_reverse_records (void *cls);
459
460 static void
461 store_reverse (void *cls,
462                int32_t success,
463                const char *emsg)
464 {
465   struct IteratorHandle *ith = cls;
466   struct ReverseRecordEntry *rr;
467
468   if (GNUNET_SYSERR == success)
469   {
470     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
471                 "%s\n",
472                 emsg);
473   }
474   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stored records (%s)\n", mynick);
475
476   for (rr = ith->records_head; NULL != rr; rr = ith->records_head)
477   {
478     GNUNET_CONTAINER_DLL_remove (ith->records_head,
479                                  ith->records_tail,
480                                  rr);
481     GNUNET_free (rr->record);
482     GNUNET_free (rr);
483   }
484   reverse_record_check_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_DAYS,
485                                                             &check_reverse_records,
486                                                             NULL);
487   GNUNET_free (ith);
488 }
489
490 static void
491 finished_cb (void *cls)
492 {
493   struct IteratorHandle *ith = cls;
494   struct ReverseRecordEntry *rr;
495   struct GNUNET_GNSRECORD_Data rd[ith->record_count];
496
497   memset (rd, 0, sizeof (struct GNUNET_GNSRECORD_Data) * ith->record_count);
498
499   rr = ith->records_head;
500   for (int i = 0; i < ith->record_count; i++)
501   {
502     rd[i].data_size = rr->record_len;
503     rd[i].data = GNUNET_malloc (rr->record_len);
504     rd[i].record_type = GNUNET_GNSRECORD_TYPE_REVERSE;
505     rd[i].expiration_time = rr->record->expiration.abs_value_us;
506     GNUNET_memcpy ((char*) rd[i].data,
507                    rr->record,
508                    rr->record_len);
509     rr = rr->next;
510   }
511   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
512               "Finished iterating for REVERSE\n");
513
514   ith->ns_qe = GNUNET_NAMESTORE_records_store (ns,
515                                                &pzone,
516                                                "+",
517                                                ith->record_count,
518                                                rd,
519                                                &store_reverse,
520                                                ith);
521   namestore_iter = NULL;
522
523 }
524
525 static void
526 it_error (void *cls)
527 {
528   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
529               "Error iterating for REVERSE\n");
530 }
531
532 static void
533 check_reverse_records (void *cls)
534 {
535   struct IteratorHandle *ith;
536   ith = GNUNET_new (struct IteratorHandle);
537   ith->record_count = 0;
538   reverse_record_check_task = NULL;
539   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
540               "Start iterating for REVERSE (%s)\n", mynick);
541   namestore_iter = GNUNET_NAMESTORE_zone_iteration_start (ns,
542                                                           NULL,
543                                                           &it_error,
544                                                           ith,
545                                                           &iterator_cb,
546                                                           ith,
547                                                           &finished_cb,
548                                                           ith);
549 }
550
551
552 /**
553  * Initialize reverser
554  *
555  * @param nh handle to a namestore
556  * @param key the private key of the gns-reverse zone
557  * @param name the name of the gns-reverse zone
558  * @return GNUNET_OK
559  */
560 int
561 GNS_reverse_init (struct GNUNET_NAMESTORE_Handle *nh,
562                   const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
563                   const char *nick)
564 {
565   GNUNET_asprintf (&mynick,
566                    "%s",
567                    nick);
568   GNUNET_CRYPTO_ecdsa_key_get_public (zone,
569                                       &myzone);
570   GNUNET_memcpy (&pzone,
571                  zone,
572                  sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
573   ns = nh;
574   reverse_record_check_task = GNUNET_SCHEDULER_add_now (&check_reverse_records,
575                                                         NULL);
576   return GNUNET_OK;
577 }
578
579 /**
580  * Cleanup reverser
581  */
582 void
583 GNS_reverse_done ()
584 {
585   if (NULL != mynick)
586     GNUNET_free (mynick);
587   if (NULL != it_task)
588     GNUNET_SCHEDULER_cancel (it_task);
589   if (NULL != reverse_record_check_task)
590     GNUNET_SCHEDULER_cancel (reverse_record_check_task);
591   if (NULL != gns_lookup_reverse)
592     GNS_resolver_lookup_cancel (gns_lookup_reverse);
593   if (NULL != namestore_iter)
594     GNUNET_NAMESTORE_zone_iteration_stop (namestore_iter);
595 }
596