From 194e1c878aa383994fef0cbbb3449fdaa599b53a Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sat, 19 Apr 2014 22:03:07 +0200 Subject: Keep a vector of pollfds instead of regenerating it all the time --- src/CMakeLists.txt | 1 + src/fastd.c | 128 ++----------------------------------- src/fastd.h | 7 ++ src/peer.c | 23 +++++++ src/poll.c | 183 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/poll.h | 43 +++++++++++++ src/socket.c | 3 + src/tuntap.c | 7 ++ 8 files changed, 273 insertions(+), 122 deletions(-) create mode 100644 src/poll.c create mode 100644 src/poll.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9e757c5..dcd21bc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -28,6 +28,7 @@ add_executable(fastd log.c options.c peer.c + poll.c random.c receive.c resolve.c diff --git a/src/fastd.c b/src/fastd.c index 0f8194b..f87f43e 100644 --- a/src/fastd.c +++ b/src/fastd.c @@ -30,11 +30,11 @@ #include "crypto.h" #include "handshake.h" #include "peer.h" +#include "poll.h" #include #include #include -#include #include #include #include @@ -397,10 +397,6 @@ static void dump_state(fastd_context_t *ctx) { pr_info(ctx, "dump finished."); } -static inline void update_time(fastd_context_t *ctx) { - clock_gettime(CLOCK_MONOTONIC, &ctx->now); -} - static inline void no_valid_address_debug(fastd_context_t *ctx, const fastd_peer_t *peer) { pr_debug(ctx, "not sending a handshake to %P (no valid address resolved)", peer); } @@ -476,120 +472,6 @@ static void handle_handshake_queue(fastd_context_t *ctx) { fastd_resolve_peer(ctx, peer, peer->next_remote); } -static inline bool handle_tun_tap(fastd_context_t *ctx, fastd_buffer_t buffer) { - if (ctx->conf->mode != MODE_TAP) - return false; - - if (buffer.len < ETH_HLEN) { - pr_debug(ctx, "truncated packet on tap interface"); - fastd_buffer_free(buffer); - return true; - } - - fastd_eth_addr_t dest_addr = fastd_get_dest_address(ctx, buffer); - if (!fastd_eth_addr_is_unicast(dest_addr)) - return false; - - fastd_peer_t *peer = fastd_peer_find_by_eth_addr(ctx, dest_addr); - - if (!peer) - return false; - - ctx->conf->protocol->send(ctx, peer, buffer); - return true; -} - -static void handle_tun(fastd_context_t *ctx) { - fastd_buffer_t buffer = fastd_tuntap_read(ctx); - if (!buffer.len) - return; - - if (handle_tun_tap(ctx, buffer)) - return; - - /* TUN mode or multicast packet */ - fastd_send_all(ctx, NULL, buffer); -} - -static inline int handshake_timeout(fastd_context_t *ctx) { - if (!ctx->handshake_queue.next) - return -1; - - fastd_peer_t *peer = container_of(ctx->handshake_queue.next, fastd_peer_t, handshake_entry); - - int diff_msec = timespec_diff(&peer->next_handshake, &ctx->now); - if (diff_msec < 0) - return 0; - else - return diff_msec; -} - -static void handle_input(fastd_context_t *ctx) { - const size_t n_fds = 2 + ctx->n_socks + VECTOR_LEN(ctx->peers); - struct pollfd fds[n_fds]; - fds[0].fd = ctx->tunfd; - fds[0].events = POLLIN; - fds[1].fd = ctx->async_rfd; - fds[1].events = POLLIN; - - size_t i; - for (i = 0; i < ctx->n_socks; i++) { - fds[2+i].fd = ctx->socks[i].fd; - fds[2+i].events = POLLIN; - } - - for (i = 0; i < VECTOR_LEN(ctx->peers); i++) { - fastd_peer_t *peer = VECTOR_INDEX(ctx->peers, i); - - if (peer->sock && fastd_peer_is_socket_dynamic(peer)) - fds[2+ctx->n_socks+i].fd = peer->sock->fd; - else - fds[2+ctx->n_socks+i].fd = -1; - - fds[i+2+ctx->n_socks].events = POLLIN; - } - - int maintenance_timeout = timespec_diff(&ctx->next_maintenance, &ctx->now); - - if (maintenance_timeout < 0) - maintenance_timeout = 0; - - int timeout = handshake_timeout(ctx); - if (timeout < 0 || timeout > maintenance_timeout) - timeout = maintenance_timeout; - - int ret = poll(fds, n_fds, timeout); - if (ret < 0) { - if (errno == EINTR) - return; - - exit_errno(ctx, "poll"); - } - - update_time(ctx); - - if (fds[0].revents & POLLIN) - handle_tun(ctx); - if (fds[1].revents & POLLIN) - fastd_async_handle(ctx); - - for (i = 0; i < ctx->n_socks; i++) { - if (fds[2+i].revents & (POLLERR|POLLHUP|POLLNVAL)) - fastd_socket_error(ctx, &ctx->socks[i]); - else if (fds[2+i].revents & POLLIN) - fastd_receive(ctx, &ctx->socks[i]); - } - - for (i = 0; i < VECTOR_LEN(ctx->peers); i++) { - fastd_peer_t *peer = VECTOR_INDEX(ctx->peers, i); - - if (fds[2+ctx->n_socks+i].revents & (POLLERR|POLLHUP|POLLNVAL)) - fastd_peer_reset_socket(ctx, peer); - else if (fds[2+ctx->n_socks+i].revents & POLLIN) - fastd_receive(ctx, peer->sock); - } -} - static void enable_temporaries(fastd_context_t *ctx) { size_t i; for (i = 0; i < VECTOR_LEN(ctx->peers_temp); i++) @@ -913,7 +795,7 @@ int main(int argc, char *argv[]) { fastd_config_check(&ctx, &conf); - update_time(&ctx); + fastd_update_time(&ctx); ctx.next_maintenance = fastd_in_seconds(&ctx, conf.maintenance_interval); @@ -926,8 +808,9 @@ int main(int argc, char *argv[]) { /* change groups early as the can be relevant for file access (for PID file & log files) */ set_groups(&ctx); - fastd_async_init(&ctx); init_sockets(&ctx); + fastd_async_init(&ctx); + fastd_poll_init(&ctx); if (!fastd_socket_handle_binds(&ctx)) exit_error(&ctx, "unable to bind default socket"); @@ -976,7 +859,7 @@ int main(int argc, char *argv[]) { while (!terminate) { handle_handshake_queue(&ctx); - handle_input(&ctx); + fastd_poll_handle(&ctx); enable_temporaries(&ctx); @@ -1014,6 +897,7 @@ int main(int argc, char *argv[]) { fastd_tuntap_close(&ctx); close_sockets(&ctx); + fastd_poll_free(&ctx); on_post_down(&ctx); diff --git a/src/fastd.h b/src/fastd.h index 9cd6b2a..a116baf 100644 --- a/src/fastd.h +++ b/src/fastd.h @@ -34,6 +34,7 @@ #include "vector.h" #include +#include #include #include #include @@ -240,6 +241,8 @@ struct fastd_context { fastd_peer_group_t *peer_group; VECTOR(fastd_peer_t*) peers; + VECTOR(struct pollfd) pollfds; + VECTOR(fastd_peer_t*) peers_temp; fastd_dlist_head_t handshake_queue; @@ -401,6 +404,10 @@ static inline struct timespec fastd_in_seconds(const fastd_context_t *ctx, int s return ret; } +static inline void fastd_update_time(fastd_context_t *ctx) { + clock_gettime(CLOCK_MONOTONIC, &ctx->now); +} + static inline bool strequal(const char *str1, const char *str2) { if (str1 && str2) return (!strcmp(str1, str2)); diff --git a/src/peer.c b/src/peer.c index 67aa622..ecb7e2c 100644 --- a/src/peer.c +++ b/src/peer.c @@ -25,6 +25,7 @@ #include "peer.h" +#include "poll.h" #include #include @@ -46,6 +47,14 @@ static inline void free_socket(fastd_context_t *ctx, fastd_peer_t *peer) { fastd_socket_close(ctx, peer->sock); free(peer->sock); + + size_t i; + for (i = 0; i < VECTOR_LEN(ctx->peers); i++) { + if (VECTOR_INDEX(ctx->peers, i) == peer) { + fastd_poll_set_fd_peer(ctx, -1, i); + break; + } + } } peer->sock = NULL; } @@ -87,6 +96,17 @@ void fastd_peer_reset_socket(fastd_context_t *ctx, fastd_peer_t *peer) { else peer->sock = fastd_socket_open(ctx, peer, AF_INET6); } + + if (!peer->sock || !fastd_peer_is_socket_dynamic(peer)) + return; + + size_t i; + for (i = 0; i < VECTOR_LEN(ctx->peers); i++) { + if (VECTOR_INDEX(ctx->peers, i) == peer) { + fastd_poll_set_fd_peer(ctx, peer->sock->fd, i); + break; + } + } } void fastd_peer_schedule_handshake(fastd_context_t *ctx, fastd_peer_t *peer, int delay) { @@ -238,6 +258,7 @@ static void delete_peer(fastd_context_t *ctx, fastd_peer_t *peer) { for (i = 0; i < VECTOR_LEN(ctx->peers); i++) { if (VECTOR_INDEX(ctx->peers, i) == peer) { VECTOR_DELETE(ctx->peers, i); + fastd_poll_delete_peer(ctx, i); break; } } @@ -550,6 +571,7 @@ fastd_peer_t* fastd_peer_add(fastd_context_t *ctx, fastd_peer_config_t *peer_con setup_peer(ctx, peer); VECTOR_ADD(ctx->peers, peer); + fastd_poll_add_peer(ctx); return peer; } @@ -599,6 +621,7 @@ void fastd_peer_enable_temporary(fastd_context_t *ctx, fastd_peer_t *peer) { exit_bug(ctx, "trying to re-enable non-temporary peer"); VECTOR_ADD(ctx->peers, peer); + fastd_poll_add_peer(ctx); } void fastd_peer_set_established(fastd_context_t *ctx, fastd_peer_t *peer) { diff --git a/src/poll.c b/src/poll.c new file mode 100644 index 0000000..1e87946 --- /dev/null +++ b/src/poll.c @@ -0,0 +1,183 @@ +/* + Copyright (c) 2012-2014, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "poll.h" +#include "async.h" +#include "peer.h" + + +void fastd_poll_init(fastd_context_t *ctx) { + VECTOR_ALLOC(ctx->pollfds, 2 + ctx->n_socks); + + VECTOR_INDEX(ctx->pollfds, 0) = (struct pollfd) { + .fd = -1, + .events = POLLIN, + .revents = 0, + }; + + VECTOR_INDEX(ctx->pollfds, 1) = (struct pollfd) { + .fd = ctx->async_rfd, + .events = POLLIN, + .revents = 0, + }; + + size_t i; + for (i = 0; i < ctx->n_socks; i++) { + VECTOR_INDEX(ctx->pollfds, 2+i) = (struct pollfd) { + .fd = -1, + .events = POLLIN, + .revents = 0, + }; + } +} + +void fastd_poll_free(fastd_context_t *ctx) { + VECTOR_FREE(ctx->pollfds); +} + + +void fastd_poll_set_fd_tuntap(fastd_context_t *ctx, int fd) { + VECTOR_INDEX(ctx->pollfds, 0).fd = fd; +} + +void fastd_poll_set_fd_sock(fastd_context_t *ctx, int fd, size_t i) { + VECTOR_INDEX(ctx->pollfds, 2+i).fd = fd; +} + +void fastd_poll_set_fd_peer(fastd_context_t *ctx, int fd, size_t i) { + VECTOR_INDEX(ctx->pollfds, 2+ctx->n_socks+i).fd = fd; +} + +void fastd_poll_add_peer(fastd_context_t *ctx) { + struct pollfd pollfd = { + .fd = -1, + .events = POLLIN, + .revents = 0, + }; + + VECTOR_ADD(ctx->pollfds, pollfd); +} + +void fastd_poll_delete_peer(fastd_context_t *ctx, size_t i) { + VECTOR_DELETE(ctx->pollfds, 2+ctx->n_socks+i); +} + + +static inline bool handle_tun_tap(fastd_context_t *ctx, fastd_buffer_t buffer) { + if (ctx->conf->mode != MODE_TAP) + return false; + + if (buffer.len < ETH_HLEN) { + pr_debug(ctx, "truncated packet on tap interface"); + fastd_buffer_free(buffer); + return true; + } + + fastd_eth_addr_t dest_addr = fastd_get_dest_address(ctx, buffer); + if (!fastd_eth_addr_is_unicast(dest_addr)) + return false; + + fastd_peer_t *peer = fastd_peer_find_by_eth_addr(ctx, dest_addr); + + if (!peer) + return false; + + ctx->conf->protocol->send(ctx, peer, buffer); + return true; +} + +static void handle_tun(fastd_context_t *ctx) { + fastd_buffer_t buffer = fastd_tuntap_read(ctx); + if (!buffer.len) + return; + + if (handle_tun_tap(ctx, buffer)) + return; + + /* TUN mode or multicast packet */ + fastd_send_all(ctx, NULL, buffer); +} + +static inline int handshake_timeout(fastd_context_t *ctx) { + if (!ctx->handshake_queue.next) + return -1; + + fastd_peer_t *peer = container_of(ctx->handshake_queue.next, fastd_peer_t, handshake_entry); + + int diff_msec = timespec_diff(&peer->next_handshake, &ctx->now); + if (diff_msec < 0) + return 0; + else + return diff_msec; +} + +void fastd_poll_handle(fastd_context_t *ctx) { + int maintenance_timeout = timespec_diff(&ctx->next_maintenance, &ctx->now); + + if (maintenance_timeout < 0) + maintenance_timeout = 0; + + int timeout = handshake_timeout(ctx); + if (timeout < 0 || timeout > maintenance_timeout) + timeout = maintenance_timeout; + + int ret = poll(VECTOR_DATA(ctx->pollfds), VECTOR_LEN(ctx->pollfds), timeout); + if (ret < 0) { + if (errno == EINTR) + return; + + exit_errno(ctx, "poll"); + } + + fastd_update_time(ctx); + + if (VECTOR_INDEX(ctx->pollfds, 0).revents & POLLIN) + handle_tun(ctx); + if (VECTOR_INDEX(ctx->pollfds, 1).revents & POLLIN) + fastd_async_handle(ctx); + + size_t i; + for (i = 0; i < ctx->n_socks; i++) { + if (VECTOR_INDEX(ctx->pollfds, 2+i).revents & (POLLERR|POLLHUP|POLLNVAL)) { + fastd_socket_error(ctx, &ctx->socks[i]); + VECTOR_INDEX(ctx->pollfds, 2+i).fd = -1; + } + else if (VECTOR_INDEX(ctx->pollfds, 2+i).revents & POLLIN) { + fastd_receive(ctx, &ctx->socks[i]); + } + } + + for (i = 0; i < VECTOR_LEN(ctx->peers); i++) { + fastd_peer_t *peer = VECTOR_INDEX(ctx->peers, i); + + if (VECTOR_INDEX(ctx->pollfds, 2+ctx->n_socks+i).revents & (POLLERR|POLLHUP|POLLNVAL)) { + fastd_peer_reset_socket(ctx, peer); + } + else if (VECTOR_INDEX(ctx->pollfds, 2+ctx->n_socks+i).revents & POLLIN) { + fastd_receive(ctx, peer->sock); + } + } +} diff --git a/src/poll.h b/src/poll.h new file mode 100644 index 0000000..cc472b2 --- /dev/null +++ b/src/poll.h @@ -0,0 +1,43 @@ +/* + Copyright (c) 2012-2014, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#pragma once + + +#include "types.h" + + +void fastd_poll_init(fastd_context_t *ctx); +void fastd_poll_free(fastd_context_t *ctx); + +void fastd_poll_set_fd_tuntap(fastd_context_t *ctx, int fd); +void fastd_poll_set_fd_sock(fastd_context_t *ctx, int fd, size_t i); +void fastd_poll_set_fd_peer(fastd_context_t *ctx, int fd, size_t i); + +void fastd_poll_add_peer(fastd_context_t *ctx); +void fastd_poll_delete_peer(fastd_context_t *ctx, size_t i); + +void fastd_poll_handle(fastd_context_t *ctx); diff --git a/src/socket.c b/src/socket.c index 4f5ac0f..6db4b9f 100644 --- a/src/socket.c +++ b/src/socket.c @@ -25,6 +25,7 @@ #include "fastd.h" +#include "poll.h" #include @@ -195,6 +196,8 @@ bool fastd_socket_handle_binds(fastd_context_t *ctx) { continue; } + fastd_poll_set_fd_sock(ctx, ctx->socks[i].fd, i); + fastd_peer_address_t bound_addr = *ctx->socks[i].bound_addr; if (!ctx->socks[i].addr->addr.sa.sa_family) bound_addr.sa.sa_family = AF_UNSPEC; diff --git a/src/tuntap.c b/src/tuntap.c index c75c281..d638611 100644 --- a/src/tuntap.c +++ b/src/tuntap.c @@ -25,6 +25,7 @@ #include "fastd.h" +#include "poll.h" #include #include @@ -101,6 +102,8 @@ void fastd_tuntap_open(fastd_context_t *ctx) { if (close(ctl_sock)) pr_error_errno(ctx, "close"); + fastd_poll_set_fd_tuntap(ctx, ctx->tunfd); + pr_debug(ctx, "tun/tap device initialized."); } @@ -201,6 +204,8 @@ void fastd_tuntap_open(fastd_context_t *ctx) { exit_bug(ctx, "invalid mode"); } + fastd_poll_set_fd_tuntap(ctx, ctx->tunfd); + pr_debug(ctx, "tun/tap device initialized."); } @@ -268,6 +273,8 @@ void fastd_tuntap_open(fastd_context_t *ctx) { exit_bug(ctx, "invalid mode"); } + fastd_poll_set_fd_tuntap(ctx, ctx->tunfd); + pr_debug(ctx, "tun device initialized."); } -- cgit v1.2.3