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
21 * @author Martin Schanzenbach
22 * @file src/reclaim/gnunet-service-reclaim.c
23 * @brief reclaim Service
27 #include "gnunet_util_lib.h"
28 #include "gnunet-service-reclaim_tickets.h"
29 #include "gnunet_constants.h"
30 #include "gnunet_gnsrecord_lib.h"
31 #include "gnunet_identity_service.h"
32 #include "gnunet_namestore_service.h"
33 #include "gnunet_protocols.h"
34 #include "gnunet_reclaim_attribute_lib.h"
35 #include "gnunet_reclaim_service.h"
36 #include "gnunet_signatures.h"
45 * Normal operation state
47 #define STATE_POST_INIT 1
50 * Minimum interval between updates
52 #define MIN_WAIT_TIME GNUNET_TIME_UNIT_MINUTES
55 * Standard token expiration time
57 #define DEFAULT_TOKEN_EXPIRATION_INTERVAL GNUNET_TIME_UNIT_HOURS
62 static struct GNUNET_IDENTITY_Handle *identity_handle;
65 * Token expiration interval
67 static struct GNUNET_TIME_Relative token_expiration_interval;
72 static struct GNUNET_NAMESTORE_Handle *nsh;
77 static struct GNUNET_SCHEDULER_Task *timeout_task;
82 static struct GNUNET_SCHEDULER_Task *update_task;
87 static const struct GNUNET_CONFIGURATION_Handle *cfg;
95 * A ticket iteration operation.
97 struct TicketIteration
102 struct TicketIteration *next;
107 struct TicketIteration *prev;
110 * Client which intiated this zone iteration
112 struct IdpClient *client;
115 * The operation id fot the iteration in the response for the client
120 * The ticket iterator
122 struct RECLAIM_TICKETS_Iterator *iter;
127 * An attribute iteration operation.
129 struct AttributeIterator
132 * Next element in the DLL
134 struct AttributeIterator *next;
137 * Previous element in the DLL
139 struct AttributeIterator *prev;
142 * IDP client which intiated this zone iteration
144 struct IdpClient *client;
147 * Key of the zone we are iterating over.
149 struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
154 struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
157 * The operation id fot the zone iteration in the response for the client
172 struct GNUNET_SERVICE_Client *client;
175 * Message queue for transmission to @e client
177 struct GNUNET_MQ_Handle *mq;
181 * Attribute iteration operations in
182 * progress initiated by this client
184 struct AttributeIterator *attr_iter_head;
188 * Attribute iteration operations
189 * in progress initiated by this client
191 struct AttributeIterator *attr_iter_tail;
194 * Head of DLL of ticket iteration ops
196 struct TicketIteration *ticket_iter_head;
199 * Tail of DLL of ticket iteration ops
201 struct TicketIteration *ticket_iter_tail;
204 * Head of DLL of ticket revocation ops
206 struct TicketRevocationOperation *revoke_op_head;
209 * Tail of DLL of ticket revocation ops
211 struct TicketRevocationOperation *revoke_op_tail;
214 * Head of DLL of ticket issue ops
216 struct TicketIssueOperation *issue_op_head;
219 * Tail of DLL of ticket issue ops
221 struct TicketIssueOperation *issue_op_tail;
224 * Head of DLL of ticket consume ops
226 struct ConsumeTicketOperation *consume_op_head;
229 * Tail of DLL of ticket consume ops
231 struct ConsumeTicketOperation *consume_op_tail;
234 * Head of DLL of attribute store ops
236 struct AttributeStoreHandle *store_op_head;
239 * Tail of DLL of attribute store ops
241 struct AttributeStoreHandle *store_op_tail;
243 * Head of DLL of attribute delete ops
245 struct AttributeDeleteHandle *delete_op_head;
248 * Tail of DLL of attribute delete ops
250 struct AttributeDeleteHandle *delete_op_tail;
255 * Handle for attribute deletion request
257 struct AttributeDeleteHandle
262 struct AttributeDeleteHandle *next;
267 struct AttributeDeleteHandle *prev;
272 struct IdpClient *client;
277 struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
283 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
288 struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
291 * The attribute to delete
293 struct GNUNET_RECLAIM_ATTRIBUTE_Claim *claim;
298 struct TicketRecordsEntry *tickets_to_update_head;
303 struct TicketRecordsEntry *tickets_to_update_tail;
318 * Handle for attribute store request
320 struct AttributeStoreHandle
325 struct AttributeStoreHandle *next;
330 struct AttributeStoreHandle *prev;
335 struct IdpClient *client;
340 struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
345 struct GNUNET_CRYPTO_EcdsaPublicKey identity_pkey;
350 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
353 * The attribute to store
355 struct GNUNET_RECLAIM_ATTRIBUTE_Claim *claim;
358 * The attribute expiration interval
360 struct GNUNET_TIME_Relative exp;
370 * Handle for ticket consume request
372 struct ConsumeTicketOperation
377 struct ConsumeTicketOperation *next;
382 struct ConsumeTicketOperation *prev;
387 struct IdpClient *client;
395 * Ticket consume handle
397 struct RECLAIM_TICKETS_ConsumeHandle *ch;
402 * Updated attribute IDs
404 struct TicketAttributeUpdateEntry
409 struct TicketAttributeUpdateEntry *next;
414 struct TicketAttributeUpdateEntry *prev;
429 * Ticket revocation request handle
431 struct TicketRevocationOperation
436 struct TicketRevocationOperation *prev;
441 struct TicketRevocationOperation *next;
446 struct IdpClient *client;
451 struct RECLAIM_TICKETS_RevokeHandle *rh;
461 * Ticket issue operation handle
463 struct TicketIssueOperation
468 struct TicketIssueOperation *prev;
473 struct TicketIssueOperation *next;
478 struct IdpClient *client;
488 * DLL for ego handles to egos containing the RECLAIM_ATTRS in a
489 * map in json_t format
497 struct EgoEntry *next;
502 struct EgoEntry *prev;
507 struct GNUNET_IDENTITY_Ego *ego;
510 * Attribute map. Contains the attributes as json_t
512 struct GNUNET_CONTAINER_MultiHashMap *attr_map;
522 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
524 RECLAIM_TICKETS_deinit ();
525 if (NULL != timeout_task)
526 GNUNET_SCHEDULER_cancel (timeout_task);
527 if (NULL != update_task)
528 GNUNET_SCHEDULER_cancel (update_task);
529 if (NULL != identity_handle)
530 GNUNET_IDENTITY_disconnect (identity_handle);
532 GNUNET_NAMESTORE_disconnect (nsh);
542 do_shutdown (void *cls)
544 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down...\n");
550 * Sends a ticket result message to the client
552 * @param client the client to send to
553 * @param r_id the request message ID to reply to
554 * @param ticket the ticket to include (may be NULL)
555 * @param success the success status of the request
558 send_ticket_result (const struct IdpClient *client,
560 const struct GNUNET_RECLAIM_Ticket *ticket,
563 struct TicketResultMessage *irm;
564 struct GNUNET_MQ_Envelope *env;
565 struct GNUNET_RECLAIM_Ticket *ticket_buf;
567 if (NULL != ticket) {
568 env = GNUNET_MQ_msg_extra (irm,
569 sizeof (struct GNUNET_RECLAIM_Ticket),
570 GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT);
571 ticket_buf = (struct GNUNET_RECLAIM_Ticket *)&irm[1];
572 *ticket_buf = *ticket;
574 env = GNUNET_MQ_msg (irm, GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT);
576 // TODO add success member
577 irm->id = htonl (r_id);
578 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending TICKET_RESULT message\n");
579 GNUNET_MQ_send (client->mq, env);
584 * Issue ticket result
586 * @param cls out ticket issue operation handle
587 * @param ticket the issued ticket
588 * @param success issue success status (GNUNET_OK if successful)
589 * @param emsg error message (NULL of success is GNUNET_OK)
592 issue_ticket_result_cb (void *cls,
593 struct GNUNET_RECLAIM_Ticket *ticket,
597 struct TicketIssueOperation *tio = cls;
598 if (GNUNET_OK != success) {
599 send_ticket_result (tio->client, tio->r_id, NULL, GNUNET_SYSERR);
600 GNUNET_CONTAINER_DLL_remove (tio->client->issue_op_head,
601 tio->client->issue_op_tail,
604 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error issuing ticket: %s\n", emsg);
607 send_ticket_result (tio->client, tio->r_id, ticket, GNUNET_SYSERR);
608 GNUNET_CONTAINER_DLL_remove (tio->client->issue_op_head,
609 tio->client->issue_op_tail,
616 * Check issue ticket message
619 * @im message to check
620 * @return GNUNET_OK if message is ok
623 check_issue_ticket_message (void *cls, const struct IssueTicketMessage *im)
627 size = ntohs (im->header.size);
628 if (size <= sizeof (struct IssueTicketMessage)) {
630 return GNUNET_SYSERR;
637 * Handle ticket issue message
639 * @param cls our client
640 * @param im the message
643 handle_issue_ticket_message (void *cls, const struct IssueTicketMessage *im)
645 struct TicketIssueOperation *tio;
646 struct IdpClient *idp = cls;
647 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs;
650 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ISSUE_TICKET message\n");
651 tio = GNUNET_new (struct TicketIssueOperation);
652 attrs_len = ntohs (im->attr_len);
653 attrs = GNUNET_RECLAIM_ATTRIBUTE_list_deserialize ((char *)&im[1], attrs_len);
654 tio->r_id = ntohl (im->id);
656 GNUNET_CONTAINER_DLL_insert (idp->issue_op_head, idp->issue_op_tail, tio);
657 RECLAIM_TICKETS_issue (&im->identity,
660 &issue_ticket_result_cb,
662 GNUNET_SERVICE_client_continue (idp->client);
663 GNUNET_RECLAIM_ATTRIBUTE_list_destroy (attrs);
668 /**********************************************************
670 **********************************************************/
673 * Handles revocation result
675 * @param cls our revocation operation handle
676 * @param success revocation result (GNUNET_OK if successful)
679 revoke_result_cb (void *cls, int32_t success)
681 struct TicketRevocationOperation *rop = cls;
682 struct GNUNET_MQ_Envelope *env;
683 struct RevokeTicketResultMessage *trm;
685 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending REVOKE_TICKET_RESULT message\n");
687 env = GNUNET_MQ_msg (trm, GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET_RESULT);
688 trm->id = htonl (rop->r_id);
689 trm->success = htonl (success);
690 GNUNET_MQ_send (rop->client->mq, env);
691 GNUNET_CONTAINER_DLL_remove (rop->client->revoke_op_head,
692 rop->client->revoke_op_tail,
699 * Check revocation message format
702 * @param im the message to check
703 * @return GNUNET_OK if message is ok
706 check_revoke_ticket_message (void *cls, const struct RevokeTicketMessage *im)
710 size = ntohs (im->header.size);
711 if (size <= sizeof (struct RevokeTicketMessage)) {
713 return GNUNET_SYSERR;
720 * Handle a revocation message to a ticket.
722 * @param cls our client
723 * @param rm the message to handle
726 handle_revoke_ticket_message (void *cls, const struct RevokeTicketMessage *rm)
728 struct TicketRevocationOperation *rop;
729 struct IdpClient *idp = cls;
730 struct GNUNET_RECLAIM_Ticket *ticket;
732 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received REVOKE_TICKET message\n");
733 rop = GNUNET_new (struct TicketRevocationOperation);
734 ticket = (struct GNUNET_RECLAIM_Ticket *)&rm[1];
735 rop->r_id = ntohl (rm->id);
737 GNUNET_CONTAINER_DLL_insert (idp->revoke_op_head, idp->revoke_op_tail, rop);
739 = RECLAIM_TICKETS_revoke (ticket, &rm->identity, &revoke_result_cb, rop);
740 GNUNET_SERVICE_client_continue (idp->client);
745 * Handle a ticket consume result
747 * @param cls our consume ticket operation handle
748 * @param identity the attribute authority
749 * @param attrs the attribute/claim list
750 * @param success GNUNET_OK if successful
751 * @param emsg error message (NULL if success=GNUNET_OK)
754 consume_result_cb (void *cls,
755 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
756 const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
760 struct ConsumeTicketOperation *cop = cls;
761 struct ConsumeTicketResultMessage *crm;
762 struct GNUNET_MQ_Envelope *env;
765 if (GNUNET_OK != success) {
766 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error consuming ticket: %s\n", emsg);
768 attrs_len = GNUNET_RECLAIM_ATTRIBUTE_list_serialize_get_size (attrs);
769 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending CONSUME_TICKET_RESULT message\n");
770 env = GNUNET_MQ_msg_extra (crm,
772 GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT);
773 crm->id = htonl (cop->r_id);
774 crm->attrs_len = htons (attrs_len);
775 crm->identity = *identity;
776 crm->result = htonl (success);
777 data_tmp = (char *)&crm[1];
778 GNUNET_RECLAIM_ATTRIBUTE_list_serialize (attrs, data_tmp);
779 GNUNET_MQ_send (cop->client->mq, env);
780 GNUNET_CONTAINER_DLL_remove (cop->client->consume_op_head,
781 cop->client->consume_op_tail,
788 * Check a consume ticket message
791 * @param cm the message to handle
794 check_consume_ticket_message (void *cls, const struct ConsumeTicketMessage *cm)
798 size = ntohs (cm->header.size);
799 if (size <= sizeof (struct ConsumeTicketMessage)) {
801 return GNUNET_SYSERR;
808 * Handle a consume ticket message
810 * @param cls our client handle
811 * @cm the message to handle
814 handle_consume_ticket_message (void *cls, const struct ConsumeTicketMessage *cm)
816 struct ConsumeTicketOperation *cop;
817 struct GNUNET_RECLAIM_Ticket *ticket;
818 struct IdpClient *idp = cls;
820 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received CONSUME_TICKET message\n");
821 cop = GNUNET_new (struct ConsumeTicketOperation);
822 cop->r_id = ntohl (cm->id);
824 ticket = (struct GNUNET_RECLAIM_Ticket *)&cm[1];
826 = RECLAIM_TICKETS_consume (&cm->identity, ticket, &consume_result_cb, cop);
827 GNUNET_CONTAINER_DLL_insert (idp->consume_op_head, idp->consume_op_tail, cop);
828 GNUNET_SERVICE_client_continue (idp->client);
831 /*****************************************
833 *****************************************/
836 * Cleanup attribute store handle
838 * @param handle handle to clean up
841 cleanup_as_handle (struct AttributeStoreHandle *ash)
843 if (NULL != ash->ns_qe)
844 GNUNET_NAMESTORE_cancel (ash->ns_qe);
845 if (NULL != ash->claim)
846 GNUNET_free (ash->claim);
852 * Attribute store result handler
854 * @param cls our attribute store handle
855 * @param success GNUNET_OK if successful
856 * @param emsg error message (NULL if success=GNUNET_OK)
859 attr_store_cont (void *cls, int32_t success, const char *emsg)
861 struct AttributeStoreHandle *ash = cls;
862 struct GNUNET_MQ_Envelope *env;
863 struct SuccessResultMessage *acr_msg;
866 GNUNET_CONTAINER_DLL_remove (ash->client->store_op_head,
867 ash->client->store_op_tail,
870 if (GNUNET_SYSERR == success) {
871 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
872 "Failed to store attribute %s\n",
874 cleanup_as_handle (ash);
875 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
879 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending SUCCESS_RESPONSE message\n");
880 env = GNUNET_MQ_msg (acr_msg, GNUNET_MESSAGE_TYPE_RECLAIM_SUCCESS_RESPONSE);
881 acr_msg->id = htonl (ash->r_id);
882 acr_msg->op_result = htonl (GNUNET_OK);
883 GNUNET_MQ_send (ash->client->mq, env);
884 cleanup_as_handle (ash);
889 * Add a new attribute
891 * @param cls the AttributeStoreHandle
894 attr_store_task (void *cls)
896 struct AttributeStoreHandle *ash = cls;
897 struct GNUNET_GNSRECORD_Data rd[1];
902 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Storing attribute\n");
903 buf_size = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (ash->claim);
904 buf = GNUNET_malloc (buf_size);
905 // Give the ash a new id if unset
906 if (0 == ash->claim->id)
908 = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
909 GNUNET_RECLAIM_ATTRIBUTE_serialize (ash->claim, buf);
911 = GNUNET_STRINGS_data_to_string_alloc (&ash->claim->id, sizeof (uint64_t));
912 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypting with label %s\n", label);
914 rd[0].data_size = buf_size;
916 rd[0].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR;
917 rd[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
918 rd[0].expiration_time = ash->exp.rel_value_us;
919 ash->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
931 * Check an attribute store message
934 * @param sam the message to check
937 check_attribute_store_message (void *cls,
938 const struct AttributeStoreMessage *sam)
942 size = ntohs (sam->header.size);
943 if (size <= sizeof (struct AttributeStoreMessage)) {
945 return GNUNET_SYSERR;
952 * Handle an attribute store message
954 * @param cls our client
955 * @param sam the message to handle
958 handle_attribute_store_message (void *cls,
959 const struct AttributeStoreMessage *sam)
961 struct AttributeStoreHandle *ash;
962 struct IdpClient *idp = cls;
964 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ATTRIBUTE_STORE message\n");
966 data_len = ntohs (sam->attr_len);
968 ash = GNUNET_new (struct AttributeStoreHandle);
969 ash->claim = GNUNET_RECLAIM_ATTRIBUTE_deserialize ((char *)&sam[1], data_len);
971 ash->r_id = ntohl (sam->id);
972 ash->identity = sam->identity;
973 ash->exp.rel_value_us = GNUNET_ntohll (sam->exp);
974 GNUNET_CRYPTO_ecdsa_key_get_public (&sam->identity, &ash->identity_pkey);
976 GNUNET_SERVICE_client_continue (idp->client);
978 GNUNET_CONTAINER_DLL_insert (idp->store_op_head, idp->store_op_tail, ash);
979 GNUNET_SCHEDULER_add_now (&attr_store_task, ash);
984 * Cleanup attribute delete handle
986 * @param adh the attribute to cleanup
989 cleanup_adh (struct AttributeDeleteHandle *adh)
991 struct TicketRecordsEntry *le;
992 if (NULL != adh->ns_it)
993 GNUNET_NAMESTORE_zone_iteration_stop (adh->ns_it);
994 if (NULL != adh->ns_qe)
995 GNUNET_NAMESTORE_cancel (adh->ns_qe);
996 if (NULL != adh->label)
997 GNUNET_free (adh->label);
998 if (NULL != adh->claim)
999 GNUNET_free (adh->claim);
1000 while (NULL != (le = adh->tickets_to_update_head)) {
1001 GNUNET_CONTAINER_DLL_remove (adh->tickets_to_update_head,
1002 adh->tickets_to_update_tail,
1004 if (NULL != le->label)
1005 GNUNET_free (le->label);
1006 if (NULL != le->data)
1007 GNUNET_free (le->data);
1015 * Send a deletion success response
1017 * @param adh our attribute deletion handle
1018 * @param success the success status
1021 send_delete_response (struct AttributeDeleteHandle *adh, int32_t success)
1023 struct GNUNET_MQ_Envelope *env;
1024 struct SuccessResultMessage *acr_msg;
1026 GNUNET_CONTAINER_DLL_remove (adh->client->delete_op_head,
1027 adh->client->delete_op_tail,
1030 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending SUCCESS_RESPONSE message\n");
1031 env = GNUNET_MQ_msg (acr_msg, GNUNET_MESSAGE_TYPE_RECLAIM_SUCCESS_RESPONSE);
1032 acr_msg->id = htonl (adh->r_id);
1033 acr_msg->op_result = htonl (success);
1034 GNUNET_MQ_send (adh->client->mq, env);
1039 * Namestore iteration within attribute deletion.
1040 * We need to reissue tickets with the deleted attribute removed.
1042 * @param cls our attribute deletion handle
1043 * @param zone the private key of the ticket issuer
1044 * @param label the label of the record
1045 * @param rd_count number of records
1046 * @param rd record data
1049 ticket_iter (void *cls,
1050 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1052 unsigned int rd_count,
1053 const struct GNUNET_GNSRECORD_Data *rd)
1055 struct AttributeDeleteHandle *adh = cls;
1056 struct TicketRecordsEntry *le;
1057 int has_changed = GNUNET_NO;
1059 for (int i = 0; i < rd_count; i++) {
1060 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
1062 if (0 != memcmp (rd[i].data, &adh->claim->id, sizeof (uint64_t)))
1064 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1065 "Attribute to delete found (%s)\n",
1067 has_changed = GNUNET_YES;
1070 if (GNUNET_YES == has_changed) {
1071 le = GNUNET_new (struct TicketRecordsEntry);
1072 le->data_size = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
1073 le->data = GNUNET_malloc (le->data_size);
1074 le->rd_count = rd_count;
1075 le->label = GNUNET_strdup (label);
1076 GNUNET_GNSRECORD_records_serialize (rd_count, rd, le->data_size, le->data);
1077 GNUNET_CONTAINER_DLL_insert (adh->tickets_to_update_head,
1078 adh->tickets_to_update_tail,
1081 GNUNET_NAMESTORE_zone_iterator_next (adh->ns_it, 1);
1086 * Recursion prototype for function
1087 * @param cls our deletion handle
1090 update_tickets (void *cls);
1094 * Callback called when a ticket was updated
1096 * @param cls our attribute deletion handle
1097 * @param success GNUNET_OK if successful
1098 * @param emsg error message (NULL if success=GNUNET_OK)
1101 ticket_updated (void *cls, int32_t success, const char *emsg)
1103 struct AttributeDeleteHandle *adh = cls;
1105 GNUNET_SCHEDULER_add_now (&update_tickets, adh);
1110 * Update tickets: Remove shared attribute which has just been deleted.
1111 * This method is called recursively until all tickets are processed.
1112 * Eventually, the updated tickets are stored using ``update_tickets''.
1114 * @param cls our attribute deletion handle
1117 update_tickets (void *cls)
1119 struct AttributeDeleteHandle *adh = cls;
1120 struct TicketRecordsEntry *le;
1121 if (NULL == adh->tickets_to_update_head) {
1122 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1123 "Finished updatding tickets, success\n");
1124 send_delete_response (adh, GNUNET_OK);
1128 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1130 adh->tickets_to_update_head->label);
1131 le = adh->tickets_to_update_head;
1132 GNUNET_CONTAINER_DLL_remove (adh->tickets_to_update_head,
1133 adh->tickets_to_update_tail,
1135 struct GNUNET_GNSRECORD_Data rd[le->rd_count];
1136 struct GNUNET_GNSRECORD_Data rd_new[le->rd_count - 1];
1137 GNUNET_GNSRECORD_records_deserialize (le->data_size,
1142 for (int i = 0; i < le->rd_count; i++) {
1143 if ((GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF == rd[i].record_type)
1144 && (0 == memcmp (rd[i].data, &adh->claim->id, sizeof (uint64_t))))
1149 adh->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
1156 GNUNET_free (le->label);
1157 GNUNET_free (le->data);
1163 * Done collecting affected tickets, start updating.
1165 * @param cls our attribute deletion handle
1168 ticket_iter_fin (void *cls)
1170 struct AttributeDeleteHandle *adh = cls;
1172 GNUNET_SCHEDULER_add_now (&update_tickets, adh);
1177 * Error collecting affected tickets. Abort.
1179 * @param cls our attribute deletion handle
1182 ticket_iter_err (void *cls)
1184 struct AttributeDeleteHandle *adh = cls;
1186 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1187 "Namestore error on delete %s\n",
1189 send_delete_response (adh, GNUNET_SYSERR);
1195 * Start processing tickets which may still contain reference to deleted
1198 * @param cls attribute deletion handle
1201 start_ticket_update (void *cls)
1203 struct AttributeDeleteHandle *adh = cls;
1204 adh->ns_it = GNUNET_NAMESTORE_zone_iteration_start (nsh,
1216 * Attribute deleted callback
1218 * @param cls our handle
1219 * @param success success status
1220 * @param emsg error message (NULL if success=GNUNET_OK)
1223 attr_delete_cont (void *cls, int32_t success, const char *emsg)
1225 struct AttributeDeleteHandle *adh = cls;
1227 if (GNUNET_SYSERR == success) {
1228 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1229 "Error deleting attribute %s\n",
1231 send_delete_response (adh, GNUNET_SYSERR);
1235 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating tickets...\n");
1236 GNUNET_SCHEDULER_add_now (&start_ticket_update, adh);
1241 * Check attribute delete message format
1244 * @dam message to check
1247 check_attribute_delete_message (void *cls,
1248 const struct AttributeDeleteMessage *dam)
1252 size = ntohs (dam->header.size);
1253 if (size <= sizeof (struct AttributeDeleteMessage)) {
1255 return GNUNET_SYSERR;
1262 * Handle attribute deletion
1264 * @param cls our client
1265 * @param dam deletion message
1268 handle_attribute_delete_message (void *cls,
1269 const struct AttributeDeleteMessage *dam)
1271 struct AttributeDeleteHandle *adh;
1272 struct IdpClient *idp = cls;
1274 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ATTRIBUTE_DELETE message\n");
1276 data_len = ntohs (dam->attr_len);
1278 adh = GNUNET_new (struct AttributeDeleteHandle);
1279 adh->claim = GNUNET_RECLAIM_ATTRIBUTE_deserialize ((char *)&dam[1], data_len);
1281 adh->r_id = ntohl (dam->id);
1282 adh->identity = dam->identity;
1284 = GNUNET_STRINGS_data_to_string_alloc (&adh->claim->id, sizeof (uint64_t));
1285 GNUNET_SERVICE_client_continue (idp->client);
1287 GNUNET_CONTAINER_DLL_insert (idp->delete_op_head, idp->delete_op_tail, adh);
1288 adh->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
1298 /*************************************************
1299 * Attrubute iteration
1300 *************************************************/
1304 * Done iterating over attributes
1306 * @param cls our iterator handle
1309 attr_iter_finished (void *cls)
1311 struct AttributeIterator *ai = cls;
1312 struct GNUNET_MQ_Envelope *env;
1313 struct AttributeResultMessage *arm;
1315 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending ATTRIBUTE_RESULT message\n");
1316 env = GNUNET_MQ_msg (arm, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT);
1317 arm->id = htonl (ai->request_id);
1318 arm->attr_len = htons (0);
1319 GNUNET_MQ_send (ai->client->mq, env);
1320 GNUNET_CONTAINER_DLL_remove (ai->client->attr_iter_head,
1321 ai->client->attr_iter_tail,
1327 * Error iterating over attributes. Abort.
1329 * @param cls our attribute iteration handle
1332 attr_iter_error (void *cls)
1334 struct AttributeIterator *ai = cls;
1336 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to iterate over attributes\n");
1337 attr_iter_finished (ai);
1342 * Got record. Return if it is an attribute.
1344 * @param cls our attribute iterator
1345 * @param zone zone we are iterating
1346 * @param label label of the records
1347 * @param rd_count record count
1351 attr_iter_cb (void *cls,
1352 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1354 unsigned int rd_count,
1355 const struct GNUNET_GNSRECORD_Data *rd)
1357 struct AttributeIterator *ai = cls;
1358 struct AttributeResultMessage *arm;
1359 struct GNUNET_MQ_Envelope *env;
1362 if (rd_count != 1) {
1363 GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1);
1367 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR != rd->record_type) {
1368 GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1);
1371 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found attribute under: %s\n", label);
1372 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending ATTRIBUTE_RESULT message\n");
1373 env = GNUNET_MQ_msg_extra (arm,
1375 GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT);
1376 arm->id = htonl (ai->request_id);
1377 arm->attr_len = htons (rd->data_size);
1378 GNUNET_CRYPTO_ecdsa_key_get_public (zone, &arm->identity);
1379 data_tmp = (char *)&arm[1];
1380 GNUNET_memcpy (data_tmp, rd->data, rd->data_size);
1381 GNUNET_MQ_send (ai->client->mq, env);
1386 * Iterate over zone to get attributes
1388 * @param cls our client
1389 * @param ais_msg the iteration message to start
1392 handle_iteration_start (void *cls,
1393 const struct AttributeIterationStartMessage *ais_msg)
1395 struct IdpClient *idp = cls;
1396 struct AttributeIterator *ai;
1398 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1399 "Received ATTRIBUTE_ITERATION_START message\n");
1400 ai = GNUNET_new (struct AttributeIterator);
1401 ai->request_id = ntohl (ais_msg->id);
1403 ai->identity = ais_msg->identity;
1405 GNUNET_CONTAINER_DLL_insert (idp->attr_iter_head, idp->attr_iter_tail, ai);
1406 ai->ns_it = GNUNET_NAMESTORE_zone_iteration_start (nsh,
1412 &attr_iter_finished,
1414 GNUNET_SERVICE_client_continue (idp->client);
1419 * Handle iteration stop message from client
1421 * @param cls the client
1422 * @param ais_msg the stop message
1425 handle_iteration_stop (void *cls,
1426 const struct AttributeIterationStopMessage *ais_msg)
1428 struct IdpClient *idp = cls;
1429 struct AttributeIterator *ai;
1432 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1433 "Received `%s' message\n",
1434 "ATTRIBUTE_ITERATION_STOP");
1435 rid = ntohl (ais_msg->id);
1436 for (ai = idp->attr_iter_head; NULL != ai; ai = ai->next)
1437 if (ai->request_id == rid)
1441 GNUNET_SERVICE_client_drop (idp->client);
1444 GNUNET_CONTAINER_DLL_remove (idp->attr_iter_head, idp->attr_iter_tail, ai);
1446 GNUNET_SERVICE_client_continue (idp->client);
1451 * Client requests next attribute from iterator
1453 * @param cls the client
1454 * @param ais_msg the message
1457 handle_iteration_next (void *cls,
1458 const struct AttributeIterationNextMessage *ais_msg)
1460 struct IdpClient *idp = cls;
1461 struct AttributeIterator *ai;
1464 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1465 "Received ATTRIBUTE_ITERATION_NEXT message\n");
1466 rid = ntohl (ais_msg->id);
1467 for (ai = idp->attr_iter_head; NULL != ai; ai = ai->next)
1468 if (ai->request_id == rid)
1472 GNUNET_SERVICE_client_drop (idp->client);
1475 GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1);
1476 GNUNET_SERVICE_client_continue (idp->client);
1479 /******************************************************
1481 ******************************************************/
1484 * Got a ticket. Return to client
1486 * @param cls our ticket iterator
1487 * @param ticket the ticket
1490 ticket_iter_cb (void *cls, struct GNUNET_RECLAIM_Ticket *ticket)
1492 struct TicketIteration *ti = cls;
1493 struct GNUNET_MQ_Envelope *env;
1494 struct TicketResultMessage *trm;
1496 if (NULL == ticket) {
1497 /* send empty response to indicate end of list */
1498 env = GNUNET_MQ_msg (trm, GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT);
1499 GNUNET_CONTAINER_DLL_remove (ti->client->ticket_iter_head,
1500 ti->client->ticket_iter_tail,
1503 env = GNUNET_MQ_msg_extra (trm,
1504 sizeof (struct GNUNET_RECLAIM_Ticket),
1505 GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT);
1506 memcpy (&trm[1], ticket, sizeof (struct GNUNET_RECLAIM_Ticket));
1508 trm->id = htonl (ti->r_id);
1509 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending TICKET_RESULT message\n");
1510 GNUNET_MQ_send (ti->client->mq, env);
1517 * Client requests a ticket iteration
1519 * @param cls the client
1520 * @param tis_msg the iteration request message
1523 handle_ticket_iteration_start (
1525 const struct TicketIterationStartMessage *tis_msg)
1527 struct IdpClient *client = cls;
1528 struct TicketIteration *ti;
1530 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1531 "Received TICKET_ITERATION_START message\n");
1532 ti = GNUNET_new (struct TicketIteration);
1533 ti->r_id = ntohl (tis_msg->id);
1534 ti->client = client;
1536 GNUNET_CONTAINER_DLL_insert (client->ticket_iter_head,
1537 client->ticket_iter_tail,
1540 = RECLAIM_TICKETS_iteration_start (&tis_msg->identity, &ticket_iter_cb, ti);
1541 GNUNET_SERVICE_client_continue (client->client);
1546 * Client has had enough tickets
1548 * @param cls the client
1549 * @param tis_msg the stop message
1552 handle_ticket_iteration_stop (void *cls,
1553 const struct TicketIterationStopMessage *tis_msg)
1555 struct IdpClient *client = cls;
1556 struct TicketIteration *ti;
1559 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1560 "Received `%s' message\n",
1561 "TICKET_ITERATION_STOP");
1562 rid = ntohl (tis_msg->id);
1563 for (ti = client->ticket_iter_head; NULL != ti; ti = ti->next)
1564 if (ti->r_id == rid)
1568 GNUNET_SERVICE_client_drop (client->client);
1571 RECLAIM_TICKETS_iteration_stop (ti->iter);
1572 GNUNET_CONTAINER_DLL_remove (client->ticket_iter_head,
1573 client->ticket_iter_tail,
1576 GNUNET_SERVICE_client_continue (client->client);
1581 * Client requests next result.
1583 * @param cls the client
1584 * @param tis_msg the message
1587 handle_ticket_iteration_next (void *cls,
1588 const struct TicketIterationNextMessage *tis_msg)
1590 struct IdpClient *client = cls;
1591 struct TicketIteration *ti;
1594 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1595 "Received TICKET_ITERATION_NEXT message\n");
1596 rid = ntohl (tis_msg->id);
1597 for (ti = client->ticket_iter_head; NULL != ti; ti = ti->next)
1598 if (ti->r_id == rid)
1602 GNUNET_SERVICE_client_drop (client->client);
1605 RECLAIM_TICKETS_iteration_next (ti->iter);
1606 GNUNET_SERVICE_client_continue (client->client);
1611 * Main function that will be run
1613 * @param cls closure
1614 * @param c the configuration used
1615 * @param server the service handle
1619 const struct GNUNET_CONFIGURATION_Handle *c,
1620 struct GNUNET_SERVICE_Handle *server)
1624 if (GNUNET_OK != RECLAIM_TICKETS_init (cfg)) {
1625 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1626 "Unable to initialized TICKETS subsystem.\n");
1627 GNUNET_SCHEDULER_shutdown ();
1630 // Connect to identity and namestore services
1631 nsh = GNUNET_NAMESTORE_connect (cfg);
1633 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1634 "error connecting to namestore");
1637 identity_handle = GNUNET_IDENTITY_connect (cfg, NULL, NULL);
1640 == GNUNET_CONFIGURATION_get_value_time (cfg,
1642 "TOKEN_EXPIRATION_INTERVAL",
1643 &token_expiration_interval)) {
1645 GNUNET_ERROR_TYPE_DEBUG,
1646 "Time window for zone iteration: %s\n",
1647 GNUNET_STRINGS_relative_time_to_string (token_expiration_interval,
1650 token_expiration_interval = DEFAULT_TOKEN_EXPIRATION_INTERVAL;
1653 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
1658 * Called whenever a client is disconnected.
1660 * @param cls closure
1661 * @param client identification of the client
1662 * @param app_ctx @a client
1665 client_disconnect_cb (void *cls,
1666 struct GNUNET_SERVICE_Client *client,
1669 struct IdpClient *idp = app_ctx;
1670 struct AttributeIterator *ai;
1671 struct TicketIteration *ti;
1672 struct TicketRevocationOperation *rop;
1673 struct TicketIssueOperation *iss;
1674 struct ConsumeTicketOperation *ct;
1675 struct AttributeStoreHandle *as;
1676 struct AttributeDeleteHandle *adh;
1678 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p disconnected\n", client);
1680 while (NULL != (iss = idp->issue_op_head)) {
1681 GNUNET_CONTAINER_DLL_remove (idp->issue_op_head, idp->issue_op_tail, iss);
1684 while (NULL != (ct = idp->consume_op_head)) {
1685 GNUNET_CONTAINER_DLL_remove (idp->consume_op_head,
1686 idp->consume_op_tail,
1689 RECLAIM_TICKETS_consume_cancel (ct->ch);
1692 while (NULL != (as = idp->store_op_head)) {
1693 GNUNET_CONTAINER_DLL_remove (idp->store_op_head, idp->store_op_tail, as);
1694 cleanup_as_handle (as);
1696 while (NULL != (adh = idp->delete_op_head)) {
1697 GNUNET_CONTAINER_DLL_remove (idp->delete_op_head, idp->delete_op_tail, adh);
1701 while (NULL != (ai = idp->attr_iter_head)) {
1702 GNUNET_CONTAINER_DLL_remove (idp->attr_iter_head, idp->attr_iter_tail, ai);
1705 while (NULL != (rop = idp->revoke_op_head)) {
1706 GNUNET_CONTAINER_DLL_remove (idp->revoke_op_head, idp->revoke_op_tail, rop);
1707 if (NULL != rop->rh)
1708 RECLAIM_TICKETS_revoke_cancel (rop->rh);
1711 while (NULL != (ti = idp->ticket_iter_head)) {
1712 GNUNET_CONTAINER_DLL_remove (idp->ticket_iter_head,
1713 idp->ticket_iter_tail,
1722 * Add a client to our list of active clients.
1725 * @param client client to add
1726 * @param mq message queue for @a client
1727 * @return internal namestore client structure for this client
1730 client_connect_cb (void *cls,
1731 struct GNUNET_SERVICE_Client *client,
1732 struct GNUNET_MQ_Handle *mq)
1734 struct IdpClient *idp;
1735 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", client);
1736 idp = GNUNET_new (struct IdpClient);
1737 idp->client = client;
1744 * Define "main" method using service macro.
1746 GNUNET_SERVICE_MAIN (
1748 GNUNET_SERVICE_OPTION_NONE,
1751 &client_disconnect_cb,
1753 GNUNET_MQ_hd_var_size (attribute_store_message,
1754 GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_STORE,
1755 struct AttributeStoreMessage,
1757 GNUNET_MQ_hd_var_size (attribute_delete_message,
1758 GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_DELETE,
1759 struct AttributeDeleteMessage,
1761 GNUNET_MQ_hd_fixed_size (
1763 GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_START,
1764 struct AttributeIterationStartMessage,
1766 GNUNET_MQ_hd_fixed_size (iteration_next,
1767 GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_NEXT,
1768 struct AttributeIterationNextMessage,
1770 GNUNET_MQ_hd_fixed_size (iteration_stop,
1771 GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_STOP,
1772 struct AttributeIterationStopMessage,
1774 GNUNET_MQ_hd_var_size (issue_ticket_message,
1775 GNUNET_MESSAGE_TYPE_RECLAIM_ISSUE_TICKET,
1776 struct IssueTicketMessage,
1778 GNUNET_MQ_hd_var_size (consume_ticket_message,
1779 GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET,
1780 struct ConsumeTicketMessage,
1782 GNUNET_MQ_hd_fixed_size (ticket_iteration_start,
1783 GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_START,
1784 struct TicketIterationStartMessage,
1786 GNUNET_MQ_hd_fixed_size (ticket_iteration_next,
1787 GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_NEXT,
1788 struct TicketIterationNextMessage,
1790 GNUNET_MQ_hd_fixed_size (ticket_iteration_stop,
1791 GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_STOP,
1792 struct TicketIterationStopMessage,
1794 GNUNET_MQ_hd_var_size (revoke_ticket_message,
1795 GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET,
1796 struct RevokeTicketMessage,
1798 GNUNET_MQ_handler_end ());
1799 /* end of gnunet-service-reclaim.c */