From 3a4964f5e8c07943474036e594698b313a73d502 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Fri, 2 Mar 2012 19:41:17 +0100 Subject: Allow floating peers --- src/fastd.c | 71 +++++++++++++++++++++++++++++++++++++++++-------------- src/fastd.h | 24 ++++++++++++++----- src/handshake.c | 2 +- src/method_null.c | 41 +++++++++++++++++++++++++++----- src/peer.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++---- src/peer.h | 36 +++++++++++++++++++++++++--- src/task.c | 4 ++-- src/task.h | 4 ++-- 8 files changed, 205 insertions(+), 43 deletions(-) diff --git a/src/fastd.c b/src/fastd.c index 53b8488..0f52435 100644 --- a/src/fastd.c +++ b/src/fastd.c @@ -130,6 +130,9 @@ static void configure(fastd_context *ctx, fastd_config *conf, int argc, char *ar char *endptr; char *addrstr; + + conf->n_floating = 0; + while ((c = getopt_long (argc, argv, "i:b:M:P:m:p:", long_options, &option_index)) != -1) { switch(c) { case 'i': @@ -145,7 +148,10 @@ static void configure(fastd_context *ctx, fastd_config *conf, int argc, char *ar addrstr = optarg; } - if (inet_pton(AF_INET, addrstr, &addr) != 1) { + if (strcmp(addrstr, "any") == 0) { + addr.s_addr = htonl(INADDR_ANY); + } + else if (inet_pton(AF_INET, addrstr, &addr) != 1) { exit_error(ctx, "invalid bind address `%s'", addrstr); } @@ -196,7 +202,10 @@ static void configure(fastd_context *ctx, fastd_config *conf, int argc, char *ar addrstr = optarg; } - if (inet_pton(AF_INET, addrstr, &addr) != 1) { + if (strcmp(addrstr, "any") == 0 || strcmp(addrstr, "float") == 0) { + addr.s_addr = htonl(INADDR_ANY); + } + else if (inet_pton(AF_INET, addrstr, &addr) != 1) { exit_error(ctx, "invalid bind address `%s'", addrstr); } @@ -214,6 +223,9 @@ static void configure(fastd_context *ctx, fastd_config *conf, int argc, char *ar (*current_peer)->port = htons(1337); // Default port } + if (!(*current_peer)->address) + conf->n_floating++; + current_peer = &(*current_peer)->next; break; @@ -226,19 +238,23 @@ static void configure(fastd_context *ctx, fastd_config *conf, int argc, char *ar } } + bool ok = true; if (conf->protocol == PROTOCOL_IP && (!conf->peers || conf->peers->next)) { - exit_error(ctx, "for protocol `ip' exactly one peer must be configured"); + pr_error(ctx, "for protocol `ip' exactly one peer must be configured"); + ok = false; } + + if (ok) + ok = conf->method->check_config(ctx, conf); + + if (!ok) + exit_error(ctx, "config error"); } static void init_peers(fastd_context *ctx) { - fastd_peer **current_peer = &ctx->peers; fastd_peer_config *peer_conf; - for (peer_conf = ctx->conf->peers; peer_conf; peer_conf = peer_conf->next) { - *current_peer = fastd_peer_init(ctx, peer_conf); - - current_peer = &(*current_peer)->next; - } + for (peer_conf = ctx->conf->peers; peer_conf; peer_conf = peer_conf->next) + fastd_peer_add(ctx, peer_conf); } static void handle_tasks(fastd_context *ctx) { @@ -285,13 +301,14 @@ static void handle_tasks(fastd_context *ctx) { break; case TASK_HANDSHAKE: - if (task->handshake.peer->state != STATE_WAIT) + if (task->handshake.peer->state != STATE_WAIT && task->handshake.peer->state != STATE_TEMP) break; pr_debug(ctx, "Sending handshake..."); fastd_handshake_send(ctx, task->handshake.peer); - fastd_task_schedule_handshake(ctx, task->handshake.peer, 20000); + if (task->handshake.peer->state == STATE_WAIT) + fastd_task_schedule_handshake(ctx, task->handshake.peer, 20000); break; default: @@ -334,7 +351,7 @@ static void handle_input(fastd_context *ctx) { } if (peer->state == STATE_ESTABLISHED) { - ctx->conf->method->method_send(ctx, peer, buffer); + ctx->conf->method->send(ctx, peer, buffer); } else { fastd_buffer_free(buffer); @@ -346,7 +363,7 @@ static void handle_input(fastd_context *ctx) { if (peer->state == STATE_ESTABLISHED) { fastd_buffer send_buffer = fastd_buffer_alloc(len, 0, 0); memcpy(send_buffer.data, buffer.data, len); - ctx->conf->method->method_send(ctx, peer, send_buffer); + ctx->conf->method->send(ctx, peer, send_buffer); } } @@ -354,7 +371,7 @@ static void handle_input(fastd_context *ctx) { } } if (fds[1].revents & POLLIN) { - size_t max_len = ctx->conf->method->method_max_packet_size(ctx); + size_t max_len = ctx->conf->method->max_packet_size(ctx); fastd_buffer buffer = fastd_buffer_alloc(max_len, 0, 0); uint8_t packet_type; @@ -385,12 +402,30 @@ static void handle_input(fastd_context *ctx) { if (peer) { switch (packet_type) { - case 0: + case PACKET_DATA: buffer.len = len - 1; - ctx->conf->method->method_handle_recv(ctx, peer, buffer); + ctx->conf->method->handle_recv(ctx, peer, buffer); + break; + + case PACKET_HANDSHAKE: + fastd_handshake_handle(ctx, peer, buffer); + break; + + default: + fastd_buffer_free(buffer); + } + } + else if(ctx->conf->n_floating) { + switch (packet_type) { + case PACKET_DATA: + fastd_buffer_free(buffer); + + peer = fastd_peer_add_temp(ctx, recvaddr.sin_addr.s_addr, recvaddr.sin_port); + fastd_task_schedule_handshake(ctx, peer, 0); break; - case 1: + case PACKET_HANDSHAKE: + peer = fastd_peer_add_temp(ctx, recvaddr.sin_addr.s_addr, recvaddr.sin_port); fastd_handshake_handle(ctx, peer, buffer); break; @@ -398,7 +433,7 @@ static void handle_input(fastd_context *ctx) { fastd_buffer_free(buffer); } } - else { + else { pr_debug(ctx, "received packet from unknown peer"); fastd_buffer_free(buffer); } diff --git a/src/fastd.h b/src/fastd.h index acc5a19..04119a7 100644 --- a/src/fastd.h +++ b/src/fastd.h @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -48,6 +49,11 @@ typedef enum _fastd_loglevel { LOG_DEBUG, } fastd_loglevel; +typedef enum _fastd_packet_type { + PACKET_DATA = 0, + PACKET_HANDSHAKE, +} fastd_packet_type; + typedef struct _fastd_buffer { void *base; size_t base_len; @@ -71,6 +77,8 @@ typedef struct _fastd_peer_config { typedef enum _fastd_peer_state { STATE_WAIT, STATE_ESTABLISHED, + STATE_TEMP, + STATE_TEMP_ESTABLISHED, } fastd_peer_state; typedef struct _fastd_eth_addr { @@ -94,20 +102,23 @@ typedef struct _fastd_peer_eth_addr { fastd_peer *peer; } fastd_peer_eth_addr; +typedef struct _fastd_config fastd_config; typedef struct _fastd_context fastd_context; typedef struct _fastd_method { const char *name; - size_t (*method_max_packet_size)(fastd_context *ctx); + bool (*check_config)(fastd_context *ctx, const fastd_config *conf); + + size_t (*max_packet_size)(fastd_context *ctx); - void (*method_init)(fastd_context *ctx, fastd_peer *peer); + void (*init)(fastd_context *ctx, fastd_peer *peer); - void (*method_handle_recv)(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer); - void (*method_send)(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer); + void (*handle_recv)(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer); + void (*send)(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer); } fastd_method; -typedef struct _fastd_config { +struct _fastd_config { fastd_loglevel loglevel; char *ifname; @@ -120,8 +131,9 @@ typedef struct _fastd_config { fastd_method *method; + unsigned n_floating; fastd_peer_config *peers; -} fastd_config; +}; struct _fastd_context { const fastd_config *conf; diff --git a/src/handshake.c b/src/handshake.c index 59ebd72..f9dec71 100644 --- a/src/handshake.c +++ b/src/handshake.c @@ -101,7 +101,7 @@ void fastd_handshake_handle(fastd_context *ctx, fastd_peer *peer, fastd_buffer b pr_info(ctx, "Handshake successful."); pr_info(ctx, "Connection established."); peer->state = STATE_ESTABLISHED; - ctx->conf->method->method_init(ctx, peer); + ctx->conf->method->init(ctx, peer); break; default: diff --git a/src/method_null.c b/src/method_null.c index 60e612d..6ed7144 100644 --- a/src/method_null.c +++ b/src/method_null.c @@ -26,8 +26,18 @@ #include "fastd.h" #include "task.h" +#include "peer.h" +static bool null_check_config(fastd_context *ctx, const fastd_config *conf) { + if (conf->n_floating > 1) { + pr_error(ctx, "with method `null' use can't define more than one floating peer"); + return false; + } + + return true; +} + static size_t null_max_packet_size(fastd_context *ctx) { return fastd_max_packet_size(ctx); } @@ -37,9 +47,24 @@ static void null_init(fastd_context *ctx, fastd_peer *peer) { } static void null_handle_recv(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer) { - if (peer->state != STATE_ESTABLISHED) { + if (!fastd_peer_is_established(peer)) { pr_info(ctx, "Connection established."); - peer->state = STATE_ESTABLISHED; + fastd_peer_set_established(ctx, peer); + } + + if (fastd_peer_is_temporary(peer)) { + fastd_peer *perm_peer; + for (perm_peer = ctx->peers; perm_peer; perm_peer = perm_peer->next) { + if (fastd_peer_is_floating(perm_peer)) + break; + } + + if (!perm_peer) { + fastd_buffer_free(buffer); + return; + } + + peer = fastd_peer_merge(ctx, perm_peer, peer); } if (buffer.len) @@ -55,8 +80,12 @@ static void null_send(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer) const fastd_method fastd_method_null = { .name = "null", - .method_max_packet_size = null_max_packet_size, - .method_init = null_init, - .method_handle_recv = null_handle_recv, - .method_send = null_send, + + .check_config = null_check_config, + + .max_packet_size = null_max_packet_size, + + .init = null_init, + .handle_recv = null_handle_recv, + .send = null_send, }; diff --git a/src/peer.c b/src/peer.c index f050ebe..721deb6 100644 --- a/src/peer.c +++ b/src/peer.c @@ -28,6 +28,8 @@ #include "peer.h" #include "task.h" +#include + const fastd_eth_addr* fastd_get_source_address(const fastd_context *ctx, fastd_buffer buffer) { switch (ctx->conf->protocol) { @@ -47,23 +49,69 @@ const fastd_eth_addr* fastd_get_dest_address(const fastd_context *ctx, fastd_buf } } -fastd_peer* fastd_peer_init(fastd_context *ctx, fastd_peer_config *peer_conf) { +static fastd_peer* add_peer(fastd_context *ctx) { fastd_peer *peer = malloc(sizeof(fastd_peer)); - peer->next = NULL; + peer->next = ctx->peers; + peer->last_req_id = 0; + + ctx->peers = peer; + + return peer; +} + +fastd_peer* fastd_peer_add(fastd_context *ctx, fastd_peer_config *peer_conf) { + fastd_peer *peer = add_peer(ctx); peer->config = peer_conf; peer->address = peer_conf->address; peer->port = peer_conf->port; peer->state = STATE_WAIT; - peer->last_req_id = 0; - fastd_task_schedule_handshake(ctx, peer, 0); + pr_debug(ctx, "added peer %s:%u", inet_ntoa((struct in_addr){ .s_addr = peer->address }), ntohs(peer->port)); + + if (peer->address) + fastd_task_schedule_handshake(ctx, peer, 0); return peer; } -void fastd_peer_free(fastd_context *ctx, fastd_peer *peer) { +fastd_peer* fastd_peer_add_temp(fastd_context *ctx, in_addr_t address, in_port_t port) { + fastd_peer *peer = add_peer(ctx); + + if (!ctx->conf->n_floating) + exit_bug(ctx, "tried to add a temporary peer with no floating remotes defined"); + + peer->config = NULL; + peer->address = address; + peer->port = port; + peer->state = STATE_TEMP; + + pr_debug(ctx, "added peer %s:%u (temporary)", inet_ntoa((struct in_addr){ .s_addr = peer->address }), ntohs(peer->port)); + + return peer; +} + +fastd_peer* fastd_peer_merge(fastd_context *ctx, fastd_peer *perm_peer, fastd_peer *temp_peer) { + pr_debug(ctx, "merging peers"); + + perm_peer->address = temp_peer->address; + perm_peer->port = temp_peer->port; + perm_peer->state = fastd_peer_is_established(temp_peer) ? STATE_ESTABLISHED : STATE_WAIT; + + int i; + for (i = 0; i < ctx->n_eth_addr; i++) { + if (ctx->eth_addr[i].peer == temp_peer) { + ctx->eth_addr[i].peer = perm_peer; + } + } + + fastd_peer_delete(ctx, temp_peer); + + return perm_peer; +} + +void fastd_peer_delete(fastd_context *ctx, fastd_peer *peer) { int i, deleted = 0; for (i = 0; i < ctx->n_eth_addr; i++) { @@ -77,6 +125,14 @@ void fastd_peer_free(fastd_context *ctx, fastd_peer *peer) { ctx->n_eth_addr -= deleted; + fastd_peer **cur_peer; + for (cur_peer = &ctx->peers; *cur_peer; cur_peer = &(*cur_peer)->next) { + if ((*cur_peer) == peer) { + *cur_peer = peer->next; + break; + } + } + free(peer); } diff --git a/src/peer.h b/src/peer.h index e89155e..cd3d1d9 100644 --- a/src/peer.h +++ b/src/peer.h @@ -34,10 +34,40 @@ const fastd_eth_addr* fastd_get_source_address(const fastd_context *ctx, fastd_buffer buffer); const fastd_eth_addr* fastd_get_dest_address(const fastd_context *ctx, fastd_buffer buffer); -fastd_peer* fastd_peer_init(fastd_context *ctx, fastd_peer_config *conf); -void fastd_peer_free(fastd_context *ctx, fastd_peer *peer); +fastd_peer* fastd_peer_add(fastd_context *ctx, fastd_peer_config *conf); +fastd_peer* fastd_peer_add_temp(fastd_context *ctx, in_addr_t address, in_port_t port); +fastd_peer* fastd_peer_merge(fastd_context *ctx, fastd_peer *perm_peer, fastd_peer *temp_peer); +void fastd_peer_delete(fastd_context *ctx, fastd_peer *peer); -static inline int fastd_eth_addr_is_unicast(const fastd_eth_addr *addr) { + +static inline bool fastd_peer_is_floating(fastd_peer *peer) { + return (peer->config && !peer->config->address); +} + +static inline bool fastd_peer_is_temporary(fastd_peer *peer) { + return (peer->state == STATE_TEMP || peer->state == STATE_TEMP_ESTABLISHED); +} + +static inline bool fastd_peer_is_established(fastd_peer *peer) { + return (peer->state == STATE_ESTABLISHED || peer->state == STATE_TEMP_ESTABLISHED); +} + +static inline void fastd_peer_set_established(fastd_context *ctx, fastd_peer *peer) { + switch(peer->state) { + case STATE_WAIT: + peer->state = STATE_ESTABLISHED; + break; + + case STATE_TEMP: + peer->state = STATE_TEMP_ESTABLISHED; + break; + + default: + pr_warn(ctx, "tried to set an already established connection to established"); + } +} + +static inline bool fastd_eth_addr_is_unicast(const fastd_eth_addr *addr) { return ((addr->data[0] & 1) == 0); } diff --git a/src/task.c b/src/task.c index ed7f7cc..0d2dd6e 100644 --- a/src/task.c +++ b/src/task.c @@ -45,11 +45,11 @@ static void fastd_task_put_send_type(fastd_context *ctx, fastd_peer *peer, uint8 } void fastd_task_put_send_handshake(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer) { - fastd_task_put_send_type(ctx, peer, 1, buffer); + fastd_task_put_send_type(ctx, peer, PACKET_HANDSHAKE, buffer); } void fastd_task_put_send(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer) { - fastd_task_put_send_type(ctx, peer, 0, buffer); + fastd_task_put_send_type(ctx, peer, PACKET_DATA, buffer); } void fastd_task_put_handle_recv(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer) { diff --git a/src/task.h b/src/task.h index d569176..fbf2c63 100644 --- a/src/task.h +++ b/src/task.h @@ -42,14 +42,14 @@ typedef enum _fastd_task_type { typedef struct _fastd_task_send { fastd_task_type type; fastd_peer *peer; - uint8_t packet_type; + fastd_packet_type packet_type; fastd_buffer buffer; } fastd_task_send; typedef struct _fastd_task_handle_recv { fastd_task_type type; fastd_peer *peer; - uint8_t packet_type; + fastd_packet_type packet_type; fastd_buffer buffer; } fastd_task_handle_recv; -- cgit v1.2.3