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