2 This file is part of GNUnet.
3 Copyright (C) 2013-2015 GNUnet e.V.
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License 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 License for more details.
15 You should have received a copy of the GNU General Public License
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 rps/gnunet-service-rps.c
23 * @brief rps service implementation
24 * @author Julius Bünger
27 #include "gnunet_applications.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_cadet_service.h"
30 #include "gnunet_peerinfo_service.h"
31 #include "gnunet_nse_service.h"
32 #include "gnunet_statistics_service.h"
34 #include "rps-test_util.h"
35 #include "gnunet-service-rps_sampler.h"
36 #include "gnunet-service-rps_custommap.h"
37 #include "gnunet-service-rps_view.h"
42 #define LOG(kind, ...) GNUNET_log(kind, __VA_ARGS__)
44 // TODO modify @brief in every file
46 // TODO check for overflows
48 // TODO align message structs
50 // TODO connect to friends
52 // TODO store peers somewhere persistent
54 // TODO blacklist? (-> mal peer detection on top of brahms)
56 // hist_size_init, hist_size_max
61 static const struct GNUNET_CONFIGURATION_Handle *cfg;
64 * Handle to the statistics service.
66 static struct GNUNET_STATISTICS_Handle *stats;
71 static struct GNUNET_PeerIdentity own_identity;
75 /***********************************************************************
76 * Old gnunet-service-rps_peers.c
77 ***********************************************************************/
80 * Set a peer flag of given peer context.
82 #define set_peer_flag(peer_ctx, mask) ((peer_ctx->peer_flags) |= (mask))
85 * Get peer flag of given peer context.
87 #define check_peer_flag_set(peer_ctx, mask)\
88 ((peer_ctx->peer_flags) & (mask) ? GNUNET_YES : GNUNET_NO)
91 * Unset flag of given peer context.
93 #define unset_peer_flag(peer_ctx, mask) ((peer_ctx->peer_flags) &= ~(mask))
96 * Set a channel flag of given channel context.
98 #define set_channel_flag(channel_flags, mask) ((*channel_flags) |= (mask))
101 * Get channel flag of given channel context.
103 #define check_channel_flag_set(channel_flags, mask)\
104 ((*channel_flags) & (mask) ? GNUNET_YES : GNUNET_NO)
107 * Unset flag of given channel context.
109 #define unset_channel_flag(channel_flags, mask) ((*channel_flags) &= ~(mask))
114 * Pending operation on peer consisting of callback and closure
116 * When an operation cannot be executed right now this struct is used to store
117 * the callback and closure for later execution.
133 * List containing all messages that are yet to be send
135 * This is used to keep track of all messages that have not been sent yet. When
136 * a peer is to be removed the pending messages can be removed properly.
138 struct PendingMessage
143 struct PendingMessage *next;
144 struct PendingMessage *prev;
147 * The envelope to the corresponding message
149 struct GNUNET_MQ_Envelope *ev;
152 * The corresponding context
154 struct PeerContext *peer_ctx;
163 * Struct used to keep track of other peer's status
165 * This is stored in a multipeermap.
166 * It contains information such as cadet channels, a message queue for sending,
167 * status about the channels, the pending operations on this peer and some flags
168 * about the status of the peer itself. (live, valid, ...)
173 * Message queue open to client
175 struct GNUNET_MQ_Handle *mq;
178 * Channel open to client.
180 struct GNUNET_CADET_Channel *send_channel;
183 * Flags to the sending channel
185 uint32_t *send_channel_flags;
188 * Channel open from client.
190 struct GNUNET_CADET_Channel *recv_channel; // unneeded?
193 * Flags to the receiving channel
195 uint32_t *recv_channel_flags;
198 * Array of pending operations on this peer.
200 struct PeerPendingOp *pending_ops;
203 * Handle to the callback given to cadet_ntfy_tmt_rdy()
205 * To be canceled on shutdown.
207 struct PendingMessage *liveliness_check_pending;
210 * Number of pending operations.
212 unsigned int num_pending_ops;
215 * Identity of the peer
217 struct GNUNET_PeerIdentity peer_id;
220 * Flags indicating status of peer
225 * Last time we received something from that peer.
227 struct GNUNET_TIME_Absolute last_message_recv;
230 * Last time we received a keepalive message.
232 struct GNUNET_TIME_Absolute last_keepalive;
235 * DLL with all messages that are yet to be sent
237 struct PendingMessage *pending_messages_head;
238 struct PendingMessage *pending_messages_tail;
241 * This is pobably followed by 'statistical' data (when we first saw
242 * him, how did we get his ID, how many pushes (in a timeinterval),
248 * @brief Closure to #valid_peer_iterator
250 struct PeersIteratorCls
255 PeersIterator iterator;
258 * Closure to iterator
264 * @brief Hashmap of valid peers.
266 static struct GNUNET_CONTAINER_MultiPeerMap *valid_peers;
269 * @brief Maximum number of valid peers to keep.
270 * TODO read from config
272 static uint32_t num_valid_peers_max = UINT32_MAX;
275 * @brief Filename of the file that stores the valid peers persistently.
277 static char *filename_valid_peers;
280 * Set of all peers to keep track of them.
282 static struct GNUNET_CONTAINER_MultiPeerMap *peer_map;
287 static struct GNUNET_CADET_Handle *cadet_handle;
292 * @brief Get the #PeerContext associated with a peer
294 * @param peer the peer id
296 * @return the #PeerContext
298 static struct PeerContext *
299 get_peer_ctx (const struct GNUNET_PeerIdentity *peer)
301 struct PeerContext *ctx;
304 ret = GNUNET_CONTAINER_multipeermap_contains (peer_map, peer);
305 GNUNET_assert (GNUNET_YES == ret);
306 ctx = GNUNET_CONTAINER_multipeermap_get (peer_map, peer);
307 GNUNET_assert (NULL != ctx);
312 Peers_check_peer_known (const struct GNUNET_PeerIdentity *peer);
315 * @brief Create a new #PeerContext and insert it into the peer map
317 * @param peer the peer to create the #PeerContext for
319 * @return the #PeerContext
321 static struct PeerContext *
322 create_peer_ctx (const struct GNUNET_PeerIdentity *peer)
324 struct PeerContext *ctx;
327 GNUNET_assert (GNUNET_NO == Peers_check_peer_known (peer));
329 ctx = GNUNET_new (struct PeerContext);
330 ctx->peer_id = *peer;
331 ctx->send_channel_flags = GNUNET_new (uint32_t);
332 ctx->recv_channel_flags = GNUNET_new (uint32_t);
333 ret = GNUNET_CONTAINER_multipeermap_put (peer_map, peer, ctx,
334 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
335 GNUNET_assert (GNUNET_OK == ret);
341 * @brief Create or get a #PeerContext
343 * @param peer the peer to get the associated context to
345 * @return the context
347 static struct PeerContext *
348 create_or_get_peer_ctx (const struct GNUNET_PeerIdentity *peer)
350 if (GNUNET_NO == Peers_check_peer_known (peer))
352 return create_peer_ctx (peer);
354 return get_peer_ctx (peer);
358 Peers_unset_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags);
361 Peers_set_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags);
364 * @brief Check whether we have a connection to this @a peer
366 * Also sets the #Peers_ONLINE flag accordingly
368 * @param peer the peer in question
370 * @return #GNUNET_YES if we are connected
371 * #GNUNET_NO otherwise
374 Peers_check_connected (const struct GNUNET_PeerIdentity *peer)
376 const struct PeerContext *peer_ctx;
378 /* If we don't know about this peer we don't know whether it's online */
379 if (GNUNET_NO == Peers_check_peer_known (peer))
383 /* Get the context */
384 peer_ctx = get_peer_ctx (peer);
385 /* If we have no channel to this peer we don't know whether it's online */
386 if ( (NULL == peer_ctx->send_channel) &&
387 (NULL == peer_ctx->recv_channel) )
389 Peers_unset_peer_flag (peer, Peers_ONLINE);
392 /* Otherwise (if we have a channel, we know that it's online */
393 Peers_set_peer_flag (peer, Peers_ONLINE);
399 * @brief The closure to #get_rand_peer_iterator.
401 struct GetRandPeerIteratorCls
404 * @brief The index of the peer to return.
405 * Will be decreased until 0.
406 * Then current peer is returned.
411 * @brief Pointer to peer to return.
413 const struct GNUNET_PeerIdentity *peer;
418 * @brief Iterator function for #get_random_peer_from_peermap.
420 * Implements #GNUNET_CONTAINER_PeerMapIterator.
421 * Decreases the index until the index is null.
422 * Then returns the current peer.
424 * @param cls the #GetRandPeerIteratorCls containing index and peer
425 * @param peer current peer
426 * @param value unused
428 * @return #GNUNET_YES if we should continue to
433 get_rand_peer_iterator (void *cls,
434 const struct GNUNET_PeerIdentity *peer,
437 struct GetRandPeerIteratorCls *iterator_cls = cls;
438 if (0 >= iterator_cls->index)
440 iterator_cls->peer = peer;
443 iterator_cls->index--;
449 * @brief Get a random peer from @a peer_map
451 * @param peer_map the peer_map to get the peer from
453 * @return a random peer
455 static const struct GNUNET_PeerIdentity *
456 get_random_peer_from_peermap (const struct
457 GNUNET_CONTAINER_MultiPeerMap *peer_map)
459 struct GetRandPeerIteratorCls *iterator_cls;
460 const struct GNUNET_PeerIdentity *ret;
462 iterator_cls = GNUNET_new (struct GetRandPeerIteratorCls);
463 iterator_cls->index = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
464 GNUNET_CONTAINER_multipeermap_size (peer_map));
465 (void) GNUNET_CONTAINER_multipeermap_iterate (valid_peers,
466 get_rand_peer_iterator,
468 ret = iterator_cls->peer;
469 GNUNET_free (iterator_cls);
475 * @brief Add a given @a peer to valid peers.
477 * If valid peers are already #num_valid_peers_max, delete a peer previously.
479 * @param peer the peer that is added to the valid peers.
481 * @return #GNUNET_YES if no other peer had to be removed
482 * #GNUNET_NO otherwise
485 add_valid_peer (const struct GNUNET_PeerIdentity *peer)
487 const struct GNUNET_PeerIdentity *rand_peer;
491 while (GNUNET_CONTAINER_multipeermap_size (valid_peers) >= num_valid_peers_max)
493 rand_peer = get_random_peer_from_peermap (valid_peers);
494 GNUNET_CONTAINER_multipeermap_remove_all (valid_peers, rand_peer);
497 (void) GNUNET_CONTAINER_multipeermap_put (valid_peers, peer, NULL,
498 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
504 * @brief Set the peer flag to living and
505 * call the pending operations on this peer.
507 * Also adds peer to #valid_peers.
509 * @param peer_ctx the #PeerContext of the peer to set live
512 set_peer_live (struct PeerContext *peer_ctx)
514 struct GNUNET_PeerIdentity *peer;
517 peer = &peer_ctx->peer_id;
518 LOG (GNUNET_ERROR_TYPE_DEBUG,
519 "Peer %s is live and valid, calling %i pending operations on it\n",
521 peer_ctx->num_pending_ops);
523 if (NULL != peer_ctx->liveliness_check_pending)
525 LOG (GNUNET_ERROR_TYPE_DEBUG,
526 "Removing pending liveliness check for peer %s\n",
527 GNUNET_i2s (&peer_ctx->peer_id));
528 // TODO wait until cadet sets mq->cancel_impl
529 //GNUNET_MQ_send_cancel (peer_ctx->liveliness_check_pending->ev);
530 GNUNET_free (peer_ctx->liveliness_check_pending);
531 peer_ctx->liveliness_check_pending = NULL;
534 (void) add_valid_peer (peer);
535 set_peer_flag (peer_ctx, Peers_ONLINE);
537 /* Call pending operations */
538 for (i = 0; i < peer_ctx->num_pending_ops; i++)
540 peer_ctx->pending_ops[i].op (peer_ctx->pending_ops[i].op_cls, peer);
542 GNUNET_array_grow (peer_ctx->pending_ops, peer_ctx->num_pending_ops, 0);
546 cleanup_destroyed_channel (void *cls,
547 const struct GNUNET_CADET_Channel *channel);
549 /* Declaration of handlers */
551 handle_peer_check (void *cls,
552 const struct GNUNET_MessageHeader *msg);
555 handle_peer_push (void *cls,
556 const struct GNUNET_MessageHeader *msg);
559 handle_peer_pull_request (void *cls,
560 const struct GNUNET_MessageHeader *msg);
563 check_peer_pull_reply (void *cls,
564 const struct GNUNET_RPS_P2P_PullReplyMessage *msg);
567 handle_peer_pull_reply (void *cls,
568 const struct GNUNET_RPS_P2P_PullReplyMessage *msg);
570 /* End declaration of handlers */
574 * @brief Get the channel of a peer. If not existing, create.
576 * @param peer the peer id
577 * @return the #GNUNET_CADET_Channel used to send data to @a peer
579 struct GNUNET_CADET_Channel *
580 get_channel (const struct GNUNET_PeerIdentity *peer)
582 struct PeerContext *peer_ctx;
583 struct GNUNET_HashCode port;
584 struct GNUNET_PeerIdentity *ctx_peer;
585 /* There exists a copy-paste-clone in run() */
586 struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
587 GNUNET_MQ_hd_fixed_size (peer_check,
588 GNUNET_MESSAGE_TYPE_RPS_PP_CHECK_LIVE,
589 struct GNUNET_MessageHeader,
591 GNUNET_MQ_hd_fixed_size (peer_push,
592 GNUNET_MESSAGE_TYPE_RPS_PP_PUSH,
593 struct GNUNET_MessageHeader,
595 GNUNET_MQ_hd_fixed_size (peer_pull_request,
596 GNUNET_MESSAGE_TYPE_RPS_PP_PULL_REQUEST,
597 struct GNUNET_MessageHeader,
599 GNUNET_MQ_hd_var_size (peer_pull_reply,
600 GNUNET_MESSAGE_TYPE_RPS_PP_PULL_REPLY,
601 struct GNUNET_RPS_P2P_PullReplyMessage,
603 GNUNET_MQ_handler_end ()
607 peer_ctx = get_peer_ctx (peer);
608 if (NULL == peer_ctx->send_channel)
610 LOG (GNUNET_ERROR_TYPE_DEBUG,
611 "Trying to establish channel to peer %s\n",
613 GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_RPS,
614 strlen (GNUNET_APPLICATION_PORT_RPS),
616 ctx_peer = GNUNET_new (struct GNUNET_PeerIdentity);
618 peer_ctx->send_channel =
619 GNUNET_CADET_channel_create (cadet_handle,
620 (struct GNUNET_PeerIdentity *) ctx_peer, /* context */
623 GNUNET_CADET_OPTION_RELIABLE,
624 NULL, /* WindowSize handler */
625 cleanup_destroyed_channel, /* Disconnect handler */
628 GNUNET_assert (NULL != peer_ctx->send_channel);
629 return peer_ctx->send_channel;
634 * Get the message queue (#GNUNET_MQ_Handle) of a specific peer.
636 * If we already have a message queue open to this client,
637 * simply return it, otherways create one.
639 * @param peer the peer to get the mq to
640 * @return the #GNUNET_MQ_Handle
642 static struct GNUNET_MQ_Handle *
643 get_mq (const struct GNUNET_PeerIdentity *peer)
645 struct PeerContext *peer_ctx;
647 peer_ctx = get_peer_ctx (peer);
649 if (NULL == peer_ctx->mq)
651 (void) get_channel (peer);
652 peer_ctx->mq = GNUNET_CADET_get_mq (peer_ctx->send_channel);
659 * @brief This is called in response to the first message we sent as a
662 * @param cls #PeerContext of peer with pending liveliness check
665 mq_liveliness_check_successful (void *cls)
667 struct PeerContext *peer_ctx = cls;
669 if (NULL != peer_ctx->liveliness_check_pending)
671 LOG (GNUNET_ERROR_TYPE_DEBUG,
672 "Liveliness check for peer %s was successfull\n",
673 GNUNET_i2s (&peer_ctx->peer_id));
674 GNUNET_free (peer_ctx->liveliness_check_pending);
675 peer_ctx->liveliness_check_pending = NULL;
676 set_peer_live (peer_ctx);
681 * Issue a check whether peer is live
683 * @param peer_ctx the context of the peer
686 check_peer_live (struct PeerContext *peer_ctx)
688 LOG (GNUNET_ERROR_TYPE_DEBUG,
689 "Get informed about peer %s getting live\n",
690 GNUNET_i2s (&peer_ctx->peer_id));
692 struct GNUNET_MQ_Handle *mq;
693 struct GNUNET_MQ_Envelope *ev;
695 ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_RPS_PP_CHECK_LIVE);
696 peer_ctx->liveliness_check_pending = GNUNET_new (struct PendingMessage);
697 peer_ctx->liveliness_check_pending->ev = ev;
698 peer_ctx->liveliness_check_pending->peer_ctx = peer_ctx;
699 peer_ctx->liveliness_check_pending->type = "Check liveliness";
700 mq = get_mq (&peer_ctx->peer_id);
701 GNUNET_MQ_notify_sent (ev,
702 mq_liveliness_check_successful,
704 GNUNET_MQ_send (mq, ev);
708 * @brief Add an envelope to a message passed to mq to list of pending messages
710 * @param peer peer the message was sent to
711 * @param ev envelope to the message
712 * @param type type of the message to be sent
713 * @return pointer to pending message
715 static struct PendingMessage *
716 insert_pending_message (const struct GNUNET_PeerIdentity *peer,
717 struct GNUNET_MQ_Envelope *ev,
720 struct PendingMessage *pending_msg;
721 struct PeerContext *peer_ctx;
723 peer_ctx = get_peer_ctx (peer);
724 pending_msg = GNUNET_new (struct PendingMessage);
725 pending_msg->ev = ev;
726 pending_msg->peer_ctx = peer_ctx;
727 pending_msg->type = type;
728 GNUNET_CONTAINER_DLL_insert (peer_ctx->pending_messages_head,
729 peer_ctx->pending_messages_tail,
736 * @brief Remove a pending message from the respective DLL
738 * @param pending_msg the pending message to remove
739 * @param cancel cancel the pending message, too
742 remove_pending_message (struct PendingMessage *pending_msg, int cancel)
744 struct PeerContext *peer_ctx;
746 peer_ctx = pending_msg->peer_ctx;
747 GNUNET_assert (NULL != peer_ctx);
748 GNUNET_CONTAINER_DLL_remove (peer_ctx->pending_messages_head,
749 peer_ctx->pending_messages_tail,
751 // TODO wait for the cadet implementation of message cancellation
752 //if (GNUNET_YES == cancel)
754 // GNUNET_MQ_send_cancel (pending_msg->ev);
756 GNUNET_free (pending_msg);
761 * @brief Check whether function of type #PeerOp was already scheduled
763 * The array with pending operations will probably never grow really big, so
764 * iterating over it should be ok.
766 * @param peer the peer to check
767 * @param peer_op the operation (#PeerOp) on the peer
769 * @return #GNUNET_YES if this operation is scheduled on that peer
770 * #GNUNET_NO otherwise
773 check_operation_scheduled (const struct GNUNET_PeerIdentity *peer,
774 const PeerOp peer_op)
776 const struct PeerContext *peer_ctx;
779 peer_ctx = get_peer_ctx (peer);
780 for (i = 0; i < peer_ctx->num_pending_ops; i++)
781 if (peer_op == peer_ctx->pending_ops[i].op)
787 Peers_remove_peer (const struct GNUNET_PeerIdentity *peer);
790 * Iterator over hash map entries. Deletes all contexts of peers.
793 * @param key current public key
794 * @param value value in the hash map
795 * @return #GNUNET_YES if we should continue to iterate,
799 peermap_clear_iterator (void *cls,
800 const struct GNUNET_PeerIdentity *key,
803 Peers_remove_peer (key);
809 * @brief This is called once a message is sent.
811 * Removes the pending message
813 * @param cls type of the message that was sent
816 mq_notify_sent_cb (void *cls)
818 struct PendingMessage *pending_msg = (struct PendingMessage *) cls;
819 LOG (GNUNET_ERROR_TYPE_DEBUG,
822 if (0 == strncmp ("PULL REPLY", pending_msg->type, 10))
823 GNUNET_STATISTICS_update(stats, "# pull replys sent", 1, GNUNET_NO);
824 if (0 == strncmp ("PULL REQUEST", pending_msg->type, 12))
825 GNUNET_STATISTICS_update(stats, "# pull requests sent", 1, GNUNET_NO);
826 if (0 == strncmp ("PUSH", pending_msg->type, 4))
827 GNUNET_STATISTICS_update(stats, "# pushes sent", 1, GNUNET_NO);
828 /* Do not cancle message */
829 remove_pending_message (pending_msg, GNUNET_NO);
834 * @brief Iterator function for #store_valid_peers.
836 * Implements #GNUNET_CONTAINER_PeerMapIterator.
837 * Writes single peer to disk.
839 * @param cls the file handle to write to.
840 * @param peer current peer
841 * @param value unused
843 * @return #GNUNET_YES if we should continue to
848 store_peer_presistently_iterator (void *cls,
849 const struct GNUNET_PeerIdentity *peer,
852 const struct GNUNET_DISK_FileHandle *fh = cls;
853 char peer_string[128];
861 size = GNUNET_snprintf (peer_string,
862 sizeof (peer_string),
864 GNUNET_i2s_full (peer));
865 GNUNET_assert (53 == size);
866 ret = GNUNET_DISK_file_write (fh,
869 GNUNET_assert (size == ret);
875 * @brief Store the peers currently in #valid_peers to disk.
880 struct GNUNET_DISK_FileHandle *fh;
881 uint32_t number_written_peers;
884 if (0 == strncmp ("DISABLE", filename_valid_peers, 7))
889 ret = GNUNET_DISK_directory_create_for_file (filename_valid_peers);
890 if (GNUNET_SYSERR == ret)
892 LOG (GNUNET_ERROR_TYPE_WARNING,
893 "Not able to create directory for file `%s'\n",
894 filename_valid_peers);
897 else if (GNUNET_NO == ret)
899 LOG (GNUNET_ERROR_TYPE_WARNING,
900 "Directory for file `%s' exists but is not writable for us\n",
901 filename_valid_peers);
904 fh = GNUNET_DISK_file_open (filename_valid_peers,
905 GNUNET_DISK_OPEN_WRITE |
906 GNUNET_DISK_OPEN_CREATE,
907 GNUNET_DISK_PERM_USER_READ |
908 GNUNET_DISK_PERM_USER_WRITE);
911 LOG (GNUNET_ERROR_TYPE_WARNING,
912 "Not able to write valid peers to file `%s'\n",
913 filename_valid_peers);
916 LOG (GNUNET_ERROR_TYPE_DEBUG,
917 "Writing %u valid peers to disk\n",
918 GNUNET_CONTAINER_multipeermap_size (valid_peers));
919 number_written_peers =
920 GNUNET_CONTAINER_multipeermap_iterate (valid_peers,
921 store_peer_presistently_iterator,
923 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
924 GNUNET_assert (number_written_peers ==
925 GNUNET_CONTAINER_multipeermap_size (valid_peers));
930 * @brief Convert string representation of peer id to peer id.
932 * Counterpart to #GNUNET_i2s_full.
934 * @param string_repr The string representation of the peer id
936 * @return The peer id
938 static const struct GNUNET_PeerIdentity *
939 s2i_full (const char *string_repr)
941 struct GNUNET_PeerIdentity *peer;
945 peer = GNUNET_new (struct GNUNET_PeerIdentity);
946 len = strlen (string_repr);
949 LOG (GNUNET_ERROR_TYPE_WARNING,
950 "Not able to convert string representation of PeerID to PeerID\n"
951 "Sting representation: %s (len %lu) - too short\n",
960 ret = GNUNET_CRYPTO_eddsa_public_key_from_string (string_repr,
963 if (GNUNET_OK != ret)
965 LOG (GNUNET_ERROR_TYPE_WARNING,
966 "Not able to convert string representation of PeerID to PeerID\n"
967 "Sting representation: %s\n",
976 * @brief Restore the peers on disk to #valid_peers.
979 restore_valid_peers ()
983 struct GNUNET_DISK_FileHandle *fh;
988 const struct GNUNET_PeerIdentity *peer;
990 if (0 == strncmp ("DISABLE", filename_valid_peers, 7))
995 if (GNUNET_OK != GNUNET_DISK_file_test (filename_valid_peers))
999 fh = GNUNET_DISK_file_open (filename_valid_peers,
1000 GNUNET_DISK_OPEN_READ,
1001 GNUNET_DISK_PERM_NONE);
1002 GNUNET_assert (NULL != fh);
1003 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_handle_size (fh, &file_size));
1004 num_peers = file_size / 53;
1005 buf = GNUNET_malloc (file_size);
1006 size_read = GNUNET_DISK_file_read (fh, buf, file_size);
1007 GNUNET_assert (size_read == file_size);
1008 LOG (GNUNET_ERROR_TYPE_DEBUG,
1009 "Restoring %" PRIu32 " peers from file `%s'\n",
1011 filename_valid_peers);
1012 for (iter_buf = buf; iter_buf < buf + file_size - 1; iter_buf += 53)
1014 str_repr = GNUNET_strndup (iter_buf, 53);
1015 peer = s2i_full (str_repr);
1016 GNUNET_free (str_repr);
1017 add_valid_peer (peer);
1018 LOG (GNUNET_ERROR_TYPE_DEBUG,
1019 "Restored valid peer %s from disk\n",
1020 GNUNET_i2s_full (peer));
1024 LOG (GNUNET_ERROR_TYPE_DEBUG,
1025 "num_peers: %" PRIu32 ", _size (valid_peers): %u\n",
1027 GNUNET_CONTAINER_multipeermap_size (valid_peers));
1028 if (num_peers != GNUNET_CONTAINER_multipeermap_size (valid_peers))
1030 LOG (GNUNET_ERROR_TYPE_WARNING,
1031 "Number of restored peers does not match file size. Have probably duplicates.\n");
1033 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
1034 LOG (GNUNET_ERROR_TYPE_DEBUG,
1035 "Restored %u valid peers from disk\n",
1036 GNUNET_CONTAINER_multipeermap_size (valid_peers));
1041 * @brief Initialise storage of peers
1043 * @param fn_valid_peers filename of the file used to store valid peer ids
1044 * @param cadet_h cadet handle
1045 * @param disconnect_handler Disconnect handler
1046 * @param own_id own peer identity
1049 Peers_initialise (char* fn_valid_peers,
1050 struct GNUNET_CADET_Handle *cadet_h,
1051 GNUNET_CADET_DisconnectEventHandler disconnect_handler,
1052 const struct GNUNET_PeerIdentity *own_id)
1054 filename_valid_peers = GNUNET_strdup (fn_valid_peers);
1055 cadet_handle = cadet_h;
1056 own_identity = *own_id;
1057 peer_map = GNUNET_CONTAINER_multipeermap_create (4, GNUNET_NO);
1058 valid_peers = GNUNET_CONTAINER_multipeermap_create (4, GNUNET_NO);
1059 restore_valid_peers ();
1064 * @brief Delete storage of peers that was created with #Peers_initialise ()
1069 if (GNUNET_SYSERR ==
1070 GNUNET_CONTAINER_multipeermap_iterate (peer_map,
1071 peermap_clear_iterator,
1074 LOG (GNUNET_ERROR_TYPE_WARNING,
1075 "Iteration destroying peers was aborted.\n");
1077 GNUNET_CONTAINER_multipeermap_destroy (peer_map);
1079 store_valid_peers ();
1080 GNUNET_free (filename_valid_peers);
1081 GNUNET_CONTAINER_multipeermap_destroy (valid_peers);
1086 * Iterator over #valid_peers hash map entries.
1088 * @param cls closure - unused
1089 * @param peer current peer id
1090 * @param value value in the hash map - unused
1091 * @return #GNUNET_YES if we should continue to
1093 * #GNUNET_NO if not.
1096 valid_peer_iterator (void *cls,
1097 const struct GNUNET_PeerIdentity *peer,
1100 struct PeersIteratorCls *it_cls = cls;
1102 return it_cls->iterator (it_cls->cls,
1108 * @brief Get all currently known, valid peer ids.
1110 * @param it function to call on each peer id
1111 * @param it_cls extra argument to @a it
1112 * @return the number of key value pairs processed,
1113 * #GNUNET_SYSERR if it aborted iteration
1116 Peers_get_valid_peers (PeersIterator iterator,
1119 struct PeersIteratorCls *cls;
1122 cls = GNUNET_new (struct PeersIteratorCls);
1123 cls->iterator = iterator;
1125 ret = GNUNET_CONTAINER_multipeermap_iterate (valid_peers,
1126 valid_peer_iterator,
1134 * @brief Add peer to known peers.
1136 * This function is called on new peer_ids from 'external' sources
1137 * (client seed, cadet get_peers(), ...)
1139 * @param peer the new #GNUNET_PeerIdentity
1141 * @return #GNUNET_YES if peer was inserted
1142 * #GNUNET_NO otherwise (if peer was already known or
1143 * peer was #own_identity)
1146 Peers_insert_peer (const struct GNUNET_PeerIdentity *peer)
1148 if ( (GNUNET_YES == Peers_check_peer_known (peer)) ||
1149 (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, &own_identity)) )
1151 return GNUNET_NO; /* We already know this peer - nothing to do */
1153 (void) create_peer_ctx (peer);
1158 Peers_check_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags);
1161 * @brief Try connecting to a peer to see whether it is online
1163 * If not known yet, insert into known peers
1165 * @param peer the peer whose liveliness is to be checked
1166 * @return #GNUNET_YES if peer had to be inserted
1167 * #GNUNET_NO otherwise (if peer was already known or
1168 * peer was #own_identity)
1171 Peers_issue_peer_liveliness_check (const struct GNUNET_PeerIdentity *peer)
1173 struct PeerContext *peer_ctx;
1176 if (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, &own_identity))
1180 ret = Peers_insert_peer (peer);
1181 peer_ctx = get_peer_ctx (peer);
1182 if (GNUNET_NO == Peers_check_peer_flag (peer, Peers_ONLINE))
1184 check_peer_live (peer_ctx);
1191 * @brief Check if peer is removable.
1194 * - a recv channel exists
1195 * - there are pending messages
1196 * - there is no pending pull reply
1198 * @param peer the peer in question
1199 * @return #GNUNET_YES if peer is removable
1200 * #GNUNET_NO if peer is NOT removable
1201 * #GNUNET_SYSERR if peer is not known
1204 Peers_check_removable (const struct GNUNET_PeerIdentity *peer)
1206 struct PeerContext *peer_ctx;
1208 if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (peer_map, peer))
1210 return GNUNET_SYSERR;
1213 peer_ctx = get_peer_ctx (peer);
1214 if ( (NULL != peer_ctx->recv_channel) ||
1215 (NULL != peer_ctx->pending_messages_head) ||
1216 (GNUNET_NO == check_peer_flag_set (peer_ctx, Peers_PULL_REPLY_PENDING)) )
1224 Peers_get_channel_flag (const struct GNUNET_PeerIdentity *peer,
1225 enum Peers_ChannelRole role);
1228 Peers_check_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags);
1231 * @brief Remove peer
1233 * @param peer the peer to clean
1234 * @return #GNUNET_YES if peer was removed
1235 * #GNUNET_NO otherwise
1238 Peers_remove_peer (const struct GNUNET_PeerIdentity *peer)
1240 struct PeerContext *peer_ctx;
1241 uint32_t *channel_flag;
1243 if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (peer_map, peer))
1248 peer_ctx = get_peer_ctx (peer);
1249 set_peer_flag (peer_ctx, Peers_TO_DESTROY);
1250 LOG (GNUNET_ERROR_TYPE_DEBUG,
1251 "Going to remove peer %s\n",
1252 GNUNET_i2s (&peer_ctx->peer_id));
1253 Peers_unset_peer_flag (peer, Peers_ONLINE);
1255 GNUNET_array_grow (peer_ctx->pending_ops, peer_ctx->num_pending_ops, 0);
1256 while (NULL != peer_ctx->pending_messages_head)
1258 LOG (GNUNET_ERROR_TYPE_DEBUG,
1259 "Removing unsent %s\n",
1260 peer_ctx->pending_messages_head->type);
1261 /* Cancle pending message, too */
1262 remove_pending_message (peer_ctx->pending_messages_head, GNUNET_YES);
1264 /* If we are still waiting for notification whether this peer is live
1265 * cancel the according task */
1266 if (NULL != peer_ctx->liveliness_check_pending)
1268 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1269 "Removing pending liveliness check for peer %s\n",
1270 GNUNET_i2s (&peer_ctx->peer_id));
1271 // TODO wait until cadet sets mq->cancel_impl
1272 //GNUNET_MQ_send_cancel (peer_ctx->liveliness_check_pending->ev);
1273 GNUNET_free (peer_ctx->liveliness_check_pending);
1274 peer_ctx->liveliness_check_pending = NULL;
1276 channel_flag = Peers_get_channel_flag (peer, Peers_CHANNEL_ROLE_SENDING);
1277 if (NULL != peer_ctx->send_channel &&
1278 GNUNET_YES != Peers_check_channel_flag (channel_flag, Peers_CHANNEL_DESTROING))
1280 LOG (GNUNET_ERROR_TYPE_DEBUG,
1281 "Destroying send channel\n");
1282 GNUNET_CADET_channel_destroy (peer_ctx->send_channel);
1283 peer_ctx->send_channel = NULL;
1285 channel_flag = Peers_get_channel_flag (peer, Peers_CHANNEL_ROLE_RECEIVING);
1286 if (NULL != peer_ctx->recv_channel &&
1287 GNUNET_YES != Peers_check_channel_flag (channel_flag, Peers_CHANNEL_DESTROING))
1289 LOG (GNUNET_ERROR_TYPE_DEBUG,
1290 "Destroying recv channel\n");
1291 GNUNET_CADET_channel_destroy (peer_ctx->recv_channel);
1292 peer_ctx->recv_channel = NULL;
1295 GNUNET_free (peer_ctx->send_channel_flags);
1296 GNUNET_free (peer_ctx->recv_channel_flags);
1298 if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_remove_all (peer_map, &peer_ctx->peer_id))
1300 LOG (GNUNET_ERROR_TYPE_WARNING, "removing peer from peer_map failed\n");
1302 GNUNET_free (peer_ctx);
1308 * @brief set flags on a given peer.
1310 * @param peer the peer to set flags on
1311 * @param flags the flags
1314 Peers_set_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags)
1316 struct PeerContext *peer_ctx;
1318 peer_ctx = get_peer_ctx (peer);
1319 set_peer_flag (peer_ctx, flags);
1324 * @brief unset flags on a given peer.
1326 * @param peer the peer to unset flags on
1327 * @param flags the flags
1330 Peers_unset_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags)
1332 struct PeerContext *peer_ctx;
1334 peer_ctx = get_peer_ctx (peer);
1335 unset_peer_flag (peer_ctx, flags);
1340 * @brief Check whether flags on a peer are set.
1342 * @param peer the peer to check the flag of
1343 * @param flags the flags to check
1345 * @return #GNUNET_SYSERR if peer is not known
1346 * #GNUNET_YES if all given flags are set
1347 * #GNUNET_NO otherwise
1350 Peers_check_peer_flag (const struct GNUNET_PeerIdentity *peer, enum Peers_PeerFlags flags)
1352 struct PeerContext *peer_ctx;
1354 if (GNUNET_NO == Peers_check_peer_known (peer))
1356 return GNUNET_SYSERR;
1358 peer_ctx = get_peer_ctx (peer);
1359 return check_peer_flag_set (peer_ctx, flags);
1364 * @brief set flags on a given channel.
1366 * @param channel the channel to set flags on
1367 * @param flags the flags
1370 Peers_set_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags)
1372 set_channel_flag (channel_flags, flags);
1377 * @brief unset flags on a given channel.
1379 * @param channel the channel to unset flags on
1380 * @param flags the flags
1383 Peers_unset_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags)
1385 unset_channel_flag (channel_flags, flags);
1390 * @brief Check whether flags on a channel are set.
1392 * @param channel the channel to check the flag of
1393 * @param flags the flags to check
1395 * @return #GNUNET_YES if all given flags are set
1396 * #GNUNET_NO otherwise
1399 Peers_check_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags)
1401 return check_channel_flag_set (channel_flags, flags);
1405 * @brief Get the flags for the channel in @a role for @a peer.
1407 * @param peer Peer to get the channel flags for.
1408 * @param role Role of channel to get flags for
1410 * @return The flags.
1413 Peers_get_channel_flag (const struct GNUNET_PeerIdentity *peer,
1414 enum Peers_ChannelRole role)
1416 const struct PeerContext *peer_ctx;
1418 peer_ctx = get_peer_ctx (peer);
1419 if (Peers_CHANNEL_ROLE_SENDING == role)
1421 return peer_ctx->send_channel_flags;
1423 else if (Peers_CHANNEL_ROLE_RECEIVING == role)
1425 return peer_ctx->recv_channel_flags;
1434 * @brief Check whether we have information about the given peer.
1436 * FIXME probably deprecated. Make this the new _online.
1438 * @param peer peer in question
1440 * @return #GNUNET_YES if peer is known
1441 * #GNUNET_NO if peer is not knwon
1444 Peers_check_peer_known (const struct GNUNET_PeerIdentity *peer)
1446 if (NULL != peer_map)
1448 return GNUNET_CONTAINER_multipeermap_contains (peer_map, peer);
1457 * @brief Check whether @a peer is actually a peer.
1459 * A valid peer is a peer that we know exists eg. we were connected to once.
1461 * @param peer peer in question
1463 * @return #GNUNET_YES if peer is valid
1464 * #GNUNET_NO if peer is not valid
1467 Peers_check_peer_valid (const struct GNUNET_PeerIdentity *peer)
1469 return GNUNET_CONTAINER_multipeermap_contains (valid_peers, peer);
1474 * @brief Indicate that we want to send to the other peer
1476 * This establishes a sending channel
1478 * @param peer the peer to establish channel to
1481 Peers_indicate_sending_intention (const struct GNUNET_PeerIdentity *peer)
1483 GNUNET_assert (GNUNET_YES == Peers_check_peer_known (peer));
1484 (void) get_channel (peer);
1489 * @brief Check whether other peer has the intention to send/opened channel
1492 * @param peer the peer in question
1494 * @return #GNUNET_YES if peer has the intention to send
1495 * #GNUNET_NO otherwise
1498 Peers_check_peer_send_intention (const struct GNUNET_PeerIdentity *peer)
1500 const struct PeerContext *peer_ctx;
1502 peer_ctx = get_peer_ctx (peer);
1503 if (NULL != peer_ctx->recv_channel)
1512 * Handle the channel a peer opens to us.
1514 * @param cls The closure
1515 * @param channel The channel the peer wants to establish
1516 * @param initiator The peer's peer ID
1518 * @return initial channel context for the channel
1519 * (can be NULL -- that's not an error)
1522 Peers_handle_inbound_channel (void *cls,
1523 struct GNUNET_CADET_Channel *channel,
1524 const struct GNUNET_PeerIdentity *initiator)
1526 struct PeerContext *peer_ctx;
1527 struct GNUNET_PeerIdentity *ctx_peer;
1529 LOG (GNUNET_ERROR_TYPE_DEBUG,
1530 "New channel was established to us (Peer %s).\n",
1531 GNUNET_i2s (initiator));
1532 GNUNET_assert (NULL != channel); /* according to cadet API */
1533 /* Make sure we 'know' about this peer */
1534 peer_ctx = create_or_get_peer_ctx (initiator);
1535 set_peer_live (peer_ctx);
1536 ctx_peer = GNUNET_new (struct GNUNET_PeerIdentity);
1537 *ctx_peer = *initiator;
1538 /* We only accept one incoming channel per peer */
1539 if (GNUNET_YES == Peers_check_peer_send_intention (initiator))
1541 set_channel_flag (peer_ctx->recv_channel_flags,
1542 Peers_CHANNEL_ESTABLISHED_TWICE);
1543 //GNUNET_CADET_channel_destroy (channel);
1544 GNUNET_CADET_channel_destroy (peer_ctx->recv_channel);
1545 peer_ctx->recv_channel = channel;
1546 /* return the channel context */
1549 peer_ctx->recv_channel = channel;
1555 * @brief Check whether a sending channel towards the given peer exists
1557 * @param peer the peer to check for
1559 * @return #GNUNET_YES if a sending channel towards that peer exists
1560 * #GNUNET_NO otherwise
1563 Peers_check_sending_channel_exists (const struct GNUNET_PeerIdentity *peer)
1565 struct PeerContext *peer_ctx;
1567 if (GNUNET_NO == Peers_check_peer_known (peer))
1568 { /* If no such peer exists, there is no channel */
1571 peer_ctx = get_peer_ctx (peer);
1572 if (NULL == peer_ctx->send_channel)
1581 * @brief check whether the given channel is the sending channel of the given
1584 * @param peer the peer in question
1585 * @param channel the channel to check for
1586 * @param role either #Peers_CHANNEL_ROLE_SENDING, or
1587 * #Peers_CHANNEL_ROLE_RECEIVING
1589 * @return #GNUNET_YES if the given chennel is the sending channel of the peer
1590 * #GNUNET_NO otherwise
1593 Peers_check_channel_role (const struct GNUNET_PeerIdentity *peer,
1594 const struct GNUNET_CADET_Channel *channel,
1595 enum Peers_ChannelRole role)
1597 const struct PeerContext *peer_ctx;
1599 if (GNUNET_NO == Peers_check_peer_known (peer))
1603 peer_ctx = get_peer_ctx (peer);
1604 if ( (Peers_CHANNEL_ROLE_SENDING == role) &&
1605 (channel == peer_ctx->send_channel) )
1609 if ( (Peers_CHANNEL_ROLE_RECEIVING == role) &&
1610 (channel == peer_ctx->recv_channel) )
1619 * @brief Destroy the send channel of a peer e.g. stop indicating a sending
1620 * intention to another peer
1622 * If there is also no channel to receive messages from that peer, remove it
1626 * @peer the peer identity of the peer whose sending channel to destroy
1627 * @return #GNUNET_YES if channel was destroyed
1628 * #GNUNET_NO otherwise
1631 Peers_destroy_sending_channel (const struct GNUNET_PeerIdentity *peer)
1633 struct PeerContext *peer_ctx;
1635 if (GNUNET_NO == Peers_check_peer_known (peer))
1639 peer_ctx = get_peer_ctx (peer);
1640 if (NULL != peer_ctx->send_channel)
1642 set_channel_flag (peer_ctx->send_channel_flags, Peers_CHANNEL_CLEAN);
1643 GNUNET_CADET_channel_destroy (peer_ctx->send_channel);
1644 peer_ctx->send_channel = NULL;
1645 peer_ctx->mq = NULL;
1646 (void) Peers_check_connected (peer);
1653 * This is called when a channel is destroyed.
1655 * @param cls The closure
1656 * @param channel The channel being closed
1659 Peers_cleanup_destroyed_channel (void *cls,
1660 const struct GNUNET_CADET_Channel *channel)
1662 struct GNUNET_PeerIdentity *peer = cls;
1663 struct PeerContext *peer_ctx;
1665 if (GNUNET_NO == Peers_check_peer_known (peer))
1666 {/* We don't want to implicitly create a context that we're about to kill */
1667 LOG (GNUNET_ERROR_TYPE_DEBUG,
1668 "channel (%s) without associated context was destroyed\n",
1672 peer_ctx = get_peer_ctx (peer);
1674 /* If our peer issued the destruction of the channel, the #Peers_TO_DESTROY
1675 * flag will be set. In this case simply make sure that the channels are
1677 /* FIXME This distinction seems to be redundant */
1678 if (Peers_check_peer_flag (peer, Peers_TO_DESTROY))
1679 {/* We initiatad the destruction of this particular peer */
1680 if (channel == peer_ctx->send_channel)
1681 peer_ctx->send_channel = NULL;
1682 else if (channel == peer_ctx->recv_channel)
1683 peer_ctx->recv_channel = NULL;
1685 if (NULL != peer_ctx->send_channel)
1687 GNUNET_CADET_channel_destroy (peer_ctx->send_channel);
1688 peer_ctx->send_channel = NULL;
1690 if (NULL != peer_ctx->recv_channel)
1692 GNUNET_CADET_channel_destroy (peer_ctx->recv_channel);
1693 peer_ctx->recv_channel = NULL;
1695 /* Set the #Peers_ONLINE flag accordingly */
1696 (void) Peers_check_connected (peer);
1701 { /* We did not initiate the destruction of this peer */
1702 if (channel == peer_ctx->send_channel)
1703 { /* Something (but us) killd the channel - clean up peer */
1704 LOG (GNUNET_ERROR_TYPE_DEBUG,
1705 "send channel (%s) was destroyed - cleaning up\n",
1707 peer_ctx->send_channel = NULL;
1709 else if (channel == peer_ctx->recv_channel)
1710 { /* Other peer doesn't want to send us messages anymore */
1711 LOG (GNUNET_ERROR_TYPE_DEBUG,
1712 "Peer %s destroyed recv channel - cleaning up channel\n",
1714 peer_ctx->recv_channel = NULL;
1718 LOG (GNUNET_ERROR_TYPE_WARNING,
1719 "unknown channel (%s) was destroyed\n",
1723 (void) Peers_check_connected (peer);
1727 * @brief Send a message to another peer.
1729 * Keeps track about pending messages so they can be properly removed when the
1730 * peer is destroyed.
1732 * @param peer receeiver of the message
1733 * @param ev envelope of the message
1734 * @param type type of the message
1737 Peers_send_message (const struct GNUNET_PeerIdentity *peer,
1738 struct GNUNET_MQ_Envelope *ev,
1741 struct PendingMessage *pending_msg;
1742 struct GNUNET_MQ_Handle *mq;
1744 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1745 "Sending message to %s of type %s\n",
1748 pending_msg = insert_pending_message (peer, ev, type);
1750 GNUNET_MQ_notify_sent (ev,
1753 GNUNET_MQ_send (mq, ev);
1757 * @brief Schedule a operation on given peer
1759 * Avoids scheduling an operation twice.
1761 * @param peer the peer we want to schedule the operation for once it gets live
1763 * @return #GNUNET_YES if the operation was scheduled
1764 * #GNUNET_NO otherwise
1767 Peers_schedule_operation (const struct GNUNET_PeerIdentity *peer,
1768 const PeerOp peer_op)
1770 struct PeerPendingOp pending_op;
1771 struct PeerContext *peer_ctx;
1773 if (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, &own_identity))
1777 GNUNET_assert (GNUNET_YES == Peers_check_peer_known (peer));
1779 //TODO if LIVE/ONLINE execute immediately
1781 if (GNUNET_NO == check_operation_scheduled (peer, peer_op))
1783 peer_ctx = get_peer_ctx (peer);
1784 pending_op.op = peer_op;
1785 pending_op.op_cls = NULL;
1786 GNUNET_array_append (peer_ctx->pending_ops,
1787 peer_ctx->num_pending_ops,
1795 * @brief Get the recv_channel of @a peer.
1796 * Needed to correctly handle (call #GNUNET_CADET_receive_done()) incoming
1799 * @param peer The peer to get the recv_channel from.
1801 * @return The recv_channel.
1803 struct GNUNET_CADET_Channel *
1804 Peers_get_recv_channel (const struct GNUNET_PeerIdentity *peer)
1806 struct PeerContext *peer_ctx;
1808 GNUNET_assert (GNUNET_YES == Peers_check_peer_known (peer));
1809 peer_ctx = get_peer_ctx (peer);
1810 return peer_ctx->recv_channel;
1812 /***********************************************************************
1813 * /Old gnunet-service-rps_peers.c
1814 ***********************************************************************/
1817 /***********************************************************************
1818 * Housekeeping with clients
1819 ***********************************************************************/
1822 * Closure used to pass the client and the id to the callback
1823 * that replies to a client's request
1830 struct ReplyCls *next;
1831 struct ReplyCls *prev;
1834 * The identifier of the request
1839 * The handle to the request
1841 struct RPS_SamplerRequestHandle *req_handle;
1844 * The client handle to send the reply to
1846 struct ClientContext *cli_ctx;
1851 * Struct used to store the context of a connected client.
1853 struct ClientContext
1858 struct ClientContext *next;
1859 struct ClientContext *prev;
1862 * The message queue to communicate with the client.
1864 struct GNUNET_MQ_Handle *mq;
1867 * DLL with handles to single requests from the client
1869 struct ReplyCls *rep_cls_head;
1870 struct ReplyCls *rep_cls_tail;
1873 * @brief How many updates this client expects to receive.
1875 int64_t view_updates_left;
1878 * The client handle to send the reply to
1880 struct GNUNET_SERVICE_Client *client;
1884 * DLL with all clients currently connected to us
1886 struct ClientContext *cli_ctx_head;
1887 struct ClientContext *cli_ctx_tail;
1889 /***********************************************************************
1890 * /Housekeeping with clients
1891 ***********************************************************************/
1897 /***********************************************************************
1899 ***********************************************************************/
1902 * Sampler used for the Brahms protocol itself.
1904 static struct RPS_Sampler *prot_sampler;
1907 * Sampler used for the clients.
1909 static struct RPS_Sampler *client_sampler;
1912 * Name to log view to
1914 static char *file_name_view_log;
1917 * The size of sampler we need to be able to satisfy the client's need
1920 static unsigned int sampler_size_client_need;
1923 * The size of sampler we need to be able to satisfy the Brahms protocol's
1924 * need of random peers.
1926 * This is one minimum size the sampler grows to.
1928 static unsigned int sampler_size_est_need;
1931 * Percentage of total peer number in the view
1932 * to send random PUSHes to
1937 * Percentage of total peer number in the view
1938 * to send random PULLs to
1943 * Identifier for the main task that runs periodically.
1945 static struct GNUNET_SCHEDULER_Task *do_round_task;
1948 * Time inverval the do_round task runs in.
1950 static struct GNUNET_TIME_Relative round_interval;
1953 * List to store peers received through pushes temporary.
1955 static struct CustomPeerMap *push_map;
1958 * List to store peers received through pulls temporary.
1960 static struct CustomPeerMap *pull_map;
1965 static struct GNUNET_NSE_Handle *nse;
1970 static struct GNUNET_CADET_Handle *cadet_handle;
1973 * @brief Port to communicate to other peers.
1975 static struct GNUNET_CADET_Port *cadet_port;
1978 * Handler to PEERINFO.
1980 static struct GNUNET_PEERINFO_Handle *peerinfo_handle;
1983 * Handle for cancellation of iteration over peers.
1985 static struct GNUNET_PEERINFO_NotifyContext *peerinfo_notify_handle;
1990 * Counts how many requets clients already issued.
1991 * Only needed in the beginning to check how many of the 64 deltas
1994 static unsigned int req_counter;
1997 * Time of the last request we received.
1999 * Used to compute the expected request rate.
2001 static struct GNUNET_TIME_Absolute last_request;
2004 * Size of #request_deltas.
2006 #define REQUEST_DELTAS_SIZE 64
2007 static unsigned int request_deltas_size = REQUEST_DELTAS_SIZE;
2010 * Last 64 deltas between requests
2012 static struct GNUNET_TIME_Relative request_deltas[REQUEST_DELTAS_SIZE];
2015 * The prediction of the rate of requests
2017 static struct GNUNET_TIME_Relative request_rate;
2020 #ifdef ENABLE_MALICIOUS
2022 * Type of malicious peer
2024 * 0 Don't act malicious at all - Default
2025 * 1 Try to maximise representation
2026 * 2 Try to partition the network
2029 static uint32_t mal_type;
2032 * Other malicious peers
2034 static struct GNUNET_PeerIdentity *mal_peers;
2037 * Hashmap of malicious peers used as set.
2038 * Used to more efficiently check whether we know that peer.
2040 static struct GNUNET_CONTAINER_MultiPeerMap *mal_peer_set;
2043 * Number of other malicious peers
2045 static uint32_t num_mal_peers;
2049 * If type is 2 This struct is used to store the attacked peers in a DLL
2056 struct AttackedPeer *next;
2057 struct AttackedPeer *prev;
2062 struct GNUNET_PeerIdentity peer_id;
2066 * If type is 2 this is the DLL of attacked peers
2068 static struct AttackedPeer *att_peers_head;
2069 static struct AttackedPeer *att_peers_tail;
2072 * This index is used to point to an attacked peer to
2073 * implement the round-robin-ish way to select attacked peers.
2075 static struct AttackedPeer *att_peer_index;
2078 * Hashmap of attacked peers used as set.
2079 * Used to more efficiently check whether we know that peer.
2081 static struct GNUNET_CONTAINER_MultiPeerMap *att_peer_set;
2084 * Number of attacked peers
2086 static uint32_t num_attacked_peers;
2089 * If type is 1 this is the attacked peer
2091 static struct GNUNET_PeerIdentity attacked_peer;
2094 * The limit of PUSHes we can send in one round.
2095 * This is an assumption of the Brahms protocol and either implemented
2098 * assumend to be the bandwidth limitation.
2100 static uint32_t push_limit = 10000;
2101 #endif /* ENABLE_MALICIOUS */
2104 /***********************************************************************
2106 ***********************************************************************/
2109 /***********************************************************************
2111 ***********************************************************************/
2115 * Print peerlist to log.
2118 print_peer_list (struct GNUNET_PeerIdentity *list,
2123 LOG (GNUNET_ERROR_TYPE_DEBUG,
2124 "Printing peer list of length %u at %p:\n",
2127 for (i = 0 ; i < len ; i++)
2129 LOG (GNUNET_ERROR_TYPE_DEBUG,
2131 i, GNUNET_i2s (&list[i]));
2137 * Remove peer from list.
2140 rem_from_list (struct GNUNET_PeerIdentity **peer_list,
2141 unsigned int *list_size,
2142 const struct GNUNET_PeerIdentity *peer)
2145 struct GNUNET_PeerIdentity *tmp;
2149 LOG (GNUNET_ERROR_TYPE_DEBUG,
2150 "Removing peer %s from list at %p\n",
2154 for ( i = 0 ; i < *list_size ; i++ )
2156 if (0 == GNUNET_CRYPTO_cmp_peer_identity (&tmp[i], peer))
2158 if (i < *list_size -1)
2159 { /* Not at the last entry -- shift peers left */
2160 memmove (&tmp[i], &tmp[i +1],
2161 ((*list_size) - i -1) * sizeof (struct GNUNET_PeerIdentity));
2163 /* Remove last entry (should be now useless PeerID) */
2164 GNUNET_array_grow (tmp, *list_size, (*list_size) -1);
2172 * Sum all time relatives of an array.
2174 static struct GNUNET_TIME_Relative
2175 T_relative_sum (const struct GNUNET_TIME_Relative *rel_array,
2178 struct GNUNET_TIME_Relative sum;
2181 sum = GNUNET_TIME_UNIT_ZERO;
2182 for ( i = 0 ; i < arr_size ; i++ )
2184 sum = GNUNET_TIME_relative_add (sum, rel_array[i]);
2191 * Compute the average of given time relatives.
2193 static struct GNUNET_TIME_Relative
2194 T_relative_avg (const struct GNUNET_TIME_Relative *rel_array,
2197 return GNUNET_TIME_relative_divide (T_relative_sum (rel_array,
2204 * Insert PeerID in #view
2206 * Called once we know a peer is live.
2207 * Implements #PeerOp
2209 * @return GNUNET_OK if peer was actually inserted
2210 * GNUNET_NO if peer was not inserted
2213 insert_in_view_op (void *cls,
2214 const struct GNUNET_PeerIdentity *peer);
2217 * Insert PeerID in #view
2219 * Called once we know a peer is live.
2221 * @return GNUNET_OK if peer was actually inserted
2222 * GNUNET_NO if peer was not inserted
2225 insert_in_view (const struct GNUNET_PeerIdentity *peer)
2229 online = Peers_check_peer_flag (peer, Peers_ONLINE);
2230 if ( (GNUNET_NO == online) ||
2231 (GNUNET_SYSERR == online) ) /* peer is not even known */
2233 (void) Peers_issue_peer_liveliness_check (peer);
2234 (void) Peers_schedule_operation (peer, insert_in_view_op);
2237 /* Open channel towards peer to keep connection open */
2238 Peers_indicate_sending_intention (peer);
2239 return View_put (peer);
2243 * Put random peer from sampler into the view as history update.
2246 hist_update (void *cls,
2247 struct GNUNET_PeerIdentity *ids,
2252 for (i = 0; i < num_peers; i++)
2254 (void) insert_in_view (&ids[i]);
2255 to_file (file_name_view_log,
2257 GNUNET_i2s_full (ids));
2263 * Wrapper around #RPS_sampler_resize()
2265 * If we do not have enough sampler elements, double current sampler size
2266 * If we have more than enough sampler elements, halv current sampler size
2269 resize_wrapper (struct RPS_Sampler *sampler, uint32_t new_size)
2271 unsigned int sampler_size;
2274 // TODO respect the min, max
2275 sampler_size = RPS_sampler_get_size (sampler);
2276 if (sampler_size > new_size * 4)
2278 RPS_sampler_resize (sampler, sampler_size / 2);
2280 else if (sampler_size < new_size)
2282 RPS_sampler_resize (sampler, sampler_size * 2);
2284 LOG (GNUNET_ERROR_TYPE_DEBUG, "sampler_size is now %u\n", sampler_size);
2289 * Wrapper around #RPS_sampler_resize() resizing the client sampler
2292 client_resize_wrapper ()
2294 uint32_t bigger_size;
2298 bigger_size = GNUNET_MAX (sampler_size_est_need, sampler_size_client_need);
2300 // TODO respect the min, max
2301 resize_wrapper (client_sampler, bigger_size);
2302 LOG (GNUNET_ERROR_TYPE_DEBUG, "sampler_size_client is now %" PRIu32 "\n",
2308 * Estimate request rate
2310 * Called every time we receive a request from the client.
2315 struct GNUNET_TIME_Relative max_round_duration;
2317 if (request_deltas_size > req_counter)
2319 if ( 1 < req_counter)
2321 /* Shift last request deltas to the right */
2322 memmove (&request_deltas[1],
2324 (req_counter - 1) * sizeof (struct GNUNET_TIME_Relative));
2326 /* Add current delta to beginning */
2328 GNUNET_TIME_absolute_get_difference (last_request,
2329 GNUNET_TIME_absolute_get ());
2330 request_rate = T_relative_avg (request_deltas, req_counter);
2331 request_rate = (request_rate.rel_value_us < 1) ?
2332 GNUNET_TIME_relative_get_unit_ () : request_rate;
2334 /* Compute the duration a round will maximally take */
2335 max_round_duration =
2336 GNUNET_TIME_relative_add (round_interval,
2337 GNUNET_TIME_relative_divide (round_interval, 2));
2339 /* Set the estimated size the sampler has to have to
2340 * satisfy the current client request rate */
2341 sampler_size_client_need =
2342 max_round_duration.rel_value_us / request_rate.rel_value_us;
2344 /* Resize the sampler */
2345 client_resize_wrapper ();
2347 last_request = GNUNET_TIME_absolute_get ();
2352 * Add all peers in @a peer_array to @a peer_map used as set.
2354 * @param peer_array array containing the peers
2355 * @param num_peers number of peers in @peer_array
2356 * @param peer_map the peermap to use as set
2359 add_peer_array_to_set (const struct GNUNET_PeerIdentity *peer_array,
2360 unsigned int num_peers,
2361 struct GNUNET_CONTAINER_MultiPeerMap *peer_map)
2364 if (NULL == peer_map)
2366 LOG (GNUNET_ERROR_TYPE_WARNING,
2367 "Trying to add peers to non-existing peermap.\n");
2371 for (i = 0; i < num_peers; i++)
2373 GNUNET_CONTAINER_multipeermap_put (peer_map,
2376 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
2382 * Send a PULL REPLY to @a peer_id
2384 * @param peer_id the peer to send the reply to.
2385 * @param peer_ids the peers to send to @a peer_id
2386 * @param num_peer_ids the number of peers to send to @a peer_id
2389 send_pull_reply (const struct GNUNET_PeerIdentity *peer_id,
2390 const struct GNUNET_PeerIdentity *peer_ids,
2391 unsigned int num_peer_ids)
2394 struct GNUNET_MQ_Envelope *ev;
2395 struct GNUNET_RPS_P2P_PullReplyMessage *out_msg;
2397 /* Compute actual size */
2398 send_size = sizeof (struct GNUNET_RPS_P2P_PullReplyMessage) +
2399 num_peer_ids * sizeof (struct GNUNET_PeerIdentity);
2401 if (GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE < send_size)
2402 /* Compute number of peers to send
2403 * If too long, simply truncate */
2404 // TODO select random ones via permutation
2405 // or even better: do good protocol design
2407 (GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE -
2408 sizeof (struct GNUNET_RPS_P2P_PullReplyMessage)) /
2409 sizeof (struct GNUNET_PeerIdentity);
2411 send_size = num_peer_ids;
2413 LOG (GNUNET_ERROR_TYPE_DEBUG,
2414 "Going to send PULL REPLY with %u peers to %s\n",
2415 send_size, GNUNET_i2s (peer_id));
2417 ev = GNUNET_MQ_msg_extra (out_msg,
2418 send_size * sizeof (struct GNUNET_PeerIdentity),
2419 GNUNET_MESSAGE_TYPE_RPS_PP_PULL_REPLY);
2420 out_msg->num_peers = htonl (send_size);
2421 GNUNET_memcpy (&out_msg[1], peer_ids,
2422 send_size * sizeof (struct GNUNET_PeerIdentity));
2424 Peers_send_message (peer_id, ev, "PULL REPLY");
2425 GNUNET_STATISTICS_update(stats, "# pull reply send issued", 1, GNUNET_NO);
2430 * Insert PeerID in #pull_map
2432 * Called once we know a peer is live.
2435 insert_in_pull_map (void *cls,
2436 const struct GNUNET_PeerIdentity *peer)
2438 CustomPeerMap_put (pull_map, peer);
2443 * Insert PeerID in #view
2445 * Called once we know a peer is live.
2446 * Implements #PeerOp
2449 insert_in_view_op (void *cls,
2450 const struct GNUNET_PeerIdentity *peer)
2452 (void) insert_in_view (peer);
2457 * Update sampler with given PeerID.
2458 * Implements #PeerOp
2461 insert_in_sampler (void *cls,
2462 const struct GNUNET_PeerIdentity *peer)
2464 LOG (GNUNET_ERROR_TYPE_DEBUG,
2465 "Updating samplers with peer %s from insert_in_sampler()\n",
2467 RPS_sampler_update (prot_sampler, peer);
2468 RPS_sampler_update (client_sampler, peer);
2469 if (0 < RPS_sampler_count_id (prot_sampler, peer))
2471 /* Make sure we 'know' about this peer */
2472 (void) Peers_issue_peer_liveliness_check (peer);
2473 /* Establish a channel towards that peer to indicate we are going to send
2475 //Peers_indicate_sending_intention (peer);
2480 * @brief This is called on peers from external sources (cadet, peerinfo, ...)
2481 * If the peer is not known, liveliness check is issued and it is
2482 * scheduled to be inserted in sampler and view.
2484 * "External sources" refer to every source except the gossip.
2486 * @param peer peer to insert
2489 got_peer (const struct GNUNET_PeerIdentity *peer)
2491 /* If we did not know this peer already, insert it into sampler and view */
2492 if (GNUNET_YES == Peers_issue_peer_liveliness_check (peer))
2494 Peers_schedule_operation (peer, insert_in_sampler);
2495 Peers_schedule_operation (peer, insert_in_view_op);
2500 * @brief Checks if there is a sending channel and if it is needed
2502 * @param peer the peer whose sending channel is checked
2503 * @return GNUNET_YES if sending channel exists and is still needed
2504 * GNUNET_NO otherwise
2507 check_sending_channel_needed (const struct GNUNET_PeerIdentity *peer)
2509 /* struct GNUNET_CADET_Channel *channel; */
2510 if (GNUNET_NO == Peers_check_peer_known (peer))
2514 if (GNUNET_YES == Peers_check_sending_channel_exists (peer))
2516 if ( (0 < RPS_sampler_count_id (prot_sampler, peer)) ||
2517 (GNUNET_YES == View_contains_peer (peer)) ||
2518 (GNUNET_YES == CustomPeerMap_contains_peer (push_map, peer)) ||
2519 (GNUNET_YES == CustomPeerMap_contains_peer (pull_map, peer)) ||
2520 (GNUNET_YES == Peers_check_peer_flag (peer, Peers_PULL_REPLY_PENDING)))
2521 { /* If we want to keep the connection to peer open */
2530 * @brief remove peer from our knowledge, the view, push and pull maps and
2533 * @param peer the peer to remove
2536 remove_peer (const struct GNUNET_PeerIdentity *peer)
2538 (void) View_remove_peer (peer);
2539 CustomPeerMap_remove_peer (pull_map, peer);
2540 CustomPeerMap_remove_peer (push_map, peer);
2541 RPS_sampler_reinitialise_by_value (prot_sampler, peer);
2542 RPS_sampler_reinitialise_by_value (client_sampler, peer);
2543 Peers_remove_peer (peer);
2548 * @brief Remove data that is not needed anymore.
2550 * If the sending channel is no longer needed it is destroyed.
2552 * @param peer the peer whose data is about to be cleaned
2555 clean_peer (const struct GNUNET_PeerIdentity *peer)
2557 if (GNUNET_NO == check_sending_channel_needed (peer))
2559 LOG (GNUNET_ERROR_TYPE_DEBUG,
2560 "Going to remove send channel to peer %s\n",
2562 #ifdef ENABLE_MALICIOUS
2563 if (0 != GNUNET_CRYPTO_cmp_peer_identity (&attacked_peer, peer))
2564 (void) Peers_destroy_sending_channel (peer);
2565 #else /* ENABLE_MALICIOUS */
2566 (void) Peers_destroy_sending_channel (peer);
2567 #endif /* ENABLE_MALICIOUS */
2570 if ( (GNUNET_NO == Peers_check_peer_send_intention (peer)) &&
2571 (GNUNET_NO == View_contains_peer (peer)) &&
2572 (GNUNET_NO == CustomPeerMap_contains_peer (push_map, peer)) &&
2573 (GNUNET_NO == CustomPeerMap_contains_peer (push_map, peer)) &&
2574 (0 == RPS_sampler_count_id (prot_sampler, peer)) &&
2575 (0 == RPS_sampler_count_id (client_sampler, peer)) &&
2576 (GNUNET_NO != Peers_check_removable (peer)) )
2577 { /* We can safely remove this peer */
2578 LOG (GNUNET_ERROR_TYPE_DEBUG,
2579 "Going to remove peer %s\n",
2587 * @brief This is called when a channel is destroyed.
2589 * Removes peer completely from our knowledge if the send_channel was destroyed
2590 * Otherwise simply delete the recv_channel
2591 * Also check if the knowledge about this peer is still needed.
2592 * If not, remove this peer from our knowledge.
2594 * @param cls The closure
2595 * @param channel The channel being closed
2596 * @param channel_ctx The context associated with this channel
2599 cleanup_destroyed_channel (void *cls,
2600 const struct GNUNET_CADET_Channel *channel)
2602 struct GNUNET_PeerIdentity *peer = cls;
2603 uint32_t *channel_flag;
2604 struct PeerContext *peer_ctx;
2606 GNUNET_assert (NULL != peer);
2608 if (GNUNET_NO == Peers_check_peer_known (peer))
2609 { /* We don't know a context to that peer */
2610 LOG (GNUNET_ERROR_TYPE_WARNING,
2611 "channel (%s) without associated context was destroyed\n",
2617 peer_ctx = get_peer_ctx (peer);
2618 if (GNUNET_YES == Peers_check_channel_role (peer, channel, Peers_CHANNEL_ROLE_RECEIVING))
2620 set_channel_flag (peer_ctx->recv_channel_flags, Peers_CHANNEL_DESTROING);
2621 } else if (GNUNET_YES == Peers_check_channel_role (peer, channel, Peers_CHANNEL_ROLE_SENDING))
2623 set_channel_flag (peer_ctx->send_channel_flags, Peers_CHANNEL_DESTROING);
2626 if (GNUNET_YES == Peers_check_peer_flag (peer, Peers_TO_DESTROY))
2627 { /* We are in the middle of removing that peer from our knowledge. In this
2628 case simply make sure that the channels are cleaned. */
2629 Peers_cleanup_destroyed_channel (cls, channel);
2630 to_file (file_name_view_log,
2631 "-%s\t(cleanup channel, ourself)",
2632 GNUNET_i2s_full (peer));
2638 Peers_check_channel_role (peer, channel, Peers_CHANNEL_ROLE_SENDING))
2639 { /* Channel used for sending was destroyed */
2640 /* Possible causes of channel destruction:
2641 * - ourselves -> cleaning send channel -> clean context
2642 * - other peer -> peer probably went down -> remove
2644 channel_flag = Peers_get_channel_flag (peer, Peers_CHANNEL_ROLE_SENDING);
2645 if (GNUNET_YES == Peers_check_channel_flag (channel_flag, Peers_CHANNEL_CLEAN))
2646 { /* We are about to clean the sending channel. Clean the respective
2648 Peers_cleanup_destroyed_channel (cls, channel);
2653 { /* Other peer destroyed our sending channel that he is supposed to keep
2654 * open. It probably went down. Remove it from our knowledge. */
2655 Peers_cleanup_destroyed_channel (cls, channel);
2661 else if (GNUNET_YES ==
2662 Peers_check_channel_role (peer, channel, Peers_CHANNEL_ROLE_RECEIVING))
2663 { /* Channel used for receiving was destroyed */
2664 /* Possible causes of channel destruction:
2665 * - ourselves -> peer tried to establish channel twice -> clean context
2666 * - other peer -> peer doesn't want to send us data -> clean
2668 channel_flag = Peers_get_channel_flag (peer, Peers_CHANNEL_ROLE_RECEIVING);
2670 Peers_check_channel_flag (channel_flag, Peers_CHANNEL_ESTABLISHED_TWICE))
2671 { /* Other peer tried to establish a channel to us twice. We do not accept
2672 * that. Clean the context. */
2673 Peers_cleanup_destroyed_channel (cls, channel);
2678 { /* Other peer doesn't want to send us data anymore. We are free to clean
2680 Peers_cleanup_destroyed_channel (cls, channel);
2688 LOG (GNUNET_ERROR_TYPE_WARNING,
2689 "Destroyed channel is neither sending nor receiving channel\n");
2694 /***********************************************************************
2696 ***********************************************************************/
2699 destroy_reply_cls (struct ReplyCls *rep_cls)
2701 struct ClientContext *cli_ctx;
2703 cli_ctx = rep_cls->cli_ctx;
2704 GNUNET_assert (NULL != cli_ctx);
2705 if (NULL != rep_cls->req_handle)
2707 RPS_sampler_request_cancel (rep_cls->req_handle);
2709 GNUNET_CONTAINER_DLL_remove (cli_ctx->rep_cls_head,
2710 cli_ctx->rep_cls_tail,
2712 GNUNET_free (rep_cls);
2717 destroy_cli_ctx (struct ClientContext *cli_ctx)
2719 GNUNET_assert (NULL != cli_ctx);
2720 if (NULL != cli_ctx->rep_cls_head)
2722 LOG (GNUNET_ERROR_TYPE_WARNING,
2723 "Trying to destroy the context of a client that still has pending requests. Going to clean those\n");
2724 while (NULL != cli_ctx->rep_cls_head)
2725 destroy_reply_cls (cli_ctx->rep_cls_head);
2727 GNUNET_CONTAINER_DLL_remove (cli_ctx_head,
2730 GNUNET_free (cli_ctx);
2735 * Function called by NSE.
2737 * Updates sizes of sampler list and view and adapt those lists
2741 nse_callback (void *cls,
2742 struct GNUNET_TIME_Absolute timestamp,
2743 double logestimate, double std_dev)
2746 //double scale; // TODO this might go gloabal/config
2748 LOG (GNUNET_ERROR_TYPE_DEBUG,
2749 "Received a ns estimate - logest: %f, std_dev: %f (old_size: %u)\n",
2750 logestimate, std_dev, RPS_sampler_get_size (prot_sampler));
2752 estimate = GNUNET_NSE_log_estimate_to_n (logestimate);
2753 // GNUNET_NSE_log_estimate_to_n (logestimate);
2754 estimate = pow (estimate, 1.0 / 3);
2755 // TODO add if std_dev is a number
2756 // estimate += (std_dev * scale);
2757 if (2 < ceil (estimate))
2759 LOG (GNUNET_ERROR_TYPE_DEBUG, "Changing estimate to %f\n", estimate);
2760 sampler_size_est_need = estimate;
2762 LOG (GNUNET_ERROR_TYPE_DEBUG, "Not using estimate %f\n", estimate);
2764 /* If the NSE has changed adapt the lists accordingly */
2765 resize_wrapper (prot_sampler, sampler_size_est_need);
2766 client_resize_wrapper ();
2771 * Callback called once the requested PeerIDs are ready.
2773 * Sends those to the requesting client.
2776 client_respond (void *cls,
2777 struct GNUNET_PeerIdentity *peer_ids,
2780 struct ReplyCls *reply_cls = cls;
2782 struct GNUNET_MQ_Envelope *ev;
2783 struct GNUNET_RPS_CS_ReplyMessage *out_msg;
2784 uint32_t size_needed;
2785 struct ClientContext *cli_ctx;
2787 GNUNET_assert (NULL != reply_cls);
2788 LOG (GNUNET_ERROR_TYPE_DEBUG,
2789 "sampler returned %" PRIu32 " peers:\n",
2791 for (i = 0; i < num_peers; i++)
2793 LOG (GNUNET_ERROR_TYPE_DEBUG,
2794 " %" PRIu32 ": %s\n",
2796 GNUNET_i2s (&peer_ids[i]));
2799 size_needed = sizeof (struct GNUNET_RPS_CS_ReplyMessage) +
2800 num_peers * sizeof (struct GNUNET_PeerIdentity);
2802 GNUNET_assert (GNUNET_MAX_MESSAGE_SIZE >= size_needed);
2804 ev = GNUNET_MQ_msg_extra (out_msg,
2805 num_peers * sizeof (struct GNUNET_PeerIdentity),
2806 GNUNET_MESSAGE_TYPE_RPS_CS_REPLY);
2807 out_msg->num_peers = htonl (num_peers);
2808 out_msg->id = htonl (reply_cls->id);
2810 GNUNET_memcpy (&out_msg[1],
2812 num_peers * sizeof (struct GNUNET_PeerIdentity));
2813 GNUNET_free (peer_ids);
2815 cli_ctx = reply_cls->cli_ctx;
2816 GNUNET_assert (NULL != cli_ctx);
2817 reply_cls->req_handle = NULL;
2818 destroy_reply_cls (reply_cls);
2819 GNUNET_MQ_send (cli_ctx->mq, ev);
2824 * Handle RPS request from the client.
2826 * @param cls closure
2827 * @param message the actual message
2830 handle_client_request (void *cls,
2831 const struct GNUNET_RPS_CS_RequestMessage *msg)
2833 struct ClientContext *cli_ctx = cls;
2835 uint32_t size_needed;
2836 struct ReplyCls *reply_cls;
2839 num_peers = ntohl (msg->num_peers);
2840 size_needed = sizeof (struct GNUNET_RPS_CS_RequestMessage) +
2841 num_peers * sizeof (struct GNUNET_PeerIdentity);
2843 if (GNUNET_MAX_MESSAGE_SIZE < size_needed)
2845 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2846 "Message received from client has size larger than expected\n");
2847 GNUNET_SERVICE_client_drop (cli_ctx->client);
2851 for (i = 0 ; i < num_peers ; i++)
2854 LOG (GNUNET_ERROR_TYPE_DEBUG,
2855 "Client requested %" PRIu32 " random peer(s).\n",
2858 reply_cls = GNUNET_new (struct ReplyCls);
2859 reply_cls->id = ntohl (msg->id);
2860 reply_cls->cli_ctx = cli_ctx;
2861 reply_cls->req_handle = RPS_sampler_get_n_rand_peers (client_sampler,
2866 GNUNET_assert (NULL != cli_ctx);
2867 GNUNET_CONTAINER_DLL_insert (cli_ctx->rep_cls_head,
2868 cli_ctx->rep_cls_tail,
2870 GNUNET_SERVICE_client_continue (cli_ctx->client);
2875 * @brief Handle a message that requests the cancellation of a request
2878 * @param message the message containing the id of the request
2881 handle_client_request_cancel (void *cls,
2882 const struct GNUNET_RPS_CS_RequestCancelMessage *msg)
2884 struct ClientContext *cli_ctx = cls;
2885 struct ReplyCls *rep_cls;
2887 GNUNET_assert (NULL != cli_ctx);
2888 GNUNET_assert (NULL != cli_ctx->rep_cls_head);
2889 rep_cls = cli_ctx->rep_cls_head;
2890 LOG (GNUNET_ERROR_TYPE_DEBUG,
2891 "Client cancels request with id %" PRIu32 "\n",
2893 while ( (NULL != rep_cls->next) &&
2894 (rep_cls->id != ntohl (msg->id)) )
2895 rep_cls = rep_cls->next;
2896 GNUNET_assert (rep_cls->id == ntohl (msg->id));
2897 destroy_reply_cls (rep_cls);
2898 GNUNET_SERVICE_client_continue (cli_ctx->client);
2903 * @brief This function is called, when the client seeds peers.
2904 * It verifies that @a msg is well-formed.
2906 * @param cls the closure (#ClientContext)
2907 * @param msg the message
2908 * @return #GNUNET_OK if @a msg is well-formed
2911 check_client_seed (void *cls, const struct GNUNET_RPS_CS_SeedMessage *msg)
2913 struct ClientContext *cli_ctx = cls;
2914 uint16_t msize = ntohs (msg->header.size);
2915 uint32_t num_peers = ntohl (msg->num_peers);
2917 msize -= sizeof (struct GNUNET_RPS_CS_SeedMessage);
2918 if ( (msize / sizeof (struct GNUNET_PeerIdentity) != num_peers) ||
2919 (msize % sizeof (struct GNUNET_PeerIdentity) != 0) )
2922 GNUNET_SERVICE_client_drop (cli_ctx->client);
2923 return GNUNET_SYSERR;
2930 * Handle seed from the client.
2932 * @param cls closure
2933 * @param message the actual message
2936 handle_client_seed (void *cls,
2937 const struct GNUNET_RPS_CS_SeedMessage *msg)
2939 struct ClientContext *cli_ctx = cls;
2940 struct GNUNET_PeerIdentity *peers;
2944 num_peers = ntohl (msg->num_peers);
2945 peers = (struct GNUNET_PeerIdentity *) &msg[1];
2946 //peers = GNUNET_new_array (num_peers, struct GNUNET_PeerIdentity);
2947 //GNUNET_memcpy (peers, &msg[1], num_peers * sizeof (struct GNUNET_PeerIdentity));
2949 LOG (GNUNET_ERROR_TYPE_DEBUG,
2950 "Client seeded peers:\n");
2951 print_peer_list (peers, num_peers);
2953 for (i = 0; i < num_peers; i++)
2955 LOG (GNUNET_ERROR_TYPE_DEBUG,
2956 "Updating samplers with seed %" PRIu32 ": %s\n",
2958 GNUNET_i2s (&peers[i]));
2960 got_peer (&peers[i]);
2963 ////GNUNET_free (peers);
2965 GNUNET_SERVICE_client_continue (cli_ctx->client);
2969 * @brief Send view to client
2971 * @param cli_ctx the context of the client
2972 * @param view_array the peerids of the view as array (can be empty)
2973 * @param view_size the size of the view array (can be 0)
2976 send_view (const struct ClientContext *cli_ctx,
2977 const struct GNUNET_PeerIdentity *view_array,
2980 struct GNUNET_MQ_Envelope *ev;
2981 struct GNUNET_RPS_CS_DEBUG_ViewReply *out_msg;
2983 if (NULL == view_array)
2985 view_size = View_size ();
2986 view_array = View_get_as_array();
2989 ev = GNUNET_MQ_msg_extra (out_msg,
2990 view_size * sizeof (struct GNUNET_PeerIdentity),
2991 GNUNET_MESSAGE_TYPE_RPS_CS_DEBUG_VIEW_REPLY);
2992 out_msg->num_peers = htonl (view_size);
2994 GNUNET_memcpy (&out_msg[1],
2996 view_size * sizeof (struct GNUNET_PeerIdentity));
2997 GNUNET_MQ_send (cli_ctx->mq, ev);
3001 * @brief sends updates to clients that are interested
3004 clients_notify_view_update (void)
3006 struct ClientContext *cli_ctx_iter;
3008 const struct GNUNET_PeerIdentity *view_array;
3010 num_peers = View_size ();
3011 view_array = View_get_as_array();
3012 /* check size of view is small enough */
3013 if (GNUNET_MAX_MESSAGE_SIZE < num_peers)
3015 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3016 "View is too big to send\n");
3020 for (cli_ctx_iter = cli_ctx_head;
3021 NULL != cli_ctx_iter;
3022 cli_ctx_iter = cli_ctx_head->next)
3024 if (1 < cli_ctx_iter->view_updates_left)
3026 /* Client wants to receive limited amount of updates */
3027 cli_ctx_iter->view_updates_left -= 1;
3028 } else if (1 == cli_ctx_iter->view_updates_left)
3030 /* Last update of view for client */
3031 cli_ctx_iter->view_updates_left = -1;
3032 } else if (0 > cli_ctx_iter->view_updates_left) {
3033 /* Client is not interested in updates */
3036 /* else _updates_left == 0 - infinite amount of updates */
3039 send_view (cli_ctx_iter, view_array, num_peers);
3045 * Handle RPS request from the client.
3047 * @param cls closure
3048 * @param message the actual message
3051 handle_client_view_request (void *cls,
3052 const struct GNUNET_RPS_CS_DEBUG_ViewRequest *msg)
3054 struct ClientContext *cli_ctx = cls;
3055 uint64_t num_updates;
3057 num_updates = ntohl (msg->num_updates);
3059 LOG (GNUNET_ERROR_TYPE_DEBUG,
3060 "Client requested %" PRIu64 " updates of view.\n",
3063 GNUNET_assert (NULL != cli_ctx);
3064 cli_ctx->view_updates_left = num_updates;
3065 send_view (cli_ctx, NULL, 0);
3066 GNUNET_SERVICE_client_continue (cli_ctx->client);
3070 * Handle a CHECK_LIVE message from another peer.
3072 * This does nothing. But without calling #GNUNET_CADET_receive_done()
3073 * the channel is blocked for all other communication.
3075 * @param cls Closure
3076 * @param msg The message header
3079 handle_peer_check (void *cls,
3080 const struct GNUNET_MessageHeader *msg)
3082 const struct GNUNET_PeerIdentity *peer = cls;
3084 GNUNET_CADET_receive_done (Peers_get_recv_channel (peer));
3088 * Handle a PUSH message from another peer.
3090 * Check the proof of work and store the PeerID
3091 * in the temporary list for pushed PeerIDs.
3093 * @param cls Closure
3094 * @param msg The message header
3097 handle_peer_push (void *cls,
3098 const struct GNUNET_MessageHeader *msg)
3100 const struct GNUNET_PeerIdentity *peer = cls;
3102 // (check the proof of work (?))
3104 LOG (GNUNET_ERROR_TYPE_DEBUG,
3105 "Received PUSH (%s)\n",
3107 GNUNET_STATISTICS_update(stats, "# push message received", 1, GNUNET_NO);
3109 #ifdef ENABLE_MALICIOUS
3110 struct AttackedPeer *tmp_att_peer;
3112 if ( (1 == mal_type) ||
3114 { /* Try to maximise representation */
3115 tmp_att_peer = GNUNET_new (struct AttackedPeer);
3116 tmp_att_peer->peer_id = *peer;
3117 if (NULL == att_peer_set)
3118 att_peer_set = GNUNET_CONTAINER_multipeermap_create (1, GNUNET_NO);
3120 GNUNET_CONTAINER_multipeermap_contains (att_peer_set,
3123 GNUNET_CONTAINER_DLL_insert (att_peers_head,
3126 add_peer_array_to_set (peer, 1, att_peer_set);
3131 else if (2 == mal_type)
3133 /* We attack one single well-known peer - simply ignore */
3135 #endif /* ENABLE_MALICIOUS */
3137 /* Add the sending peer to the push_map */
3138 CustomPeerMap_put (push_map, peer);
3140 GNUNET_CADET_receive_done (Peers_get_recv_channel (peer));
3145 * Handle PULL REQUEST request message from another peer.
3147 * Reply with the view of PeerIDs.
3149 * @param cls Closure
3150 * @param msg The message header
3153 handle_peer_pull_request (void *cls,
3154 const struct GNUNET_MessageHeader *msg)
3156 struct GNUNET_PeerIdentity *peer = cls;
3157 const struct GNUNET_PeerIdentity *view_array;
3159 LOG (GNUNET_ERROR_TYPE_DEBUG, "Received PULL REQUEST (%s)\n", GNUNET_i2s (peer));
3160 GNUNET_STATISTICS_update(stats, "# pull request message received", 1, GNUNET_NO);
3162 #ifdef ENABLE_MALICIOUS
3165 { /* Try to maximise representation */
3166 send_pull_reply (peer, mal_peers, num_mal_peers);
3169 else if (2 == mal_type)
3170 { /* Try to partition network */
3171 if (0 == GNUNET_CRYPTO_cmp_peer_identity (&attacked_peer, peer))
3173 send_pull_reply (peer, mal_peers, num_mal_peers);
3176 #endif /* ENABLE_MALICIOUS */
3178 GNUNET_break_op (Peers_check_peer_known (peer));
3179 GNUNET_CADET_receive_done (Peers_get_recv_channel (peer));
3180 view_array = View_get_as_array ();
3181 send_pull_reply (peer, view_array, View_size ());
3186 * Check whether we sent a corresponding request and
3187 * whether this reply is the first one.
3189 * @param cls Closure
3190 * @param msg The message header
3193 check_peer_pull_reply (void *cls,
3194 const struct GNUNET_RPS_P2P_PullReplyMessage *msg)
3196 struct GNUNET_PeerIdentity *sender = cls;
3198 if (sizeof (struct GNUNET_RPS_P2P_PullReplyMessage) > ntohs (msg->header.size))
3200 GNUNET_break_op (0);
3201 return GNUNET_SYSERR;
3204 if ((ntohs (msg->header.size) - sizeof (struct GNUNET_RPS_P2P_PullReplyMessage)) /
3205 sizeof (struct GNUNET_PeerIdentity) != ntohl (msg->num_peers))
3207 LOG (GNUNET_ERROR_TYPE_ERROR,
3208 "message says it sends %" PRIu32 " peers, have space for %lu peers\n",
3209 ntohl (msg->num_peers),
3210 (ntohs (msg->header.size) - sizeof (struct GNUNET_RPS_P2P_PullReplyMessage)) /
3211 sizeof (struct GNUNET_PeerIdentity));
3212 GNUNET_break_op (0);
3213 return GNUNET_SYSERR;
3216 if (GNUNET_YES != Peers_check_peer_flag (sender, Peers_PULL_REPLY_PENDING))
3218 LOG (GNUNET_ERROR_TYPE_WARNING,
3219 "Received a pull reply from a peer we didn't request one from!\n");
3220 GNUNET_break_op (0);
3221 return GNUNET_SYSERR;
3227 * Handle PULL REPLY message from another peer.
3229 * @param cls Closure
3230 * @param msg The message header
3233 handle_peer_pull_reply (void *cls,
3234 const struct GNUNET_RPS_P2P_PullReplyMessage *msg)
3236 const struct GNUNET_PeerIdentity *peers;
3237 struct GNUNET_PeerIdentity *sender = cls;
3239 #ifdef ENABLE_MALICIOUS
3240 struct AttackedPeer *tmp_att_peer;
3241 #endif /* ENABLE_MALICIOUS */
3243 LOG (GNUNET_ERROR_TYPE_DEBUG, "Received PULL REPLY (%s)\n", GNUNET_i2s (sender));
3244 GNUNET_STATISTICS_update(stats, "# pull reply messages received", 1, GNUNET_NO);
3246 #ifdef ENABLE_MALICIOUS
3247 // We shouldn't even receive pull replies as we're not sending
3251 #endif /* ENABLE_MALICIOUS */
3253 /* Do actual logic */
3254 peers = (const struct GNUNET_PeerIdentity *) &msg[1];
3256 LOG (GNUNET_ERROR_TYPE_DEBUG,
3257 "PULL REPLY received, got following %u peers:\n",
3258 ntohl (msg->num_peers));
3260 for (i = 0; i < ntohl (msg->num_peers); i++)
3262 LOG (GNUNET_ERROR_TYPE_DEBUG,
3265 GNUNET_i2s (&peers[i]));
3267 #ifdef ENABLE_MALICIOUS
3268 if ((NULL != att_peer_set) &&
3269 (1 == mal_type || 3 == mal_type))
3270 { /* Add attacked peer to local list */
3271 // TODO check if we sent a request and this was the first reply
3272 if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (att_peer_set,
3274 && GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (mal_peer_set,
3276 && 0 != GNUNET_CRYPTO_cmp_peer_identity (&peers[i],
3279 tmp_att_peer = GNUNET_new (struct AttackedPeer);
3280 tmp_att_peer->peer_id = peers[i];
3281 GNUNET_CONTAINER_DLL_insert (att_peers_head,
3284 add_peer_array_to_set (&peers[i], 1, att_peer_set);
3288 #endif /* ENABLE_MALICIOUS */
3289 if (0 != GNUNET_CRYPTO_cmp_peer_identity (&own_identity,
3292 /* Make sure we 'know' about this peer */
3293 (void) Peers_insert_peer (&peers[i]);
3295 if (GNUNET_YES == Peers_check_peer_valid (&peers[i]))
3297 CustomPeerMap_put (pull_map, &peers[i]);
3301 Peers_schedule_operation (&peers[i], insert_in_pull_map);
3302 (void) Peers_issue_peer_liveliness_check (&peers[i]);
3307 Peers_unset_peer_flag (sender, Peers_PULL_REPLY_PENDING);
3308 clean_peer (sender);
3310 GNUNET_CADET_receive_done (Peers_get_recv_channel (sender));
3315 * Compute a random delay.
3316 * A uniformly distributed value between mean + spread and mean - spread.
3318 * For example for mean 4 min and spread 2 the minimum is (4 min - (1/2 * 4 min))
3319 * It would return a random value between 2 and 6 min.
3321 * @param mean the mean
3322 * @param spread the inverse amount of deviation from the mean
3324 static struct GNUNET_TIME_Relative
3325 compute_rand_delay (struct GNUNET_TIME_Relative mean,
3326 unsigned int spread)
3328 struct GNUNET_TIME_Relative half_interval;
3329 struct GNUNET_TIME_Relative ret;
3330 unsigned int rand_delay;
3331 unsigned int max_rand_delay;
3335 LOG (GNUNET_ERROR_TYPE_WARNING,
3336 "Not accepting spread of 0\n");
3340 GNUNET_assert (0 != mean.rel_value_us);
3342 /* Compute random time value between spread * mean and spread * mean */
3343 half_interval = GNUNET_TIME_relative_divide (mean, spread);
3345 max_rand_delay = GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us / mean.rel_value_us * (2/spread);
3347 * Compute random value between (0 and 1) * round_interval
3348 * via multiplying round_interval with a 'fraction' (0 to value)/value
3350 rand_delay = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, max_rand_delay);
3351 ret = GNUNET_TIME_relative_saturating_multiply (mean, rand_delay);
3352 ret = GNUNET_TIME_relative_divide (ret, max_rand_delay);
3353 ret = GNUNET_TIME_relative_add (ret, half_interval);
3355 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == ret.rel_value_us)
3356 LOG (GNUNET_ERROR_TYPE_WARNING,
3357 "Returning FOREVER_REL\n");
3364 * Send single pull request
3366 * @param peer_id the peer to send the pull request to.
3369 send_pull_request (const struct GNUNET_PeerIdentity *peer)
3371 struct GNUNET_MQ_Envelope *ev;
3373 GNUNET_assert (GNUNET_NO == Peers_check_peer_flag (peer,
3374 Peers_PULL_REPLY_PENDING));
3375 Peers_set_peer_flag (peer, Peers_PULL_REPLY_PENDING);
3377 LOG (GNUNET_ERROR_TYPE_DEBUG,
3378 "Going to send PULL REQUEST to peer %s.\n",
3381 ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_RPS_PP_PULL_REQUEST);
3382 Peers_send_message (peer, ev, "PULL REQUEST");
3383 GNUNET_STATISTICS_update(stats, "# pull request send issued", 1, GNUNET_NO);
3390 * @param peer_id the peer to send the push to.
3393 send_push (const struct GNUNET_PeerIdentity *peer_id)
3395 struct GNUNET_MQ_Envelope *ev;
3397 LOG (GNUNET_ERROR_TYPE_DEBUG,
3398 "Going to send PUSH to peer %s.\n",
3399 GNUNET_i2s (peer_id));
3401 ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_RPS_PP_PUSH);
3402 Peers_send_message (peer_id, ev, "PUSH");
3403 GNUNET_STATISTICS_update(stats, "# push send issued", 1, GNUNET_NO);
3408 do_round (void *cls);
3411 do_mal_round (void *cls);
3413 #ifdef ENABLE_MALICIOUS
3417 * @brief This function is called, when the client tells us to act malicious.
3418 * It verifies that @a msg is well-formed.
3420 * @param cls the closure (#ClientContext)
3421 * @param msg the message
3422 * @return #GNUNET_OK if @a msg is well-formed
3425 check_client_act_malicious (void *cls,
3426 const struct GNUNET_RPS_CS_ActMaliciousMessage *msg)
3428 struct ClientContext *cli_ctx = cls;
3429 uint16_t msize = ntohs (msg->header.size);
3430 uint32_t num_peers = ntohl (msg->num_peers);
3432 msize -= sizeof (struct GNUNET_RPS_CS_ActMaliciousMessage);
3433 if ( (msize / sizeof (struct GNUNET_PeerIdentity) != num_peers) ||
3434 (msize % sizeof (struct GNUNET_PeerIdentity) != 0) )
3436 LOG (GNUNET_ERROR_TYPE_ERROR,
3437 "message says it sends %" PRIu32 " peers, have space for %lu peers\n",
3438 ntohl (msg->num_peers),
3439 (msize / sizeof (struct GNUNET_PeerIdentity)));
3441 GNUNET_SERVICE_client_drop (cli_ctx->client);
3442 return GNUNET_SYSERR;
3448 * Turn RPS service to act malicious.
3450 * @param cls Closure
3451 * @param client The client that sent the message
3452 * @param msg The message header
3455 handle_client_act_malicious (void *cls,
3456 const struct GNUNET_RPS_CS_ActMaliciousMessage *msg)
3458 struct ClientContext *cli_ctx = cls;
3459 struct GNUNET_PeerIdentity *peers;
3460 uint32_t num_mal_peers_sent;
3461 uint32_t num_mal_peers_old;
3463 /* Do actual logic */
3464 peers = (struct GNUNET_PeerIdentity *) &msg[1];
3465 mal_type = ntohl (msg->type);
3466 if (NULL == mal_peer_set)
3467 mal_peer_set = GNUNET_CONTAINER_multipeermap_create (1, GNUNET_NO);
3469 LOG (GNUNET_ERROR_TYPE_DEBUG,
3470 "Now acting malicious type %" PRIu32 ", got %" PRIu32 " peers.\n",
3472 ntohl (msg->num_peers));
3475 { /* Try to maximise representation */
3476 /* Add other malicious peers to those we already know */
3478 num_mal_peers_sent = ntohl (msg->num_peers);
3479 num_mal_peers_old = num_mal_peers;
3480 GNUNET_array_grow (mal_peers,
3482 num_mal_peers + num_mal_peers_sent);
3483 GNUNET_memcpy (&mal_peers[num_mal_peers_old],
3485 num_mal_peers_sent * sizeof (struct GNUNET_PeerIdentity));
3487 /* Add all mal peers to mal_peer_set */
3488 add_peer_array_to_set (&mal_peers[num_mal_peers_old],
3492 /* Substitute do_round () with do_mal_round () */
3493 GNUNET_SCHEDULER_cancel (do_round_task);
3494 do_round_task = GNUNET_SCHEDULER_add_now (&do_mal_round, NULL);
3497 else if ( (2 == mal_type) ||
3499 { /* Try to partition the network */
3500 /* Add other malicious peers to those we already know */
3502 num_mal_peers_sent = ntohl (msg->num_peers) - 1;
3503 num_mal_peers_old = num_mal_peers;
3504 GNUNET_array_grow (mal_peers,
3506 num_mal_peers + num_mal_peers_sent);
3507 if (NULL != mal_peers &&
3510 GNUNET_memcpy (&mal_peers[num_mal_peers_old],
3512 num_mal_peers_sent * sizeof (struct GNUNET_PeerIdentity));
3514 /* Add all mal peers to mal_peer_set */
3515 add_peer_array_to_set (&mal_peers[num_mal_peers_old],
3520 /* Store the one attacked peer */
3521 GNUNET_memcpy (&attacked_peer,
3522 &msg->attacked_peer,
3523 sizeof (struct GNUNET_PeerIdentity));
3524 /* Set the flag of the attacked peer to valid to avoid problems */
3525 if (GNUNET_NO == Peers_check_peer_known (&attacked_peer))
3527 (void) Peers_issue_peer_liveliness_check (&attacked_peer);
3530 LOG (GNUNET_ERROR_TYPE_DEBUG,
3531 "Attacked peer is %s\n",
3532 GNUNET_i2s (&attacked_peer));
3534 /* Substitute do_round () with do_mal_round () */
3535 GNUNET_SCHEDULER_cancel (do_round_task);
3536 do_round_task = GNUNET_SCHEDULER_add_now (&do_mal_round, NULL);
3538 else if (0 == mal_type)
3539 { /* Stop acting malicious */
3540 GNUNET_array_grow (mal_peers, num_mal_peers, 0);
3542 /* Substitute do_mal_round () with do_round () */
3543 GNUNET_SCHEDULER_cancel (do_round_task);
3544 do_round_task = GNUNET_SCHEDULER_add_now (&do_round, NULL);
3549 GNUNET_SERVICE_client_continue (cli_ctx->client);
3551 GNUNET_SERVICE_client_continue (cli_ctx->client);
3556 * Send out PUSHes and PULLs maliciously.
3558 * This is executed regylary.
3561 do_mal_round (void *cls)
3563 uint32_t num_pushes;
3565 struct GNUNET_TIME_Relative time_next_round;
3566 struct AttackedPeer *tmp_att_peer;
3568 LOG (GNUNET_ERROR_TYPE_DEBUG,
3569 "Going to execute next round maliciously type %" PRIu32 ".\n",
3571 do_round_task = NULL;
3572 GNUNET_assert (mal_type <= 3);
3573 /* Do malicious actions */
3575 { /* Try to maximise representation */
3577 /* The maximum of pushes we're going to send this round */
3578 num_pushes = GNUNET_MIN (GNUNET_MIN (push_limit,
3579 num_attacked_peers),
3580 GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE);
3582 LOG (GNUNET_ERROR_TYPE_DEBUG,
3583 "Going to send %" PRIu32 " pushes\n",
3586 /* Send PUSHes to attacked peers */
3587 for (i = 0 ; i < num_pushes ; i++)
3589 if (att_peers_tail == att_peer_index)
3590 att_peer_index = att_peers_head;
3592 att_peer_index = att_peer_index->next;
3594 send_push (&att_peer_index->peer_id);
3597 /* Send PULLs to some peers to learn about additional peers to attack */
3598 tmp_att_peer = att_peer_index;
3599 for (i = 0 ; i < num_pushes * alpha ; i++)
3601 if (att_peers_tail == tmp_att_peer)
3602 tmp_att_peer = att_peers_head;
3604 att_peer_index = tmp_att_peer->next;
3606 send_pull_request (&tmp_att_peer->peer_id);
3611 else if (2 == mal_type)
3613 * Try to partition the network
3614 * Send as many pushes to the attacked peer as possible
3615 * That is one push per round as it will ignore more.
3617 (void) Peers_issue_peer_liveliness_check (&attacked_peer);
3618 if (GNUNET_YES == Peers_check_peer_flag (&attacked_peer, Peers_ONLINE))
3619 send_push (&attacked_peer);
3624 { /* Combined attack */
3626 /* Send PUSH to attacked peers */
3627 if (GNUNET_YES == Peers_check_peer_known (&attacked_peer))
3629 (void) Peers_issue_peer_liveliness_check (&attacked_peer);
3630 if (GNUNET_YES == Peers_check_peer_flag (&attacked_peer, Peers_ONLINE))
3632 LOG (GNUNET_ERROR_TYPE_DEBUG,
3633 "Goding to send push to attacked peer (%s)\n",
3634 GNUNET_i2s (&attacked_peer));
3635 send_push (&attacked_peer);
3638 (void) Peers_issue_peer_liveliness_check (&attacked_peer);
3640 /* The maximum of pushes we're going to send this round */
3641 num_pushes = GNUNET_MIN (GNUNET_MIN (push_limit - 1,
3642 num_attacked_peers),
3643 GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE);
3645 LOG (GNUNET_ERROR_TYPE_DEBUG,
3646 "Going to send %" PRIu32 " pushes\n",
3649 for (i = 0; i < num_pushes; i++)
3651 if (att_peers_tail == att_peer_index)
3652 att_peer_index = att_peers_head;
3654 att_peer_index = att_peer_index->next;
3656 send_push (&att_peer_index->peer_id);
3659 /* Send PULLs to some peers to learn about additional peers to attack */
3660 tmp_att_peer = att_peer_index;
3661 for (i = 0; i < num_pushes * alpha; i++)
3663 if (att_peers_tail == tmp_att_peer)
3664 tmp_att_peer = att_peers_head;
3666 att_peer_index = tmp_att_peer->next;
3668 send_pull_request (&tmp_att_peer->peer_id);
3672 /* Schedule next round */
3673 time_next_round = compute_rand_delay (round_interval, 2);
3675 //do_round_task = GNUNET_SCHEDULER_add_delayed (round_interval, &do_mal_round,
3677 GNUNET_assert (NULL == do_round_task);
3678 do_round_task = GNUNET_SCHEDULER_add_delayed (time_next_round,
3679 &do_mal_round, NULL);
3680 LOG (GNUNET_ERROR_TYPE_DEBUG, "Finished round\n");
3682 #endif /* ENABLE_MALICIOUS */
3685 * Send out PUSHes and PULLs, possibly update #view, samplers.
3687 * This is executed regylary.
3690 do_round (void *cls)
3693 const struct GNUNET_PeerIdentity *view_array;
3694 unsigned int *permut;
3695 unsigned int a_peers; /* Number of peers we send pushes to */
3696 unsigned int b_peers; /* Number of peers we send pull requests to */
3697 uint32_t first_border;
3698 uint32_t second_border;
3699 struct GNUNET_PeerIdentity peer;
3700 struct GNUNET_PeerIdentity *update_peer;
3702 LOG (GNUNET_ERROR_TYPE_DEBUG,
3703 "Going to execute next round.\n");
3704 GNUNET_STATISTICS_update(stats, "# rounds", 1, GNUNET_NO);
3705 do_round_task = NULL;
3706 LOG (GNUNET_ERROR_TYPE_DEBUG,
3707 "Printing view:\n");
3708 to_file (file_name_view_log,
3709 "___ new round ___");
3710 view_array = View_get_as_array ();
3711 for (i = 0; i < View_size (); i++)
3713 LOG (GNUNET_ERROR_TYPE_DEBUG,
3714 "\t%s\n", GNUNET_i2s (&view_array[i]));
3715 to_file (file_name_view_log,
3717 GNUNET_i2s_full (&view_array[i]));
3721 /* Send pushes and pull requests */
3722 if (0 < View_size ())
3724 permut = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_STRONG,
3728 a_peers = ceil (alpha * View_size ());
3730 LOG (GNUNET_ERROR_TYPE_DEBUG,
3731 "Going to send pushes to %u (ceil (%f * %u)) peers.\n",
3732 a_peers, alpha, View_size ());
3733 for (i = 0; i < a_peers; i++)
3735 peer = view_array[permut[i]];
3736 if (0 != GNUNET_CRYPTO_cmp_peer_identity (&own_identity, &peer)) // TODO
3737 { // FIXME if this fails schedule/loop this for later
3742 /* Send PULL requests */
3743 b_peers = ceil (beta * View_size ());
3744 first_border = a_peers;
3745 second_border = a_peers + b_peers;
3746 if (second_border > View_size ())
3748 first_border = View_size () - b_peers;
3749 second_border = View_size ();
3751 LOG (GNUNET_ERROR_TYPE_DEBUG,
3752 "Going to send pulls to %u (ceil (%f * %u)) peers.\n",
3753 b_peers, beta, View_size ());
3754 for (i = first_border; i < second_border; i++)
3756 peer = view_array[permut[i]];
3757 if (0 != GNUNET_CRYPTO_cmp_peer_identity (&own_identity, &peer) &&
3758 GNUNET_NO == Peers_check_peer_flag (&peer, Peers_PULL_REPLY_PENDING)) // TODO
3759 { // FIXME if this fails schedule/loop this for later
3760 send_pull_request (&peer);
3764 GNUNET_free (permut);
3770 /* TODO see how many peers are in push-/pull- list! */
3772 if ((CustomPeerMap_size (push_map) <= alpha * View_size ()) &&
3773 (0 < CustomPeerMap_size (push_map)) &&
3774 (0 < CustomPeerMap_size (pull_map)))
3775 { /* If conditions for update are fulfilled, update */
3776 LOG (GNUNET_ERROR_TYPE_DEBUG, "Update of the view.\n");
3778 uint32_t final_size;
3779 uint32_t peers_to_clean_size;
3780 struct GNUNET_PeerIdentity *peers_to_clean;
3782 peers_to_clean = NULL;
3783 peers_to_clean_size = 0;
3784 GNUNET_array_grow (peers_to_clean, peers_to_clean_size, View_size ());
3785 GNUNET_memcpy (peers_to_clean,
3787 View_size () * sizeof (struct GNUNET_PeerIdentity));
3789 /* Seems like recreating is the easiest way of emptying the peermap */
3791 to_file (file_name_view_log,
3794 first_border = GNUNET_MIN (ceil (alpha * sampler_size_est_need),
3795 CustomPeerMap_size (push_map));
3796 second_border = first_border +
3797 GNUNET_MIN (floor (beta * sampler_size_est_need),
3798 CustomPeerMap_size (pull_map));
3799 final_size = second_border +
3800 ceil ((1 - (alpha + beta)) * sampler_size_est_need);
3802 /* Update view with peers received through PUSHes */
3803 permut = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_STRONG,
3804 CustomPeerMap_size (push_map));
3805 for (i = 0; i < first_border; i++)
3807 (void) insert_in_view (CustomPeerMap_get_peer_by_index (push_map,
3809 to_file (file_name_view_log,
3811 GNUNET_i2s_full (&view_array[i]));
3812 // TODO change the peer_flags accordingly
3814 GNUNET_free (permut);
3817 /* Update view with peers received through PULLs */
3818 permut = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_STRONG,
3819 CustomPeerMap_size (pull_map));
3820 for (i = first_border; i < second_border; i++)
3822 (void) insert_in_view (CustomPeerMap_get_peer_by_index (pull_map,
3823 permut[i - first_border]));
3824 to_file (file_name_view_log,
3826 GNUNET_i2s_full (&view_array[i]));
3827 // TODO change the peer_flags accordingly
3829 GNUNET_free (permut);
3832 /* Update view with peers from history */
3833 RPS_sampler_get_n_rand_peers (prot_sampler,
3836 final_size - second_border);
3837 // TODO change the peer_flags accordingly
3839 for (i = 0; i < View_size (); i++)
3840 rem_from_list (&peers_to_clean, &peers_to_clean_size, &view_array[i]);
3842 /* Clean peers that were removed from the view */
3843 for (i = 0; i < peers_to_clean_size; i++)
3845 to_file (file_name_view_log,
3847 GNUNET_i2s_full (&peers_to_clean[i]));
3848 clean_peer (&peers_to_clean[i]);
3849 //peer_destroy_channel_send (sender);
3852 GNUNET_array_grow (peers_to_clean, peers_to_clean_size, 0);
3853 clients_notify_view_update();
3855 LOG (GNUNET_ERROR_TYPE_DEBUG, "No update of the view.\n");
3856 GNUNET_STATISTICS_update(stats, "# rounds blocked", 1, GNUNET_NO);
3857 if (CustomPeerMap_size (push_map) > alpha * View_size () &&
3858 !(0 >= CustomPeerMap_size (pull_map)))
3859 GNUNET_STATISTICS_update(stats, "# rounds blocked - too many pushes", 1, GNUNET_NO);
3860 if (CustomPeerMap_size (push_map) > alpha * View_size () &&
3861 (0 >= CustomPeerMap_size (pull_map)))
3862 GNUNET_STATISTICS_update(stats, "# rounds blocked - too many pushes, no pull replies", 1, GNUNET_NO);
3863 if (0 >= CustomPeerMap_size (push_map) &&
3864 !(0 >= CustomPeerMap_size (pull_map)))
3865 GNUNET_STATISTICS_update(stats, "# rounds blocked - no pushes", 1, GNUNET_NO);
3866 if (0 >= CustomPeerMap_size (push_map) &&
3867 (0 >= CustomPeerMap_size (pull_map)))
3868 GNUNET_STATISTICS_update(stats, "# rounds blocked - no pushes, no pull replies", 1, GNUNET_NO);
3869 if (0 >= CustomPeerMap_size (pull_map) &&
3870 CustomPeerMap_size (push_map) > alpha * View_size () &&
3871 0 >= CustomPeerMap_size (push_map))
3872 GNUNET_STATISTICS_update(stats, "# rounds blocked - no pull replies", 1, GNUNET_NO);
3874 // TODO independent of that also get some peers from CADET_get_peers()?
3875 GNUNET_STATISTICS_set (stats,
3876 "# peers in push map at end of round",
3877 CustomPeerMap_size (push_map),
3879 GNUNET_STATISTICS_set (stats,
3880 "# peers in pull map at end of round",
3881 CustomPeerMap_size (pull_map),
3883 GNUNET_STATISTICS_set (stats,
3884 "# peers in view at end of round",
3888 LOG (GNUNET_ERROR_TYPE_DEBUG,
3889 "Received %u pushes and %u pulls last round (alpha (%.2f) * view_size (%u) = %.2f)\n",
3890 CustomPeerMap_size (push_map),
3891 CustomPeerMap_size (pull_map),
3894 alpha * View_size ());
3896 /* Update samplers */
3897 for (i = 0; i < CustomPeerMap_size (push_map); i++)
3899 update_peer = CustomPeerMap_get_peer_by_index (push_map, i);
3900 LOG (GNUNET_ERROR_TYPE_DEBUG,
3901 "Updating with peer %s from push list\n",
3902 GNUNET_i2s (update_peer));
3903 insert_in_sampler (NULL, update_peer);
3904 clean_peer (update_peer); /* This cleans only if it is not in the view */
3905 //peer_destroy_channel_send (sender);
3908 for (i = 0; i < CustomPeerMap_size (pull_map); i++)
3910 LOG (GNUNET_ERROR_TYPE_DEBUG,
3911 "Updating with peer %s from pull list\n",
3912 GNUNET_i2s (CustomPeerMap_get_peer_by_index (pull_map, i)));
3913 insert_in_sampler (NULL, CustomPeerMap_get_peer_by_index (pull_map, i));
3914 /* This cleans only if it is not in the view */
3915 clean_peer (CustomPeerMap_get_peer_by_index (pull_map, i));
3916 //peer_destroy_channel_send (sender);
3920 /* Empty push/pull lists */
3921 CustomPeerMap_clear (push_map);
3922 CustomPeerMap_clear (pull_map);
3924 struct GNUNET_TIME_Relative time_next_round;
3926 time_next_round = compute_rand_delay (round_interval, 2);
3928 /* Schedule next round */
3929 do_round_task = GNUNET_SCHEDULER_add_delayed (time_next_round,
3931 LOG (GNUNET_ERROR_TYPE_DEBUG, "Finished round\n");
3936 * This is called from GNUNET_CADET_get_peers().
3938 * It is called on every peer(ID) that cadet somehow has contact with.
3939 * We use those to initialise the sampler.
3942 init_peer_cb (void *cls,
3943 const struct GNUNET_PeerIdentity *peer,
3944 int tunnel, // "Do we have a tunnel towards this peer?"
3945 unsigned int n_paths, // "Number of known paths towards this peer"
3946 unsigned int best_path) // "How long is the best path?
3947 // (0 = unknown, 1 = ourselves, 2 = neighbor)"
3951 LOG (GNUNET_ERROR_TYPE_DEBUG,
3952 "Got peer_id %s from cadet\n",
3959 * @brief Iterator function over stored, valid peers.
3961 * We initialise the sampler with those.
3963 * @param cls the closure
3964 * @param peer the peer id
3965 * @return #GNUNET_YES if we should continue to
3967 * #GNUNET_NO if not.
3970 valid_peers_iterator (void *cls,
3971 const struct GNUNET_PeerIdentity *peer)
3975 LOG (GNUNET_ERROR_TYPE_DEBUG,
3976 "Got stored, valid peer %s\n",
3985 * Iterator over peers from peerinfo.
3987 * @param cls closure
3988 * @param peer id of the peer, NULL for last call
3989 * @param hello hello message for the peer (can be NULL)
3990 * @param error message
3993 process_peerinfo_peers (void *cls,
3994 const struct GNUNET_PeerIdentity *peer,
3995 const struct GNUNET_HELLO_Message *hello,
3996 const char *err_msg)
4000 LOG (GNUNET_ERROR_TYPE_DEBUG,
4001 "Got peer_id %s from peerinfo\n",
4009 * Task run during shutdown.
4014 shutdown_task (void *cls)
4016 struct ClientContext *client_ctx;
4017 struct ReplyCls *reply_cls;
4019 LOG (GNUNET_ERROR_TYPE_DEBUG,
4020 "RPS is going down\n");
4022 /* Clean all clients */
4023 for (client_ctx = cli_ctx_head;
4024 NULL != cli_ctx_head;
4025 client_ctx = cli_ctx_head)
4027 /* Clean pending requests to the sampler */
4028 for (reply_cls = client_ctx->rep_cls_head;
4029 NULL != client_ctx->rep_cls_head;
4030 reply_cls = client_ctx->rep_cls_head)
4032 RPS_sampler_request_cancel (reply_cls->req_handle);
4033 GNUNET_CONTAINER_DLL_remove (client_ctx->rep_cls_head,
4034 client_ctx->rep_cls_tail,
4036 GNUNET_free (reply_cls);
4038 GNUNET_CONTAINER_DLL_remove (cli_ctx_head, cli_ctx_tail, client_ctx);
4039 GNUNET_free (client_ctx);
4041 GNUNET_PEERINFO_notify_cancel (peerinfo_notify_handle);
4042 GNUNET_PEERINFO_disconnect (peerinfo_handle);
4044 if (NULL != do_round_task)
4046 GNUNET_SCHEDULER_cancel (do_round_task);
4047 do_round_task = NULL;
4052 GNUNET_NSE_disconnect (nse);
4053 RPS_sampler_destroy (prot_sampler);
4054 RPS_sampler_destroy (client_sampler);
4055 GNUNET_CADET_close_port (cadet_port);
4056 GNUNET_CADET_disconnect (cadet_handle);
4058 CustomPeerMap_destroy (push_map);
4059 CustomPeerMap_destroy (pull_map);
4062 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
4065 #ifdef ENABLE_MALICIOUS
4066 struct AttackedPeer *tmp_att_peer;
4067 GNUNET_free (file_name_view_log);
4068 GNUNET_array_grow (mal_peers, num_mal_peers, 0);
4069 if (NULL != mal_peer_set)
4070 GNUNET_CONTAINER_multipeermap_destroy (mal_peer_set);
4071 if (NULL != att_peer_set)
4072 GNUNET_CONTAINER_multipeermap_destroy (att_peer_set);
4073 while (NULL != att_peers_head)
4075 tmp_att_peer = att_peers_head;
4076 GNUNET_CONTAINER_DLL_remove (att_peers_head, att_peers_tail, tmp_att_peer);
4078 #endif /* ENABLE_MALICIOUS */
4083 * Handle client connecting to the service.
4086 * @param client the new client
4087 * @param mq the message queue of @a client
4091 client_connect_cb (void *cls,
4092 struct GNUNET_SERVICE_Client *client,
4093 struct GNUNET_MQ_Handle *mq)
4095 struct ClientContext *cli_ctx;
4097 LOG (GNUNET_ERROR_TYPE_DEBUG,
4098 "Client connected\n");
4100 return client; /* Server was destroyed before a client connected. Shutting down */
4101 cli_ctx = GNUNET_new (struct ClientContext);
4102 cli_ctx->mq = GNUNET_SERVICE_client_get_mq (client);
4103 cli_ctx->view_updates_left = -1;
4104 cli_ctx->client = client;
4105 GNUNET_CONTAINER_DLL_insert (cli_ctx_head,
4112 * Callback called when a client disconnected from the service
4114 * @param cls closure for the service
4115 * @param c the client that disconnected
4116 * @param internal_cls should be equal to @a c
4119 client_disconnect_cb (void *cls,
4120 struct GNUNET_SERVICE_Client *client,
4123 struct ClientContext *cli_ctx = internal_cls;
4125 GNUNET_assert (client == cli_ctx->client);
4127 {/* shutdown task - destroy all clients */
4128 while (NULL != cli_ctx_head)
4129 destroy_cli_ctx (cli_ctx_head);
4132 { /* destroy this client */
4133 LOG (GNUNET_ERROR_TYPE_DEBUG,
4134 "Client disconnected. Destroy its context.\n");
4135 destroy_cli_ctx (cli_ctx);
4141 * Handle random peer sampling clients.
4143 * @param cls closure
4144 * @param c configuration to use
4145 * @param service the initialized service
4149 const struct GNUNET_CONFIGURATION_Handle *c,
4150 struct GNUNET_SERVICE_Handle *service)
4154 char* fn_valid_peers;
4155 struct GNUNET_HashCode port;
4157 GNUNET_log_setup ("rps", GNUNET_error_type_to_string (GNUNET_ERROR_TYPE_DEBUG), NULL);
4162 GNUNET_CRYPTO_get_peer_identity (cfg, &own_identity); // TODO check return value
4163 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4164 "STARTING SERVICE (rps) for peer [%s]\n",
4165 GNUNET_i2s (&own_identity));
4166 #ifdef ENABLE_MALICIOUS
4167 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4168 "Malicious execution compiled in.\n");
4169 #endif /* ENABLE_MALICIOUS */
4173 /* Get time interval from the configuration */
4174 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, "RPS",
4178 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
4179 "RPS", "ROUNDINTERVAL");
4180 GNUNET_SCHEDULER_shutdown ();
4184 /* Get initial size of sampler/view from the configuration */
4186 GNUNET_CONFIGURATION_get_value_number (cfg, "RPS", "INITSIZE",
4187 (long long unsigned int *) &sampler_size_est_need))
4189 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
4191 GNUNET_SCHEDULER_shutdown ();
4194 LOG (GNUNET_ERROR_TYPE_DEBUG, "INITSIZE is %u\n", sampler_size_est_need);
4197 GNUNET_CONFIGURATION_get_value_filename (cfg,
4199 "FILENAME_VALID_PEERS",
4202 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
4203 "rps", "FILENAME_VALID_PEERS");
4209 /* file_name_view_log */
4210 if (GNUNET_OK != GNUNET_DISK_directory_create ("/tmp/rps/"))
4212 LOG (GNUNET_ERROR_TYPE_WARNING,
4213 "Failed to create directory /tmp/rps/\n");
4216 size = (14 + strlen (GNUNET_i2s_full (&own_identity)) + 1) * sizeof (char);
4217 file_name_view_log = GNUNET_malloc (size);
4218 out_size = GNUNET_snprintf (file_name_view_log,
4221 GNUNET_i2s_full (&own_identity));
4222 if (size < out_size ||
4225 LOG (GNUNET_ERROR_TYPE_WARNING,
4226 "Failed to write string to buffer (size: %i, out_size: %i)\n",
4232 /* connect to NSE */
4233 nse = GNUNET_NSE_connect (cfg, nse_callback, NULL);
4240 /* Initialise cadet */
4241 /* There exists a copy-paste-clone in get_channel() */
4242 struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
4243 GNUNET_MQ_hd_fixed_size (peer_check,
4244 GNUNET_MESSAGE_TYPE_RPS_PP_CHECK_LIVE,
4245 struct GNUNET_MessageHeader,
4247 GNUNET_MQ_hd_fixed_size (peer_push,
4248 GNUNET_MESSAGE_TYPE_RPS_PP_PUSH,
4249 struct GNUNET_MessageHeader,
4251 GNUNET_MQ_hd_fixed_size (peer_pull_request,
4252 GNUNET_MESSAGE_TYPE_RPS_PP_PULL_REQUEST,
4253 struct GNUNET_MessageHeader,
4255 GNUNET_MQ_hd_var_size (peer_pull_reply,
4256 GNUNET_MESSAGE_TYPE_RPS_PP_PULL_REPLY,
4257 struct GNUNET_RPS_P2P_PullReplyMessage,
4259 GNUNET_MQ_handler_end ()
4262 cadet_handle = GNUNET_CADET_connect (cfg);
4263 GNUNET_assert (NULL != cadet_handle);
4264 GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_RPS,
4265 strlen (GNUNET_APPLICATION_PORT_RPS),
4267 cadet_port = GNUNET_CADET_open_port (cadet_handle,
4269 &Peers_handle_inbound_channel, /* Connect handler */
4271 NULL, /* WindowSize handler */
4272 cleanup_destroyed_channel, /* Disconnect handler */
4276 peerinfo_handle = GNUNET_PEERINFO_connect (cfg);
4277 Peers_initialise (fn_valid_peers, cadet_handle, cleanup_destroyed_channel,
4279 GNUNET_free (fn_valid_peers);
4281 /* Initialise sampler */
4282 struct GNUNET_TIME_Relative half_round_interval;
4283 struct GNUNET_TIME_Relative max_round_interval;
4285 half_round_interval = GNUNET_TIME_relative_divide (round_interval, 2);
4286 max_round_interval = GNUNET_TIME_relative_add (round_interval, half_round_interval);
4288 prot_sampler = RPS_sampler_init (sampler_size_est_need, max_round_interval);
4289 client_sampler = RPS_sampler_mod_init (sampler_size_est_need, max_round_interval);
4291 /* Initialise push and pull maps */
4292 push_map = CustomPeerMap_create (4);
4293 pull_map = CustomPeerMap_create (4);
4296 //LOG (GNUNET_ERROR_TYPE_DEBUG, "Requesting peers from CADET\n");
4297 //GNUNET_CADET_get_peers (cadet_handle, &init_peer_cb, NULL);
4298 // TODO send push/pull to each of those peers?
4299 // TODO read stored valid peers from last run
4300 LOG (GNUNET_ERROR_TYPE_DEBUG, "Requesting stored valid peers\n");
4301 Peers_get_valid_peers (valid_peers_iterator, NULL);
4303 peerinfo_notify_handle = GNUNET_PEERINFO_notify (cfg,
4305 process_peerinfo_peers,
4308 LOG (GNUNET_ERROR_TYPE_INFO, "Ready to receive requests from clients\n");
4310 do_round_task = GNUNET_SCHEDULER_add_now (&do_round, NULL);
4311 LOG (GNUNET_ERROR_TYPE_DEBUG, "Scheduled first round\n");
4313 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
4314 stats = GNUNET_STATISTICS_create ("rps", cfg);
4320 * Define "main" method using service macro.
4324 GNUNET_SERVICE_OPTION_NONE,
4327 &client_disconnect_cb,
4329 GNUNET_MQ_hd_fixed_size (client_request,
4330 GNUNET_MESSAGE_TYPE_RPS_CS_REQUEST,
4331 struct GNUNET_RPS_CS_RequestMessage,
4333 GNUNET_MQ_hd_fixed_size (client_request_cancel,
4334 GNUNET_MESSAGE_TYPE_RPS_CS_REQUEST_CANCEL,
4335 struct GNUNET_RPS_CS_RequestCancelMessage,
4337 GNUNET_MQ_hd_var_size (client_seed,
4338 GNUNET_MESSAGE_TYPE_RPS_CS_SEED,
4339 struct GNUNET_RPS_CS_SeedMessage,
4341 #ifdef ENABLE_MALICIOUS
4342 GNUNET_MQ_hd_var_size (client_act_malicious,
4343 GNUNET_MESSAGE_TYPE_RPS_ACT_MALICIOUS,
4344 struct GNUNET_RPS_CS_ActMaliciousMessage,
4346 #endif /* ENABLE_MALICIOUS */
4347 GNUNET_MQ_hd_fixed_size (client_view_request,
4348 GNUNET_MESSAGE_TYPE_RPS_CS_DEBUG_VIEW_REQUEST,
4349 struct GNUNET_RPS_CS_DEBUG_ViewRequest,
4351 GNUNET_MQ_handler_end());
4353 /* end of gnunet-service-rps.c */