summaryrefslogtreecommitdiffstats
path: root/src/receive.c
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2015-01-20 22:51:40 +0100
committerMatthias Schiffer <mschiffer@universe-factory.net>2015-01-20 22:51:40 +0100
commitb5d83e3988d346af26b479b7c1be96185de040aa (patch)
treeac1de596302c14d46a576f788b3fca31bb11a80c /src/receive.c
parent9f1a5ab5614976e10c4cfaeb055b6c0058b8ba20 (diff)
downloadfastd-b5d83e3988d346af26b479b7c1be96185de040aa.tar
fastd-b5d83e3988d346af26b479b7c1be96185de040aa.zip
Implement new hash table to keep track of unknown peers handshakes have been sent to
This should significantly reduce the number of handshakes sent after restarting fastd with many active connections.
Diffstat (limited to 'src/receive.c')
-rw-r--r--src/receive.c69
1 files changed, 55 insertions, 14 deletions
diff --git a/src/receive.c b/src/receive.c
index 22c26c5..2ee402a 100644
--- a/src/receive.c
+++ b/src/receive.c
@@ -32,6 +32,7 @@
#include "fastd.h"
#include "handshake.h"
+#include "hash.h"
#include "peer.h"
#include "peer_hashtable.h"
@@ -86,34 +87,74 @@ static inline void handle_socket_control(struct msghdr *message, const fastd_soc
}
}
+/** Initializes the hashtables used to keep track of handshakes sent to unknown peers */
+void fastd_receive_unknown_init(void) {
+ size_t i, j;
+ for (i = 0; i < UNKNOWN_TABLES; i++) {
+ ctx.unknown_handshakes[i] = fastd_new0_array(UNKNOWN_ENTRIES, fastd_handshake_timeout_t);
+
+ for (j = 0; j < UNKNOWN_ENTRIES; j++)
+ ctx.unknown_handshakes[i][j].timeout = ctx.now;
+ }
+
+ fastd_random_bytes(&ctx.unknown_handshake_seed, sizeof(ctx.unknown_handshake_seed), false);
+}
+
+/** Frees the hashtables used to keep track of handshakes sent to unknown peers */
+void fastd_receive_unknown_free(void) {
+ size_t i;
+ for (i = 0; i < UNKNOWN_TABLES; i++)
+ free(ctx.unknown_handshakes[i]);
+}
+
+/** Returns the i'th hash bucket for a peer address */
+fastd_handshake_timeout_t * unknown_hash_entry(int64_t base, size_t i, const fastd_peer_address_t *addr) {
+ int64_t slice = base - i;
+ uint32_t hash = ctx.unknown_handshake_seed;
+ fastd_hash(&hash, &slice, sizeof(slice));
+ fastd_peer_address_hash(&hash, addr);
+ fastd_hash_final(&hash);
+
+ return &ctx.unknown_handshakes[(size_t)slice % UNKNOWN_TABLES][hash % UNKNOWN_ENTRIES];
+}
+
+
/**
Checks if a handshake should be sent after an unexpected payload packet has been received
backoff_unknown() tries to avoid flooding hosts with handshakes.
*/
static bool backoff_unknown(const fastd_peer_address_t *addr) {
- size_t i;
- for (i = 0; i < array_size(ctx.unknown_handshakes); i++) {
- const fastd_handshake_timeout_t *t = &ctx.unknown_handshakes[(ctx.unknown_handshake_pos + i) % array_size(ctx.unknown_handshakes)];
+ static const size_t table_interval = MIN_HANDSHAKE_INTERVAL / (UNKNOWN_TABLES - 1);
- if (fastd_timed_out(t->timeout))
- break;
+ int64_t base = ctx.now / table_interval;
+ size_t first_empty = UNKNOWN_TABLES, i;
- if (fastd_peer_address_equal(addr, &t->address)) {
- pr_debug2("sent a handshake to unknown address %I a short time ago, not sending again", addr);
- return true;
+ for (i = 0; i < UNKNOWN_TABLES; i++) {
+ const fastd_handshake_timeout_t *t = unknown_hash_entry(base, i, addr);
+
+ if (fastd_timed_out(t->timeout)) {
+ if (first_empty == UNKNOWN_TABLES)
+ first_empty = i;
+
+ continue;
}
+
+ if (!fastd_peer_address_equal(addr, &t->address))
+ continue;
+
+ pr_debug2("sent a handshake to unknown address %I a short time ago, not sending again", addr);
+ return true;
}
- if (ctx.unknown_handshake_pos == 0)
- ctx.unknown_handshake_pos = array_size(ctx.unknown_handshakes)-1;
- else
- ctx.unknown_handshake_pos--;
+ /* We didn't find the address in any of the hashtables, now insert it */
+ if (first_empty == UNKNOWN_TABLES)
+ first_empty = fastd_rand(0, UNKNOWN_TABLES);
- fastd_handshake_timeout_t *t = &ctx.unknown_handshakes[ctx.unknown_handshake_pos];
+ fastd_handshake_timeout_t *t = unknown_hash_entry(base, first_empty, addr);
t->address = *addr;
- t->timeout = ctx.now + MIN_HANDSHAKE_INTERVAL;
+ t->timeout = ctx.now + MIN_HANDSHAKE_INTERVAL - first_empty * table_interval;
return false;
}