changelog housekeeping
[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    * Namestore Iterator
174    */
175   struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
176
177   /**
178    * Callback
179    */
180   RECLAIM_TICKETS_TicketResult cb;
181
182   /**
183    * Callback cls
184    */
185   void *cb_cls;
186 };
187
188 /**
189  * Ticket iterator
190  */
191 struct RECLAIM_TICKETS_Iterator
192 {
193   /**
194    * Namestore queue entry
195    */
196   struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
197
198   /**
199    * Iter callback
200    */
201   RECLAIM_TICKETS_TicketIter cb;
202
203   /**
204    * Iter cls
205    */
206   void *cb_cls;
207 };
208
209
210 struct RevokedAttributeEntry
211 {
212   /**
213    * DLL
214    */
215   struct RevokedAttributeEntry *next;
216
217   /**
218    * DLL
219    */
220   struct RevokedAttributeEntry *prev;
221
222   /**
223    * Old ID of the attribute
224    */
225   uint64_t old_id;
226
227   /**
228    * New ID of the attribute
229    */
230   uint64_t new_id;
231 };
232
233
234 /**
235  * Ticket revocation request handle
236  */
237 struct RECLAIM_TICKETS_RevokeHandle
238 {
239   /**
240    * Issuer Key
241    */
242   struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
243
244   /**
245    * Callback
246    */
247   RECLAIM_TICKETS_RevokeCallback cb;
248
249   /**
250    * Callback cls
251    */
252   void *cb_cls;
253
254   /**
255    * Ticket to issue
256    */
257   struct GNUNET_RECLAIM_Ticket ticket;
258
259   /**
260    * QueueEntry
261    */
262   struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
263
264   /**
265    * Namestore iterator
266    */
267   struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
268
269   /**
270    * Revoked attributes
271    */
272   struct RevokedAttributeEntry *attrs_head;
273
274   /**
275    * Revoked attributes
276    */
277   struct RevokedAttributeEntry *attrs_tail;
278
279   /**
280    * Current attribute to move
281    */
282   struct RevokedAttributeEntry *move_attr;
283
284   /**
285    * Number of attributes in ticket
286    */
287   unsigned int ticket_attrs;
288
289   /**
290    * Tickets to update
291    */
292   struct TicketRecordsEntry *tickets_to_update_head;
293
294   /**
295    * Tickets to update
296    */
297   struct TicketRecordsEntry *tickets_to_update_tail;
298 };
299
300 /**
301  * Ticket expiration interval
302  */
303 static struct GNUNET_TIME_Relative ticket_refresh_interval;
304
305 /* Namestore handle */
306 static struct GNUNET_NAMESTORE_Handle *nsh;
307
308 /* GNS handle */
309 static struct GNUNET_GNS_Handle *gns;
310
311 /* Handle to the statistics service */
312 static struct GNUNET_STATISTICS_Handle *stats;
313
314 static void
315 move_attrs (struct RECLAIM_TICKETS_RevokeHandle *rh);
316
317 static void
318 move_attrs_cont (void *cls)
319 {
320   move_attrs ((struct RECLAIM_TICKETS_RevokeHandle *) cls);
321 }
322
323 /**
324  * Cleanup revoke handle
325  *
326  * @param rh the ticket revocation handle
327  */
328 static void
329 cleanup_rvk (struct RECLAIM_TICKETS_RevokeHandle *rh)
330 {
331   struct RevokedAttributeEntry *ae;
332   struct TicketRecordsEntry *le;
333   if (NULL != rh->ns_qe)
334     GNUNET_NAMESTORE_cancel (rh->ns_qe);
335   if (NULL != rh->ns_it)
336     GNUNET_NAMESTORE_zone_iteration_stop (rh->ns_it);
337   while (NULL != (ae = rh->attrs_head))
338   {
339     GNUNET_CONTAINER_DLL_remove (rh->attrs_head, rh->attrs_tail, ae);
340     GNUNET_free (ae);
341   }
342   while (NULL != (le = rh->tickets_to_update_head))
343   {
344     GNUNET_CONTAINER_DLL_remove (rh->tickets_to_update_head,
345                                  rh->tickets_to_update_head,
346                                  le);
347     if (NULL != le->data)
348       GNUNET_free (le->data);
349     if (NULL != le->label)
350       GNUNET_free (le->label);
351     GNUNET_free (le);
352   }
353   GNUNET_free (rh);
354 }
355
356 static void
357 del_attr_finished (void *cls, int32_t success, const char *emsg)
358 {
359   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
360   rvk->ns_qe = NULL;
361   if (GNUNET_SYSERR == success)
362   {
363     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
364                 "Error removing attribute: %s\n",
365                 emsg);
366     rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
367     cleanup_rvk (rvk);
368     return;
369   }
370   rvk->move_attr = rvk->move_attr->next;
371   GNUNET_SCHEDULER_add_now (&move_attrs_cont, rvk);
372 }
373
374 static void
375 move_attr_finished (void *cls, int32_t success, const char *emsg)
376 {
377   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
378   char *label;
379   rvk->ns_qe = NULL;
380   if (GNUNET_SYSERR == success)
381   {
382     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error moving attribute: %s\n", emsg);
383     rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
384     cleanup_rvk (rvk);
385     return;
386   }
387   label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->old_id,
388                                                sizeof (uint64_t));
389   GNUNET_assert (NULL != label);
390   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Removing attribute %s\n", label);
391   rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
392                                                &rvk->identity,
393                                                label,
394                                                0,
395                                                NULL,
396                                                &del_attr_finished,
397                                                rvk);
398   GNUNET_free (label);
399 }
400
401
402 static void
403 rvk_move_attr_cb (void *cls,
404                   const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
405                   const char *label,
406                   unsigned int rd_count,
407                   const struct GNUNET_GNSRECORD_Data *rd)
408 {
409   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
410   struct GNUNET_RECLAIM_ATTRIBUTE_Claim *claim;
411   struct GNUNET_GNSRECORD_Data new_rd;
412   struct RevokedAttributeEntry *le;
413   char *new_label;
414   char *attr_data;
415   rvk->ns_qe = NULL;
416   if (0 == rd_count)
417   {
418     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
419                 "The attribute %s no longer exists!\n",
420                 label);
421     le = rvk->move_attr;
422     rvk->move_attr = le->next;
423     GNUNET_CONTAINER_DLL_remove (rvk->attrs_head, rvk->attrs_tail, le);
424     GNUNET_free (le);
425     GNUNET_SCHEDULER_add_now (&move_attrs_cont, rvk);
426     return;
427   }
428   /** find a new place for this attribute **/
429   rvk->move_attr->new_id =
430     GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
431   new_rd = *rd;
432   claim = GNUNET_RECLAIM_ATTRIBUTE_deserialize (rd->data, rd->data_size);
433   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
434               "Attribute to update: Name=%s, ID=%" PRIu64 "\n",
435               claim->name,
436               claim->id);
437   claim->id = rvk->move_attr->new_id;
438   new_rd.data_size = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (claim);
439   attr_data = GNUNET_malloc (rd->data_size);
440   new_rd.data_size = GNUNET_RECLAIM_ATTRIBUTE_serialize (claim, attr_data);
441   new_rd.data = attr_data;
442   new_label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->new_id,
443                                                    sizeof (uint64_t));
444   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute %s\n", new_label);
445   rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
446                                                &rvk->identity,
447                                                new_label,
448                                                1,
449                                                &new_rd,
450                                                &move_attr_finished,
451                                                rvk);
452   GNUNET_free (new_label);
453   GNUNET_free (claim);
454   GNUNET_free (attr_data);
455 }
456
457
458 static void
459 rvk_ticket_update (void *cls,
460                    const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
461                    const char *label,
462                    unsigned int rd_count,
463                    const struct GNUNET_GNSRECORD_Data *rd)
464 {
465   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
466   struct TicketRecordsEntry *le;
467   struct RevokedAttributeEntry *ae;
468   int has_changed = GNUNET_NO;
469
470   /** Let everything point to the old record **/
471   for (int i = 0; i < rd_count; i++)
472   {
473     if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
474       continue;
475     for (ae = rvk->attrs_head; NULL != ae; ae = ae->next)
476     {
477       if (0 != memcmp (rd[i].data, &ae->old_id, sizeof (uint64_t)))
478         continue;
479       has_changed = GNUNET_YES;
480       break;
481     }
482     if (GNUNET_YES == has_changed)
483       break;
484   }
485   if (GNUNET_YES == has_changed)
486   {
487     le = GNUNET_new (struct TicketRecordsEntry);
488     le->data_size = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
489     le->data = GNUNET_malloc (le->data_size);
490     le->rd_count = rd_count;
491     le->label = GNUNET_strdup (label);
492     GNUNET_GNSRECORD_records_serialize (rd_count, rd, le->data_size, le->data);
493     GNUNET_CONTAINER_DLL_insert (rvk->tickets_to_update_head,
494                                  rvk->tickets_to_update_tail,
495                                  le);
496   }
497   GNUNET_NAMESTORE_zone_iterator_next (rvk->ns_it, 1);
498 }
499
500
501 static void
502 process_tickets (void *cls);
503
504
505 static void
506 ticket_processed (void *cls, int32_t success, const char *emsg)
507 {
508   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
509   rvk->ns_qe = NULL;
510   GNUNET_SCHEDULER_add_now (&process_tickets, rvk);
511 }
512
513 static void
514 process_tickets (void *cls)
515 {
516   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
517   struct TicketRecordsEntry *le;
518   struct RevokedAttributeEntry *ae;
519   if (NULL == rvk->tickets_to_update_head)
520   {
521     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
522                 "Finished updatding tickets, success\n");
523     rvk->cb (rvk->cb_cls, GNUNET_OK);
524     cleanup_rvk (rvk);
525     return;
526   }
527   le = rvk->tickets_to_update_head;
528   GNUNET_CONTAINER_DLL_remove (rvk->tickets_to_update_head,
529                                rvk->tickets_to_update_tail,
530                                le);
531   struct GNUNET_GNSRECORD_Data rd[le->rd_count];
532   if (GNUNET_OK != GNUNET_GNSRECORD_records_deserialize (le->data_size,
533                                                          le->data,
534                                                          le->rd_count,
535                                                          rd))
536   {
537     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
538                 "Unable to deserialize ticket record(s)\n");
539     rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
540     cleanup_rvk (rvk);
541     return;
542   }
543   for (int i = 0; i < le->rd_count; i++)
544   {
545     if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
546       continue;
547     for (ae = rvk->attrs_head; NULL != ae; ae = ae->next)
548     {
549       if (0 != memcmp (rd[i].data, &ae->old_id, sizeof (uint64_t)))
550         continue;
551       rd[i].data = &ae->new_id;
552     }
553   }
554   rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
555                                                &rvk->identity,
556                                                le->label,
557                                                le->rd_count,
558                                                rd,
559                                                &ticket_processed,
560                                                rvk);
561   GNUNET_free (le->label);
562   GNUNET_free (le->data);
563   GNUNET_free (le);
564 }
565
566 static void
567 rvk_ticket_update_finished (void *cls)
568 {
569   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
570   rvk->ns_it = NULL;
571   GNUNET_SCHEDULER_add_now (&process_tickets, rvk);
572 }
573
574
575 static void
576 rvk_ns_iter_err (void *cls)
577 {
578   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
579   rvk->ns_it = NULL;
580   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
581               "Namestore error on revocation (id=%" PRIu64 "\n",
582               rvk->move_attr->old_id);
583   rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
584   cleanup_rvk (rvk);
585 }
586
587
588 static void
589 rvk_ns_err (void *cls)
590 {
591   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
592   rvk->ns_qe = NULL;
593   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
594               "Namestore error on revocation (id=%" PRIu64 "\n",
595               rvk->move_attr->old_id);
596   rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
597   cleanup_rvk (rvk);
598 }
599
600
601 static void
602 move_attrs (struct RECLAIM_TICKETS_RevokeHandle *rvk)
603 {
604   char *label;
605
606   if (NULL == rvk->move_attr)
607   {
608     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished moving attributes\n");
609     rvk->ns_it =
610       GNUNET_NAMESTORE_zone_iteration_start (nsh,
611                                              &rvk->identity,
612                                              &rvk_ns_iter_err,
613                                              rvk,
614                                              &rvk_ticket_update,
615                                              rvk,
616                                              &rvk_ticket_update_finished,
617                                              rvk);
618     return;
619   }
620   label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->old_id,
621                                                sizeof (uint64_t));
622   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Moving attribute %s\n", label);
623
624   rvk->ns_qe = GNUNET_NAMESTORE_records_lookup (nsh,
625                                                 &rvk->identity,
626                                                 label,
627                                                 &rvk_ns_err,
628                                                 rvk,
629                                                 &rvk_move_attr_cb,
630                                                 rvk);
631   GNUNET_free (label);
632 }
633
634
635 static void
636 remove_ticket_cont (void *cls, int32_t success, const char *emsg)
637 {
638   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
639   rvk->ns_qe = NULL;
640   if (GNUNET_SYSERR == success)
641   {
642     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
643     rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
644     cleanup_rvk (rvk);
645     return;
646   }
647   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleted ticket\n");
648   if (0 == rvk->ticket_attrs)
649   {
650     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
651                 "No attributes to move... strange\n");
652     rvk->cb (rvk->cb_cls, GNUNET_OK);
653     cleanup_rvk (rvk);
654     return;
655   }
656   rvk->move_attr = rvk->attrs_head;
657   move_attrs (rvk);
658 }
659
660
661 static void
662 revoke_attrs_cb (void *cls,
663                  const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
664                  const char *label,
665                  unsigned int rd_count,
666                  const struct GNUNET_GNSRECORD_Data *rd)
667
668 {
669   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
670   struct RevokedAttributeEntry *le;
671   rvk->ns_qe = NULL;
672   for (int i = 0; i < rd_count; i++)
673   {
674     if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
675       continue;
676     le = GNUNET_new (struct RevokedAttributeEntry);
677     le->old_id = *((uint64_t *) rd[i].data);
678     GNUNET_CONTAINER_DLL_insert (rvk->attrs_head, rvk->attrs_tail, le);
679     rvk->ticket_attrs++;
680   }
681
682   /** Now, remove ticket **/
683   rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
684                                                &rvk->identity,
685                                                label,
686                                                0,
687                                                NULL,
688                                                &remove_ticket_cont,
689                                                rvk);
690 }
691
692
693 static void
694 rvk_attrs_err_cb (void *cls)
695 {
696   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
697   rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
698   cleanup_rvk (rvk);
699 }
700
701
702 struct RECLAIM_TICKETS_RevokeHandle *
703 RECLAIM_TICKETS_revoke (const struct GNUNET_RECLAIM_Ticket *ticket,
704                         const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
705                         RECLAIM_TICKETS_RevokeCallback cb,
706                         void *cb_cls)
707 {
708   struct RECLAIM_TICKETS_RevokeHandle *rvk;
709   char *label;
710
711   rvk = GNUNET_new (struct RECLAIM_TICKETS_RevokeHandle);
712   rvk->cb = cb;
713   rvk->cb_cls = cb_cls;
714   rvk->identity = *identity;
715   rvk->ticket = *ticket;
716   GNUNET_CRYPTO_ecdsa_key_get_public (&rvk->identity, &rvk->ticket.identity);
717   /** Get shared attributes **/
718   label = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof (uint64_t));
719   GNUNET_assert (NULL != label);
720   rvk->ns_qe = GNUNET_NAMESTORE_records_lookup (nsh,
721                                                 identity,
722                                                 label,
723                                                 &rvk_attrs_err_cb,
724                                                 rvk,
725                                                 &revoke_attrs_cb,
726                                                 rvk);
727   GNUNET_free (label);
728   return rvk;
729 }
730
731
732 void
733 RECLAIM_TICKETS_revoke_cancel (struct RECLAIM_TICKETS_RevokeHandle *rh)
734 {
735   cleanup_rvk (rh);
736 }
737 /*******************************
738  * Ticket consume
739  *******************************/
740
741 /**
742  * Cleanup ticket consume handle
743  * @param cth the handle to clean up
744  */
745 static void
746 cleanup_cth (struct RECLAIM_TICKETS_ConsumeHandle *cth)
747 {
748   struct ParallelLookup *lu;
749   if (NULL != cth->lookup_request)
750     GNUNET_GNS_lookup_cancel (cth->lookup_request);
751   if (NULL != cth->kill_task)
752     GNUNET_SCHEDULER_cancel (cth->kill_task);
753   while (NULL != (lu = cth->parallel_lookups_head))
754   {
755     if (NULL != lu->lookup_request)
756       GNUNET_GNS_lookup_cancel (lu->lookup_request);
757     GNUNET_free_non_null (lu->label);
758     GNUNET_CONTAINER_DLL_remove (cth->parallel_lookups_head,
759                                  cth->parallel_lookups_tail,
760                                  lu);
761     GNUNET_free (lu);
762   }
763
764   if (NULL != cth->attrs)
765     GNUNET_RECLAIM_ATTRIBUTE_list_destroy (cth->attrs);
766   GNUNET_free (cth);
767 }
768
769
770 static void
771 process_parallel_lookup_result (void *cls,
772                                 uint32_t rd_count,
773                                 const struct GNUNET_GNSRECORD_Data *rd)
774 {
775   struct ParallelLookup *parallel_lookup = cls;
776   struct RECLAIM_TICKETS_ConsumeHandle *cth = parallel_lookup->handle;
777   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *attr_le;
778   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
779               "Parallel lookup finished (count=%u)\n",
780               rd_count);
781
782   GNUNET_CONTAINER_DLL_remove (cth->parallel_lookups_head,
783                                cth->parallel_lookups_tail,
784                                parallel_lookup);
785   GNUNET_free (parallel_lookup->label);
786
787   GNUNET_STATISTICS_update (stats,
788                             "attribute_lookup_time_total",
789                             GNUNET_TIME_absolute_get_duration (
790                               parallel_lookup->lookup_start_time)
791                               .rel_value_us,
792                             GNUNET_YES);
793   GNUNET_STATISTICS_update (stats, "attribute_lookups_count", 1, GNUNET_YES);
794
795
796   GNUNET_free (parallel_lookup);
797   if (1 != rd_count)
798     GNUNET_break (0); // TODO
799   if (rd->record_type == GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR)
800   {
801     attr_le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry);
802     attr_le->claim =
803       GNUNET_RECLAIM_ATTRIBUTE_deserialize (rd->data, rd->data_size);
804     GNUNET_CONTAINER_DLL_insert (cth->attrs->list_head,
805                                  cth->attrs->list_tail,
806                                  attr_le);
807   }
808   if (NULL != cth->parallel_lookups_head)
809     return; // Wait for more
810   /* Else we are done */
811
812   cth->cb (cth->cb_cls, &cth->ticket.identity, cth->attrs, GNUNET_OK, NULL);
813   cleanup_cth (cth);
814 }
815
816
817 static void
818 abort_parallel_lookups (void *cls)
819 {
820   struct RECLAIM_TICKETS_ConsumeHandle *cth = cls;
821   struct ParallelLookup *lu;
822   struct ParallelLookup *tmp;
823
824   cth->kill_task = NULL;
825   for (lu = cth->parallel_lookups_head; NULL != lu;)
826   {
827     GNUNET_GNS_lookup_cancel (lu->lookup_request);
828     GNUNET_free (lu->label);
829     tmp = lu->next;
830     GNUNET_CONTAINER_DLL_remove (cth->parallel_lookups_head,
831                                  cth->parallel_lookups_tail,
832                                  lu);
833     GNUNET_free (lu);
834     lu = tmp;
835   }
836   cth->cb (cth->cb_cls, NULL, NULL, GNUNET_SYSERR, "Aborted");
837 }
838
839
840 static void
841 lookup_authz_cb (void *cls,
842                  uint32_t rd_count,
843                  const struct GNUNET_GNSRECORD_Data *rd)
844 {
845   struct RECLAIM_TICKETS_ConsumeHandle *cth = cls;
846   struct ParallelLookup *parallel_lookup;
847   char *lbl;
848
849   cth->lookup_request = NULL;
850
851   GNUNET_STATISTICS_update (stats,
852                             "reclaim_authz_lookup_time_total",
853                             GNUNET_TIME_absolute_get_duration (
854                               cth->lookup_start_time)
855                               .rel_value_us,
856                             GNUNET_YES);
857   GNUNET_STATISTICS_update (stats,
858                             "reclaim_authz_lookups_count",
859                             1,
860                             GNUNET_YES);
861
862   for (int i = 0; i < rd_count; i++)
863   {
864     if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
865       continue;
866     lbl = GNUNET_STRINGS_data_to_string_alloc (rd[i].data, rd[i].data_size);
867     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Attribute ref found %s\n", lbl);
868     parallel_lookup = GNUNET_new (struct ParallelLookup);
869     parallel_lookup->handle = cth;
870     parallel_lookup->label = lbl;
871     parallel_lookup->lookup_start_time = GNUNET_TIME_absolute_get ();
872     parallel_lookup->lookup_request =
873       GNUNET_GNS_lookup (gns,
874                          lbl,
875                          &cth->ticket.identity,
876                          GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR,
877                          GNUNET_GNS_LO_DEFAULT,
878                          &process_parallel_lookup_result,
879                          parallel_lookup);
880     GNUNET_CONTAINER_DLL_insert (cth->parallel_lookups_head,
881                                  cth->parallel_lookups_tail,
882                                  parallel_lookup);
883   }
884   if (NULL != cth->parallel_lookups_head)
885   {
886     cth->kill_task = GNUNET_SCHEDULER_add_delayed (
887       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 3),
888       &abort_parallel_lookups,
889       cth);
890     return;
891   }
892   cth->cb (cth->cb_cls, &cth->ticket.identity, cth->attrs, GNUNET_OK, NULL);
893   cleanup_cth (cth);
894 }
895
896
897 struct RECLAIM_TICKETS_ConsumeHandle *
898 RECLAIM_TICKETS_consume (const struct GNUNET_CRYPTO_EcdsaPrivateKey *id,
899                          const struct GNUNET_RECLAIM_Ticket *ticket,
900                          RECLAIM_TICKETS_ConsumeCallback cb,
901                          void *cb_cls)
902 {
903   struct RECLAIM_TICKETS_ConsumeHandle *cth;
904   char *label;
905   cth = GNUNET_new (struct RECLAIM_TICKETS_ConsumeHandle);
906
907   cth->identity = *id;
908   GNUNET_CRYPTO_ecdsa_key_get_public (&cth->identity, &cth->identity_pub);
909   cth->attrs = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList);
910   cth->ticket = *ticket;
911   cth->cb = cb;
912   cth->cb_cls = cb_cls;
913   label =
914     GNUNET_STRINGS_data_to_string_alloc (&cth->ticket.rnd, sizeof (uint64_t));
915   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
916               "Looking for AuthZ info under %s\n",
917               label);
918   cth->lookup_start_time = GNUNET_TIME_absolute_get ();
919   cth->lookup_request =
920     GNUNET_GNS_lookup (gns,
921                        label,
922                        &cth->ticket.identity,
923                        GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF,
924                        GNUNET_GNS_LO_DEFAULT,
925                        &lookup_authz_cb,
926                        cth);
927   GNUNET_free (label);
928   return cth;
929 }
930
931 void
932 RECLAIM_TICKETS_consume_cancel (struct RECLAIM_TICKETS_ConsumeHandle *cth)
933 {
934   cleanup_cth (cth);
935   return;
936 }
937
938
939 /*******************************
940  * Ticket issue
941  *******************************/
942
943 /**
944  * Cleanup ticket consume handle
945  * @param handle the handle to clean up
946  */
947 static void
948 cleanup_issue_handle (struct TicketIssueHandle *handle)
949 {
950   if (NULL != handle->ns_qe)
951     GNUNET_NAMESTORE_cancel (handle->ns_qe);
952   GNUNET_free (handle);
953 }
954
955
956 static void
957 store_ticket_issue_cont (void *cls, int32_t success, const char *emsg)
958 {
959   struct TicketIssueHandle *handle = cls;
960
961   handle->ns_qe = NULL;
962   if (GNUNET_SYSERR == success)
963   {
964     handle->cb (handle->cb_cls,
965                 &handle->ticket,
966                 GNUNET_SYSERR,
967                 "Error storing AuthZ ticket in GNS");
968     return;
969   }
970   handle->cb (handle->cb_cls, &handle->ticket, GNUNET_OK, NULL);
971   cleanup_issue_handle (handle);
972 }
973
974
975 static void
976 issue_ticket (struct TicketIssueHandle *ih)
977 {
978   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
979   struct GNUNET_GNSRECORD_Data *attrs_record;
980   char *label;
981   size_t list_len = 1;
982   int i;
983
984   for (le = ih->attrs->list_head; NULL != le; le = le->next)
985     list_len++;
986
987   attrs_record =
988     GNUNET_malloc (list_len * sizeof (struct GNUNET_GNSRECORD_Data));
989   i = 0;
990   for (le = ih->attrs->list_head; NULL != le; le = le->next)
991   {
992     attrs_record[i].data = &le->claim->id;
993     attrs_record[i].data_size = sizeof (le->claim->id);
994     //FIXME: Should this be the attribute expiration time or ticket refresh intv
995     attrs_record[i].expiration_time = ticket_refresh_interval.rel_value_us;
996     attrs_record[i].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF;
997     attrs_record[i].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
998     i++;
999   }
1000   attrs_record[i].data = &ih->ticket;
1001   attrs_record[i].data_size = sizeof (struct GNUNET_RECLAIM_Ticket);
1002   attrs_record[i].expiration_time = ticket_refresh_interval.rel_value_us;
1003   attrs_record[i].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET;
1004   attrs_record[i].flags =
1005     GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION | GNUNET_GNSRECORD_RF_PRIVATE;
1006
1007   label =
1008     GNUNET_STRINGS_data_to_string_alloc (&ih->ticket.rnd, sizeof (uint64_t));
1009   // Publish record
1010   ih->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
1011                                               &ih->identity,
1012                                               label,
1013                                               list_len,
1014                                               attrs_record,
1015                                               &store_ticket_issue_cont,
1016                                               ih);
1017   GNUNET_free (attrs_record);
1018   GNUNET_free (label);
1019 }
1020
1021 /*************************************************
1022  * Ticket iteration (finding a specific ticket)
1023  *************************************************/
1024
1025 static void
1026 filter_tickets_error_cb (void *cls)
1027 {
1028   struct TicketIssueHandle *tih = cls;
1029   tih->ns_it = NULL;
1030   tih->cb (tih->cb_cls,
1031            &tih->ticket,
1032            GNUNET_SYSERR,
1033            "Error storing AuthZ ticket in GNS");
1034   cleanup_issue_handle (tih);
1035 }
1036
1037 static void
1038 filter_tickets_cb (void *cls,
1039                    const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1040                    const char *label,
1041                    unsigned int rd_count,
1042                    const struct GNUNET_GNSRECORD_Data *rd)
1043 {
1044   struct TicketIssueHandle *tih = cls;
1045   struct GNUNET_RECLAIM_Ticket *ticket = NULL;
1046
1047   // figure out the number of requested attributes
1048   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
1049   unsigned int attr_cnt = 0;
1050   for (le = tih->attrs->list_head; NULL != le; le = le->next)
1051     attr_cnt++;
1052
1053   // ticket search
1054   unsigned int found_attrs_cnt = 0;
1055
1056   for (int i = 0; i < rd_count; i++)
1057   {
1058     // found ticket
1059     if (GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET == rd[i].record_type)
1060     {
1061       ticket = (struct GNUNET_RECLAIM_Ticket *) rd[i].data;
1062       // cmp audience
1063       if (0 == memcmp (&tih->ticket.audience,
1064                        &ticket->audience,
1065                        sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
1066       {
1067         tih->ticket = *ticket;
1068         continue;
1069       }
1070       ticket = NULL;
1071     }
1072
1073     // cmp requested attributes with ticket attributes
1074     if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
1075       continue;
1076     for (le = tih->attrs->list_head; NULL != le; le = le->next)
1077     {
1078       // cmp attr_ref id with requested attr id
1079       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1080                   " %" PRIu64 "\n  %" PRIu64 "\n",
1081                   *((uint64_t *) rd[i].data),
1082                   le->claim->id);
1083
1084
1085       if (0 == memcmp (rd[i].data, &le->claim->id, sizeof (uint64_t)))
1086         found_attrs_cnt++;
1087     }
1088   }
1089
1090   if (attr_cnt == found_attrs_cnt && NULL != ticket)
1091   {
1092     GNUNET_NAMESTORE_zone_iteration_stop (tih->ns_it);
1093     tih->cb (tih->cb_cls, &tih->ticket, GNUNET_OK, NULL);
1094     cleanup_issue_handle (tih);
1095     return;
1096   }
1097
1098   // ticket not found in current record
1099   GNUNET_NAMESTORE_zone_iterator_next (tih->ns_it, 1);
1100 }
1101
1102
1103 static void
1104 filter_tickets_finished_cb (void *cls)
1105 {
1106   struct TicketIssueHandle *tih = cls;
1107   GNUNET_CRYPTO_ecdsa_key_get_public (&tih->identity, &tih->ticket.identity);
1108   tih->ticket.rnd =
1109     GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
1110   issue_ticket (tih);
1111 }
1112
1113 void
1114 RECLAIM_TICKETS_issue (const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1115                        const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
1116                        const struct GNUNET_CRYPTO_EcdsaPublicKey *audience,
1117                        RECLAIM_TICKETS_TicketResult cb,
1118                        void *cb_cls)
1119 {
1120   struct TicketIssueHandle *tih;
1121   tih = GNUNET_new (struct TicketIssueHandle);
1122   tih->cb = cb;
1123   tih->cb_cls = cb_cls;
1124   tih->attrs = GNUNET_RECLAIM_ATTRIBUTE_list_dup (attrs);
1125   tih->identity = *identity;
1126   tih->ticket.audience = *audience;
1127
1128   // check whether the ticket has already been issued
1129   tih->ns_it =
1130     GNUNET_NAMESTORE_zone_iteration_start (nsh,
1131                                            &tih->identity,
1132                                            &filter_tickets_error_cb,
1133                                            tih,
1134                                            &filter_tickets_cb,
1135                                            tih,
1136                                            &filter_tickets_finished_cb,
1137                                            tih);
1138 }
1139
1140 /************************************
1141  * Ticket iteration
1142  ************************************/
1143
1144 static void
1145 cleanup_iter (struct RECLAIM_TICKETS_Iterator *iter)
1146 {
1147   if (NULL != iter->ns_it)
1148     GNUNET_NAMESTORE_zone_iteration_stop (iter->ns_it);
1149   GNUNET_free (iter);
1150 }
1151
1152
1153 static void
1154 collect_tickets_cb (void *cls,
1155                     const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1156                     const char *label,
1157                     unsigned int rd_count,
1158                     const struct GNUNET_GNSRECORD_Data *rd)
1159 {
1160   struct RECLAIM_TICKETS_Iterator *iter = cls;
1161
1162   for (int i = 0; i < rd_count; i++)
1163   {
1164     if (GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET != rd[i].record_type)
1165       continue;
1166     iter->cb (iter->cb_cls, (struct GNUNET_RECLAIM_Ticket *) rd[i].data);
1167     return;
1168   }
1169   GNUNET_NAMESTORE_zone_iterator_next (iter->ns_it, 1);
1170 }
1171
1172
1173 static void
1174 collect_tickets_finished_cb (void *cls)
1175 {
1176   struct RECLAIM_TICKETS_Iterator *iter = cls;
1177   iter->ns_it = NULL;
1178   iter->cb (iter->cb_cls, NULL);
1179   cleanup_iter (iter);
1180 }
1181
1182
1183 static void
1184 collect_tickets_error_cb (void *cls)
1185 {
1186   struct RECLAIM_TICKETS_Iterator *iter = cls;
1187   iter->ns_it = NULL;
1188   iter->cb (iter->cb_cls, NULL);
1189   cleanup_iter (iter);
1190 }
1191
1192
1193 void
1194 RECLAIM_TICKETS_iteration_next (struct RECLAIM_TICKETS_Iterator *iter)
1195 {
1196   GNUNET_NAMESTORE_zone_iterator_next (iter->ns_it, 1);
1197 }
1198
1199
1200 void
1201 RECLAIM_TICKETS_iteration_stop (struct RECLAIM_TICKETS_Iterator *iter)
1202 {
1203   GNUNET_NAMESTORE_zone_iteration_stop (iter->ns_it);
1204   cleanup_iter (iter);
1205 }
1206
1207
1208 struct RECLAIM_TICKETS_Iterator *
1209 RECLAIM_TICKETS_iteration_start (
1210   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1211   RECLAIM_TICKETS_TicketIter cb,
1212   void *cb_cls)
1213 {
1214   struct RECLAIM_TICKETS_Iterator *iter;
1215
1216   iter = GNUNET_new (struct RECLAIM_TICKETS_Iterator);
1217   iter->cb = cb;
1218   iter->cb_cls = cb_cls;
1219   iter->ns_it =
1220     GNUNET_NAMESTORE_zone_iteration_start (nsh,
1221                                            identity,
1222                                            &collect_tickets_error_cb,
1223                                            iter,
1224                                            &collect_tickets_cb,
1225                                            iter,
1226                                            &collect_tickets_finished_cb,
1227                                            iter);
1228   return iter;
1229 }
1230
1231
1232 int
1233 RECLAIM_TICKETS_init (const struct GNUNET_CONFIGURATION_Handle *c)
1234 {
1235   // Get ticket expiration time (relative) from config
1236   if (GNUNET_OK ==
1237       GNUNET_CONFIGURATION_get_value_time (c,
1238                                            "reclaim",
1239                                            "TICKET_REFRESH_INTERVAL",
1240                                            &ticket_refresh_interval))
1241   {
1242     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1243                 "Configured refresh interval for tickets: %s\n",
1244                 GNUNET_STRINGS_relative_time_to_string (ticket_refresh_interval,
1245                                                         GNUNET_YES));
1246   }
1247   else
1248   {
1249     ticket_refresh_interval = DEFAULT_TICKET_REFRESH_INTERVAL;
1250   }
1251   // Connect to identity and namestore services
1252   nsh = GNUNET_NAMESTORE_connect (c);
1253   if (NULL == nsh)
1254   {
1255     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1256                          "error connecting to namestore");
1257     return GNUNET_SYSERR;
1258   }
1259   gns = GNUNET_GNS_connect (c);
1260   if (NULL == gns)
1261   {
1262     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to gns");
1263     return GNUNET_SYSERR;
1264   }
1265   stats = GNUNET_STATISTICS_create ("reclaim", c);
1266   return GNUNET_OK;
1267 }
1268
1269 void
1270 RECLAIM_TICKETS_deinit (void)
1271 {
1272   if (NULL != nsh)
1273     GNUNET_NAMESTORE_disconnect (nsh);
1274   nsh = NULL;
1275   if (NULL != gns)
1276     GNUNET_GNS_disconnect (gns);
1277   gns = NULL;
1278   if (NULL != stats)
1279   {
1280     GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
1281     stats = NULL;
1282   }
1283 }