RECLAIM: debug messages
[oweals/gnunet.git] / src / reclaim / gnunet-service-reclaim_tickets.c
1 /*
2    This file is part of GNUnet.
3    Copyright (C) 2012-2015 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 /**
22  * @author Martin Schanzenbach
23  * @file src/reclaim/gnunet-service-reclaim_tickets.c
24  * @brief reclaim tickets
25  *
26  */
27 #include <inttypes.h>
28
29 #include "gnunet-service-reclaim_tickets.h"
30
31 struct ParallelLookup;
32
33 struct RECLAIM_TICKETS_ConsumeHandle
34 {
35   /**
36    * Ticket
37    */
38   struct GNUNET_RECLAIM_Ticket ticket;
39
40   /**
41    * LookupRequest
42    */
43   struct GNUNET_GNS_LookupRequest *lookup_request;
44
45   /**
46    * Audience Key
47    */
48   struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
49
50   /**
51    * Audience Key
52    */
53   struct GNUNET_CRYPTO_EcdsaPublicKey identity_pub;
54
55   /**
56    * Lookup DLL
57    */
58   struct ParallelLookup *parallel_lookups_head;
59
60   /**
61    * Lookup DLL
62    */
63   struct ParallelLookup *parallel_lookups_tail;
64
65   /**
66    * Kill task
67    */
68   struct GNUNET_SCHEDULER_Task *kill_task;
69
70   /**
71    * Attributes
72    */
73   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs;
74
75   /**
76    * Lookup time
77    */
78   struct GNUNET_TIME_Absolute lookup_start_time;
79
80   /**
81    * Callback
82    */
83   RECLAIM_TICKETS_ConsumeCallback cb;
84
85   /**
86    * Callbacl closure
87    */
88   void *cb_cls;
89 };
90
91 /**
92  * Handle for a parallel GNS lookup job
93  */
94 struct ParallelLookup
95 {
96   /* DLL */
97   struct ParallelLookup *next;
98
99   /* DLL */
100   struct ParallelLookup *prev;
101
102   /* The GNS request */
103   struct GNUNET_GNS_LookupRequest *lookup_request;
104
105   /* The handle the return to */
106   struct RECLAIM_TICKETS_ConsumeHandle *handle;
107
108   /**
109    * Lookup time
110    */
111   struct GNUNET_TIME_Absolute lookup_start_time;
112
113   /* The label to look up */
114   char *label;
115 };
116
117
118 /**
119  * A reference to a ticket stored in GNS
120  */
121 struct TicketReference
122 {
123   /**
124    * DLL
125    */
126   struct TicketReference *next;
127
128   /**
129    * DLL
130    */
131   struct TicketReference *prev;
132
133   /**
134    * Attributes
135    */
136   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs;
137
138   /**
139    * Tickets
140    */
141   struct GNUNET_RECLAIM_Ticket ticket;
142 };
143
144
145 /**
146  * Ticket issue request handle
147  */
148 struct TicketIssueHandle
149 {
150   /**
151    * Attributes to issue
152    */
153   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs;
154
155   /**
156    * Issuer Key
157    */
158   struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
159
160   /**
161    * Ticket to issue
162    */
163   struct GNUNET_RECLAIM_Ticket ticket;
164
165   /**
166    * QueueEntry
167    */
168   struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
169
170   /**
171    * Callback
172    */
173   RECLAIM_TICKETS_TicketResult cb;
174
175   /**
176    * Callback cls
177    */
178   void *cb_cls;
179 };
180
181 /**
182  * Ticket iterator
183  */
184 struct RECLAIM_TICKETS_Iterator
185 {
186   /**
187    * Namestore queue entry
188    */
189   struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
190
191   /**
192    * Iter callback
193    */
194   RECLAIM_TICKETS_TicketIter cb;
195
196   /**
197    * Iter cls
198    */
199   void *cb_cls;
200 };
201
202
203 struct RevokedAttributeEntry
204 {
205   /**
206    * DLL
207    */
208   struct RevokedAttributeEntry *next;
209
210   /**
211    * DLL
212    */
213   struct RevokedAttributeEntry *prev;
214
215   /**
216    * Old ID of the attribute
217    */
218   uint64_t old_id;
219
220   /**
221    * New ID of the attribute
222    */
223   uint64_t new_id;
224 };
225
226
227 struct TicketRecordsEntry
228 {
229   /**
230    * DLL
231    */
232   struct TicketRecordsEntry *next;
233
234   /**
235    * DLL
236    */
237   struct TicketRecordsEntry *prev;
238
239   /**
240    * Record count
241    */
242   unsigned int rd_count;
243
244   /**
245    * Data
246    */
247   char *data;
248
249   /**
250    * Data size
251    */
252   size_t data_size;
253
254   /**
255    * Label
256    */
257   char *label;
258 };
259
260 /**
261  * Ticket revocation request handle
262  */
263 struct RECLAIM_TICKETS_RevokeHandle
264 {
265   /**
266    * Issuer Key
267    */
268   struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
269
270   /**
271    * Callback
272    */
273   RECLAIM_TICKETS_RevokeCallback cb;
274
275   /**
276    * Callback cls
277    */
278   void *cb_cls;
279
280   /**
281    * Ticket to issue
282    */
283   struct GNUNET_RECLAIM_Ticket ticket;
284
285   /**
286    * QueueEntry
287    */
288   struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
289
290   /**
291    * Namestore iterator
292    */
293   struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
294
295   /**
296    * Revoked attributes
297    */
298   struct RevokedAttributeEntry *attrs_head;
299
300   /**
301    * Revoked attributes
302    */
303   struct RevokedAttributeEntry *attrs_tail;
304
305   /**
306    * Current attribute to move
307    */
308   struct RevokedAttributeEntry *move_attr;
309
310   /**
311    * Number of attributes in ticket
312    */
313   unsigned int ticket_attrs;
314
315   /**
316    * Tickets to update
317    */
318   struct TicketRecordsEntry *tickets_to_update_head;
319
320   /**
321    * Tickets to update
322    */
323   struct TicketRecordsEntry *tickets_to_update_tail;
324 };
325
326
327 /* Namestore handle */
328 static struct GNUNET_NAMESTORE_Handle *nsh;
329
330 /* GNS handle */
331 static struct GNUNET_GNS_Handle *gns;
332
333 /* Handle to the statistics service */
334 static struct GNUNET_STATISTICS_Handle *stats;
335
336 static void
337 move_attrs (struct RECLAIM_TICKETS_RevokeHandle *rh);
338
339 static void
340 move_attrs_cont (void *cls)
341 {
342   move_attrs ((struct RECLAIM_TICKETS_RevokeHandle *)cls);
343 }
344
345 /**
346  * Cleanup revoke handle
347  *
348  * @param rh the ticket revocation handle
349  */
350 static void
351 cleanup_rvk (struct RECLAIM_TICKETS_RevokeHandle *rh)
352 {
353   struct RevokedAttributeEntry *ae;
354   struct TicketRecordsEntry *le;
355   if (NULL != rh->ns_qe)
356     GNUNET_NAMESTORE_cancel (rh->ns_qe);
357   if (NULL != rh->ns_it)
358     GNUNET_NAMESTORE_zone_iteration_stop (rh->ns_it);
359   while (NULL != (ae = rh->attrs_head)) {
360     GNUNET_CONTAINER_DLL_remove (rh->attrs_head, rh->attrs_tail, ae);
361     GNUNET_free (ae);
362   }
363   while (NULL != (le = rh->tickets_to_update_head)) {
364     GNUNET_CONTAINER_DLL_remove (rh->tickets_to_update_head,
365                                  rh->tickets_to_update_head, le);
366     if (NULL != le->data)
367       GNUNET_free (le->data);
368     if (NULL != le->label)
369       GNUNET_free (le->label);
370     GNUNET_free (le);
371   }
372   GNUNET_free (rh);
373 }
374
375 static void
376 del_attr_finished (void *cls, int32_t success, const char *emsg)
377 {
378   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
379   rvk->ns_qe = NULL;
380   if (GNUNET_SYSERR == success) {
381     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error removing attribute: %s\n",
382                 emsg);
383     rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
384     cleanup_rvk (rvk);
385     return;
386   }
387   rvk->move_attr = rvk->move_attr->next;
388   GNUNET_SCHEDULER_add_now (&move_attrs_cont, rvk);
389 }
390
391 static void
392 move_attr_finished (void *cls, int32_t success, const char *emsg)
393 {
394   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
395   char *label;
396   rvk->ns_qe = NULL;
397   if (GNUNET_SYSERR == success) {
398     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error moving attribute: %s\n", emsg);
399     rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
400     cleanup_rvk (rvk);
401     return;
402   }
403   label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->old_id,
404                                                sizeof (uint64_t));
405   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Removing attribute %s\n", label);
406   rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh, &rvk->identity, label, 0,
407                                                NULL, &del_attr_finished, rvk);
408 }
409
410
411 static void
412 rvk_move_attr_cb (void *cls, const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
413                   const char *label, unsigned int rd_count,
414                   const struct GNUNET_GNSRECORD_Data *rd)
415 {
416   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
417   struct RevokedAttributeEntry *le;
418   char *new_label;
419   rvk->ns_qe = NULL;
420   if (0 == rd_count) {
421     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
422                 "The attribute %s no longer exists!\n", label);
423     le = rvk->move_attr;
424     rvk->move_attr = le->next;
425     GNUNET_CONTAINER_DLL_remove (rvk->attrs_head, rvk->attrs_tail, le);
426     GNUNET_free (le);
427     GNUNET_SCHEDULER_add_now (&move_attrs_cont, rvk);
428     return;
429   }
430   /** find a new place for this attribute **/
431   rvk->move_attr->new_id =
432       GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
433   new_label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->new_id,
434                                                    sizeof (uint64_t));
435   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute %s\n", new_label);
436   rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh, &rvk->identity, new_label,
437                                                1, rd, &move_attr_finished, rvk);
438   GNUNET_free (new_label);
439 }
440
441
442 static void
443 rvk_ticket_update (void *cls, const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
444                    const char *label, unsigned int rd_count,
445                    const struct GNUNET_GNSRECORD_Data *rd)
446 {
447   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
448   struct TicketRecordsEntry *le;
449   struct RevokedAttributeEntry *ae;
450   int has_changed = GNUNET_NO;
451
452   /** Let everything point to the old record **/
453   for (int i = 0; i < rd_count; i++) {
454     if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
455       continue;
456     for (ae = rvk->attrs_head; NULL != ae; ae = ae->next) {
457       if (0 != memcmp (rd[i].data, &ae->old_id, sizeof (uint64_t)))
458         continue;
459       has_changed = GNUNET_YES;
460       break;
461     }
462     if (GNUNET_YES == has_changed)
463       break;
464   }
465   if (GNUNET_YES == has_changed) {
466     le = GNUNET_new (struct TicketRecordsEntry);
467     le->data_size = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
468     le->data = GNUNET_malloc (le->data_size);
469     le->rd_count = rd_count;
470     le->label = GNUNET_strdup (label);
471     GNUNET_GNSRECORD_records_serialize (rd_count, rd, le->data_size, le->data);
472     GNUNET_CONTAINER_DLL_insert (rvk->tickets_to_update_head,
473                                  rvk->tickets_to_update_tail, le);
474   }
475   GNUNET_NAMESTORE_zone_iterator_next (rvk->ns_it, 1);
476 }
477
478
479 static void
480 process_tickets (void *cls);
481
482
483 static void
484 ticket_processed (void *cls, int32_t success, const char *emsg)
485 {
486   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
487   rvk->ns_qe = NULL;
488   GNUNET_SCHEDULER_add_now (&process_tickets, rvk);
489 }
490
491 static void
492 process_tickets (void *cls)
493 {
494   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
495   struct TicketRecordsEntry *le;
496   struct RevokedAttributeEntry *ae;
497   if (NULL == rvk->tickets_to_update_head) {
498     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
499                 "Finished updatding tickets, success\n");
500     rvk->cb (rvk->cb_cls, GNUNET_OK);
501     cleanup_rvk (rvk);
502     return;
503   }
504   le = rvk->tickets_to_update_head;
505   GNUNET_CONTAINER_DLL_remove (rvk->tickets_to_update_head,
506                                rvk->tickets_to_update_tail, le);
507   struct GNUNET_GNSRECORD_Data rd[le->rd_count];
508   GNUNET_GNSRECORD_records_deserialize (le->data_size, le->data, le->rd_count,
509                                         rd);
510   for (int i = 0; i < le->rd_count; i++) {
511     if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
512       continue;
513     for (ae = rvk->attrs_head; NULL != ae; ae = ae->next) {
514       if (0 != memcmp (rd[i].data, &ae->old_id, sizeof (uint64_t)))
515         continue;
516       rd[i].data = &ae->new_id;
517     }
518   }
519   rvk->ns_qe = GNUNET_NAMESTORE_records_store (
520       nsh, &rvk->identity, le->label, le->rd_count, rd, &ticket_processed, rvk);
521   GNUNET_free (le->label);
522   GNUNET_free (le->data);
523   GNUNET_free (le);
524 }
525
526 static void
527 rvk_ticket_update_finished (void *cls)
528 {
529   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
530   rvk->ns_it = NULL;
531   GNUNET_SCHEDULER_add_now (&process_tickets, rvk);
532 }
533
534
535 static void
536 rvk_ns_iter_err (void *cls)
537 {
538   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
539   rvk->ns_it = NULL;
540   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
541               "Namestore error on revocation (id=%" PRIu64 "\n",
542               rvk->move_attr->old_id);
543   rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
544   cleanup_rvk (rvk);
545 }
546
547
548 static void
549 rvk_ns_err (void *cls)
550 {
551   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
552   rvk->ns_qe = NULL;
553   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
554               "Namestore error on revocation (id=%" PRIu64 "\n",
555               rvk->move_attr->old_id);
556   rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
557   cleanup_rvk (rvk);
558 }
559
560
561 static void
562 move_attrs (struct RECLAIM_TICKETS_RevokeHandle *rvk)
563 {
564   char *label;
565
566   if (NULL == rvk->move_attr) {
567     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished moving attributes\n");
568     rvk->ns_it = GNUNET_NAMESTORE_zone_iteration_start (
569         nsh, &rvk->identity, &rvk_ns_iter_err, rvk, &rvk_ticket_update, rvk,
570         &rvk_ticket_update_finished, rvk);
571     return;
572   }
573   label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->old_id,
574                                                sizeof (uint64_t));
575   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Moving attribute %s\n", label);
576
577   rvk->ns_qe = GNUNET_NAMESTORE_records_lookup (
578       nsh, &rvk->identity, label, &rvk_ns_err, rvk, &rvk_move_attr_cb, rvk);
579   GNUNET_free (label);
580 }
581
582
583 static void
584 remove_ticket_cont (void *cls, int32_t success, const char *emsg)
585 {
586   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
587   rvk->ns_qe = NULL;
588   if (GNUNET_SYSERR == success) {
589     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
590     rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
591     cleanup_rvk (rvk);
592     return;
593   }
594   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleted ticket\n");
595   if (0 == rvk->ticket_attrs) {
596     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
597                 "No attributes to move... strange\n");
598     rvk->cb (rvk->cb_cls, GNUNET_OK);
599     cleanup_rvk (rvk);
600     return;
601   }
602   rvk->move_attr = rvk->attrs_head;
603   move_attrs (rvk);
604 }
605
606
607 static void
608 revoke_attrs_cb (void *cls, const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
609                  const char *label, unsigned int rd_count,
610                  const struct GNUNET_GNSRECORD_Data *rd)
611
612 {
613   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
614   struct RevokedAttributeEntry *le;
615   rvk->ns_qe = NULL;
616   for (int i = 0; i < rd_count; i++) {
617     if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
618       continue;
619     le = GNUNET_new (struct RevokedAttributeEntry);
620     le->old_id = *((uint64_t *)rd[i].data);
621     GNUNET_CONTAINER_DLL_insert (rvk->attrs_head, rvk->attrs_tail, le);
622     rvk->ticket_attrs++;
623   }
624
625   /** Now, remove ticket **/
626   rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh, &rvk->identity, label, 0,
627                                                NULL, &remove_ticket_cont, rvk);
628 }
629
630
631 static void
632 rvk_attrs_err_cb (void *cls)
633 {
634   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
635   rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
636   cleanup_rvk (rvk);
637 }
638
639
640 struct RECLAIM_TICKETS_RevokeHandle *
641 RECLAIM_TICKETS_revoke (const struct GNUNET_RECLAIM_Ticket *ticket,
642                         const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
643                         RECLAIM_TICKETS_RevokeCallback cb, void *cb_cls)
644 {
645   struct RECLAIM_TICKETS_RevokeHandle *rvk;
646   char *label;
647
648   rvk = GNUNET_new (struct RECLAIM_TICKETS_RevokeHandle);
649   rvk->cb = cb;
650   rvk->cb_cls = cb_cls;
651   rvk->identity = *identity;
652   rvk->ticket = *ticket;
653   GNUNET_CRYPTO_ecdsa_key_get_public (&rvk->identity, &rvk->ticket.identity);
654   /** Get shared attributes **/
655   label = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof (uint64_t));
656
657   rvk->ns_qe = GNUNET_NAMESTORE_records_lookup (
658       nsh, identity, label, &rvk_attrs_err_cb, rvk, &revoke_attrs_cb, rvk);
659   return rvk;
660 }
661
662
663 void
664 RECLAIM_TICKETS_revoke_cancel (struct RECLAIM_TICKETS_RevokeHandle *rh)
665 {
666   cleanup_rvk (rh);
667 }
668 /*******************************
669  * Ticket consume
670  *******************************/
671
672 /**
673  * Cleanup ticket consume handle
674  * @param cth the handle to clean up
675  */
676 static void
677 cleanup_cth (struct RECLAIM_TICKETS_ConsumeHandle *cth)
678 {
679   struct ParallelLookup *lu;
680   struct ParallelLookup *tmp;
681   if (NULL != cth->lookup_request)
682     GNUNET_GNS_lookup_cancel (cth->lookup_request);
683   for (lu = cth->parallel_lookups_head; NULL != lu;) {
684     GNUNET_GNS_lookup_cancel (lu->lookup_request);
685     GNUNET_free (lu->label);
686     tmp = lu->next;
687     GNUNET_CONTAINER_DLL_remove (cth->parallel_lookups_head,
688                                  cth->parallel_lookups_tail, lu);
689     GNUNET_free (lu);
690     lu = tmp;
691   }
692
693   if (NULL != cth->attrs)
694     GNUNET_RECLAIM_ATTRIBUTE_list_destroy (cth->attrs);
695   GNUNET_free (cth);
696 }
697
698
699 static void
700 process_parallel_lookup_result (void *cls, uint32_t rd_count,
701                                 const struct GNUNET_GNSRECORD_Data *rd)
702 {
703   struct ParallelLookup *parallel_lookup = cls;
704   struct RECLAIM_TICKETS_ConsumeHandle *cth = parallel_lookup->handle;
705   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *attr_le;
706   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Parallel lookup finished (count=%u)\n",
707               rd_count);
708
709   GNUNET_CONTAINER_DLL_remove (cth->parallel_lookups_head,
710                                cth->parallel_lookups_tail, parallel_lookup);
711   GNUNET_free (parallel_lookup->label);
712
713   GNUNET_STATISTICS_update (
714       stats, "attribute_lookup_time_total",
715       GNUNET_TIME_absolute_get_duration (parallel_lookup->lookup_start_time)
716           .rel_value_us,
717       GNUNET_YES);
718   GNUNET_STATISTICS_update (stats, "attribute_lookups_count", 1, GNUNET_YES);
719
720
721   GNUNET_free (parallel_lookup);
722   if (1 != rd_count)
723     GNUNET_break (0); // TODO
724   if (rd->record_type == GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR) {
725     attr_le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry);
726     attr_le->claim =
727         GNUNET_RECLAIM_ATTRIBUTE_deserialize (rd->data, rd->data_size);
728     GNUNET_CONTAINER_DLL_insert (cth->attrs->list_head, cth->attrs->list_tail,
729                                  attr_le);
730   }
731   if (NULL != cth->parallel_lookups_head)
732     return; // Wait for more
733   /* Else we are done */
734
735   GNUNET_SCHEDULER_cancel (cth->kill_task);
736   cth->cb (cth->cb_cls, &cth->ticket.identity, cth->attrs, GNUNET_OK, NULL);
737   cleanup_cth (cth);
738 }
739
740
741 static void
742 abort_parallel_lookups (void *cls)
743 {
744   struct RECLAIM_TICKETS_ConsumeHandle *cth = cls;
745   struct ParallelLookup *lu;
746   struct ParallelLookup *tmp;
747
748   cth->kill_task = NULL;
749   for (lu = cth->parallel_lookups_head; NULL != lu;) {
750     GNUNET_GNS_lookup_cancel (lu->lookup_request);
751     GNUNET_free (lu->label);
752     tmp = lu->next;
753     GNUNET_CONTAINER_DLL_remove (cth->parallel_lookups_head,
754                                  cth->parallel_lookups_tail, lu);
755     GNUNET_free (lu);
756     lu = tmp;
757   }
758   cth->cb (cth->cb_cls, NULL, NULL, GNUNET_SYSERR, "Aborted");
759 }
760
761
762 static void
763 lookup_authz_cb (void *cls, uint32_t rd_count,
764                  const struct GNUNET_GNSRECORD_Data *rd)
765 {
766   struct RECLAIM_TICKETS_ConsumeHandle *cth = cls;
767   struct ParallelLookup *parallel_lookup;
768   char *lbl;
769
770   cth->lookup_request = NULL;
771
772   GNUNET_STATISTICS_update (
773       stats, "reclaim_authz_lookup_time_total",
774       GNUNET_TIME_absolute_get_duration (cth->lookup_start_time).rel_value_us,
775       GNUNET_YES);
776   GNUNET_STATISTICS_update (stats, "reclaim_authz_lookups_count", 1,
777                             GNUNET_YES);
778
779   for (int i = 0; i < rd_count; i++) {
780     lbl = GNUNET_STRINGS_data_to_string_alloc (rd[i].data, rd[i].data_size);
781     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Attribute ref found %s\n", lbl);
782     parallel_lookup = GNUNET_new (struct ParallelLookup);
783     parallel_lookup->handle = cth;
784     parallel_lookup->label = lbl;
785     parallel_lookup->lookup_start_time = GNUNET_TIME_absolute_get ();
786     parallel_lookup->lookup_request = GNUNET_GNS_lookup (
787         gns, lbl, &cth->ticket.identity, GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR,
788         GNUNET_GNS_LO_DEFAULT, &process_parallel_lookup_result,
789         parallel_lookup);
790     GNUNET_CONTAINER_DLL_insert (cth->parallel_lookups_head,
791                                  cth->parallel_lookups_tail, parallel_lookup);
792   }
793   cth->kill_task = GNUNET_SCHEDULER_add_delayed (
794       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 3),
795       &abort_parallel_lookups, cth);
796 }
797
798
799 struct RECLAIM_TICKETS_ConsumeHandle *
800 RECLAIM_TICKETS_consume (const struct GNUNET_CRYPTO_EcdsaPrivateKey *id,
801                          const struct GNUNET_RECLAIM_Ticket *ticket,
802                          RECLAIM_TICKETS_ConsumeCallback cb, void *cb_cls)
803 {
804   struct RECLAIM_TICKETS_ConsumeHandle *cth;
805   char *label;
806   cth = GNUNET_new (struct RECLAIM_TICKETS_ConsumeHandle);
807
808   cth->identity = *id;
809   GNUNET_CRYPTO_ecdsa_key_get_public (&cth->identity, &cth->identity_pub);
810   cth->attrs = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList);
811   cth->ticket = *ticket;
812   cth->cb = cb;
813   cth->cb_cls = cb_cls;
814   label =
815       GNUNET_STRINGS_data_to_string_alloc (&cth->ticket.rnd, sizeof (uint64_t));
816   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking for AuthZ info under %s\n",
817               label);
818   cth->lookup_start_time = GNUNET_TIME_absolute_get ();
819   cth->lookup_request = GNUNET_GNS_lookup (
820       gns, label, &cth->ticket.identity, GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF,
821       GNUNET_GNS_LO_DEFAULT, &lookup_authz_cb, cth);
822   GNUNET_free (label);
823   return cth;
824 }
825
826 void
827 RECLAIM_TICKETS_consume_cancel (struct RECLAIM_TICKETS_ConsumeHandle *cth)
828 {
829   cleanup_cth (cth);
830   return;
831 }
832
833
834 /*******************************
835  * Ticket issue
836  *******************************/
837
838 /**
839  * Cleanup ticket consume handle
840  * @param handle the handle to clean up
841  */
842 static void
843 cleanup_issue_handle (struct TicketIssueHandle *handle)
844 {
845   if (NULL != handle->ns_qe)
846     GNUNET_NAMESTORE_cancel (handle->ns_qe);
847   GNUNET_free (handle);
848 }
849
850
851 static void
852 store_ticket_issue_cont (void *cls, int32_t success, const char *emsg)
853 {
854   struct TicketIssueHandle *handle = cls;
855
856   handle->ns_qe = NULL;
857   if (GNUNET_SYSERR == success) {
858     handle->cb (handle->cb_cls, &handle->ticket, GNUNET_SYSERR,
859                 "Error storing AuthZ ticket in GNS");
860     return;
861   }
862   handle->cb (handle->cb_cls, &handle->ticket, GNUNET_OK, NULL);
863   cleanup_issue_handle (handle);
864 }
865
866
867 static void
868 issue_ticket (struct TicketIssueHandle *ih)
869 {
870   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
871   struct GNUNET_GNSRECORD_Data *attrs_record;
872   char *label;
873   size_t list_len = 1;
874   int i;
875
876   for (le = ih->attrs->list_head; NULL != le; le = le->next)
877     list_len++;
878
879   attrs_record =
880       GNUNET_malloc (list_len * sizeof (struct GNUNET_GNSRECORD_Data));
881   i = 0;
882   for (le = ih->attrs->list_head; NULL != le; le = le->next) {
883     attrs_record[i].data = &le->claim->id;
884     attrs_record[i].data_size = sizeof (le->claim->id);
885     attrs_record[i].expiration_time = GNUNET_TIME_UNIT_DAYS.rel_value_us;
886     attrs_record[i].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF;
887     attrs_record[i].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
888     i++;
889   }
890   attrs_record[i].data = &ih->ticket;
891   attrs_record[i].data_size = sizeof (struct GNUNET_RECLAIM_Ticket);
892   attrs_record[i].expiration_time = GNUNET_TIME_UNIT_DAYS.rel_value_us;
893   attrs_record[i].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET;
894   attrs_record[i].flags =
895       GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION | GNUNET_GNSRECORD_RF_PRIVATE;
896
897   label =
898       GNUNET_STRINGS_data_to_string_alloc (&ih->ticket.rnd, sizeof (uint64_t));
899   // Publish record
900   ih->ns_qe = GNUNET_NAMESTORE_records_store (nsh, &ih->identity, label,
901                                               list_len, attrs_record,
902                                               &store_ticket_issue_cont, ih);
903   GNUNET_free (attrs_record);
904   GNUNET_free (label);
905 }
906
907
908 void
909 RECLAIM_TICKETS_issue (const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
910                        const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
911                        const struct GNUNET_CRYPTO_EcdsaPublicKey *audience,
912                        RECLAIM_TICKETS_TicketResult cb, void *cb_cls)
913 {
914   struct TicketIssueHandle *tih;
915   tih = GNUNET_new (struct TicketIssueHandle);
916   tih->cb = cb;
917   tih->cb_cls = cb_cls;
918   tih->attrs = GNUNET_RECLAIM_ATTRIBUTE_list_dup (attrs);
919   tih->identity = *identity;
920   GNUNET_CRYPTO_ecdsa_key_get_public (identity, &tih->ticket.identity);
921   tih->ticket.rnd =
922       GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
923   tih->ticket.audience = *audience;
924   issue_ticket (tih);
925 }
926
927 /************************************
928  * Ticket iteration
929  ************************************/
930
931 static void
932 cleanup_iter (struct RECLAIM_TICKETS_Iterator *iter)
933 {
934   if (NULL != iter->ns_it)
935     GNUNET_NAMESTORE_zone_iteration_stop (iter->ns_it);
936   GNUNET_free (iter);
937 }
938
939
940 static void
941 collect_tickets_cb (void *cls, const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
942                     const char *label, unsigned int rd_count,
943                     const struct GNUNET_GNSRECORD_Data *rd)
944 {
945   struct RECLAIM_TICKETS_Iterator *iter = cls;
946
947   for (int i = 0; i < rd_count; i++) {
948     if (GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET != rd[i].record_type)
949       continue;
950     iter->cb (iter->cb_cls, (struct GNUNET_RECLAIM_Ticket *)rd[i].data);
951     return;
952   }
953   GNUNET_NAMESTORE_zone_iterator_next (iter->ns_it, 1);
954 }
955
956
957 static void
958 collect_tickets_finished_cb (void *cls)
959 {
960   struct RECLAIM_TICKETS_Iterator *iter = cls;
961   iter->ns_it = NULL;
962   iter->cb (iter->cb_cls, NULL);
963   cleanup_iter (iter);
964 }
965
966
967 static void
968 collect_tickets_error_cb (void *cls)
969 {
970   struct RECLAIM_TICKETS_Iterator *iter = cls;
971   iter->ns_it = NULL;
972   iter->cb (iter->cb_cls, NULL);
973   cleanup_iter (iter);
974 }
975
976
977 void
978 RECLAIM_TICKETS_iteration_next (struct RECLAIM_TICKETS_Iterator *iter)
979 {
980   GNUNET_NAMESTORE_zone_iterator_next (iter->ns_it, 1);
981 }
982
983
984 void
985 RECLAIM_TICKETS_iteration_stop (struct RECLAIM_TICKETS_Iterator *iter)
986 {
987   GNUNET_NAMESTORE_zone_iteration_stop (iter->ns_it);
988   cleanup_iter (iter);
989 }
990
991
992 struct RECLAIM_TICKETS_Iterator *
993 RECLAIM_TICKETS_iteration_start (
994     const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
995     RECLAIM_TICKETS_TicketIter cb, void *cb_cls)
996 {
997   struct RECLAIM_TICKETS_Iterator *iter;
998
999   iter = GNUNET_new (struct RECLAIM_TICKETS_Iterator);
1000   iter->cb = cb;
1001   iter->cb_cls = cb_cls;
1002   iter->ns_it = GNUNET_NAMESTORE_zone_iteration_start (
1003       nsh, identity, &collect_tickets_error_cb, iter, &collect_tickets_cb, iter,
1004       &collect_tickets_finished_cb, iter);
1005   return iter;
1006 }
1007
1008
1009 int
1010 RECLAIM_TICKETS_init (const struct GNUNET_CONFIGURATION_Handle *c)
1011 {
1012   // Connect to identity and namestore services
1013   nsh = GNUNET_NAMESTORE_connect (c);
1014   if (NULL == nsh) {
1015     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1016                          "error connecting to namestore");
1017     return GNUNET_SYSERR;
1018   }
1019   gns = GNUNET_GNS_connect (c);
1020   if (NULL == gns) {
1021     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to gns");
1022     return GNUNET_SYSERR;
1023   }
1024   stats = GNUNET_STATISTICS_create ("reclaim", c);
1025   return GNUNET_OK;
1026 }
1027
1028 void
1029 RECLAIM_TICKETS_deinit (void)
1030 {
1031   if (NULL != nsh)
1032     GNUNET_NAMESTORE_disconnect (nsh);
1033   nsh = NULL;
1034   if (NULL != gns)
1035     GNUNET_GNS_disconnect (gns);
1036   gns = NULL;
1037   if (NULL != stats) {
1038     GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
1039     stats = NULL;
1040   }
1041 }