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