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