RECLAIM/REST: add attribute delete REST call
[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, uint32_t r_id,
535                     const struct GNUNET_RECLAIM_Ticket *ticket,
536                     uint32_t success)
537 {
538   struct TicketResultMessage *irm;
539   struct GNUNET_MQ_Envelope *env;
540   struct GNUNET_RECLAIM_Ticket *ticket_buf;
541
542   if (NULL != ticket) {
543     env = GNUNET_MQ_msg_extra (irm, sizeof (struct GNUNET_RECLAIM_Ticket),
544                                GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT);
545     ticket_buf = (struct GNUNET_RECLAIM_Ticket *)&irm[1];
546     *ticket_buf = *ticket;
547   } else {
548     env = GNUNET_MQ_msg (irm, GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT);
549   }
550   // TODO add success member
551   irm->id = htonl (r_id);
552   GNUNET_MQ_send (client->mq, env);
553 }
554
555 static void
556 issue_ticket_result_cb (void *cls, struct GNUNET_RECLAIM_Ticket *ticket,
557                         int32_t success, const char *emsg)
558 {
559   struct TicketIssueOperation *tio = cls;
560   if (GNUNET_OK != success) {
561     send_ticket_result (tio->client, tio->r_id, NULL, GNUNET_SYSERR);
562     GNUNET_CONTAINER_DLL_remove (tio->client->issue_op_head,
563                                  tio->client->issue_op_tail, tio);
564     GNUNET_free (tio);
565     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error issuing ticket: %s\n", emsg);
566     return;
567   }
568   send_ticket_result (tio->client, tio->r_id, ticket, GNUNET_SYSERR);
569   GNUNET_CONTAINER_DLL_remove (tio->client->issue_op_head,
570                                tio->client->issue_op_tail, tio);
571   GNUNET_free (tio);
572 }
573
574 static int
575 check_issue_ticket_message (void *cls, const struct IssueTicketMessage *im)
576 {
577   uint16_t size;
578
579   size = ntohs (im->header.size);
580   if (size <= sizeof (struct IssueTicketMessage)) {
581     GNUNET_break (0);
582     return GNUNET_SYSERR;
583   }
584   return GNUNET_OK;
585 }
586
587 static void
588 handle_issue_ticket_message (void *cls, const struct IssueTicketMessage *im)
589 {
590   struct TicketIssueOperation *tio;
591   struct IdpClient *idp = cls;
592   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs;
593   size_t attrs_len;
594
595   tio = GNUNET_new (struct TicketIssueOperation);
596   attrs_len = ntohs (im->attr_len);
597   attrs = GNUNET_RECLAIM_ATTRIBUTE_list_deserialize ((char *)&im[1], attrs_len);
598   tio->r_id = ntohl (im->id);
599   tio->client = idp;
600   GNUNET_CONTAINER_DLL_insert (idp->issue_op_head, idp->issue_op_tail, tio);
601   RECLAIM_TICKETS_issue (&im->identity, attrs, &im->rp, &issue_ticket_result_cb,
602                          tio);
603   GNUNET_SERVICE_client_continue (idp->client);
604   GNUNET_RECLAIM_ATTRIBUTE_list_destroy (attrs);
605 }
606
607 /**********************************************************
608  * Revocation
609  **********************************************************/
610
611 static void
612 revoke_result_cb (void *cls, int32_t success)
613 {
614   struct TicketRevocationOperation *rop = cls;
615   struct GNUNET_MQ_Envelope *env;
616   struct RevokeTicketResultMessage *trm;
617
618   rop->rh = NULL;
619   env = GNUNET_MQ_msg (trm, GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET_RESULT);
620   trm->id = htonl (rop->r_id);
621   trm->success = htonl (success);
622   GNUNET_MQ_send (rop->client->mq, env);
623   GNUNET_CONTAINER_DLL_remove (rop->client->revoke_op_head,
624                                rop->client->revoke_op_tail, rop);
625   GNUNET_free (rop);
626 }
627
628
629 static int
630 check_revoke_ticket_message (void *cls, const struct RevokeTicketMessage *im)
631 {
632   uint16_t size;
633
634   size = ntohs (im->header.size);
635   if (size <= sizeof (struct RevokeTicketMessage)) {
636     GNUNET_break (0);
637     return GNUNET_SYSERR;
638   }
639   return GNUNET_OK;
640 }
641
642 static void
643 handle_revoke_ticket_message (void *cls, const struct RevokeTicketMessage *rm)
644 {
645   struct TicketRevocationOperation *rop;
646   struct IdpClient *idp = cls;
647   struct GNUNET_RECLAIM_Ticket *ticket;
648
649   rop = GNUNET_new (struct TicketRevocationOperation);
650   ticket = (struct GNUNET_RECLAIM_Ticket *)&rm[1];
651   rop->r_id = ntohl (rm->id);
652   rop->client = idp;
653   GNUNET_CONTAINER_DLL_insert (idp->revoke_op_head, idp->revoke_op_tail, rop);
654   rop->rh =
655       RECLAIM_TICKETS_revoke (ticket, &rm->identity, &revoke_result_cb, rop);
656   GNUNET_SERVICE_client_continue (idp->client);
657 }
658
659 static int
660 check_consume_ticket_message (void *cls, const struct ConsumeTicketMessage *cm)
661 {
662   uint16_t size;
663
664   size = ntohs (cm->header.size);
665   if (size <= sizeof (struct ConsumeTicketMessage)) {
666     GNUNET_break (0);
667     return GNUNET_SYSERR;
668   }
669   return GNUNET_OK;
670 }
671
672 static void
673 consume_result_cb (void *cls,
674                    const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
675                    const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
676                    int32_t success, const char *emsg)
677 {
678   struct ConsumeTicketOperation *cop = cls;
679   struct ConsumeTicketResultMessage *crm;
680   struct GNUNET_MQ_Envelope *env;
681   char *data_tmp;
682   size_t attrs_len;
683   if (GNUNET_OK != success) {
684     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error consuming ticket: %s\n", emsg);
685   }
686   attrs_len = GNUNET_RECLAIM_ATTRIBUTE_list_serialize_get_size (attrs);
687   env = GNUNET_MQ_msg_extra (crm, attrs_len,
688                              GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT);
689   crm->id = htonl (cop->r_id);
690   crm->attrs_len = htons (attrs_len);
691   crm->identity = *identity;
692   crm->result = htonl (success);
693   data_tmp = (char *)&crm[1];
694   GNUNET_RECLAIM_ATTRIBUTE_list_serialize (attrs, data_tmp);
695   GNUNET_MQ_send (cop->client->mq, env);
696   GNUNET_CONTAINER_DLL_remove (cop->client->consume_op_head,
697                                cop->client->consume_op_tail, cop);
698   GNUNET_free (cop);
699 }
700
701 static void
702 handle_consume_ticket_message (void *cls, const struct ConsumeTicketMessage *cm)
703 {
704   struct ConsumeTicketOperation *cop;
705   struct GNUNET_RECLAIM_Ticket *ticket;
706   struct IdpClient *idp = cls;
707
708   cop = GNUNET_new (struct ConsumeTicketOperation);
709   cop->r_id = ntohl (cm->id);
710   cop->client = idp;
711   ticket = (struct GNUNET_RECLAIM_Ticket *)&cm[1];
712   cop->ch =
713       RECLAIM_TICKETS_consume (&cm->identity, ticket, &consume_result_cb, cop);
714   GNUNET_CONTAINER_DLL_insert (idp->consume_op_head, idp->consume_op_tail, cop);
715   GNUNET_SERVICE_client_continue (idp->client);
716 }
717
718 /*****************************************
719  * Attribute store
720  *****************************************/
721
722 /**
723  * Cleanup attribute store handle
724  *
725  * @param handle handle to clean up
726  */
727 static void
728 cleanup_as_handle (struct AttributeStoreHandle *ash)
729 {
730   if (NULL != ash->ns_qe)
731     GNUNET_NAMESTORE_cancel (ash->ns_qe);
732   if (NULL != ash->claim)
733     GNUNET_free (ash->claim);
734   GNUNET_free (ash);
735 }
736
737 static void
738 attr_store_cont (void *cls, int32_t success, const char *emsg)
739 {
740   struct AttributeStoreHandle *ash = cls;
741   struct GNUNET_MQ_Envelope *env;
742   struct SuccessResultMessage *acr_msg;
743
744   ash->ns_qe = NULL;
745   GNUNET_CONTAINER_DLL_remove (ash->client->store_op_head,
746                                ash->client->store_op_tail, ash);
747
748   if (GNUNET_SYSERR == success) {
749     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to store attribute %s\n",
750                 emsg);
751     cleanup_as_handle (ash);
752     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
753     return;
754   }
755
756   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending SUCCESS_RESPONSE message\n");
757   env = GNUNET_MQ_msg (acr_msg, GNUNET_MESSAGE_TYPE_RECLAIM_SUCCESS_RESPONSE);
758   acr_msg->id = htonl (ash->r_id);
759   acr_msg->op_result = htonl (GNUNET_OK);
760   GNUNET_MQ_send (ash->client->mq, env);
761   cleanup_as_handle (ash);
762 }
763
764 /**
765  * Adds a new attribute
766  *
767  * @param cls the AttributeStoreHandle
768  */
769 static void
770 attr_store_task (void *cls)
771 {
772   struct AttributeStoreHandle *ash = cls;
773   struct GNUNET_GNSRECORD_Data rd[1];
774   char *buf;
775   char *label;
776   size_t buf_size;
777
778   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Storing attribute\n");
779   buf_size = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (ash->claim);
780   buf = GNUNET_malloc (buf_size);
781   // Give the ash a new id
782   ash->claim->id =
783       GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
784   GNUNET_RECLAIM_ATTRIBUTE_serialize (ash->claim, buf);
785   label =
786       GNUNET_STRINGS_data_to_string_alloc (&ash->claim->id, sizeof (uint64_t));
787   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypting with label %s\n", label);
788
789   rd[0].data_size = buf_size;
790   rd[0].data = buf;
791   rd[0].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR;
792   rd[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
793   rd[0].expiration_time = ash->exp.rel_value_us;
794   ash->ns_qe = GNUNET_NAMESTORE_records_store (nsh, &ash->identity, label, 1,
795                                                rd, &attr_store_cont, ash);
796   GNUNET_free (buf);
797 }
798
799 static int
800 check_attribute_store_message (void *cls,
801                                const struct AttributeStoreMessage *sam)
802 {
803   uint16_t size;
804
805   size = ntohs (sam->header.size);
806   if (size <= sizeof (struct AttributeStoreMessage)) {
807     GNUNET_break (0);
808     return GNUNET_SYSERR;
809   }
810   return GNUNET_OK;
811 }
812
813 static void
814 handle_attribute_store_message (void *cls,
815                                 const struct AttributeStoreMessage *sam)
816 {
817   struct AttributeStoreHandle *ash;
818   struct IdpClient *idp = cls;
819   size_t data_len;
820   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ATTRIBUTE_STORE message\n");
821
822   data_len = ntohs (sam->attr_len);
823
824   ash = GNUNET_new (struct AttributeStoreHandle);
825   ash->claim = GNUNET_RECLAIM_ATTRIBUTE_deserialize ((char *)&sam[1], data_len);
826
827   ash->r_id = ntohl (sam->id);
828   ash->identity = sam->identity;
829   ash->exp.rel_value_us = GNUNET_ntohll (sam->exp);
830   GNUNET_CRYPTO_ecdsa_key_get_public (&sam->identity, &ash->identity_pkey);
831
832   GNUNET_SERVICE_client_continue (idp->client);
833   ash->client = idp;
834   GNUNET_CONTAINER_DLL_insert (idp->store_op_head, idp->store_op_tail, ash);
835   GNUNET_SCHEDULER_add_now (&attr_store_task, ash);
836 }
837
838
839 static void
840 cleanup_adh (struct AttributeDeleteHandle *adh)
841 {
842   struct TicketRecordsEntry *le;
843   if (NULL != adh->ns_it)
844     GNUNET_NAMESTORE_zone_iteration_stop (adh->ns_it);
845   if (NULL != adh->ns_qe)
846     GNUNET_NAMESTORE_cancel (adh->ns_qe);
847   if (NULL != adh->label)
848     GNUNET_free (adh->label);
849   if (NULL != adh->claim)
850     GNUNET_free (adh->claim);
851   while (NULL != (le = adh->tickets_to_update_head)) {
852     GNUNET_CONTAINER_DLL_remove (adh->tickets_to_update_head,
853                                  adh->tickets_to_update_tail, le);
854     if (NULL != le->label)
855       GNUNET_free (le->label);
856     if (NULL != le->data)
857       GNUNET_free (le->data);
858     GNUNET_free (le);
859   }
860   GNUNET_free (adh);
861 }
862
863
864 static void
865 send_delete_response (struct AttributeDeleteHandle *adh, int32_t success)
866 {
867   struct GNUNET_MQ_Envelope *env;
868   struct SuccessResultMessage *acr_msg;
869
870   GNUNET_CONTAINER_DLL_remove (adh->client->delete_op_head,
871                                adh->client->delete_op_tail, adh);
872
873   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending SUCCESS_RESPONSE message\n");
874   env = GNUNET_MQ_msg (acr_msg, GNUNET_MESSAGE_TYPE_RECLAIM_SUCCESS_RESPONSE);
875   acr_msg->id = htonl (adh->r_id);
876   acr_msg->op_result = htonl (success);
877   GNUNET_MQ_send (adh->client->mq, env);
878 }
879
880
881 static void
882 ticket_iter (void *cls, const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
883              const char *label, unsigned int rd_count,
884              const struct GNUNET_GNSRECORD_Data *rd)
885 {
886   struct AttributeDeleteHandle *adh = cls;
887   struct TicketRecordsEntry *le;
888   int has_changed = GNUNET_NO;
889
890   for (int i = 0; i < rd_count; i++) {
891     if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
892       continue;
893     if (0 != memcmp (rd[i].data, &adh->claim->id, sizeof (uint64_t)))
894       continue;
895     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Attribute to delete found (%s)\n",
896                 adh->label);
897     has_changed = GNUNET_YES;
898     break;
899   }
900   if (GNUNET_YES == has_changed) {
901     le = GNUNET_new (struct TicketRecordsEntry);
902     le->data_size = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
903     le->data = GNUNET_malloc (le->data_size);
904     le->rd_count = rd_count;
905     le->label = GNUNET_strdup (label);
906     GNUNET_GNSRECORD_records_serialize (rd_count, rd, le->data_size, le->data);
907     GNUNET_CONTAINER_DLL_insert (adh->tickets_to_update_head,
908                                  adh->tickets_to_update_tail, le);
909   }
910   GNUNET_NAMESTORE_zone_iterator_next (adh->ns_it, 1);
911 }
912
913
914 static void
915 update_tickets (void *cls);
916
917
918 static void
919 ticket_updated (void *cls, int32_t success, const char *emsg)
920 {
921   struct AttributeDeleteHandle *adh = cls;
922   adh->ns_qe = NULL;
923   GNUNET_SCHEDULER_add_now (&update_tickets, adh);
924 }
925
926 static void
927 update_tickets (void *cls)
928 {
929   struct AttributeDeleteHandle *adh = cls;
930   struct TicketRecordsEntry *le;
931   if (NULL == adh->tickets_to_update_head) {
932     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
933                 "Finished updatding tickets, success\n");
934     send_delete_response (adh, GNUNET_OK);
935     cleanup_adh (adh);
936     return;
937   }
938   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Updating %s\n",
939               adh->tickets_to_update_head->label);
940   le = adh->tickets_to_update_head;
941   GNUNET_CONTAINER_DLL_remove (adh->tickets_to_update_head,
942                                adh->tickets_to_update_tail, le);
943   struct GNUNET_GNSRECORD_Data rd[le->rd_count];
944   struct GNUNET_GNSRECORD_Data rd_new[le->rd_count - 1];
945   GNUNET_GNSRECORD_records_deserialize (le->data_size, le->data, le->rd_count,
946                                         rd);
947   int j = 0;
948   for (int i = 0; i < le->rd_count; i++) {
949     if ((GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF == rd[i].record_type) &&
950         (0 == memcmp (rd[i].data, &adh->claim->id, sizeof (uint64_t))))
951       continue;
952     rd_new[j] = rd[i];
953     j++;
954   }
955   adh->ns_qe = GNUNET_NAMESTORE_records_store (nsh, &adh->identity, le->label,
956                                                j, rd_new, &ticket_updated, adh);
957   GNUNET_free (le->label);
958   GNUNET_free (le->data);
959   GNUNET_free (le);
960 }
961
962
963 static void
964 ticket_iter_fin (void *cls)
965 {
966   struct AttributeDeleteHandle *adh = cls;
967   adh->ns_it = NULL;
968   GNUNET_SCHEDULER_add_now (&update_tickets, adh);
969 }
970
971
972 static void
973 ticket_iter_err (void *cls)
974 {
975   struct AttributeDeleteHandle *adh = cls;
976   adh->ns_it = NULL;
977   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Namestore error on delete %s\n",
978               adh->label);
979   send_delete_response (adh, GNUNET_SYSERR);
980   cleanup_adh (adh);
981 }
982
983
984 static void
985 start_ticket_update (void *cls)
986 {
987   struct AttributeDeleteHandle *adh = cls;
988   adh->ns_it = GNUNET_NAMESTORE_zone_iteration_start (
989       nsh, &adh->identity, &ticket_iter_err, adh, &ticket_iter, adh,
990       &ticket_iter_fin, adh);
991 }
992
993
994 static void
995 attr_delete_cont (void *cls, int32_t success, const char *emsg)
996 {
997   struct AttributeDeleteHandle *adh = cls;
998   adh->ns_qe = NULL;
999   if (GNUNET_SYSERR == success) {
1000     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error deleting attribute %s\n",
1001                 adh->label);
1002     send_delete_response (adh, GNUNET_SYSERR);
1003     cleanup_adh (adh);
1004     return;
1005   }
1006   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Updating tickets...\n");
1007   GNUNET_SCHEDULER_add_now (&start_ticket_update, adh);
1008 }
1009
1010
1011 static int
1012 check_attribute_delete_message (void *cls,
1013                                 const struct AttributeDeleteMessage *dam)
1014 {
1015   uint16_t size;
1016
1017   size = ntohs (dam->header.size);
1018   if (size <= sizeof (struct AttributeDeleteMessage)) {
1019     GNUNET_break (0);
1020     return GNUNET_SYSERR;
1021   }
1022   return GNUNET_OK;
1023 }
1024
1025
1026 static void
1027 handle_attribute_delete_message (void *cls,
1028                                  const struct AttributeDeleteMessage *dam)
1029 {
1030   struct AttributeDeleteHandle *adh;
1031   struct IdpClient *idp = cls;
1032   size_t data_len;
1033   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Received ATTRIBUTE_DELETE message\n");
1034
1035   data_len = ntohs (dam->attr_len);
1036
1037   adh = GNUNET_new (struct AttributeDeleteHandle);
1038   adh->claim = GNUNET_RECLAIM_ATTRIBUTE_deserialize ((char *)&dam[1], data_len);
1039
1040   adh->r_id = ntohl (dam->id);
1041   adh->identity = dam->identity;
1042   adh->label =
1043       GNUNET_STRINGS_data_to_string_alloc (&adh->claim->id, sizeof (uint64_t));
1044   GNUNET_SERVICE_client_continue (idp->client);
1045   adh->client = idp;
1046   GNUNET_CONTAINER_DLL_insert (idp->delete_op_head, idp->delete_op_tail, adh);
1047   adh->ns_qe = GNUNET_NAMESTORE_records_store (nsh, &adh->identity, adh->label,
1048                                                0, NULL, &attr_delete_cont, adh);
1049 }
1050
1051
1052 /*************************************************
1053  * Attrubute iteration
1054  *************************************************/
1055
1056 static void
1057 cleanup_attribute_iter_handle (struct AttributeIterator *ai)
1058 {
1059   GNUNET_free (ai);
1060 }
1061
1062 static void
1063 attr_iter_error (void *cls)
1064 {
1065   struct AttributeIterator *ai = cls;
1066   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to iterate over attributes\n");
1067   GNUNET_CONTAINER_DLL_remove (ai->client->attr_iter_head,
1068                                ai->client->attr_iter_tail, ai);
1069   cleanup_attribute_iter_handle (ai);
1070   GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1071 }
1072
1073 static void
1074 attr_iter_finished (void *cls)
1075 {
1076   struct AttributeIterator *ai = cls;
1077   struct GNUNET_MQ_Envelope *env;
1078   struct AttributeResultMessage *arm;
1079
1080   env = GNUNET_MQ_msg (arm, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT);
1081   arm->id = htonl (ai->request_id);
1082   arm->attr_len = htons (0);
1083   GNUNET_MQ_send (ai->client->mq, env);
1084   GNUNET_CONTAINER_DLL_remove (ai->client->attr_iter_head,
1085                                ai->client->attr_iter_tail, ai);
1086   cleanup_attribute_iter_handle (ai);
1087 }
1088
1089 static void
1090 attr_iter_cb (void *cls, const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1091               const char *label, unsigned int rd_count,
1092               const struct GNUNET_GNSRECORD_Data *rd)
1093 {
1094   struct AttributeIterator *ai = cls;
1095   struct AttributeResultMessage *arm;
1096   struct GNUNET_MQ_Envelope *env;
1097   char *data_tmp;
1098
1099   if (rd_count != 1) {
1100     GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1);
1101     return;
1102   }
1103
1104   if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR != rd->record_type) {
1105     GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1);
1106     return;
1107   }
1108   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found attribute under: %s\n", label);
1109   env = GNUNET_MQ_msg_extra (arm, rd->data_size,
1110                              GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT);
1111   arm->id = htonl (ai->request_id);
1112   arm->attr_len = htons (rd->data_size);
1113   GNUNET_CRYPTO_ecdsa_key_get_public (zone, &arm->identity);
1114   data_tmp = (char *)&arm[1];
1115   GNUNET_memcpy (data_tmp, rd->data, rd->data_size);
1116   GNUNET_MQ_send (ai->client->mq, env);
1117 }
1118
1119 static void
1120 handle_iteration_start (void *cls,
1121                         const struct AttributeIterationStartMessage *ais_msg)
1122 {
1123   struct IdpClient *idp = cls;
1124   struct AttributeIterator *ai;
1125
1126   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1127               "Received ATTRIBUTE_ITERATION_START message\n");
1128   ai = GNUNET_new (struct AttributeIterator);
1129   ai->request_id = ntohl (ais_msg->id);
1130   ai->client = idp;
1131   ai->identity = ais_msg->identity;
1132
1133   GNUNET_CONTAINER_DLL_insert (idp->attr_iter_head, idp->attr_iter_tail, ai);
1134   ai->ns_it = GNUNET_NAMESTORE_zone_iteration_start (
1135       nsh, &ai->identity, &attr_iter_error, ai, &attr_iter_cb, ai,
1136       &attr_iter_finished, ai);
1137   GNUNET_SERVICE_client_continue (idp->client);
1138 }
1139
1140 static void
1141 handle_iteration_stop (void *cls,
1142                        const struct AttributeIterationStopMessage *ais_msg)
1143 {
1144   struct IdpClient *idp = cls;
1145   struct AttributeIterator *ai;
1146   uint32_t rid;
1147
1148   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n",
1149               "ATTRIBUTE_ITERATION_STOP");
1150   rid = ntohl (ais_msg->id);
1151   for (ai = idp->attr_iter_head; NULL != ai; ai = ai->next)
1152     if (ai->request_id == rid)
1153       break;
1154   if (NULL == ai) {
1155     GNUNET_break (0);
1156     GNUNET_SERVICE_client_drop (idp->client);
1157     return;
1158   }
1159   GNUNET_CONTAINER_DLL_remove (idp->attr_iter_head, idp->attr_iter_tail, ai);
1160   GNUNET_free (ai);
1161   GNUNET_SERVICE_client_continue (idp->client);
1162 }
1163
1164 static void
1165 handle_iteration_next (void *cls,
1166                        const struct AttributeIterationNextMessage *ais_msg)
1167 {
1168   struct IdpClient *idp = cls;
1169   struct AttributeIterator *ai;
1170   uint32_t rid;
1171
1172   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1173               "Received ATTRIBUTE_ITERATION_NEXT message\n");
1174   rid = ntohl (ais_msg->id);
1175   for (ai = idp->attr_iter_head; NULL != ai; ai = ai->next)
1176     if (ai->request_id == rid)
1177       break;
1178   if (NULL == ai) {
1179     GNUNET_break (0);
1180     GNUNET_SERVICE_client_drop (idp->client);
1181     return;
1182   }
1183   GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1);
1184   GNUNET_SERVICE_client_continue (idp->client);
1185 }
1186
1187 /******************************************************
1188  * Ticket iteration
1189  ******************************************************/
1190
1191 static void
1192 ticket_iter_cb (void *cls, struct GNUNET_RECLAIM_Ticket *ticket)
1193 {
1194   struct TicketIteration *ti = cls;
1195   struct GNUNET_MQ_Envelope *env;
1196   struct TicketResultMessage *trm;
1197
1198   if (NULL == ticket) {
1199     /* send empty response to indicate end of list */
1200     env = GNUNET_MQ_msg (trm, GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT);
1201     GNUNET_CONTAINER_DLL_remove (ti->client->ticket_iter_head,
1202                                  ti->client->ticket_iter_tail, ti);
1203   } else {
1204     env = GNUNET_MQ_msg_extra (trm, sizeof (struct GNUNET_RECLAIM_Ticket),
1205                                GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT);
1206     memcpy (&trm[1], ticket, sizeof (struct GNUNET_RECLAIM_Ticket));
1207   }
1208   trm->id = htonl (ti->r_id);
1209   GNUNET_MQ_send (ti->client->mq, env);
1210   if (NULL == ticket)
1211     GNUNET_free (ti);
1212 }
1213
1214 static void
1215 handle_ticket_iteration_start (
1216     void *cls, const struct TicketIterationStartMessage *tis_msg)
1217 {
1218   struct IdpClient *client = cls;
1219   struct TicketIteration *ti;
1220
1221   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1222               "Received TICKET_ITERATION_START message\n");
1223   ti = GNUNET_new (struct TicketIteration);
1224   ti->r_id = ntohl (tis_msg->id);
1225   ti->client = client;
1226
1227   GNUNET_CONTAINER_DLL_insert (client->ticket_iter_head,
1228                                client->ticket_iter_tail, ti);
1229   ti->iter =
1230       RECLAIM_TICKETS_iteration_start (&tis_msg->identity, &ticket_iter_cb, ti);
1231   GNUNET_SERVICE_client_continue (client->client);
1232 }
1233
1234 static void
1235 handle_ticket_iteration_stop (void *cls,
1236                               const struct TicketIterationStopMessage *tis_msg)
1237 {
1238   struct IdpClient *client = cls;
1239   struct TicketIteration *ti;
1240   uint32_t rid;
1241
1242   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n",
1243               "TICKET_ITERATION_STOP");
1244   rid = ntohl (tis_msg->id);
1245   for (ti = client->ticket_iter_head; NULL != ti; ti = ti->next)
1246     if (ti->r_id == rid)
1247       break;
1248   if (NULL == ti) {
1249     GNUNET_break (0);
1250     GNUNET_SERVICE_client_drop (client->client);
1251     return;
1252   }
1253   RECLAIM_TICKETS_iteration_stop (ti->iter);
1254   GNUNET_CONTAINER_DLL_remove (client->ticket_iter_head,
1255                                client->ticket_iter_tail, ti);
1256   GNUNET_free (ti);
1257   GNUNET_SERVICE_client_continue (client->client);
1258 }
1259
1260 static void
1261 handle_ticket_iteration_next (void *cls,
1262                               const struct TicketIterationNextMessage *tis_msg)
1263 {
1264   struct IdpClient *client = cls;
1265   struct TicketIteration *ti;
1266   uint32_t rid;
1267
1268   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1269               "Received TICKET_ITERATION_NEXT message\n");
1270   rid = ntohl (tis_msg->id);
1271   for (ti = client->ticket_iter_head; NULL != ti; ti = ti->next)
1272     if (ti->r_id == rid)
1273       break;
1274   if (NULL == ti) {
1275     GNUNET_break (0);
1276     GNUNET_SERVICE_client_drop (client->client);
1277     return;
1278   }
1279   RECLAIM_TICKETS_iteration_next (ti->iter);
1280   GNUNET_SERVICE_client_continue (client->client);
1281 }
1282
1283 /**
1284  * Main function that will be run
1285  *
1286  * @param cls closure
1287  * @param c the configuration used
1288  * @param server the service handle
1289  */
1290 static void
1291 run (void *cls, const struct GNUNET_CONFIGURATION_Handle *c,
1292      struct GNUNET_SERVICE_Handle *server)
1293 {
1294   cfg = c;
1295
1296   if (GNUNET_OK != RECLAIM_TICKETS_init (cfg)) {
1297     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1298                 "Unable to initialized TICKETS subsystem.\n");
1299     GNUNET_SCHEDULER_shutdown ();
1300     return;
1301   }
1302   // Connect to identity and namestore services
1303   nsh = GNUNET_NAMESTORE_connect (cfg);
1304   if (NULL == nsh) {
1305     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1306                          "error connecting to namestore");
1307   }
1308
1309   identity_handle = GNUNET_IDENTITY_connect (cfg, NULL, NULL);
1310
1311   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_time (
1312                        cfg, "reclaim", "TOKEN_EXPIRATION_INTERVAL",
1313                        &token_expiration_interval)) {
1314     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Time window for zone iteration: %s\n",
1315                 GNUNET_STRINGS_relative_time_to_string (
1316                     token_expiration_interval, GNUNET_YES));
1317   } else {
1318     token_expiration_interval = DEFAULT_TOKEN_EXPIRATION_INTERVAL;
1319   }
1320
1321   GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
1322 }
1323
1324 /**
1325  * Called whenever a client is disconnected.
1326  *
1327  * @param cls closure
1328  * @param client identification of the client
1329  * @param app_ctx @a client
1330  */
1331 static void
1332 client_disconnect_cb (void *cls, struct GNUNET_SERVICE_Client *client,
1333                       void *app_ctx)
1334 {
1335   struct IdpClient *idp = app_ctx;
1336   struct AttributeIterator *ai;
1337   struct TicketIteration *ti;
1338   struct TicketRevocationOperation *rop;
1339   struct TicketIssueOperation *iss;
1340   struct ConsumeTicketOperation *ct;
1341   struct AttributeStoreHandle *as;
1342   struct AttributeDeleteHandle *adh;
1343
1344   // TODO other operations
1345
1346   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p disconnected\n", client);
1347
1348   while (NULL != (iss = idp->issue_op_head)) {
1349     GNUNET_CONTAINER_DLL_remove (idp->issue_op_head, idp->issue_op_tail, iss);
1350     GNUNET_free (iss);
1351   }
1352   while (NULL != (ct = idp->consume_op_head)) {
1353     GNUNET_CONTAINER_DLL_remove (idp->consume_op_head, idp->consume_op_tail,
1354                                  ct);
1355     if (NULL != ct->ch)
1356       RECLAIM_TICKETS_consume_cancel (ct->ch);
1357     GNUNET_free (ct);
1358   }
1359   while (NULL != (as = idp->store_op_head)) {
1360     GNUNET_CONTAINER_DLL_remove (idp->store_op_head, idp->store_op_tail, as);
1361     cleanup_as_handle (as);
1362   }
1363   while (NULL != (adh = idp->delete_op_head)) {
1364     GNUNET_CONTAINER_DLL_remove (idp->delete_op_head, idp->delete_op_tail, adh);
1365     cleanup_adh (adh);
1366   }
1367
1368   while (NULL != (ai = idp->attr_iter_head)) {
1369     GNUNET_CONTAINER_DLL_remove (idp->attr_iter_head, idp->attr_iter_tail, ai);
1370     cleanup_attribute_iter_handle (ai);
1371   }
1372   while (NULL != (rop = idp->revoke_op_head)) {
1373     GNUNET_CONTAINER_DLL_remove (idp->revoke_op_head, idp->revoke_op_tail, rop);
1374     if (NULL != rop->rh)
1375       RECLAIM_TICKETS_revoke_cancel (rop->rh);
1376     GNUNET_free (rop);
1377   }
1378   while (NULL != (ti = idp->ticket_iter_head)) {
1379     GNUNET_CONTAINER_DLL_remove (idp->ticket_iter_head, idp->ticket_iter_tail,
1380                                  ti);
1381     GNUNET_free (ti);
1382   }
1383   GNUNET_free (idp);
1384 }
1385
1386 /**
1387  * Add a client to our list of active clients.
1388  *
1389  * @param cls NULL
1390  * @param client client to add
1391  * @param mq message queue for @a client
1392  * @return internal namestore client structure for this client
1393  */
1394 static void *
1395 client_connect_cb (void *cls, struct GNUNET_SERVICE_Client *client,
1396                    struct GNUNET_MQ_Handle *mq)
1397 {
1398   struct IdpClient *idp;
1399   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", client);
1400   idp = GNUNET_new (struct IdpClient);
1401   idp->client = client;
1402   idp->mq = mq;
1403   return idp;
1404 }
1405
1406 /**
1407  * Define "main" method using service macro.
1408  */
1409 GNUNET_SERVICE_MAIN (
1410     "reclaim", GNUNET_SERVICE_OPTION_NONE, &run, &client_connect_cb,
1411     &client_disconnect_cb, NULL,
1412     GNUNET_MQ_hd_var_size (attribute_store_message,
1413                            GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_STORE,
1414                            struct AttributeStoreMessage, NULL),
1415     GNUNET_MQ_hd_var_size (attribute_delete_message,
1416                            GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_DELETE,
1417                            struct AttributeDeleteMessage, NULL),
1418     GNUNET_MQ_hd_fixed_size (
1419         iteration_start, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_START,
1420         struct AttributeIterationStartMessage, NULL),
1421     GNUNET_MQ_hd_fixed_size (
1422         iteration_next, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_NEXT,
1423         struct AttributeIterationNextMessage, NULL),
1424     GNUNET_MQ_hd_fixed_size (
1425         iteration_stop, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_STOP,
1426         struct AttributeIterationStopMessage, NULL),
1427     GNUNET_MQ_hd_var_size (issue_ticket_message,
1428                            GNUNET_MESSAGE_TYPE_RECLAIM_ISSUE_TICKET,
1429                            struct IssueTicketMessage, NULL),
1430     GNUNET_MQ_hd_var_size (consume_ticket_message,
1431                            GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET,
1432                            struct ConsumeTicketMessage, NULL),
1433     GNUNET_MQ_hd_fixed_size (ticket_iteration_start,
1434                              GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_START,
1435                              struct TicketIterationStartMessage, NULL),
1436     GNUNET_MQ_hd_fixed_size (ticket_iteration_next,
1437                              GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_NEXT,
1438                              struct TicketIterationNextMessage, NULL),
1439     GNUNET_MQ_hd_fixed_size (ticket_iteration_stop,
1440                              GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_STOP,
1441                              struct TicketIterationStopMessage, NULL),
1442     GNUNET_MQ_hd_var_size (revoke_ticket_message,
1443                            GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET,
1444                            struct RevokeTicketMessage, NULL),
1445     GNUNET_MQ_handler_end ());
1446 /* end of gnunet-service-reclaim.c */