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