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