From dcaf41a18e1bd9014d1cf3ca7a7129a1be76e811 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Wed, 28 Aug 2013 23:34:55 +0200 Subject: Simplify keepalive sending By using a global keepalive timer, the O(n) keepalive queue purge operation on every send operation is avoided. --- src/config.c | 3 +- src/fastd.c | 71 +++++++++++++++++++++++++------------------ src/fastd.h | 2 ++ src/peer.h | 1 + src/protocol_ec25519_fhmqvc.c | 8 ++--- src/task.c | 62 +++---------------------------------- src/task.h | 9 ------ 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 -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_ */ -- cgit v1.2.3