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