RECLAIM: Various fixes (coverity)
[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   {
334     GNUNET_CONTAINER_DLL_remove (rh->attrs_head, rh->attrs_tail, ae);
335     GNUNET_free (ae);
336   }
337   while (NULL != (le = rh->tickets_to_update_head))
338   {
339     GNUNET_CONTAINER_DLL_remove (rh->tickets_to_update_head,
340                                  rh->tickets_to_update_head,
341                                  le);
342     if (NULL != le->data)
343       GNUNET_free (le->data);
344     if (NULL != le->label)
345       GNUNET_free (le->label);
346     GNUNET_free (le);
347   }
348   GNUNET_free (rh);
349 }
350
351 static void
352 del_attr_finished (void *cls, int32_t success, const char *emsg)
353 {
354   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
355   rvk->ns_qe = NULL;
356   if (GNUNET_SYSERR == success)
357   {
358     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
359                 "Error removing attribute: %s\n",
360                 emsg);
361     rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
362     cleanup_rvk (rvk);
363     return;
364   }
365   rvk->move_attr = rvk->move_attr->next;
366   GNUNET_SCHEDULER_add_now (&move_attrs_cont, rvk);
367 }
368
369 static void
370 move_attr_finished (void *cls, int32_t success, const char *emsg)
371 {
372   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
373   char *label;
374   rvk->ns_qe = NULL;
375   if (GNUNET_SYSERR == success)
376   {
377     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error moving attribute: %s\n", emsg);
378     rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
379     cleanup_rvk (rvk);
380     return;
381   }
382   label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->old_id,
383                                                sizeof (uint64_t));
384   GNUNET_assert (NULL != label);
385   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Removing attribute %s\n", label);
386   rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
387                                                &rvk->identity,
388                                                label,
389                                                0,
390                                                NULL,
391                                                &del_attr_finished,
392                                                rvk);
393   GNUNET_free (label);
394 }
395
396
397 static void
398 rvk_move_attr_cb (void *cls,
399                   const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
400                   const char *label,
401                   unsigned int rd_count,
402                   const struct GNUNET_GNSRECORD_Data *rd)
403 {
404   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
405   struct GNUNET_RECLAIM_ATTRIBUTE_Claim *claim;
406   struct GNUNET_GNSRECORD_Data new_rd;
407   struct RevokedAttributeEntry *le;
408   char *new_label;
409   char *attr_data;
410   rvk->ns_qe = NULL;
411   if (0 == rd_count)
412   {
413     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
414                 "The attribute %s no longer exists!\n",
415                 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_rd = *rd;
427   claim = GNUNET_RECLAIM_ATTRIBUTE_deserialize (rd->data, rd->data_size);
428   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
429               "Attribute to update: Name=%s, ID=%" PRIu64 "\n",
430               claim->name,
431               claim->id);
432   claim->id = rvk->move_attr->new_id;
433   new_rd.data_size = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (claim);
434   attr_data = GNUNET_malloc (rd->data_size);
435   new_rd.data_size = GNUNET_RECLAIM_ATTRIBUTE_serialize (claim, attr_data);
436   new_rd.data = attr_data;
437   new_label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->new_id,
438                                                    sizeof (uint64_t));
439   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute %s\n", new_label);
440   rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
441                                                &rvk->identity,
442                                                new_label,
443                                                1,
444                                                &new_rd,
445                                                &move_attr_finished,
446                                                rvk);
447   GNUNET_free (new_label);
448   GNUNET_free (claim);
449   GNUNET_free (attr_data);
450 }
451
452
453 static void
454 rvk_ticket_update (void *cls,
455                    const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
456                    const char *label,
457                    unsigned int rd_count,
458                    const struct GNUNET_GNSRECORD_Data *rd)
459 {
460   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
461   struct TicketRecordsEntry *le;
462   struct RevokedAttributeEntry *ae;
463   int has_changed = GNUNET_NO;
464
465   /** Let everything point to the old record **/
466   for (int i = 0; i < rd_count; i++)
467   {
468     if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
469       continue;
470     for (ae = rvk->attrs_head; NULL != ae; ae = ae->next)
471     {
472       if (0 != memcmp (rd[i].data, &ae->old_id, sizeof (uint64_t)))
473         continue;
474       has_changed = GNUNET_YES;
475       break;
476     }
477     if (GNUNET_YES == has_changed)
478       break;
479   }
480   if (GNUNET_YES == has_changed)
481   {
482     le = GNUNET_new (struct TicketRecordsEntry);
483     le->data_size = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
484     le->data = GNUNET_malloc (le->data_size);
485     le->rd_count = rd_count;
486     le->label = GNUNET_strdup (label);
487     GNUNET_GNSRECORD_records_serialize (rd_count, rd, le->data_size, le->data);
488     GNUNET_CONTAINER_DLL_insert (rvk->tickets_to_update_head,
489                                  rvk->tickets_to_update_tail,
490                                  le);
491   }
492   GNUNET_NAMESTORE_zone_iterator_next (rvk->ns_it, 1);
493 }
494
495
496 static void
497 process_tickets (void *cls);
498
499
500 static void
501 ticket_processed (void *cls, int32_t success, const char *emsg)
502 {
503   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
504   rvk->ns_qe = NULL;
505   GNUNET_SCHEDULER_add_now (&process_tickets, rvk);
506 }
507
508 static void
509 process_tickets (void *cls)
510 {
511   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
512   struct TicketRecordsEntry *le;
513   struct RevokedAttributeEntry *ae;
514   if (NULL == rvk->tickets_to_update_head)
515   {
516     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
517                 "Finished updatding tickets, success\n");
518     rvk->cb (rvk->cb_cls, GNUNET_OK);
519     cleanup_rvk (rvk);
520     return;
521   }
522   le = rvk->tickets_to_update_head;
523   GNUNET_CONTAINER_DLL_remove (rvk->tickets_to_update_head,
524                                rvk->tickets_to_update_tail,
525                                le);
526   struct GNUNET_GNSRECORD_Data rd[le->rd_count];
527   if (GNUNET_OK != GNUNET_GNSRECORD_records_deserialize (le->data_size,
528                                                          le->data,
529                                                          le->rd_count,
530                                                          rd))
531   {
532     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
533                 "Unable to deserialize ticket record(s)\n");
534     rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
535     cleanup_rvk (rvk);
536     return;
537   }
538   for (int i = 0; i < le->rd_count; i++)
539   {
540     if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
541       continue;
542     for (ae = rvk->attrs_head; NULL != ae; ae = ae->next)
543     {
544       if (0 != memcmp (rd[i].data, &ae->old_id, sizeof (uint64_t)))
545         continue;
546       rd[i].data = &ae->new_id;
547     }
548   }
549   rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
550                                                &rvk->identity,
551                                                le->label,
552                                                le->rd_count,
553                                                rd,
554                                                &ticket_processed,
555                                                rvk);
556   GNUNET_free (le->label);
557   GNUNET_free (le->data);
558   GNUNET_free (le);
559 }
560
561 static void
562 rvk_ticket_update_finished (void *cls)
563 {
564   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
565   rvk->ns_it = NULL;
566   GNUNET_SCHEDULER_add_now (&process_tickets, rvk);
567 }
568
569
570 static void
571 rvk_ns_iter_err (void *cls)
572 {
573   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
574   rvk->ns_it = NULL;
575   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
576               "Namestore error on revocation (id=%" PRIu64 "\n",
577               rvk->move_attr->old_id);
578   rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
579   cleanup_rvk (rvk);
580 }
581
582
583 static void
584 rvk_ns_err (void *cls)
585 {
586   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
587   rvk->ns_qe = NULL;
588   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
589               "Namestore error on revocation (id=%" PRIu64 "\n",
590               rvk->move_attr->old_id);
591   rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
592   cleanup_rvk (rvk);
593 }
594
595
596 static void
597 move_attrs (struct RECLAIM_TICKETS_RevokeHandle *rvk)
598 {
599   char *label;
600
601   if (NULL == rvk->move_attr)
602   {
603     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished moving attributes\n");
604     rvk->ns_it =
605       GNUNET_NAMESTORE_zone_iteration_start (nsh,
606                                              &rvk->identity,
607                                              &rvk_ns_iter_err,
608                                              rvk,
609                                              &rvk_ticket_update,
610                                              rvk,
611                                              &rvk_ticket_update_finished,
612                                              rvk);
613     return;
614   }
615   label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->old_id,
616                                                sizeof (uint64_t));
617   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Moving attribute %s\n", label);
618
619   rvk->ns_qe = GNUNET_NAMESTORE_records_lookup (nsh,
620                                                 &rvk->identity,
621                                                 label,
622                                                 &rvk_ns_err,
623                                                 rvk,
624                                                 &rvk_move_attr_cb,
625                                                 rvk);
626   GNUNET_free (label);
627 }
628
629
630 static void
631 remove_ticket_cont (void *cls, int32_t success, const char *emsg)
632 {
633   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
634   rvk->ns_qe = NULL;
635   if (GNUNET_SYSERR == success)
636   {
637     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
638     rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
639     cleanup_rvk (rvk);
640     return;
641   }
642   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleted ticket\n");
643   if (0 == rvk->ticket_attrs)
644   {
645     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
646                 "No attributes to move... strange\n");
647     rvk->cb (rvk->cb_cls, GNUNET_OK);
648     cleanup_rvk (rvk);
649     return;
650   }
651   rvk->move_attr = rvk->attrs_head;
652   move_attrs (rvk);
653 }
654
655
656 static void
657 revoke_attrs_cb (void *cls,
658                  const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
659                  const char *label,
660                  unsigned int rd_count,
661                  const struct GNUNET_GNSRECORD_Data *rd)
662
663 {
664   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
665   struct RevokedAttributeEntry *le;
666   rvk->ns_qe = NULL;
667   for (int i = 0; i < rd_count; i++)
668   {
669     if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
670       continue;
671     le = GNUNET_new (struct RevokedAttributeEntry);
672     le->old_id = *((uint64_t *) rd[i].data);
673     GNUNET_CONTAINER_DLL_insert (rvk->attrs_head, rvk->attrs_tail, le);
674     rvk->ticket_attrs++;
675   }
676
677   /** Now, remove ticket **/
678   rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
679                                                &rvk->identity,
680                                                label,
681                                                0,
682                                                NULL,
683                                                &remove_ticket_cont,
684                                                rvk);
685 }
686
687
688 static void
689 rvk_attrs_err_cb (void *cls)
690 {
691   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
692   rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
693   cleanup_rvk (rvk);
694 }
695
696
697 struct RECLAIM_TICKETS_RevokeHandle *
698 RECLAIM_TICKETS_revoke (const struct GNUNET_RECLAIM_Ticket *ticket,
699                         const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
700                         RECLAIM_TICKETS_RevokeCallback cb,
701                         void *cb_cls)
702 {
703   struct RECLAIM_TICKETS_RevokeHandle *rvk;
704   char *label;
705
706   rvk = GNUNET_new (struct RECLAIM_TICKETS_RevokeHandle);
707   rvk->cb = cb;
708   rvk->cb_cls = cb_cls;
709   rvk->identity = *identity;
710   rvk->ticket = *ticket;
711   GNUNET_CRYPTO_ecdsa_key_get_public (&rvk->identity, &rvk->ticket.identity);
712   /** Get shared attributes **/
713   label = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof (uint64_t));
714   GNUNET_assert (NULL != label);
715   rvk->ns_qe = GNUNET_NAMESTORE_records_lookup (nsh,
716                                                 identity,
717                                                 label,
718                                                 &rvk_attrs_err_cb,
719                                                 rvk,
720                                                 &revoke_attrs_cb,
721                                                 rvk);
722   return rvk;
723 }
724
725
726 void
727 RECLAIM_TICKETS_revoke_cancel (struct RECLAIM_TICKETS_RevokeHandle *rh)
728 {
729   cleanup_rvk (rh);
730 }
731 /*******************************
732  * Ticket consume
733  *******************************/
734
735 /**
736  * Cleanup ticket consume handle
737  * @param cth the handle to clean up
738  */
739 static void
740 cleanup_cth (struct RECLAIM_TICKETS_ConsumeHandle *cth)
741 {
742   struct ParallelLookup *lu;
743   if (NULL != cth->lookup_request)
744     GNUNET_GNS_lookup_cancel (cth->lookup_request);
745   if (NULL != cth->kill_task)
746     GNUNET_SCHEDULER_cancel (cth->kill_task);
747   while (NULL != (lu = cth->parallel_lookups_head))
748   {
749     if (NULL != lu->lookup_request)
750       GNUNET_GNS_lookup_cancel (lu->lookup_request);
751     GNUNET_free_non_null (lu->label);
752     GNUNET_CONTAINER_DLL_remove (cth->parallel_lookups_head,
753                                  cth->parallel_lookups_tail,
754                                  lu);
755     GNUNET_free (lu);
756   }
757
758   if (NULL != cth->attrs)
759     GNUNET_RECLAIM_ATTRIBUTE_list_destroy (cth->attrs);
760   GNUNET_free (cth);
761 }
762
763
764 static void
765 process_parallel_lookup_result (void *cls,
766                                 uint32_t rd_count,
767                                 const struct GNUNET_GNSRECORD_Data *rd)
768 {
769   struct ParallelLookup *parallel_lookup = cls;
770   struct RECLAIM_TICKETS_ConsumeHandle *cth = parallel_lookup->handle;
771   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *attr_le;
772   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
773               "Parallel lookup finished (count=%u)\n",
774               rd_count);
775
776   GNUNET_CONTAINER_DLL_remove (cth->parallel_lookups_head,
777                                cth->parallel_lookups_tail,
778                                parallel_lookup);
779   GNUNET_free (parallel_lookup->label);
780
781   GNUNET_STATISTICS_update (stats,
782                             "attribute_lookup_time_total",
783                             GNUNET_TIME_absolute_get_duration (
784                               parallel_lookup->lookup_start_time)
785                               .rel_value_us,
786                             GNUNET_YES);
787   GNUNET_STATISTICS_update (stats, "attribute_lookups_count", 1, GNUNET_YES);
788
789
790   GNUNET_free (parallel_lookup);
791   if (1 != rd_count)
792     GNUNET_break (0); // TODO
793   if (rd->record_type == GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR)
794   {
795     attr_le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry);
796     attr_le->claim =
797       GNUNET_RECLAIM_ATTRIBUTE_deserialize (rd->data, rd->data_size);
798     GNUNET_CONTAINER_DLL_insert (cth->attrs->list_head,
799                                  cth->attrs->list_tail,
800                                  attr_le);
801   }
802   if (NULL != cth->parallel_lookups_head)
803     return; // Wait for more
804   /* Else we are done */
805
806   cth->cb (cth->cb_cls, &cth->ticket.identity, cth->attrs, GNUNET_OK, NULL);
807   cleanup_cth (cth);
808 }
809
810
811 static void
812 abort_parallel_lookups (void *cls)
813 {
814   struct RECLAIM_TICKETS_ConsumeHandle *cth = cls;
815   struct ParallelLookup *lu;
816   struct ParallelLookup *tmp;
817
818   cth->kill_task = NULL;
819   for (lu = cth->parallel_lookups_head; NULL != lu;)
820   {
821     GNUNET_GNS_lookup_cancel (lu->lookup_request);
822     GNUNET_free (lu->label);
823     tmp = lu->next;
824     GNUNET_CONTAINER_DLL_remove (cth->parallel_lookups_head,
825                                  cth->parallel_lookups_tail,
826                                  lu);
827     GNUNET_free (lu);
828     lu = tmp;
829   }
830   cth->cb (cth->cb_cls, NULL, NULL, GNUNET_SYSERR, "Aborted");
831 }
832
833
834 static void
835 lookup_authz_cb (void *cls,
836                  uint32_t rd_count,
837                  const struct GNUNET_GNSRECORD_Data *rd)
838 {
839   struct RECLAIM_TICKETS_ConsumeHandle *cth = cls;
840   struct ParallelLookup *parallel_lookup;
841   char *lbl;
842
843   cth->lookup_request = NULL;
844
845   GNUNET_STATISTICS_update (stats,
846                             "reclaim_authz_lookup_time_total",
847                             GNUNET_TIME_absolute_get_duration (
848                               cth->lookup_start_time)
849                               .rel_value_us,
850                             GNUNET_YES);
851   GNUNET_STATISTICS_update (stats,
852                             "reclaim_authz_lookups_count",
853                             1,
854                             GNUNET_YES);
855
856   for (int i = 0; i < rd_count; i++)
857   {
858     if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
859       continue;
860     lbl = GNUNET_STRINGS_data_to_string_alloc (rd[i].data, rd[i].data_size);
861     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Attribute ref found %s\n", lbl);
862     parallel_lookup = GNUNET_new (struct ParallelLookup);
863     parallel_lookup->handle = cth;
864     parallel_lookup->label = lbl;
865     parallel_lookup->lookup_start_time = GNUNET_TIME_absolute_get ();
866     parallel_lookup->lookup_request =
867       GNUNET_GNS_lookup (gns,
868                          lbl,
869                          &cth->ticket.identity,
870                          GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR,
871                          GNUNET_GNS_LO_DEFAULT,
872                          &process_parallel_lookup_result,
873                          parallel_lookup);
874     GNUNET_CONTAINER_DLL_insert (cth->parallel_lookups_head,
875                                  cth->parallel_lookups_tail,
876                                  parallel_lookup);
877   }
878   if (NULL != cth->parallel_lookups_head)
879   {
880     cth->kill_task = GNUNET_SCHEDULER_add_delayed (
881       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 3),
882       &abort_parallel_lookups,
883       cth);
884     return;
885   }
886   cth->cb (cth->cb_cls, &cth->ticket.identity, cth->attrs, GNUNET_OK, NULL);
887   cleanup_cth (cth);
888 }
889
890
891 struct RECLAIM_TICKETS_ConsumeHandle *
892 RECLAIM_TICKETS_consume (const struct GNUNET_CRYPTO_EcdsaPrivateKey *id,
893                          const struct GNUNET_RECLAIM_Ticket *ticket,
894                          RECLAIM_TICKETS_ConsumeCallback cb,
895                          void *cb_cls)
896 {
897   struct RECLAIM_TICKETS_ConsumeHandle *cth;
898   char *label;
899   cth = GNUNET_new (struct RECLAIM_TICKETS_ConsumeHandle);
900
901   cth->identity = *id;
902   GNUNET_CRYPTO_ecdsa_key_get_public (&cth->identity, &cth->identity_pub);
903   cth->attrs = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList);
904   cth->ticket = *ticket;
905   cth->cb = cb;
906   cth->cb_cls = cb_cls;
907   label =
908     GNUNET_STRINGS_data_to_string_alloc (&cth->ticket.rnd, sizeof (uint64_t));
909   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
910               "Looking for AuthZ info under %s\n",
911               label);
912   cth->lookup_start_time = GNUNET_TIME_absolute_get ();
913   cth->lookup_request =
914     GNUNET_GNS_lookup (gns,
915                        label,
916                        &cth->ticket.identity,
917                        GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF,
918                        GNUNET_GNS_LO_DEFAULT,
919                        &lookup_authz_cb,
920                        cth);
921   GNUNET_free (label);
922   return cth;
923 }
924
925 void
926 RECLAIM_TICKETS_consume_cancel (struct RECLAIM_TICKETS_ConsumeHandle *cth)
927 {
928   cleanup_cth (cth);
929   return;
930 }
931
932
933 /*******************************
934  * Ticket issue
935  *******************************/
936
937 /**
938  * Cleanup ticket consume handle
939  * @param handle the handle to clean up
940  */
941 static void
942 cleanup_issue_handle (struct TicketIssueHandle *handle)
943 {
944   if (NULL != handle->ns_qe)
945     GNUNET_NAMESTORE_cancel (handle->ns_qe);
946   GNUNET_free (handle);
947 }
948
949
950 static void
951 store_ticket_issue_cont (void *cls, int32_t success, const char *emsg)
952 {
953   struct TicketIssueHandle *handle = cls;
954
955   handle->ns_qe = NULL;
956   if (GNUNET_SYSERR == success)
957   {
958     handle->cb (handle->cb_cls,
959                 &handle->ticket,
960                 GNUNET_SYSERR,
961                 "Error storing AuthZ ticket in GNS");
962     return;
963   }
964   handle->cb (handle->cb_cls, &handle->ticket, GNUNET_OK, NULL);
965   cleanup_issue_handle (handle);
966 }
967
968
969 static void
970 issue_ticket (struct TicketIssueHandle *ih)
971 {
972   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
973   struct GNUNET_GNSRECORD_Data *attrs_record;
974   char *label;
975   size_t list_len = 1;
976   int i;
977
978   for (le = ih->attrs->list_head; NULL != le; le = le->next)
979     list_len++;
980
981   attrs_record =
982     GNUNET_malloc (list_len * sizeof (struct GNUNET_GNSRECORD_Data));
983   i = 0;
984   for (le = ih->attrs->list_head; NULL != le; le = le->next)
985   {
986     attrs_record[i].data = &le->claim->id;
987     attrs_record[i].data_size = sizeof (le->claim->id);
988     //FIXME: Should this be the attribute expiration time or ticket refresh intv
989     attrs_record[i].expiration_time = ticket_refresh_interval.rel_value_us;
990     attrs_record[i].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF;
991     attrs_record[i].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
992     i++;
993   }
994   attrs_record[i].data = &ih->ticket;
995   attrs_record[i].data_size = sizeof (struct GNUNET_RECLAIM_Ticket);
996   attrs_record[i].expiration_time = ticket_refresh_interval.rel_value_us;
997   attrs_record[i].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET;
998   attrs_record[i].flags =
999     GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION | GNUNET_GNSRECORD_RF_PRIVATE;
1000
1001   label =
1002     GNUNET_STRINGS_data_to_string_alloc (&ih->ticket.rnd, sizeof (uint64_t));
1003   // Publish record
1004   ih->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
1005                                               &ih->identity,
1006                                               label,
1007                                               list_len,
1008                                               attrs_record,
1009                                               &store_ticket_issue_cont,
1010                                               ih);
1011   GNUNET_free (attrs_record);
1012   GNUNET_free (label);
1013 }
1014
1015
1016 void
1017 RECLAIM_TICKETS_issue (const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1018                        const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
1019                        const struct GNUNET_CRYPTO_EcdsaPublicKey *audience,
1020                        RECLAIM_TICKETS_TicketResult cb,
1021                        void *cb_cls)
1022 {
1023   struct TicketIssueHandle *tih;
1024   tih = GNUNET_new (struct TicketIssueHandle);
1025   tih->cb = cb;
1026   tih->cb_cls = cb_cls;
1027   tih->attrs = GNUNET_RECLAIM_ATTRIBUTE_list_dup (attrs);
1028   tih->identity = *identity;
1029   GNUNET_CRYPTO_ecdsa_key_get_public (identity, &tih->ticket.identity);
1030   tih->ticket.rnd =
1031     GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
1032   tih->ticket.audience = *audience;
1033   issue_ticket (tih);
1034 }
1035
1036 /************************************
1037  * Ticket iteration
1038  ************************************/
1039
1040 static void
1041 cleanup_iter (struct RECLAIM_TICKETS_Iterator *iter)
1042 {
1043   if (NULL != iter->ns_it)
1044     GNUNET_NAMESTORE_zone_iteration_stop (iter->ns_it);
1045   GNUNET_free (iter);
1046 }
1047
1048
1049 static void
1050 collect_tickets_cb (void *cls,
1051                     const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1052                     const char *label,
1053                     unsigned int rd_count,
1054                     const struct GNUNET_GNSRECORD_Data *rd)
1055 {
1056   struct RECLAIM_TICKETS_Iterator *iter = cls;
1057
1058   for (int i = 0; i < rd_count; i++)
1059   {
1060     if (GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET != rd[i].record_type)
1061       continue;
1062     iter->cb (iter->cb_cls, (struct GNUNET_RECLAIM_Ticket *) rd[i].data);
1063     return;
1064   }
1065   GNUNET_NAMESTORE_zone_iterator_next (iter->ns_it, 1);
1066 }
1067
1068
1069 static void
1070 collect_tickets_finished_cb (void *cls)
1071 {
1072   struct RECLAIM_TICKETS_Iterator *iter = cls;
1073   iter->ns_it = NULL;
1074   iter->cb (iter->cb_cls, NULL);
1075   cleanup_iter (iter);
1076 }
1077
1078
1079 static void
1080 collect_tickets_error_cb (void *cls)
1081 {
1082   struct RECLAIM_TICKETS_Iterator *iter = cls;
1083   iter->ns_it = NULL;
1084   iter->cb (iter->cb_cls, NULL);
1085   cleanup_iter (iter);
1086 }
1087
1088
1089 void
1090 RECLAIM_TICKETS_iteration_next (struct RECLAIM_TICKETS_Iterator *iter)
1091 {
1092   GNUNET_NAMESTORE_zone_iterator_next (iter->ns_it, 1);
1093 }
1094
1095
1096 void
1097 RECLAIM_TICKETS_iteration_stop (struct RECLAIM_TICKETS_Iterator *iter)
1098 {
1099   GNUNET_NAMESTORE_zone_iteration_stop (iter->ns_it);
1100   cleanup_iter (iter);
1101 }
1102
1103
1104 struct RECLAIM_TICKETS_Iterator *
1105 RECLAIM_TICKETS_iteration_start (
1106   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1107   RECLAIM_TICKETS_TicketIter cb,
1108   void *cb_cls)
1109 {
1110   struct RECLAIM_TICKETS_Iterator *iter;
1111
1112   iter = GNUNET_new (struct RECLAIM_TICKETS_Iterator);
1113   iter->cb = cb;
1114   iter->cb_cls = cb_cls;
1115   iter->ns_it =
1116     GNUNET_NAMESTORE_zone_iteration_start (nsh,
1117                                            identity,
1118                                            &collect_tickets_error_cb,
1119                                            iter,
1120                                            &collect_tickets_cb,
1121                                            iter,
1122                                            &collect_tickets_finished_cb,
1123                                            iter);
1124   return iter;
1125 }
1126
1127
1128 int
1129 RECLAIM_TICKETS_init (const struct GNUNET_CONFIGURATION_Handle *c)
1130 {
1131   // Get ticket expiration time (relative) from config
1132   if (GNUNET_OK ==
1133       GNUNET_CONFIGURATION_get_value_time (c,
1134                                            "reclaim",
1135                                            "TICKET_REFRESH_INTERVAL",
1136                                            &ticket_refresh_interval))
1137   {
1138     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1139                 "Configured refresh interval for tickets: %s\n",
1140                 GNUNET_STRINGS_relative_time_to_string (ticket_refresh_interval,
1141                                                         GNUNET_YES));
1142   }
1143   else
1144   {
1145     ticket_refresh_interval = DEFAULT_TICKET_REFRESH_INTERVAL;
1146   }
1147   // Connect to identity and namestore services
1148   nsh = GNUNET_NAMESTORE_connect (c);
1149   if (NULL == nsh)
1150   {
1151     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1152                          "error connecting to namestore");
1153     return GNUNET_SYSERR;
1154   }
1155   gns = GNUNET_GNS_connect (c);
1156   if (NULL == gns)
1157   {
1158     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to gns");
1159     return GNUNET_SYSERR;
1160   }
1161   stats = GNUNET_STATISTICS_create ("reclaim", c);
1162   return GNUNET_OK;
1163 }
1164
1165 void
1166 RECLAIM_TICKETS_deinit (void)
1167 {
1168   if (NULL != nsh)
1169     GNUNET_NAMESTORE_disconnect (nsh);
1170   nsh = NULL;
1171   if (NULL != gns)
1172     GNUNET_GNS_disconnect (gns);
1173   gns = NULL;
1174   if (NULL != stats)
1175   {
1176     GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
1177     stats = NULL;
1178   }
1179 }