obsolete due to alpine policy
[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 /**********************************************************
717 * Revocation
718 **********************************************************/
719
720 /**
721  * Handles revocation result
722  *
723  * @param cls our revocation operation handle
724  * @param success revocation result (GNUNET_OK if successful)
725  */
726 static void
727 revoke_result_cb (void *cls, int32_t success)
728 {
729   struct TicketRevocationOperation *rop = cls;
730   struct GNUNET_MQ_Envelope *env;
731   struct RevokeTicketResultMessage *trm;
732
733   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
734               "Sending REVOKE_TICKET_RESULT message\n");
735   rop->rh = NULL;
736   env = GNUNET_MQ_msg (trm, GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET_RESULT);
737   trm->id = htonl (rop->r_id);
738   trm->success = htonl (success);
739   GNUNET_MQ_send (rop->client->mq, env);
740   GNUNET_CONTAINER_DLL_remove (rop->client->revoke_op_head,
741                                rop->client->revoke_op_tail,
742                                rop);
743   GNUNET_free (rop);
744 }
745
746
747 /**
748  * Check revocation message format
749  *
750  * @param cls unused
751  * @param im the message to check
752  * @return GNUNET_OK if message is ok
753  */
754 static int
755 check_revoke_ticket_message (void *cls, const struct RevokeTicketMessage *im)
756 {
757   uint16_t size;
758
759   size = ntohs (im->header.size);
760   if (size != sizeof(struct RevokeTicketMessage))
761   {
762     GNUNET_break (0);
763     return GNUNET_SYSERR;
764   }
765   return GNUNET_OK;
766 }
767
768
769 /**
770  * Handle a revocation message to a ticket.
771  *
772  * @param cls our client
773  * @param rm the message to handle
774  */
775 static void
776 handle_revoke_ticket_message (void *cls, const struct RevokeTicketMessage *rm)
777 {
778   struct TicketRevocationOperation *rop;
779   struct IdpClient *idp = cls;
780
781   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received REVOKE_TICKET message\n");
782   rop = GNUNET_new (struct TicketRevocationOperation);
783   rop->r_id = ntohl (rm->id);
784   rop->client = idp;
785   GNUNET_CONTAINER_DLL_insert (idp->revoke_op_head, idp->revoke_op_tail, rop);
786   rop->rh
787     = RECLAIM_TICKETS_revoke (&rm->ticket, &rm->identity, &revoke_result_cb,
788                               rop);
789   GNUNET_SERVICE_client_continue (idp->client);
790 }
791
792
793 /**
794  * Handle a ticket consume result
795  *
796  * @param cls our consume ticket operation handle
797  * @param identity the attribute authority
798  * @param attrs the attribute/claim list
799  * @param success GNUNET_OK if successful
800  * @param emsg error message (NULL if success=GNUNET_OK)
801  */
802 static void
803 consume_result_cb (void *cls,
804                    const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
805                    const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
806                    int32_t success,
807                    const char *emsg)
808 {
809   struct ConsumeTicketOperation *cop = cls;
810   struct ConsumeTicketResultMessage *crm;
811   struct GNUNET_MQ_Envelope *env;
812   char *data_tmp;
813   size_t attrs_len;
814
815   if (GNUNET_OK != success)
816   {
817     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error consuming ticket: %s\n", emsg);
818   }
819   attrs_len = GNUNET_RECLAIM_ATTRIBUTE_list_serialize_get_size (attrs);
820   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
821               "Sending CONSUME_TICKET_RESULT message\n");
822   env = GNUNET_MQ_msg_extra (crm,
823                              attrs_len,
824                              GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT);
825   crm->id = htonl (cop->r_id);
826   crm->attrs_len = htons (attrs_len);
827   crm->identity = *identity;
828   crm->result = htonl (success);
829   data_tmp = (char *) &crm[1];
830   GNUNET_RECLAIM_ATTRIBUTE_list_serialize (attrs, data_tmp);
831   GNUNET_MQ_send (cop->client->mq, env);
832   GNUNET_CONTAINER_DLL_remove (cop->client->consume_op_head,
833                                cop->client->consume_op_tail,
834                                cop);
835   GNUNET_free (cop);
836 }
837
838
839 /**
840  * Check a consume ticket message
841  *
842  * @param cls unused
843  * @param cm the message to handle
844  */
845 static int
846 check_consume_ticket_message (void *cls, const struct ConsumeTicketMessage *cm)
847 {
848   uint16_t size;
849
850   size = ntohs (cm->header.size);
851   if (size != sizeof(struct ConsumeTicketMessage))
852   {
853     GNUNET_break (0);
854     return GNUNET_SYSERR;
855   }
856   return GNUNET_OK;
857 }
858
859
860 /**
861  * Handle a consume ticket message
862  *
863  * @param cls our client handle
864  * @cm the message to handle
865  */
866 static void
867 handle_consume_ticket_message (void *cls, const struct ConsumeTicketMessage *cm)
868 {
869   struct ConsumeTicketOperation *cop;
870   struct IdpClient *idp = cls;
871
872   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received CONSUME_TICKET message\n");
873   cop = GNUNET_new (struct ConsumeTicketOperation);
874   cop->r_id = ntohl (cm->id);
875   cop->client = idp;
876   cop->ch
877     = RECLAIM_TICKETS_consume (&cm->identity, &cm->ticket, &consume_result_cb,
878                                cop);
879   GNUNET_CONTAINER_DLL_insert (idp->consume_op_head, idp->consume_op_tail, cop);
880   GNUNET_SERVICE_client_continue (idp->client);
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  * Error iterating over attributes. Abort.
1360  *
1361  * @param cls our attribute iteration handle
1362  */
1363 static void
1364 attr_iter_error (void *cls)
1365 {
1366   struct AttributeIterator *ai = cls;
1367
1368   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to iterate over attributes\n");
1369   attr_iter_finished (ai);
1370 }
1371
1372
1373 /**
1374  * Got record. Return if it is an attribute.
1375  *
1376  * @param cls our attribute iterator
1377  * @param zone zone we are iterating
1378  * @param label label of the records
1379  * @param rd_count record count
1380  * @param rd records
1381  */
1382 static void
1383 attr_iter_cb (void *cls,
1384               const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1385               const char *label,
1386               unsigned int rd_count,
1387               const struct GNUNET_GNSRECORD_Data *rd)
1388 {
1389   struct AttributeIterator *ai = cls;
1390   struct AttributeResultMessage *arm;
1391   struct GNUNET_MQ_Envelope *env;
1392   char *data_tmp;
1393
1394   if (rd_count != 1)
1395   {
1396     GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1);
1397     return;
1398   }
1399
1400   if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR != rd->record_type)
1401   {
1402     GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1);
1403     return;
1404   }
1405   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found attribute under: %s\n", label);
1406   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending ATTRIBUTE_RESULT message\n");
1407   env = GNUNET_MQ_msg_extra (arm,
1408                              rd->data_size,
1409                              GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT);
1410   arm->id = htonl (ai->request_id);
1411   arm->attr_len = htons (rd->data_size);
1412   GNUNET_CRYPTO_ecdsa_key_get_public (zone, &arm->identity);
1413   data_tmp = (char *) &arm[1];
1414   GNUNET_memcpy (data_tmp, rd->data, rd->data_size);
1415   GNUNET_MQ_send (ai->client->mq, env);
1416 }
1417
1418
1419 /**
1420  * Iterate over zone to get attributes
1421  *
1422  * @param cls our client
1423  * @param ais_msg the iteration message to start
1424  */
1425 static void
1426 handle_iteration_start (void *cls,
1427                         const struct AttributeIterationStartMessage *ais_msg)
1428 {
1429   struct IdpClient *idp = cls;
1430   struct AttributeIterator *ai;
1431
1432   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1433               "Received ATTRIBUTE_ITERATION_START message\n");
1434   ai = GNUNET_new (struct AttributeIterator);
1435   ai->request_id = ntohl (ais_msg->id);
1436   ai->client = idp;
1437   ai->identity = ais_msg->identity;
1438
1439   GNUNET_CONTAINER_DLL_insert (idp->attr_iter_head, idp->attr_iter_tail, ai);
1440   ai->ns_it = GNUNET_NAMESTORE_zone_iteration_start (nsh,
1441                                                      &ai->identity,
1442                                                      &attr_iter_error,
1443                                                      ai,
1444                                                      &attr_iter_cb,
1445                                                      ai,
1446                                                      &attr_iter_finished,
1447                                                      ai);
1448   GNUNET_SERVICE_client_continue (idp->client);
1449 }
1450
1451
1452 /**
1453  * Handle iteration stop message from client
1454  *
1455  * @param cls the client
1456  * @param ais_msg the stop message
1457  */
1458 static void
1459 handle_iteration_stop (void *cls,
1460                        const struct AttributeIterationStopMessage *ais_msg)
1461 {
1462   struct IdpClient *idp = cls;
1463   struct AttributeIterator *ai;
1464   uint32_t rid;
1465
1466   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1467               "Received `%s' message\n",
1468               "ATTRIBUTE_ITERATION_STOP");
1469   rid = ntohl (ais_msg->id);
1470   for (ai = idp->attr_iter_head; NULL != ai; ai = ai->next)
1471     if (ai->request_id == rid)
1472       break;
1473   if (NULL == ai)
1474   {
1475     GNUNET_break (0);
1476     GNUNET_SERVICE_client_drop (idp->client);
1477     return;
1478   }
1479   GNUNET_CONTAINER_DLL_remove (idp->attr_iter_head, idp->attr_iter_tail, ai);
1480   GNUNET_free (ai);
1481   GNUNET_SERVICE_client_continue (idp->client);
1482 }
1483
1484
1485 /**
1486  * Client requests next attribute from iterator
1487  *
1488  * @param cls the client
1489  * @param ais_msg the message
1490  */
1491 static void
1492 handle_iteration_next (void *cls,
1493                        const struct AttributeIterationNextMessage *ais_msg)
1494 {
1495   struct IdpClient *idp = cls;
1496   struct AttributeIterator *ai;
1497   uint32_t rid;
1498
1499   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1500               "Received ATTRIBUTE_ITERATION_NEXT message\n");
1501   rid = ntohl (ais_msg->id);
1502   for (ai = idp->attr_iter_head; NULL != ai; ai = ai->next)
1503     if (ai->request_id == rid)
1504       break;
1505   if (NULL == ai)
1506   {
1507     GNUNET_break (0);
1508     GNUNET_SERVICE_client_drop (idp->client);
1509     return;
1510   }
1511   GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1);
1512   GNUNET_SERVICE_client_continue (idp->client);
1513 }
1514
1515 /******************************************************
1516 * Ticket iteration
1517 ******************************************************/
1518
1519 /**
1520  * Got a ticket. Return to client
1521  *
1522  * @param cls our ticket iterator
1523  * @param ticket the ticket
1524  */
1525 static void
1526 ticket_iter_cb (void *cls, struct GNUNET_RECLAIM_Ticket *ticket)
1527 {
1528   struct TicketIteration *ti = cls;
1529   struct GNUNET_MQ_Envelope *env;
1530   struct TicketResultMessage *trm;
1531
1532   env = GNUNET_MQ_msg (trm, GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT);
1533   if (NULL == ticket)
1534   {
1535     /* send empty response to indicate end of list */
1536     GNUNET_CONTAINER_DLL_remove (ti->client->ticket_iter_head,
1537                                  ti->client->ticket_iter_tail,
1538                                  ti);
1539   }
1540   else
1541   {
1542     trm->ticket = *ticket;
1543   }
1544   trm->id = htonl (ti->r_id);
1545   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending TICKET_RESULT message\n");
1546   GNUNET_MQ_send (ti->client->mq, env);
1547   if (NULL == ticket)
1548     GNUNET_free (ti);
1549 }
1550
1551
1552 /**
1553  * Client requests a ticket iteration
1554  *
1555  * @param cls the client
1556  * @param tis_msg the iteration request message
1557  */
1558 static void
1559 handle_ticket_iteration_start (
1560   void *cls,
1561   const struct TicketIterationStartMessage *tis_msg)
1562 {
1563   struct IdpClient *client = cls;
1564   struct TicketIteration *ti;
1565
1566   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1567               "Received TICKET_ITERATION_START message\n");
1568   ti = GNUNET_new (struct TicketIteration);
1569   ti->r_id = ntohl (tis_msg->id);
1570   ti->client = client;
1571
1572   GNUNET_CONTAINER_DLL_insert (client->ticket_iter_head,
1573                                client->ticket_iter_tail,
1574                                ti);
1575   ti->iter
1576     = RECLAIM_TICKETS_iteration_start (&tis_msg->identity, &ticket_iter_cb, ti);
1577   GNUNET_SERVICE_client_continue (client->client);
1578 }
1579
1580
1581 /**
1582  * Client has had enough tickets
1583  *
1584  * @param cls the client
1585  * @param tis_msg the stop message
1586  */
1587 static void
1588 handle_ticket_iteration_stop (void *cls,
1589                               const struct TicketIterationStopMessage *tis_msg)
1590 {
1591   struct IdpClient *client = cls;
1592   struct TicketIteration *ti;
1593   uint32_t rid;
1594
1595   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1596               "Received `%s' message\n",
1597               "TICKET_ITERATION_STOP");
1598   rid = ntohl (tis_msg->id);
1599   for (ti = client->ticket_iter_head; NULL != ti; ti = ti->next)
1600     if (ti->r_id == rid)
1601       break;
1602   if (NULL == ti)
1603   {
1604     GNUNET_break (0);
1605     GNUNET_SERVICE_client_drop (client->client);
1606     return;
1607   }
1608   RECLAIM_TICKETS_iteration_stop (ti->iter);
1609   GNUNET_CONTAINER_DLL_remove (client->ticket_iter_head,
1610                                client->ticket_iter_tail,
1611                                ti);
1612   GNUNET_free (ti);
1613   GNUNET_SERVICE_client_continue (client->client);
1614 }
1615
1616
1617 /**
1618  * Client requests next result.
1619  *
1620  * @param cls the client
1621  * @param tis_msg the message
1622  */
1623 static void
1624 handle_ticket_iteration_next (void *cls,
1625                               const struct TicketIterationNextMessage *tis_msg)
1626 {
1627   struct IdpClient *client = cls;
1628   struct TicketIteration *ti;
1629   uint32_t rid;
1630
1631   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1632               "Received TICKET_ITERATION_NEXT message\n");
1633   rid = ntohl (tis_msg->id);
1634   for (ti = client->ticket_iter_head; NULL != ti; ti = ti->next)
1635     if (ti->r_id == rid)
1636       break;
1637   if (NULL == ti)
1638   {
1639     GNUNET_break (0);
1640     GNUNET_SERVICE_client_drop (client->client);
1641     return;
1642   }
1643   RECLAIM_TICKETS_iteration_next (ti->iter);
1644   GNUNET_SERVICE_client_continue (client->client);
1645 }
1646
1647
1648 /**
1649  * Main function that will be run
1650  *
1651  * @param cls closure
1652  * @param c the configuration used
1653  * @param server the service handle
1654  */
1655 static void
1656 run (void *cls,
1657      const struct GNUNET_CONFIGURATION_Handle *c,
1658      struct GNUNET_SERVICE_Handle *server)
1659 {
1660   cfg = c;
1661
1662   if (GNUNET_OK != RECLAIM_TICKETS_init (cfg))
1663   {
1664     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1665                 "Unable to initialize TICKETS subsystem.\n");
1666     GNUNET_SCHEDULER_shutdown ();
1667     return;
1668   }
1669   // Connect to identity and namestore services
1670   nsh = GNUNET_NAMESTORE_connect (cfg);
1671   if (NULL == nsh)
1672   {
1673     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1674                          "error connecting to namestore");
1675   }
1676
1677   GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
1678 }
1679
1680
1681 /**
1682  * Called whenever a client is disconnected.
1683  *
1684  * @param cls closure
1685  * @param client identification of the client
1686  * @param app_ctx @a client
1687  */
1688 static void
1689 client_disconnect_cb (void *cls,
1690                       struct GNUNET_SERVICE_Client *client,
1691                       void *app_ctx)
1692 {
1693   struct IdpClient *idp = app_ctx;
1694
1695   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p disconnected\n", client);
1696   GNUNET_CONTAINER_DLL_remove (client_list_head,
1697                                client_list_tail,
1698                                idp);
1699   cleanup_client (idp);
1700 }
1701
1702
1703 /**
1704  * Add a client to our list of active clients.
1705  *
1706  * @param cls NULL
1707  * @param client client to add
1708  * @param mq message queue for @a client
1709  * @return internal namestore client structure for this client
1710  */
1711 static void *
1712 client_connect_cb (void *cls,
1713                    struct GNUNET_SERVICE_Client *client,
1714                    struct GNUNET_MQ_Handle *mq)
1715 {
1716   struct IdpClient *idp;
1717
1718   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", client);
1719   idp = GNUNET_new (struct IdpClient);
1720   idp->client = client;
1721   idp->mq = mq;
1722   GNUNET_CONTAINER_DLL_insert (client_list_head,
1723                                client_list_tail,
1724                                idp);
1725   return idp;
1726 }
1727
1728
1729 /**
1730  * Define "main" method using service macro.
1731  */
1732 GNUNET_SERVICE_MAIN (
1733   "reclaim",
1734   GNUNET_SERVICE_OPTION_NONE,
1735   &run,
1736   &client_connect_cb,
1737   &client_disconnect_cb,
1738   NULL,
1739   GNUNET_MQ_hd_var_size (attribute_store_message,
1740                          GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_STORE,
1741                          struct AttributeStoreMessage,
1742                          NULL),
1743   GNUNET_MQ_hd_var_size (attribute_delete_message,
1744                          GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_DELETE,
1745                          struct AttributeDeleteMessage,
1746                          NULL),
1747   GNUNET_MQ_hd_fixed_size (
1748     iteration_start,
1749     GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_START,
1750     struct AttributeIterationStartMessage,
1751     NULL),
1752   GNUNET_MQ_hd_fixed_size (iteration_next,
1753                            GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_NEXT,
1754                            struct AttributeIterationNextMessage,
1755                            NULL),
1756   GNUNET_MQ_hd_fixed_size (iteration_stop,
1757                            GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_STOP,
1758                            struct AttributeIterationStopMessage,
1759                            NULL),
1760   GNUNET_MQ_hd_var_size (issue_ticket_message,
1761                          GNUNET_MESSAGE_TYPE_RECLAIM_ISSUE_TICKET,
1762                          struct IssueTicketMessage,
1763                          NULL),
1764   GNUNET_MQ_hd_var_size (consume_ticket_message,
1765                          GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET,
1766                          struct ConsumeTicketMessage,
1767                          NULL),
1768   GNUNET_MQ_hd_fixed_size (ticket_iteration_start,
1769                            GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_START,
1770                            struct TicketIterationStartMessage,
1771                            NULL),
1772   GNUNET_MQ_hd_fixed_size (ticket_iteration_next,
1773                            GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_NEXT,
1774                            struct TicketIterationNextMessage,
1775                            NULL),
1776   GNUNET_MQ_hd_fixed_size (ticket_iteration_stop,
1777                            GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_STOP,
1778                            struct TicketIterationStopMessage,
1779                            NULL),
1780   GNUNET_MQ_hd_var_size (revoke_ticket_message,
1781                          GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET,
1782                          struct RevokeTicketMessage,
1783                          NULL),
1784   GNUNET_MQ_handler_end ());
1785 /* end of gnunet-service-reclaim.c */