summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2013-08-28 23:34:55 +0200
committerMatthias Schiffer <mschiffer@universe-factory.net>2013-08-29 00:45:13 +0200
commitdcaf41a18e1bd9014d1cf3ca7a7129a1be76e811 (patch)
tree024ee42fb7f76ed8e2fb4c1a5ec66031cdcc26b6
parent2343f5329c0d5e7d8073810e56577d944b7c518e (diff)
downloadfastd-dcaf41a18e1bd9014d1cf3ca7a7129a1be76e811.tar
fastd-dcaf41a18e1bd9014d1cf3ca7a7129a1be76e811.zip
Simplify keepalive sending
By using a global keepalive timer, the O(n) keepalive queue purge operation on every send operation is avoided.
-rw-r--r--src/config.c3
-rw-r--r--src/fastd.c71
-rw-r--r--src/fastd.h2
-rw-r--r--src/peer.h1
-rw-r--r--src/protocol_ec25519_fhmqvc.c8
-rw-r--r--src/task.c62
-rw-r--r--src/task.h9
7 files changed, 54 insertions, 102 deletions
diff --git a/src/config.c b/src/config.c
index 48a9c8c..1be93b0 100644
--- a/src/config.c
+++ b/src/config.c
@@ -89,7 +89,8 @@ static void default_config(fastd_config_t *conf) {
conf->log_syslog_ident = strdup("fastd");
- conf->keepalive_interval = 20;
+ conf->keepalive_interval = 10;
+ conf->keepalive_timeout = 15;
conf->peer_stale_time = 90;
conf->eth_addr_stale_time = 300;
diff --git a/src/fastd.c b/src/fastd.c
index 173e5f3..786f158 100644
--- a/src/fastd.c
+++ b/src/fastd.c
@@ -425,37 +425,27 @@ static void send_handshake(fastd_context_t *ctx, fastd_peer_t *peer) {
static void handle_tasks(fastd_context_t *ctx) {
fastd_task_t *task;
while ((task = fastd_task_get(ctx)) != NULL) {
- switch (task->type) {
- case TASK_HANDSHAKE:
- fastd_peer_schedule_handshake(ctx, task->peer);
+ fastd_peer_schedule_handshake(ctx, task->peer);
- if(!fastd_peer_may_connect(ctx, task->peer)) {
- task->peer->next_remote = task->peer->remotes;
- break;
- }
-
- send_handshake(ctx, task->peer);
-
- if (fastd_peer_is_established(task->peer))
- break;
-
- task->peer->next_remote = task->peer->next_remote->next;
- if (!task->peer->next_remote)
- task->peer->next_remote = task->peer->remotes;
+ if(!fastd_peer_may_connect(ctx, task->peer)) {
+ task->peer->next_remote = task->peer->remotes;
+ free(task);
+ continue;
+ }
- if (fastd_remote_is_dynamic(task->peer->next_remote))
- fastd_resolve_peer(ctx, task->peer, task->peer->next_remote);
+ send_handshake(ctx, task->peer);
- break;
+ if (fastd_peer_is_established(task->peer)) {
+ free(task);
+ continue;
+ }
- case TASK_KEEPALIVE:
- pr_debug2(ctx, "sending keepalive to %P", task->peer);
- ctx->conf->protocol->send(ctx, task->peer, fastd_buffer_alloc(ctx, 0, ctx->conf->min_encrypt_head_space, ctx->conf->min_encrypt_tail_space));
- break;
+ task->peer->next_remote = task->peer->next_remote->next;
+ if (!task->peer->next_remote)
+ task->peer->next_remote = task->peer->remotes;
- default:
- exit_bug(ctx, "invalid task type");
- }
+ if (fastd_remote_is_dynamic(task->peer->next_remote))
+ fastd_resolve_peer(ctx, task->peer, task->peer->next_remote);
free(task);
}
@@ -557,10 +547,14 @@ static void handle_input(fastd_context_t *ctx) {
if (i != n_fds)
exit_bug(ctx, "fd count mismatch");
- int timeout = fastd_task_timeout(ctx);
+ int keepalive_timeout = timespec_diff(&ctx->next_keepalives, &ctx->now);
- if (timeout < 0 || timeout > 60000)
- timeout = 60000; /* call maintenance at least once a minute */
+ if (keepalive_timeout < 0)
+ keepalive_timeout = 0;
+
+ int timeout = fastd_task_timeout(ctx);
+ if (timeout < 0 || timeout > keepalive_timeout)
+ timeout = keepalive_timeout;
int ret = poll(fds, n_fds, timeout);
if (ret < 0) {
@@ -628,6 +622,22 @@ static void maintenance(fastd_context_t *ctx) {
fastd_peer_eth_addr_cleanup(ctx);
fastd_socket_handle_binds(ctx);
+
+ if (timespec_after(&ctx->now, &ctx->next_keepalives)) {
+ fastd_peer_t *peer;
+ for (peer = ctx->peers; peer; peer = peer->next) {
+ if (!fastd_peer_is_established(peer))
+ continue;
+
+ if (timespec_diff(&ctx->now, &peer->last_send) < (int)ctx->conf->keepalive_timeout*1000)
+ continue;
+
+ pr_debug2(ctx, "sending keepalive to %P", peer);
+ ctx->conf->protocol->send(ctx, peer, fastd_buffer_alloc(ctx, 0, ctx->conf->min_encrypt_head_space, ctx->conf->min_encrypt_tail_space));
+ }
+
+ ctx->next_keepalives.tv_sec += ctx->conf->keepalive_interval;
+ }
}
@@ -748,6 +758,9 @@ int main(int argc, char *argv[]) {
update_time(&ctx);
+ ctx.next_keepalives = ctx.now;
+ ctx.next_keepalives.tv_sec += conf.keepalive_interval;
+
pr_info(&ctx, "fastd " FASTD_VERSION " starting");
fastd_cap_init(&ctx);
diff --git a/src/fastd.h b/src/fastd.h
index c6e25cb..133e2e0 100644
--- a/src/fastd.h
+++ b/src/fastd.h
@@ -167,6 +167,7 @@ struct fastd_config {
char *log_syslog_ident;
fastd_log_file_t *log_files;
+ unsigned keepalive_timeout;
unsigned keepalive_interval;
unsigned peer_stale_time;
unsigned eth_addr_stale_time;
@@ -277,6 +278,7 @@ struct fastd_context {
fastd_peer_t *peers;
fastd_peer_t *peers_temp;
fastd_queue_t task_queue;
+ struct timespec next_keepalives;
int resolverfd;
int resolvewfd;
diff --git a/src/peer.h b/src/peer.h
index 5a73abd..39b17a8 100644
--- a/src/peer.h
+++ b/src/peer.h
@@ -43,6 +43,7 @@ struct fastd_peer {
fastd_peer_state_t state;
struct timespec seen;
+ struct timespec last_send;
fastd_remote_t *remotes;
fastd_remote_t *next_remote;
diff --git a/src/protocol_ec25519_fhmqvc.c b/src/protocol_ec25519_fhmqvc.c
index fd9c6a4..d1d4740 100644
--- a/src/protocol_ec25519_fhmqvc.c
+++ b/src/protocol_ec25519_fhmqvc.c
@@ -435,8 +435,6 @@ static bool establish(fastd_context_t *ctx, fastd_peer_t *peer, const fastd_meth
pr_verbose(ctx, "new session with %P established using method `%s'.", peer, method->name);
- fastd_task_schedule_keepalive(ctx, peer, ctx->conf->keepalive_interval*1000);
-
if (initiator)
fastd_peer_schedule_handshake(ctx, peer);
else
@@ -795,7 +793,7 @@ static void protocol_handle_recv(fastd_context_t *ctx, fastd_peer_t *peer, fastd
if (!peer->protocol_state->session.handshakes_cleaned) {
pr_debug(ctx, "cleaning left handshakes with %P", peer);
- fastd_task_delete_peer_handshakes(ctx, peer);
+ fastd_task_delete_peer(ctx, peer);
peer->protocol_state->session.handshakes_cleaned = true;
if (peer->protocol_state->session.method->session_is_initiator(ctx, peer->protocol_state->session.method_state))
@@ -832,9 +830,7 @@ static void session_send(fastd_context_t *ctx, fastd_peer_t *peer, fastd_buffer_
}
fastd_send(ctx, peer->sock, &peer->local_address, &peer->address, send_buffer);
-
- fastd_task_delete_peer_keepalives(ctx, peer);
- fastd_task_schedule_keepalive(ctx, peer, ctx->conf->keepalive_interval*1000);
+ peer->last_send = ctx->now;
}
static void protocol_send(fastd_context_t *ctx, fastd_peer_t *peer, fastd_buffer_t buffer) {
diff --git a/src/task.c b/src/task.c
index 9ed17f7..768c9c3 100644
--- a/src/task.c
+++ b/src/task.c
@@ -31,72 +31,31 @@ fastd_task_t* fastd_task_get(fastd_context_t *ctx) {
return container_of(fastd_queue_get(ctx, &ctx->task_queue), fastd_task_t, entry);
}
-static bool is_handshake(fastd_queue_entry_t *data, void *extra) {
+static bool is_peer(fastd_queue_entry_t *data, void *extra) {
fastd_task_t *task = container_of(data, fastd_task_t, entry);
fastd_peer_t *peer = extra;
- if (task->peer != peer)
- return false;
-
- return (task->type == TASK_HANDSHAKE);
+ return (task->peer == peer);
}
void fastd_task_schedule_handshake(fastd_context_t *ctx, fastd_peer_t *peer, int timeout) {
- if (fastd_queue_has_entry(ctx, &ctx->task_queue, is_handshake, peer)) {
+ if (fastd_queue_has_entry(ctx, &ctx->task_queue, is_peer, peer)) {
pr_debug(ctx, "not sending a handshake to %P, there still is one queued", peer);
return;
}
fastd_task_t *task = malloc(sizeof(fastd_task_t));
- task->type = TASK_HANDSHAKE;
task->peer = peer;
fastd_queue_put(ctx, &ctx->task_queue, &task->entry, timeout);
}
-static bool is_keepalive(fastd_queue_entry_t *data, void *extra) {
+static bool delete_peer_task(fastd_queue_entry_t *data, void *extra) {
fastd_task_t *task = container_of(data, fastd_task_t, entry);
fastd_peer_t *peer = extra;
if (task->peer != peer)
- return false;
-
- return (task->type == TASK_KEEPALIVE);
-}
-
-void fastd_task_schedule_keepalive(fastd_context_t *ctx, fastd_peer_t *peer, int timeout) {
- if (fastd_queue_has_entry(ctx, &ctx->task_queue, is_keepalive, peer)) {
- pr_debug(ctx, "not sending a keepalive to %P, there still is one queued", peer);
- return;
- }
-
- fastd_task_t *task = malloc(sizeof(fastd_task_t));
-
- task->type = TASK_KEEPALIVE;
- task->peer = peer;
-
- fastd_queue_put(ctx, &ctx->task_queue, &task->entry, timeout);
-}
-
-typedef struct delete_task_extra {
- fastd_peer_t *peer;
- bool handshake_only;
- bool keepalive_only;
-} delete_task_extra_t;
-
-static bool delete_task(fastd_queue_entry_t *data, void *extra) {
- delete_task_extra_t *e = extra;
- fastd_task_t *task = container_of(data, fastd_task_t, entry);
- fastd_peer_t *peer = e->peer;
-
- if (task->peer != peer)
- return true;
-
- if (e->handshake_only && task->type != TASK_HANDSHAKE)
- return true;
-
- if (e->keepalive_only && task->type != TASK_KEEPALIVE)
return true;
free(task);
@@ -105,16 +64,5 @@ static bool delete_task(fastd_queue_entry_t *data, void *extra) {
}
void fastd_task_delete_peer(fastd_context_t *ctx, fastd_peer_t *peer) {
- delete_task_extra_t extra = {peer, false, false};
- fastd_queue_filter(ctx, &ctx->task_queue, delete_task, &extra);
-}
-
-void fastd_task_delete_peer_handshakes(fastd_context_t *ctx, fastd_peer_t *peer) {
- delete_task_extra_t extra = {peer, true, false};
- fastd_queue_filter(ctx, &ctx->task_queue, delete_task, &extra);
-}
-
-void fastd_task_delete_peer_keepalives(fastd_context_t *ctx, fastd_peer_t *peer) {
- delete_task_extra_t extra = {peer, false, true};
- fastd_queue_filter(ctx, &ctx->task_queue, delete_task, &extra);
+ fastd_queue_filter(ctx, &ctx->task_queue, delete_peer_task, peer);
}
diff --git a/src/task.h b/src/task.h
index d80ddd6..ae6b1f3 100644
--- a/src/task.h
+++ b/src/task.h
@@ -33,15 +33,9 @@
#include <sys/uio.h>
-typedef enum fastd_task_type {
- TASK_HANDSHAKE,
- TASK_KEEPALIVE,
-} fastd_task_type_t;
-
typedef struct fastd_task {
fastd_queue_entry_t entry;
- fastd_task_type_t type;
fastd_peer_t *peer;
} fastd_task_t;
@@ -54,10 +48,7 @@ static inline int fastd_task_timeout(fastd_context_t *ctx) {
fastd_task_t* fastd_task_get(fastd_context_t *ctx);
void fastd_task_schedule_handshake(fastd_context_t *ctx, fastd_peer_t *peer, int timeout);
-void fastd_task_schedule_keepalive(fastd_context_t *ctx, fastd_peer_t *peer, int timeout);
void fastd_task_delete_peer(fastd_context_t *ctx, fastd_peer_t *peer);
-void fastd_task_delete_peer_handshakes(fastd_context_t *ctx, fastd_peer_t *peer);
-void fastd_task_delete_peer_keepalives(fastd_context_t *ctx, fastd_peer_t *peer);
#endif /* _FASTD_TASK_H_ */