From 5b1d1a36df766dd60eb68b24a5edf4229b68e564 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Wed, 18 Nov 2015 03:44:26 +0100 Subject: Unify periodic handshakes and peer maintenance --- src/build.h.in | 6 +++ src/peer.c | 147 +++++++++++++++++++++++++++++++-------------------------- src/peer.h | 22 +++++---- src/task.c | 4 -- src/types.h | 3 +- 5 files changed, 98 insertions(+), 84 deletions(-) diff --git a/src/build.h.in b/src/build.h.in index 9b4727e..503348b 100644 --- a/src/build.h.in +++ b/src/build.h.in @@ -111,6 +111,12 @@ #define MAX_CONFIG_DEPTH @MAX_CONFIG_DEPTH_NUM@ +/** The default handshake interval */ +#define DEFAULT_HANDSHAKE_INTERVAL 20000 /* 20 seconds */ + +/** The default handshake interval jitter */ +#define DEFAULT_HANDSHAKE_JITTER 2500 /* 2.5 seconds */ + /** The interval of periodic maintenance tasks */ #define MAINTENANCE_INTERVAL 10000 /* 10 seconds */ diff --git a/src/peer.c b/src/peer.c index 22339b4..8b2dfdb 100644 --- a/src/peer.c +++ b/src/peer.c @@ -256,6 +256,36 @@ void fastd_peer_reset_socket(fastd_peer_t *peer) { return; } +/** Schedules the peer maintenance task (or removes the scheduled task if there's nothing to do) */ +static void schedule_peer_task(fastd_peer_t *peer) { + fastd_timeout_t timeout = fastd_timeout_min(peer->reset_timeout, + fastd_timeout_min(peer->keepalive_timeout, + peer->next_handshake)); + + if (timeout == fastd_timeout_inv) { + pr_debug2("Removing scheduled task for %P", peer); + fastd_task_unschedule(&peer->task); + } + else if (fastd_task_timeout(&peer->task) > timeout) { + pr_debug2("Replacing scheduled task for %P", peer); + fastd_task_unschedule(&peer->task); + fastd_task_schedule(&peer->task, TASK_TYPE_PEER, timeout); + } + else { + pr_debug2("Keeping scheduled task for %P", peer); + } +} + +/** Sets the timeout for the next handshake without actually rescheduling */ +static void set_next_handshake(fastd_peer_t *peer, int delay) { + peer->next_handshake = ctx.now + delay; +} + +/** Sets the timeout for the next handshake to the default delay and jitter without actually rescheduling */ +static void set_next_handshake_default(fastd_peer_t *peer) { + set_next_handshake(peer, fastd_peer_handshake_default_rand()); +} + /** Schedules a handshake after the given delay @@ -263,8 +293,8 @@ void fastd_peer_reset_socket(fastd_peer_t *peer) { @param delay the delay in milliseconds */ void fastd_peer_schedule_handshake(fastd_peer_t *peer, int delay) { - fastd_peer_unschedule_handshake(peer); - fastd_task_schedule(&peer->handshake_task, TASK_TYPE_HANDSHAKE, ctx.now + delay); + set_next_handshake(peer, delay); + schedule_peer_task(peer); } /** Checks if the peer group \e group1 lies in \e group2 */ @@ -313,7 +343,6 @@ static void reset_peer(fastd_peer_t *peer) { VECTOR_RESIZE(ctx.eth_addrs, VECTOR_LEN(ctx.eth_addrs)-deleted); - fastd_peer_unschedule_handshake(peer); fastd_task_unschedule(&peer->task); fastd_peer_hashtable_remove(peer); @@ -364,23 +393,6 @@ void fastd_peer_handle_resolve(fastd_peer_t *peer, fastd_remote_t *remote, size_ init_handshake(peer); } -/** Schedules the peer maintenance task (or removes the scheduled task if there's nothing to do) */ -static void schedule_peer_task(fastd_peer_t *peer) { - fastd_timeout_t timeout = fastd_timeout_min(peer->reset_timeout, peer->keepalive_timeout); - if (timeout == fastd_timeout_inv) { - pr_debug2("Removing scheduled task for %P", peer); - fastd_task_unschedule(&peer->task); - } - else if (fastd_task_timeout(&peer->task) > timeout) { - pr_debug2("Replacing scheduled task for %P", peer); - fastd_task_unschedule(&peer->task); - fastd_task_schedule(&peer->task, TASK_TYPE_PEER, timeout); - } - else { - pr_debug2("Keeping scheduled task for %P", peer); - } -} - /** Initializes a peer */ static void setup_peer(fastd_peer_t *peer) { if (VECTOR_LEN(peer->remotes) == 0) { @@ -415,13 +427,12 @@ static void setup_peer(fastd_peer_t *peer) { peer->verify_valid_timeout = ctx.now; #endif + peer->next_handshake = fastd_timeout_inv; peer->reset_timeout = fastd_timeout_inv; peer->keepalive_timeout = fastd_timeout_inv; - if (fastd_peer_is_dynamic(peer)) { + if (fastd_peer_is_dynamic(peer)) peer->reset_timeout = ctx.now; - schedule_peer_task(peer); - } if (!fastd_peer_is_enabled(peer)) /* Keep the peer in STATE_INACTIVE */ @@ -447,7 +458,7 @@ static void setup_peer(fastd_peer_t *peer) { if (next_remote->hostname) { peer->state = STATE_RESOLVING; fastd_resolve_peer(peer, next_remote); - fastd_peer_schedule_handshake_default(peer); + set_next_handshake_default(peer); } else { init_handshake(peer); @@ -456,6 +467,8 @@ static void setup_peer(fastd_peer_t *peer) { else { peer->state = STATE_PASSIVE; } + + schedule_peer_task(peer); } /** @@ -842,47 +855,6 @@ static void send_handshake(fastd_peer_t *peer, fastd_remote_t *next_remote) { conf.protocol->handshake_init(peer->sock, &peer->local_address, &peer->address, peer); } -/** Sends a handshake to one peer, if a scheduled handshake is due */ -void fastd_peer_handle_handshake_task(fastd_task_t *task) { - fastd_peer_t *peer = container_of(task, fastd_peer_t, handshake_task); - - fastd_peer_schedule_handshake_default(peer); - - if (!fastd_peer_may_connect(peer)) { - if (peer->next_remote != -1) { - pr_debug("temporarily disabling handshakes with %P", peer); - peer->next_remote = -1; - } - - return; - } - - fastd_remote_t *next_remote = fastd_peer_get_next_remote(peer); - - if (next_remote || fastd_peer_is_established(peer)) { - send_handshake(peer, next_remote); - - if (fastd_peer_is_established(peer)) - return; - - peer->state = STATE_HANDSHAKE; - - if (++next_remote->current_address < next_remote->n_addresses) - return; - - peer->next_remote++; - } - - if (peer->next_remote < 0 || (size_t)peer->next_remote >= VECTOR_LEN(peer->remotes)) - peer->next_remote = 0; - - next_remote = fastd_peer_get_next_remote(peer); - next_remote->current_address = 0; - - if (next_remote->hostname) - fastd_resolve_peer(peer, next_remote); -} - /** Marks a peer as established */ bool fastd_peer_set_established(fastd_peer_t *peer) { if (fastd_peer_is_established(peer)) @@ -963,6 +935,45 @@ bool fastd_peer_find_by_eth_addr(const fastd_eth_addr_t addr, fastd_peer_t **pee return true; } +/** Sends a handshake to one peer, if a scheduled handshake is due */ +static void handle_task_handshake(fastd_peer_t *peer) { + set_next_handshake_default(peer); + + if (!fastd_peer_may_connect(peer)) { + if (peer->next_remote != -1) { + pr_debug("temporarily disabling handshakes with %P", peer); + peer->next_remote = -1; + } + + return; + } + + fastd_remote_t *next_remote = fastd_peer_get_next_remote(peer); + + if (next_remote || fastd_peer_is_established(peer)) { + send_handshake(peer, next_remote); + + if (fastd_peer_is_established(peer)) + return; + + peer->state = STATE_HANDSHAKE; + + if (++next_remote->current_address < next_remote->n_addresses) + return; + + peer->next_remote++; + } + + if (peer->next_remote < 0 || (size_t)peer->next_remote >= VECTOR_LEN(peer->remotes)) + peer->next_remote = 0; + + next_remote = fastd_peer_get_next_remote(peer); + next_remote->current_address = 0; + + if (next_remote->hostname) + fastd_resolve_peer(peer, next_remote); +} + /** Performs maintenance tasks for a peer @@ -972,9 +983,6 @@ bool fastd_peer_find_by_eth_addr(const fastd_eth_addr_t addr, fastd_peer_t **pee void fastd_peer_handle_task(fastd_task_t *task) { fastd_peer_t *peer = container_of(task, fastd_peer_t, task); - if (!fastd_peer_is_dynamic(peer) && !fastd_peer_is_established(peer)) - return; - /* check for peer timeout */ if (fastd_timed_out(peer->reset_timeout)) { if (fastd_peer_is_dynamic(peer)) @@ -991,6 +999,9 @@ void fastd_peer_handle_task(fastd_task_t *task) { conf.protocol->send(peer, fastd_buffer_alloc(0, conf.min_encrypt_head_space, conf.min_encrypt_tail_space)); } + if (fastd_timed_out(peer->next_handshake)) + handle_task_handshake(peer); + schedule_peer_task(peer); } diff --git a/src/peer.h b/src/peer.h index 27894f5..88e192b 100644 --- a/src/peer.h +++ b/src/peer.h @@ -90,13 +90,14 @@ struct fastd_peer { fastd_peer_state_t state; /**< The peer's state */ - fastd_task_t handshake_task; /**< Entry in the handshake queue */ + fastd_task_t task; /**< Task queue entry for periodic maintenance tasks */ + + fastd_timeout_t next_handshake; /**< The time of the next handshake */ fastd_timeout_t last_handshake_timeout; /**< No handshakes are sent to the peer until this timeout has occured to avoid flooding the peer */ fastd_timeout_t last_handshake_response_timeout; /**< All handshakes from last_handshake_address will be ignored until this timeout has occured */ fastd_timeout_t establish_handshake_timeout; /**< A timeout during which all handshakes for this peer will be ignored after a new connection has been established */ int64_t established; /**< The time this peer connection has been established */ - fastd_task_t task; /**< Task queue entry for periodic maintenance tasks */ fastd_timeout_t reset_timeout; /**< The timeout after which the peer is reset */ fastd_timeout_t keepalive_timeout; /**< The timeout after which a keepalive is sent to the peer */ @@ -153,7 +154,6 @@ void fastd_peer_exec_shell_command(const fastd_shell_command_t *command, const f void fastd_peer_eth_addr_add(fastd_peer_t *peer, fastd_eth_addr_t addr); bool fastd_peer_find_by_eth_addr(const fastd_eth_addr_t addr, fastd_peer_t **peer); -void fastd_peer_handle_handshake_task(fastd_task_t *task); void fastd_peer_handle_task(fastd_task_t *task); void fastd_peer_eth_addr_cleanup(void); void fastd_peer_reset_all(void); @@ -173,18 +173,20 @@ static inline uint16_t fastd_peer_address_get_port(const fastd_peer_address_t *a } } -/** - Schedules a handshake with the default delay and jitter +/** Returns a random value in the range DEFAULT_HANDSHAKE_INTERVAL +/- DEFAULT_HANDSHAKE_JITTER */ +static inline int fastd_peer_handshake_default_rand(void) { + return fastd_rand(DEFAULT_HANDSHAKE_INTERVAL-DEFAULT_HANDSHAKE_JITTER, + DEFAULT_HANDSHAKE_INTERVAL+DEFAULT_HANDSHAKE_JITTER); +} - The default relay is between 17.5 and 22.5 seconds -*/ +/** Schedules a handshake with the default delay and jitter */ static inline void fastd_peer_schedule_handshake_default(fastd_peer_t *peer) { - fastd_peer_schedule_handshake(peer, fastd_rand(17500, 22500)); + fastd_peer_schedule_handshake(peer, fastd_peer_handshake_default_rand()); } /** Cancels a scheduled handshake */ static inline void fastd_peer_unschedule_handshake(fastd_peer_t *peer) { - fastd_task_unschedule(&peer->handshake_task); + peer->next_handshake = fastd_timeout_inv; } #ifdef WITH_DYNAMIC_PEERS @@ -205,7 +207,7 @@ static inline void fastd_peer_set_verified(fastd_peer_t *peer, bool ok) { /** Checks if there's a handshake queued for the peer */ static inline bool fastd_peer_handshake_scheduled(fastd_peer_t *peer) { - return fastd_task_scheduled(&peer->handshake_task); + return (peer->next_handshake != fastd_timeout_inv); } /** Checks if a peer is floating (is has at least one floating remote or no remotes at all) */ diff --git a/src/task.c b/src/task.c index 079fc4a..8a95b06 100644 --- a/src/task.c +++ b/src/task.c @@ -51,10 +51,6 @@ static void handle_task(void) { maintenance(); break; - case TASK_TYPE_HANDSHAKE: - fastd_peer_handle_handshake_task(task); - break; - case TASK_TYPE_PEER: fastd_peer_handle_task(task); break; diff --git a/src/types.h b/src/types.h index edc84f8..e29943c 100644 --- a/src/types.h +++ b/src/types.h @@ -89,8 +89,7 @@ typedef enum fastd_poll_type { typedef enum fastd_task_type { TASK_TYPE_UNSPEC = 0, /**< Unspecified task type */ TASK_TYPE_MAINTENANCE, /**< Scheduled maintenance */ - TASK_TYPE_HANDSHAKE, /**< Scheduled handshake */ - TASK_TYPE_PEER, /**< Peer maintenance */ + TASK_TYPE_PEER, /**< Peer maintenance (handshake, reset, keepalive) */ } fastd_task_type_t; -- cgit v1.2.3