RECLAIM: remove sqlite plugin; housekeeping
[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_NAMESTORE_RECORD_STORE_RESPONSE
411  *
412  * @param cls
413  * @param msg the message we received
414  */
415 static void
416 handle_attribute_store_response (void *cls,
417                                  const struct AttributeStoreResultMessage *msg)
418 {
419   struct GNUNET_RECLAIM_Handle *h = cls;
420   struct GNUNET_RECLAIM_Operation *op;
421   uint32_t r_id = ntohl (msg->id);
422   int res;
423   const char *emsg;
424
425   for (op = h->op_head; NULL != op; op = op->next)
426     if (op->r_id == r_id)
427       break;
428   if (NULL == op)
429     return;
430
431   res = ntohl (msg->op_result);
432   LOG (GNUNET_ERROR_TYPE_DEBUG,
433        "Received ATTRIBUTE_STORE_RESPONSE with result %d\n", res);
434
435   /* TODO: add actual error message to response... */
436   if (GNUNET_SYSERR == res)
437     emsg = _ ("failed to store record\n");
438   else
439     emsg = NULL;
440   if (NULL != op->as_cb)
441     op->as_cb (op->cls, res, emsg);
442   GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
443   free_op (op);
444 }
445
446
447 /**
448  * Handle an incoming message of type
449  * #GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT
450  *
451  * @param cls
452  * @param msg the message we received
453  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
454  */
455 static int
456 check_consume_ticket_result (void *cls,
457                              const struct ConsumeTicketResultMessage *msg)
458 {
459   size_t msg_len;
460   size_t attrs_len;
461
462   msg_len = ntohs (msg->header.size);
463   attrs_len = ntohs (msg->attrs_len);
464   if (msg_len != sizeof (struct ConsumeTicketResultMessage) + attrs_len) {
465     GNUNET_break (0);
466     return GNUNET_SYSERR;
467   }
468   return GNUNET_OK;
469 }
470
471
472 /**
473  * Handle an incoming message of type
474  * #GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT
475  *
476  * @param cls
477  * @param msg the message we received
478  */
479 static void
480 handle_consume_ticket_result (void *cls,
481                               const struct ConsumeTicketResultMessage *msg)
482 {
483   struct GNUNET_RECLAIM_Handle *h = cls;
484   struct GNUNET_RECLAIM_Operation *op;
485   size_t attrs_len;
486   uint32_t r_id = ntohl (msg->id);
487
488   attrs_len = ntohs (msg->attrs_len);
489   LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing attribute result.\n");
490
491
492   for (op = h->op_head; NULL != op; op = op->next)
493     if (op->r_id == r_id)
494       break;
495   if (NULL == op)
496     return;
497
498   {
499     struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs;
500     struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
501     attrs =
502         GNUNET_RECLAIM_ATTRIBUTE_list_deserialize ((char *)&msg[1], attrs_len);
503     if (NULL != op->ar_cb) {
504       if (NULL == attrs) {
505         op->ar_cb (op->cls, &msg->identity, NULL);
506       } else {
507         for (le = attrs->list_head; NULL != le; le = le->next)
508           op->ar_cb (op->cls, &msg->identity, le->claim);
509         GNUNET_RECLAIM_ATTRIBUTE_list_destroy (attrs);
510       }
511     }
512     if (NULL != op) {
513       op->ar_cb (op->cls, NULL, NULL);
514       GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
515       free_op (op);
516     }
517     return;
518   }
519   GNUNET_assert (0);
520 }
521
522
523 /**
524  * Handle an incoming message of type
525  * #GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT
526  *
527  * @param cls
528  * @param msg the message we received
529  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
530  */
531 static int
532 check_attribute_result (void *cls, const struct AttributeResultMessage *msg)
533 {
534   size_t msg_len;
535   size_t attr_len;
536
537   msg_len = ntohs (msg->header.size);
538   attr_len = ntohs (msg->attr_len);
539   if (msg_len != sizeof (struct AttributeResultMessage) + attr_len) {
540     GNUNET_break (0);
541     return GNUNET_SYSERR;
542   }
543   return GNUNET_OK;
544 }
545
546
547 /**
548  * Handle an incoming message of type
549  * #GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT
550  *
551  * @param cls
552  * @param msg the message we received
553  */
554 static void
555 handle_attribute_result (void *cls, const struct AttributeResultMessage *msg)
556 {
557   static struct GNUNET_CRYPTO_EcdsaPrivateKey identity_dummy;
558   struct GNUNET_RECLAIM_Handle *h = cls;
559   struct GNUNET_RECLAIM_AttributeIterator *it;
560   struct GNUNET_RECLAIM_Operation *op;
561   size_t attr_len;
562   uint32_t r_id = ntohl (msg->id);
563
564   attr_len = ntohs (msg->attr_len);
565   LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing attribute result.\n");
566
567
568   for (it = h->it_head; NULL != it; it = it->next)
569     if (it->r_id == r_id)
570       break;
571   for (op = h->op_head; NULL != op; op = op->next)
572     if (op->r_id == r_id)
573       break;
574   if ((NULL == it) && (NULL == op))
575     return;
576
577   if ((0 ==
578        (memcmp (&msg->identity, &identity_dummy, sizeof (identity_dummy))))) {
579     if ((NULL == it) && (NULL == op)) {
580       GNUNET_break (0);
581       force_reconnect (h);
582       return;
583     }
584     if (NULL != it) {
585       if (NULL != it->finish_cb)
586         it->finish_cb (it->finish_cb_cls);
587       free_it (it);
588     }
589     if (NULL != op) {
590       if (NULL != op->ar_cb)
591         op->ar_cb (op->cls, NULL, NULL);
592       GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
593       free_op (op);
594     }
595     return;
596   }
597
598   {
599     struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr;
600     attr = GNUNET_RECLAIM_ATTRIBUTE_deserialize ((char *)&msg[1], attr_len);
601     if (NULL != it) {
602       if (NULL != it->proc)
603         it->proc (it->proc_cls, &msg->identity, attr);
604     } else if (NULL != op) {
605       if (NULL != op->ar_cb)
606         op->ar_cb (op->cls, &msg->identity, attr);
607     }
608     GNUNET_free (attr);
609     return;
610   }
611   GNUNET_assert (0);
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 (
739           attribute_store_response,
740           GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_STORE_RESPONSE,
741           struct AttributeStoreResultMessage, h),
742       GNUNET_MQ_hd_var_size (attribute_result,
743                              GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT,
744                              struct AttributeResultMessage, h),
745       GNUNET_MQ_hd_var_size (ticket_result,
746                              GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT,
747                              struct TicketResultMessage, h),
748       GNUNET_MQ_hd_var_size (consume_ticket_result,
749                              GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT,
750                              struct ConsumeTicketResultMessage, h),
751       GNUNET_MQ_hd_fixed_size (revoke_ticket_result,
752                                GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET_RESULT,
753                                struct RevokeTicketResultMessage, h),
754       GNUNET_MQ_handler_end ()};
755   struct GNUNET_RECLAIM_Operation *op;
756
757   GNUNET_assert (NULL == h->mq);
758   LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to reclaim service.\n");
759
760   h->mq =
761       GNUNET_CLIENT_connect (h->cfg, "reclaim", handlers, &mq_error_handler, h);
762   if (NULL == h->mq)
763     return;
764   for (op = h->op_head; NULL != op; op = op->next)
765     GNUNET_MQ_send_copy (h->mq, op->env);
766 }
767
768
769 /**
770  * Connect to the reclaim service.
771  *
772  * @param cfg the configuration to use
773  * @return handle to use
774  */
775 struct GNUNET_RECLAIM_Handle *
776 GNUNET_RECLAIM_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
777 {
778   struct GNUNET_RECLAIM_Handle *h;
779
780   h = GNUNET_new (struct GNUNET_RECLAIM_Handle);
781   h->cfg = cfg;
782   reconnect (h);
783   if (NULL == h->mq) {
784     GNUNET_free (h);
785     return NULL;
786   }
787   return h;
788 }
789
790
791 /**
792  * Cancel an operation. Note that the operation MAY still
793  * be executed; this merely cancels the continuation; if the request
794  * was already transmitted, the service may still choose to complete
795  * the operation.
796  *
797  * @param op operation to cancel
798  */
799 void
800 GNUNET_RECLAIM_cancel (struct GNUNET_RECLAIM_Operation *op)
801 {
802   struct GNUNET_RECLAIM_Handle *h = op->h;
803
804   GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
805   free_op (op);
806 }
807
808
809 /**
810  * Disconnect from service
811  *
812  * @param h handle to destroy
813  */
814 void
815 GNUNET_RECLAIM_disconnect (struct GNUNET_RECLAIM_Handle *h)
816 {
817   GNUNET_assert (NULL != h);
818   if (NULL != h->mq) {
819     GNUNET_MQ_destroy (h->mq);
820     h->mq = NULL;
821   }
822   if (NULL != h->reconnect_task) {
823     GNUNET_SCHEDULER_cancel (h->reconnect_task);
824     h->reconnect_task = NULL;
825   }
826   GNUNET_assert (NULL == h->op_head);
827   GNUNET_free (h);
828 }
829
830 /**
831  * Store an attribute.  If the attribute is already present,
832  * it is replaced with the new attribute.
833  *
834  * @param h handle to the re:claimID service
835  * @param pkey private key of the identity
836  * @param attr the attribute value
837  * @param exp_interval the relative expiration interval for the attribute
838  * @param cont continuation to call when done
839  * @param cont_cls closure for @a cont
840  * @return handle to abort the request
841  */
842 struct GNUNET_RECLAIM_Operation *
843 GNUNET_RECLAIM_attribute_store (
844     struct GNUNET_RECLAIM_Handle *h,
845     const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey,
846     const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr,
847     const struct GNUNET_TIME_Relative *exp_interval,
848     GNUNET_RECLAIM_ContinuationWithStatus cont, void *cont_cls)
849 {
850   struct GNUNET_RECLAIM_Operation *op;
851   struct AttributeStoreMessage *sam;
852   size_t attr_len;
853
854   op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
855   op->h = h;
856   op->as_cb = cont;
857   op->cls = cont_cls;
858   op->r_id = h->r_id_gen++;
859   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
860   attr_len = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (attr);
861   op->env = GNUNET_MQ_msg_extra (sam, attr_len,
862                                  GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_STORE);
863   sam->identity = *pkey;
864   sam->id = htonl (op->r_id);
865   sam->exp = GNUNET_htonll (exp_interval->rel_value_us);
866
867   GNUNET_RECLAIM_ATTRIBUTE_serialize (attr, (char *)&sam[1]);
868
869   sam->attr_len = htons (attr_len);
870   if (NULL != h->mq)
871     GNUNET_MQ_send_copy (h->mq, op->env);
872   return op;
873 }
874
875
876 /**
877  * List all attributes for a local identity.
878  * This MUST lock the `struct GNUNET_RECLAIM_Handle`
879  * for any other calls than #GNUNET_RECLAIM_get_attributes_next() and
880  * #GNUNET_RECLAIM_get_attributes_stop. @a proc will be called once
881  * immediately, and then again after
882  * #GNUNET_RECLAIM_get_attributes_next() is invoked.
883  *
884  * On error (disconnect), @a error_cb will be invoked.
885  * On normal completion, @a finish_cb proc will be
886  * invoked.
887  *
888  * @param h Handle to the re:claimID service
889  * @param identity Identity to iterate over
890  * @param error_cb Function to call on error (i.e. disconnect),
891  *        the handle is afterwards invalid
892  * @param error_cb_cls Closure for @a error_cb
893  * @param proc Function to call on each attribute
894  * @param proc_cls Closure for @a proc
895  * @param finish_cb Function to call on completion
896  *        the handle is afterwards invalid
897  * @param finish_cb_cls Closure for @a finish_cb
898  * @return an iterator Handle to use for iteration
899  */
900 struct GNUNET_RECLAIM_AttributeIterator *
901 GNUNET_RECLAIM_get_attributes_start (
902     struct GNUNET_RECLAIM_Handle *h,
903     const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
904     GNUNET_SCHEDULER_TaskCallback error_cb, void *error_cb_cls,
905     GNUNET_RECLAIM_AttributeResult proc, void *proc_cls,
906     GNUNET_SCHEDULER_TaskCallback finish_cb, void *finish_cb_cls)
907 {
908   struct GNUNET_RECLAIM_AttributeIterator *it;
909   struct GNUNET_MQ_Envelope *env;
910   struct AttributeIterationStartMessage *msg;
911   uint32_t rid;
912
913   rid = h->r_id_gen++;
914   it = GNUNET_new (struct GNUNET_RECLAIM_AttributeIterator);
915   it->h = h;
916   it->error_cb = error_cb;
917   it->error_cb_cls = error_cb_cls;
918   it->finish_cb = finish_cb;
919   it->finish_cb_cls = finish_cb_cls;
920   it->proc = proc;
921   it->proc_cls = proc_cls;
922   it->r_id = rid;
923   it->identity = *identity;
924   GNUNET_CONTAINER_DLL_insert_tail (h->it_head, h->it_tail, it);
925   env = GNUNET_MQ_msg (msg,
926                        GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_START);
927   msg->id = htonl (rid);
928   msg->identity = *identity;
929   if (NULL == h->mq)
930     it->env = env;
931   else
932     GNUNET_MQ_send (h->mq, env);
933   return it;
934 }
935
936
937 /**
938  * Calls the record processor specified in #GNUNET_RECLAIM_get_attributes_start
939  * for the next record.
940  *
941  * @param it the iterator
942  */
943 void
944 GNUNET_RECLAIM_get_attributes_next (struct GNUNET_RECLAIM_AttributeIterator *it)
945 {
946   struct GNUNET_RECLAIM_Handle *h = it->h;
947   struct AttributeIterationNextMessage *msg;
948   struct GNUNET_MQ_Envelope *env;
949
950   env =
951       GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_NEXT);
952   msg->id = htonl (it->r_id);
953   GNUNET_MQ_send (h->mq, env);
954 }
955
956
957 /**
958  * Stops iteration and releases the handle for further calls. Must
959  * be called on any iteration that has not yet completed prior to calling
960  * #GNUNET_RECLAIM_disconnect.
961  *
962  * @param it the iterator
963  */
964 void
965 GNUNET_RECLAIM_get_attributes_stop (struct GNUNET_RECLAIM_AttributeIterator *it)
966 {
967   struct GNUNET_RECLAIM_Handle *h = it->h;
968   struct GNUNET_MQ_Envelope *env;
969   struct AttributeIterationStopMessage *msg;
970
971   if (NULL != h->mq) {
972     env = GNUNET_MQ_msg (msg,
973                          GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_STOP);
974     msg->id = htonl (it->r_id);
975     GNUNET_MQ_send (h->mq, env);
976   }
977   free_it (it);
978 }
979
980
981 /**
982  * Issues a ticket to another relying party. The identity may use
983  * @GNUNET_RECLAIM_ticket_consume to consume the ticket
984  * and retrieve the attributes specified in the attribute list.
985  *
986  * @param h the reclaim to use
987  * @param iss the issuing identity (= the user)
988  * @param rp the subject of the ticket (= the relying party)
989  * @param attrs the attributes that the relying party is given access to
990  * @param cb the callback
991  * @param cb_cls the callback closure
992  * @return handle to abort the operation
993  */
994 struct GNUNET_RECLAIM_Operation *
995 GNUNET_RECLAIM_ticket_issue (
996     struct GNUNET_RECLAIM_Handle *h,
997     const struct GNUNET_CRYPTO_EcdsaPrivateKey *iss,
998     const struct GNUNET_CRYPTO_EcdsaPublicKey *rp,
999     const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
1000     GNUNET_RECLAIM_TicketCallback cb, void *cb_cls)
1001 {
1002   struct GNUNET_RECLAIM_Operation *op;
1003   struct IssueTicketMessage *tim;
1004   size_t attr_len;
1005
1006   op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
1007   op->h = h;
1008   op->tr_cb = cb;
1009   op->cls = cb_cls;
1010   op->r_id = h->r_id_gen++;
1011   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
1012   attr_len = GNUNET_RECLAIM_ATTRIBUTE_list_serialize_get_size (attrs);
1013   op->env = GNUNET_MQ_msg_extra (tim, attr_len,
1014                                  GNUNET_MESSAGE_TYPE_RECLAIM_ISSUE_TICKET);
1015   tim->identity = *iss;
1016   tim->rp = *rp;
1017   tim->id = htonl (op->r_id);
1018
1019   GNUNET_RECLAIM_ATTRIBUTE_list_serialize (attrs, (char *)&tim[1]);
1020
1021   tim->attr_len = htons (attr_len);
1022   if (NULL != h->mq)
1023     GNUNET_MQ_send_copy (h->mq, op->env);
1024   return op;
1025 }
1026
1027
1028 /**
1029  * Consumes an issued ticket. The ticket is persisted
1030  * and used to retrieve identity information from the issuer
1031  *
1032  * @param h the reclaim to use
1033  * @param identity the identity that is the subject of the issued ticket (the
1034  * relying party)
1035  * @param ticket the issued ticket to consume
1036  * @param cb the callback to call
1037  * @param cb_cls the callback closure
1038  * @return handle to abort the operation
1039  */
1040 struct GNUNET_RECLAIM_Operation *
1041 GNUNET_RECLAIM_ticket_consume (
1042     struct GNUNET_RECLAIM_Handle *h,
1043     const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1044     const struct GNUNET_RECLAIM_Ticket *ticket,
1045     GNUNET_RECLAIM_AttributeResult cb, void *cb_cls)
1046 {
1047   struct GNUNET_RECLAIM_Operation *op;
1048   struct ConsumeTicketMessage *ctm;
1049
1050   op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
1051   op->h = h;
1052   op->ar_cb = cb;
1053   op->cls = cb_cls;
1054   op->r_id = h->r_id_gen++;
1055   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
1056   op->env =
1057       GNUNET_MQ_msg_extra (ctm, sizeof (const struct GNUNET_RECLAIM_Ticket),
1058                            GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET);
1059   ctm->identity = *identity;
1060   ctm->id = htonl (op->r_id);
1061
1062   GNUNET_memcpy ((char *)&ctm[1], ticket,
1063                  sizeof (const struct GNUNET_RECLAIM_Ticket));
1064
1065   if (NULL != h->mq)
1066     GNUNET_MQ_send_copy (h->mq, op->env);
1067   return op;
1068 }
1069
1070
1071 /**
1072  * Lists all tickets that have been issued to remote
1073  * identites (relying parties)
1074  *
1075  * @param h the reclaim to use
1076  * @param identity the issuing identity
1077  * @param error_cb function to call on error (i.e. disconnect),
1078  *        the handle is afterwards invalid
1079  * @param error_cb_cls closure for @a error_cb
1080  * @param proc function to call on each ticket; it
1081  *        will be called repeatedly with a value (if available)
1082  * @param proc_cls closure for @a proc
1083  * @param finish_cb function to call on completion
1084  *        the handle is afterwards invalid
1085  * @param finish_cb_cls closure for @a finish_cb
1086  * @return an iterator handle to use for iteration
1087  */
1088 struct GNUNET_RECLAIM_TicketIterator *
1089 GNUNET_RECLAIM_ticket_iteration_start (
1090     struct GNUNET_RECLAIM_Handle *h,
1091     const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1092     GNUNET_SCHEDULER_TaskCallback error_cb, void *error_cb_cls,
1093     GNUNET_RECLAIM_TicketCallback proc, void *proc_cls,
1094     GNUNET_SCHEDULER_TaskCallback finish_cb, void *finish_cb_cls)
1095 {
1096   struct GNUNET_RECLAIM_TicketIterator *it;
1097   struct GNUNET_MQ_Envelope *env;
1098   struct TicketIterationStartMessage *msg;
1099   uint32_t rid;
1100
1101   rid = h->r_id_gen++;
1102   it = GNUNET_new (struct GNUNET_RECLAIM_TicketIterator);
1103   it->h = h;
1104   it->error_cb = error_cb;
1105   it->error_cb_cls = error_cb_cls;
1106   it->finish_cb = finish_cb;
1107   it->finish_cb_cls = finish_cb_cls;
1108   it->tr_cb = proc;
1109   it->cls = proc_cls;
1110   it->r_id = rid;
1111   GNUNET_CONTAINER_DLL_insert_tail (h->ticket_it_head, h->ticket_it_tail, it);
1112   env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_START);
1113   msg->id = htonl (rid);
1114   msg->identity = *identity;
1115   if (NULL == h->mq)
1116     it->env = env;
1117   else
1118     GNUNET_MQ_send (h->mq, env);
1119   return it;
1120 }
1121
1122
1123 /**
1124  * Calls the ticket processor specified in
1125  * #GNUNET_RECLAIM_ticket_iteration_start for the next record.
1126  *
1127  * @param it the iterator
1128  */
1129 void
1130 GNUNET_RECLAIM_ticket_iteration_next (struct GNUNET_RECLAIM_TicketIterator *it)
1131 {
1132   struct GNUNET_RECLAIM_Handle *h = it->h;
1133   struct TicketIterationNextMessage *msg;
1134   struct GNUNET_MQ_Envelope *env;
1135
1136   env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_NEXT);
1137   msg->id = htonl (it->r_id);
1138   GNUNET_MQ_send (h->mq, env);
1139 }
1140
1141
1142 /**
1143  * Stops iteration and releases the handle for further calls.  Must
1144  * be called on any iteration that has not yet completed prior to calling
1145  * #GNUNET_RECLAIM_disconnect.
1146  *
1147  * @param it the iterator
1148  */
1149 void
1150 GNUNET_RECLAIM_ticket_iteration_stop (struct GNUNET_RECLAIM_TicketIterator *it)
1151 {
1152   struct GNUNET_RECLAIM_Handle *h = it->h;
1153   struct GNUNET_MQ_Envelope *env;
1154   struct TicketIterationStopMessage *msg;
1155
1156   if (NULL != h->mq) {
1157     env =
1158         GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_STOP);
1159     msg->id = htonl (it->r_id);
1160     GNUNET_MQ_send (h->mq, env);
1161   }
1162   GNUNET_free (it);
1163 }
1164
1165
1166 /**
1167  * Revoked an issued ticket. The relying party will be unable to retrieve
1168  * attributes. Other issued tickets remain unaffected.
1169  * This includes tickets issued to other relying parties as well as to
1170  * other tickets issued to the audience specified in this ticket.
1171  *
1172  * @param h the identity provider to use
1173  * @param identity the issuing identity
1174  * @param ticket the ticket to revoke
1175  * @param cb the callback
1176  * @param cb_cls the callback closure
1177  * @return handle to abort the operation
1178  */
1179 struct GNUNET_RECLAIM_Operation *
1180 GNUNET_RECLAIM_ticket_revoke (
1181     struct GNUNET_RECLAIM_Handle *h,
1182     const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1183     const struct GNUNET_RECLAIM_Ticket *ticket,
1184     GNUNET_RECLAIM_ContinuationWithStatus cb, void *cb_cls)
1185 {
1186   struct GNUNET_RECLAIM_Operation *op;
1187   struct RevokeTicketMessage *msg;
1188   uint32_t rid;
1189
1190   rid = h->r_id_gen++;
1191   op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
1192   op->h = h;
1193   op->rvk_cb = cb;
1194   op->cls = cb_cls;
1195   op->r_id = rid;
1196   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
1197   op->env = GNUNET_MQ_msg_extra (msg, sizeof (struct GNUNET_RECLAIM_Ticket),
1198                                  GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET);
1199   msg->id = htonl (rid);
1200   msg->identity = *identity;
1201   GNUNET_memcpy (&msg[1], ticket, sizeof (struct GNUNET_RECLAIM_Ticket));
1202   if (NULL != h->mq) {
1203     GNUNET_MQ_send (h->mq, op->env);
1204     op->env = NULL;
1205   }
1206   return op;
1207 }
1208
1209
1210 /* end of reclaim_api.c */