tolerate additional IPv4 address now available for gnunet.org
[oweals/gnunet.git] / src / rps / gnunet-service-rps.c
index dec92190319fd649d0eedd8aa907e052ffa0df24..c5530a1eb8b02e6ac399845222ccc46b481d6baf 100644 (file)
      WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      Affero General Public License for more details.
-    
+
      You should have received a copy of the GNU Affero General Public License
      along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+     SPDX-License-Identifier: AGPL3.0-or-later
 */
 
 /**
@@ -259,7 +261,7 @@ struct ChannelCtx
 };
 
 
-#ifdef ENABLE_MALICIOUS
+#if ENABLE_MALICIOUS
 
 /**
  * If type is 2 This struct is used to store the attacked peers in a DLL
@@ -280,6 +282,20 @@ struct AttackedPeer
 
 #endif /* ENABLE_MALICIOUS */
 
+/**
+ * @brief This number determines the number of slots for files that represent
+ * histograms
+ */
+#define HISTOGRAM_FILE_SLOTS 32
+
+/**
+ * @brief The size (in bytes) a file needs to store the histogram
+ *
+ * Per slot: 1 newline, up to 4 chars,
+ * Additionally: 1 null termination
+ */
+#define SIZE_DUMP_FILE (HISTOGRAM_FILE_SLOTS * 5) + 1
+
 /**
  * @brief One Sub.
  *
@@ -329,7 +345,7 @@ struct Sub
   unsigned int sampler_size_est_need;
 
   /**
-   * Time inverval the do_round task runs in.
+   * Time interval the do_round task runs in.
    */
   struct GNUNET_TIME_Relative round_interval;
 
@@ -338,32 +354,26 @@ struct Sub
    */
   struct RPS_Sampler *sampler;
 
+#ifdef TO_FILE_FULL
   /**
    * Name to log view to
    */
   char *file_name_view_log;
+#endif /* TO_FILE_FULL */
 
 #ifdef TO_FILE
+#ifdef TO_FILE_FULL
   /**
    * Name to log number of observed peers to
    */
   char *file_name_observed_log;
+#endif /* TO_FILE_FULL */
 
   /**
    * @brief Count the observed peers
    */
   uint32_t num_observed_peers;
 
-  /**
-   * @brief File name to log number of pushes per round to
-   */
-  char *file_name_push_recv;
-
-  /**
-   * @brief File name to log number of pushes per round to
-   */
-  char *file_name_pull_delays;
-
   /**
    * @brief Multipeermap (ab-) used to count unique peer_ids
    */
@@ -416,7 +426,16 @@ struct Sub
    *
    * Number at index i represents the number of rounds with i observed pushes.
    */
-  uint32_t push_recv[256];
+  uint32_t push_recv[HISTOGRAM_FILE_SLOTS];
+
+  /**
+   * @brief Histogram of deltas between the expected and actual number of
+   * received pushes.
+   *
+   * As half of the entries are expected to be negative, this is shifted by
+   * #HISTOGRAM_FILE_SLOTS/2.
+   */
+  uint32_t push_delta[HISTOGRAM_FILE_SLOTS];
 
   /**
    * @brief Number of pull replies with this delay measured in rounds.
@@ -424,7 +443,7 @@ struct Sub
    * Number at index i represents the number of pull replies with a delay of i
    * rounds.
    */
-  uint32_t pull_delays[256];
+  uint32_t pull_delays[HISTOGRAM_FILE_SLOTS];
 };
 
 
@@ -490,7 +509,7 @@ static struct GNUNET_PEERINFO_Handle *peerinfo_handle;
 static struct GNUNET_PEERINFO_NotifyContext *peerinfo_notify_handle;
 
 
-#ifdef ENABLE_MALICIOUS
+#if ENABLE_MALICIOUS
 /**
  * Type of malicious peer
  *
@@ -779,8 +798,7 @@ get_rand_peer_iterator (void *cls,
  * @return a random peer
  */
 static const struct GNUNET_PeerIdentity *
