2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 GNUnet e.V.
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.
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.
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/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
22 * @author Martin Schanzenbach
23 * @file src/reclaim/gnunet-service-reclaim_tickets.c
24 * @brief reclaim tickets
27 #include "gnunet-service-reclaim_tickets.h"
29 struct ParallelLookup;
31 struct RECLAIM_TICKETS_ConsumeHandle {
35 struct GNUNET_RECLAIM_Ticket ticket;
40 struct GNUNET_GNS_LookupRequest *lookup_request;
45 struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
50 struct GNUNET_CRYPTO_EcdsaPublicKey identity_pub;
55 struct ParallelLookup *parallel_lookups_head;
60 struct ParallelLookup *parallel_lookups_tail;
65 struct GNUNET_SCHEDULER_Task *kill_task;
70 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs;
75 struct GNUNET_TIME_Absolute lookup_start_time;
80 RECLAIM_TICKETS_ConsumeCallback cb;
89 * Handle for a parallel GNS lookup job
91 struct ParallelLookup {
93 struct ParallelLookup *next;
96 struct ParallelLookup *prev;
99 struct GNUNET_GNS_LookupRequest *lookup_request;
101 /* The handle the return to */
102 struct RECLAIM_TICKETS_ConsumeHandle *handle;
107 struct GNUNET_TIME_Absolute lookup_start_time;
109 /* The label to look up */
115 * A reference to a ticket stored in GNS
117 struct TicketReference {
121 struct TicketReference *next;
126 struct TicketReference *prev;
131 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs;
136 struct GNUNET_RECLAIM_Ticket ticket;
141 * Ticket issue request handle
143 struct TicketIssueHandle {
145 * Attributes to issue
147 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs;
152 struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
157 struct GNUNET_RECLAIM_Ticket ticket;
162 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
165 * Ticket reference list
167 struct TicketReference *ticket_refs_head;
170 * Ticket reference list
172 struct TicketReference *ticket_refs_tail;
175 * Number of references
177 uint32_t ticket_ref_num;
182 RECLAIM_TICKETS_TicketResult cb;
193 struct RECLAIM_TICKETS_Iterator {
197 struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
202 struct GNUNET_CRYPTO_EcdsaPublicKey identity_pub;
205 * Namestore queue entry
207 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
212 RECLAIM_TICKETS_TicketIter cb;
220 * Ticket reference list
222 struct TicketReference *tickets_head;
225 * Ticket reference list
227 struct TicketReference *tickets_tail;
230 /* Namestore handle */
231 static struct GNUNET_NAMESTORE_Handle *nsh;
234 static struct GNUNET_GNS_Handle *gns;
236 /* Handle to the statistics service */
237 static struct GNUNET_STATISTICS_Handle *stats;
241 * Cleanup ticket consume handle
242 * @param cth the handle to clean up
244 static void cleanup_cth (struct RECLAIM_TICKETS_ConsumeHandle *cth)
246 struct ParallelLookup *lu;
247 struct ParallelLookup *tmp;
248 if (NULL != cth->lookup_request)
249 GNUNET_GNS_lookup_cancel (cth->lookup_request);
250 for (lu = cth->parallel_lookups_head; NULL != lu;) {
251 GNUNET_GNS_lookup_cancel (lu->lookup_request);
252 GNUNET_free (lu->label);
254 GNUNET_CONTAINER_DLL_remove (cth->parallel_lookups_head,
255 cth->parallel_lookups_tail, lu);
260 if (NULL != cth->attrs)
261 GNUNET_RECLAIM_ATTRIBUTE_list_destroy (cth->attrs);
267 process_parallel_lookup_result (void *cls, uint32_t rd_count,
268 const struct GNUNET_GNSRECORD_Data *rd)
270 struct ParallelLookup *parallel_lookup = cls;
271 struct RECLAIM_TICKETS_ConsumeHandle *cth = parallel_lookup->handle;
272 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *attr_le;
273 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Parallel lookup finished (count=%u)\n",
276 GNUNET_CONTAINER_DLL_remove (cth->parallel_lookups_head,
277 cth->parallel_lookups_tail, parallel_lookup);
278 GNUNET_free (parallel_lookup->label);
280 GNUNET_STATISTICS_update (
281 stats, "attribute_lookup_time_total",
282 GNUNET_TIME_absolute_get_duration (parallel_lookup->lookup_start_time)
285 GNUNET_STATISTICS_update (stats, "attribute_lookups_count", 1, GNUNET_YES);
288 GNUNET_free (parallel_lookup);
290 GNUNET_break (0); // TODO
291 if (rd->record_type == GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR) {
292 attr_le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry);
294 GNUNET_RECLAIM_ATTRIBUTE_deserialize (rd->data, rd->data_size);
295 GNUNET_CONTAINER_DLL_insert (cth->attrs->list_head, cth->attrs->list_tail,
298 if (NULL != cth->parallel_lookups_head)
299 return; // Wait for more
300 /* Else we are done */
302 GNUNET_SCHEDULER_cancel (cth->kill_task);
303 cth->cb (cth->cb_cls, &cth->ticket.identity, cth->attrs, GNUNET_OK, NULL);
308 static void abort_parallel_lookups (void *cls)
310 struct RECLAIM_TICKETS_ConsumeHandle *cth = cls;
311 struct ParallelLookup *lu;
312 struct ParallelLookup *tmp;
314 cth->kill_task = NULL;
315 for (lu = cth->parallel_lookups_head; NULL != lu;) {
316 GNUNET_GNS_lookup_cancel (lu->lookup_request);
317 GNUNET_free (lu->label);
319 GNUNET_CONTAINER_DLL_remove (cth->parallel_lookups_head,
320 cth->parallel_lookups_tail, lu);
324 cth->cb (cth->cb_cls, NULL, NULL, GNUNET_SYSERR, "Aborted");
328 static void lookup_authz_cb (void *cls, uint32_t rd_count,
329 const struct GNUNET_GNSRECORD_Data *rd)
331 struct RECLAIM_TICKETS_ConsumeHandle *cth = cls;
332 struct ParallelLookup *parallel_lookup;
335 cth->lookup_request = NULL;
337 GNUNET_STATISTICS_update (
338 stats, "reclaim_authz_lookup_time_total",
339 GNUNET_TIME_absolute_get_duration (cth->lookup_start_time).rel_value_us,
341 GNUNET_STATISTICS_update (stats, "reclaim_authz_lookups_count", 1,
344 for (int i = 0; i < rd_count; i++) {
345 lbl = GNUNET_STRINGS_data_to_string_alloc (rd[i].data, rd[i].data_size);
346 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Attribute ref found %s\n", lbl);
347 parallel_lookup = GNUNET_new (struct ParallelLookup);
348 parallel_lookup->handle = cth;
349 parallel_lookup->label = lbl;
350 parallel_lookup->lookup_start_time = GNUNET_TIME_absolute_get ();
351 parallel_lookup->lookup_request = GNUNET_GNS_lookup (
352 gns, lbl, &cth->ticket.identity, GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR,
353 GNUNET_GNS_LO_DEFAULT, &process_parallel_lookup_result,
355 GNUNET_CONTAINER_DLL_insert (cth->parallel_lookups_head,
356 cth->parallel_lookups_tail, parallel_lookup);
358 cth->kill_task = GNUNET_SCHEDULER_add_delayed (
359 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 3),
360 &abort_parallel_lookups, cth);
364 struct RECLAIM_TICKETS_ConsumeHandle *
365 RECLAIM_TICKETS_consume (const struct GNUNET_CRYPTO_EcdsaPrivateKey *id,
366 const struct GNUNET_RECLAIM_Ticket *ticket,
367 RECLAIM_TICKETS_ConsumeCallback cb, void *cb_cls)
369 struct RECLAIM_TICKETS_ConsumeHandle *cth;
371 cth = GNUNET_new (struct RECLAIM_TICKETS_ConsumeHandle);
374 GNUNET_CRYPTO_ecdsa_key_get_public (&cth->identity, &cth->identity_pub);
375 cth->attrs = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList);
376 cth->ticket = *ticket;
378 cth->cb_cls = cb_cls;
380 GNUNET_STRINGS_data_to_string_alloc (&cth->ticket.rnd, sizeof (uint64_t));
381 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Looking for AuthZ info under %s\n",
383 cth->lookup_start_time = GNUNET_TIME_absolute_get ();
384 cth->lookup_request = GNUNET_GNS_lookup (
385 gns, label, &cth->ticket.identity, GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF,
386 GNUNET_GNS_LO_DEFAULT, &lookup_authz_cb, cth);
391 void RECLAIM_TICKETS_consume_cancel (struct RECLAIM_TICKETS_ConsumeHandle *cth)
398 /*******************************
400 *******************************/
403 * Cleanup ticket consume handle
404 * @param handle the handle to clean up
406 static void cleanup_issue_handle (struct TicketIssueHandle *handle)
408 struct TicketReference *tr;
409 struct TicketReference *tr_tmp;
410 if (NULL != handle->attrs)
411 GNUNET_RECLAIM_ATTRIBUTE_list_destroy (handle->attrs);
412 if (NULL != handle->ns_qe)
413 GNUNET_NAMESTORE_cancel (handle->ns_qe);
414 for (tr = handle->ticket_refs_head; NULL != tr;) {
415 if (NULL != tr->attrs)
416 GNUNET_RECLAIM_ATTRIBUTE_list_destroy (tr->attrs);
419 GNUNET_free (tr_tmp);
421 GNUNET_free (handle);
425 static void store_ticket_refs_cont (void *cls, int32_t success,
428 struct TicketIssueHandle *handle = cls;
429 handle->ns_qe = NULL;
430 if (GNUNET_OK != success) {
431 handle->cb (handle->cb_cls, NULL, GNUNET_SYSERR,
432 "Error storing updated ticket refs in GNS");
433 cleanup_issue_handle (handle);
436 handle->cb (handle->cb_cls, &handle->ticket, GNUNET_OK, NULL);
437 cleanup_issue_handle (handle);
441 static void update_ticket_refs (void *cls)
443 struct TicketIssueHandle *handle = cls;
444 struct GNUNET_GNSRECORD_Data refs_rd[handle->ticket_ref_num];
445 struct TicketReference *tr;
447 tr = handle->ticket_refs_head;
448 for (int i = 0; i < handle->ticket_ref_num; i++) {
449 refs_rd[i].data = &tr->ticket;
450 refs_rd[i].data_size = sizeof (struct GNUNET_RECLAIM_Ticket);
451 refs_rd[i].expiration_time = GNUNET_TIME_UNIT_DAYS.rel_value_us;
452 refs_rd[i].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_TICKETREF;
454 GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION | GNUNET_GNSRECORD_RF_PRIVATE;
458 handle->ns_qe = GNUNET_NAMESTORE_records_store (
459 nsh, &handle->identity, GNUNET_GNS_EMPTY_LABEL_AT, handle->ticket_ref_num,
460 refs_rd, &store_ticket_refs_cont, handle);
464 static void ticket_lookup_cb (void *cls,
465 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
466 const char *label, unsigned int rd_count,
467 const struct GNUNET_GNSRECORD_Data *rd)
469 struct TicketIssueHandle *handle = cls;
470 struct TicketReference *tr;
472 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
473 "Received tickets from local namestore.\n");
474 handle->ns_qe = NULL;
475 for (int i = 0; i < rd_count; i++) {
476 if (GNUNET_GNSRECORD_TYPE_RECLAIM_TICKETREF != rd[i].record_type)
478 tr = GNUNET_new (struct TicketReference);
479 memcpy (&tr->ticket, rd[i].data, sizeof (struct GNUNET_RECLAIM_Ticket));
480 if (0 != memcmp (&tr->ticket.identity, &handle->ticket.identity,
481 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) {
486 GNUNET_CONTAINER_DLL_insert (handle->ticket_refs_head,
487 handle->ticket_refs_tail, tr);
488 handle->ticket_ref_num++;
490 tr = GNUNET_new (struct TicketReference);
491 tr->ticket = handle->ticket;
492 tr->attrs = GNUNET_RECLAIM_ATTRIBUTE_list_dup (handle->attrs);
493 GNUNET_CONTAINER_DLL_insert (handle->ticket_refs_head,
494 handle->ticket_refs_tail, tr);
495 handle->ticket_ref_num++;
496 GNUNET_SCHEDULER_add_now (&update_ticket_refs, handle);
501 * TODO maybe we should cleanup the ATTRREFS here?
503 static void ticket_lookup_error_cb (void *cls)
505 struct TicketIssueHandle *handle = cls;
506 handle->ns_qe = NULL;
507 handle->cb (handle->cb_cls, &handle->ticket, GNUNET_SYSERR,
508 "Error checking for ticketsin GNS\n");
509 cleanup_issue_handle (handle);
512 static void store_ticket_issue_cont (void *cls, int32_t success,
515 struct TicketIssueHandle *handle = cls;
517 handle->ns_qe = NULL;
518 if (GNUNET_SYSERR == success) {
519 handle->cb (handle->cb_cls, &handle->ticket, GNUNET_SYSERR,
520 "Error storing AuthZ ticket in GNS");
523 /* First, local references to tickets */
524 handle->ns_qe = GNUNET_NAMESTORE_records_lookup (
525 nsh, &handle->identity, GNUNET_GNS_EMPTY_LABEL_AT,
526 &ticket_lookup_error_cb, handle, &ticket_lookup_cb, handle);
530 static void issue_ticket (struct TicketIssueHandle *ih)
532 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
533 struct GNUNET_GNSRECORD_Data *attrs_record;
538 for (le = ih->attrs->list_head; NULL != le; le = le->next)
542 GNUNET_malloc (list_len * sizeof (struct GNUNET_GNSRECORD_Data));
544 for (le = ih->attrs->list_head; NULL != le; le = le->next) {
545 attrs_record[i].data = &le->claim->id;
546 attrs_record[i].data_size = sizeof (le->claim->id);
547 attrs_record[i].expiration_time = GNUNET_TIME_UNIT_DAYS.rel_value_us;
548 attrs_record[i].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF;
549 attrs_record[i].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
553 GNUNET_STRINGS_data_to_string_alloc (&ih->ticket.rnd, sizeof (uint64_t));
555 ih->ns_qe = GNUNET_NAMESTORE_records_store (nsh, &ih->identity, label,
556 list_len, attrs_record,
557 &store_ticket_issue_cont, ih);
558 GNUNET_free (attrs_record);
563 void RECLAIM_TICKETS_issue (
564 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
565 const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
566 const struct GNUNET_CRYPTO_EcdsaPublicKey *audience,
567 RECLAIM_TICKETS_TicketResult cb, void *cb_cls)
569 struct TicketIssueHandle *tih;
570 tih = GNUNET_new (struct TicketIssueHandle);
572 tih->cb_cls = cb_cls;
573 tih->attrs = GNUNET_RECLAIM_ATTRIBUTE_list_dup (attrs);
574 tih->identity = *identity;
575 GNUNET_CRYPTO_ecdsa_key_get_public (identity, &tih->ticket.identity);
577 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
578 tih->ticket.audience = *audience;
582 /************************************
584 ************************************/
586 static void cleanup_iter (struct RECLAIM_TICKETS_Iterator *iter)
588 struct TicketReference *tr;
589 struct TicketReference *tr_tmp;
590 if (NULL != iter->ns_qe)
591 GNUNET_NAMESTORE_cancel (iter->ns_qe);
592 for (tr = iter->tickets_head; NULL != tr;) {
593 if (NULL != tr->attrs)
594 GNUNET_RECLAIM_ATTRIBUTE_list_destroy (tr->attrs);
597 GNUNET_free (tr_tmp);
602 static void do_cleanup_iter (void *cls)
604 struct RECLAIM_TICKETS_Iterator *iter = cls;
609 * Perform ticket iteration step
611 * @param ti ticket iterator to process
613 static void run_ticket_iteration_round (struct RECLAIM_TICKETS_Iterator *iter)
615 struct TicketReference *tr;
616 if (NULL == iter->tickets_head) {
618 iter->cb (iter->cb_cls, NULL);
619 GNUNET_SCHEDULER_add_now (&do_cleanup_iter, iter);
622 tr = iter->tickets_head;
623 GNUNET_CONTAINER_DLL_remove (iter->tickets_head, iter->tickets_tail, tr);
624 iter->cb (iter->cb_cls, &tr->ticket);
625 if (NULL != tr->attrs)
626 GNUNET_RECLAIM_ATTRIBUTE_list_destroy (tr->attrs);
631 collect_tickets_cb (void *cls, const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
632 const char *label, unsigned int rd_count,
633 const struct GNUNET_GNSRECORD_Data *rd)
635 struct RECLAIM_TICKETS_Iterator *iter = cls;
636 struct TicketReference *tr;
639 for (int i = 0; i < rd_count; i++) {
640 if (GNUNET_GNSRECORD_TYPE_RECLAIM_TICKETREF != rd[i].record_type)
642 tr = GNUNET_new (struct TicketReference);
643 memcpy (&tr->ticket, rd[i].data, sizeof (struct GNUNET_RECLAIM_Ticket));
644 if (0 != memcmp (&tr->ticket.identity, &iter->identity_pub,
645 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) {
650 GNUNET_CONTAINER_DLL_insert (iter->tickets_head, iter->tickets_tail, tr);
652 run_ticket_iteration_round (iter);
655 static void collect_tickets_error_cb (void *cls)
657 struct RECLAIM_TICKETS_Iterator *iter = cls;
659 iter->cb (iter->cb_cls, NULL);
663 void RECLAIM_TICKETS_iteration_next (struct RECLAIM_TICKETS_Iterator *iter)
665 run_ticket_iteration_round (iter);
668 void RECLAIM_TICKETS_iteration_stop (struct RECLAIM_TICKETS_Iterator *iter)
673 struct RECLAIM_TICKETS_Iterator *RECLAIM_TICKETS_iteration_start (
674 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
675 RECLAIM_TICKETS_TicketIter cb, void *cb_cls)
677 struct RECLAIM_TICKETS_Iterator *iter;
679 iter = GNUNET_new (struct RECLAIM_TICKETS_Iterator);
680 iter->identity = *identity;
681 GNUNET_CRYPTO_ecdsa_key_get_public (identity, &iter->identity_pub);
683 iter->cb_cls = cb_cls;
684 iter->ns_qe = GNUNET_NAMESTORE_records_lookup (
685 nsh, identity, GNUNET_GNS_EMPTY_LABEL_AT, &collect_tickets_error_cb, iter,
686 &collect_tickets_cb, iter);
691 int RECLAIM_TICKETS_init (const struct GNUNET_CONFIGURATION_Handle *c)
693 // Connect to identity and namestore services
694 nsh = GNUNET_NAMESTORE_connect (c);
696 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
697 "error connecting to namestore");
698 return GNUNET_SYSERR;
700 gns = GNUNET_GNS_connect (c);
702 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to gns");
703 return GNUNET_SYSERR;
705 stats = GNUNET_STATISTICS_create ("reclaim", c);
709 void RECLAIM_TICKETS_deinit (void)
712 GNUNET_NAMESTORE_disconnect (nsh);
715 GNUNET_GNS_disconnect (gns);
718 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);