summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2012-03-02 19:41:17 +0100
committerMatthias Schiffer <mschiffer@universe-factory.net>2012-03-02 19:41:17 +0100
commit3a4964f5e8c07943474036e594698b313a73d502 (patch)
tree232984b71eed3d874feb179b78272b8d7b69d4fd
parent0f2e170ea6edee4df0f90a3821d5c054db6bd6b7 (diff)
downloadfastd-3a4964f5e8c07943474036e594698b313a73d502.tar
fastd-3a4964f5e8c07943474036e594698b313a73d502.zip
Allow floating peers
-rw-r--r--src/fastd.c71
-rw-r--r--src/fastd.h24
-rw-r--r--src/handshake.c2
-rw-r--r--src/method_null.c41
-rw-r--r--src/peer.c66
-rw-r--r--src/peer.h36
-rw-r--r--src/task.c4
-rw-r--r--src/task.h4
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 <errno.h>
#include <linux/if_ether.h>
#include <netinet/in.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
@@ -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 <arpa/inet.h>
+
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;