remove 'illegal' (non-reentrant) log logic from signal handler
[oweals/gnunet.git] / src / reclaim / reclaim_api.c
1 /*
2    This file is part of GNUnet.
3    Copyright (C) 2016 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 /**
22  * @file reclaim/reclaim_api.c
23  * @brief api to interact with the reclaim service
24  * @author Martin Schanzenbach
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_constants.h"
29 #include "gnunet_mq_lib.h"
30 #include "gnunet_protocols.h"
31 #include "gnunet_reclaim_lib.h"
32 #include "gnunet_reclaim_service.h"
33 #include "reclaim.h"
34
35 #define LOG(kind, ...) GNUNET_log_from (kind, "reclaim-api", __VA_ARGS__)
36
37
38 /**
39  * Handle for an operation with the service.
40  */
41 struct GNUNET_RECLAIM_Operation
42 {
43   /**
44    * Main handle.
45    */
46   struct GNUNET_RECLAIM_Handle *h;
47
48   /**
49    * We keep operations in a DLL.
50    */
51   struct GNUNET_RECLAIM_Operation *next;
52
53   /**
54    * We keep operations in a DLL.
55    */
56   struct GNUNET_RECLAIM_Operation *prev;
57
58   /**
59    * Message to send to the service.
60    * Allocated at the end of this struct.
61    */
62   const struct GNUNET_MessageHeader *msg;
63
64   /**
65    * Continuation to invoke after attribute store call
66    */
67   GNUNET_RECLAIM_ContinuationWithStatus as_cb;
68
69   /**
70    * Attribute result callback
71    */
72   GNUNET_RECLAIM_AttributeResult ar_cb;
73
74   /**
75    * Attribute result callback
76    */
77   GNUNET_RECLAIM_AttributeTicketResult atr_cb;
78
79   /**
80    * Attestation result callback
81    */
82   GNUNET_RECLAIM_AttestationResult at_cb;
83
84   /**
85    * Revocation result callback
86    */
87   GNUNET_RECLAIM_ContinuationWithStatus rvk_cb;
88
89   /**
90    * Ticket result callback
91    */
92   GNUNET_RECLAIM_TicketCallback tr_cb;
93
94   /**
95    * Envelope with the message for this queue entry.
96    */
97   struct GNUNET_MQ_Envelope *env;
98
99   /**
100    * request id
101    */
102   uint32_t r_id;
103
104   /**
105    * Closure for @e cont or @e cb.
106    */
107   void *cls;
108 };
109
110
111 /**
112  * Handle for a ticket iterator operation
113  */
114 struct GNUNET_RECLAIM_TicketIterator
115 {
116   /**
117    * Kept in a DLL.
118    */
119   struct GNUNET_RECLAIM_TicketIterator *next;
120
121   /**
122    * Kept in a DLL.
123    */
124   struct GNUNET_RECLAIM_TicketIterator *prev;
125
126   /**
127    * Main handle to access the idp.
128    */
129   struct GNUNET_RECLAIM_Handle *h;
130
131   /**
132    * Function to call on completion.
133    */
134   GNUNET_SCHEDULER_TaskCallback finish_cb;
135
136   /**
137    * Closure for @e finish_cb.
138    */
139   void *finish_cb_cls;
140
141   /**
142    * The continuation to call with the results
143    */
144   GNUNET_RECLAIM_TicketCallback tr_cb;
145
146   /**
147    * Closure for @e tr_cb.
148    */
149   void *cls;
150
151   /**
152    * Function to call on errors.
153    */
154   GNUNET_SCHEDULER_TaskCallback error_cb;
155
156   /**
157    * Closure for @e error_cb.
158    */
159   void *error_cb_cls;
160
161   /**
162    * Envelope of the message to send to the service, if not yet
163    * sent.
164    */
165   struct GNUNET_MQ_Envelope *env;
166
167   /**
168    * The operation id this zone iteration operation has
169    */
170   uint32_t r_id;
171 };
172
173
174 /**
175  * Handle for a attribute iterator operation
176  */
177 struct GNUNET_RECLAIM_AttributeIterator
178 {
179   /**
180    * Kept in a DLL.
181    */
182   struct GNUNET_RECLAIM_AttributeIterator *next;
183
184   /**
185    * Kept in a DLL.
186    */
187   struct GNUNET_RECLAIM_AttributeIterator *prev;
188
189   /**
190    * Main handle to access the service.
191    */
192   struct GNUNET_RECLAIM_Handle *h;
193
194   /**
195    * Function to call on completion.
196    */
197   GNUNET_SCHEDULER_TaskCallback finish_cb;
198
199   /**
200    * Closure for @e finish_cb.
201    */
202   void *finish_cb_cls;
203
204   /**
205    * The continuation to call with the results
206    */
207   GNUNET_RECLAIM_AttributeResult proc;
208
209   /**
210    * Closure for @e proc.
211    */
212   void *proc_cls;
213
214   /**
215    * Function to call on errors.
216    */
217   GNUNET_SCHEDULER_TaskCallback error_cb;
218
219   /**
220    * Closure for @e error_cb.
221    */
222   void *error_cb_cls;
223
224   /**
225    * Envelope of the message to send to the service, if not yet
226    * sent.
227    */
228   struct GNUNET_MQ_Envelope *env;
229
230   /**
231    * Private key of the zone.
232    */
233   struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
234
235   /**
236    * The operation id this zone iteration operation has
237    */
238   uint32_t r_id;
239 };
240
241 /**
242  * Handle for a attestation iterator operation
243  */
244 struct GNUNET_RECLAIM_AttestationIterator
245 {
246   /**
247    * Kept in a DLL.
248    */
249   struct GNUNET_RECLAIM_AttestationIterator *next;
250
251   /**
252    * Kept in a DLL.
253    */
254   struct GNUNET_RECLAIM_AttestationIterator *prev;
255
256   /**
257    * Main handle to access the service.
258    */
259   struct GNUNET_RECLAIM_Handle *h;
260
261   /**
262    * Function to call on completion.
263    */
264   GNUNET_SCHEDULER_TaskCallback finish_cb;
265
266   /**
267    * Closure for @e finish_cb.
268    */
269   void *finish_cb_cls;
270
271   /**
272    * The continuation to call with the results
273    */
274   GNUNET_RECLAIM_AttestationResult proc;
275
276   /**
277    * Closure for @e proc.
278    */
279   void *proc_cls;
280
281   /**
282    * Function to call on errors.
283    */
284   GNUNET_SCHEDULER_TaskCallback error_cb;
285
286   /**
287    * Closure for @e error_cb.
288    */
289   void *error_cb_cls;
290
291   /**
292    * Envelope of the message to send to the service, if not yet
293    * sent.
294    */
295   struct GNUNET_MQ_Envelope *env;
296
297   /**
298    * Private key of the zone.
299    */
300   struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
301
302   /**
303    * The operation id this zone iteration operation has
304    */
305   uint32_t r_id;
306 };
307
308
309 /**
310  * Handle to the service.
311  */
312 struct GNUNET_RECLAIM_Handle
313 {
314   /**
315    * Configuration to use.
316    */
317   const struct GNUNET_CONFIGURATION_Handle *cfg;
318
319   /**
320    * Socket (if available).
321    */
322   struct GNUNET_CLIENT_Connection *client;
323
324   /**
325    * Closure for 'cb'.
326    */
327   void *cb_cls;
328
329   /**
330    * Head of active operations.
331    */
332   struct GNUNET_RECLAIM_Operation *op_head;
333
334   /**
335    * Tail of active operations.
336    */
337   struct GNUNET_RECLAIM_Operation *op_tail;
338
339   /**
340    * Head of active iterations
341    */
342   struct GNUNET_RECLAIM_AttributeIterator *it_head;
343
344   /**
345    * Tail of active iterations
346    */
347   struct GNUNET_RECLAIM_AttributeIterator *it_tail;
348
349   /**
350    * Head of active iterations
351    */
352   struct GNUNET_RECLAIM_AttestationIterator *ait_head;
353
354   /**
355    * Tail of active iterations
356    */
357   struct GNUNET_RECLAIM_AttestationIterator *ait_tail;
358
359   /**
360    * Head of active iterations
361    */
362   struct GNUNET_RECLAIM_TicketIterator *ticket_it_head;
363
364   /**
365    * Tail of active iterations
366    */
367   struct GNUNET_RECLAIM_TicketIterator *ticket_it_tail;
368
369   /**
370    * Currently pending transmission request, or NULL for none.
371    */
372   struct GNUNET_CLIENT_TransmitHandle *th;
373
374   /**
375    * Task doing exponential back-off trying to reconnect.
376    */
377   struct GNUNET_SCHEDULER_Task *reconnect_task;
378
379   /**
380    * Time for next connect retry.
381    */
382   struct GNUNET_TIME_Relative reconnect_backoff;
383
384   /**
385    * Connection to service (if available).
386    */
387   struct GNUNET_MQ_Handle *mq;
388
389   /**
390    * Request Id generator.  Incremented by one for each request.
391    */
392   uint32_t r_id_gen;
393
394   /**
395    * Are we polling for incoming messages right now?
396    */
397   int in_receive;
398 };
399
400
401 /**
402  * Try again to connect to the service.
403  *
404  * @param h handle to the reclaim service.
405  */
406 static void
407 reconnect (struct GNUNET_RECLAIM_Handle *h);
408
409
410 /**
411  * Reconnect
412  *
413  * @param cls the handle
414  */
415 static void
416 reconnect_task (void *cls)
417 {
418   struct GNUNET_RECLAIM_Handle *handle = cls;
419
420   handle->reconnect_task = NULL;
421   reconnect (handle);
422 }
423
424
425 /**
426  * Disconnect from service and then reconnect.
427  *
428  * @param handle our service
429  */
430 static void
431 force_reconnect (struct GNUNET_RECLAIM_Handle *handle)
432 {
433   GNUNET_MQ_destroy (handle->mq);
434   handle->mq = NULL;
435   handle->reconnect_backoff =
436     GNUNET_TIME_STD_BACKOFF (handle->reconnect_backoff);
437   handle->reconnect_task =
438     GNUNET_SCHEDULER_add_delayed (handle->reconnect_backoff,
439                                   &reconnect_task,
440                                   handle);
441 }
442
443
444 /**
445  * Free @a it.
446  *
447  * @param it entry to free
448  */
449 static void
450 free_it (struct GNUNET_RECLAIM_AttributeIterator *it)
451 {
452   struct GNUNET_RECLAIM_Handle *h = it->h;
453
454   GNUNET_CONTAINER_DLL_remove (h->it_head, h->it_tail, it);
455   if (NULL != it->env)
456     GNUNET_MQ_discard (it->env);
457   GNUNET_free (it);
458 }
459
460
461 /**
462  * Free @a it.
463  *
464  * @param ait entry to free
465  */
466 static void
467 free_ait (struct GNUNET_RECLAIM_AttestationIterator *ait)
468 {
469   struct GNUNET_RECLAIM_Handle *h = ait->h;
470
471   GNUNET_CONTAINER_DLL_remove (h->ait_head, h->ait_tail, ait);
472   if (NULL != ait->env)
473     GNUNET_MQ_discard (ait->env);
474   GNUNET_free (ait);
475 }
476
477
478 /**
479  * Free @a op
480  *
481  * @param op the operation to free
482  */
483 static void
484 free_op (struct GNUNET_RECLAIM_Operation *op)
485 {
486   if (NULL == op)
487     return;
488   if (NULL != op->env)
489     GNUNET_MQ_discard (op->env);
490   GNUNET_free (op);
491 }
492
493
494 /**
495  * Generic error handler, called with the appropriate error code and
496  * the same closure specified at the creation of the message queue.
497  * Not every message queue implementation supports an error handler.
498  *
499  * @param cls closure with the `struct GNUNET_GNS_Handle *`
500  * @param error error code
501  */
502 static void
503 mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
504 {
505   struct GNUNET_RECLAIM_Handle *handle = cls;
506
507   force_reconnect (handle);
508 }
509
510
511 /**
512  * Handle an incoming message of type
513  * #GNUNET_MESSAGE_TYPE_RECLAIM_SUCCESS_RESPONSE
514  *
515  * @param cls
516  * @param msg the message we received
517  */
518 static void
519 handle_success_response (void *cls, const struct SuccessResultMessage *msg)
520 {
521   struct GNUNET_RECLAIM_Handle *h = cls;
522   struct GNUNET_RECLAIM_Operation *op;
523   uint32_t r_id = ntohl (msg->id);
524   int res;
525   const char *emsg;
526
527   for (op = h->op_head; NULL != op; op = op->next)
528     if (op->r_id == r_id)
529       break;
530   if (NULL == op)
531     return;
532
533   res = ntohl (msg->op_result);
534   LOG (GNUNET_ERROR_TYPE_DEBUG,
535        "Received SUCCESS_RESPONSE with result %d\n",
536        res);
537
538   /* TODO: add actual error message to response... */
539   if (GNUNET_SYSERR == res)
540     emsg = _ ("failed to store record\n");
541   else
542     emsg = NULL;
543   if (NULL != op->as_cb)
544     op->as_cb (op->cls, res, emsg);
545   GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
546   free_op (op);
547 }
548
549
550 /**
551  * Handle an incoming message of type
552  * #GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT
553  *
554  * @param cls
555  * @param msg the message we received
556  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
557  */
558 static int
559 check_consume_ticket_result (void *cls,
560                              const struct ConsumeTicketResultMessage *msg)
561 {
562   size_t msg_len;
563   size_t attrs_len;
564   size_t attests_len;
565
566   msg_len = ntohs (msg->header.size);
567   attrs_len = ntohs (msg->attrs_len);
568   attests_len = ntohs (msg->attestations_len);
569   if (msg_len !=
570       sizeof(struct ConsumeTicketResultMessage) + attrs_len + attests_len)
571   {
572     GNUNET_break (0);
573     return GNUNET_SYSERR;
574   }
575   return GNUNET_OK;
576 }
577
578
579 /**
580  * Handle an incoming message of type
581  * #GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT
582  *
583  * @param cls
584  * @param msg the message we received
585  */
586 static void
587 handle_consume_ticket_result (void *cls,
588                               const struct ConsumeTicketResultMessage *msg)
589 {
590   struct GNUNET_RECLAIM_Handle *h = cls;
591   struct GNUNET_RECLAIM_Operation *op;
592   size_t attrs_len;
593   size_t attests_len;
594   uint32_t r_id = ntohl (msg->id);
595   char *read_ptr;
596
597   attrs_len = ntohs (msg->attrs_len);
598   attests_len = ntohs (msg->attestations_len);
599   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing ticket result.\n");
600
601
602   for (op = h->op_head; NULL != op; op = op->next)
603     if (op->r_id == r_id)
604       break;
605   if (NULL == op)
606     return;
607
608   {
609     struct GNUNET_RECLAIM_AttributeList *attrs;
610     struct GNUNET_RECLAIM_AttributeListEntry *le;
611     struct GNUNET_RECLAIM_AttestationList *attests;
612     struct GNUNET_RECLAIM_AttestationListEntry *ale;
613     attrs =
614       GNUNET_RECLAIM_attribute_list_deserialize ((char *) &msg[1], attrs_len);
615     read_ptr = ((char *) &msg[1]) + attrs_len;
616     attests =
617       GNUNET_RECLAIM_attestation_list_deserialize (read_ptr, attests_len);
618     if (NULL != op->atr_cb)
619     {
620       if (NULL == attrs)
621       {
622         op->atr_cb (op->cls, &msg->identity, NULL, NULL);
623       }
624       else
625       {
626         for (le = attrs->list_head; NULL != le; le = le->next)
627         {
628           if (GNUNET_NO ==
629               GNUNET_RECLAIM_id_is_zero (&le->attribute->attestation))
630           {
631             for (ale = attests->list_head; NULL != ale; ale = ale->next)
632             {
633               if (GNUNET_YES ==
634                   GNUNET_RECLAIM_id_is_equal (&le->attribute->attestation,
635                                               &ale->attestation->id))
636               {
637                 op->atr_cb (op->cls, &msg->identity,
638                             le->attribute, ale->attestation);
639                 break;
640               }
641
642             }
643           }
644           else     // No attestations
645           {
646             op->atr_cb (op->cls, &msg->identity,
647                         le->attribute, NULL);
648           }
649         }
650         if (NULL != attrs)
651           GNUNET_RECLAIM_attribute_list_destroy (attrs);
652         if (NULL != attests)
653           GNUNET_RECLAIM_attestation_list_destroy (attests);
654         attrs = NULL;
655         attests = NULL;
656       }
657       op->atr_cb (op->cls, NULL, NULL, NULL);
658     }
659     GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
660     free_op (op);
661     GNUNET_free_non_null (attrs);
662     return;
663   }
664   GNUNET_assert (0);
665 }
666
667
668 /**
669  * Handle an incoming message of type
670  * #GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT
671  *
672  * @param cls
673  * @param msg the message we received
674  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
675  */
676 static int
677 check_attribute_result (void *cls, const struct AttributeResultMessage *msg)
678 {
679   size_t msg_len;
680   size_t attr_len;
681
682   msg_len = ntohs (msg->header.size);
683   attr_len = ntohs (msg->attr_len);
684   if (msg_len != sizeof(struct AttributeResultMessage) + attr_len)
685   {
686     GNUNET_break (0);
687     return GNUNET_SYSERR;
688   }
689   return GNUNET_OK;
690 }
691
692
693 /**
694  * Handle an incoming message of type
695  * #GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT
696  *
697  * @param cls
698  * @param msg the message we received
699  */
700 static void
701 handle_attribute_result (void *cls, const struct AttributeResultMessage *msg)
702 {
703   static struct GNUNET_CRYPTO_EcdsaPrivateKey identity_dummy;
704   struct GNUNET_RECLAIM_Handle *h = cls;
705   struct GNUNET_RECLAIM_AttributeIterator *it;
706   struct GNUNET_RECLAIM_Operation *op;
707   size_t attr_len;
708   uint32_t r_id = ntohl (msg->id);
709
710   attr_len = ntohs (msg->attr_len);
711   LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing attribute result.\n");
712
713
714   for (it = h->it_head; NULL != it; it = it->next)
715     if (it->r_id == r_id)
716       break;
717   for (op = h->op_head; NULL != op; op = op->next)
718     if (op->r_id == r_id)
719       break;
720   if ((NULL == it) && (NULL == op))
721     return;
722
723   if ((0 ==
724        (memcmp (&msg->identity, &identity_dummy, sizeof(identity_dummy)))))
725   {
726     if ((NULL == it) && (NULL == op))
727     {
728       GNUNET_break (0);
729       force_reconnect (h);
730       return;
731     }
732     if (NULL != it)
733     {
734       if (NULL != it->finish_cb)
735         it->finish_cb (it->finish_cb_cls);
736       free_it (it);
737     }
738     if (NULL != op)
739     {
740       if (NULL != op->ar_cb)
741         op->ar_cb (op->cls, NULL, NULL);
742       GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
743       free_op (op);
744     }
745     return;
746   }
747
748   {
749     struct GNUNET_RECLAIM_Attribute *attr;
750     attr = GNUNET_RECLAIM_attribute_deserialize ((char *) &msg[1], attr_len);
751     if (NULL != it)
752     {
753       if (NULL != it->proc)
754         it->proc (it->proc_cls, &msg->identity, attr);
755     }
756     else if (NULL != op)
757     {
758       if (NULL != op->ar_cb)
759         op->ar_cb (op->cls, &msg->identity, attr);
760     }
761     GNUNET_free (attr);
762     return;
763   }
764   GNUNET_assert (0);
765 }
766
767
768 /**
769    * Handle an incoming message of type
770    * #GNUNET_MESSAGE_TYPE_RECLAIM_attestation_RESULT
771    *
772    * @param cls
773    * @param msg the message we received
774    * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
775    */
776 static int
777 check_attestation_result (void *cls, const struct AttestationResultMessage *msg)
778 {
779   size_t msg_len;
780   size_t attest_len;
781
782   msg_len = ntohs (msg->header.size);
783   attest_len = ntohs (msg->attestation_len);
784   if (msg_len != sizeof(struct AttestationResultMessage) + attest_len)
785   {
786     GNUNET_break (0);
787     return GNUNET_SYSERR;
788   }
789   return GNUNET_OK;
790 }
791
792
793 /**
794  * Handle an incoming message of type
795  * #GNUNET_MESSAGE_TYPE_RECLAIM_attestation_RESULT
796  *
797  * @param cls
798  * @param msg the message we received
799  */
800 static void
801 handle_attestation_result (void *cls, const struct
802                            AttestationResultMessage *msg)
803 {
804   static struct GNUNET_CRYPTO_EcdsaPrivateKey identity_dummy;
805   struct GNUNET_RECLAIM_Handle *h = cls;
806   struct GNUNET_RECLAIM_AttestationIterator *it;
807   struct GNUNET_RECLAIM_Operation *op;
808   size_t att_len;
809   uint32_t r_id = ntohl (msg->id);
810
811   att_len = ntohs (msg->attestation_len);
812   LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing attestation result.\n");
813
814
815   for (it = h->ait_head; NULL != it; it = it->next)
816     if (it->r_id == r_id)
817       break;
818   for (op = h->op_head; NULL != op; op = op->next)
819     if (op->r_id == r_id)
820       break;
821   if ((NULL == it) && (NULL == op))
822     return;
823
824   if ((0 ==
825        (memcmp (&msg->identity, &identity_dummy, sizeof(identity_dummy)))))
826   {
827     if ((NULL == it) && (NULL == op))
828     {
829       GNUNET_break (0);
830       force_reconnect (h);
831       return;
832     }
833     if (NULL != it)
834     {
835       if (NULL != it->finish_cb)
836         it->finish_cb (it->finish_cb_cls);
837       free_ait (it);
838     }
839     if (NULL != op)
840     {
841       if (NULL != op->at_cb)
842         op->at_cb (op->cls, NULL, NULL);
843       GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
844       free_op (op);
845     }
846     return;
847   }
848
849   {
850     struct GNUNET_RECLAIM_Attestation *att;
851     att = GNUNET_RECLAIM_attestation_deserialize ((char *) &msg[1], att_len);
852
853     if (NULL != it)
854     {
855       if (NULL != it->proc)
856         it->proc (it->proc_cls, &msg->identity, att);
857     }
858     else if (NULL != op)
859     {
860       if (NULL != op->at_cb)
861         op->at_cb (op->cls, &msg->identity, att);
862     }
863     GNUNET_free (att);
864     return;
865   }
866   GNUNET_assert (0);
867 }
868
869
870 /**
871  * Handle an incoming message of type
872  * #GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT
873  *
874  * @param cls
875  * @param msg the message we received
876  */
877 static void
878 handle_ticket_result (void *cls, const struct TicketResultMessage *msg)
879 {
880   struct GNUNET_RECLAIM_Handle *handle = cls;
881   struct GNUNET_RECLAIM_Operation *op;
882   struct GNUNET_RECLAIM_TicketIterator *it;
883   uint32_t r_id = ntohl (msg->id);
884   static const struct GNUNET_RECLAIM_Ticket ticket;
885
886   for (op = handle->op_head; NULL != op; op = op->next)
887     if (op->r_id == r_id)
888       break;
889   for (it = handle->ticket_it_head; NULL != it; it = it->next)
890     if (it->r_id == r_id)
891       break;
892   if ((NULL == op) && (NULL == it))
893     return;
894   if (NULL != op)
895   {
896     GNUNET_CONTAINER_DLL_remove (handle->op_head, handle->op_tail, op);
897     if (0 ==
898         memcmp (&msg->ticket, &ticket, sizeof(struct GNUNET_RECLAIM_Ticket)))
899     {
900       if (NULL != op->tr_cb)
901         op->tr_cb (op->cls, NULL);
902     }
903     else
904     {
905       if (NULL != op->tr_cb)
906         op->tr_cb (op->cls, &msg->ticket);
907     }
908     free_op (op);
909     return;
910   }
911   else if (NULL != it)
912   {
913     if (0 ==
914         memcmp (&msg->ticket, &ticket, sizeof(struct GNUNET_RECLAIM_Ticket)))
915     {
916       GNUNET_CONTAINER_DLL_remove (handle->ticket_it_head,
917                                    handle->ticket_it_tail,
918                                    it);
919       it->finish_cb (it->finish_cb_cls);
920       GNUNET_free (it);
921     }
922     else
923     {
924       if (NULL != it->tr_cb)
925         it->tr_cb (it->cls, &msg->ticket);
926     }
927     return;
928   }
929   GNUNET_break (0);
930 }
931
932
933 /**
934  * Handle an incoming message of type
935  * #GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET_RESULT
936  *
937  * @param cls
938  * @param msg the message we received
939  */
940 static void
941 handle_revoke_ticket_result (void *cls,
942                              const struct RevokeTicketResultMessage *msg)
943 {
944   struct GNUNET_RECLAIM_Handle *h = cls;
945   struct GNUNET_RECLAIM_Operation *op;
946   uint32_t r_id = ntohl (msg->id);
947   int32_t success;
948
949   LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing revocation result.\n");
950
951
952   for (op = h->op_head; NULL != op; op = op->next)
953     if (op->r_id == r_id)
954       break;
955   if (NULL == op)
956     return;
957   success = ntohl (msg->success);
958   {
959     if (NULL != op->rvk_cb)
960     {
961       op->rvk_cb (op->cls, success, NULL);
962     }
963     GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
964     free_op (op);
965     return;
966   }
967   GNUNET_assert (0);
968 }
969
970
971 /**
972  * Try again to connect to the service.
973  *
974  * @param h handle to the reclaim service.
975  */
976 static void
977 reconnect (struct GNUNET_RECLAIM_Handle *h)
978 {
979   struct GNUNET_MQ_MessageHandler handlers[] =
980   { GNUNET_MQ_hd_fixed_size (success_response,
981                              GNUNET_MESSAGE_TYPE_RECLAIM_SUCCESS_RESPONSE,
982                              struct SuccessResultMessage,
983                              h),
984     GNUNET_MQ_hd_var_size (attribute_result,
985                            GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT,
986                            struct AttributeResultMessage,
987                            h),
988     GNUNET_MQ_hd_var_size (attestation_result,
989                            GNUNET_MESSAGE_TYPE_RECLAIM_ATTESTATION_RESULT,
990                            struct AttestationResultMessage,
991                            h),
992     GNUNET_MQ_hd_fixed_size (ticket_result,
993                              GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT,
994                              struct TicketResultMessage,
995                              h),
996     GNUNET_MQ_hd_var_size (consume_ticket_result,
997                            GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT,
998                            struct ConsumeTicketResultMessage,
999                            h),
1000     GNUNET_MQ_hd_fixed_size (revoke_ticket_result,
1001                              GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET_RESULT,
1002                              struct RevokeTicketResultMessage,
1003                              h),
1004     GNUNET_MQ_handler_end () };
1005   struct GNUNET_RECLAIM_Operation *op;
1006
1007   GNUNET_assert (NULL == h->mq);
1008   LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to reclaim service.\n");
1009
1010   h->mq =
1011     GNUNET_CLIENT_connect (h->cfg, "reclaim", handlers, &mq_error_handler, h);
1012   if (NULL == h->mq)
1013     return;
1014   for (op = h->op_head; NULL != op; op = op->next)
1015     GNUNET_MQ_send_copy (h->mq, op->env);
1016 }
1017
1018
1019 /**
1020  * Connect to the reclaim service.
1021  *
1022  * @param cfg the configuration to use
1023  * @return handle to use
1024  */
1025 struct GNUNET_RECLAIM_Handle *
1026 GNUNET_RECLAIM_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
1027 {
1028   struct GNUNET_RECLAIM_Handle *h;
1029
1030   h = GNUNET_new (struct GNUNET_RECLAIM_Handle);
1031   h->cfg = cfg;
1032   reconnect (h);
1033   if (NULL == h->mq)
1034   {
1035     GNUNET_free (h);
1036     return NULL;
1037   }
1038   return h;
1039 }
1040
1041
1042 /**
1043  * Cancel an operation. Note that the operation MAY still
1044  * be executed; this merely cancels the continuation; if the request
1045  * was already transmitted, the service may still choose to complete
1046  * the operation.
1047  *
1048  * @param op operation to cancel
1049  */
1050 void
1051 GNUNET_RECLAIM_cancel (struct GNUNET_RECLAIM_Operation *op)
1052 {
1053   struct GNUNET_RECLAIM_Handle *h = op->h;
1054
1055   GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
1056   free_op (op);
1057 }
1058
1059
1060 /**
1061  * Disconnect from service
1062  *
1063  * @param h handle to destroy
1064  */
1065 void
1066 GNUNET_RECLAIM_disconnect (struct GNUNET_RECLAIM_Handle *h)
1067 {
1068   GNUNET_assert (NULL != h);
1069   if (NULL != h->mq)
1070   {
1071     GNUNET_MQ_destroy (h->mq);
1072     h->mq = NULL;
1073   }
1074   if (NULL != h->reconnect_task)
1075   {
1076     GNUNET_SCHEDULER_cancel (h->reconnect_task);
1077     h->reconnect_task = NULL;
1078   }
1079   GNUNET_assert (NULL == h->op_head);
1080   GNUNET_free (h);
1081 }
1082
1083
1084 /**
1085  * Store an attribute.  If the attribute is already present,
1086  * it is replaced with the new attribute.
1087  *
1088  * @param h handle to the re:claimID service
1089  * @param pkey private key of the identity
1090  * @param attr the attribute value
1091  * @param exp_interval the relative expiration interval for the attribute
1092  * @param cont continuation to call when done
1093  * @param cont_cls closure for @a cont
1094  * @return handle to abort the request
1095  */
1096 struct GNUNET_RECLAIM_Operation *
1097 GNUNET_RECLAIM_attribute_store (
1098   struct GNUNET_RECLAIM_Handle *h,
1099   const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey,
1100   const struct GNUNET_RECLAIM_Attribute *attr,
1101   const struct GNUNET_TIME_Relative *exp_interval,
1102   GNUNET_RECLAIM_ContinuationWithStatus cont,
1103   void *cont_cls)
1104 {
1105   struct GNUNET_RECLAIM_Operation *op;
1106   struct AttributeStoreMessage *sam;
1107   size_t attr_len;
1108
1109   op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
1110   op->h = h;
1111   op->as_cb = cont;
1112   op->cls = cont_cls;
1113   op->r_id = h->r_id_gen++;
1114   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
1115   attr_len = GNUNET_RECLAIM_attribute_serialize_get_size (attr);
1116   op->env = GNUNET_MQ_msg_extra (sam,
1117                                  attr_len,
1118                                  GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_STORE);
1119   sam->identity = *pkey;
1120   sam->id = htonl (op->r_id);
1121   sam->exp = GNUNET_htonll (exp_interval->rel_value_us);
1122
1123   GNUNET_RECLAIM_attribute_serialize (attr, (char *) &sam[1]);
1124
1125   sam->attr_len = htons (attr_len);
1126   if (NULL != h->mq)
1127     GNUNET_MQ_send_copy (h->mq, op->env);
1128   return op;
1129 }
1130
1131
1132 /**
1133  * Delete an attribute. Tickets used to share this attribute are updated
1134  * accordingly.
1135  *
1136  * @param h handle to the re:claimID service
1137  * @param pkey Private key of the identity to add an attribute to
1138  * @param attr The attribute
1139  * @param cont Continuation to call when done
1140  * @param cont_cls Closure for @a cont
1141  * @return handle Used to to abort the request
1142  */
1143 struct GNUNET_RECLAIM_Operation *
1144 GNUNET_RECLAIM_attribute_delete (
1145   struct GNUNET_RECLAIM_Handle *h,
1146   const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey,
1147   const struct GNUNET_RECLAIM_Attribute *attr,
1148   GNUNET_RECLAIM_ContinuationWithStatus cont,
1149   void *cont_cls)
1150 {
1151   struct GNUNET_RECLAIM_Operation *op;
1152   struct AttributeDeleteMessage *dam;
1153   size_t attr_len;
1154
1155   op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
1156   op->h = h;
1157   op->as_cb = cont;
1158   op->cls = cont_cls;
1159   op->r_id = h->r_id_gen++;
1160   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
1161   attr_len = GNUNET_RECLAIM_attribute_serialize_get_size (attr);
1162   op->env = GNUNET_MQ_msg_extra (dam,
1163                                  attr_len,
1164                                  GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_DELETE);
1165   dam->identity = *pkey;
1166   dam->id = htonl (op->r_id);
1167   GNUNET_RECLAIM_attribute_serialize (attr, (char *) &dam[1]);
1168
1169   dam->attr_len = htons (attr_len);
1170   if (NULL != h->mq)
1171     GNUNET_MQ_send_copy (h->mq, op->env);
1172   return op;
1173 }
1174
1175
1176 /**
1177    * Store an attestation.  If the attestation is already present,
1178    * it is replaced with the new attestation.
1179    *
1180    * @param h handle to the re:claimID service
1181    * @param pkey private key of the identity
1182    * @param attr the attestation value
1183    * @param exp_interval the relative expiration interval for the attestation
1184    * @param cont continuation to call when done
1185    * @param cont_cls closure for @a cont
1186    * @return handle to abort the request
1187    */
1188 struct GNUNET_RECLAIM_Operation *
1189 GNUNET_RECLAIM_attestation_store (
1190   struct GNUNET_RECLAIM_Handle *h,
1191   const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey,
1192   const struct GNUNET_RECLAIM_Attestation *attr,
1193   const struct GNUNET_TIME_Relative *exp_interval,
1194   GNUNET_RECLAIM_ContinuationWithStatus cont,
1195   void *cont_cls)
1196 {
1197   struct GNUNET_RECLAIM_Operation *op;
1198   struct AttributeStoreMessage *sam;
1199   size_t attr_len;
1200
1201   op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
1202   op->h = h;
1203   op->as_cb = cont;
1204   op->cls = cont_cls;
1205   op->r_id = h->r_id_gen++;
1206   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
1207   attr_len = GNUNET_RECLAIM_attestation_serialize_get_size (attr);
1208   op->env = GNUNET_MQ_msg_extra (sam,
1209                                  attr_len,
1210                                  GNUNET_MESSAGE_TYPE_RECLAIM_ATTESTATION_STORE);
1211   sam->identity = *pkey;
1212   sam->id = htonl (op->r_id);
1213   sam->exp = GNUNET_htonll (exp_interval->rel_value_us);
1214
1215   GNUNET_RECLAIM_attestation_serialize (attr, (char *) &sam[1]);
1216
1217   sam->attr_len = htons (attr_len);
1218   if (NULL != h->mq)
1219     GNUNET_MQ_send_copy (h->mq, op->env);
1220   return op;
1221 }
1222
1223
1224 /**
1225    * Delete an attestation. Tickets used to share this attestation are updated
1226    * accordingly.
1227    *
1228    * @param h handle to the re:claimID service
1229    * @param pkey Private key of the identity to add an attribute to
1230    * @param attr The attestation
1231    * @param cont Continuation to call when done
1232    * @param cont_cls Closure for @a cont
1233    * @return handle Used to to abort the request
1234    */
1235 struct GNUNET_RECLAIM_Operation *
1236 GNUNET_RECLAIM_attestation_delete (
1237   struct GNUNET_RECLAIM_Handle *h,
1238   const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey,
1239   const struct GNUNET_RECLAIM_Attestation *attr,
1240   GNUNET_RECLAIM_ContinuationWithStatus cont,
1241   void *cont_cls)
1242 {
1243   struct GNUNET_RECLAIM_Operation *op;
1244   struct AttributeDeleteMessage *dam;
1245   size_t attr_len;
1246
1247   op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
1248   op->h = h;
1249   op->as_cb = cont;
1250   op->cls = cont_cls;
1251   op->r_id = h->r_id_gen++;
1252   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
1253   attr_len = GNUNET_RECLAIM_attestation_serialize_get_size (attr);
1254   op->env = GNUNET_MQ_msg_extra (dam,
1255                                  attr_len,
1256                                  GNUNET_MESSAGE_TYPE_RECLAIM_ATTESTATION_DELETE);
1257   dam->identity = *pkey;
1258   dam->id = htonl (op->r_id);
1259   GNUNET_RECLAIM_attestation_serialize (attr, (char *) &dam[1]);
1260
1261   dam->attr_len = htons (attr_len);
1262   if (NULL != h->mq)
1263     GNUNET_MQ_send_copy (h->mq, op->env);
1264   return op;
1265 }
1266
1267
1268 /**
1269  * List all attributes for a local identity.
1270  * This MUST lock the `struct GNUNET_RECLAIM_Handle`
1271  * for any other calls than #GNUNET_RECLAIM_get_attributes_next() and
1272  * #GNUNET_RECLAIM_get_attributes_stop. @a proc will be called once
1273  * immediately, and then again after
1274  * #GNUNET_RECLAIM_get_attributes_next() is invoked.
1275  *
1276  * On error (disconnect), @a error_cb will be invoked.
1277  * On normal completion, @a finish_cb proc will be
1278  * invoked.
1279  *
1280  * @param h Handle to the re:claimID service
1281  * @param identity Identity to iterate over
1282  * @param error_cb Function to call on error (i.e. disconnect),
1283  *        the handle is afterwards invalid
1284  * @param error_cb_cls Closure for @a error_cb
1285  * @param proc Function to call on each attribute
1286  * @param proc_cls Closure for @a proc
1287  * @param finish_cb Function to call on completion
1288  *        the handle is afterwards invalid
1289  * @param finish_cb_cls Closure for @a finish_cb
1290  * @return an iterator Handle to use for iteration
1291  */
1292 struct GNUNET_RECLAIM_AttributeIterator *
1293 GNUNET_RECLAIM_get_attributes_start (
1294   struct GNUNET_RECLAIM_Handle *h,
1295   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1296   GNUNET_SCHEDULER_TaskCallback error_cb,
1297   void *error_cb_cls,
1298   GNUNET_RECLAIM_AttributeResult proc,
1299   void *proc_cls,
1300   GNUNET_SCHEDULER_TaskCallback finish_cb,
1301   void *finish_cb_cls)
1302 {
1303   struct GNUNET_RECLAIM_AttributeIterator *it;
1304   struct GNUNET_MQ_Envelope *env;
1305   struct AttributeIterationStartMessage *msg;
1306   uint32_t rid;
1307
1308   rid = h->r_id_gen++;
1309   it = GNUNET_new (struct GNUNET_RECLAIM_AttributeIterator);
1310   it->h = h;
1311   it->error_cb = error_cb;
1312   it->error_cb_cls = error_cb_cls;
1313   it->finish_cb = finish_cb;
1314   it->finish_cb_cls = finish_cb_cls;
1315   it->proc = proc;
1316   it->proc_cls = proc_cls;
1317   it->r_id = rid;
1318   it->identity = *identity;
1319   GNUNET_CONTAINER_DLL_insert_tail (h->it_head, h->it_tail, it);
1320   env =
1321     GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_START);
1322   msg->id = htonl (rid);
1323   msg->identity = *identity;
1324   if (NULL == h->mq)
1325     it->env = env;
1326   else
1327     GNUNET_MQ_send (h->mq, env);
1328   return it;
1329 }
1330
1331
1332 /**
1333  * Calls the record processor specified in #GNUNET_RECLAIM_get_attributes_start
1334  * for the next record.
1335  *
1336  * @param it the iterator
1337  */
1338 void
1339 GNUNET_RECLAIM_get_attributes_next (struct GNUNET_RECLAIM_AttributeIterator *it)
1340 {
1341   struct GNUNET_RECLAIM_Handle *h = it->h;
1342   struct AttributeIterationNextMessage *msg;
1343   struct GNUNET_MQ_Envelope *env;
1344
1345   env =
1346     GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_NEXT);
1347   msg->id = htonl (it->r_id);
1348   GNUNET_MQ_send (h->mq, env);
1349 }
1350
1351
1352 /**
1353  * Stops iteration and releases the handle for further calls. Must
1354  * be called on any iteration that has not yet completed prior to calling
1355  * #GNUNET_RECLAIM_disconnect.
1356  *
1357  * @param it the iterator
1358  */
1359 void
1360 GNUNET_RECLAIM_get_attributes_stop (struct GNUNET_RECLAIM_AttributeIterator *it)
1361 {
1362   struct GNUNET_RECLAIM_Handle *h = it->h;
1363   struct GNUNET_MQ_Envelope *env;
1364   struct AttributeIterationStopMessage *msg;
1365
1366   if (NULL != h->mq)
1367   {
1368     env =
1369       GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_STOP);
1370     msg->id = htonl (it->r_id);
1371     GNUNET_MQ_send (h->mq, env);
1372   }
1373   free_it (it);
1374 }
1375
1376
1377 /**
1378  * List all attestations for a local identity.
1379  * This MUST lock the `struct GNUNET_RECLAIM_Handle`
1380  * for any other calls than #GNUNET_RECLAIM_get_attestations_next() and
1381  * #GNUNET_RECLAIM_get_attestations_stop. @a proc will be called once
1382  * immediately, and then again after
1383  * #GNUNET_RECLAIM_get_attestations_next() is invoked.
1384  *
1385  * On error (disconnect), @a error_cb will be invoked.
1386  * On normal completion, @a finish_cb proc will be
1387  * invoked.
1388  *
1389  * @param h Handle to the re:claimID service
1390  * @param identity Identity to iterate over
1391  * @param error_cb Function to call on error (i.e. disconnect),
1392  *        the handle is afterwards invalid
1393  * @param error_cb_cls Closure for @a error_cb
1394  * @param proc Function to call on each attestation
1395  * @param proc_cls Closure for @a proc
1396  * @param finish_cb Function to call on completion
1397  *        the handle is afterwards invalid
1398  * @param finish_cb_cls Closure for @a finish_cb
1399  * @return an iterator Handle to use for iteration
1400  */
1401 struct GNUNET_RECLAIM_AttestationIterator *
1402 GNUNET_RECLAIM_get_attestations_start (
1403   struct GNUNET_RECLAIM_Handle *h,
1404   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1405   GNUNET_SCHEDULER_TaskCallback error_cb,
1406   void *error_cb_cls,
1407   GNUNET_RECLAIM_AttestationResult proc,
1408   void *proc_cls,
1409   GNUNET_SCHEDULER_TaskCallback finish_cb,
1410   void *finish_cb_cls)
1411 {
1412   struct GNUNET_RECLAIM_AttestationIterator *ait;
1413   struct GNUNET_MQ_Envelope *env;
1414   struct AttestationIterationStartMessage *msg;
1415   uint32_t rid;
1416
1417   rid = h->r_id_gen++;
1418   ait = GNUNET_new (struct GNUNET_RECLAIM_AttestationIterator);
1419   ait->h = h;
1420   ait->error_cb = error_cb;
1421   ait->error_cb_cls = error_cb_cls;
1422   ait->finish_cb = finish_cb;
1423   ait->finish_cb_cls = finish_cb_cls;
1424   ait->proc = proc;
1425   ait->proc_cls = proc_cls;
1426   ait->r_id = rid;
1427   ait->identity = *identity;
1428   GNUNET_CONTAINER_DLL_insert_tail (h->ait_head, h->ait_tail, ait);
1429   env =
1430     GNUNET_MQ_msg (msg,
1431                    GNUNET_MESSAGE_TYPE_RECLAIM_ATTESTATION_ITERATION_START);
1432   msg->id = htonl (rid);
1433   msg->identity = *identity;
1434   if (NULL == h->mq)
1435     ait->env = env;
1436   else
1437     GNUNET_MQ_send (h->mq, env);
1438   return ait;
1439 }
1440
1441
1442 /**
1443  * Calls the record processor specified in #GNUNET_RECLAIM_get_attestation_start
1444  * for the next record.
1445  *
1446  * @param it the iterator
1447  */
1448 void
1449 GNUNET_RECLAIM_get_attestations_next (struct
1450                                       GNUNET_RECLAIM_AttestationIterator *ait)
1451 {
1452   struct GNUNET_RECLAIM_Handle *h = ait->h;
1453   struct AttestationIterationNextMessage *msg;
1454   struct GNUNET_MQ_Envelope *env;
1455
1456   env =
1457     GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_ATTESTATION_ITERATION_NEXT);
1458   msg->id = htonl (ait->r_id);
1459   GNUNET_MQ_send (h->mq, env);
1460 }
1461
1462
1463 /**
1464  * Stops iteration and releases the handle for further calls. Must
1465  * be called on any iteration that has not yet completed prior to calling
1466  * #GNUNET_RECLAIM_disconnect.
1467  *
1468  * @param it the iterator
1469  */
1470 void
1471 GNUNET_RECLAIM_get_attestations_stop (struct
1472                                       GNUNET_RECLAIM_AttestationIterator *ait)
1473 {
1474   struct GNUNET_RECLAIM_Handle *h = ait->h;
1475   struct GNUNET_MQ_Envelope *env;
1476   struct AttestationIterationStopMessage *msg;
1477
1478   if (NULL != h->mq)
1479   {
1480     env =
1481       GNUNET_MQ_msg (msg,
1482                      GNUNET_MESSAGE_TYPE_RECLAIM_ATTESTATION_ITERATION_STOP);
1483     msg->id = htonl (ait->r_id);
1484     GNUNET_MQ_send (h->mq, env);
1485   }
1486   free_ait (ait);
1487 }
1488
1489
1490 /**
1491  * Issues a ticket to another relying party. The identity may use
1492  * @GNUNET_RECLAIM_ticket_consume to consume the ticket
1493  * and retrieve the attributes specified in the attribute list.
1494  *
1495  * @param h the reclaim to use
1496  * @param iss the issuing identity (= the user)
1497  * @param rp the subject of the ticket (= the relying party)
1498  * @param attrs the attributes that the relying party is given access to
1499  * @param cb the callback
1500  * @param cb_cls the callback closure
1501  * @return handle to abort the operation
1502  */
1503 struct GNUNET_RECLAIM_Operation *
1504 GNUNET_RECLAIM_ticket_issue (
1505   struct GNUNET_RECLAIM_Handle *h,
1506   const struct GNUNET_CRYPTO_EcdsaPrivateKey *iss,
1507   const struct GNUNET_CRYPTO_EcdsaPublicKey *rp,
1508   const struct GNUNET_RECLAIM_AttributeList *attrs,
1509   GNUNET_RECLAIM_TicketCallback cb,
1510   void *cb_cls)
1511 {
1512   struct GNUNET_RECLAIM_Operation *op;
1513   struct IssueTicketMessage *tim;
1514   size_t attr_len;
1515
1516   fprintf (stderr, "Issuing ticket\n");
1517   op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
1518   op->h = h;
1519   op->tr_cb = cb;
1520   op->cls = cb_cls;
1521   op->r_id = h->r_id_gen++;
1522   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
1523   attr_len = GNUNET_RECLAIM_attribute_list_serialize_get_size (attrs);
1524   op->env = GNUNET_MQ_msg_extra (tim,
1525                                  attr_len,
1526                                  GNUNET_MESSAGE_TYPE_RECLAIM_ISSUE_TICKET);
1527   tim->identity = *iss;
1528   tim->rp = *rp;
1529   tim->id = htonl (op->r_id);
1530
1531   GNUNET_RECLAIM_attribute_list_serialize (attrs, (char *) &tim[1]);
1532
1533   tim->attr_len = htons (attr_len);
1534   if (NULL != h->mq)
1535     GNUNET_MQ_send_copy (h->mq, op->env);
1536   return op;
1537 }
1538
1539
1540 /**
1541  * Consumes an issued ticket. The ticket is persisted
1542  * and used to retrieve identity information from the issuer
1543  *
1544  * @param h the reclaim to use
1545  * @param identity the identity that is the subject of the issued ticket (the
1546  * relying party)
1547  * @param ticket the issued ticket to consume
1548  * @param cb the callback to call
1549  * @param cb_cls the callback closure
1550  * @return handle to abort the operation
1551  */
1552 struct GNUNET_RECLAIM_Operation *
1553 GNUNET_RECLAIM_ticket_consume (
1554   struct GNUNET_RECLAIM_Handle *h,
1555   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1556   const struct GNUNET_RECLAIM_Ticket *ticket,
1557   GNUNET_RECLAIM_AttributeTicketResult cb,
1558   void *cb_cls)
1559 {
1560   struct GNUNET_RECLAIM_Operation *op;
1561   struct ConsumeTicketMessage *ctm;
1562
1563   op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
1564   op->h = h;
1565   op->atr_cb = cb;
1566   op->cls = cb_cls;
1567   op->r_id = h->r_id_gen++;
1568   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
1569   op->env = GNUNET_MQ_msg (ctm, GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET);
1570   ctm->identity = *identity;
1571   ctm->id = htonl (op->r_id);
1572   ctm->ticket = *ticket;
1573   if (NULL != h->mq)
1574     GNUNET_MQ_send_copy (h->mq, op->env);
1575   return op;
1576 }
1577
1578
1579 /**
1580  * Lists all tickets that have been issued to remote
1581  * identites (relying parties)
1582  *
1583  * @param h the reclaim to use
1584  * @param identity the issuing identity
1585  * @param error_cb function to call on error (i.e. disconnect),
1586  *        the handle is afterwards invalid
1587  * @param error_cb_cls closure for @a error_cb
1588  * @param proc function to call on each ticket; it
1589  *        will be called repeatedly with a value (if available)
1590  * @param proc_cls closure for @a proc
1591  * @param finish_cb function to call on completion
1592  *        the handle is afterwards invalid
1593  * @param finish_cb_cls closure for @a finish_cb
1594  * @return an iterator handle to use for iteration
1595  */
1596 struct GNUNET_RECLAIM_TicketIterator *
1597 GNUNET_RECLAIM_ticket_iteration_start (
1598   struct GNUNET_RECLAIM_Handle *h,
1599   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1600   GNUNET_SCHEDULER_TaskCallback error_cb,
1601   void *error_cb_cls,
1602   GNUNET_RECLAIM_TicketCallback proc,
1603   void *proc_cls,
1604   GNUNET_SCHEDULER_TaskCallback finish_cb,
1605   void *finish_cb_cls)
1606 {
1607   struct GNUNET_RECLAIM_TicketIterator *it;
1608   struct GNUNET_MQ_Envelope *env;
1609   struct TicketIterationStartMessage *msg;
1610   uint32_t rid;
1611
1612   rid = h->r_id_gen++;
1613   it = GNUNET_new (struct GNUNET_RECLAIM_TicketIterator);
1614   it->h = h;
1615   it->error_cb = error_cb;
1616   it->error_cb_cls = error_cb_cls;
1617   it->finish_cb = finish_cb;
1618   it->finish_cb_cls = finish_cb_cls;
1619   it->tr_cb = proc;
1620   it->cls = proc_cls;
1621   it->r_id = rid;
1622   GNUNET_CONTAINER_DLL_insert_tail (h->ticket_it_head, h->ticket_it_tail, it);
1623   env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_START);
1624   msg->id = htonl (rid);
1625   msg->identity = *identity;
1626   if (NULL == h->mq)
1627     it->env = env;
1628   else
1629     GNUNET_MQ_send (h->mq, env);
1630   return it;
1631 }
1632
1633
1634 /**
1635  * Calls the ticket processor specified in
1636  * #GNUNET_RECLAIM_ticket_iteration_start for the next record.
1637  *
1638  * @param it the iterator
1639  */
1640 void
1641 GNUNET_RECLAIM_ticket_iteration_next (struct GNUNET_RECLAIM_TicketIterator *it)
1642 {
1643   struct GNUNET_RECLAIM_Handle *h = it->h;
1644   struct TicketIterationNextMessage *msg;
1645   struct GNUNET_MQ_Envelope *env;
1646
1647   env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_NEXT);
1648   msg->id = htonl (it->r_id);
1649   GNUNET_MQ_send (h->mq, env);
1650 }
1651
1652
1653 /**
1654  * Stops iteration and releases the handle for further calls.  Must
1655  * be called on any iteration that has not yet completed prior to calling
1656  * #GNUNET_RECLAIM_disconnect.
1657  *
1658  * @param it the iterator
1659  */
1660 void
1661 GNUNET_RECLAIM_ticket_iteration_stop (struct GNUNET_RECLAIM_TicketIterator *it)
1662 {
1663   struct GNUNET_RECLAIM_Handle *h = it->h;
1664   struct GNUNET_MQ_Envelope *env;
1665   struct TicketIterationStopMessage *msg;
1666
1667   if (NULL != h->mq)
1668   {
1669     env =
1670       GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_STOP);
1671     msg->id = htonl (it->r_id);
1672     GNUNET_MQ_send (h->mq, env);
1673   }
1674   GNUNET_free (it);
1675 }
1676
1677
1678 /**
1679  * Revoked an issued ticket. The relying party will be unable to retrieve
1680  * attributes. Other issued tickets remain unaffected.
1681  * This includes tickets issued to other relying parties as well as to
1682  * other tickets issued to the audience specified in this ticket.
1683  *
1684  * @param h the identity provider to use
1685  * @param identity the issuing identity
1686  * @param ticket the ticket to revoke
1687  * @param cb the callback
1688  * @param cb_cls the callback closure
1689  * @return handle to abort the operation
1690  */
1691 struct GNUNET_RECLAIM_Operation *
1692 GNUNET_RECLAIM_ticket_revoke (
1693   struct GNUNET_RECLAIM_Handle *h,
1694   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1695   const struct GNUNET_RECLAIM_Ticket *ticket,
1696   GNUNET_RECLAIM_ContinuationWithStatus cb,
1697   void *cb_cls)
1698 {
1699   struct GNUNET_RECLAIM_Operation *op;
1700   struct RevokeTicketMessage *msg;
1701   uint32_t rid;
1702
1703   rid = h->r_id_gen++;
1704   op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
1705   op->h = h;
1706   op->rvk_cb = cb;
1707   op->cls = cb_cls;
1708   op->r_id = rid;
1709   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
1710   op->env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET);
1711   msg->id = htonl (rid);
1712   msg->identity = *identity;
1713   msg->ticket = *ticket;
1714   if (NULL != h->mq)
1715   {
1716     GNUNET_MQ_send (h->mq, op->env);
1717     op->env = NULL;
1718   }
1719   return op;
1720 }
1721
1722
1723 /* end of reclaim_api.c */