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