tolerate additional IPv4 address now available for gnunet.org
[oweals/gnunet.git] / src / rps / gnunet-service-rps.c
index 375c93a67c77958136163e2078b7c9f59ef5cb7a..c5530a1eb8b02e6ac399845222ccc46b481d6baf 100644 (file)
@@ -282,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.
  *
@@ -331,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;
 
@@ -340,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
    */
@@ -418,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.
@@ -426,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];
 };
 
 
@@ -1379,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,
@@ -1782,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;
   }
@@ -2143,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 */
@@ -2375,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);
 }
@@ -2576,6 +2602,13 @@ insert_in_sampler (void *cls,
      * messages to it */
     //indicate_sending_intention (peer);
   }
+  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
@@ -2585,11 +2618,17 @@ 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_FULL */
 #endif /* TO_FILE */
 }
 
@@ -2675,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));
+  }
 }
 
 
@@ -2702,14 +2753,18 @@ clean_peer (struct Sub *sub,
         "Going to remove send channel to peer %s\n",
         GNUNET_i2s (peer));
     #if ENABLE_MALICIOUS
-    if (0 != GNUNET_CRYPTO_cmp_peer_identity (&attacked_peer, peer))
-      (void) destroy_sending_channel (get_peer_ctx (sub->peer_map, peer));
+    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,
@@ -2722,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",
@@ -2848,7 +2903,7 @@ new_sub (const struct GNUNET_HashCode *hash,
     char str_hash[105];
 
     GNUNET_snprintf (str_hash,
-                    strlen (str_hash),
+                    sizeof (str_hash),
                     GNUNET_h2s_full (hash));
     tmp_filename_valid_peers = sub->filename_valid_peers;
     GNUNET_asprintf (&sub->filename_valid_peers,
@@ -2869,14 +2924,14 @@ 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");
+#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);
@@ -2902,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.
  *
@@ -2910,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);
@@ -2921,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);
@@ -2934,54 +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];
-    
-    GNUNET_snprintf (push_recv_str_tmp,
-                    sizeof (push_recv_str_tmp),
-                    "%" PRIu32 "\n",
-                    sub->push_recv[i]);
-    (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 pull delays to disk */
-  for (uint32_t i = 0; i < 256; i++)
-  {
-    char pull_delays_str_tmp[8];
+  /* Write push deltas to disk */
+  write_histogram_to_file (sub->push_delta,
+                           "push_delta");
 
-    GNUNET_snprintf (pull_delays_str_tmp,
-                    sizeof (pull_delays_str_tmp),
-                    "%" PRIu32 "\n",
-                    sub->pull_delays[i]);
-    (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 pull delays to disk */
+  write_histogram_to_file (sub->pull_delays,
+                           "pull_delays");
 
   GNUNET_CONTAINER_multipeermap_destroy (sub->observed_unique_peers);
   sub->observed_unique_peers = NULL;
@@ -3442,6 +3511,15 @@ 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);
+    }
   }
 
   #if ENABLE_MALICIOUS
@@ -3529,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);
     }
@@ -3592,8 +3670,6 @@ check_peer_pull_reply (void *cls,
                                 1,
                                 GNUNET_NO);
     }
-    GNUNET_break_op (0);
-    return GNUNET_SYSERR;
   }
   return GNUNET_OK;
 }
@@ -3626,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,
@@ -3678,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));
@@ -3766,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,
@@ -3774,7 +3857,9 @@ 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,
@@ -3816,6 +3901,15 @@ 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);
+    }
   }
 }
 
@@ -4134,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 */
   }
 
 
@@ -4220,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));
@@ -4251,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);
@@ -4275,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);
@@ -4296,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]);
     }
 
@@ -4309,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) &&
@@ -4322,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,
@@ -4343,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,