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_util_lib.h"
28 #include "gnunet_cadet_service.h"
29 #include "gnunet_peerinfo_service.h"
30 #include "gnunet_nse_service.h"
32 #include "rps-test_util.h"
33 #include "gnunet-service-rps_sampler.h"
34 #include "gnunet-service-rps_custommap.h"
35 #include "gnunet-service-rps_peers.h"
36 #include "gnunet-service-rps_view.h"
41 #define LOG(kind, ...) GNUNET_log(kind, __VA_ARGS__)
43 // TODO modify @brief in every file
45 // TODO check for overflows
47 // TODO align message structs
49 // TODO connect to friends
51 // TODO store peers somewhere persistent
53 // TODO blacklist? (-> mal peer detection on top of brahms)
55 // hist_size_init, hist_size_max
60 static const struct GNUNET_CONFIGURATION_Handle *cfg;
65 static struct GNUNET_PeerIdentity own_identity;
68 /***********************************************************************
69 * Housekeeping with clients
70 ***********************************************************************/
73 * Closure used to pass the client and the id to the callback
74 * that replies to a client's request
81 struct ReplyCls *next;
82 struct ReplyCls *prev;
85 * The identifier of the request
90 * The handle to the request
92 struct RPS_SamplerRequestHandle *req_handle;
95 * The client handle to send the reply to
97 struct GNUNET_SERVER_Client *client;
102 * Struct used to store the context of a connected client.
109 struct ClientContext *next;
110 struct ClientContext *prev;
113 * The message queue to communicate with the client.
115 struct GNUNET_MQ_Handle *mq;
118 * DLL with handles to single requests from the client
120 struct ReplyCls *rep_cls_head;
121 struct ReplyCls *rep_cls_tail;
125 * DLL with all clients currently connected to us
127 struct ClientContext *cli_ctx_head;
128 struct ClientContext *cli_ctx_tail;
130 /***********************************************************************
131 * /Housekeeping with clients
132 ***********************************************************************/
138 /***********************************************************************
140 ***********************************************************************/
143 * Sampler used for the Brahms protocol itself.
145 static struct RPS_Sampler *prot_sampler;
148 * Sampler used for the clients.
150 static struct RPS_Sampler *client_sampler;
153 * Name to log view to
155 static char *file_name_view_log;
158 * The size of sampler we need to be able to satisfy the client's need
161 static unsigned int sampler_size_client_need;
164 * The size of sampler we need to be able to satisfy the Brahms protocol's
165 * need of random peers.
167 * This is one minimum size the sampler grows to.
169 static unsigned int sampler_size_est_need;
172 * Percentage of total peer number in the view
173 * to send random PUSHes to
178 * Percentage of total peer number in the view
179 * to send random PULLs to
184 * Identifier for the main task that runs periodically.
186 static struct GNUNET_SCHEDULER_Task *do_round_task;
189 * Time inverval the do_round task runs in.
191 static struct GNUNET_TIME_Relative round_interval;
194 * List to store peers received through pushes temporary.
196 static struct CustomPeerMap *push_map;
199 * List to store peers received through pulls temporary.
201 static struct CustomPeerMap *pull_map;
206 static struct GNUNET_NSE_Handle *nse;
211 static struct GNUNET_CADET_Handle *cadet_handle;
214 * Handler to PEERINFO.
216 static struct GNUNET_PEERINFO_Handle *peerinfo_handle;
219 * Handle for cancellation of iteration over peers.
221 static struct GNUNET_PEERINFO_NotifyContext *peerinfo_notify_handle;
226 * Counts how many requets clients already issued.
227 * Only needed in the beginning to check how many of the 64 deltas
230 static unsigned int req_counter;
233 * Time of the last request we received.
235 * Used to compute the expected request rate.
237 static struct GNUNET_TIME_Absolute last_request;
240 * Size of #request_deltas.
242 #define REQUEST_DELTAS_SIZE 64
243 static unsigned int request_deltas_size = REQUEST_DELTAS_SIZE;
246 * Last 64 deltas between requests
248 static struct GNUNET_TIME_Relative request_deltas[REQUEST_DELTAS_SIZE];
251 * The prediction of the rate of requests
253 static struct GNUNET_TIME_Relative request_rate;
256 #ifdef ENABLE_MALICIOUS
258 * Type of malicious peer
260 * 0 Don't act malicious at all - Default
261 * 1 Try to maximise representation
262 * 2 Try to partition the network
265 static uint32_t mal_type;
268 * Other malicious peers
270 static struct GNUNET_PeerIdentity *mal_peers;
273 * Hashmap of malicious peers used as set.
274 * Used to more efficiently check whether we know that peer.
276 static struct GNUNET_CONTAINER_MultiPeerMap *mal_peer_set;
279 * Number of other malicious peers
281 static uint32_t num_mal_peers;
285 * If type is 2 This struct is used to store the attacked peers in a DLL
292 struct AttackedPeer *next;
293 struct AttackedPeer *prev;
298 struct GNUNET_PeerIdentity peer_id;
302 * If type is 2 this is the DLL of attacked peers
304 static struct AttackedPeer *att_peers_head;
305 static struct AttackedPeer *att_peers_tail;
308 * This index is used to point to an attacked peer to
309 * implement the round-robin-ish way to select attacked peers.
311 static struct AttackedPeer *att_peer_index;
314 * Hashmap of attacked peers used as set.
315 * Used to more efficiently check whether we know that peer.
317 static struct GNUNET_CONTAINER_MultiPeerMap *att_peer_set;
320 * Number of attacked peers
322 static uint32_t num_attacked_peers;
325 * If type is 1 this is the attacked peer
327 static struct GNUNET_PeerIdentity attacked_peer;
330 * The limit of PUSHes we can send in one round.
331 * This is an assumption of the Brahms protocol and either implemented
334 * assumend to be the bandwidth limitation.
336 static uint32_t push_limit = 10000;
337 #endif /* ENABLE_MALICIOUS */
340 /***********************************************************************
342 ***********************************************************************/
345 /***********************************************************************
347 ***********************************************************************/
351 * Print peerlist to log.
354 print_peer_list (struct GNUNET_PeerIdentity *list,
359 LOG (GNUNET_ERROR_TYPE_DEBUG,
360 "Printing peer list of length %u at %p:\n",
363 for (i = 0 ; i < len ; i++)
365 LOG (GNUNET_ERROR_TYPE_DEBUG,
367 i, GNUNET_i2s (&list[i]));
373 * Remove peer from list.
376 rem_from_list (struct GNUNET_PeerIdentity **peer_list,
377 unsigned int *list_size,
378 const struct GNUNET_PeerIdentity *peer)
381 struct GNUNET_PeerIdentity *tmp;
385 LOG (GNUNET_ERROR_TYPE_DEBUG,
386 "Removing peer %s from list at %p\n",
390 for ( i = 0 ; i < *list_size ; i++ )
392 if (0 == GNUNET_CRYPTO_cmp_peer_identity (&tmp[i], peer))
394 if (i < *list_size -1)
395 { /* Not at the last entry -- shift peers left */
396 memcpy (&tmp[i], &tmp[i +1],
397 ((*list_size) - i -1) * sizeof (struct GNUNET_PeerIdentity));
399 /* Remove last entry (should be now useless PeerID) */
400 GNUNET_array_grow (tmp, *list_size, (*list_size) -1);
408 * Sum all time relatives of an array.
410 static struct GNUNET_TIME_Relative
411 T_relative_sum (const struct GNUNET_TIME_Relative *rel_array,
414 struct GNUNET_TIME_Relative sum;
417 sum = GNUNET_TIME_UNIT_ZERO;
418 for ( i = 0 ; i < arr_size ; i++ )
420 sum = GNUNET_TIME_relative_add (sum, rel_array[i]);
427 * Compute the average of given time relatives.
429 static struct GNUNET_TIME_Relative
430 T_relative_avg (const struct GNUNET_TIME_Relative *rel_array,
433 return GNUNET_TIME_relative_divide (T_relative_sum (rel_array,
440 * Put random peer from sampler into the view as history update.
443 hist_update (void *cls,
444 struct GNUNET_PeerIdentity *ids,
449 for (i = 0; i < num_peers; i++)
452 to_file (file_name_view_log,
454 GNUNET_i2s_full (ids));
460 * Wrapper around #RPS_sampler_resize()
462 * If we do not have enough sampler elements, double current sampler size
463 * If we have more than enough sampler elements, halv current sampler size
466 resize_wrapper (struct RPS_Sampler *sampler, uint32_t new_size)
468 unsigned int sampler_size;
471 // TODO respect the min, max
472 sampler_size = RPS_sampler_get_size (sampler);
473 if (sampler_size > new_size * 4)
475 RPS_sampler_resize (sampler, sampler_size / 2);
477 else if (sampler_size < new_size)
479 RPS_sampler_resize (sampler, sampler_size * 2);
481 LOG (GNUNET_ERROR_TYPE_DEBUG, "sampler_size is now %u\n", sampler_size);
486 * Wrapper around #RPS_sampler_resize() resizing the client sampler
489 client_resize_wrapper ()
491 uint32_t bigger_size;
495 bigger_size = GNUNET_MAX (sampler_size_est_need, sampler_size_client_need);
497 // TODO respect the min, max
498 resize_wrapper (client_sampler, bigger_size);
499 LOG (GNUNET_ERROR_TYPE_DEBUG, "sampler_size_client is now %" PRIu32 "\n",
505 * Estimate request rate
507 * Called every time we receive a request from the client.
512 struct GNUNET_TIME_Relative max_round_duration;
514 if (request_deltas_size > req_counter)
516 if ( 1 < req_counter)
518 /* Shift last request deltas to the right */
519 memcpy (&request_deltas[1],
521 (req_counter - 1) * sizeof (struct GNUNET_TIME_Relative));
523 /* Add current delta to beginning */
525 GNUNET_TIME_absolute_get_difference (last_request,
526 GNUNET_TIME_absolute_get ());
527 request_rate = T_relative_avg (request_deltas, req_counter);
528 request_rate = (request_rate.rel_value_us < 1) ?
529 GNUNET_TIME_relative_get_unit_ () : request_rate;
531 /* Compute the duration a round will maximally take */
533 GNUNET_TIME_relative_add (round_interval,
534 GNUNET_TIME_relative_divide (round_interval, 2));
536 /* Set the estimated size the sampler has to have to
537 * satisfy the current client request rate */
538 sampler_size_client_need =
539 max_round_duration.rel_value_us / request_rate.rel_value_us;
541 /* Resize the sampler */
542 client_resize_wrapper ();
544 last_request = GNUNET_TIME_absolute_get ();
549 * Add all peers in @a peer_array to @a peer_map used as set.
551 * @param peer_array array containing the peers
552 * @param num_peers number of peers in @peer_array
553 * @param peer_map the peermap to use as set
556 add_peer_array_to_set (const struct GNUNET_PeerIdentity *peer_array,
557 unsigned int num_peers,
558 struct GNUNET_CONTAINER_MultiPeerMap *peer_map)
561 if (NULL == peer_map)
563 LOG (GNUNET_ERROR_TYPE_WARNING,
564 "Trying to add peers to non-existing peermap.\n");
568 for (i = 0; i < num_peers; i++)
570 GNUNET_CONTAINER_multipeermap_put (peer_map,
573 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
579 * Send a PULL REPLY to @a peer_id
581 * @param peer_id the peer to send the reply to.
582 * @param peer_ids the peers to send to @a peer_id
583 * @param num_peer_ids the number of peers to send to @a peer_id
586 send_pull_reply (const struct GNUNET_PeerIdentity *peer_id,
587 const struct GNUNET_PeerIdentity *peer_ids,
588 unsigned int num_peer_ids)
591 struct GNUNET_MQ_Envelope *ev;
592 struct GNUNET_RPS_P2P_PullReplyMessage *out_msg;
594 /* Compute actual size */
595 send_size = sizeof (struct GNUNET_RPS_P2P_PullReplyMessage) +
596 num_peer_ids * sizeof (struct GNUNET_PeerIdentity);
598 if (GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE < send_size)
599 /* Compute number of peers to send
600 * If too long, simply truncate */
601 // TODO select random ones via permutation
602 // or even better: do good protocol design
604 (GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE -
605 sizeof (struct GNUNET_RPS_P2P_PullReplyMessage)) /
606 sizeof (struct GNUNET_PeerIdentity);
608 send_size = num_peer_ids;
610 LOG (GNUNET_ERROR_TYPE_DEBUG,
611 "Going to send PULL REPLY with %u peers to %s\n",
612 send_size, GNUNET_i2s (peer_id));
614 ev = GNUNET_MQ_msg_extra (out_msg,
615 send_size * sizeof (struct GNUNET_PeerIdentity),
616 GNUNET_MESSAGE_TYPE_RPS_PP_PULL_REPLY);
617 out_msg->num_peers = htonl (send_size);
618 memcpy (&out_msg[1], peer_ids,
619 send_size * sizeof (struct GNUNET_PeerIdentity));
621 Peers_send_message (peer_id, ev, "PULL REPLY");
626 * Insert PeerID in #pull_map
628 * Called once we know a peer is live.
631 insert_in_pull_map (void *cls,
632 const struct GNUNET_PeerIdentity *peer)
634 CustomPeerMap_put (pull_map, peer);
639 * Insert PeerID in #view
641 * Called once we know a peer is live.
645 insert_in_view (void *cls,
646 const struct GNUNET_PeerIdentity *peer)
648 GNUNET_assert (GNUNET_YES == Peers_check_peer_flag (peer, Peers_ONLINE));
654 * Update sampler with given PeerID.
658 insert_in_sampler (void *cls,
659 const struct GNUNET_PeerIdentity *peer)
661 LOG (GNUNET_ERROR_TYPE_DEBUG,
662 "Updating samplers with peer %s from insert_in_sampler()\n",
664 RPS_sampler_update (prot_sampler, peer);
665 RPS_sampler_update (client_sampler, peer);
666 if (0 < RPS_sampler_count_id (prot_sampler, peer))
668 /* Make sure we 'know' about this peer */
669 (void) Peers_check_peer_live (peer);
670 /* Establish a channel towards that peer to indicate we are going to send
672 Peers_indicate_sending_intention (peer);
673 //Peers_issue_peer_liveliness_check (peer);
678 * @brief If @a peer was unknown, check liveliness and insert it in view and
681 * @param peer peer to insert
684 got_peer (const struct GNUNET_PeerIdentity *peer)
686 /* If we did not know this peer already, insert it into sampler and view */
687 if (GNUNET_YES == Peers_check_peer_live (peer))
689 Peers_schedule_operation (peer, insert_in_sampler);
690 Peers_schedule_operation (peer, insert_in_view);
695 * @brief Checks if there is a sending channel and if it is needed
697 * @param peer the peer whose sending channel is checked
698 * @return GNUNET_YES if sending channel exists and is still needed
699 * GNUNET_NO otherwise
702 check_sending_channel_needed (const struct GNUNET_PeerIdentity *peer)
704 /* struct GNUNET_CADET_Channel *channel; */
705 if (GNUNET_NO == Peers_check_peer_known (peer))
709 if (GNUNET_YES == Peers_check_sending_channel_exists (peer))
711 if ( (0 < RPS_sampler_count_id (prot_sampler, peer)) ||
712 (GNUNET_YES == View_contains_peer (peer)) ||
713 (GNUNET_YES == CustomPeerMap_contains_peer (push_map, peer)) ||
714 (GNUNET_YES == CustomPeerMap_contains_peer (pull_map, peer)) ||
715 (GNUNET_YES == Peers_check_peer_flag (peer, Peers_PULL_REPLY_PENDING)))
716 { /* If we want to keep the connection to peer open */
725 * @brief remove peer from our knowledge, the view, push and pull maps and
728 * @param peer the peer to remove
731 remove_peer (const struct GNUNET_PeerIdentity *peer)
733 View_remove_peer (peer);
734 CustomPeerMap_remove_peer (pull_map, peer);
735 CustomPeerMap_remove_peer (push_map, peer);
736 RPS_sampler_reinitialise_by_value (prot_sampler, peer);
737 RPS_sampler_reinitialise_by_value (client_sampler, peer);
738 Peers_remove_peer (peer);
743 * @brief Remove data that is not needed anymore.
745 * If the sending channel is no longer needed it is destroyed.
747 * @param peer the peer whose data is about to be cleaned
750 clean_peer (const struct GNUNET_PeerIdentity *peer)
752 if (GNUNET_NO == check_sending_channel_needed (peer))
754 #ifdef ENABLE_MALICIOUS
755 if (0 != GNUNET_CRYPTO_cmp_peer_identity (&attacked_peer, peer))
756 Peers_destroy_sending_channel (peer);
757 #else /* ENABLE_MALICIOUS */
758 Peers_destroy_sending_channel (peer);
759 #endif /* ENABLE_MALICIOUS */
762 if ( (GNUNET_NO == Peers_check_peer_send_intention (peer)) &&
763 (GNUNET_NO == View_contains_peer (peer)) &&
764 (GNUNET_NO == CustomPeerMap_contains_peer (push_map, peer)) &&
765 (GNUNET_NO == CustomPeerMap_contains_peer (push_map, peer)) &&
766 (0 == RPS_sampler_count_id (prot_sampler, peer)) &&
767 (0 == RPS_sampler_count_id (client_sampler, peer)) )
768 { /* We can safely remov this peer */
772 Peers_clean_peer (peer);
776 * @brief This is called when a channel is destroyed.
778 * Removes peer completely from our knowledge if the send_channel was destroyed
779 * Otherwise simply delete the recv_channel
781 * @param cls The closure
782 * @param channel The channel being closed
783 * @param channel_ctx The context associated with this channel
786 cleanup_destroyed_channel (void *cls,
787 const struct GNUNET_CADET_Channel *channel,
790 struct GNUNET_PeerIdentity *peer;
792 peer = (struct GNUNET_PeerIdentity *) GNUNET_CADET_channel_get_info (
793 (struct GNUNET_CADET_Channel *) channel, GNUNET_CADET_OPTION_PEER);
794 // FIXME wait for cadet to change this function
796 if (GNUNET_NO == Peers_check_peer_known (peer))
797 { /* We don't know a context to that peer */
798 LOG (GNUNET_ERROR_TYPE_WARNING,
799 "channel (%s) without associated context was destroyed\n",
804 if (GNUNET_YES == Peers_check_peer_flag (peer, Peers_TO_DESTROY))
805 { /* We are in the middle of removing that peer from our knowledge. In this
806 case simply make sure that the channels are cleaned. */
807 Peers_cleanup_destroyed_channel (cls, channel, channel_ctx);
808 to_file (file_name_view_log,
809 "-%s\t(cleanup channel, ourself)",
810 GNUNET_i2s_full (peer));
815 Peers_check_channel_role (peer, channel, Peers_CHANNEL_ROLE_SENDING))
816 { /* Channel used for sending was destroyed */
817 /* Possible causes of channel destruction:
818 * - ourselves -> cleaning send channel -> clean context
819 * - other peer -> peer probably went down -> remove
821 if (GNUNET_YES == Peers_check_channel_flag (channel_ctx, Peers_CHANNEL_CLEAN))
822 { /* We are about to clean the sending channel. Clean the respective
824 Peers_cleanup_destroyed_channel (cls, channel, channel_ctx);
828 { /* Other peer destroyed our sending channel that he is supposed to keep
829 * open. It probably went down. Remove it from our knowledge. */
830 Peers_cleanup_destroyed_channel (cls, channel, channel_ctx);
835 else if (GNUNET_YES ==
836 Peers_check_channel_role (peer, channel, Peers_CHANNEL_ROLE_RECEIVING))
837 { /* Channel used for receiving was destroyed */
838 /* Possible causes of channel destruction:
839 * - ourselves -> peer tried to establish channel twice -> clean context
840 * - other peer -> peer doesn't want to send us data -> clean
843 Peers_check_channel_flag (channel_ctx, Peers_CHANNEL_ESTABLISHED_TWICE))
844 { /* Other peer tried to establish a channel to us twice. We do not accept
845 * that. Clean the context. */
846 Peers_cleanup_destroyed_channel (cls, channel, channel_ctx);
850 { /* Other peer doesn't want to send us data anymore. We are free to clean
852 Peers_cleanup_destroyed_channel (cls, channel, channel_ctx);
859 LOG (GNUNET_ERROR_TYPE_WARNING,
860 "Destroyed channel is neither sending nor receiving channel\n");
864 /***********************************************************************
866 ***********************************************************************/
869 destroy_reply_cls (struct ReplyCls *rep_cls)
871 struct ClientContext *cli_ctx;
873 cli_ctx = GNUNET_SERVER_client_get_user_context (rep_cls->client,
874 struct ClientContext);
875 GNUNET_assert (NULL != cli_ctx);
876 GNUNET_CONTAINER_DLL_remove (cli_ctx->rep_cls_head,
877 cli_ctx->rep_cls_tail,
879 GNUNET_free (rep_cls);
884 destroy_cli_ctx (struct ClientContext *cli_ctx)
886 GNUNET_assert (NULL != cli_ctx);
887 if (NULL != cli_ctx->mq)
889 GNUNET_MQ_destroy (cli_ctx->mq);
891 if (NULL != cli_ctx->rep_cls_head)
893 LOG (GNUNET_ERROR_TYPE_WARNING,
894 "Trying to destroy the context of a client that still has pending requests. Going to clean those\n");
895 while (NULL != cli_ctx->rep_cls_head)
896 destroy_reply_cls (cli_ctx->rep_cls_head);
898 GNUNET_CONTAINER_DLL_remove (cli_ctx_head,
901 GNUNET_free (cli_ctx);
906 * Function called by NSE.
908 * Updates sizes of sampler list and view and adapt those lists
912 nse_callback (void *cls,
913 struct GNUNET_TIME_Absolute timestamp,
914 double logestimate, double std_dev)
917 //double scale; // TODO this might go gloabal/config
919 LOG (GNUNET_ERROR_TYPE_DEBUG,
920 "Received a ns estimate - logest: %f, std_dev: %f (old_size: %u)\n",
921 logestimate, std_dev, RPS_sampler_get_size (prot_sampler));
923 estimate = GNUNET_NSE_log_estimate_to_n (logestimate);
924 // GNUNET_NSE_log_estimate_to_n (logestimate);
925 estimate = pow (estimate, 1.0 / 3);
926 // TODO add if std_dev is a number
927 // estimate += (std_dev * scale);
928 if (2 < ceil (estimate))
930 LOG (GNUNET_ERROR_TYPE_DEBUG, "Changing estimate to %f\n", estimate);
931 sampler_size_est_need = estimate;
933 LOG (GNUNET_ERROR_TYPE_DEBUG, "Not using estimate %f\n", estimate);
935 /* If the NSE has changed adapt the lists accordingly */
936 resize_wrapper (prot_sampler, sampler_size_est_need);
937 client_resize_wrapper ();
942 * Callback called once the requested PeerIDs are ready.
944 * Sends those to the requesting client.
947 client_respond (void *cls,
948 struct GNUNET_PeerIdentity *peer_ids,
952 struct GNUNET_MQ_Envelope *ev;
953 struct GNUNET_RPS_CS_ReplyMessage *out_msg;
954 struct ReplyCls *reply_cls = (struct ReplyCls *) cls;
955 uint32_t size_needed;
956 struct ClientContext *cli_ctx;
958 GNUNET_assert (NULL != reply_cls);
959 LOG (GNUNET_ERROR_TYPE_DEBUG,
960 "sampler returned %" PRIu32 " peers:\n",
962 for (i = 0; i < num_peers; i++)
964 LOG (GNUNET_ERROR_TYPE_DEBUG,
965 " %" PRIu32 ": %s\n",
967 GNUNET_i2s (&peer_ids[i]));
970 size_needed = sizeof (struct GNUNET_RPS_CS_ReplyMessage) +
971 num_peers * sizeof (struct GNUNET_PeerIdentity);
973 GNUNET_assert (GNUNET_SERVER_MAX_MESSAGE_SIZE >= size_needed);
975 ev = GNUNET_MQ_msg_extra (out_msg,
976 num_peers * sizeof (struct GNUNET_PeerIdentity),
977 GNUNET_MESSAGE_TYPE_RPS_CS_REPLY);
978 out_msg->num_peers = htonl (num_peers);
979 out_msg->id = htonl (reply_cls->id);
983 num_peers * sizeof (struct GNUNET_PeerIdentity));
984 GNUNET_free (peer_ids);
986 cli_ctx = GNUNET_SERVER_client_get_user_context (reply_cls->client,
987 struct ClientContext);
988 GNUNET_assert (NULL != cli_ctx);
989 destroy_reply_cls (reply_cls);
990 GNUNET_MQ_send (cli_ctx->mq, ev);
995 * Handle RPS request from the client.
998 * @param client identification of the client
999 * @param message the actual message
1002 handle_client_request (void *cls,
1003 struct GNUNET_SERVER_Client *client,
1004 const struct GNUNET_MessageHeader *message)
1006 struct GNUNET_RPS_CS_RequestMessage *msg;
1008 uint32_t size_needed;
1009 struct ReplyCls *reply_cls;
1011 struct ClientContext *cli_ctx;
1013 msg = (struct GNUNET_RPS_CS_RequestMessage *) message;
1015 num_peers = ntohl (msg->num_peers);
1016 size_needed = sizeof (struct GNUNET_RPS_CS_RequestMessage) +
1017 num_peers * sizeof (struct GNUNET_PeerIdentity);
1019 if (GNUNET_SERVER_MAX_MESSAGE_SIZE < size_needed)
1021 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1022 "Message received from client has size larger than expected\n");
1023 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1027 for (i = 0 ; i < num_peers ; i++)
1030 LOG (GNUNET_ERROR_TYPE_DEBUG,
1031 "Client requested %" PRIu32 " random peer(s).\n",
1034 reply_cls = GNUNET_new (struct ReplyCls);
1035 reply_cls->id = ntohl (msg->id);
1036 reply_cls->client = client;
1037 reply_cls->req_handle = RPS_sampler_get_n_rand_peers (client_sampler,
1042 cli_ctx = GNUNET_SERVER_client_get_user_context (client, struct ClientContext);
1043 GNUNET_assert (NULL != cli_ctx);
1044 GNUNET_CONTAINER_DLL_insert (cli_ctx->rep_cls_head,
1045 cli_ctx->rep_cls_tail,
1047 GNUNET_SERVER_receive_done (client,
1053 * @brief Handle a message that requests the cancellation of a request
1056 * @param client the client that requests the cancellation
1057 * @param message the message containing the id of the request
1060 handle_client_request_cancel (void *cls,
1061 struct GNUNET_SERVER_Client *client,
1062 const struct GNUNET_MessageHeader *message)
1064 struct GNUNET_RPS_CS_RequestCancelMessage *msg =
1065 (struct GNUNET_RPS_CS_RequestCancelMessage *) message;
1066 struct ClientContext *cli_ctx;
1067 struct ReplyCls *rep_cls;
1069 cli_ctx = GNUNET_SERVER_client_get_user_context (client, struct ClientContext);
1070 GNUNET_assert (NULL != cli_ctx->rep_cls_head);
1071 rep_cls = cli_ctx->rep_cls_head;
1072 LOG (GNUNET_ERROR_TYPE_DEBUG,
1073 "Client cancels request with id %" PRIu32 "\n",
1075 while ( (NULL != rep_cls->next) &&
1076 (rep_cls->id != ntohl (msg->id)) )
1077 rep_cls = rep_cls->next;
1078 GNUNET_assert (rep_cls->id == ntohl (msg->id));
1079 RPS_sampler_request_cancel (rep_cls->req_handle);
1080 destroy_reply_cls (rep_cls);
1081 GNUNET_SERVER_receive_done (client,
1087 * Handle seed from the client.
1089 * @param cls closure
1090 * @param client identification of the client
1091 * @param message the actual message
1094 handle_client_seed (void *cls,
1095 struct GNUNET_SERVER_Client *client,
1096 const struct GNUNET_MessageHeader *message)
1098 struct GNUNET_RPS_CS_SeedMessage *in_msg;
1099 struct GNUNET_PeerIdentity *peers;
1103 if (sizeof (struct GNUNET_RPS_CS_SeedMessage) > ntohs (message->size))
1105 GNUNET_break_op (0);
1106 GNUNET_SERVER_receive_done (client,
1110 in_msg = (struct GNUNET_RPS_CS_SeedMessage *) message;
1111 num_peers = ntohl (in_msg->num_peers);
1112 peers = (struct GNUNET_PeerIdentity *) &in_msg[1];
1113 //peers = GNUNET_new_array (num_peers, struct GNUNET_PeerIdentity);
1114 //memcpy (peers, &in_msg[1], num_peers * sizeof (struct GNUNET_PeerIdentity));
1116 if ((ntohs (message->size) - sizeof (struct GNUNET_RPS_CS_SeedMessage)) /
1117 sizeof (struct GNUNET_PeerIdentity) != num_peers)
1119 GNUNET_break_op (0);
1120 GNUNET_SERVER_receive_done (client,
1125 LOG (GNUNET_ERROR_TYPE_DEBUG,
1126 "Client seeded peers:\n");
1127 print_peer_list (peers, num_peers);
1129 for (i = 0; i < num_peers; i++)
1131 LOG (GNUNET_ERROR_TYPE_DEBUG,
1132 "Updating samplers with seed %" PRIu32 ": %s\n",
1134 GNUNET_i2s (&peers[i]));
1136 got_peer (&peers[i]);
1138 //RPS_sampler_update (prot_sampler, &peers[i]);
1139 //RPS_sampler_update (client_sampler, &peers[i]);
1142 ////GNUNET_free (peers);
1144 GNUNET_SERVER_receive_done (client,
1150 * Handle a PUSH message from another peer.
1152 * Check the proof of work and store the PeerID
1153 * in the temporary list for pushed PeerIDs.
1155 * @param cls Closure
1156 * @param channel The channel the PUSH was received over
1157 * @param channel_ctx The context associated with this channel
1158 * @param msg The message header
1161 handle_peer_push (void *cls,
1162 struct GNUNET_CADET_Channel *channel,
1164 const struct GNUNET_MessageHeader *msg)
1166 const struct GNUNET_PeerIdentity *peer;
1168 // (check the proof of work (?))
1170 peer = (const struct GNUNET_PeerIdentity *)
1171 GNUNET_CADET_channel_get_info (channel, GNUNET_CADET_OPTION_PEER);
1172 // FIXME wait for cadet to change this function
1174 LOG (GNUNET_ERROR_TYPE_DEBUG,
1175 "Received PUSH (%s)\n",
1178 #ifdef ENABLE_MALICIOUS
1179 struct AttackedPeer *tmp_att_peer;
1181 tmp_att_peer = GNUNET_new (struct AttackedPeer);
1182 memcpy (&tmp_att_peer->peer_id, peer, sizeof (struct GNUNET_PeerIdentity));
1185 { /* Try to maximise representation */
1186 if (NULL == att_peer_set)
1187 att_peer_set = GNUNET_CONTAINER_multipeermap_create (1, GNUNET_NO);
1188 if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (att_peer_set,
1191 GNUNET_CONTAINER_DLL_insert (att_peers_head,
1194 add_peer_array_to_set (peer, 1, att_peer_set);
1200 else if (2 == mal_type)
1201 { /* We attack one single well-known peer - simply ignore */
1206 GNUNET_free (tmp_att_peer);
1209 #endif /* ENABLE_MALICIOUS */
1211 /* Add the sending peer to the push_map */
1212 CustomPeerMap_put (push_map, peer);
1214 GNUNET_CADET_receive_done (channel);
1220 * Handle PULL REQUEST request message from another peer.
1222 * Reply with the view of PeerIDs.
1224 * @param cls Closure
1225 * @param channel The channel the PULL REQUEST was received over
1226 * @param channel_ctx The context associated with this channel
1227 * @param msg The message header
1230 handle_peer_pull_request (void *cls,
1231 struct GNUNET_CADET_Channel *channel,
1233 const struct GNUNET_MessageHeader *msg)
1235 struct GNUNET_PeerIdentity *peer;
1236 const struct GNUNET_PeerIdentity *view_array;
1238 peer = (struct GNUNET_PeerIdentity *)
1239 GNUNET_CADET_channel_get_info (channel,
1240 GNUNET_CADET_OPTION_PEER);
1241 // FIXME wait for cadet to change this function
1243 LOG (GNUNET_ERROR_TYPE_DEBUG, "Received PULL REQUEST (%s)\n", GNUNET_i2s (peer));
1245 #ifdef ENABLE_MALICIOUS
1248 { /* Try to maximise representation */
1249 send_pull_reply (peer, mal_peers, num_mal_peers);
1253 else if (2 == mal_type)
1254 { /* Try to partition network */
1255 if (0 == GNUNET_CRYPTO_cmp_peer_identity (&attacked_peer, peer))
1257 send_pull_reply (peer, mal_peers, num_mal_peers);
1261 #endif /* ENABLE_MALICIOUS */
1263 view_array = View_get_as_array ();
1265 send_pull_reply (peer, view_array, View_size ());
1267 GNUNET_CADET_receive_done (channel);
1273 * Handle PULL REPLY message from another peer.
1275 * Check whether we sent a corresponding request and
1276 * whether this reply is the first one.
1278 * @param cls Closure
1279 * @param channel The channel the PUSH was received over
1280 * @param channel_ctx The context associated with this channel
1281 * @param msg The message header
1284 handle_peer_pull_reply (void *cls,
1285 struct GNUNET_CADET_Channel *channel,
1287 const struct GNUNET_MessageHeader *msg)
1289 struct GNUNET_RPS_P2P_PullReplyMessage *in_msg;
1290 struct GNUNET_PeerIdentity *peers;
1291 struct GNUNET_PeerIdentity *sender;
1293 #ifdef ENABLE_MALICIOUS
1294 struct AttackedPeer *tmp_att_peer;
1295 #endif /* ENABLE_MALICIOUS */
1297 /* Check for protocol violation */
1298 if (sizeof (struct GNUNET_RPS_P2P_PullReplyMessage) > ntohs (msg->size))
1300 GNUNET_break_op (0);
1301 GNUNET_CADET_receive_done (channel);
1302 return GNUNET_SYSERR;
1305 in_msg = (struct GNUNET_RPS_P2P_PullReplyMessage *) msg;
1306 if ((ntohs (msg->size) - sizeof (struct GNUNET_RPS_P2P_PullReplyMessage)) /
1307 sizeof (struct GNUNET_PeerIdentity) != ntohl (in_msg->num_peers))
1309 LOG (GNUNET_ERROR_TYPE_ERROR,
1310 "message says it sends %" PRIu32 " peers, have space for %lu peers\n",
1311 ntohl (in_msg->num_peers),
1312 (ntohs (msg->size) - sizeof (struct GNUNET_RPS_P2P_PullReplyMessage)) /
1313 sizeof (struct GNUNET_PeerIdentity));
1314 GNUNET_break_op (0);
1315 GNUNET_CADET_receive_done (channel);
1316 return GNUNET_SYSERR;
1319 // Guess simply casting isn't the nicest way...
1320 // FIXME wait for cadet to change this function
1321 sender = (struct GNUNET_PeerIdentity *)
1322 GNUNET_CADET_channel_get_info (channel, GNUNET_CADET_OPTION_PEER);
1324 LOG (GNUNET_ERROR_TYPE_DEBUG, "Received PULL REPLY (%s)\n", GNUNET_i2s (sender));
1326 if (GNUNET_YES != Peers_check_peer_flag (sender, Peers_PULL_REPLY_PENDING))
1328 LOG (GNUNET_ERROR_TYPE_WARNING,
1329 "Received a pull reply from a peer we didn't request one from!\n");
1330 GNUNET_break_op (0);
1331 GNUNET_CADET_receive_done (channel);
1336 #ifdef ENABLE_MALICIOUS
1337 // We shouldn't even receive pull replies as we're not sending
1340 #endif /* ENABLE_MALICIOUS */
1342 /* Do actual logic */
1343 peers = (struct GNUNET_PeerIdentity *) &in_msg[1];
1345 LOG (GNUNET_ERROR_TYPE_DEBUG,
1346 "PULL REPLY received, got following %u peers:\n",
1347 ntohl (in_msg->num_peers));
1349 for (i = 0 ; i < ntohl (in_msg->num_peers) ; i++)
1351 LOG (GNUNET_ERROR_TYPE_DEBUG,
1354 GNUNET_i2s (&peers[i]));
1356 #ifdef ENABLE_MALICIOUS
1357 if ((NULL != att_peer_set) &&
1358 (1 == mal_type || 3 == mal_type))
1359 { /* Add attacked peer to local list */
1360 // TODO check if we sent a request and this was the first reply
1361 if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (att_peer_set,
1363 && GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (mal_peer_set,
1365 && 0 != GNUNET_CRYPTO_cmp_peer_identity (&peers[i],
1368 tmp_att_peer = GNUNET_new (struct AttackedPeer);
1369 tmp_att_peer->peer_id = peers[i];
1370 GNUNET_CONTAINER_DLL_insert (att_peers_head,
1373 add_peer_array_to_set (&peers[i], 1, att_peer_set);
1377 #endif /* ENABLE_MALICIOUS */
1378 if (0 != GNUNET_CRYPTO_cmp_peer_identity (&own_identity,
1381 /* Make sure we 'know' about this peer */
1382 (void) Peers_check_peer_live (&peers[i]);
1384 if (GNUNET_YES == Peers_check_peer_valid (&peers[i]))
1386 CustomPeerMap_put (pull_map, &peers[i]);
1390 Peers_schedule_operation (&peers[i], insert_in_pull_map);
1391 Peers_issue_peer_liveliness_check (&peers[i]);
1396 Peers_unset_peer_flag (sender, Peers_PULL_REPLY_PENDING);
1397 clean_peer (sender);
1399 GNUNET_CADET_receive_done (channel);
1405 * Compute a random delay.
1406 * A uniformly distributed value between mean + spread and mean - spread.
1408 * For example for mean 4 min and spread 2 the minimum is (4 min - (1/2 * 4 min))
1409 * It would return a random value between 2 and 6 min.
1411 * @param mean the mean
1412 * @param spread the inverse amount of deviation from the mean
1414 static struct GNUNET_TIME_Relative
1415 compute_rand_delay (struct GNUNET_TIME_Relative mean,
1416 unsigned int spread)
1418 struct GNUNET_TIME_Relative half_interval;
1419 struct GNUNET_TIME_Relative ret;
1420 unsigned int rand_delay;
1421 unsigned int max_rand_delay;
1425 LOG (GNUNET_ERROR_TYPE_WARNING,
1426 "Not accepting spread of 0\n");
1430 /* Compute random time value between spread * mean and spread * mean */
1431 half_interval = GNUNET_TIME_relative_divide (mean, spread);
1433 max_rand_delay = GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us / mean.rel_value_us * (2/spread);
1435 * Compute random value between (0 and 1) * round_interval
1436 * via multiplying round_interval with a 'fraction' (0 to value)/value
1438 rand_delay = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, max_rand_delay);
1439 ret = GNUNET_TIME_relative_multiply (mean, rand_delay);
1440 ret = GNUNET_TIME_relative_divide (ret, max_rand_delay);
1441 ret = GNUNET_TIME_relative_add (ret, half_interval);
1443 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == ret.rel_value_us)
1444 LOG (GNUNET_ERROR_TYPE_WARNING,
1445 "Returning FOREVER_REL\n");
1452 * Send single pull request
1454 * @param peer_id the peer to send the pull request to.
1457 send_pull_request (const struct GNUNET_PeerIdentity *peer)
1459 struct GNUNET_MQ_Envelope *ev;
1461 GNUNET_assert (GNUNET_NO == Peers_check_peer_flag (peer,
1462 Peers_PULL_REPLY_PENDING));
1463 Peers_set_peer_flag (peer, Peers_PULL_REPLY_PENDING);
1465 LOG (GNUNET_ERROR_TYPE_DEBUG,
1466 "Going to send PULL REQUEST to peer %s.\n",
1469 ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_RPS_PP_PULL_REQUEST);
1470 Peers_send_message (peer, ev, "PULL REQUEST");
1477 * @param peer_id the peer to send the push to.
1480 send_push (const struct GNUNET_PeerIdentity *peer_id)
1482 struct GNUNET_MQ_Envelope *ev;
1484 LOG (GNUNET_ERROR_TYPE_DEBUG,
1485 "Going to send PUSH to peer %s.\n",
1486 GNUNET_i2s (peer_id));
1488 ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_RPS_PP_PUSH);
1489 Peers_send_message (peer_id, ev, "PUSH");
1494 do_round (void *cls);
1497 do_mal_round (void *cls);
1500 #ifdef ENABLE_MALICIOUS
1502 * Turn RPS service to act malicious.
1504 * @param cls Closure
1505 * @param client The client that sent the message
1506 * @param msg The message header
1509 handle_client_act_malicious (void *cls,
1510 struct GNUNET_SERVER_Client *client,
1511 const struct GNUNET_MessageHeader *msg)
1513 struct GNUNET_RPS_CS_ActMaliciousMessage *in_msg;
1514 struct GNUNET_PeerIdentity *peers;
1515 uint32_t num_mal_peers_sent;
1516 uint32_t num_mal_peers_old;
1518 /* Check for protocol violation */
1519 if (sizeof (struct GNUNET_RPS_CS_ActMaliciousMessage) > ntohs (msg->size))
1521 GNUNET_break_op (0);
1524 in_msg = (struct GNUNET_RPS_CS_ActMaliciousMessage *) msg;
1525 if ((ntohs (msg->size) - sizeof (struct GNUNET_RPS_CS_ActMaliciousMessage)) /
1526 sizeof (struct GNUNET_PeerIdentity) != ntohl (in_msg->num_peers))
1528 LOG (GNUNET_ERROR_TYPE_ERROR,
1529 "message says it sends %" PRIu32 " peers, have space for %lu peers\n",
1530 ntohl (in_msg->num_peers),
1531 (ntohs (msg->size) - sizeof (struct GNUNET_RPS_CS_ActMaliciousMessage)) /
1532 sizeof (struct GNUNET_PeerIdentity));
1533 GNUNET_break_op (0);
1537 /* Do actual logic */
1538 peers = (struct GNUNET_PeerIdentity *) &msg[1];
1539 mal_type = ntohl (in_msg->type);
1540 if (NULL == mal_peer_set)
1541 mal_peer_set = GNUNET_CONTAINER_multipeermap_create (1, GNUNET_NO);
1543 LOG (GNUNET_ERROR_TYPE_DEBUG,
1544 "Now acting malicious type %" PRIu32 ", got %" PRIu32 " peers.\n",
1546 ntohl (in_msg->num_peers));
1549 { /* Try to maximise representation */
1550 /* Add other malicious peers to those we already know */
1552 num_mal_peers_sent = ntohl (in_msg->num_peers);
1553 num_mal_peers_old = num_mal_peers;
1554 GNUNET_array_grow (mal_peers,
1556 num_mal_peers + num_mal_peers_sent);
1557 memcpy (&mal_peers[num_mal_peers_old],
1559 num_mal_peers_sent * sizeof (struct GNUNET_PeerIdentity));
1561 /* Add all mal peers to mal_peer_set */
1562 add_peer_array_to_set (&mal_peers[num_mal_peers_old],
1566 /* Substitute do_round () with do_mal_round () */
1567 GNUNET_SCHEDULER_cancel (do_round_task);
1568 do_round_task = GNUNET_SCHEDULER_add_now (&do_mal_round, NULL);
1571 else if ( (2 == mal_type) ||
1573 { /* Try to partition the network */
1574 /* Add other malicious peers to those we already know */
1576 num_mal_peers_sent = ntohl (in_msg->num_peers) - 1;
1577 num_mal_peers_old = num_mal_peers;
1578 GNUNET_array_grow (mal_peers,
1580 num_mal_peers + num_mal_peers_sent);
1581 if (NULL != mal_peers &&
1584 memcpy (&mal_peers[num_mal_peers_old],
1586 num_mal_peers_sent * sizeof (struct GNUNET_PeerIdentity));
1588 /* Add all mal peers to mal_peer_set */
1589 add_peer_array_to_set (&mal_peers[num_mal_peers_old],
1594 /* Store the one attacked peer */
1595 memcpy (&attacked_peer,
1596 &in_msg->attacked_peer,
1597 sizeof (struct GNUNET_PeerIdentity));
1598 /* Set the flag of the attacked peer to valid to avoid problems */
1599 if (GNUNET_NO == Peers_check_peer_known (&attacked_peer))
1601 Peers_check_peer_live (&attacked_peer);
1602 Peers_issue_peer_liveliness_check (&attacked_peer);
1605 LOG (GNUNET_ERROR_TYPE_DEBUG,
1606 "Attacked peer is %s\n",
1607 GNUNET_i2s (&attacked_peer));
1609 /* Substitute do_round () with do_mal_round () */
1610 GNUNET_SCHEDULER_cancel (do_round_task);
1611 do_round_task = GNUNET_SCHEDULER_add_now (&do_mal_round, NULL);
1613 else if (0 == mal_type)
1614 { /* Stop acting malicious */
1615 GNUNET_array_grow (mal_peers, num_mal_peers, 0);
1617 /* Substitute do_mal_round () with do_round () */
1618 GNUNET_SCHEDULER_cancel (do_round_task);
1619 do_round_task = GNUNET_SCHEDULER_add_now (&do_round, NULL);
1625 GNUNET_SERVER_receive_done (client,
1631 * Send out PUSHes and PULLs maliciously.
1633 * This is executed regylary.
1636 do_mal_round (void *cls)
1638 uint32_t num_pushes;
1640 struct GNUNET_TIME_Relative time_next_round;
1641 struct AttackedPeer *tmp_att_peer;
1643 LOG (GNUNET_ERROR_TYPE_DEBUG,
1644 "Going to execute next round maliciously type %" PRIu32 ".\n",
1646 do_round_task = NULL;
1647 GNUNET_assert (mal_type <= 3);
1648 /* Do malicious actions */
1650 { /* Try to maximise representation */
1652 /* The maximum of pushes we're going to send this round */
1653 num_pushes = GNUNET_MIN (GNUNET_MIN (push_limit,
1654 num_attacked_peers),
1655 GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE);
1657 LOG (GNUNET_ERROR_TYPE_DEBUG,
1658 "Going to send %" PRIu32 " pushes\n",
1661 /* Send PUSHes to attacked peers */
1662 for (i = 0 ; i < num_pushes ; i++)
1664 if (att_peers_tail == att_peer_index)
1665 att_peer_index = att_peers_head;
1667 att_peer_index = att_peer_index->next;
1669 send_push (&att_peer_index->peer_id);
1672 /* Send PULLs to some peers to learn about additional peers to attack */
1673 tmp_att_peer = att_peer_index;
1674 for (i = 0 ; i < num_pushes * alpha ; i++)
1676 if (att_peers_tail == tmp_att_peer)
1677 tmp_att_peer = att_peers_head;
1679 att_peer_index = tmp_att_peer->next;
1681 send_pull_request (&tmp_att_peer->peer_id);
1686 else if (2 == mal_type)
1688 * Try to partition the network
1689 * Send as many pushes to the attacked peer as possible
1690 * That is one push per round as it will ignore more.
1692 Peers_check_peer_live (&attacked_peer);
1693 if (GNUNET_YES == Peers_check_peer_valid (&attacked_peer))
1694 send_push (&attacked_peer);
1699 { /* Combined attack */
1701 /* Send PUSH to attacked peers */
1702 if (GNUNET_YES == Peers_check_peer_known (&attacked_peer))
1704 Peers_check_peer_live (&attacked_peer);
1705 if (GNUNET_YES == Peers_check_peer_valid (&attacked_peer))
1707 LOG (GNUNET_ERROR_TYPE_DEBUG,
1708 "Goding to send push to attacked peer (%s)\n",
1709 GNUNET_i2s (&attacked_peer));
1710 send_push (&attacked_peer);
1713 Peers_issue_peer_liveliness_check (&attacked_peer);
1716 Peers_check_peer_live (&attacked_peer);
1717 Peers_issue_peer_liveliness_check (&attacked_peer);
1719 /* The maximum of pushes we're going to send this round */
1720 num_pushes = GNUNET_MIN (GNUNET_MIN (push_limit - 1,
1721 num_attacked_peers),
1722 GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE);
1724 LOG (GNUNET_ERROR_TYPE_DEBUG,
1725 "Going to send %" PRIu32 " pushes\n",
1728 for (i = 0; i < num_pushes; i++)
1730 if (att_peers_tail == att_peer_index)
1731 att_peer_index = att_peers_head;
1733 att_peer_index = att_peer_index->next;
1735 send_push (&att_peer_index->peer_id);
1738 /* Send PULLs to some peers to learn about additional peers to attack */
1739 tmp_att_peer = att_peer_index;
1740 for (i = 0; i < num_pushes * alpha; i++)
1742 if (att_peers_tail == tmp_att_peer)
1743 tmp_att_peer = att_peers_head;
1745 att_peer_index = tmp_att_peer->next;
1747 send_pull_request (&tmp_att_peer->peer_id);
1751 /* Schedule next round */
1752 time_next_round = compute_rand_delay (round_interval, 2);
1754 //do_round_task = GNUNET_SCHEDULER_add_delayed (round_interval, &do_mal_round,
1756 GNUNET_assert (NULL == do_round_task);
1757 do_round_task = GNUNET_SCHEDULER_add_delayed (time_next_round,
1758 &do_mal_round, NULL);
1759 LOG (GNUNET_ERROR_TYPE_DEBUG, "Finished round\n");
1761 #endif /* ENABLE_MALICIOUS */
1765 * Send out PUSHes and PULLs, possibly update #view, samplers.
1767 * This is executed regylary.
1770 do_round (void *cls)
1773 const struct GNUNET_PeerIdentity *view_array;
1774 unsigned int *permut;
1775 unsigned int a_peers; /* Number of peers we send pushes to */
1776 unsigned int b_peers; /* Number of peers we send pull requests to */
1777 uint32_t first_border;
1778 uint32_t second_border;
1779 struct GNUNET_PeerIdentity peer;
1780 struct GNUNET_PeerIdentity *update_peer;
1782 LOG (GNUNET_ERROR_TYPE_DEBUG,
1783 "Going to execute next round.\n");
1784 do_round_task = NULL;
1785 LOG (GNUNET_ERROR_TYPE_DEBUG,
1786 "Printing view:\n");
1787 to_file (file_name_view_log,
1788 "___ new round ___");
1789 view_array = View_get_as_array ();
1790 for (i = 0; i < View_size (); i++)
1792 LOG (GNUNET_ERROR_TYPE_DEBUG,
1793 "\t%s\n", GNUNET_i2s (&view_array[i]));
1794 to_file (file_name_view_log,
1796 GNUNET_i2s_full (&view_array[i]));
1800 /* Send pushes and pull requests */
1801 if (0 < View_size ())
1803 permut = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_STRONG,
1807 a_peers = ceil (alpha * View_size ());
1809 LOG (GNUNET_ERROR_TYPE_DEBUG,
1810 "Going to send pushes to %u (ceil (%f * %u)) peers.\n",
1811 a_peers, alpha, View_size ());
1812 for (i = 0; i < a_peers; i++)
1814 peer = view_array[permut[i]];
1815 if (0 != GNUNET_CRYPTO_cmp_peer_identity (&own_identity, &peer)) // TODO
1816 { // FIXME if this fails schedule/loop this for later
1821 /* Send PULL requests */
1822 b_peers = ceil (beta * View_size ());
1823 first_border = a_peers;
1824 second_border = a_peers + b_peers;
1825 if (second_border > View_size ())
1827 first_border = View_size () - b_peers;
1828 second_border = View_size ();
1830 LOG (GNUNET_ERROR_TYPE_DEBUG,
1831 "Going to send pulls to %u (ceil (%f * %u)) peers.\n",
1832 b_peers, beta, View_size ());
1833 for (i = first_border; i < second_border; i++)
1835 peer = view_array[permut[i]];
1836 if (0 != GNUNET_CRYPTO_cmp_peer_identity (&own_identity, &peer) &&
1837 GNUNET_NO == Peers_check_peer_flag (&peer, Peers_PULL_REPLY_PENDING)) // TODO
1838 { // FIXME if this fails schedule/loop this for later
1839 send_pull_request (&peer);
1843 GNUNET_free (permut);
1849 /* TODO see how many peers are in push-/pull- list! */
1851 if ((CustomPeerMap_size (push_map) <= alpha * View_size ()) &&
1852 (0 < CustomPeerMap_size (push_map)) &&
1853 (0 < CustomPeerMap_size (pull_map)))
1854 { /* If conditions for update are fulfilled, update */
1855 LOG (GNUNET_ERROR_TYPE_DEBUG, "Update of the view.\n");
1857 uint32_t final_size;
1858 uint32_t peers_to_clean_size;
1859 struct GNUNET_PeerIdentity *peers_to_clean;
1861 peers_to_clean = NULL;
1862 peers_to_clean_size = 0;
1863 GNUNET_array_grow (peers_to_clean, peers_to_clean_size, View_size ());
1864 memcpy (peers_to_clean,
1866 View_size () * sizeof (struct GNUNET_PeerIdentity));
1868 /* Seems like recreating is the easiest way of emptying the peermap */
1870 to_file (file_name_view_log,
1873 first_border = GNUNET_MIN (ceil (alpha * sampler_size_est_need),
1874 CustomPeerMap_size (push_map));
1875 second_border = first_border +
1876 GNUNET_MIN (floor (beta * sampler_size_est_need),
1877 CustomPeerMap_size (pull_map));
1878 final_size = second_border +
1879 ceil ((1 - (alpha + beta)) * sampler_size_est_need);
1881 /* Update view with peers received through PUSHes */
1882 permut = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_STRONG,
1883 CustomPeerMap_size (push_map));
1884 for (i = 0; i < first_border; i++)
1886 View_put (CustomPeerMap_get_peer_by_index (push_map, permut[i]));
1887 to_file (file_name_view_log,
1889 GNUNET_i2s_full (&view_array[i]));
1890 // TODO change the peer_flags accordingly
1892 GNUNET_free (permut);
1895 /* Update view with peers received through PULLs */
1896 permut = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_STRONG,
1897 CustomPeerMap_size (pull_map));
1898 for (i = first_border; i < second_border; i++)
1900 View_put (CustomPeerMap_get_peer_by_index (pull_map,
1901 permut[i - first_border]));
1902 to_file (file_name_view_log,
1904 GNUNET_i2s_full (&view_array[i]));
1905 // TODO change the peer_flags accordingly
1907 GNUNET_free (permut);
1910 /* Update view with peers from history */
1911 RPS_sampler_get_n_rand_peers (prot_sampler,
1914 final_size - second_border);
1915 // TODO change the peer_flags accordingly
1917 for (i = 0; i < View_size (); i++)
1918 rem_from_list (&peers_to_clean, &peers_to_clean_size, &view_array[i]);
1920 /* Clean peers that were removed from the view */
1921 for (i = 0; i < peers_to_clean_size; i++)
1923 to_file (file_name_view_log,
1925 GNUNET_i2s_full (&peers_to_clean[i]));
1926 Peers_clean_peer (&peers_to_clean[i]);
1927 //peer_destroy_channel_send (sender);
1930 GNUNET_array_grow (peers_to_clean, peers_to_clean_size, 0);
1931 peers_to_clean = NULL;
1935 LOG (GNUNET_ERROR_TYPE_DEBUG, "No update of the view.\n");
1937 // TODO independent of that also get some peers from CADET_get_peers()?
1939 LOG (GNUNET_ERROR_TYPE_DEBUG,
1940 "Received %u pushes and %u pulls last round (alpha (%.2f) * view_size (%u) = %.2f)\n",
1941 CustomPeerMap_size (push_map),
1942 CustomPeerMap_size (pull_map),
1945 alpha * View_size ());
1947 /* Update samplers */
1948 for (i = 0; i < CustomPeerMap_size (push_map); i++)
1950 update_peer = CustomPeerMap_get_peer_by_index (push_map, i);
1951 LOG (GNUNET_ERROR_TYPE_DEBUG,
1952 "Updating with peer %s from push list\n",
1953 GNUNET_i2s (update_peer));
1954 insert_in_sampler (NULL, update_peer);
1955 Peers_clean_peer (update_peer); /* This cleans only if it is not in the view */
1956 //peer_destroy_channel_send (sender);
1959 for (i = 0; i < CustomPeerMap_size (pull_map); i++)
1961 LOG (GNUNET_ERROR_TYPE_DEBUG,
1962 "Updating with peer %s from pull list\n",
1963 GNUNET_i2s (CustomPeerMap_get_peer_by_index (pull_map, i)));
1964 insert_in_sampler (NULL, CustomPeerMap_get_peer_by_index (pull_map, i));
1965 /* This cleans only if it is not in the view */
1966 Peers_clean_peer (CustomPeerMap_get_peer_by_index (pull_map, i));
1967 //peer_destroy_channel_send (sender);
1971 /* Empty push/pull lists */
1972 CustomPeerMap_clear (push_map);
1973 CustomPeerMap_clear (pull_map);
1975 struct GNUNET_TIME_Relative time_next_round;
1977 time_next_round = compute_rand_delay (round_interval, 2);
1979 /* Schedule next round */
1980 do_round_task = GNUNET_SCHEDULER_add_delayed (time_next_round,
1982 LOG (GNUNET_ERROR_TYPE_DEBUG, "Finished round\n");
1987 rps_start (struct GNUNET_SERVER_Handle *server);
1991 * This is called from GNUNET_CADET_get_peers().
1993 * It is called on every peer(ID) that cadet somehow has contact with.
1994 * We use those to initialise the sampler.
1997 init_peer_cb (void *cls,
1998 const struct GNUNET_PeerIdentity *peer,
1999 int tunnel, // "Do we have a tunnel towards this peer?"
2000 unsigned int n_paths, // "Number of known paths towards this peer"
2001 unsigned int best_path) // "How long is the best path?
2002 // (0 = unknown, 1 = ourselves, 2 = neighbor)"
2006 LOG (GNUNET_ERROR_TYPE_DEBUG,
2007 "Got peer_id %s from cadet\n",
2014 * @brief Iterator function over stored, valid peers.
2016 * We initialise the sampler with those.
2018 * @param cls the closure
2019 * @param peer the peer id
2020 * @return #GNUNET_YES if we should continue to
2022 * #GNUNET_NO if not.
2025 valid_peers_iterator (void *cls,
2026 const struct GNUNET_PeerIdentity *peer)
2030 LOG (GNUNET_ERROR_TYPE_DEBUG,
2031 "Got stored, valid peer %s\n",
2040 * Iterator over peers from peerinfo.
2042 * @param cls closure
2043 * @param peer id of the peer, NULL for last call
2044 * @param hello hello message for the peer (can be NULL)
2045 * @param error message
2048 process_peerinfo_peers (void *cls,
2049 const struct GNUNET_PeerIdentity *peer,
2050 const struct GNUNET_HELLO_Message *hello,
2051 const char *err_msg)
2055 LOG (GNUNET_ERROR_TYPE_DEBUG,
2056 "Got peer_id %s from peerinfo\n",
2064 * Task run during shutdown.
2069 shutdown_task (void *cls)
2071 LOG (GNUNET_ERROR_TYPE_DEBUG,
2072 "RPS is going down\n");
2073 GNUNET_PEERINFO_notify_cancel (peerinfo_notify_handle);
2074 GNUNET_PEERINFO_disconnect (peerinfo_handle);
2076 if (NULL != do_round_task)
2078 GNUNET_SCHEDULER_cancel (do_round_task);
2079 do_round_task = NULL;
2084 GNUNET_NSE_disconnect (nse);
2085 RPS_sampler_destroy (prot_sampler);
2086 RPS_sampler_destroy (client_sampler);
2087 GNUNET_CADET_disconnect (cadet_handle);
2089 CustomPeerMap_destroy (push_map);
2090 CustomPeerMap_destroy (pull_map);
2091 #ifdef ENABLE_MALICIOUS
2092 struct AttackedPeer *tmp_att_peer;
2093 GNUNET_free (file_name_view_log);
2094 GNUNET_array_grow (mal_peers, num_mal_peers, 0);
2095 if (NULL != mal_peer_set)
2096 GNUNET_CONTAINER_multipeermap_destroy (mal_peer_set);
2097 if (NULL != att_peer_set)
2098 GNUNET_CONTAINER_multipeermap_destroy (att_peer_set);
2099 while (NULL != att_peers_head)
2101 tmp_att_peer = att_peers_head;
2102 GNUNET_CONTAINER_DLL_remove (att_peers_head, att_peers_tail, tmp_att_peer);
2104 #endif /* ENABLE_MALICIOUS */
2109 * @brief Get informed about a connecting client.
2112 * @param client the client that connects
2115 handle_client_connect (void *cls,
2116 struct GNUNET_SERVER_Client *client)
2118 struct ClientContext *cli_ctx;
2120 LOG (GNUNET_ERROR_TYPE_DEBUG,
2121 "Client connected\n");
2123 return; /* Server was destroyed before a client connected. Shutting down */
2124 cli_ctx = GNUNET_new (struct ClientContext);
2125 cli_ctx->mq = GNUNET_MQ_queue_for_server_client (client);
2126 GNUNET_SERVER_client_set_user_context (client, cli_ctx);
2127 GNUNET_CONTAINER_DLL_insert (cli_ctx_head,
2133 * A client disconnected. Remove all of its data structure entries.
2135 * @param cls closure, NULL
2136 * @param client identification of the client
2139 handle_client_disconnect (void *cls,
2140 struct GNUNET_SERVER_Client *client)
2142 struct ClientContext *cli_ctx;
2145 {/* shutdown task */
2146 while (NULL != cli_ctx_head)
2147 destroy_cli_ctx (cli_ctx_head);
2151 cli_ctx = GNUNET_SERVER_client_get_user_context (client, struct ClientContext);
2152 destroy_cli_ctx (cli_ctx);
2158 * Actually start the service.
2161 rps_start (struct GNUNET_SERVER_Handle *server)
2163 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
2164 {&handle_client_request, NULL, GNUNET_MESSAGE_TYPE_RPS_CS_REQUEST,
2165 sizeof (struct GNUNET_RPS_CS_RequestMessage)},
2166 {&handle_client_request_cancel, NULL, GNUNET_MESSAGE_TYPE_RPS_CS_REQUEST_CANCEL,
2167 sizeof (struct GNUNET_RPS_CS_RequestCancelMessage)},
2168 {&handle_client_seed, NULL, GNUNET_MESSAGE_TYPE_RPS_CS_SEED, 0},
2169 #ifdef ENABLE_MALICIOUS
2170 {&handle_client_act_malicious, NULL, GNUNET_MESSAGE_TYPE_RPS_ACT_MALICIOUS , 0},
2171 #endif /* ENABLE_MALICIOUS */
2175 GNUNET_SERVER_add_handlers (server, handlers);
2176 GNUNET_SERVER_connect_notify (server,
2177 &handle_client_connect,
2179 GNUNET_SERVER_disconnect_notify (server,
2180 &handle_client_disconnect,
2182 LOG (GNUNET_ERROR_TYPE_INFO, "Ready to receive requests from clients\n");
2185 do_round_task = GNUNET_SCHEDULER_add_now (&do_round, NULL);
2186 LOG (GNUNET_ERROR_TYPE_DEBUG, "Scheduled first round\n");
2188 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
2194 * Process statistics requests.
2196 * @param cls closure
2197 * @param server the initialized server
2198 * @param c configuration to use
2202 struct GNUNET_SERVER_Handle *server,
2203 const struct GNUNET_CONFIGURATION_Handle *c)
2207 char* fn_valid_peers;
2209 GNUNET_log_setup ("rps", GNUNET_error_type_to_string (GNUNET_ERROR_TYPE_DEBUG), NULL);
2214 GNUNET_CRYPTO_get_peer_identity (cfg, &own_identity); // TODO check return value
2215 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2216 "STARTING SERVICE (rps) for peer [%s]\n",
2217 GNUNET_i2s (&own_identity));
2218 #ifdef ENABLE_MALICIOUS
2219 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2220 "Malicious execution compiled in.\n");
2221 #endif /* ENABLE_MALICIOUS */
2225 /* Get time interval from the configuration */
2226 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, "RPS",
2230 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
2231 "RPS", "ROUNDINTERVAL");
2232 GNUNET_SCHEDULER_shutdown ();
2236 /* Get initial size of sampler/view from the configuration */
2238 GNUNET_CONFIGURATION_get_value_number (cfg, "RPS", "INITSIZE",
2239 (long long unsigned int *) &sampler_size_est_need))
2241 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
2243 GNUNET_SCHEDULER_shutdown ();
2246 LOG (GNUNET_ERROR_TYPE_DEBUG, "INITSIZE is %u\n", sampler_size_est_need);
2249 GNUNET_CONFIGURATION_get_value_filename (cfg,
2251 "FILENAME_VALID_PEERS",
2254 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
2255 "rps", "FILENAME_VALID_PEERS");
2261 /* file_name_view_log */
2262 if (GNUNET_OK != GNUNET_DISK_directory_create ("/tmp/rps/"))
2264 LOG (GNUNET_ERROR_TYPE_WARNING,
2265 "Failed to create directory /tmp/rps/\n");
2268 size = (14 + strlen (GNUNET_i2s_full (&own_identity)) + 1) * sizeof (char);
2269 file_name_view_log = GNUNET_malloc (size);
2270 out_size = GNUNET_snprintf (file_name_view_log,
2273 GNUNET_i2s_full (&own_identity));
2274 if (size < out_size ||
2277 LOG (GNUNET_ERROR_TYPE_WARNING,
2278 "Failed to write string to buffer (size: %i, out_size: %i)\n",
2284 /* connect to NSE */
2285 nse = GNUNET_NSE_connect (cfg, nse_callback, NULL);
2292 /* Initialise cadet */
2293 static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
2294 {&handle_peer_push , GNUNET_MESSAGE_TYPE_RPS_PP_PUSH ,
2295 sizeof (struct GNUNET_MessageHeader)},
2296 {&handle_peer_pull_request, GNUNET_MESSAGE_TYPE_RPS_PP_PULL_REQUEST,
2297 sizeof (struct GNUNET_MessageHeader)},
2298 {&handle_peer_pull_reply , GNUNET_MESSAGE_TYPE_RPS_PP_PULL_REPLY , 0},
2301 const uint32_t ports[] = {GNUNET_RPS_CADET_PORT, 0}; // _PORT specified in src/rps/rps.h
2302 cadet_handle = GNUNET_CADET_connect (cfg,
2304 &Peers_handle_inbound_channel,
2305 &cleanup_destroyed_channel,
2309 peerinfo_handle = GNUNET_PEERINFO_connect (cfg);
2310 Peers_initialise (fn_valid_peers, cadet_handle, &own_identity);
2311 GNUNET_free (fn_valid_peers);
2313 /* Initialise sampler */
2314 struct GNUNET_TIME_Relative half_round_interval;
2315 struct GNUNET_TIME_Relative max_round_interval;
2317 half_round_interval = GNUNET_TIME_relative_multiply (round_interval, .5);
2318 max_round_interval = GNUNET_TIME_relative_add (round_interval, half_round_interval);
2320 prot_sampler = RPS_sampler_init (sampler_size_est_need, max_round_interval);
2321 client_sampler = RPS_sampler_mod_init (sampler_size_est_need, max_round_interval);
2323 /* Initialise push and pull maps */
2324 push_map = CustomPeerMap_create (4);
2325 pull_map = CustomPeerMap_create (4);
2328 LOG (GNUNET_ERROR_TYPE_DEBUG, "Requesting peers from CADET\n");
2329 GNUNET_CADET_get_peers (cadet_handle, &init_peer_cb, NULL);
2330 // TODO send push/pull to each of those peers?
2331 // TODO read stored valid peers from last run
2332 LOG (GNUNET_ERROR_TYPE_DEBUG, "Requesting stored valid peers\n");
2333 Peers_get_valid_peers (valid_peers_iterator, NULL);
2335 peerinfo_notify_handle = GNUNET_PEERINFO_notify (cfg,
2337 process_peerinfo_peers,
2345 * The main function for the rps service.
2347 * @param argc number of arguments from the command line
2348 * @param argv command line arguments
2349 * @return 0 ok, 1 on error
2352 main (int argc, char *const *argv)
2354 return (GNUNET_OK ==
2355 GNUNET_SERVICE_run (argc,
2358 GNUNET_SERVICE_OPTION_NONE,
2359 &run, NULL)) ? 0 : 1;
2362 /* end of gnunet-service-rps.c */