-get_random_peer_from_peermap (const struct
-                              GNUNET_CONTAINER_MultiPeerMap *valid_peers)
+get_random_peer_from_peermap (struct GNUNET_CONTAINER_MultiPeerMap *valid_peers)
 {
   struct GetRandPeerIteratorCls *iterator_cls;
   const struct GNUNET_PeerIdentity *ret;
@@ -1378,6 +1396,7 @@ mq_notify_sent_cb (void *cls)
     if (0 == strncmp ("PUSH", pending_msg->type, 4))
       GNUNET_STATISTICS_update(stats, "# pushes sent", 1, GNUNET_NO);
     if (0 == strncmp ("PULL REQUEST", pending_msg->type, 12) &&
+                      NULL != map_single_hop &&
         GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (map_single_hop,
           &pending_msg->peer_ctx->peer_id))
       GNUNET_STATISTICS_update(stats,
@@ -1660,7 +1679,7 @@ valid_peer_iterator (void *cls,
  *         #GNUNET_SYSERR if it aborted iteration
  */
 static int
-get_valid_peers (const struct GNUNET_CONTAINER_MultiPeerMap *valid_peers,
+get_valid_peers (struct GNUNET_CONTAINER_MultiPeerMap *valid_peers,
                  PeersIterator iterator,
                  void *it_cls)
 {
@@ -1781,7 +1800,7 @@ check_removable (const struct PeerContext *peer_ctx)
 
   if ( (NULL != peer_ctx->recv_channel_ctx) ||
        (NULL != peer_ctx->pending_messages_head) ||
-       (GNUNET_NO == check_peer_flag_set (peer_ctx, Peers_PULL_REPLY_PENDING)) )
+       (GNUNET_YES == check_peer_flag_set (peer_ctx, Peers_PULL_REPLY_PENDING)) )
   {
     return GNUNET_NO;
   }
@@ -2142,7 +2161,7 @@ rem_from_list (struct GNUNET_PeerIdentity **peer_list,
 
   for ( i = 0 ; i < *list_size ; i++ )
   {
-    if (0 == GNUNET_CRYPTO_cmp_peer_identity (&tmp[i], peer))
+    if (0 == GNUNET_memcmp (&tmp[i], peer))
     {
       if (i < *list_size -1)
       { /* Not at the last entry -- shift peers left */
@@ -2374,14 +2393,22 @@ hist_update (const struct GNUNET_PeerIdentity *ids,
   for (i = 0; i < num_peers; i++)
   {
     int inserted;
+    if (GNUNET_YES != check_peer_known (sub->peer_map, &ids[i]))
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING,
+           "Peer in history update not known!\n");
+      continue;
+    }
     inserted = insert_in_view (sub, &ids[i]);
     if (GNUNET_OK == inserted)
     {
       clients_notify_stream_peer (sub, 1, &ids[i]);
     }
+#ifdef TO_FILE_FULL
     to_file (sub->file_name_view_log,
              "+%s\t(hist)",
              GNUNET_i2s_full (ids));
+#endif /* TO_FILE_FULL */
   }
   clients_notify_view_update (sub);
 }
@@ -2575,7 +2602,14 @@ insert_in_sampler (void *cls,
      * messages to it */
     //indicate_sending_intention (peer);
   }
-  #ifdef TO_FILE
+  if (sub == msub)
+  {
+    GNUNET_STATISTICS_update (stats,
+                              "# observed peers in gossip",
+                              1,
+                              GNUNET_NO);
+  }
+#ifdef TO_FILE
   sub->num_observed_peers++;
   GNUNET_CONTAINER_multipeermap_put
     (sub->observed_unique_peers,
@@ -2584,12 +2618,18 @@ insert_in_sampler (void *cls,
      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
   uint32_t num_observed_unique_peers =
     GNUNET_CONTAINER_multipeermap_size (sub->observed_unique_peers);
+  GNUNET_STATISTICS_set (stats,
+                         "# unique peers in gossip",
+                         num_observed_unique_peers,
+                         GNUNET_NO);
+#ifdef TO_FILE_FULL
   to_file (sub->file_name_observed_log,
           "%" PRIu32 " %" PRIu32 " %f\n",
           sub->num_observed_peers,
           num_observed_unique_peers,
           1.0*num_observed_unique_peers/sub->num_observed_peers)
-  #endif /* TO_FILE */
+#endif /* TO_FILE_FULL */
+#endif /* TO_FILE */
 }
 
 
@@ -2674,11 +2714,23 @@ static void
 remove_peer (struct Sub *sub,
              const struct GNUNET_PeerIdentity *peer)
 {
-  (void) View_remove_peer (sub->view, peer);
-  CustomPeerMap_remove_peer (sub->pull_map, peer);
-  CustomPeerMap_remove_peer (sub->push_map, peer);
-  RPS_sampler_reinitialise_by_value (sub->sampler, peer);
-  destroy_peer (get_peer_ctx (sub->peer_map, peer));
+  (void) View_remove_peer (sub->view,
+                           peer);
+  CustomPeerMap_remove_peer (sub->pull_map,
+                             peer);
+  CustomPeerMap_remove_peer (sub->push_map,
+                             peer);
+  RPS_sampler_reinitialise_by_value (sub->sampler,
+                                     peer);
+  /* We want to destroy the peer now.
+   * Sometimes, it just seems that it's already been removed from the peer_map,
+   * so check the peer_map first. */
+  if (GNUNET_YES == check_peer_known (sub->peer_map,
+                                      peer))
+  {
+    destroy_peer (get_peer_ctx (sub->peer_map,
+                                peer));
+  }
 }
 
 
@@ -2700,15 +2752,19 @@ clean_peer (struct Sub *sub,
     LOG (GNUNET_ERROR_TYPE_DEBUG,
         "Going to remove send channel to peer %s\n",
         GNUNET_i2s (peer));
-    #ifdef ENABLE_MALICIOUS
-    if (0 != GNUNET_CRYPTO_cmp_peer_identity (&attacked_peer, peer))
-      (void) destroy_sending_channel (get_peer_ctx (sub->peer_map, peer));
+    #if ENABLE_MALICIOUS
+    if (0 != GNUNET_memcmp (&attacked_peer,
+                                              peer))
+      (void) destroy_sending_channel (get_peer_ctx (sub->peer_map,
+                                                    peer));
     #else /* ENABLE_MALICIOUS */
-    (void) destroy_sending_channel (get_peer_ctx (sub->peer_map, peer));
+    (void) destroy_sending_channel (get_peer_ctx (sub->peer_map,
+                                                  peer));
     #endif /* ENABLE_MALICIOUS */
   }
 
-  if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (sub->peer_map, peer))
+  if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (sub->peer_map,
+                                                           peer))
   {
     /* Peer was already removed by callback on destroyed channel */
     LOG (GNUNET_ERROR_TYPE_WARNING,
@@ -2721,8 +2777,8 @@ clean_peer (struct Sub *sub,
        (GNUNET_NO == View_contains_peer (sub->view, peer)) &&
        (GNUNET_NO == CustomPeerMap_contains_peer (sub->push_map, peer)) &&
        (GNUNET_NO == CustomPeerMap_contains_peer (sub->push_map, peer)) &&
-       (0 == RPS_sampler_count_id (sub->sampler,   peer)) &&
-       (GNUNET_NO != check_removable (get_peer_ctx (sub->peer_map, peer))) )
+       (0 == RPS_sampler_count_id (sub->sampler, peer)) &&
+       (GNUNET_YES == check_removable (get_peer_ctx (sub->peer_map, peer))) )
   { /* We can safely remove this peer */
     LOG (GNUNET_ERROR_TYPE_DEBUG,
         "Going to remove peer %s\n",
@@ -2845,19 +2901,15 @@ new_sub (const struct GNUNET_HashCode *hash,
   {
     char *tmp_filename_valid_peers;
     char str_hash[105];
-    uint32_t len_filename_valid_peers;
-
-    (void) GNUNET_snprintf (str_hash, 105, GNUNET_h2s_full (hash));
-    tmp_filename_valid_peers = GNUNET_strdup (sub->filename_valid_peers);
-    GNUNET_free (sub->filename_valid_peers);
-    len_filename_valid_peers = strlen (tmp_filename_valid_peers) + 105; /* Len of full hash + 1 */
-    sub->filename_valid_peers = GNUNET_malloc (len_filename_valid_peers);
-    strncat (sub->filename_valid_peers,
-             tmp_filename_valid_peers,
-             len_filename_valid_peers);
-    strncat (sub->filename_valid_peers,
-             str_hash,
-             len_filename_valid_peers);
+
+    GNUNET_snprintf (str_hash,
+                    sizeof (str_hash),
+                    GNUNET_h2s_full (hash));
+    tmp_filename_valid_peers = sub->filename_valid_peers;
+    GNUNET_asprintf (&sub->filename_valid_peers,
+                    "%s%s",
+                    tmp_filename_valid_peers,
+                    str_hash);
     GNUNET_free (tmp_filename_valid_peers);
   }
   sub->peer_map = GNUNET_CONTAINER_multipeermap_create (4, GNUNET_NO);
@@ -2872,18 +2924,18 @@ new_sub (const struct GNUNET_HashCode *hash,
                                   round_interval);
 
   /* Logging of internals */
+#ifdef TO_FILE_FULL
   sub->file_name_view_log = store_prefix_file_name (&own_identity, "view");
-  #ifdef TO_FILE
+#endif /* TO_FILE_FULL */
+#ifdef TO_FILE
+#ifdef TO_FILE_FULL
   sub->file_name_observed_log = store_prefix_file_name (&own_identity,
                                                        "observed");
-  sub->file_name_push_recv = store_prefix_file_name (&own_identity,
-                                                     "push_recv");
-  sub->file_name_pull_delays = store_prefix_file_name (&own_identity,
-                                                       "pull_delays");
+#endif /* TO_FILE_FULL */
   sub->num_observed_peers = 0;
   sub->observed_unique_peers = GNUNET_CONTAINER_multipeermap_create (1,
                                                                     GNUNET_NO);
-  #endif /* TO_FILE */
+#endif /* TO_FILE */
 
   /* Set up data structures for gossip */
   sub->push_map = CustomPeerMap_create (4);
@@ -2905,6 +2957,50 @@ new_sub (const struct GNUNET_HashCode *hash,
 }
 
 
+#ifdef TO_FILE
+/**
+ * @brief Write all numbers in the given array into the given file
+ *
+ * Single numbers devided by a newline
+ *
+ * @param hist_array[] the array to dump
+ * @param file_name file to dump into
+ */
+static void
+write_histogram_to_file (const uint32_t hist_array[],
+                         const char *file_name)
+{
+  char collect_str[SIZE_DUMP_FILE + 1] = "";
+  char *recv_str_iter;
+  char *file_name_full;
+
+  recv_str_iter = collect_str;
+  file_name_full = store_prefix_file_name (&own_identity,
+                                           file_name);
+  for (uint32_t i = 0; i < HISTOGRAM_FILE_SLOTS; i++)
+  {
+    char collect_str_tmp[8];
+
+    GNUNET_snprintf (collect_str_tmp,
+                    sizeof (collect_str_tmp),
+                    "%" PRIu32 "\n",
+                    hist_array[i]);
+    recv_str_iter = stpncpy (recv_str_iter,
+                             collect_str_tmp,
+                             6);
+  }
+  (void) stpcpy (recv_str_iter,
+                 "\n");
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Writing push stats to disk\n");
+  to_file_w_len (file_name_full,
+                 SIZE_DUMP_FILE,
+                 collect_str);
+  GNUNET_free (file_name_full);
+}
+#endif /* TO_FILE */
+
+
 /**
  * @brief Destroy Sub.
  *
@@ -2913,10 +3009,6 @@ new_sub (const struct GNUNET_HashCode *hash,
 static void
 destroy_sub (struct Sub *sub)
 {
-#ifdef TO_FILE
-  char push_recv_str[1536] = ""; /* 256 * 6 (1 whitespace, 1 comma, up to 4 chars) */
-  char pull_delays_str[1536] = ""; /* 256 * 6 (1 whitespace, 1 comma, up to 4 chars) */
-#endif /* TO_FILE */
   GNUNET_assert (NULL != sub);
   GNUNET_assert (NULL != sub->do_round_task);
   GNUNET_SCHEDULER_cancel (sub->do_round_task);
@@ -2924,6 +3016,7 @@ destroy_sub (struct Sub *sub)
 
   /* Disconnect from cadet */
   GNUNET_CADET_close_port (sub->cadet_port);
+  sub->cadet_port= NULL;
 
   /* Clean up data structures for peers */
   RPS_sampler_destroy (sub->sampler);
@@ -2937,53 +3030,27 @@ destroy_sub (struct Sub *sub)
   peers_terminate (sub);
 
   /* Free leftover data structures */
+#ifdef TO_FILE_FULL
   GNUNET_free (sub->file_name_view_log);
   sub->file_name_view_log = NULL;
+#endif /* TO_FILE_FULL */
 #ifdef TO_FILE
+#ifdef TO_FILE_FULL
   GNUNET_free (sub->file_name_observed_log);
   sub->file_name_observed_log = NULL;
+#endif /* TO_FILE_FULL */
 
   /* Write push frequencies to disk */
-  for (uint32_t i = 0; i < 256; i++)
-  {
-    char push_recv_str_tmp[8];
-    (void) snprintf (push_recv_str_tmp, 8, "%" PRIu32 "\n", sub->push_recv[i]);
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Adding str `%s' to `%s'\n",
-         push_recv_str_tmp,
-         push_recv_str);
-    (void) strncat (push_recv_str,
-                    push_recv_str_tmp,
-                    1535 - strnlen (push_recv_str, 1536));
-  }
-  (void) strncat (push_recv_str,
-                  "\n",
-                  1535 - strnlen (push_recv_str, 1536));
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Writing push stats to disk\n");
-  to_file_w_len (sub->file_name_push_recv, 1535, push_recv_str);
-  GNUNET_free (sub->file_name_push_recv);
-  sub->file_name_push_recv = NULL;
+  write_histogram_to_file (sub->push_recv,
+                           "push_recv");
+
+  /* Write push deltas to disk */
+  write_histogram_to_file (sub->push_delta,
+                           "push_delta");
 
   /* Write pull delays to disk */
-  for (uint32_t i = 0; i < 256; i++)
-  {
-    char pull_delays_str_tmp[8];
-    (void) snprintf (pull_delays_str_tmp, 8, "%" PRIu32 "\n", sub->pull_delays[i]);
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Adding str `%s' to `%s'\n",
-         pull_delays_str_tmp,
-         pull_delays_str);
-    (void) strncat (pull_delays_str,
-                    pull_delays_str_tmp,
-                    1535 - strnlen (pull_delays_str, 1536));
-  }
-  (void) strncat (pull_delays_str,
-                  "\n",
-                  1535 - strnlen (pull_delays_str, 1536));
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Writing pull delays to disk\n");
-  to_file_w_len (sub->file_name_pull_delays, 1535, pull_delays_str);
-  GNUNET_free (sub->file_name_pull_delays);
-  sub->file_name_pull_delays = NULL;
+  write_histogram_to_file (sub->pull_delays,
+                           "pull_delays");
 
   GNUNET_CONTAINER_multipeermap_destroy (sub->observed_unique_peers);
   sub->observed_unique_peers = NULL;
@@ -3035,8 +3102,11 @@ core_connects (void *cls,
   (void) cls;
   (void) mq;
 
-  GNUNET_CONTAINER_multipeermap_put (map_single_hop, peer, NULL,
-      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
+  GNUNET_assert (GNUNET_YES ==
+                GNUNET_CONTAINER_multipeermap_put (map_single_hop,
+                                                   peer,
+                                                   NULL,
+                                                   GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
   return NULL;
 }
 
@@ -3441,9 +3511,18 @@ handle_peer_push (void *cls,
   if (channel_ctx->peer_ctx->sub == msub)
   {
     GNUNET_STATISTICS_update(stats, "# push message received", 1, GNUNET_NO);
+    if (NULL != map_single_hop &&
+        GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (map_single_hop,
+                                                             peer))
+    {
+      GNUNET_STATISTICS_update (stats,
+                                "# push message received (multi-hop peer)",
+                                1,
+                                GNUNET_NO);
+    }
   }
 
-  #ifdef ENABLE_MALICIOUS
+  #if ENABLE_MALICIOUS
   struct AttackedPeer *tmp_att_peer;
 
   if ( (1 == mal_type) ||
@@ -3508,7 +3587,8 @@ handle_peer_pull_request (void *cls,
                              "# pull request message received",
                              1,
                              GNUNET_NO);
-    if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (map_single_hop,
+    if (NULL != map_single_hop &&
+        GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (map_single_hop,
                                                              &peer_ctx->peer_id))
     {
       GNUNET_STATISTICS_update (stats,
@@ -3518,7 +3598,7 @@ handle_peer_pull_request (void *cls,
     }
   }
 
-  #ifdef ENABLE_MALICIOUS
+  #if ENABLE_MALICIOUS
   if (1 == mal_type
       || 3 == mal_type)
   { /* Try to maximise representation */
@@ -3527,7 +3607,7 @@ handle_peer_pull_request (void *cls,
 
   else if (2 == mal_type)
   { /* Try to partition network */
-    if (0 == GNUNET_CRYPTO_cmp_peer_identity (&attacked_peer, peer))
+    if (0 == GNUNET_memcmp (&attacked_peer, peer))
     {
       send_pull_reply (peer_ctx, mal_peers, num_mal_peers);
     }
@@ -3590,8 +3670,6 @@ check_peer_pull_reply (void *cls,
                                 1,
                                 GNUNET_NO);
     }
-    GNUNET_break_op (0);
-    return GNUNET_SYSERR;
   }
   return GNUNET_OK;
 }
@@ -3612,7 +3690,7 @@ handle_peer_pull_reply (void *cls,
   const struct GNUNET_PeerIdentity *peers;
   struct Sub *sub = channel_ctx->peer_ctx->sub;
   uint32_t i;
-#ifdef ENABLE_MALICIOUS
+#if ENABLE_MALICIOUS
   struct AttackedPeer *tmp_att_peer;
 #endif /* ENABLE_MALICIOUS */
 
@@ -3624,7 +3702,8 @@ handle_peer_pull_reply (void *cls,
                               "# pull reply messages received",
                               1,
                               GNUNET_NO);
-    if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (map_single_hop,
+    if (NULL != map_single_hop &&
+        GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (map_single_hop,
           &channel_ctx->peer_ctx->peer_id))
     {
       GNUNET_STATISTICS_update (stats,
@@ -3634,7 +3713,7 @@ handle_peer_pull_reply (void *cls,
     }
   }
 
-  #ifdef ENABLE_MALICIOUS
+  #if ENABLE_MALICIOUS
   // We shouldn't even receive pull replies as we're not sending
   if (2 == mal_type)
   {
@@ -3655,7 +3734,7 @@ handle_peer_pull_reply (void *cls,
          i,
          GNUNET_i2s (&peers[i]));
 
-    #ifdef ENABLE_MALICIOUS
+    #if ENABLE_MALICIOUS
     if ((NULL != att_peer_set) &&
         (1 == mal_type || 3 == mal_type))
     { /* Add attacked peer to local list */
@@ -3676,25 +3755,30 @@ handle_peer_pull_reply (void *cls,
     }
     #endif /* ENABLE_MALICIOUS */
     /* Make sure we 'know' about this peer */
-    (void) insert_peer (channel_ctx->peer_ctx->sub, &peers[i]);
+    (void) insert_peer (channel_ctx->peer_ctx->sub,
+                        &peers[i]);
 
     if (GNUNET_YES == check_peer_valid (channel_ctx->peer_ctx->sub->valid_peers,
                                         &peers[i]))
     {
-      CustomPeerMap_put (channel_ctx->peer_ctx->sub->pull_map, &peers[i]);
+      CustomPeerMap_put (channel_ctx->peer_ctx->sub->pull_map,
+                         &peers[i]);
     }
     else
     {
       schedule_operation (channel_ctx->peer_ctx,
                           insert_in_pull_map,
                           channel_ctx->peer_ctx->sub); /* cls */
-      (void) issue_peer_online_check (channel_ctx->peer_ctx->sub, &peers[i]);
+      (void) issue_peer_online_check (channel_ctx->peer_ctx->sub,
+                                      &peers[i]);
     }
   }
 
-  UNSET_PEER_FLAG (get_peer_ctx (channel_ctx->peer_ctx->sub->peer_map, sender),
+  UNSET_PEER_FLAG (get_peer_ctx (channel_ctx->peer_ctx->sub->peer_map,
+                                 sender),
                    Peers_PULL_REPLY_PENDING);
-  clean_peer (channel_ctx->peer_ctx->sub, sender);
+  clean_peer (channel_ctx->peer_ctx->sub,
+              sender);
 
   GNUNET_break_op (check_peer_known (channel_ctx->peer_ctx->sub->peer_map,
                                      sender));
@@ -3764,7 +3848,8 @@ send_pull_request (struct PeerContext *peer_ctx)
   GNUNET_assert (GNUNET_NO == check_peer_flag (peer_ctx->sub->peer_map,
                                                &peer_ctx->peer_id,
                                                Peers_PULL_REPLY_PENDING));
-  SET_PEER_FLAG (peer_ctx, Peers_PULL_REPLY_PENDING);
+  SET_PEER_FLAG (peer_ctx,
+                 Peers_PULL_REPLY_PENDING);
   peer_ctx->round_pull_req = peer_ctx->sub->num_rounds;
 
   LOG (GNUNET_ERROR_TYPE_DEBUG,
@@ -3772,14 +3857,17 @@ send_pull_request (struct PeerContext *peer_ctx)
        GNUNET_i2s (&peer_ctx->peer_id));
 
   ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_RPS_PP_PULL_REQUEST);
-  send_message (peer_ctx, ev, "PULL REQUEST");
+  send_message (peer_ctx,
+                ev,
+                "PULL REQUEST");
   if (peer_ctx->sub)
   {
     GNUNET_STATISTICS_update (stats,
                               "# pull request send issued",
                               1,
                               GNUNET_NO);
-    if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (map_single_hop,
+    if (NULL != map_single_hop &&
+        GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (map_single_hop,
                                                              &peer_ctx->peer_id))
     {
       GNUNET_STATISTICS_update (stats,
@@ -3813,11 +3901,20 @@ send_push (struct PeerContext *peer_ctx)
                               "# push send issued",
                               1,
                               GNUNET_NO);
+    if (NULL != map_single_hop &&
+        GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains (map_single_hop,
+                                                             &peer_ctx->peer_id))
+    {
+      GNUNET_STATISTICS_update (stats,
+                                "# push send issued (multi-hop peer)",
+                                1,
+                                GNUNET_NO);
+    }
   }
 }
 
 
-#ifdef ENABLE_MALICIOUS
+#if ENABLE_MALICIOUS
 
 
 /**
@@ -4131,18 +4228,20 @@ do_round (void *cls)
     GNUNET_STATISTICS_update (stats, "# rounds", 1, GNUNET_NO);
   }
   sub->do_round_task = NULL;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Printing view:\n");
+#ifdef TO_FILE_FULL
   to_file (sub->file_name_view_log,
            "___ new round ___");
+#endif /* TO_FILE_FULL */
   view_array = View_get_as_array (sub->view);
   for (i = 0; i < View_size (sub->view); i++)
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
          "\t%s\n", GNUNET_i2s (&view_array[i]));
+#ifdef TO_FILE_FULL
     to_file (sub->file_name_view_log,
              "=%s\t(do round)",
              GNUNET_i2s_full (&view_array[i]));
+#endif /* TO_FILE_FULL */
   }
 
 
@@ -4217,8 +4316,10 @@ do_round (void *cls)
 
     /* Seems like recreating is the easiest way of emptying the peermap */
     View_clear (sub->view);
+#ifdef TO_FILE_FULL
     to_file (sub->file_name_view_log,
              "--- emptied ---");
+#endif /* TO_FILE_FULL */
 
     first_border  = GNUNET_MIN (ceil (alpha * sub->view_size_est_need),
                                 CustomPeerMap_size (sub->push_map));
@@ -4248,9 +4349,11 @@ do_round (void *cls)
             1,
             CustomPeerMap_get_peer_by_index (sub->push_map, permut[i]));
       }
+#ifdef TO_FILE_FULL
       to_file (sub->file_name_view_log,
                "+%s\t(push list)",
                GNUNET_i2s_full (&view_array[i]));
+#endif /* TO_FILE_FULL */
       // TODO change the peer_flags accordingly
     }
     GNUNET_free (permut);
@@ -4272,9 +4375,11 @@ do_round (void *cls)
             CustomPeerMap_get_peer_by_index (sub->pull_map,
                                              permut[i - first_border]));
       }
+#ifdef TO_FILE_FULL
       to_file (sub->file_name_view_log,
                "+%s\t(pull list)",
                GNUNET_i2s_full (&view_array[i]));
+#endif /* TO_FILE_FULL */
       // TODO change the peer_flags accordingly
     }
     GNUNET_free (permut);
@@ -4293,9 +4398,11 @@ do_round (void *cls)
     /* Clean peers that were removed from the view */
     for (i = 0; i < peers_to_clean_size; i++)
     {
+#ifdef TO_FILE_FULL
       to_file (sub->file_name_view_log,
                "-%s",
                GNUNET_i2s_full (&peers_to_clean[i]));
+#endif /* TO_FILE_FULL */
       clean_peer (sub, &peers_to_clean[i]);
     }
 
@@ -4306,10 +4413,10 @@ do_round (void *cls)
     if (sub == msub)
     {
       GNUNET_STATISTICS_update(stats, "# rounds blocked", 1, GNUNET_NO);
-      if (CustomPeerMap_size (sub->push_map) > alpha * View_size (sub->view) &&
+      if (CustomPeerMap_size (sub->push_map) > alpha * sub->view_size_est_need &&
           !(0 >= CustomPeerMap_size (sub->pull_map)))
         GNUNET_STATISTICS_update(stats, "# rounds blocked - too many pushes", 1, GNUNET_NO);
-      if (CustomPeerMap_size (sub->push_map) > alpha * View_size (sub->view) &&
+      if (CustomPeerMap_size (sub->push_map) > alpha * sub->view_size_est_need &&
           (0 >= CustomPeerMap_size (sub->pull_map)))
         GNUNET_STATISTICS_update(stats, "# rounds blocked - too many pushes, no pull replies", 1, GNUNET_NO);
       if (0 >= CustomPeerMap_size (sub->push_map) &&
@@ -4319,13 +4426,27 @@ do_round (void *cls)
           (0 >= CustomPeerMap_size (sub->pull_map)))
         GNUNET_STATISTICS_update(stats, "# rounds blocked - no pushes, no pull replies", 1, GNUNET_NO);
       if (0 >= CustomPeerMap_size (sub->pull_map) &&
-          CustomPeerMap_size (sub->push_map) > alpha * View_size (sub->view) &&
+          CustomPeerMap_size (sub->push_map) > alpha * sub->view_size_est_need &&
           0 >= CustomPeerMap_size (sub->push_map))
         GNUNET_STATISTICS_update(stats, "# rounds blocked - no pull replies", 1, GNUNET_NO);
     }
   }
   // TODO independent of that also get some peers from CADET_get_peers()?
-  sub->push_recv[CustomPeerMap_size (sub->push_map)]++;
+  if (CustomPeerMap_size (sub->push_map) < HISTOGRAM_FILE_SLOTS)
+  {
+    sub->push_recv[CustomPeerMap_size (sub->push_map)]++;
+  }
+  else
+  {
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         "Push map size too big for histogram (%u, %u)\n",
+         CustomPeerMap_size (sub->push_map),
+         HISTOGRAM_FILE_SLOTS);
+  }
+  // FIXME check bounds of histogram
+  sub->push_delta[(int32_t) (CustomPeerMap_size (sub->push_map) -
+                   (alpha * sub->view_size_est_need)) +
+                          (HISTOGRAM_FILE_SLOTS/2)]++;
   if (sub == msub)
   {
     GNUNET_STATISTICS_set (stats,
@@ -4340,6 +4461,14 @@ do_round (void *cls)
         "# peers in view at end of round",
         View_size (sub->view),
         GNUNET_NO);
+    GNUNET_STATISTICS_set (stats,
+        "# expected pushes",
+        alpha * sub->view_size_est_need,
+        GNUNET_NO);
+    GNUNET_STATISTICS_set (stats,
+        "delta expected - received pushes",
+        CustomPeerMap_size (sub->push_map) - (alpha * sub->view_size_est_need),
+        GNUNET_NO);
   }
 
   LOG (GNUNET_ERROR_TYPE_DEBUG,
@@ -4539,7 +4668,7 @@ shutdown_task (void *cls)
   }
   GNUNET_CADET_disconnect (cadet_handle);
   cadet_handle = NULL;
-#ifdef ENABLE_MALICIOUS
+#if ENABLE_MALICIOUS
   struct AttackedPeer *tmp_att_peer;
   GNUNET_array_grow (mal_peers,
                      num_mal_peers,
@@ -4557,6 +4686,7 @@ shutdown_task (void *cls)
     GNUNET_free (tmp_att_peer);
   }
 #endif /* ENABLE_MALICIOUS */
+  close_all_files();
 }
 
 
@@ -4651,7 +4781,7 @@ run (void *cls,
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
               "STARTING SERVICE (rps) for peer [%s]\n",
               GNUNET_i2s (&own_identity));
-#ifdef ENABLE_MALICIOUS
+#if ENABLE_MALICIOUS
   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
               "Malicious execution compiled in.\n");
 #endif /* ENABLE_MALICIOUS */
@@ -4744,7 +4874,7 @@ GNUNET_SERVICE_MAIN
    GNUNET_MESSAGE_TYPE_RPS_CS_SEED,
    struct GNUNET_RPS_CS_SeedMessage,
    NULL),
-#ifdef ENABLE_MALICIOUS
+#if ENABLE_MALICIOUS
  GNUNET_MQ_hd_var_size (client_act_malicious,
    GNUNET_MESSAGE_TYPE_RPS_ACT_MALICIOUS,
    struct GNUNET_RPS_CS_ActMaliciousMessage,