REST/NAMESTORE: rework API
[oweals/gnunet.git] / src / reclaim / gnunet-service-reclaim.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  * @author Martin Schanzenbach
22  * @file src/reclaim/gnunet-service-reclaim.c
23  * @brief reclaim Service
24  *
25  */
26 #include "platform.h"
27
28 #include "gnunet_util_lib.h"
29
30 #include "gnunet-service-reclaim_tickets.h"
31 #include "gnunet_constants.h"
32 #include "gnunet_gnsrecord_lib.h"
33 #include "gnunet_identity_service.h"
34 #include "gnunet_namestore_service.h"
35 #include "gnunet_protocols.h"
36 #include "gnunet_reclaim_attribute_lib.h"
37 #include "gnunet_reclaim_service.h"
38 #include "gnunet_signatures.h"
39 #include "reclaim.h"
40
41 /**
42  * First pass state
43  */
44 #define STATE_INIT 0
45
46 /**
47  * Normal operation state
48  */
49 #define STATE_POST_INIT 1
50
51 /**
52  * Minimum interval between updates
53  */
54 #define MIN_WAIT_TIME GNUNET_TIME_UNIT_MINUTES
55
56 /**
57  * Standard token expiration time
58  */
59 #define DEFAULT_TOKEN_EXPIRATION_INTERVAL GNUNET_TIME_UNIT_HOURS
60
61 /**
62  * Identity handle
63  */
64 static struct GNUNET_IDENTITY_Handle *identity_handle;
65
66 /**
67  * Token expiration interval
68  */
69 static struct GNUNET_TIME_Relative token_expiration_interval;
70
71 /**
72  * Namestore handle
73  */
74 static struct GNUNET_NAMESTORE_Handle *nsh;
75
76 /**
77  * Timeout task
78  */
79 static struct GNUNET_SCHEDULER_Task *timeout_task;
80
81 /**
82  * Update task
83  */
84 static struct GNUNET_SCHEDULER_Task *update_task;
85
86 /**
87  * Our configuration.
88  */
89 static const struct GNUNET_CONFIGURATION_Handle *cfg;
90
91 /**
92  * An idp client
93  */
94 struct IdpClient;
95
96 /**
97  * A ticket iteration operation.
98  */
99 struct TicketIteration
100 {
101   /**
102    * DLL
103    */
104   struct TicketIteration *next;
105
106   /**
107    * DLL
108    */
109   struct TicketIteration *prev;
110
111   /**
112    * Client which intiated this zone iteration
113    */
114   struct IdpClient *client;
115
116   /**
117    * The operation id fot the iteration in the response for the client
118    */
119   uint32_t r_id;
120
121   /**
122    * The ticket iterator
123    */
124   struct RECLAIM_TICKETS_Iterator *iter;
125 };
126
127 /**
128  * An attribute iteration operation.
129  */
130 struct AttributeIterator
131 {
132   /**
133    * Next element in the DLL
134    */
135   struct AttributeIterator *next;
136
137   /**
138    * Previous element in the DLL
139    */
140   struct AttributeIterator *prev;
141
142   /**
143    * IDP client which intiated this zone iteration
144    */
145   struct IdpClient *client;
146
147   /**
148    * Key of the zone we are iterating over.
149    */
150   struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
151
152   /**
153    * Namestore iterator
154    */
155   struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
156
157   /**
158    * The operation id fot the zone iteration in the response for the client
159    */
160   uint32_t request_id;
161 };
162
163 /**
164  * An idp client
165  */
166 struct IdpClient
167 {
168
169   /**
170    * The client
171    */
172   struct GNUNET_SERVICE_Client *client;
173
174   /**
175    * Message queue for transmission to @e client
176    */
177   struct GNUNET_MQ_Handle *mq;
178
179   /**
180    * Head of the DLL of
181    * Attribute iteration operations in
182    * progress initiated by this client
183    */
184   struct AttributeIterator *attr_iter_head;
185
186   /**
187    * Tail of the DLL of
188    * Attribute iteration operations
189    * in progress initiated by this client
190    */
191   struct AttributeIterator *attr_iter_tail;
192
193   /**
194    * Head of DLL of ticket iteration ops
195    */
196   struct TicketIteration *ticket_iter_head;
197
198   /**
199    * Tail of DLL of ticket iteration ops
200    */
201   struct TicketIteration *ticket_iter_tail;
202
203   /**
204    * Head of DLL of ticket revocation ops
205    */
206   struct TicketRevocationOperation *revoke_op_head;
207
208   /**
209    * Tail of DLL of ticket revocation ops
210    */
211   struct TicketRevocationOperation *revoke_op_tail;
212
213   /**
214    * Head of DLL of ticket issue ops
215    */
216   struct TicketIssueOperation *issue_op_head;
217
218   /**
219    * Tail of DLL of ticket issue ops
220    */
221   struct TicketIssueOperation *issue_op_tail;
222
223   /**
224    * Head of DLL of ticket consume ops
225    */
226   struct ConsumeTicketOperation *consume_op_head;
227
228   /**
229    * Tail of DLL of ticket consume ops
230    */
231   struct ConsumeTicketOperation *consume_op_tail;
232
233   /**
234    * Head of DLL of attribute store ops
235    */
236   struct AttributeStoreHandle *store_op_head;
237
238   /**
239    * Tail of DLL of attribute store ops
240    */
241   struct AttributeStoreHandle *store_op_tail;
242   /**
243    * Head of DLL of attribute delete ops
244    */
245   struct AttributeDeleteHandle *delete_op_head;
246
247   /**
248    * Tail of DLL of attribute delete ops
249    */
250   struct AttributeDeleteHandle *delete_op_tail;
251 };
252
253
254 struct AttributeDeleteHandle
255 {
256   /**
257    * DLL
258    */
259   struct AttributeDeleteHandle *next;
260
261   /**
262    * DLL
263    */
264   struct AttributeDeleteHandle *prev;
265
266   /**
267    * Client connection
268    */
269   struct IdpClient *client;
270
271   /**
272    * Identity
273    */
274   struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
275
276
277   /**
278    * QueueEntry
279    */
280   struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
281
282   /**
283    * Iterator
284    */
285   struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
286
287   /**
288    * The attribute to delete
289    */
290   struct GNUNET_RECLAIM_ATTRIBUTE_Claim *claim;
291
292   /**
293    * Tickets to update
294    */
295   struct TicketRecordsEntry *tickets_to_update_head;
296
297   /**
298    * Tickets to update
299    */
300   struct TicketRecordsEntry *tickets_to_update_tail;
301
302   /**
303    * Attribute label
304    */
305   char *label;
306
307   /**
308    * request id
309    */
310   uint32_t r_id;
311 };
312
313
314 struct AttributeStoreHandle
315 {
316   /**
317    * DLL
318    */
319   struct AttributeStoreHandle *next;
320
321   /**
322    * DLL
323    */
324   struct AttributeStoreHandle *prev;
325
326   /**
327    * Client connection
328    */
329   struct IdpClient *client;
330
331   /**
332    * Identity
333    */
334   struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
335
336   /**
337    * Identity pubkey
338    */
339   struct GNUNET_CRYPTO_EcdsaPublicKey identity_pkey;
340
341   /**
342    * QueueEntry
343    */
344   struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
345
346   /**
347    * The attribute to store
348    */
349   struct GNUNET_RECLAIM_ATTRIBUTE_Claim *claim;
350
351   /**
352    * The attribute expiration interval
353    */
354   struct GNUNET_TIME_Relative exp;
355
356   /**
357    * request id
358    */
359   uint32_t r_id;
360 };
361
362 struct ConsumeTicketOperation
363 {
364   /**
365    * DLL
366    */
367   struct ConsumeTicketOperation *next;
368
369   /**
370    * DLL
371    */
372   struct ConsumeTicketOperation *prev;
373
374   /**
375    * Client connection
376    */
377   struct IdpClient *client;
378
379   /**
380    * request id
381    */
382   uint32_t r_id;
383
384   /**
385    * Ticket consume handle
386    */
387   struct RECLAIM_TICKETS_ConsumeHandle *ch;
388 };
389
390 /**
391  * Updated attribute IDs
392  */
393 struct TicketAttributeUpdateEntry
394 {
395   /**
396    * DLL
397    */
398   struct TicketAttributeUpdateEntry *next;
399
400   /**
401    * DLL
402    */
403   struct TicketAttributeUpdateEntry *prev;
404
405   /**
406    * The old ID
407    */
408   uint64_t old_id;
409
410   /**
411    * The new ID
412    */
413   uint64_t new_id;
414 };
415
416 /**
417  * Ticket revocation request handle
418  */
419 struct TicketRevocationOperation
420 {
421   /**
422    * DLL
423    */
424   struct TicketRevocationOperation *prev;
425
426   /**
427    * DLL
428    */
429   struct TicketRevocationOperation *next;
430
431   /**
432    * Client connection
433    */
434   struct IdpClient *client;
435
436   /**
437    * Revocation handle
438    */
439   struct RECLAIM_TICKETS_RevokeHandle *rh;
440
441   /**
442    * request id
443    */
444   uint32_t r_id;
445 };
446
447 /**
448  * Ticket issue operation handle
449  */
450 struct TicketIssueOperation
451 {
452   /**
453    * DLL
454    */
455   struct TicketIssueOperation *prev;
456
457   /**
458    * DLL
459    */
460   struct TicketIssueOperation *next;
461
462   /**
463    * Client connection
464    */
465   struct IdpClient *client;
466
467   /**
468    * request id
469    */
470   uint32_t r_id;
471 };
472
473 /**
474  * DLL for ego handles to egos containing the RECLAIM_ATTRS in a
475  * map in json_t format
476  *
477  */
478 struct EgoEntry
479 {
480   /**
481    * DLL
482    */
483   struct EgoEntry *next;
484
485   /**
486    * DLL
487    */
488   struct EgoEntry *prev;
489
490   /**
491    * Ego handle
492    */
493   struct GNUNET_IDENTITY_Ego *ego;
494
495   /**
496    * Attribute map. Contains the attributes as json_t
497    */
498   struct GNUNET_CONTAINER_MultiHashMap *attr_map;
499 };
500
501 /**
502  * Cleanup task
503  */
504 static void
505 cleanup ()
506 {
507   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
508
509   RECLAIM_TICKETS_deinit ();
510   if (NULL != timeout_task)
511     GNUNET_SCHEDULER_cancel (timeout_task);
512   if (NULL != update_task)
513     GNUNET_SCHEDULER_cancel (update_task);
514   if (NULL != identity_handle)
515     GNUNET_IDENTITY_disconnect (identity_handle);
516   if (NULL != nsh)
517     GNUNET_NAMESTORE_disconnect (nsh);
518 }
519
520 /**
521  * Shutdown task
522  *
523  * @param cls NULL
524  */
525 static void
526 do_shutdown (void *cls)
527 {
528   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down...\n");
529   cleanup ();
530 }
531
532
533 static void
534 send_ticket_result (const struct IdpClient *client,
535                     uint32_t r_id,
536                     const struct GNUNET_RECLAIM_Ticket *ticket,
537                     uint32_t success)
538 {
539   struct TicketResultMessage *irm;
540   struct GNUNET_MQ_Envelope *env;
541   struct GNUNET_RECLAIM_Ticket *ticket_buf;
542
543   if (NULL != ticket) {
544     env = GNUNET_MQ_msg_extra (irm,
545                                sizeof (struct GNUNET_RECLAIM_Ticket),
546                                GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT);
547     ticket_buf = (struct GNUNET_RECLAIM_Ticket *)&irm[1];
548     *ticket_buf = *ticket;
549   } else {
550     env = GNUNET_MQ_msg (irm, GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT);
551   }
552   // TODO add success member
553   irm->id = htonl (r_id);
554   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending TICKET_RESULT message\n");
555   GNUNET_MQ_send (client->mq, env);
556 }
557
558 static void
559 issue_ticket_result_cb (void *cls,
560                         struct GNUNET_RECLAIM_Ticket *ticket,
561                         int32_t success,
562                         const char *emsg)
563 {
564   struct TicketIssueOperation *tio = cls;
565   if (GNUNET_OK != success) {
566     send_ticket_result (tio->client, tio->r_id, NULL, GNUNET_SYSERR);
567     GNUNET_CONTAINER_DLL_remove (tio->client->issue_op_head,
568                                  tio->client->issue_op_tail,
569                                  tio);
570     GNUNET_free (tio);
571     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error issuing ticket: %s\n", emsg);
572     return;
573   }
574   send_ticket_result (tio->client, tio->r_id, ticket, GNUNET_SYSERR);
575   GNUNET_CONTAINER_DLL_remove (tio->client->issue_op_head,
576                                tio->client->issue_op_tail,
577                                tio);
578   GNUNET_free (tio);
579 }
580
581 static int
582 check_issue_ticket_message (void *cls, const struct IssueTicketMessage *im)
583 {
584   uint16_t size;
585
586   size = ntohs (im->header.size);
587   if (size <= sizeof (struct IssueTicketMessage)) {
588     GNUNET_break (0);
589     return GNUNET_SYSERR;
590   }
591   return GNUNET_OK;
592 }
593
594 static void
595 handle_issue_ticket_message (void *cls, const struct IssueTicketMessage *im)
596 {
597   struct TicketIssueOperation *tio;
598   struct IdpClient *idp = cls;
599   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs;
600   size_t attrs_len;
601
602   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ISSUE_TICKET message\n");
603   tio = GNUNET_new (struct TicketIssueOperation);
604   attrs_len = ntohs (im->attr_len);
605   attrs = GNUNET_RECLAIM_ATTRIBUTE_list_deserialize ((char *)&im[1], attrs_len);
606   tio->r_id = ntohl (im->id);
607   tio->client = idp;
608   GNUNET_CONTAINER_DLL_insert (idp->issue_op_head, idp->issue_op_tail, tio);
609   RECLAIM_TICKETS_issue (&im->identity,
610                          attrs,
611                          &im->rp,
612                          &issue_ticket_result_cb,
613                          tio);
614   GNUNET_SERVICE_client_continue (idp->client);
615   GNUNET_RECLAIM_ATTRIBUTE_list_destroy (attrs);
616 }
617
618 /**********************************************************
619  * Revocation
620  **********************************************************/
621
622 static void
623 revoke_result_cb (void *cls, int32_t success)
624 {
625   struct TicketRevocationOperation *rop = cls;
626   struct GNUNET_MQ_Envelope *env;
627   struct RevokeTicketResultMessage *trm;
628
629   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending REVOKE_TICKET_RESULT message\n");
630   rop->rh = NULL;
631   env = GNUNET_MQ_msg (trm, GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET_RESULT);
632   trm->id = htonl (rop->r_id);
633   trm->success = htonl (success);
634   GNUNET_MQ_send (rop->client->mq, env);
635   GNUNET_CONTAINER_DLL_remove (rop->client->revoke_op_head,
636                                rop->client->revoke_op_tail,
637                                rop);
638   GNUNET_free (rop);
639 }
640
641
642 static int
643 check_revoke_ticket_message (void *cls, const struct RevokeTicketMessage *im)
644 {
645   uint16_t size;
646
647   size = ntohs (im->header.size);
648   if (size <= sizeof (struct RevokeTicketMessage)) {
649     GNUNET_break (0);
650     return GNUNET_SYSERR;
651   }
652   return GNUNET_OK;
653 }
654
655 static void
656 handle_revoke_ticket_message (void *cls, const struct RevokeTicketMessage *rm)
657 {
658   struct TicketRevocationOperation *rop;
659   struct IdpClient *idp = cls;
660   struct GNUNET_RECLAIM_Ticket *ticket;
661
662   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received REVOKE_TICKET message\n");
663   rop = GNUNET_new (struct TicketRevocationOperation);
664   ticket = (struct GNUNET_RECLAIM_Ticket *)&rm[1];
665   rop->r_id = ntohl (rm->id);
666   rop->client = idp;
667   GNUNET_CONTAINER_DLL_insert (idp->revoke_op_head, idp->revoke_op_tail, rop);
668   rop->rh
669     = RECLAIM_TICKETS_revoke (ticket, &rm->identity, &revoke_result_cb, rop);
670   GNUNET_SERVICE_client_continue (idp->client);
671 }
672
673 static int
674 check_consume_ticket_message (void *cls, const struct ConsumeTicketMessage *cm)
675 {
676   uint16_t size;
677
678   size = ntohs (cm->header.size);
679   if (size <= sizeof (struct ConsumeTicketMessage)) {
680     GNUNET_break (0);
681     return GNUNET_SYSERR;
682   }
683   return GNUNET_OK;
684 }
685
686 static void
687 consume_result_cb (void *cls,
688                    const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
689                    const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
690                    int32_t success,
691                    const char *emsg)
692 {
693   struct ConsumeTicketOperation *cop = cls;
694   struct ConsumeTicketResultMessage *crm;
695   struct GNUNET_MQ_Envelope *env;
696   char *data_tmp;
697   size_t attrs_len;
698   if (GNUNET_OK != success) {
699     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error consuming ticket: %s\n", emsg);
700   }
701   attrs_len = GNUNET_RECLAIM_ATTRIBUTE_list_serialize_get_size (attrs);
702   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending CONSUME_TICKET_RESULT message\n");
703   env = GNUNET_MQ_msg_extra (crm,
704                              attrs_len,
705                              GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT);
706   crm->id = htonl (cop->r_id);
707   crm->attrs_len = htons (attrs_len);
708   crm->identity = *identity;
709   crm->result = htonl (success);
710   data_tmp = (char *)&crm[1];
711   GNUNET_RECLAIM_ATTRIBUTE_list_serialize (attrs, data_tmp);
712   GNUNET_MQ_send (cop->client->mq, env);
713   GNUNET_CONTAINER_DLL_remove (cop->client->consume_op_head,
714                                cop->client->consume_op_tail,
715                                cop);
716   GNUNET_free (cop);
717 }
718
719 static void
720 handle_consume_ticket_message (void *cls, const struct ConsumeTicketMessage *cm)
721 {
722   struct ConsumeTicketOperation *cop;
723   struct GNUNET_RECLAIM_Ticket *ticket;
724   struct IdpClient *idp = cls;
725
726   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received CONSUME_TICKET message\n");
727   cop = GNUNET_new (struct ConsumeTicketOperation);
728   cop->r_id = ntohl (cm->id);
729   cop->client = idp;
730   ticket = (struct GNUNET_RECLAIM_Ticket *)&cm[1];
731   cop->ch
732     = RECLAIM_TICKETS_consume (&cm->identity, ticket, &consume_result_cb, cop);
733   GNUNET_CONTAINER_DLL_insert (idp->consume_op_head, idp->consume_op_tail, cop);
734   GNUNET_SERVICE_client_continue (idp->client);
735 }
736
737 /*****************************************
738  * Attribute store
739  *****************************************/
740
741 /**
742  * Cleanup attribute store handle
743  *
744  * @param handle handle to clean up
745  */
746 static void
747 cleanup_as_handle (struct AttributeStoreHandle *ash)
748 {
749   if (NULL != ash->ns_qe)
750     GNUNET_NAMESTORE_cancel (ash->ns_qe);
751   if (NULL != ash->claim)
752     GNUNET_free (ash->claim);
753   GNUNET_free (ash);
754 }
755
756 static void
757 attr_store_cont (void *cls, int32_t success, const char *emsg)
758 {
759   struct AttributeStoreHandle *ash = cls;
760   struct GNUNET_MQ_Envelope *env;
761   struct SuccessResultMessage *acr_msg;
762
763   ash->ns_qe = NULL;
764   GNUNET_CONTAINER_DLL_remove (ash->client->store_op_head,
765                                ash->client->store_op_tail,
766                                ash);
767
768   if (GNUNET_SYSERR == success) {
769     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
770                 "Failed to store attribute %s\n",
771                 emsg);
772     cleanup_as_handle (ash);
773     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
774     return;
775   }
776
777   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending SUCCESS_RESPONSE message\n");
778   env = GNUNET_MQ_msg (acr_msg, GNUNET_MESSAGE_TYPE_RECLAIM_SUCCESS_RESPONSE);
779   acr_msg->id = htonl (ash->r_id);
780   acr_msg->op_result = htonl (GNUNET_OK);
781   GNUNET_MQ_send (ash->client->mq, env);
782   cleanup_as_handle (ash);
783 }
784
785 /**
786  * Adds a new attribute
787  *
788  * @param cls the AttributeStoreHandle
789  */
790 static void
791 attr_store_task (void *cls)
792 {
793   struct AttributeStoreHandle *ash = cls;
794   struct GNUNET_GNSRECORD_Data rd[1];
795   char *buf;
796   char *label;
797   size_t buf_size;
798
799   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Storing attribute\n");
800   buf_size = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (ash->claim);
801   buf = GNUNET_malloc (buf_size);
802   // Give the ash a new id if unset
803   if (0 == ash->claim->id)
804     ash->claim->id
805       = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
806   GNUNET_RECLAIM_ATTRIBUTE_serialize (ash->claim, buf);
807   label
808     = GNUNET_STRINGS_data_to_string_alloc (&ash->claim->id, sizeof (uint64_t));
809   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypting with label %s\n", label);
810
811   rd[0].data_size = buf_size;
812   rd[0].data = buf;
813   rd[0].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR;
814   rd[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
815   rd[0].expiration_time = ash->exp.rel_value_us;
816   ash->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
817                                                &ash->identity,
818                                                label,
819                                                1,
820                                                rd,
821                                                &attr_store_cont,
822                                                ash);
823   GNUNET_free (buf);
824 }
825
826 static int
827 check_attribute_store_message (void *cls,
828                                const struct AttributeStoreMessage *sam)
829 {
830   uint16_t size;
831
832   size = ntohs (sam->header.size);
833   if (size <= sizeof (struct AttributeStoreMessage)) {
834     GNUNET_break (0);
835     return GNUNET_SYSERR;
836   }
837   return GNUNET_OK;
838 }
839
840 static void
841 handle_attribute_store_message (void *cls,
842                                 const struct AttributeStoreMessage *sam)
843 {
844   struct AttributeStoreHandle *ash;
845   struct IdpClient *idp = cls;
846   size_t data_len;
847   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ATTRIBUTE_STORE message\n");
848
849   data_len = ntohs (sam->attr_len);
850
851   ash = GNUNET_new (struct AttributeStoreHandle);
852   ash->claim = GNUNET_RECLAIM_ATTRIBUTE_deserialize ((char *)&sam[1], data_len);
853
854   ash->r_id = ntohl (sam->id);
855   ash->identity = sam->identity;
856   ash->exp.rel_value_us = GNUNET_ntohll (sam->exp);
857   GNUNET_CRYPTO_ecdsa_key_get_public (&sam->identity, &ash->identity_pkey);
858
859   GNUNET_SERVICE_client_continue (idp->client);
860   ash->client = idp;
861   GNUNET_CONTAINER_DLL_insert (idp->store_op_head, idp->store_op_tail, ash);
862   GNUNET_SCHEDULER_add_now (&attr_store_task, ash);
863 }
864
865
866 static void
867 cleanup_adh (struct AttributeDeleteHandle *adh)
868 {
869   struct TicketRecordsEntry *le;
870   if (NULL != adh->ns_it)
871     GNUNET_NAMESTORE_zone_iteration_stop (adh->ns_it);
872   if (NULL != adh->ns_qe)
873     GNUNET_NAMESTORE_cancel (adh->ns_qe);
874   if (NULL != adh->label)
875     GNUNET_free (adh->label);
876   if (NULL != adh->claim)
877     GNUNET_free (adh->claim);
878   while (NULL != (le = adh->tickets_to_update_head)) {
879     GNUNET_CONTAINER_DLL_remove (adh->tickets_to_update_head,
880                                  adh->tickets_to_update_tail,
881                                  le);
882     if (NULL != le->label)
883       GNUNET_free (le->label);
884     if (NULL != le->data)
885       GNUNET_free (le->data);
886     GNUNET_free (le);
887   }
888   GNUNET_free (adh);
889 }
890
891
892 static void
893 send_delete_response (struct AttributeDeleteHandle *adh, int32_t success)
894 {
895   struct GNUNET_MQ_Envelope *env;
896   struct SuccessResultMessage *acr_msg;
897
898   GNUNET_CONTAINER_DLL_remove (adh->client->delete_op_head,
899                                adh->client->delete_op_tail,
900                                adh);
901
902   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending SUCCESS_RESPONSE message\n");
903   env = GNUNET_MQ_msg (acr_msg, GNUNET_MESSAGE_TYPE_RECLAIM_SUCCESS_RESPONSE);
904   acr_msg->id = htonl (adh->r_id);
905   acr_msg->op_result = htonl (success);
906   GNUNET_MQ_send (adh->client->mq, env);
907 }
908
909
910 static void
911 ticket_iter (void *cls,
912              const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
913              const char *label,
914              unsigned int rd_count,
915              const struct GNUNET_GNSRECORD_Data *rd)
916 {
917   struct AttributeDeleteHandle *adh = cls;
918   struct TicketRecordsEntry *le;
919   int has_changed = GNUNET_NO;
920
921   for (int i = 0; i < rd_count; i++) {
922     if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
923       continue;
924     if (0 != memcmp (rd[i].data, &adh->claim->id, sizeof (uint64_t)))
925       continue;
926     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
927                 "Attribute to delete found (%s)\n",
928                 adh->label);
929     has_changed = GNUNET_YES;
930     break;
931   }
932   if (GNUNET_YES == has_changed) {
933     le = GNUNET_new (struct TicketRecordsEntry);
934     le->data_size = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
935     le->data = GNUNET_malloc (le->data_size);
936     le->rd_count = rd_count;
937     le->label = GNUNET_strdup (label);
938     GNUNET_GNSRECORD_records_serialize (rd_count, rd, le->data_size, le->data);
939     GNUNET_CONTAINER_DLL_insert (adh->tickets_to_update_head,
940                                  adh->tickets_to_update_tail,
941                                  le);
942   }
943   GNUNET_NAMESTORE_zone_iterator_next (adh->ns_it, 1);
944 }
945
946
947 static void
948 update_tickets (void *cls);
949
950
951 static void
952 ticket_updated (void *cls, int32_t success, const char *emsg)
953 {
954   struct AttributeDeleteHandle *adh = cls;
955   adh->ns_qe = NULL;
956   GNUNET_SCHEDULER_add_now (&update_tickets, adh);
957 }
958
959 static void
960 update_tickets (void *cls)
961 {
962   struct AttributeDeleteHandle *adh = cls;
963   struct TicketRecordsEntry *le;
964   if (NULL == adh->tickets_to_update_head) {
965     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
966                 "Finished updatding tickets, success\n");
967     send_delete_response (adh, GNUNET_OK);
968     cleanup_adh (adh);
969     return;
970   }
971   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
972               "Updating %s\n",
973               adh->tickets_to_update_head->label);
974   le = adh->tickets_to_update_head;
975   GNUNET_CONTAINER_DLL_remove (adh->tickets_to_update_head,
976                                adh->tickets_to_update_tail,
977                                le);
978   struct GNUNET_GNSRECORD_Data rd[le->rd_count];
979   struct GNUNET_GNSRECORD_Data rd_new[le->rd_count - 1];
980   GNUNET_GNSRECORD_records_deserialize (le->data_size,
981                                         le->data,
982                                         le->rd_count,
983                                         rd);
984   int j = 0;
985   for (int i = 0; i < le->rd_count; i++) {
986     if ((GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF == rd[i].record_type)
987         && (0 == memcmp (rd[i].data, &adh->claim->id, sizeof (uint64_t))))
988       continue;
989     rd_new[j] = rd[i];
990     j++;
991   }
992   adh->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
993                                                &adh->identity,
994                                                le->label,
995                                                j,
996                                                rd_new,
997                                                &ticket_updated,
998                                                adh);
999   GNUNET_free (le->label);
1000   GNUNET_free (le->data);
1001   GNUNET_free (le);
1002 }
1003
1004
1005 static void
1006 ticket_iter_fin (void *cls)
1007 {
1008   struct AttributeDeleteHandle *adh = cls;
1009   adh->ns_it = NULL;
1010   GNUNET_SCHEDULER_add_now (&update_tickets, adh);
1011 }
1012
1013
1014 static void
1015 ticket_iter_err (void *cls)
1016 {
1017   struct AttributeDeleteHandle *adh = cls;
1018   adh->ns_it = NULL;
1019   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1020               "Namestore error on delete %s\n",
1021               adh->label);
1022   send_delete_response (adh, GNUNET_SYSERR);
1023   cleanup_adh (adh);
1024 }
1025
1026
1027 static void
1028 start_ticket_update (void *cls)
1029 {
1030   struct AttributeDeleteHandle *adh = cls;
1031   adh->ns_it = GNUNET_NAMESTORE_zone_iteration_start (nsh,
1032                                                       &adh->identity,
1033                                                       &ticket_iter_err,
1034                                                       adh,
1035                                                       &ticket_iter,
1036                                                       adh,
1037                                                       &ticket_iter_fin,
1038                                                       adh);
1039 }
1040
1041
1042 static void
1043 attr_delete_cont (void *cls, int32_t success, const char *emsg)
1044 {
1045   struct AttributeDeleteHandle *adh = cls;
1046   adh->ns_qe = NULL;
1047   if (GNUNET_SYSERR == success) {
1048     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1049                 "Error deleting attribute %s\n",
1050                 adh->label);
1051     send_delete_response (adh, GNUNET_SYSERR);
1052     cleanup_adh (adh);
1053     return;
1054   }
1055   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Updating tickets...\n");
1056   GNUNET_SCHEDULER_add_now (&start_ticket_update, adh);
1057 }
1058
1059
1060 static int
1061 check_attribute_delete_message (void *cls,
1062                                 const struct AttributeDeleteMessage *dam)
1063 {
1064   uint16_t size;
1065
1066   size = ntohs (dam->header.size);
1067   if (size <= sizeof (struct AttributeDeleteMessage)) {
1068     GNUNET_break (0);
1069     return GNUNET_SYSERR;
1070   }
1071   return GNUNET_OK;
1072 }
1073
1074
1075 static void
1076 handle_attribute_delete_message (void *cls,
1077                                  const struct AttributeDeleteMessage *dam)
1078 {
1079   struct AttributeDeleteHandle *adh;
1080   struct IdpClient *idp = cls;
1081   size_t data_len;
1082   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ATTRIBUTE_DELETE message\n");
1083
1084   data_len = ntohs (dam->attr_len);
1085
1086   adh = GNUNET_new (struct AttributeDeleteHandle);
1087   adh->claim = GNUNET_RECLAIM_ATTRIBUTE_deserialize ((char *)&dam[1], data_len);
1088
1089   adh->r_id = ntohl (dam->id);
1090   adh->identity = dam->identity;
1091   adh->label
1092     = GNUNET_STRINGS_data_to_string_alloc (&adh->claim->id, sizeof (uint64_t));
1093   GNUNET_SERVICE_client_continue (idp->client);
1094   adh->client = idp;
1095   GNUNET_CONTAINER_DLL_insert (idp->delete_op_head, idp->delete_op_tail, adh);
1096   adh->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
1097                                                &adh->identity,
1098                                                adh->label,
1099                                                0,
1100                                                NULL,
1101                                                &attr_delete_cont,
1102                                                adh);
1103 }
1104
1105
1106 /*************************************************
1107  * Attrubute iteration
1108  *************************************************/
1109
1110 static void
1111 cleanup_attribute_iter_handle (struct AttributeIterator *ai)
1112 {
1113   GNUNET_free (ai);
1114 }
1115
1116 static void
1117 attr_iter_error (void *cls)
1118 {
1119   struct AttributeIterator *ai = cls;
1120   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to iterate over attributes\n");
1121   GNUNET_CONTAINER_DLL_remove (ai->client->attr_iter_head,
1122                                ai->client->attr_iter_tail,
1123                                ai);
1124   cleanup_attribute_iter_handle (ai);
1125   GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1126 }
1127
1128 static void
1129 attr_iter_finished (void *cls)
1130 {
1131   struct AttributeIterator *ai = cls;
1132   struct GNUNET_MQ_Envelope *env;
1133   struct AttributeResultMessage *arm;
1134
1135   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending ATTRIBUTE_RESULT message\n");
1136   env = GNUNET_MQ_msg (arm, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT);
1137   arm->id = htonl (ai->request_id);
1138   arm->attr_len = htons (0);
1139   GNUNET_MQ_send (ai->client->mq, env);
1140   GNUNET_CONTAINER_DLL_remove (ai->client->attr_iter_head,
1141                                ai->client->attr_iter_tail,
1142                                ai);
1143   cleanup_attribute_iter_handle (ai);
1144 }
1145
1146 static void
1147 attr_iter_cb (void *cls,
1148               const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1149               const char *label,
1150               unsigned int rd_count,
1151               const struct GNUNET_GNSRECORD_Data *rd)
1152 {
1153   struct AttributeIterator *ai = cls;
1154   struct AttributeResultMessage *arm;
1155   struct GNUNET_MQ_Envelope *env;
1156   char *data_tmp;
1157
1158   if (rd_count != 1) {
1159     GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1);
1160     return;
1161   }
1162
1163   if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR != rd->record_type) {
1164     GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1);
1165     return;
1166   }
1167   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found attribute under: %s\n", label);
1168   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending ATTRIBUTE_RESULT message\n");
1169   env = GNUNET_MQ_msg_extra (arm,
1170                              rd->data_size,
1171                              GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT);
1172   arm->id = htonl (ai->request_id);
1173   arm->attr_len = htons (rd->data_size);
1174   GNUNET_CRYPTO_ecdsa_key_get_public (zone, &arm->identity);
1175   data_tmp = (char *)&arm[1];
1176   GNUNET_memcpy (data_tmp, rd->data, rd->data_size);
1177   GNUNET_MQ_send (ai->client->mq, env);
1178 }
1179
1180 static void
1181 handle_iteration_start (void *cls,
1182                         const struct AttributeIterationStartMessage *ais_msg)
1183 {
1184   struct IdpClient *idp = cls;
1185   struct AttributeIterator *ai;
1186
1187   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1188               "Received ATTRIBUTE_ITERATION_START message\n");
1189   ai = GNUNET_new (struct AttributeIterator);
1190   ai->request_id = ntohl (ais_msg->id);
1191   ai->client = idp;
1192   ai->identity = ais_msg->identity;
1193
1194   GNUNET_CONTAINER_DLL_insert (idp->attr_iter_head, idp->attr_iter_tail, ai);
1195   ai->ns_it = GNUNET_NAMESTORE_zone_iteration_start (nsh,
1196                                                      &ai->identity,
1197                                                      &attr_iter_error,
1198                                                      ai,
1199                                                      &attr_iter_cb,
1200                                                      ai,
1201                                                      &attr_iter_finished,
1202                                                      ai);
1203   GNUNET_SERVICE_client_continue (idp->client);
1204 }
1205
1206 static void
1207 handle_iteration_stop (void *cls,
1208                        const struct AttributeIterationStopMessage *ais_msg)
1209 {
1210   struct IdpClient *idp = cls;
1211   struct AttributeIterator *ai;
1212   uint32_t rid;
1213
1214   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1215               "Received `%s' message\n",
1216               "ATTRIBUTE_ITERATION_STOP");
1217   rid = ntohl (ais_msg->id);
1218   for (ai = idp->attr_iter_head; NULL != ai; ai = ai->next)
1219     if (ai->request_id == rid)
1220       break;
1221   if (NULL == ai) {
1222     GNUNET_break (0);
1223     GNUNET_SERVICE_client_drop (idp->client);
1224     return;
1225   }
1226   GNUNET_CONTAINER_DLL_remove (idp->attr_iter_head, idp->attr_iter_tail, ai);
1227   GNUNET_free (ai);
1228   GNUNET_SERVICE_client_continue (idp->client);
1229 }
1230
1231 static void
1232 handle_iteration_next (void *cls,
1233                        const struct AttributeIterationNextMessage *ais_msg)
1234 {
1235   struct IdpClient *idp = cls;
1236   struct AttributeIterator *ai;
1237   uint32_t rid;
1238
1239   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1240               "Received ATTRIBUTE_ITERATION_NEXT message\n");
1241   rid = ntohl (ais_msg->id);
1242   for (ai = idp->attr_iter_head; NULL != ai; ai = ai->next)
1243     if (ai->request_id == rid)
1244       break;
1245   if (NULL == ai) {
1246     GNUNET_break (0);
1247     GNUNET_SERVICE_client_drop (idp->client);
1248     return;
1249   }
1250   GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1);
1251   GNUNET_SERVICE_client_continue (idp->client);
1252 }
1253
1254 /******************************************************
1255  * Ticket iteration
1256  ******************************************************/
1257
1258 static void
1259 ticket_iter_cb (void *cls, struct GNUNET_RECLAIM_Ticket *ticket)
1260 {
1261   struct TicketIteration *ti = cls;
1262   struct GNUNET_MQ_Envelope *env;
1263   struct TicketResultMessage *trm;
1264
1265   if (NULL == ticket) {
1266     /* send empty response to indicate end of list */
1267     env = GNUNET_MQ_msg (trm, GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT);
1268     GNUNET_CONTAINER_DLL_remove (ti->client->ticket_iter_head,
1269                                  ti->client->ticket_iter_tail,
1270                                  ti);
1271   } else {
1272     env = GNUNET_MQ_msg_extra (trm,
1273                                sizeof (struct GNUNET_RECLAIM_Ticket),
1274                                GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT);
1275     memcpy (&trm[1], ticket, sizeof (struct GNUNET_RECLAIM_Ticket));
1276   }
1277   trm->id = htonl (ti->r_id);
1278   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending TICKET_RESULT message\n");
1279   GNUNET_MQ_send (ti->client->mq, env);
1280   if (NULL == ticket)
1281     GNUNET_free (ti);
1282 }
1283
1284 static void
1285 handle_ticket_iteration_start (
1286   void *cls,
1287   const struct TicketIterationStartMessage *tis_msg)
1288 {
1289   struct IdpClient *client = cls;
1290   struct TicketIteration *ti;
1291
1292   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1293               "Received TICKET_ITERATION_START message\n");
1294   ti = GNUNET_new (struct TicketIteration);
1295   ti->r_id = ntohl (tis_msg->id);
1296   ti->client = client;
1297
1298   GNUNET_CONTAINER_DLL_insert (client->ticket_iter_head,
1299                                client->ticket_iter_tail,
1300                                ti);
1301   ti->iter
1302     = RECLAIM_TICKETS_iteration_start (&tis_msg->identity, &ticket_iter_cb, ti);
1303   GNUNET_SERVICE_client_continue (client->client);
1304 }
1305
1306 static void
1307 handle_ticket_iteration_stop (void *cls,
1308                               const struct TicketIterationStopMessage *tis_msg)
1309 {
1310   struct IdpClient *client = cls;
1311   struct TicketIteration *ti;
1312   uint32_t rid;
1313
1314   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1315               "Received `%s' message\n",
1316               "TICKET_ITERATION_STOP");
1317   rid = ntohl (tis_msg->id);
1318   for (ti = client->ticket_iter_head; NULL != ti; ti = ti->next)
1319     if (ti->r_id == rid)
1320       break;
1321   if (NULL == ti) {
1322     GNUNET_break (0);
1323     GNUNET_SERVICE_client_drop (client->client);
1324     return;
1325   }
1326   RECLAIM_TICKETS_iteration_stop (ti->iter);
1327   GNUNET_CONTAINER_DLL_remove (client->ticket_iter_head,
1328                                client->ticket_iter_tail,
1329                                ti);
1330   GNUNET_free (ti);
1331   GNUNET_SERVICE_client_continue (client->client);
1332 }
1333
1334 static void
1335 handle_ticket_iteration_next (void *cls,
1336                               const struct TicketIterationNextMessage *tis_msg)
1337 {
1338   struct IdpClient *client = cls;
1339   struct TicketIteration *ti;
1340   uint32_t rid;
1341
1342   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1343               "Received TICKET_ITERATION_NEXT message\n");
1344   rid = ntohl (tis_msg->id);
1345   for (ti = client->ticket_iter_head; NULL != ti; ti = ti->next)
1346     if (ti->r_id == rid)
1347       break;
1348   if (NULL == ti) {
1349     GNUNET_break (0);
1350     GNUNET_SERVICE_client_drop (client->client);
1351     return;
1352   }
1353   RECLAIM_TICKETS_iteration_next (ti->iter);
1354   GNUNET_SERVICE_client_continue (client->client);
1355 }
1356
1357 /**
1358  * Main function that will be run
1359  *
1360  * @param cls closure
1361  * @param c the configuration used
1362  * @param server the service handle
1363  */
1364 static void
1365 run (void *cls,
1366      const struct GNUNET_CONFIGURATION_Handle *c,
1367      struct GNUNET_SERVICE_Handle *server)
1368 {
1369   cfg = c;
1370
1371   if (GNUNET_OK != RECLAIM_TICKETS_init (cfg)) {
1372     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1373                 "Unable to initialized TICKETS subsystem.\n");
1374     GNUNET_SCHEDULER_shutdown ();
1375     return;
1376   }
1377   // Connect to identity and namestore services
1378   nsh = GNUNET_NAMESTORE_connect (cfg);
1379   if (NULL == nsh) {
1380     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1381                          "error connecting to namestore");
1382   }
1383
1384   identity_handle = GNUNET_IDENTITY_connect (cfg, NULL, NULL);
1385
1386   if (GNUNET_OK
1387       == GNUNET_CONFIGURATION_get_value_time (cfg,
1388                                               "reclaim",
1389                                               "TOKEN_EXPIRATION_INTERVAL",
1390                                               &token_expiration_interval)) {
1391     GNUNET_log (
1392       GNUNET_ERROR_TYPE_DEBUG,
1393       "Time window for zone iteration: %s\n",
1394       GNUNET_STRINGS_relative_time_to_string (token_expiration_interval,
1395                                               GNUNET_YES));
1396   } else {
1397     token_expiration_interval = DEFAULT_TOKEN_EXPIRATION_INTERVAL;
1398   }
1399
1400   GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
1401 }
1402
1403 /**
1404  * Called whenever a client is disconnected.
1405  *
1406  * @param cls closure
1407  * @param client identification of the client
1408  * @param app_ctx @a client
1409  */
1410 static void
1411 client_disconnect_cb (void *cls,
1412                       struct GNUNET_SERVICE_Client *client,
1413                       void *app_ctx)
1414 {
1415   struct IdpClient *idp = app_ctx;
1416   struct AttributeIterator *ai;
1417   struct TicketIteration *ti;
1418   struct TicketRevocationOperation *rop;
1419   struct TicketIssueOperation *iss;
1420   struct ConsumeTicketOperation *ct;
1421   struct AttributeStoreHandle *as;
1422   struct AttributeDeleteHandle *adh;
1423
1424   // TODO other operations
1425
1426   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p disconnected\n", client);
1427
1428   while (NULL != (iss = idp->issue_op_head)) {
1429     GNUNET_CONTAINER_DLL_remove (idp->issue_op_head, idp->issue_op_tail, iss);
1430     GNUNET_free (iss);
1431   }
1432   while (NULL != (ct = idp->consume_op_head)) {
1433     GNUNET_CONTAINER_DLL_remove (idp->consume_op_head,
1434                                  idp->consume_op_tail,
1435                                  ct);
1436     if (NULL != ct->ch)
1437       RECLAIM_TICKETS_consume_cancel (ct->ch);
1438     GNUNET_free (ct);
1439   }
1440   while (NULL != (as = idp->store_op_head)) {
1441     GNUNET_CONTAINER_DLL_remove (idp->store_op_head, idp->store_op_tail, as);
1442     cleanup_as_handle (as);
1443   }
1444   while (NULL != (adh = idp->delete_op_head)) {
1445     GNUNET_CONTAINER_DLL_remove (idp->delete_op_head, idp->delete_op_tail, adh);
1446     cleanup_adh (adh);
1447   }
1448
1449   while (NULL != (ai = idp->attr_iter_head)) {
1450     GNUNET_CONTAINER_DLL_remove (idp->attr_iter_head, idp->attr_iter_tail, ai);
1451     cleanup_attribute_iter_handle (ai);
1452   }
1453   while (NULL != (rop = idp->revoke_op_head)) {
1454     GNUNET_CONTAINER_DLL_remove (idp->revoke_op_head, idp->revoke_op_tail, rop);
1455     if (NULL != rop->rh)
1456       RECLAIM_TICKETS_revoke_cancel (rop->rh);
1457     GNUNET_free (rop);
1458   }
1459   while (NULL != (ti = idp->ticket_iter_head)) {
1460     GNUNET_CONTAINER_DLL_remove (idp->ticket_iter_head,
1461                                  idp->ticket_iter_tail,
1462                                  ti);
1463     GNUNET_free (ti);
1464   }
1465   GNUNET_free (idp);
1466 }
1467
1468 /**
1469  * Add a client to our list of active clients.
1470  *
1471  * @param cls NULL
1472  * @param client client to add
1473  * @param mq message queue for @a client
1474  * @return internal namestore client structure for this client
1475  */
1476 static void *
1477 client_connect_cb (void *cls,
1478                    struct GNUNET_SERVICE_Client *client,
1479                    struct GNUNET_MQ_Handle *mq)
1480 {
1481   struct IdpClient *idp;
1482   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", client);
1483   idp = GNUNET_new (struct IdpClient);
1484   idp->client = client;
1485   idp->mq = mq;
1486   return idp;
1487 }
1488
1489 /**
1490  * Define "main" method using service macro.
1491  */
1492 GNUNET_SERVICE_MAIN (
1493   "reclaim",
1494   GNUNET_SERVICE_OPTION_NONE,
1495   &run,
1496   &client_connect_cb,
1497   &client_disconnect_cb,
1498   NULL,
1499   GNUNET_MQ_hd_var_size (attribute_store_message,
1500                          GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_STORE,
1501                          struct AttributeStoreMessage,
1502                          NULL),
1503   GNUNET_MQ_hd_var_size (attribute_delete_message,
1504                          GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_DELETE,
1505                          struct AttributeDeleteMessage,
1506                          NULL),
1507   GNUNET_MQ_hd_fixed_size (
1508     iteration_start,
1509     GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_START,
1510     struct AttributeIterationStartMessage,
1511     NULL),
1512   GNUNET_MQ_hd_fixed_size (iteration_next,
1513                            GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_NEXT,
1514                            struct AttributeIterationNextMessage,
1515                            NULL),
1516   GNUNET_MQ_hd_fixed_size (iteration_stop,
1517                            GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_STOP,
1518                            struct AttributeIterationStopMessage,
1519                            NULL),
1520   GNUNET_MQ_hd_var_size (issue_ticket_message,
1521                          GNUNET_MESSAGE_TYPE_RECLAIM_ISSUE_TICKET,
1522                          struct IssueTicketMessage,
1523                          NULL),
1524   GNUNET_MQ_hd_var_size (consume_ticket_message,
1525                          GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET,
1526                          struct ConsumeTicketMessage,
1527                          NULL),
1528   GNUNET_MQ_hd_fixed_size (ticket_iteration_start,
1529                            GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_START,
1530                            struct TicketIterationStartMessage,
1531                            NULL),
1532   GNUNET_MQ_hd_fixed_size (ticket_iteration_next,
1533                            GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_NEXT,
1534                            struct TicketIterationNextMessage,
1535                            NULL),
1536   GNUNET_MQ_hd_fixed_size (ticket_iteration_stop,
1537                            GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_STOP,
1538                            struct TicketIterationStopMessage,
1539                            NULL),
1540   GNUNET_MQ_hd_var_size (revoke_ticket_message,
1541                          GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET,
1542                          struct RevokeTicketMessage,
1543                          NULL),
1544   GNUNET_MQ_handler_end ());
1545 /* end of gnunet-service-reclaim.c */