obsolete due to alpine policy
[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_attribute_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    * Revocation result callback
76    */
77   GNUNET_RECLAIM_ContinuationWithStatus rvk_cb;
78
79   /**
80    * Ticket result callback
81    */
82   GNUNET_RECLAIM_TicketCallback tr_cb;
83
84   /**
85    * Envelope with the message for this queue entry.
86    */
87   struct GNUNET_MQ_Envelope *env;
88
89   /**
90    * request id
91    */
92   uint32_t r_id;
93
94   /**
95    * Closure for @e cont or @e cb.
96    */
97   void *cls;
98 };
99
100
101 /**
102  * Handle for a ticket iterator operation
103  */
104 struct GNUNET_RECLAIM_TicketIterator
105 {
106   /**
107    * Kept in a DLL.
108    */
109   struct GNUNET_RECLAIM_TicketIterator *next;
110
111   /**
112    * Kept in a DLL.
113    */
114   struct GNUNET_RECLAIM_TicketIterator *prev;
115
116   /**
117    * Main handle to access the idp.
118    */
119   struct GNUNET_RECLAIM_Handle *h;
120
121   /**
122    * Function to call on completion.
123    */
124   GNUNET_SCHEDULER_TaskCallback finish_cb;
125
126   /**
127    * Closure for @e finish_cb.
128    */
129   void *finish_cb_cls;
130
131   /**
132    * The continuation to call with the results
133    */
134   GNUNET_RECLAIM_TicketCallback tr_cb;
135
136   /**
137    * Closure for @e tr_cb.
138    */
139   void *cls;
140
141   /**
142    * Function to call on errors.
143    */
144   GNUNET_SCHEDULER_TaskCallback error_cb;
145
146   /**
147    * Closure for @e error_cb.
148    */
149   void *error_cb_cls;
150
151   /**
152    * Envelope of the message to send to the service, if not yet
153    * sent.
154    */
155   struct GNUNET_MQ_Envelope *env;
156
157   /**
158    * The operation id this zone iteration operation has
159    */
160   uint32_t r_id;
161 };
162
163
164 /**
165  * Handle for a attribute iterator operation
166  */
167 struct GNUNET_RECLAIM_AttributeIterator
168 {
169   /**
170    * Kept in a DLL.
171    */
172   struct GNUNET_RECLAIM_AttributeIterator *next;
173
174   /**
175    * Kept in a DLL.
176    */
177   struct GNUNET_RECLAIM_AttributeIterator *prev;
178
179   /**
180    * Main handle to access the service.
181    */
182   struct GNUNET_RECLAIM_Handle *h;
183
184   /**
185    * Function to call on completion.
186    */
187   GNUNET_SCHEDULER_TaskCallback finish_cb;
188
189   /**
190    * Closure for @e finish_cb.
191    */
192   void *finish_cb_cls;
193
194   /**
195    * The continuation to call with the results
196    */
197   GNUNET_RECLAIM_AttributeResult proc;
198
199   /**
200    * Closure for @e proc.
201    */
202   void *proc_cls;
203
204   /**
205    * Function to call on errors.
206    */
207   GNUNET_SCHEDULER_TaskCallback error_cb;
208
209   /**
210    * Closure for @e error_cb.
211    */
212   void *error_cb_cls;
213
214   /**
215    * Envelope of the message to send to the service, if not yet
216    * sent.
217    */
218   struct GNUNET_MQ_Envelope *env;
219
220   /**
221    * Private key of the zone.
222    */
223   struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
224
225   /**
226    * The operation id this zone iteration operation has
227    */
228   uint32_t r_id;
229 };
230
231
232 /**
233  * Handle to the service.
234  */
235 struct GNUNET_RECLAIM_Handle
236 {
237   /**
238    * Configuration to use.
239    */
240   const struct GNUNET_CONFIGURATION_Handle *cfg;
241
242   /**
243    * Socket (if available).
244    */
245   struct GNUNET_CLIENT_Connection *client;
246
247   /**
248    * Closure for 'cb'.
249    */
250   void *cb_cls;
251
252   /**
253    * Head of active operations.
254    */
255   struct GNUNET_RECLAIM_Operation *op_head;
256
257   /**
258    * Tail of active operations.
259    */
260   struct GNUNET_RECLAIM_Operation *op_tail;
261
262   /**
263    * Head of active iterations
264    */
265   struct GNUNET_RECLAIM_AttributeIterator *it_head;
266
267   /**
268    * Tail of active iterations
269    */
270   struct GNUNET_RECLAIM_AttributeIterator *it_tail;
271
272   /**
273    * Head of active iterations
274    */
275   struct GNUNET_RECLAIM_TicketIterator *ticket_it_head;
276
277   /**
278    * Tail of active iterations
279    */
280   struct GNUNET_RECLAIM_TicketIterator *ticket_it_tail;
281
282   /**
283    * Currently pending transmission request, or NULL for none.
284    */
285   struct GNUNET_CLIENT_TransmitHandle *th;
286
287   /**
288    * Task doing exponential back-off trying to reconnect.
289    */
290   struct GNUNET_SCHEDULER_Task *reconnect_task;
291
292   /**
293    * Time for next connect retry.
294    */
295   struct GNUNET_TIME_Relative reconnect_backoff;
296
297   /**
298    * Connection to service (if available).
299    */
300   struct GNUNET_MQ_Handle *mq;
301
302   /**
303    * Request Id generator.  Incremented by one for each request.
304    */
305   uint32_t r_id_gen;
306
307   /**
308    * Are we polling for incoming messages right now?
309    */
310   int in_receive;
311 };
312
313
314 /**
315  * Try again to connect to the service.
316  *
317  * @param h handle to the reclaim service.
318  */
319 static void
320 reconnect (struct GNUNET_RECLAIM_Handle *h);
321
322
323 /**
324  * Reconnect
325  *
326  * @param cls the handle
327  */
328 static void
329 reconnect_task (void *cls)
330 {
331   struct GNUNET_RECLAIM_Handle *handle = cls;
332
333   handle->reconnect_task = NULL;
334   reconnect (handle);
335 }
336
337
338 /**
339  * Disconnect from service and then reconnect.
340  *
341  * @param handle our service
342  */
343 static void
344 force_reconnect (struct GNUNET_RECLAIM_Handle *handle)
345 {
346   GNUNET_MQ_destroy (handle->mq);
347   handle->mq = NULL;
348   handle->reconnect_backoff =
349     GNUNET_TIME_STD_BACKOFF (handle->reconnect_backoff);
350   handle->reconnect_task =
351     GNUNET_SCHEDULER_add_delayed (handle->reconnect_backoff,
352                                   &reconnect_task,
353                                   handle);
354 }
355
356
357 /**
358  * Free @a it.
359  *
360  * @param it entry to free
361  */
362 static void
363 free_it (struct GNUNET_RECLAIM_AttributeIterator *it)
364 {
365   struct GNUNET_RECLAIM_Handle *h = it->h;
366
367   GNUNET_CONTAINER_DLL_remove (h->it_head, h->it_tail, it);
368   if (NULL != it->env)
369     GNUNET_MQ_discard (it->env);
370   GNUNET_free (it);
371 }
372
373 /**
374  * Free @a op
375  *
376  * @param op the operation to free
377  */
378 static void
379 free_op (struct GNUNET_RECLAIM_Operation *op)
380 {
381   if (NULL == op)
382     return;
383   if (NULL != op->env)
384     GNUNET_MQ_discard (op->env);
385   GNUNET_free (op);
386 }
387
388
389 /**
390  * Generic error handler, called with the appropriate error code and
391  * the same closure specified at the creation of the message queue.
392  * Not every message queue implementation supports an error handler.
393  *
394  * @param cls closure with the `struct GNUNET_GNS_Handle *`
395  * @param error error code
396  */
397 static void
398 mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
399 {
400   struct GNUNET_RECLAIM_Handle *handle = cls;
401
402   force_reconnect (handle);
403 }
404
405
406 /**
407  * Handle an incoming message of type
408  * #GNUNET_MESSAGE_TYPE_RECLAIM_SUCCESS_RESPONSE
409  *
410  * @param cls
411  * @param msg the message we received
412  */
413 static void
414 handle_success_response (void *cls, const struct SuccessResultMessage *msg)
415 {
416   struct GNUNET_RECLAIM_Handle *h = cls;
417   struct GNUNET_RECLAIM_Operation *op;
418   uint32_t r_id = ntohl (msg->id);
419   int res;
420   const char *emsg;
421
422   for (op = h->op_head; NULL != op; op = op->next)
423     if (op->r_id == r_id)
424       break;
425   if (NULL == op)
426     return;
427
428   res = ntohl (msg->op_result);
429   LOG (GNUNET_ERROR_TYPE_DEBUG,
430        "Received SUCCESS_RESPONSE with result %d\n",
431        res);
432
433   /* TODO: add actual error message to response... */
434   if (GNUNET_SYSERR == res)
435     emsg = _ ("failed to store record\n");
436   else
437     emsg = NULL;
438   if (NULL != op->as_cb)
439     op->as_cb (op->cls, res, emsg);
440   GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
441   free_op (op);
442 }
443
444
445 /**
446  * Handle an incoming message of type
447  * #GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT
448  *
449  * @param cls
450  * @param msg the message we received
451  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
452  */
453 static int
454 check_consume_ticket_result (void *cls,
455                              const struct ConsumeTicketResultMessage *msg)
456 {
457   size_t msg_len;
458   size_t attrs_len;
459
460   msg_len = ntohs (msg->header.size);
461   attrs_len = ntohs (msg->attrs_len);
462   if (msg_len != sizeof(struct ConsumeTicketResultMessage) + attrs_len)
463   {
464     GNUNET_break (0);
465     return GNUNET_SYSERR;
466   }
467   return GNUNET_OK;
468 }
469
470
471 /**
472  * Handle an incoming message of type
473  * #GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT
474  *
475  * @param cls
476  * @param msg the message we received
477  */
478 static void
479 handle_consume_ticket_result (void *cls,
480                               const struct ConsumeTicketResultMessage *msg)
481 {
482   struct GNUNET_RECLAIM_Handle *h = cls;
483   struct GNUNET_RECLAIM_Operation *op;
484   size_t attrs_len;
485   uint32_t r_id = ntohl (msg->id);
486
487   attrs_len = ntohs (msg->attrs_len);
488   LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing attribute result.\n");
489
490
491   for (op = h->op_head; NULL != op; op = op->next)
492     if (op->r_id == r_id)
493       break;
494   if (NULL == op)
495     return;
496
497   {
498     struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs;
499     struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
500     attrs =
501       GNUNET_RECLAIM_ATTRIBUTE_list_deserialize ((char *) &msg[1], attrs_len);
502     if (NULL != op->ar_cb)
503     {
504       if (NULL == attrs)
505       {
506         op->ar_cb (op->cls, &msg->identity, NULL);
507       }
508       else
509       {
510         for (le = attrs->list_head; NULL != le; le = le->next)
511           op->ar_cb (op->cls, &msg->identity, le->claim);
512         GNUNET_RECLAIM_ATTRIBUTE_list_destroy (attrs);
513         attrs = NULL;
514       }
515       op->ar_cb (op->cls, NULL, NULL);
516     }
517     GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
518     free_op (op);
519     GNUNET_free_non_null (attrs);
520     return;
521   }
522   GNUNET_assert (0);
523 }
524
525
526 /**
527  * Handle an incoming message of type
528  * #GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT
529  *
530  * @param cls
531  * @param msg the message we received
532  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
533  */
534 static int
535 check_attribute_result (void *cls, const struct AttributeResultMessage *msg)
536 {
537   size_t msg_len;
538   size_t attr_len;
539
540   msg_len = ntohs (msg->header.size);
541   attr_len = ntohs (msg->attr_len);
542   if (msg_len != sizeof(struct AttributeResultMessage) + attr_len)
543   {
544     GNUNET_break (0);
545     return GNUNET_SYSERR;
546   }
547   return GNUNET_OK;
548 }
549
550
551 /**
552  * Handle an incoming message of type
553  * #GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT
554  *
555  * @param cls
556  * @param msg the message we received
557  */
558 static void
559 handle_attribute_result (void *cls, const struct AttributeResultMessage *msg)
560 {
561   static struct GNUNET_CRYPTO_EcdsaPrivateKey identity_dummy;
562   struct GNUNET_RECLAIM_Handle *h = cls;
563   struct GNUNET_RECLAIM_AttributeIterator *it;
564   struct GNUNET_RECLAIM_Operation *op;
565   size_t attr_len;
566   uint32_t r_id = ntohl (msg->id);
567
568   attr_len = ntohs (msg->attr_len);
569   LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing attribute result.\n");
570
571
572   for (it = h->it_head; NULL != it; it = it->next)
573     if (it->r_id == r_id)
574       break;
575   for (op = h->op_head; NULL != op; op = op->next)
576     if (op->r_id == r_id)
577       break;
578   if ((NULL == it) && (NULL == op))
579     return;
580
581   if ((0 ==
582        (memcmp (&msg->identity, &identity_dummy, sizeof(identity_dummy)))))
583   {
584     if ((NULL == it) && (NULL == op))
585     {
586       GNUNET_break (0);
587       force_reconnect (h);
588       return;
589     }
590     if (NULL != it)
591     {
592       if (NULL != it->finish_cb)
593         it->finish_cb (it->finish_cb_cls);
594       free_it (it);
595     }
596     if (NULL != op)
597     {
598       if (NULL != op->ar_cb)
599         op->ar_cb (op->cls, NULL, NULL);
600       GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
601       free_op (op);
602     }
603     return;
604   }
605
606   {
607     struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr;
608     attr = GNUNET_RECLAIM_ATTRIBUTE_deserialize ((char *) &msg[1], attr_len);
609     if (NULL != it)
610     {
611       if (NULL != it->proc)
612         it->proc (it->proc_cls, &msg->identity, attr);
613     }
614     else if (NULL != op)
615     {
616       if (NULL != op->ar_cb)
617         op->ar_cb (op->cls, &msg->identity, attr);
618     }
619     GNUNET_free (attr);
620     return;
621   }
622   GNUNET_assert (0);
623 }
624
625
626 /**
627  * Handle an incoming message of type
628  * #GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT
629  *
630  * @param cls
631  * @param msg the message we received
632  */
633 static void
634 handle_ticket_result (void *cls, const struct TicketResultMessage *msg)
635 {
636   struct GNUNET_RECLAIM_Handle *handle = cls;
637   struct GNUNET_RECLAIM_Operation *op;
638   struct GNUNET_RECLAIM_TicketIterator *it;
639   uint32_t r_id = ntohl (msg->id);
640   static const struct GNUNET_RECLAIM_Ticket ticket;
641
642   for (op = handle->op_head; NULL != op; op = op->next)
643     if (op->r_id == r_id)
644       break;
645   for (it = handle->ticket_it_head; NULL != it; it = it->next)
646     if (it->r_id == r_id)
647       break;
648   if ((NULL == op) && (NULL == it))
649     return;
650   if (NULL != op)
651   {
652     GNUNET_CONTAINER_DLL_remove (handle->op_head, handle->op_tail, op);
653     if (0 ==
654         memcmp (&msg->ticket, &ticket, sizeof(struct GNUNET_RECLAIM_Ticket)))
655     {
656       if (NULL != op->tr_cb)
657         op->tr_cb (op->cls, NULL);
658     }
659     else
660     {
661       if (NULL != op->tr_cb)
662         op->tr_cb (op->cls, &msg->ticket);
663     }
664     free_op (op);
665     return;
666   }
667   else if (NULL != it)
668   {
669     if (0 ==
670         memcmp (&msg->ticket, &ticket, sizeof(struct GNUNET_RECLAIM_Ticket)))
671     {
672       GNUNET_CONTAINER_DLL_remove (handle->ticket_it_head,
673                                    handle->ticket_it_tail,
674                                    it);
675       it->finish_cb (it->finish_cb_cls);
676       GNUNET_free (it);
677     }
678     else
679     {
680       if (NULL != it->tr_cb)
681         it->tr_cb (it->cls, &msg->ticket);
682     }
683     return;
684   }
685   GNUNET_break (0);
686 }
687
688
689 /**
690  * Handle an incoming message of type
691  * #GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET_RESULT
692  *
693  * @param cls
694  * @param msg the message we received
695  */
696 static void
697 handle_revoke_ticket_result (void *cls,
698                              const struct RevokeTicketResultMessage *msg)
699 {
700   struct GNUNET_RECLAIM_Handle *h = cls;
701   struct GNUNET_RECLAIM_Operation *op;
702   uint32_t r_id = ntohl (msg->id);
703   int32_t success;
704
705   LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing revocation result.\n");
706
707
708   for (op = h->op_head; NULL != op; op = op->next)
709     if (op->r_id == r_id)
710       break;
711   if (NULL == op)
712     return;
713   success = ntohl (msg->success);
714   {
715     if (NULL != op->rvk_cb)
716     {
717       op->rvk_cb (op->cls, success, NULL);
718     }
719     GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
720     free_op (op);
721     return;
722   }
723   GNUNET_assert (0);
724 }
725
726
727 /**
728  * Try again to connect to the service.
729  *
730  * @param h handle to the reclaim service.
731  */
732 static void
733 reconnect (struct GNUNET_RECLAIM_Handle *h)
734 {
735   struct GNUNET_MQ_MessageHandler handlers[] =
736   { GNUNET_MQ_hd_fixed_size (success_response,
737                              GNUNET_MESSAGE_TYPE_RECLAIM_SUCCESS_RESPONSE,
738                              struct SuccessResultMessage,
739                              h),
740     GNUNET_MQ_hd_var_size (attribute_result,
741                            GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT,
742                            struct AttributeResultMessage,
743                            h),
744     GNUNET_MQ_hd_fixed_size (ticket_result,
745                              GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT,
746                              struct TicketResultMessage,
747                              h),
748     GNUNET_MQ_hd_var_size (consume_ticket_result,
749                            GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT,
750                            struct ConsumeTicketResultMessage,
751                            h),
752     GNUNET_MQ_hd_fixed_size (revoke_ticket_result,
753                              GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET_RESULT,
754                              struct RevokeTicketResultMessage,
755                              h),
756     GNUNET_MQ_handler_end () };
757   struct GNUNET_RECLAIM_Operation *op;
758
759   GNUNET_assert (NULL == h->mq);
760   LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to reclaim service.\n");
761
762   h->mq =
763     GNUNET_CLIENT_connect (h->cfg, "reclaim", handlers, &mq_error_handler, h);
764   if (NULL == h->mq)
765     return;
766   for (op = h->op_head; NULL != op; op = op->next)
767     GNUNET_MQ_send_copy (h->mq, op->env);
768 }
769
770
771 /**
772  * Connect to the reclaim service.
773  *
774  * @param cfg the configuration to use
775  * @return handle to use
776  */
777 struct GNUNET_RECLAIM_Handle *
778 GNUNET_RECLAIM_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
779 {
780   struct GNUNET_RECLAIM_Handle *h;
781
782   h = GNUNET_new (struct GNUNET_RECLAIM_Handle);
783   h->cfg = cfg;
784   reconnect (h);
785   if (NULL == h->mq)
786   {
787     GNUNET_free (h);
788     return NULL;
789   }
790   return h;
791 }
792
793
794 /**
795  * Cancel an operation. Note that the operation MAY still
796  * be executed; this merely cancels the continuation; if the request
797  * was already transmitted, the service may still choose to complete
798  * the operation.
799  *
800  * @param op operation to cancel
801  */
802 void
803 GNUNET_RECLAIM_cancel (struct GNUNET_RECLAIM_Operation *op)
804 {
805   struct GNUNET_RECLAIM_Handle *h = op->h;
806
807   GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
808   free_op (op);
809 }
810
811
812 /**
813  * Disconnect from service
814  *
815  * @param h handle to destroy
816  */
817 void
818 GNUNET_RECLAIM_disconnect (struct GNUNET_RECLAIM_Handle *h)
819 {
820   GNUNET_assert (NULL != h);
821   if (NULL != h->mq)
822   {
823     GNUNET_MQ_destroy (h->mq);
824     h->mq = NULL;
825   }
826   if (NULL != h->reconnect_task)
827   {
828     GNUNET_SCHEDULER_cancel (h->reconnect_task);
829     h->reconnect_task = NULL;
830   }
831   GNUNET_assert (NULL == h->op_head);
832   GNUNET_free (h);
833 }
834
835 /**
836  * Store an attribute.  If the attribute is already present,
837  * it is replaced with the new attribute.
838  *
839  * @param h handle to the re:claimID service
840  * @param pkey private key of the identity
841  * @param attr the attribute value
842  * @param exp_interval the relative expiration interval for the attribute
843  * @param cont continuation to call when done
844  * @param cont_cls closure for @a cont
845  * @return handle to abort the request
846  */
847 struct GNUNET_RECLAIM_Operation *
848 GNUNET_RECLAIM_attribute_store (
849   struct GNUNET_RECLAIM_Handle *h,
850   const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey,
851   const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr,
852   const struct GNUNET_TIME_Relative *exp_interval,
853   GNUNET_RECLAIM_ContinuationWithStatus cont,
854   void *cont_cls)
855 {
856   struct GNUNET_RECLAIM_Operation *op;
857   struct AttributeStoreMessage *sam;
858   size_t attr_len;
859
860   op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
861   op->h = h;
862   op->as_cb = cont;
863   op->cls = cont_cls;
864   op->r_id = h->r_id_gen++;
865   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
866   attr_len = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (attr);
867   op->env = GNUNET_MQ_msg_extra (sam,
868                                  attr_len,
869                                  GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_STORE);
870   sam->identity = *pkey;
871   sam->id = htonl (op->r_id);
872   sam->exp = GNUNET_htonll (exp_interval->rel_value_us);
873
874   GNUNET_RECLAIM_ATTRIBUTE_serialize (attr, (char *) &sam[1]);
875
876   sam->attr_len = htons (attr_len);
877   if (NULL != h->mq)
878     GNUNET_MQ_send_copy (h->mq, op->env);
879   return op;
880 }
881
882
883 /**
884  * Delete an attribute. Tickets used to share this attribute are updated
885  * accordingly.
886  *
887  * @param h handle to the re:claimID service
888  * @param pkey Private key of the identity to add an attribute to
889  * @param attr The attribute
890  * @param cont Continuation to call when done
891  * @param cont_cls Closure for @a cont
892  * @return handle Used to to abort the request
893  */
894 struct GNUNET_RECLAIM_Operation *
895 GNUNET_RECLAIM_attribute_delete (
896   struct GNUNET_RECLAIM_Handle *h,
897   const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey,
898   const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr,
899   GNUNET_RECLAIM_ContinuationWithStatus cont,
900   void *cont_cls)
901 {
902   struct GNUNET_RECLAIM_Operation *op;
903   struct AttributeDeleteMessage *dam;
904   size_t attr_len;
905
906   op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
907   op->h = h;
908   op->as_cb = cont;
909   op->cls = cont_cls;
910   op->r_id = h->r_id_gen++;
911   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
912   attr_len = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (attr);
913   op->env = GNUNET_MQ_msg_extra (dam,
914                                  attr_len,
915                                  GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_DELETE);
916   dam->identity = *pkey;
917   dam->id = htonl (op->r_id);
918   GNUNET_RECLAIM_ATTRIBUTE_serialize (attr, (char *) &dam[1]);
919
920   dam->attr_len = htons (attr_len);
921   if (NULL != h->mq)
922     GNUNET_MQ_send_copy (h->mq, op->env);
923   return op;
924 }
925
926
927 /**
928  * List all attributes for a local identity.
929  * This MUST lock the `struct GNUNET_RECLAIM_Handle`
930  * for any other calls than #GNUNET_RECLAIM_get_attributes_next() and
931  * #GNUNET_RECLAIM_get_attributes_stop. @a proc will be called once
932  * immediately, and then again after
933  * #GNUNET_RECLAIM_get_attributes_next() is invoked.
934  *
935  * On error (disconnect), @a error_cb will be invoked.
936  * On normal completion, @a finish_cb proc will be
937  * invoked.
938  *
939  * @param h Handle to the re:claimID service
940  * @param identity Identity to iterate over
941  * @param error_cb Function to call on error (i.e. disconnect),
942  *        the handle is afterwards invalid
943  * @param error_cb_cls Closure for @a error_cb
944  * @param proc Function to call on each attribute
945  * @param proc_cls Closure for @a proc
946  * @param finish_cb Function to call on completion
947  *        the handle is afterwards invalid
948  * @param finish_cb_cls Closure for @a finish_cb
949  * @return an iterator Handle to use for iteration
950  */
951 struct GNUNET_RECLAIM_AttributeIterator *
952 GNUNET_RECLAIM_get_attributes_start (
953   struct GNUNET_RECLAIM_Handle *h,
954   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
955   GNUNET_SCHEDULER_TaskCallback error_cb,
956   void *error_cb_cls,
957   GNUNET_RECLAIM_AttributeResult proc,
958   void *proc_cls,
959   GNUNET_SCHEDULER_TaskCallback finish_cb,
960   void *finish_cb_cls)
961 {
962   struct GNUNET_RECLAIM_AttributeIterator *it;
963   struct GNUNET_MQ_Envelope *env;
964   struct AttributeIterationStartMessage *msg;
965   uint32_t rid;
966
967   rid = h->r_id_gen++;
968   it = GNUNET_new (struct GNUNET_RECLAIM_AttributeIterator);
969   it->h = h;
970   it->error_cb = error_cb;
971   it->error_cb_cls = error_cb_cls;
972   it->finish_cb = finish_cb;
973   it->finish_cb_cls = finish_cb_cls;
974   it->proc = proc;
975   it->proc_cls = proc_cls;
976   it->r_id = rid;
977   it->identity = *identity;
978   GNUNET_CONTAINER_DLL_insert_tail (h->it_head, h->it_tail, it);
979   env =
980     GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_START);
981   msg->id = htonl (rid);
982   msg->identity = *identity;
983   if (NULL == h->mq)
984     it->env = env;
985   else
986     GNUNET_MQ_send (h->mq, env);
987   return it;
988 }
989
990
991 /**
992  * Calls the record processor specified in #GNUNET_RECLAIM_get_attributes_start
993  * for the next record.
994  *
995  * @param it the iterator
996  */
997 void
998 GNUNET_RECLAIM_get_attributes_next (struct GNUNET_RECLAIM_AttributeIterator *it)
999 {
1000   struct GNUNET_RECLAIM_Handle *h = it->h;
1001   struct AttributeIterationNextMessage *msg;
1002   struct GNUNET_MQ_Envelope *env;
1003
1004   env =
1005     GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_NEXT);
1006   msg->id = htonl (it->r_id);
1007   GNUNET_MQ_send (h->mq, env);
1008 }
1009
1010
1011 /**
1012  * Stops iteration and releases the handle for further calls. Must
1013  * be called on any iteration that has not yet completed prior to calling
1014  * #GNUNET_RECLAIM_disconnect.
1015  *
1016  * @param it the iterator
1017  */
1018 void
1019 GNUNET_RECLAIM_get_attributes_stop (struct GNUNET_RECLAIM_AttributeIterator *it)
1020 {
1021   struct GNUNET_RECLAIM_Handle *h = it->h;
1022   struct GNUNET_MQ_Envelope *env;
1023   struct AttributeIterationStopMessage *msg;
1024
1025   if (NULL != h->mq)
1026   {
1027     env =
1028       GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_STOP);
1029     msg->id = htonl (it->r_id);
1030     GNUNET_MQ_send (h->mq, env);
1031   }
1032   free_it (it);
1033 }
1034
1035
1036 /**
1037  * Issues a ticket to another relying party. The identity may use
1038  * @GNUNET_RECLAIM_ticket_consume to consume the ticket
1039  * and retrieve the attributes specified in the attribute list.
1040  *
1041  * @param h the reclaim to use
1042  * @param iss the issuing identity (= the user)
1043  * @param rp the subject of the ticket (= the relying party)
1044  * @param attrs the attributes that the relying party is given access to
1045  * @param cb the callback
1046  * @param cb_cls the callback closure
1047  * @return handle to abort the operation
1048  */
1049 struct GNUNET_RECLAIM_Operation *
1050 GNUNET_RECLAIM_ticket_issue (
1051   struct GNUNET_RECLAIM_Handle *h,
1052   const struct GNUNET_CRYPTO_EcdsaPrivateKey *iss,
1053   const struct GNUNET_CRYPTO_EcdsaPublicKey *rp,
1054   const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
1055   GNUNET_RECLAIM_TicketCallback cb,
1056   void *cb_cls)
1057 {
1058   struct GNUNET_RECLAIM_Operation *op;
1059   struct IssueTicketMessage *tim;
1060   size_t attr_len;
1061
1062   fprintf (stderr, "Issuing ticket\n");
1063   op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
1064   op->h = h;
1065   op->tr_cb = cb;
1066   op->cls = cb_cls;
1067   op->r_id = h->r_id_gen++;
1068   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
1069   attr_len = GNUNET_RECLAIM_ATTRIBUTE_list_serialize_get_size (attrs);
1070   op->env = GNUNET_MQ_msg_extra (tim,
1071                                  attr_len,
1072                                  GNUNET_MESSAGE_TYPE_RECLAIM_ISSUE_TICKET);
1073   tim->identity = *iss;
1074   tim->rp = *rp;
1075   tim->id = htonl (op->r_id);
1076
1077   GNUNET_RECLAIM_ATTRIBUTE_list_serialize (attrs, (char *) &tim[1]);
1078
1079   tim->attr_len = htons (attr_len);
1080   if (NULL != h->mq)
1081     GNUNET_MQ_send_copy (h->mq, op->env);
1082   return op;
1083 }
1084
1085
1086 /**
1087  * Consumes an issued ticket. The ticket is persisted
1088  * and used to retrieve identity information from the issuer
1089  *
1090  * @param h the reclaim to use
1091  * @param identity the identity that is the subject of the issued ticket (the
1092  * relying party)
1093  * @param ticket the issued ticket to consume
1094  * @param cb the callback to call
1095  * @param cb_cls the callback closure
1096  * @return handle to abort the operation
1097  */
1098 struct GNUNET_RECLAIM_Operation *
1099 GNUNET_RECLAIM_ticket_consume (
1100   struct GNUNET_RECLAIM_Handle *h,
1101   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1102   const struct GNUNET_RECLAIM_Ticket *ticket,
1103   GNUNET_RECLAIM_AttributeResult cb,
1104   void *cb_cls)
1105 {
1106   struct GNUNET_RECLAIM_Operation *op;
1107   struct ConsumeTicketMessage *ctm;
1108
1109   op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
1110   op->h = h;
1111   op->ar_cb = cb;
1112   op->cls = cb_cls;
1113   op->r_id = h->r_id_gen++;
1114   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
1115   op->env = GNUNET_MQ_msg (ctm, GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET);
1116   ctm->identity = *identity;
1117   ctm->id = htonl (op->r_id);
1118   ctm->ticket = *ticket;
1119   if (NULL != h->mq)
1120     GNUNET_MQ_send_copy (h->mq, op->env);
1121   return op;
1122 }
1123
1124
1125 /**
1126  * Lists all tickets that have been issued to remote
1127  * identites (relying parties)
1128  *
1129  * @param h the reclaim to use
1130  * @param identity the issuing identity
1131  * @param error_cb function to call on error (i.e. disconnect),
1132  *        the handle is afterwards invalid
1133  * @param error_cb_cls closure for @a error_cb
1134  * @param proc function to call on each ticket; it
1135  *        will be called repeatedly with a value (if available)
1136  * @param proc_cls closure for @a proc
1137  * @param finish_cb function to call on completion
1138  *        the handle is afterwards invalid
1139  * @param finish_cb_cls closure for @a finish_cb
1140  * @return an iterator handle to use for iteration
1141  */
1142 struct GNUNET_RECLAIM_TicketIterator *
1143 GNUNET_RECLAIM_ticket_iteration_start (
1144   struct GNUNET_RECLAIM_Handle *h,
1145   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1146   GNUNET_SCHEDULER_TaskCallback error_cb,
1147   void *error_cb_cls,
1148   GNUNET_RECLAIM_TicketCallback proc,
1149   void *proc_cls,
1150   GNUNET_SCHEDULER_TaskCallback finish_cb,
1151   void *finish_cb_cls)
1152 {
1153   struct GNUNET_RECLAIM_TicketIterator *it;
1154   struct GNUNET_MQ_Envelope *env;
1155   struct TicketIterationStartMessage *msg;
1156   uint32_t rid;
1157
1158   rid = h->r_id_gen++;
1159   it = GNUNET_new (struct GNUNET_RECLAIM_TicketIterator);
1160   it->h = h;
1161   it->error_cb = error_cb;
1162   it->error_cb_cls = error_cb_cls;
1163   it->finish_cb = finish_cb;
1164   it->finish_cb_cls = finish_cb_cls;
1165   it->tr_cb = proc;
1166   it->cls = proc_cls;
1167   it->r_id = rid;
1168   GNUNET_CONTAINER_DLL_insert_tail (h->ticket_it_head, h->ticket_it_tail, it);
1169   env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_START);
1170   msg->id = htonl (rid);
1171   msg->identity = *identity;
1172   if (NULL == h->mq)
1173     it->env = env;
1174   else
1175     GNUNET_MQ_send (h->mq, env);
1176   return it;
1177 }
1178
1179
1180 /**
1181  * Calls the ticket processor specified in
1182  * #GNUNET_RECLAIM_ticket_iteration_start for the next record.
1183  *
1184  * @param it the iterator
1185  */
1186 void
1187 GNUNET_RECLAIM_ticket_iteration_next (struct GNUNET_RECLAIM_TicketIterator *it)
1188 {
1189   struct GNUNET_RECLAIM_Handle *h = it->h;
1190   struct TicketIterationNextMessage *msg;
1191   struct GNUNET_MQ_Envelope *env;
1192
1193   env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_NEXT);
1194   msg->id = htonl (it->r_id);
1195   GNUNET_MQ_send (h->mq, env);
1196 }
1197
1198
1199 /**
1200  * Stops iteration and releases the handle for further calls.  Must
1201  * be called on any iteration that has not yet completed prior to calling
1202  * #GNUNET_RECLAIM_disconnect.
1203  *
1204  * @param it the iterator
1205  */
1206 void
1207 GNUNET_RECLAIM_ticket_iteration_stop (struct GNUNET_RECLAIM_TicketIterator *it)
1208 {
1209   struct GNUNET_RECLAIM_Handle *h = it->h;
1210   struct GNUNET_MQ_Envelope *env;
1211   struct TicketIterationStopMessage *msg;
1212
1213   if (NULL != h->mq)
1214   {
1215     env =
1216       GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_STOP);
1217     msg->id = htonl (it->r_id);
1218     GNUNET_MQ_send (h->mq, env);
1219   }
1220   GNUNET_free (it);
1221 }
1222
1223
1224 /**
1225  * Revoked an issued ticket. The relying party will be unable to retrieve
1226  * attributes. Other issued tickets remain unaffected.
1227  * This includes tickets issued to other relying parties as well as to
1228  * other tickets issued to the audience specified in this ticket.
1229  *
1230  * @param h the identity provider to use
1231  * @param identity the issuing identity
1232  * @param ticket the ticket to revoke
1233  * @param cb the callback
1234  * @param cb_cls the callback closure
1235  * @return handle to abort the operation
1236  */
1237 struct GNUNET_RECLAIM_Operation *
1238 GNUNET_RECLAIM_ticket_revoke (
1239   struct GNUNET_RECLAIM_Handle *h,
1240   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1241   const struct GNUNET_RECLAIM_Ticket *ticket,
1242   GNUNET_RECLAIM_ContinuationWithStatus cb,
1243   void *cb_cls)
1244 {
1245   struct GNUNET_RECLAIM_Operation *op;
1246   struct RevokeTicketMessage *msg;
1247   uint32_t rid;
1248
1249   rid = h->r_id_gen++;
1250   op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
1251   op->h = h;
1252   op->rvk_cb = cb;
1253   op->cls = cb_cls;
1254   op->r_id = rid;
1255   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
1256   op->env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET);
1257   msg->id = htonl (rid);
1258   msg->identity = *identity;
1259   msg->ticket = *ticket;
1260   if (NULL != h->mq)
1261   {
1262     GNUNET_MQ_send (h->mq, op->env);
1263     op->env = NULL;
1264   }
1265   return op;
1266 }
1267
1268
1269 /* end of reclaim_api.c */