2 This file is part of GNUnet.
3 Copyright (C) 2013, 2014 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public Licerevocation as published
7 by the Free Software Foundation; either version 3, or (at your
8 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 General Public Licerevocation for more details.
15 You should have received a copy of the GNU General Public Licerevocation
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
22 * @file revocation/gnunet-service-revocation.c
23 * @brief key revocation service
24 * @author Christian Grothoff
26 * The purpose of this service is to allow users to permanently revoke
27 * (compromised) keys. This is done by flooding the network with the
28 * revocation requests. To reduce the attack potential offered by such
29 * flooding, revocations must include a proof of work. We use the
30 * set service for efficiently computing the union of revocations of
34 * - optimization: avoid sending revocation back to peer that we got it from;
35 * - optimization: have randomized delay in sending revocations to other peers
36 * to make it rare to traverse each link twice (NSE-style)
40 #include "gnunet_util_lib.h"
41 #include "gnunet_constants.h"
42 #include "gnunet_protocols.h"
43 #include "gnunet_signatures.h"
44 #include "gnunet_statistics_service.h"
45 #include "gnunet_core_service.h"
46 #include "gnunet_revocation_service.h"
47 #include "gnunet_set_service.h"
48 #include "revocation.h"
53 * Per-peer information.
59 * Queue for sending messages to this peer.
61 struct GNUNET_MQ_Handle *mq;
64 * What is the identity of the peer?
66 struct GNUNET_PeerIdentity id;
69 * Tasked used to trigger the set union operation.
71 struct GNUNET_SCHEDULER_Task * transmit_task;
74 * Handle to active set union operation (over revocation sets).
76 struct GNUNET_SET_OperationHandle *so;
82 * Set from all revocations known to us.
84 static struct GNUNET_SET_Handle *revocation_set;
87 * Hash map with all revoked keys, maps the hash of the public key
88 * to the respective `struct RevokeMessage`.
90 static struct GNUNET_CONTAINER_MultiHashMap *revocation_map;
93 * Handle to our current configuration.
95 static const struct GNUNET_CONFIGURATION_Handle *cfg;
98 * Handle to the statistics service.
100 static struct GNUNET_STATISTICS_Handle *stats;
103 * Handle to the core service (for flooding)
105 static struct GNUNET_CORE_Handle *core_api;
108 * Map of all connected peers.
110 static struct GNUNET_CONTAINER_MultiPeerMap *peers;
113 * The peer identity of this peer.
115 static struct GNUNET_PeerIdentity my_identity;
118 * Handle to this serivce's server.
120 static struct GNUNET_SERVER_Handle *srv;
123 * Notification context for convenient sending of replies to the clients.
125 static struct GNUNET_SERVER_NotificationContext *nc;
128 * File handle for the revocation database.
130 static struct GNUNET_DISK_FileHandle *revocation_db;
133 * Handle for us listening to incoming revocation set union requests.
135 static struct GNUNET_SET_ListenHandle *revocation_union_listen_handle;
138 * Amount of work required (W-bit collisions) for REVOCATION proofs, in collision-bits.
140 static unsigned long long revocation_work_required;
143 * Our application ID for set union operations. Must be the
144 * same for all (compatible) peers.
146 static struct GNUNET_HashCode revocation_set_union_app_id;
150 * Create a new PeerEntry and add it to the peers multipeermap.
152 * @param peer the peer identity
153 * @return a pointer to the new PeerEntry
155 static struct PeerEntry *
156 new_peer_entry(const struct GNUNET_PeerIdentity *peer)
158 struct PeerEntry *peer_entry;
160 peer_entry = GNUNET_new (struct PeerEntry);
161 peer_entry->id = *peer;
162 GNUNET_assert (GNUNET_OK ==
163 GNUNET_CONTAINER_multipeermap_put (peers,
166 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
167 peer_entry->mq = GNUNET_CORE_mq_create (core_api, peer);
173 * Delete a PeerEntry for the given peer
175 * @param peer the identity of the peer to delete
178 delete_peer_entry(const struct GNUNET_PeerIdentity *peer)
180 struct PeerEntry *peer_entry;
182 peer_entry = GNUNET_CONTAINER_multipeermap_get (peers,
184 GNUNET_assert (NULL != peer_entry);
185 GNUNET_assert (GNUNET_YES ==
186 GNUNET_CONTAINER_multipeermap_remove (peers,
189 GNUNET_MQ_destroy (peer_entry->mq);
190 if (NULL != peer_entry->transmit_task)
192 GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
193 peer_entry->transmit_task = NULL;
195 if (NULL != peer_entry->so)
197 GNUNET_SET_operation_cancel (peer_entry->so);
198 peer_entry->so = NULL;
200 GNUNET_free (peer_entry);
205 * An revoke message has been received, check that it is well-formed.
207 * @param rm the message to verify
208 * @return #GNUNET_YES if the message is verified
209 * #GNUNET_NO if the key/signature don't verify
212 verify_revoke_message (const struct RevokeMessage *rm)
215 GNUNET_REVOCATION_check_pow (&rm->public_key,
217 (unsigned int) revocation_work_required))
219 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
220 "Proof of work invalid!\n");
225 GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_REVOCATION,
238 * Handle QUERY message from client.
241 * @param client who sent the message
242 * @param message the message received
245 handle_query_message (void *cls,
246 struct GNUNET_SERVER_Client *client,
247 const struct GNUNET_MessageHeader *message)
249 const struct QueryMessage *qm = (const struct QueryMessage *) message;
250 struct QueryResponseMessage qrm;
251 struct GNUNET_HashCode hc;
254 GNUNET_CRYPTO_hash (&qm->key,
255 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
257 res = GNUNET_CONTAINER_multihashmap_contains (revocation_map,
259 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
261 ? "Received revocation check for valid key `%s' from client\n"
262 : "Received revocation check for revoked key `%s' from client\n",
264 qrm.header.size = htons (sizeof (struct QueryResponseMessage));
265 qrm.header.type = htons (GNUNET_MESSAGE_TYPE_REVOCATION_QUERY_RESPONSE);
266 qrm.is_valid = htonl ((GNUNET_YES == res) ? GNUNET_NO : GNUNET_YES);
267 GNUNET_SERVER_notification_context_add (nc,
269 GNUNET_SERVER_notification_context_unicast (nc,
273 GNUNET_SERVER_receive_done (client,
279 * Flood the given revocation message to all neighbours.
281 * @param cls the `struct RevokeMessage` to flood
282 * @param target a neighbour
283 * @param value our `struct PeerEntry` for the neighbour
284 * @return #GNUNET_OK (continue to iterate)
288 const struct GNUNET_PeerIdentity *target,
291 const struct RevokeMessage *rm = cls;
292 struct PeerEntry *pe = value;
293 struct GNUNET_MQ_Envelope *e;
294 struct RevokeMessage *cp;
296 e = GNUNET_MQ_msg (cp,
297 GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE);
299 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
300 "Flooding revocation to `%s'\n",
301 GNUNET_i2s (target));
302 GNUNET_MQ_send (pe->mq,
309 * Publicize revocation message. Stores the message locally in the
310 * database and passes it to all connected neighbours (and adds it to
311 * the set for future connections).
313 * @param rm message to publicize
314 * @return #GNUNET_OK on success, #GNUNET_NO if we encountered an error,
315 * #GNUNET_SYSERR if the message was malformed
318 publicize_rm (const struct RevokeMessage *rm)
320 struct RevokeMessage *cp;
321 struct GNUNET_HashCode hc;
322 struct GNUNET_SET_Element e;
324 GNUNET_CRYPTO_hash (&rm->public_key,
325 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
328 GNUNET_CONTAINER_multihashmap_contains (revocation_map,
331 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
332 "Duplicate revocation received from peer. Ignored.\n");
336 verify_revoke_message (rm))
339 return GNUNET_SYSERR;
342 if (sizeof (struct RevokeMessage) !=
343 GNUNET_DISK_file_write (revocation_db,
345 sizeof (struct RevokeMessage)))
347 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
352 GNUNET_DISK_file_sync (revocation_db))
354 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
358 /* keep copy in memory */
359 cp = (struct RevokeMessage *) GNUNET_copy_message (&rm->header);
360 GNUNET_break (GNUNET_OK ==
361 GNUNET_CONTAINER_multihashmap_put (revocation_map,
364 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
365 /* add to set for future connections */
366 e.size = htons (rm->header.size);
370 GNUNET_SET_add_element (revocation_set,
380 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
381 "Added revocation info to SET\n");
383 /* flood to neighbours */
384 GNUNET_CONTAINER_multipeermap_iterate (peers,
392 * Handle REVOKE message from client.
395 * @param client who sent the message
396 * @param message the message received
399 handle_revoke_message (void *cls,
400 struct GNUNET_SERVER_Client *client,
401 const struct GNUNET_MessageHeader *message)
403 const struct RevokeMessage *rm;
404 struct RevocationResponseMessage rrm;
407 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
408 "Received REVOKE message from client\n");
409 rm = (const struct RevokeMessage *) message;
410 if (GNUNET_SYSERR == (ret = publicize_rm (rm)))
413 GNUNET_SERVER_receive_done (client,
417 rrm.header.size = htons (sizeof (struct RevocationResponseMessage));
418 rrm.header.type = htons (GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE_RESPONSE);
419 rrm.is_valid = htonl ((GNUNET_OK == ret) ? GNUNET_NO : GNUNET_YES);
420 GNUNET_SERVER_notification_context_add (nc,
422 GNUNET_SERVER_notification_context_unicast (nc,
426 GNUNET_SERVER_receive_done (client,
432 * Core handler for flooded revocation messages.
434 * @param cls closure unused
435 * @param message message
436 * @param peer peer identity this message is from (ignored)
439 handle_p2p_revoke_message (void *cls,
440 const struct GNUNET_PeerIdentity *peer,
441 const struct GNUNET_MessageHeader *message)
443 const struct RevokeMessage *rm;
445 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
446 "Received REVOKE message from peer\n");
447 rm = (const struct RevokeMessage *) message;
448 GNUNET_break_op (GNUNET_SYSERR != publicize_rm (rm));
454 * Callback for set operation results. Called for each element in the
455 * result set. Each element contains a revocation, which we should
456 * validate and then add to our revocation list (and set).
459 * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
460 * @param status see `enum GNUNET_SET_Status`
463 add_revocation (void *cls,
464 const struct GNUNET_SET_Element *element,
465 enum GNUNET_SET_Status status)
467 struct PeerEntry *peer_entry = cls;
468 const struct RevokeMessage *rm;
472 case GNUNET_SET_STATUS_OK:
473 if (element->size != sizeof (struct RevokeMessage))
478 if (0 != element->element_type)
480 GNUNET_STATISTICS_update (stats,
481 gettext_noop ("# unsupported revocations received via set union"),
486 (void) handle_p2p_revoke_message (NULL,
489 GNUNET_STATISTICS_update (stats,
490 gettext_noop ("# revocation messages received via set union"),
493 case GNUNET_SET_STATUS_FAILURE:
494 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
495 _("Error computing revocation set union with %s\n"),
496 GNUNET_i2s (&peer_entry->id));
497 peer_entry->so = NULL;
498 GNUNET_STATISTICS_update (stats,
499 gettext_noop ("# revocation set unions failed"),
503 case GNUNET_SET_STATUS_HALF_DONE:
505 case GNUNET_SET_STATUS_DONE:
506 peer_entry->so = NULL;
507 GNUNET_STATISTICS_update (stats,
508 gettext_noop ("# revocation set unions completed"),
520 * The timeout for performing the set union has expired,
521 * run the set operation on the revocation certificates.
524 * @param tc scheduler context (unused)
527 transmit_task_cb (void *cls,
528 const struct GNUNET_SCHEDULER_TaskContext *tc)
530 struct PeerEntry *peer_entry = cls;
532 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
533 "Starting set exchange with peer `%s'\n",
534 GNUNET_i2s (&peer_entry->id));
535 peer_entry->transmit_task = NULL;
536 peer_entry->so = GNUNET_SET_prepare (&peer_entry->id,
537 &revocation_set_union_app_id,
539 GNUNET_SET_RESULT_ADDED,
543 GNUNET_SET_commit (peer_entry->so,
546 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
547 _("SET service crashed, terminating revocation service\n"));
548 GNUNET_SCHEDULER_shutdown ();
555 * Method called whenever a peer connects. Sets up the PeerEntry and
556 * schedules the initial revocation set exchange with this peer.
559 * @param peer peer identity this notification is about
562 handle_core_connect (void *cls,
563 const struct GNUNET_PeerIdentity *peer)
565 struct PeerEntry *peer_entry;
566 struct GNUNET_HashCode my_hash;
567 struct GNUNET_HashCode peer_hash;
569 if (0 == memcmp (peer,
571 sizeof (my_identity)))
576 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
577 "Peer `%s' connected to us\n",
579 GNUNET_STATISTICS_update (stats,
583 peer_entry = GNUNET_CONTAINER_multipeermap_get (peers,
585 if (NULL != peer_entry)
587 /* This can happen if "core"'s notification is a tad late
588 and CADET+SET were faster and already produced a
589 #handle_revocation_union_request() for us to deal
590 with. This should be rare, but isn't impossible. */
593 peer_entry = new_peer_entry(peer);
594 GNUNET_CRYPTO_hash (&my_identity,
595 sizeof (my_identity),
597 GNUNET_CRYPTO_hash (peer,
600 if (0 < GNUNET_CRYPTO_hash_cmp (&my_hash,
603 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
604 "Starting SET operation with peer `%s'\n",
606 peer_entry->transmit_task =
607 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
615 * Method called whenever a peer disconnects. Deletes the PeerEntry and cancels
616 * any pending transmission requests to that peer.
619 * @param peer peer identity this notification is about
622 handle_core_disconnect (void *cls,
623 const struct GNUNET_PeerIdentity *peer)
625 if (0 == memcmp (peer,
627 sizeof (my_identity)))
632 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
633 "Peer `%s' disconnected from us\n",
635 delete_peer_entry(peer);
636 GNUNET_STATISTICS_update (stats,
644 * Free all values in a hash map.
648 * @param value value to free
649 * @return #GNUNET_OK (continue to iterate)
652 free_entry (void *cls,
653 const struct GNUNET_HashCode *key,
662 * Task run during shutdown.
668 shutdown_task (void *cls,
669 const struct GNUNET_SCHEDULER_TaskContext *tc)
671 if (NULL != revocation_set)
673 GNUNET_SET_destroy (revocation_set);
674 revocation_set = NULL;
676 if (NULL != revocation_union_listen_handle)
678 GNUNET_SET_listen_cancel (revocation_union_listen_handle);
679 revocation_union_listen_handle = NULL;
681 if (NULL != core_api)
683 GNUNET_CORE_disconnect (core_api);
688 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
693 GNUNET_CONTAINER_multipeermap_destroy (peers);
698 GNUNET_SERVER_notification_context_destroy (nc);
701 if (NULL != revocation_db)
703 GNUNET_DISK_file_close (revocation_db);
704 revocation_db = NULL;
706 GNUNET_CONTAINER_multihashmap_iterate (revocation_map,
709 GNUNET_CONTAINER_multihashmap_destroy (revocation_map);
714 * Called on core init/fail.
716 * @param cls service closure
717 * @param identity the public identity of this peer
720 core_init (void *cls,
721 const struct GNUNET_PeerIdentity *identity)
723 if (NULL == identity)
725 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
726 "Connection to core FAILED!\n");
727 GNUNET_SCHEDULER_shutdown ();
730 my_identity = *identity;
735 * Called when another peer wants to do a set operation with the
736 * local peer. If a listen error occurs, the 'request' is NULL.
739 * @param other_peer the other peer
740 * @param context_msg message with application specific information from
742 * @param request request from the other peer (never NULL), use GNUNET_SET_accept()
743 * to accept it, otherwise the request will be refused
744 * Note that we can't just return value from the listen callback,
745 * as it is also necessary to specify the set we want to do the
746 * operation with, whith sometimes can be derived from the context
747 * message. It's necessary to specify the timeout.
750 handle_revocation_union_request (void *cls,
751 const struct GNUNET_PeerIdentity *other_peer,
752 const struct GNUNET_MessageHeader *context_msg,
753 struct GNUNET_SET_Request *request)
755 struct PeerEntry *peer_entry;
762 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
763 "Received set exchange request from peer `%s'\n",
764 GNUNET_i2s (other_peer));
765 peer_entry = GNUNET_CONTAINER_multipeermap_get (peers,
767 if (NULL == peer_entry)
769 peer_entry = new_peer_entry(other_peer);
771 peer_entry->so = GNUNET_SET_accept (request,
772 GNUNET_SET_RESULT_ADDED,
776 GNUNET_SET_commit (peer_entry->so,
779 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
780 _("SET service crashed, terminating revocation service\n"));
781 GNUNET_SCHEDULER_shutdown ();
788 * Handle network size estimate clients.
791 * @param server the initialized server
792 * @param c configuration to use
796 struct GNUNET_SERVER_Handle *server,
797 const struct GNUNET_CONFIGURATION_Handle *c)
799 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
800 {&handle_query_message, NULL, GNUNET_MESSAGE_TYPE_REVOCATION_QUERY,
801 sizeof (struct QueryMessage)},
802 {&handle_revoke_message, NULL, GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE,
803 sizeof (struct RevokeMessage)},
806 static const struct GNUNET_CORE_MessageHandler core_handlers[] = {
807 {&handle_p2p_revoke_message, GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE,
808 sizeof (struct RevokeMessage)},
813 struct RevokeMessage *rm;
814 struct GNUNET_HashCode hc;
817 GNUNET_CONFIGURATION_get_value_filename (c,
822 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
825 GNUNET_SCHEDULER_shutdown ();
830 revocation_map = GNUNET_CONTAINER_multihashmap_create (16, GNUNET_NO);
831 nc = GNUNET_SERVER_notification_context_create (server, 1);
833 GNUNET_CONFIGURATION_get_value_number (cfg, "REVOCATION", "WORKBITS",
834 &revocation_work_required))
836 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
839 GNUNET_SCHEDULER_shutdown ();
843 if (revocation_work_required >= sizeof (struct GNUNET_HashCode) * 8)
845 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
848 _("Value is too large.\n"));
849 GNUNET_SCHEDULER_shutdown ();
853 revocation_set = GNUNET_SET_create (cfg,
854 GNUNET_SET_OPERATION_UNION);
855 revocation_union_listen_handle
856 = GNUNET_SET_listen (cfg,
857 GNUNET_SET_OPERATION_UNION,
858 &revocation_set_union_app_id,
859 &handle_revocation_union_request,
861 revocation_db = GNUNET_DISK_file_open (fn,
862 GNUNET_DISK_OPEN_READWRITE |
863 GNUNET_DISK_OPEN_CREATE,
864 GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE |
865 GNUNET_DISK_PERM_GROUP_READ |
866 GNUNET_DISK_PERM_OTHER_READ);
867 if (NULL == revocation_db)
869 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
872 _("Could not open revocation database file!"));
873 GNUNET_SCHEDULER_shutdown ();
878 GNUNET_DISK_file_size (fn, &left, GNUNET_YES, GNUNET_YES))
880 while (left > sizeof (struct RevokeMessage))
882 rm = GNUNET_new (struct RevokeMessage);
883 if (sizeof (struct RevokeMessage) !=
884 GNUNET_DISK_file_read (revocation_db,
886 sizeof (struct RevokeMessage)))
888 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
892 GNUNET_SCHEDULER_shutdown ();
896 GNUNET_break (0 == ntohl (rm->reserved));
897 GNUNET_CRYPTO_hash (&rm->public_key,
898 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
900 GNUNET_break (GNUNET_OK ==
901 GNUNET_CONTAINER_multihashmap_put (revocation_map,
904 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
908 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
911 peers = GNUNET_CONTAINER_multipeermap_create (128,
913 GNUNET_SERVER_add_handlers (srv, handlers);
914 /* Connect to core service and register core handlers */
915 core_api = GNUNET_CORE_connect (cfg, /* Main configuration */
916 NULL, /* Closure passed to functions */
917 &core_init, /* Call core_init once connected */
918 &handle_core_connect, /* Handle connects */
919 &handle_core_disconnect, /* Handle disconnects */
920 NULL, /* Don't want notified about all incoming messages */
921 GNUNET_NO, /* For header only inbound notification */
922 NULL, /* Don't want notified about all outbound messages */
923 GNUNET_NO, /* For header only outbound notification */
924 core_handlers); /* Register these handlers */
925 if (NULL == core_api)
927 GNUNET_SCHEDULER_shutdown ();
930 stats = GNUNET_STATISTICS_create ("revocation", cfg);
935 * The main function for the network size estimation service.
937 * @param argc number of arguments from the command line
938 * @param argv command line arguments
939 * @return 0 ok, 1 on error
945 GNUNET_CRYPTO_hash ("revocation-set-union-application-id",
946 strlen ("revocation-set-union-application-id"),
947 &revocation_set_union_app_id);
949 GNUNET_SERVICE_run (argc,
952 GNUNET_SERVICE_OPTION_NONE,
953 &run, NULL)) ? 0 : 1;
957 #if defined(LINUX) && defined(__GLIBC__)
962 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
964 void __attribute__ ((constructor))
965 GNUNET_ARM_memory_init ()
967 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
968 mallopt (M_TOP_PAD, 1 * 1024);
974 /* end of gnunet-service-revocation.c */