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