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