memcmp() -> GNUNET_memcmp(), first take
[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  * Handle an incoming message of type
615  * #GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT
616  *
617  * @param cls
618  * @param msg the message we received
619  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
620  */
621 static int
622 check_ticket_result (void *cls, const struct TicketResultMessage *msg)
623 {
624   size_t msg_len;
625
626   msg_len = ntohs (msg->header.size);
627   if (msg_len < sizeof (struct TicketResultMessage)) {
628     GNUNET_break (0);
629     return GNUNET_SYSERR;
630   }
631   return GNUNET_OK;
632 }
633
634
635 /**
636  * Handle an incoming message of type
637  * #GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT
638  *
639  * @param cls
640  * @param msg the message we received
641  */
642 static void
643 handle_ticket_result (void *cls, const struct TicketResultMessage *msg)
644 {
645   struct GNUNET_RECLAIM_Handle *handle = cls;
646   struct GNUNET_RECLAIM_Operation *op;
647   struct GNUNET_RECLAIM_TicketIterator *it;
648   const struct GNUNET_RECLAIM_Ticket *ticket;
649   uint32_t r_id = ntohl (msg->id);
650   size_t msg_len;
651
652   for (op = handle->op_head; NULL != op; op = op->next)
653     if (op->r_id == r_id)
654       break;
655   for (it = handle->ticket_it_head; NULL != it; it = it->next)
656     if (it->r_id == r_id)
657       break;
658   if ((NULL == op) && (NULL == it))
659     return;
660   msg_len = ntohs (msg->header.size);
661   if (NULL != op) {
662     GNUNET_CONTAINER_DLL_remove (handle->op_head, handle->op_tail, op);
663     if (msg_len == sizeof (struct TicketResultMessage)) {
664       if (NULL != op->tr_cb)
665         op->tr_cb (op->cls, NULL);
666     } else {
667       ticket = (struct GNUNET_RECLAIM_Ticket *)&msg[1];
668       if (NULL != op->tr_cb)
669         op->tr_cb (op->cls, ticket);
670     }
671     free_op (op);
672     return;
673   } else if (NULL != it) {
674     if (msg_len == sizeof (struct TicketResultMessage)) {
675       if (NULL != it->tr_cb)
676         GNUNET_CONTAINER_DLL_remove (handle->ticket_it_head,
677                                      handle->ticket_it_tail, it);
678       it->finish_cb (it->finish_cb_cls);
679       GNUNET_free (it);
680     } else {
681       ticket = (struct GNUNET_RECLAIM_Ticket *)&msg[1];
682       if (NULL != it->tr_cb)
683         it->tr_cb (it->cls, ticket);
684     }
685     return;
686   }
687   GNUNET_break (0);
688 }
689
690
691 /**
692  * Handle an incoming message of type
693  * #GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET_RESULT
694  *
695  * @param cls
696  * @param msg the message we received
697  */
698 static void
699 handle_revoke_ticket_result (void *cls,
700                              const struct RevokeTicketResultMessage *msg)
701 {
702   struct GNUNET_RECLAIM_Handle *h = cls;
703   struct GNUNET_RECLAIM_Operation *op;
704   uint32_t r_id = ntohl (msg->id);
705   int32_t success;
706
707   LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing revocation result.\n");
708
709
710   for (op = h->op_head; NULL != op; op = op->next)
711     if (op->r_id == r_id)
712       break;
713   if (NULL == op)
714     return;
715   success = ntohl (msg->success);
716   {
717     if (NULL != op->rvk_cb) {
718       op->rvk_cb (op->cls, success, NULL);
719     }
720     GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
721     free_op (op);
722     return;
723   }
724   GNUNET_assert (0);
725 }
726
727
728 /**
729  * Try again to connect to the service.
730  *
731  * @param h handle to the reclaim service.
732  */
733 static void
734 reconnect (struct GNUNET_RECLAIM_Handle *h)
735 {
736   struct GNUNET_MQ_MessageHandler handlers[] = {
737       GNUNET_MQ_hd_fixed_size (success_response,
738                                GNUNET_MESSAGE_TYPE_RECLAIM_SUCCESS_RESPONSE,
739                                struct SuccessResultMessage, h),
740       GNUNET_MQ_hd_var_size (attribute_result,
741                              GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT,
742                              struct AttributeResultMessage, h),
743       GNUNET_MQ_hd_var_size (ticket_result,
744                              GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT,
745                              struct TicketResultMessage, h),
746       GNUNET_MQ_hd_var_size (consume_ticket_result,
747                              GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT,
748                              struct ConsumeTicketResultMessage, h),
749       GNUNET_MQ_hd_fixed_size (revoke_ticket_result,
750                                GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET_RESULT,
751                                struct RevokeTicketResultMessage, h),
752       GNUNET_MQ_handler_end ()};
753   struct GNUNET_RECLAIM_Operation *op;
754
755   GNUNET_assert (NULL == h->mq);
756   LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to reclaim service.\n");
757
758   h->mq =
759       GNUNET_CLIENT_connect (h->cfg, "reclaim", handlers, &mq_error_handler, h);
760   if (NULL == h->mq)
761     return;
762   for (op = h->op_head; NULL != op; op = op->next)
763     GNUNET_MQ_send_copy (h->mq, op->env);
764 }
765
766
767 /**
768  * Connect to the reclaim service.
769  *
770  * @param cfg the configuration to use
771  * @return handle to use
772  */
773 struct GNUNET_RECLAIM_Handle *
774 GNUNET_RECLAIM_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
775 {
776   struct GNUNET_RECLAIM_Handle *h;
777
778   h = GNUNET_new (struct GNUNET_RECLAIM_Handle);
779   h->cfg = cfg;
780   reconnect (h);
781   if (NULL == h->mq) {
782     GNUNET_free (h);
783     return NULL;
784   }
785   return h;
786 }
787
788
789 /**
790  * Cancel an operation. Note that the operation MAY still
791  * be executed; this merely cancels the continuation; if the request
792  * was already transmitted, the service may still choose to complete
793  * the operation.
794  *
795  * @param op operation to cancel
796  */
797 void
798 GNUNET_RECLAIM_cancel (struct GNUNET_RECLAIM_Operation *op)
799 {
800   struct GNUNET_RECLAIM_Handle *h = op->h;
801
802   GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
803   free_op (op);
804 }
805
806
807 /**
808  * Disconnect from service
809  *
810  * @param h handle to destroy
811  */
812 void
813 GNUNET_RECLAIM_disconnect (struct GNUNET_RECLAIM_Handle *h)
814 {
815   GNUNET_assert (NULL != h);
816   if (NULL != h->mq) {
817     GNUNET_MQ_destroy (h->mq);
818     h->mq = NULL;
819   }
820   if (NULL != h->reconnect_task) {
821     GNUNET_SCHEDULER_cancel (h->reconnect_task);
822     h->reconnect_task = NULL;
823   }
824   GNUNET_assert (NULL == h->op_head);
825   GNUNET_free (h);
826 }
827
828 /**
829  * Store an attribute.  If the attribute is already present,
830  * it is replaced with the new attribute.
831  *
832  * @param h handle to the re:claimID service
833  * @param pkey private key of the identity
834  * @param attr the attribute value
835  * @param exp_interval the relative expiration interval for the attribute
836  * @param cont continuation to call when done
837  * @param cont_cls closure for @a cont
838  * @return handle to abort the request
839  */
840 struct GNUNET_RECLAIM_Operation *
841 GNUNET_RECLAIM_attribute_store (
842     struct GNUNET_RECLAIM_Handle *h,
843     const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey,
844     const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr,
845     const struct GNUNET_TIME_Relative *exp_interval,
846     GNUNET_RECLAIM_ContinuationWithStatus cont, void *cont_cls)
847 {
848   struct GNUNET_RECLAIM_Operation *op;
849   struct AttributeStoreMessage *sam;
850   size_t attr_len;
851
852   op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
853   op->h = h;
854   op->as_cb = cont;
855   op->cls = cont_cls;
856   op->r_id = h->r_id_gen++;
857   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
858   attr_len = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (attr);
859   op->env = GNUNET_MQ_msg_extra (sam, attr_len,
860                                  GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_STORE);
861   sam->identity = *pkey;
862   sam->id = htonl (op->r_id);
863   sam->exp = GNUNET_htonll (exp_interval->rel_value_us);
864
865   GNUNET_RECLAIM_ATTRIBUTE_serialize (attr, (char *)&sam[1]);
866
867   sam->attr_len = htons (attr_len);
868   if (NULL != h->mq)
869     GNUNET_MQ_send_copy (h->mq, op->env);
870   return op;
871 }
872
873
874 /**
875  * Delete an attribute. Tickets used to share this attribute are updated
876  * accordingly.
877  *
878  * @param h handle to the re:claimID service
879  * @param pkey Private key of the identity to add an attribute to
880  * @param attr The attribute
881  * @param cont Continuation to call when done
882  * @param cont_cls Closure for @a cont
883  * @return handle Used to to abort the request
884  */
885 struct GNUNET_RECLAIM_Operation *
886 GNUNET_RECLAIM_attribute_delete (
887     struct GNUNET_RECLAIM_Handle *h,
888     const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey,
889     const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr,
890     GNUNET_RECLAIM_ContinuationWithStatus cont, void *cont_cls)
891 {
892   struct GNUNET_RECLAIM_Operation *op;
893   struct AttributeDeleteMessage *dam;
894   size_t attr_len;
895
896   op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
897   op->h = h;
898   op->as_cb = cont;
899   op->cls = cont_cls;
900   op->r_id = h->r_id_gen++;
901   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
902   attr_len = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (attr);
903   op->env = GNUNET_MQ_msg_extra (dam, attr_len,
904                                  GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_DELETE);
905   dam->identity = *pkey;
906   dam->id = htonl (op->r_id);
907   GNUNET_RECLAIM_ATTRIBUTE_serialize (attr, (char *)&dam[1]);
908
909   dam->attr_len = htons (attr_len);
910   if (NULL != h->mq)
911     GNUNET_MQ_send_copy (h->mq, op->env);
912   return op;
913 }
914
915
916 /**
917  * List all attributes for a local identity.
918  * This MUST lock the `struct GNUNET_RECLAIM_Handle`
919  * for any other calls than #GNUNET_RECLAIM_get_attributes_next() and
920  * #GNUNET_RECLAIM_get_attributes_stop. @a proc will be called once
921  * immediately, and then again after
922  * #GNUNET_RECLAIM_get_attributes_next() is invoked.
923  *
924  * On error (disconnect), @a error_cb will be invoked.
925  * On normal completion, @a finish_cb proc will be
926  * invoked.
927  *
928  * @param h Handle to the re:claimID service
929  * @param identity Identity to iterate over
930  * @param error_cb Function to call on error (i.e. disconnect),
931  *        the handle is afterwards invalid
932  * @param error_cb_cls Closure for @a error_cb
933  * @param proc Function to call on each attribute
934  * @param proc_cls Closure for @a proc
935  * @param finish_cb Function to call on completion
936  *        the handle is afterwards invalid
937  * @param finish_cb_cls Closure for @a finish_cb
938  * @return an iterator Handle to use for iteration
939  */
940 struct GNUNET_RECLAIM_AttributeIterator *
941 GNUNET_RECLAIM_get_attributes_start (
942     struct GNUNET_RECLAIM_Handle *h,
943     const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
944     GNUNET_SCHEDULER_TaskCallback error_cb, void *error_cb_cls,
945     GNUNET_RECLAIM_AttributeResult proc, void *proc_cls,
946     GNUNET_SCHEDULER_TaskCallback finish_cb, void *finish_cb_cls)
947 {
948   struct GNUNET_RECLAIM_AttributeIterator *it;
949   struct GNUNET_MQ_Envelope *env;
950   struct AttributeIterationStartMessage *msg;
951   uint32_t rid;
952
953   rid = h->r_id_gen++;
954   it = GNUNET_new (struct GNUNET_RECLAIM_AttributeIterator);
955   it->h = h;
956   it->error_cb = error_cb;
957   it->error_cb_cls = error_cb_cls;
958   it->finish_cb = finish_cb;
959   it->finish_cb_cls = finish_cb_cls;
960   it->proc = proc;
961   it->proc_cls = proc_cls;
962   it->r_id = rid;
963   it->identity = *identity;
964   GNUNET_CONTAINER_DLL_insert_tail (h->it_head, h->it_tail, it);
965   env = GNUNET_MQ_msg (msg,
966                        GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_START);
967   msg->id = htonl (rid);
968   msg->identity = *identity;
969   if (NULL == h->mq)
970     it->env = env;
971   else
972     GNUNET_MQ_send (h->mq, env);
973   return it;
974 }
975
976
977 /**
978  * Calls the record processor specified in #GNUNET_RECLAIM_get_attributes_start
979  * for the next record.
980  *
981  * @param it the iterator
982  */
983 void
984 GNUNET_RECLAIM_get_attributes_next (struct GNUNET_RECLAIM_AttributeIterator *it)
985 {
986   struct GNUNET_RECLAIM_Handle *h = it->h;
987   struct AttributeIterationNextMessage *msg;
988   struct GNUNET_MQ_Envelope *env;
989
990   env =
991       GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_NEXT);
992   msg->id = htonl (it->r_id);
993   GNUNET_MQ_send (h->mq, env);
994 }
995
996
997 /**
998  * Stops iteration and releases the handle for further calls. Must
999  * be called on any iteration that has not yet completed prior to calling
1000  * #GNUNET_RECLAIM_disconnect.
1001  *
1002  * @param it the iterator
1003  */
1004 void
1005 GNUNET_RECLAIM_get_attributes_stop (struct GNUNET_RECLAIM_AttributeIterator *it)
1006 {
1007   struct GNUNET_RECLAIM_Handle *h = it->h;
1008   struct GNUNET_MQ_Envelope *env;
1009   struct AttributeIterationStopMessage *msg;
1010
1011   if (NULL != h->mq) {
1012     env = GNUNET_MQ_msg (msg,
1013                          GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_STOP);
1014     msg->id = htonl (it->r_id);
1015     GNUNET_MQ_send (h->mq, env);
1016   }
1017   free_it (it);
1018 }
1019
1020
1021 /**
1022  * Issues a ticket to another relying party. The identity may use
1023  * @GNUNET_RECLAIM_ticket_consume to consume the ticket
1024  * and retrieve the attributes specified in the attribute list.
1025  *
1026  * @param h the reclaim to use
1027  * @param iss the issuing identity (= the user)
1028  * @param rp the subject of the ticket (= the relying party)
1029  * @param attrs the attributes that the relying party is given access to
1030  * @param cb the callback
1031  * @param cb_cls the callback closure
1032  * @return handle to abort the operation
1033  */
1034 struct GNUNET_RECLAIM_Operation *
1035 GNUNET_RECLAIM_ticket_issue (
1036     struct GNUNET_RECLAIM_Handle *h,
1037     const struct GNUNET_CRYPTO_EcdsaPrivateKey *iss,
1038     const struct GNUNET_CRYPTO_EcdsaPublicKey *rp,
1039     const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
1040     GNUNET_RECLAIM_TicketCallback cb, void *cb_cls)
1041 {
1042   struct GNUNET_RECLAIM_Operation *op;
1043   struct IssueTicketMessage *tim;
1044   size_t attr_len;
1045
1046   op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
1047   op->h = h;
1048   op->tr_cb = cb;
1049   op->cls = cb_cls;
1050   op->r_id = h->r_id_gen++;
1051   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
1052   attr_len = GNUNET_RECLAIM_ATTRIBUTE_list_serialize_get_size (attrs);
1053   op->env = GNUNET_MQ_msg_extra (tim, attr_len,
1054                                  GNUNET_MESSAGE_TYPE_RECLAIM_ISSUE_TICKET);
1055   tim->identity = *iss;
1056   tim->rp = *rp;
1057   tim->id = htonl (op->r_id);
1058
1059   GNUNET_RECLAIM_ATTRIBUTE_list_serialize (attrs, (char *)&tim[1]);
1060
1061   tim->attr_len = htons (attr_len);
1062   if (NULL != h->mq)
1063     GNUNET_MQ_send_copy (h->mq, op->env);
1064   return op;
1065 }
1066
1067
1068 /**
1069  * Consumes an issued ticket. The ticket is persisted
1070  * and used to retrieve identity information from the issuer
1071  *
1072  * @param h the reclaim to use
1073  * @param identity the identity that is the subject of the issued ticket (the
1074  * relying party)
1075  * @param ticket the issued ticket to consume
1076  * @param cb the callback to call
1077  * @param cb_cls the callback closure
1078  * @return handle to abort the operation
1079  */
1080 struct GNUNET_RECLAIM_Operation *
1081 GNUNET_RECLAIM_ticket_consume (
1082     struct GNUNET_RECLAIM_Handle *h,
1083     const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1084     const struct GNUNET_RECLAIM_Ticket *ticket,
1085     GNUNET_RECLAIM_AttributeResult cb, void *cb_cls)
1086 {
1087   struct GNUNET_RECLAIM_Operation *op;
1088   struct ConsumeTicketMessage *ctm;
1089
1090   op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
1091   op->h = h;
1092   op->ar_cb = cb;
1093   op->cls = cb_cls;
1094   op->r_id = h->r_id_gen++;
1095   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
1096   op->env =
1097       GNUNET_MQ_msg_extra (ctm, sizeof (const struct GNUNET_RECLAIM_Ticket),
1098                            GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET);
1099   ctm->identity = *identity;
1100   ctm->id = htonl (op->r_id);
1101
1102   GNUNET_memcpy ((char *)&ctm[1], ticket,
1103                  sizeof (const struct GNUNET_RECLAIM_Ticket));
1104
1105   if (NULL != h->mq)
1106     GNUNET_MQ_send_copy (h->mq, op->env);
1107   return op;
1108 }
1109
1110
1111 /**
1112  * Lists all tickets that have been issued to remote
1113  * identites (relying parties)
1114  *
1115  * @param h the reclaim to use
1116  * @param identity the issuing identity
1117  * @param error_cb function to call on error (i.e. disconnect),
1118  *        the handle is afterwards invalid
1119  * @param error_cb_cls closure for @a error_cb
1120  * @param proc function to call on each ticket; it
1121  *        will be called repeatedly with a value (if available)
1122  * @param proc_cls closure for @a proc
1123  * @param finish_cb function to call on completion
1124  *        the handle is afterwards invalid
1125  * @param finish_cb_cls closure for @a finish_cb
1126  * @return an iterator handle to use for iteration
1127  */
1128 struct GNUNET_RECLAIM_TicketIterator *
1129 GNUNET_RECLAIM_ticket_iteration_start (
1130     struct GNUNET_RECLAIM_Handle *h,
1131     const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1132     GNUNET_SCHEDULER_TaskCallback error_cb, void *error_cb_cls,
1133     GNUNET_RECLAIM_TicketCallback proc, void *proc_cls,
1134     GNUNET_SCHEDULER_TaskCallback finish_cb, void *finish_cb_cls)
1135 {
1136   struct GNUNET_RECLAIM_TicketIterator *it;
1137   struct GNUNET_MQ_Envelope *env;
1138   struct TicketIterationStartMessage *msg;
1139   uint32_t rid;
1140
1141   rid = h->r_id_gen++;
1142   it = GNUNET_new (struct GNUNET_RECLAIM_TicketIterator);
1143   it->h = h;
1144   it->error_cb = error_cb;
1145   it->error_cb_cls = error_cb_cls;
1146   it->finish_cb = finish_cb;
1147   it->finish_cb_cls = finish_cb_cls;
1148   it->tr_cb = proc;
1149   it->cls = proc_cls;
1150   it->r_id = rid;
1151   GNUNET_CONTAINER_DLL_insert_tail (h->ticket_it_head, h->ticket_it_tail, it);
1152   env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_START);
1153   msg->id = htonl (rid);
1154   msg->identity = *identity;
1155   if (NULL == h->mq)
1156     it->env = env;
1157   else
1158     GNUNET_MQ_send (h->mq, env);
1159   return it;
1160 }
1161
1162
1163 /**
1164  * Calls the ticket processor specified in
1165  * #GNUNET_RECLAIM_ticket_iteration_start for the next record.
1166  *
1167  * @param it the iterator
1168  */
1169 void
1170 GNUNET_RECLAIM_ticket_iteration_next (struct GNUNET_RECLAIM_TicketIterator *it)
1171 {
1172   struct GNUNET_RECLAIM_Handle *h = it->h;
1173   struct TicketIterationNextMessage *msg;
1174   struct GNUNET_MQ_Envelope *env;
1175
1176   env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_NEXT);
1177   msg->id = htonl (it->r_id);
1178   GNUNET_MQ_send (h->mq, env);
1179 }
1180
1181
1182 /**
1183  * Stops iteration and releases the handle for further calls.  Must
1184  * be called on any iteration that has not yet completed prior to calling
1185  * #GNUNET_RECLAIM_disconnect.
1186  *
1187  * @param it the iterator
1188  */
1189 void
1190 GNUNET_RECLAIM_ticket_iteration_stop (struct GNUNET_RECLAIM_TicketIterator *it)
1191 {
1192   struct GNUNET_RECLAIM_Handle *h = it->h;
1193   struct GNUNET_MQ_Envelope *env;
1194   struct TicketIterationStopMessage *msg;
1195
1196   if (NULL != h->mq) {
1197     env =
1198         GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_STOP);
1199     msg->id = htonl (it->r_id);
1200     GNUNET_MQ_send (h->mq, env);
1201   }
1202   GNUNET_free (it);
1203 }
1204
1205
1206 /**
1207  * Revoked an issued ticket. The relying party will be unable to retrieve
1208  * attributes. Other issued tickets remain unaffected.
1209  * This includes tickets issued to other relying parties as well as to
1210  * other tickets issued to the audience specified in this ticket.
1211  *
1212  * @param h the identity provider to use
1213  * @param identity the issuing identity
1214  * @param ticket the ticket to revoke
1215  * @param cb the callback
1216  * @param cb_cls the callback closure
1217  * @return handle to abort the operation
1218  */
1219 struct GNUNET_RECLAIM_Operation *
1220 GNUNET_RECLAIM_ticket_revoke (
1221     struct GNUNET_RECLAIM_Handle *h,
1222     const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1223     const struct GNUNET_RECLAIM_Ticket *ticket,
1224     GNUNET_RECLAIM_ContinuationWithStatus cb, void *cb_cls)
1225 {
1226   struct GNUNET_RECLAIM_Operation *op;
1227   struct RevokeTicketMessage *msg;
1228   uint32_t rid;
1229
1230   rid = h->r_id_gen++;
1231   op = GNUNET_new (struct GNUNET_RECLAIM_Operation);
1232   op->h = h;
1233   op->rvk_cb = cb;
1234   op->cls = cb_cls;
1235   op->r_id = rid;
1236   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
1237   op->env = GNUNET_MQ_msg_extra (msg, sizeof (struct GNUNET_RECLAIM_Ticket),
1238                                  GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET);
1239   msg->id = htonl (rid);
1240   msg->identity = *identity;
1241   GNUNET_memcpy (&msg[1], ticket, sizeof (struct GNUNET_RECLAIM_Ticket));
1242   if (NULL != h->mq) {
1243     GNUNET_MQ_send (h->mq, op->env);
1244     op->env = NULL;
1245   }
1246   return op;
1247 }
1248
1249
1250 /* end of reclaim_api.c */