123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962 |
- /*
- This file is part of GNUnet.
- Copyright (C) 2013, 2014, 2016 GNUnet e.V.
- GNUnet is free software: you can redistribute it and/or modify it
- under the terms of the GNU Affero General Public License as published
- by the Free Software Foundation, either version 3 of the License,
- or (at your option) any later version.
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- SPDX-License-Identifier: AGPL3.0-or-later
- */
- /**
- * @file revocation/gnunet-service-revocation.c
- * @brief key revocation service
- * @author Christian Grothoff
- *
- * The purpose of this service is to allow users to permanently revoke
- * (compromised) keys. This is done by flooding the network with the
- * revocation requests. To reduce the attack potential offered by such
- * flooding, revocations must include a proof of work. We use the
- * set service for efficiently computing the union of revocations of
- * peers that connect.
- *
- * TODO:
- * - optimization: avoid sending revocation back to peer that we got it from;
- * - optimization: have randomized delay in sending revocations to other peers
- * to make it rare to traverse each link twice (NSE-style)
- */
- #include "platform.h"
- #include <math.h>
- #include "gnunet_util_lib.h"
- #include "gnunet_block_lib.h"
- #include "gnunet_constants.h"
- #include "gnunet_protocols.h"
- #include "gnunet_signatures.h"
- #include "gnunet_statistics_service.h"
- #include "gnunet_core_service.h"
- #include "gnunet_revocation_service.h"
- #include "gnunet_set_service.h"
- #include "revocation.h"
- #include <gcrypt.h>
- /**
- * Per-peer information.
- */
- struct PeerEntry
- {
- /**
- * Queue for sending messages to this peer.
- */
- struct GNUNET_MQ_Handle *mq;
- /**
- * What is the identity of the peer?
- */
- struct GNUNET_PeerIdentity id;
- /**
- * Tasked used to trigger the set union operation.
- */
- struct GNUNET_SCHEDULER_Task *transmit_task;
- /**
- * Handle to active set union operation (over revocation sets).
- */
- struct GNUNET_SET_OperationHandle *so;
- };
- /**
- * Set from all revocations known to us.
- */
- static struct GNUNET_SET_Handle *revocation_set;
- /**
- * Hash map with all revoked keys, maps the hash of the public key
- * to the respective `struct RevokeMessage`.
- */
- static struct GNUNET_CONTAINER_MultiHashMap *revocation_map;
- /**
- * Handle to our current configuration.
- */
- static const struct GNUNET_CONFIGURATION_Handle *cfg;
- /**
- * Handle to the statistics service.
- */
- static struct GNUNET_STATISTICS_Handle *stats;
- /**
- * Handle to the core service (for flooding)
- */
- static struct GNUNET_CORE_Handle *core_api;
- /**
- * Map of all connected peers.
- */
- static struct GNUNET_CONTAINER_MultiPeerMap *peers;
- /**
- * The peer identity of this peer.
- */
- static struct GNUNET_PeerIdentity my_identity;
- /**
- * File handle for the revocation database.
- */
- static struct GNUNET_DISK_FileHandle *revocation_db;
- /**
- * Handle for us listening to incoming revocation set union requests.
- */
- static struct GNUNET_SET_ListenHandle *revocation_union_listen_handle;
- /**
- * Amount of work required (W-bit collisions) for REVOCATION proofs, in collision-bits.
- */
- static unsigned long long revocation_work_required;
- /**
- * Our application ID for set union operations. Must be the
- * same for all (compatible) peers.
- */
- static struct GNUNET_HashCode revocation_set_union_app_id;
- /**
- * Create a new PeerEntry and add it to the peers multipeermap.
- *
- * @param peer the peer identity
- * @return a pointer to the new PeerEntry
- */
- static struct PeerEntry *
- new_peer_entry(const struct GNUNET_PeerIdentity *peer)
- {
- struct PeerEntry *peer_entry;
- peer_entry = GNUNET_new (struct PeerEntry);
- peer_entry->id = *peer;
- GNUNET_assert (GNUNET_OK ==
- GNUNET_CONTAINER_multipeermap_put (peers,
- &peer_entry->id,
- peer_entry,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
- return peer_entry;
- }
- /**
- * An revoke message has been received, check that it is well-formed.
- *
- * @param rm the message to verify
- * @return #GNUNET_YES if the message is verified
- * #GNUNET_NO if the key/signature don't verify
- */
- static int
- verify_revoke_message (const struct RevokeMessage *rm)
- {
- if (GNUNET_YES !=
- GNUNET_REVOCATION_check_pow (&rm->public_key,
- rm->proof_of_work,
- (unsigned int) revocation_work_required))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Proof of work invalid!\n");
- GNUNET_break_op (0);
- return GNUNET_NO;
- }
- if (GNUNET_OK !=
- GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_REVOCATION,
- &rm->purpose,
- &rm->signature,
- &rm->public_key))
- {
- GNUNET_break_op (0);
- return GNUNET_NO;
- }
- return GNUNET_YES;
- }
- /**
- * Handle client connecting to the service.
- *
- * @param cls NULL
- * @param client the new client
- * @param mq the message queue of @a client
- * @return @a client
- */
- static void *
- client_connect_cb (void *cls,
- struct GNUNET_SERVICE_Client *client,
- struct GNUNET_MQ_Handle *mq)
- {
- return client;
- }
- /**
- * Handle client connecting to the service.
- *
- * @param cls NULL
- * @param client the new client
- * @param app_cls must alias @a client
- */
- static void
- client_disconnect_cb (void *cls,
- struct GNUNET_SERVICE_Client *client,
- void *app_cls)
- {
- GNUNET_assert (client == app_cls);
- }
- /**
- * Handle QUERY message from client.
- *
- * @param cls client who sent the message
- * @param qm the message received
- */
- static void
- handle_query_message (void *cls,
- const struct QueryMessage *qm)
- {
- struct GNUNET_SERVICE_Client *client = cls;
- struct GNUNET_MQ_Envelope *env;
- struct QueryResponseMessage *qrm;
- struct GNUNET_HashCode hc;
- int res;
- GNUNET_CRYPTO_hash (&qm->key,
- sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
- &hc);
- res = GNUNET_CONTAINER_multihashmap_contains (revocation_map,
- &hc);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- (GNUNET_NO == res)
- ? "Received revocation check for valid key `%s' from client\n"
- : "Received revocation check for revoked key `%s' from client\n",
- GNUNET_h2s (&hc));
- env = GNUNET_MQ_msg (qrm,
- GNUNET_MESSAGE_TYPE_REVOCATION_QUERY_RESPONSE);
- qrm->is_valid = htonl ((GNUNET_YES == res) ? GNUNET_NO : GNUNET_YES);
- GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
- env);
- GNUNET_SERVICE_client_continue (client);
- }
- /**
- * Flood the given revocation message to all neighbours.
- *
- * @param cls the `struct RevokeMessage` to flood
- * @param target a neighbour
- * @param value our `struct PeerEntry` for the neighbour
- * @return #GNUNET_OK (continue to iterate)
- */
- static int
- do_flood (void *cls,
- const struct GNUNET_PeerIdentity *target,
- void *value)
- {
- const struct RevokeMessage *rm = cls;
- struct PeerEntry *pe = value;
- struct GNUNET_MQ_Envelope *e;
- struct RevokeMessage *cp;
- if (NULL == pe->mq)
- return GNUNET_OK; /* peer connected to us via SET,
- but we have no direct CORE
- connection for flooding */
- e = GNUNET_MQ_msg (cp,
- GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE);
- *cp = *rm;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Flooding revocation to `%s'\n",
- GNUNET_i2s (target));
- GNUNET_MQ_send (pe->mq,
- e);
- return GNUNET_OK;
- }
- /**
- * Publicize revocation message. Stores the message locally in the
- * database and passes it to all connected neighbours (and adds it to
- * the set for future connections).
- *
- * @param rm message to publicize
- * @return #GNUNET_OK on success, #GNUNET_NO if we encountered an error,
- * #GNUNET_SYSERR if the message was malformed
- */
- static int
- publicize_rm (const struct RevokeMessage *rm)
- {
- struct RevokeMessage *cp;
- struct GNUNET_HashCode hc;
- struct GNUNET_SET_Element e;
- GNUNET_CRYPTO_hash (&rm->public_key,
- sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
- &hc);
- if (GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap_contains (revocation_map,
- &hc))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Duplicate revocation received from peer. Ignored.\n");
- return GNUNET_OK;
- }
- if (GNUNET_OK !=
- verify_revoke_message (rm))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- /* write to disk */
- if (sizeof (struct RevokeMessage) !=
- GNUNET_DISK_file_write (revocation_db,
- rm,
- sizeof (struct RevokeMessage)))
- {
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
- "write");
- return GNUNET_NO;
- }
- if (GNUNET_OK !=
- GNUNET_DISK_file_sync (revocation_db))
- {
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
- "sync");
- return GNUNET_NO;
- }
- /* keep copy in memory */
- cp = (struct RevokeMessage *) GNUNET_copy_message (&rm->header);
- GNUNET_break (GNUNET_OK ==
- GNUNET_CONTAINER_multihashmap_put (revocation_map,
- &hc,
- cp,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
- /* add to set for future connections */
- e.size = htons (rm->header.size);
- e.element_type = GNUNET_BLOCK_TYPE_REVOCATION;
- e.data = rm;
- if (GNUNET_OK !=
- GNUNET_SET_add_element (revocation_set,
- &e,
- NULL,
- NULL))
- {
- GNUNET_break (0);
- return GNUNET_OK;
- }
- else
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Added revocation info to SET\n");
- }
- /* flood to neighbours */
- GNUNET_CONTAINER_multipeermap_iterate (peers,
- &do_flood,
- cp);
- return GNUNET_OK;
- }
- /**
- * Handle REVOKE message from client.
- *
- * @param cls client who sent the message
- * @param rm the message received
- */
- static void
- handle_revoke_message (void *cls,
- const struct RevokeMessage *rm)
- {
- struct GNUNET_SERVICE_Client *client = cls;
- struct GNUNET_MQ_Envelope *env;
- struct RevocationResponseMessage *rrm;
- int ret;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received REVOKE message from client\n");
- if (GNUNET_SYSERR == (ret = publicize_rm (rm)))
- {
- GNUNET_break_op (0);
- GNUNET_SERVICE_client_drop (client);
- return;
- }
- env = GNUNET_MQ_msg (rrm,
- GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE_RESPONSE);
- rrm->is_valid = htonl ((GNUNET_OK == ret) ? GNUNET_NO : GNUNET_YES);
- GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
- env);
- GNUNET_SERVICE_client_continue (client);
- }
- /**
- * Core handler for flooded revocation messages.
- *
- * @param cls closure unused
- * @param rm revocation message
- */
- static void
- handle_p2p_revoke (void *cls,
- const struct RevokeMessage *rm)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received REVOKE message\n");
- GNUNET_break_op (GNUNET_SYSERR !=
- publicize_rm (rm));
- }
- /**
- * Callback for set operation results. Called for each element in the
- * result set. Each element contains a revocation, which we should
- * validate and then add to our revocation list (and set).
- *
- * @param cls closure
- * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
- * @param current_size current set size
- * @param status see `enum GNUNET_SET_Status`
- */
- static void
- add_revocation (void *cls,
- const struct GNUNET_SET_Element *element,
- uint64_t current_size,
- enum GNUNET_SET_Status status)
- {
- struct PeerEntry *peer_entry = cls;
- const struct RevokeMessage *rm;
- switch (status)
- {
- case GNUNET_SET_STATUS_OK:
- if (element->size != sizeof (struct RevokeMessage))
- {
- GNUNET_break_op (0);
- return;
- }
- if (GNUNET_BLOCK_TYPE_REVOCATION != element->element_type)
- {
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# unsupported revocations received via set union"),
- 1,
- GNUNET_NO);
- return;
- }
- rm = element->data;
- (void) handle_p2p_revoke (NULL,
- rm);
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# revocation messages received via set union"),
- 1, GNUNET_NO);
- break;
- case GNUNET_SET_STATUS_FAILURE:
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _("Error computing revocation set union with %s\n"),
- GNUNET_i2s (&peer_entry->id));
- peer_entry->so = NULL;
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# revocation set unions failed"),
- 1,
- GNUNET_NO);
- break;
- case GNUNET_SET_STATUS_HALF_DONE:
- break;
- case GNUNET_SET_STATUS_DONE:
- peer_entry->so = NULL;
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# revocation set unions completed"),
- 1,
- GNUNET_NO);
- break;
- default:
- GNUNET_break (0);
- break;
- }
- }
- /**
- * The timeout for performing the set union has expired,
- * run the set operation on the revocation certificates.
- *
- * @param cls NULL
- */
- static void
- transmit_task_cb (void *cls)
- {
- struct PeerEntry *peer_entry = cls;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Starting set exchange with peer `%s'\n",
- GNUNET_i2s (&peer_entry->id));
- peer_entry->transmit_task = NULL;
- GNUNET_assert (NULL == peer_entry->so);
- peer_entry->so = GNUNET_SET_prepare (&peer_entry->id,
- &revocation_set_union_app_id,
- NULL,
- GNUNET_SET_RESULT_ADDED,
- (struct GNUNET_SET_Option[]) {{ 0 }},
- &add_revocation,
- peer_entry);
- if (GNUNET_OK !=
- GNUNET_SET_commit (peer_entry->so,
- revocation_set))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _("SET service crashed, terminating revocation service\n"));
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
- }
- /**
- * Method called whenever a peer connects. Sets up the PeerEntry and
- * schedules the initial revocation set exchange with this peer.
- *
- * @param cls closure
- * @param peer peer identity this notification is about
- */
- static void *
- handle_core_connect (void *cls,
- const struct GNUNET_PeerIdentity *peer,
- struct GNUNET_MQ_Handle *mq)
- {
- struct PeerEntry *peer_entry;
- struct GNUNET_HashCode my_hash;
- struct GNUNET_HashCode peer_hash;
- if (0 == memcmp (peer,
- &my_identity,
- sizeof (my_identity)))
- {
- return NULL;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Peer `%s' connected to us\n",
- GNUNET_i2s (peer));
- GNUNET_STATISTICS_update (stats,
- "# peers connected",
- 1,
- GNUNET_NO);
- peer_entry = GNUNET_CONTAINER_multipeermap_get (peers,
- peer);
- if (NULL != peer_entry)
- {
- /* This can happen if "core"'s notification is a tad late
- and CADET+SET were faster and already produced a
- #handle_revocation_union_request() for us to deal
- with. This should be rare, but isn't impossible. */
- peer_entry->mq = mq;
- return peer_entry;
- }
- peer_entry = new_peer_entry (peer);
- peer_entry->mq = mq;
- GNUNET_CRYPTO_hash (&my_identity,
- sizeof (my_identity),
- &my_hash);
- GNUNET_CRYPTO_hash (peer,
- sizeof (*peer),
- &peer_hash);
- if (0 < GNUNET_CRYPTO_hash_cmp (&my_hash,
- &peer_hash))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Starting SET operation with peer `%s'\n",
- GNUNET_i2s (peer));
- peer_entry->transmit_task =
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
- &transmit_task_cb,
- peer_entry);
- }
- return peer_entry;
- }
- /**
- * Method called whenever a peer disconnects. Deletes the PeerEntry and cancels
- * any pending transmission requests to that peer.
- *
- * @param cls closure
- * @param peer peer identity this notification is about
- * @param internal_cls our `struct PeerEntry` for this peer
- */
- static void
- handle_core_disconnect (void *cls,
- const struct GNUNET_PeerIdentity *peer,
- void *internal_cls)
- {
- struct PeerEntry *peer_entry = internal_cls;
- if (0 == memcmp (peer,
- &my_identity,
- sizeof (my_identity)))
- return;
- GNUNET_assert (NULL != peer_entry);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Peer `%s' disconnected from us\n",
- GNUNET_i2s (peer));
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CONTAINER_multipeermap_remove (peers,
- peer,
- peer_entry));
- if (NULL != peer_entry->transmit_task)
- {
- GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
- peer_entry->transmit_task = NULL;
- }
- if (NULL != peer_entry->so)
- {
- GNUNET_SET_operation_cancel (peer_entry->so);
- peer_entry->so = NULL;
- }
- GNUNET_free (peer_entry);
- GNUNET_STATISTICS_update (stats,
- "# peers connected",
- -1,
- GNUNET_NO);
- }
- /**
- * Free all values in a hash map.
- *
- * @param cls NULL
- * @param key the key
- * @param value value to free
- * @return #GNUNET_OK (continue to iterate)
- */
- static int
- free_entry (void *cls,
- const struct GNUNET_HashCode *key,
- void *value)
- {
- GNUNET_free (value);
- return GNUNET_OK;
- }
- /**
- * Task run during shutdown.
- *
- * @param cls unused
- */
- static void
- shutdown_task (void *cls)
- {
- if (NULL != revocation_set)
- {
- GNUNET_SET_destroy (revocation_set);
- revocation_set = NULL;
- }
- if (NULL != revocation_union_listen_handle)
- {
- GNUNET_SET_listen_cancel (revocation_union_listen_handle);
- revocation_union_listen_handle = NULL;
- }
- if (NULL != core_api)
- {
- GNUNET_CORE_disconnect (core_api);
- core_api = NULL;
- }
- if (NULL != stats)
- {
- GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
- stats = NULL;
- }
- if (NULL != peers)
- {
- GNUNET_CONTAINER_multipeermap_destroy (peers);
- peers = NULL;
- }
- if (NULL != revocation_db)
- {
- GNUNET_DISK_file_close (revocation_db);
- revocation_db = NULL;
- }
- GNUNET_CONTAINER_multihashmap_iterate (revocation_map,
- &free_entry,
- NULL);
- GNUNET_CONTAINER_multihashmap_destroy (revocation_map);
- }
- /**
- * Called on core init/fail.
- *
- * @param cls service closure
- * @param identity the public identity of this peer
- */
- static void
- core_init (void *cls,
- const struct GNUNET_PeerIdentity *identity)
- {
- if (NULL == identity)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Connection to core FAILED!\n");
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
- my_identity = *identity;
- }
- /**
- * Called when another peer wants to do a set operation with the
- * local peer. If a listen error occurs, the 'request' is NULL.
- *
- * @param cls closure
- * @param other_peer the other peer
- * @param context_msg message with application specific information from
- * the other peer
- * @param request request from the other peer (never NULL), use GNUNET_SET_accept()
- * to accept it, otherwise the request will be refused
- * Note that we can't just return value from the listen callback,
- * as it is also necessary to specify the set we want to do the
- * operation with, whith sometimes can be derived from the context
- * message. It's necessary to specify the timeout.
- */
- static void
- handle_revocation_union_request (void *cls,
- const struct GNUNET_PeerIdentity *other_peer,
- const struct GNUNET_MessageHeader *context_msg,
- struct GNUNET_SET_Request *request)
- {
- struct PeerEntry *peer_entry;
- if (NULL == request)
- {
- GNUNET_break (0);
- return;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received set exchange request from peer `%s'\n",
- GNUNET_i2s (other_peer));
- peer_entry = GNUNET_CONTAINER_multipeermap_get (peers,
- other_peer);
- if (NULL == peer_entry)
- {
- peer_entry = new_peer_entry (other_peer);
- }
- if (NULL != peer_entry->so)
- {
- GNUNET_break_op (0);
- return;
- }
- peer_entry->so = GNUNET_SET_accept (request,
- GNUNET_SET_RESULT_ADDED,
- (struct GNUNET_SET_Option[]) {{ 0 }},
- &add_revocation,
- peer_entry);
- if (GNUNET_OK !=
- GNUNET_SET_commit (peer_entry->so,
- revocation_set))
- {
- GNUNET_break (0);
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
- }
- /**
- * Handle network size estimate clients.
- *
- * @param cls closure
- * @param server the initialized server
- * @param c configuration to use
- */
- static void
- run (void *cls,
- const struct GNUNET_CONFIGURATION_Handle *c,
- struct GNUNET_SERVICE_Handle *service)
- {
- struct GNUNET_MQ_MessageHandler core_handlers[] = {
- GNUNET_MQ_hd_fixed_size (p2p_revoke,
- GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE,
- struct RevokeMessage,
- NULL),
- GNUNET_MQ_handler_end ()
- };
- char *fn;
- uint64_t left;
- struct RevokeMessage *rm;
- struct GNUNET_HashCode hc;
- GNUNET_CRYPTO_hash ("revocation-set-union-application-id",
- strlen ("revocation-set-union-application-id"),
- &revocation_set_union_app_id);
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_filename (c,
- "REVOCATION",
- "DATABASE",
- &fn))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "REVOCATION",
- "DATABASE");
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
- cfg = c;
- revocation_map = GNUNET_CONTAINER_multihashmap_create (16,
- GNUNET_NO);
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (cfg,
- "REVOCATION",
- "WORKBITS",
- &revocation_work_required))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "REVOCATION",
- "WORKBITS");
- GNUNET_SCHEDULER_shutdown ();
- GNUNET_free (fn);
- return;
- }
- if (revocation_work_required >= sizeof (struct GNUNET_HashCode) * 8)
- {
- GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
- "REVOCATION",
- "WORKBITS",
- _("Value is too large.\n"));
- GNUNET_SCHEDULER_shutdown ();
- GNUNET_free (fn);
- return;
- }
- revocation_set = GNUNET_SET_create (cfg,
- GNUNET_SET_OPERATION_UNION);
- revocation_union_listen_handle
- = GNUNET_SET_listen (cfg,
- GNUNET_SET_OPERATION_UNION,
- &revocation_set_union_app_id,
- &handle_revocation_union_request,
- NULL);
- revocation_db = GNUNET_DISK_file_open (fn,
- GNUNET_DISK_OPEN_READWRITE |
- GNUNET_DISK_OPEN_CREATE,
- GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE |
- GNUNET_DISK_PERM_GROUP_READ |
- GNUNET_DISK_PERM_OTHER_READ);
- if (NULL == revocation_db)
- {
- GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
- "REVOCATION",
- "DATABASE",
- _("Could not open revocation database file!"));
- GNUNET_SCHEDULER_shutdown ();
- GNUNET_free (fn);
- return;
- }
- if (GNUNET_OK !=
- GNUNET_DISK_file_size (fn, &left, GNUNET_YES, GNUNET_YES))
- left = 0;
- while (left > sizeof (struct RevokeMessage))
- {
- rm = GNUNET_new (struct RevokeMessage);
- if (sizeof (struct RevokeMessage) !=
- GNUNET_DISK_file_read (revocation_db,
- rm,
- sizeof (struct RevokeMessage)))
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
- "read",
- fn);
- GNUNET_free (rm);
- GNUNET_SCHEDULER_shutdown ();
- GNUNET_free (fn);
- return;
- }
- GNUNET_break (0 == ntohl (rm->reserved));
- GNUNET_CRYPTO_hash (&rm->public_key,
- sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
- &hc);
- GNUNET_break (GNUNET_OK ==
- GNUNET_CONTAINER_multihashmap_put (revocation_map,
- &hc,
- rm,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
- }
- GNUNET_free (fn);
- GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
- NULL);
- peers = GNUNET_CONTAINER_multipeermap_create (128,
- GNUNET_YES);
- /* Connect to core service and register core handlers */
- core_api = GNUNET_CORE_connect (cfg, /* Main configuration */
- NULL, /* Closure passed to functions */
- &core_init, /* Call core_init once connected */
- &handle_core_connect, /* Handle connects */
- &handle_core_disconnect, /* Handle disconnects */
- core_handlers); /* Register these handlers */
- if (NULL == core_api)
- {
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
- stats = GNUNET_STATISTICS_create ("revocation",
- cfg);
- }
- /**
- * Define "main" method using service macro.
- */
- GNUNET_SERVICE_MAIN
- ("revocation",
- GNUNET_SERVICE_OPTION_NONE,
- &run,
- &client_connect_cb,
- &client_disconnect_cb,
- NULL,
- GNUNET_MQ_hd_fixed_size (query_message,
- GNUNET_MESSAGE_TYPE_REVOCATION_QUERY,
- struct QueryMessage,
- NULL),
- GNUNET_MQ_hd_fixed_size (revoke_message,
- GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE,
- struct RevokeMessage,
- NULL),
- GNUNET_MQ_handler_end ());
- #if defined(LINUX) && defined(__GLIBC__)
- #include <malloc.h>
- /**
- * MINIMIZE heap size (way below 128k) since this process doesn't need much.
- */
- void __attribute__ ((constructor))
- GNUNET_REVOCATION_memory_init ()
- {
- mallopt (M_TRIM_THRESHOLD, 4 * 1024);
- mallopt (M_TOP_PAD, 1 * 1024);
- malloc_trim (0);
- }
- #endif
- /* end of gnunet-service-revocation.c */
|