diff options
-rw-r--r-- | ffd/CMakeLists.txt | 1 | ||||
-rw-r--r-- | ffd/ack.c | 88 | ||||
-rw-r--r-- | ffd/ffd.c | 14 | ||||
-rw-r--r-- | ffd/ffd.h | 6 |
4 files changed, 107 insertions, 2 deletions
diff --git a/ffd/CMakeLists.txt b/ffd/CMakeLists.txt index 830fef4..2cc8cd4 100644 --- a/ffd/CMakeLists.txt +++ b/ffd/CMakeLists.txt @@ -1,6 +1,7 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${FFD_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}) add_executable(ffd + ack.c announce.c ffd.c neigh.c diff --git a/ffd/ack.c b/ffd/ack.c new file mode 100644 index 0000000..0dbb13c --- /dev/null +++ b/ffd/ack.c @@ -0,0 +1,88 @@ +/* + Copyright (c) 2012, Matthias Schiffer <mschiffer@universe-factory.net> + 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 "ffd.h" +#include "queue.h" + + +static uint8_t acks[1 << 13] = {}; +static ffd_queue_t *ack_requests = NULL; +static uint16_t nonce = 0; + + +#define SET_ACK(n) do {acks[n >> 3] |= 1 << (n & 7);} while(0) +#define UNSET_ACK(n) do {acks[n >> 3] &= ~(1 << (n & 7));} while(0) +#define GET_ACK(n) ((acks[n >> 3] & (1 << (n & 7))) != 0) + + +typedef struct _ack_arg_t { + void (*cb)(uint16_t nonce, void *arg); + void *arg; + + uint16_t nonce; + unsigned interval; + unsigned retries; +} ack_arg_t; + + +void ffd_ack_handle(uint16_t n) { + SET_ACK(n); +} + +static void ack_resend(const struct timespec *timeout, void *argp) { + ack_arg_t *arg = argp; + + if (GET_ACK(arg->nonce) || !(--arg->retries)) { + free(arg); + return; + } + + arg->cb(arg->nonce, arg->arg); + + ffd_queue_put_delayed(&ack_requests, ack_resend, timeout, arg->interval, arg); +} + +void ffd_ack_request(void (*cb)(uint16_t nonce, void *arg), unsigned interval, unsigned retries, void *arg) { + UNSET_ACK(nonce); + cb(nonce, arg); + + ack_arg_t *ack_arg = malloc(sizeof(ack_arg_t)); + ack_arg->cb = cb; + ack_arg->arg = arg; + ack_arg->nonce = nonce++; + ack_arg->interval = interval; + ack_arg->retries = retries; + + ffd_queue_put_delayed(&ack_requests, ack_resend, &now, interval, ack_arg); +} + +int ffd_ack_timeout(void) { + return ffd_queue_timeout(&ack_requests); +} + +void ffd_ack_run(void) { + ffd_queue_run(&ack_requests); +} @@ -203,6 +203,15 @@ static void handle_tlv_ack_req(const ffd_tlv_ack_req_t *tlv_req, size_t len, han ffd_send_ack(neigh, ntohs(tlv_req->nonce)); } +static void handle_tlv_ack(const ffd_tlv_ack_t *tlv_ack, size_t len, handle_tlv_arg_t *arg) { + if (len < sizeof(ffd_tlv_ack_t)) { + fprintf(stderr, "warn: received short acknowledement TLV.\n"); + return; + } + + ffd_ack_handle(ntohs(tlv_ack->nonce)); +} + static void handle_tlv_hello(const ffd_tlv_hello_t *tlv_hello, size_t len, handle_tlv_arg_t *arg) { if (len < sizeof(ffd_tlv_hello_t)) { fprintf(stderr, "warn: received short hello TLV.\n"); @@ -425,7 +434,7 @@ static void handle_tlv(ffd_tlv_type_t type, const void *data, size_t len, void * return; case TLV_ACK: - /* we don't send ack reqs */ + handle_tlv_ack(data, len, arg); return; case TLV_HELLO: @@ -617,10 +626,11 @@ int main() { while (true) { ffd_queue_run(&tasks); ffd_update_run(); + ffd_ack_run(); struct pollfd fds[1]; - int timeout = 10*timeout_min(ffd_queue_timeout(&tasks), ffd_update_timeout()); + int timeout = 10*timeout_min(timeout_min(ffd_queue_timeout(&tasks), ffd_update_timeout()), ffd_ack_timeout()); if (timeout < 0) timeout = -1; @@ -53,6 +53,7 @@ #define FFD_DELAY (FFD_HELLO_INTERVAL/2) #define FFD_URGENT_DELAY 20 +#define FFD_ACK_INTERVAL FFD_URGENT_DELAY #define FFD_UPDATE_WITH_DATA 0x01 @@ -207,6 +208,11 @@ ffd_nexthop_t* ffd_announce_nexthop_new(ffd_announce_t *announce, ffd_neigh_t *n bool ffd_announce_seqno_request(ffd_announce_t *announce, ffd_neigh_t *neigh, uint16_t seqno); void ffd_announce_free(ffd_announce_t *announce); +void ffd_ack_handle(uint16_t n); +void ffd_ack_request(void (*cb)(uint16_t nonce, void *arg), unsigned interval, unsigned retries, void *arg); +int ffd_ack_timeout(void); +void ffd_ack_run(void); + void ffd_update_enqueue(const ffd_node_id_t *node, uint16_t type, uint16_t key, ffd_neigh_t *neigh, bool urgent); int ffd_update_timeout(void); void ffd_update_run(void); |