diff options
-rw-r--r-- | ffd/announce.c | 4 | ||||
-rw-r--r-- | ffd/ffd.c | 26 | ||||
-rw-r--r-- | ffd/ffd.h | 2 | ||||
-rw-r--r-- | ffd/queue.h | 4 | ||||
-rw-r--r-- | ffd/send.c | 84 |
5 files changed, 104 insertions, 16 deletions
diff --git a/ffd/announce.c b/ffd/announce.c index 00bd78c..491aefd 100644 --- a/ffd/announce.c +++ b/ffd/announce.c @@ -123,7 +123,7 @@ static inline void seqno_update(ffd_announce_t *announce) { next = cur; fprintf(stderr, "debug: update matches seqno request, forwarding\n"); - ffd_send_update(NULL, req->neigh, announce, false); + ffd_send_update(NULL, req->neigh, announce, true, false); ffd_neigh_unref(req->neigh); free(req); } @@ -145,7 +145,7 @@ void ffd_announce_update(ffd_announce_t *announce) { if (((announce->last_metric == 0xffff) != (announce->metric.metric == 0xffff)) || diff <= -1024 || diff >= 384) { fprintf(stderr, "info: announce metric has changed significantly, sending updates\n"); - ffd_send_update(NULL, NULL, announce, false); + ffd_send_update(NULL, NULL, announce, announce->metric.metric == 0xffff, false); } if (announce->selected) @@ -52,7 +52,8 @@ static char *mesh = "bat0"; int sockfd; struct timespec now; -static ffd_queue_head *tasks; +ffd_queue_head *tasks = NULL; +ffd_queue_head *retransmits = NULL; ffd_node_id_t self; ffd_iface_t *iface_list = NULL; @@ -358,13 +359,13 @@ static void handle_tlv_announce_req(const ffd_tlv_announce_req_t *tlv_req, size_ fprintf(stderr, "debug: received announce request\n"); if (ffd_is_node_id_unspec(&tlv_req->node)) { - ffd_send_update(NULL, get_tlv_neigh(arg), NULL, tlv_req->flags & FFD_UPDATE_WITH_DATA); + ffd_send_update(NULL, get_tlv_neigh(arg), NULL, false, tlv_req->flags & FFD_UPDATE_WITH_DATA); } else { ffd_announce_t *announce = ffd_announce_find(&tlv_req->node, ntohs(tlv_req->type), ntohs(tlv_req->key)); if (announce) - ffd_send_update(NULL, get_tlv_neigh(arg), announce, tlv_req->flags & FFD_UPDATE_WITH_DATA); + ffd_send_update(NULL, get_tlv_neigh(arg), announce, false, tlv_req->flags & FFD_UPDATE_WITH_DATA); else ffd_send_retract(get_tlv_neigh(arg), tlv_req->node, ntohs(tlv_req->type), ntohs(tlv_req->key)); } @@ -397,14 +398,14 @@ static void handle_tlv_seqno_req(const ffd_tlv_seqno_req_t *tlv_req, size_t len, if ((int16_t)(seqno-announce->selected->metric_seqno.seqno) <= 0) { fprintf(stderr, "debug: received seqno request, seqno already ok\n"); - ffd_send_update(NULL, neigh, announce, false); + ffd_send_update(NULL, neigh, announce, true, false); return; } if (!announce->selected->neigh) { fprintf(stderr, "debug: received seqno request, incrementing seqno\n"); announce->selected->metric_seqno.seqno++; - ffd_send_update(NULL, neigh, announce, false); + ffd_send_update(NULL, neigh, announce, true, false); return; } @@ -494,7 +495,7 @@ static void send_updates(void) { ffd_iface_t *iface; for (iface = iface_list; iface; iface = iface->next) { - ffd_send_update(iface, NULL, NULL, false); + ffd_send_update(iface, NULL, NULL, false, false); } } @@ -591,6 +592,16 @@ static void register_periodic_tasks(void) { } +static inline int timeout_min(int a, int b) { + if (a < 0) + return b; + else if (b < 0) + return a; + else + return min(a, b); +} + + int main() { if (!check_config()) return 1; @@ -606,10 +617,11 @@ int main() { while (true) { ffd_queue_run(&tasks); + ffd_queue_run(&retransmits); struct pollfd fds[1]; - int timeout = 10*ffd_queue_timeout(&tasks); + int timeout = 10*timeout_min(ffd_queue_timeout(&tasks), ffd_queue_timeout(&retransmits)); if (timeout < 0) timeout = -1; @@ -207,7 +207,7 @@ void ffd_announce_seqno_request_free_list(ffd_announce_t *announce); void ffd_send_ack(ffd_neigh_t *neigh, uint16_t nonce); void ffd_send_hellos(void); -void ffd_send_update(ffd_iface_t *iface, ffd_neigh_t *neigh, ffd_announce_t *announce, bool with_data); +void ffd_send_update(ffd_iface_t *iface, ffd_neigh_t *neigh, ffd_announce_t *announce, bool urgent, bool with_data); void ffd_send_retract(ffd_neigh_t *neigh, ffd_node_id_t node, uint16_t type, uint16_t key); void ffd_send_announce_request(ffd_iface_t *iface, ffd_neigh_t *neigh, ffd_node_id_t node, uint16_t type, uint16_t key, bool with_data); void ffd_send_seqno_request(ffd_neigh_t *neigh, ffd_announce_t *announce, uint16_t seqno); diff --git a/ffd/queue.h b/ffd/queue.h index 9fae53d..4674481 100644 --- a/ffd/queue.h +++ b/ffd/queue.h @@ -40,6 +40,10 @@ typedef struct _ffd_queue_head { } ffd_queue_head; +extern ffd_queue_head *tasks; +extern ffd_queue_head *retransmits; + + void ffd_queue_put(ffd_queue_head **queue, ffd_queue_cb cb, const struct timespec *timeout, void *arg); @@ -27,6 +27,7 @@ #include "ffd.h" #include "neigh.h" #include "packet.h" +#include "queue.h" #include "tlv.h" #include "tlv_types.h" @@ -72,6 +73,7 @@ static bool send_eth(const eth_addr_t *addr, unsigned ifindex, const void *buf, return true; } + static inline bool send_neigh(const ffd_neigh_t *neigh, const ffd_packet_t *packet) { if (!neigh->iface) return false; @@ -84,8 +86,12 @@ static inline bool send_neigh(const ffd_neigh_t *neigh, const ffd_packet_t *pack return true; } +static inline bool send_ifindex(unsigned ifindex, const ffd_packet_t *packet) { + return send_eth(&ffd_addr, ifindex, packet, sizeof(ffd_packet_t)+ntohs(packet->len)); +} + static inline bool send_iface(const ffd_iface_t *iface, const ffd_packet_t *packet) { - if (!send_eth(&ffd_addr, iface->ifindex, packet, sizeof(ffd_packet_t)+ntohs(packet->len))) { + if (!send_ifindex(iface->ifindex, packet)) { fprintf(stderr, "send_eth: %m\n"); return false; } @@ -108,6 +114,54 @@ static inline void send_any(const ffd_iface_t *iface, const ffd_neigh_t *neigh, send_broadcast(packet); } + +typedef struct _retransmit_arg { + unsigned iface; + ffd_neigh_t *neigh; + ffd_packet_t *packet; + + unsigned ref; +} retransmit_arg; + +static void retransmit_cb(const struct timespec *timeout, void *argp) { + retransmit_arg *arg = argp; + + fprintf(stderr, "debug: doing retransmit\n"); + + if (arg->neigh) + send_neigh(arg->neigh, arg->packet); + else if(arg->iface) + send_ifindex(arg->iface, arg->packet); + else + send_broadcast(arg->packet); + + if (!--arg->ref) { + if (arg->neigh) + ffd_neigh_unref(arg->neigh); + + free(arg->packet); + free(arg); + } +} + +static void send_retransmit(ffd_iface_t *iface, ffd_neigh_t *neigh, ffd_packet_t *packet) { + if (neigh) + ffd_neigh_ref(neigh); + + retransmit_arg *arg = malloc(sizeof(retransmit_arg)); + arg->iface = iface ? iface->ifindex : 0; + arg->neigh = neigh; + arg->packet = packet; + arg->ref = 5; + + ffd_queue_put_delayed(&retransmits, retransmit_cb, &now, 100, arg); + ffd_queue_put_delayed(&retransmits, retransmit_cb, &now, 75, arg); + ffd_queue_put_delayed(&retransmits, retransmit_cb, &now, 50, arg); + ffd_queue_put_delayed(&retransmits, retransmit_cb, &now, 25, arg); + ffd_queue_put_delayed(&retransmits, retransmit_cb, &now, 0, arg); +} + + void ffd_send_ack(ffd_neigh_t *neigh, uint16_t nonce) { ffd_packet_t *packet = alloca(sizeof(ffd_packet_t)+FFD_PACKET_MAX); @@ -223,8 +277,12 @@ static bool add_update(ffd_packet_t *packet, size_t max_len, ffd_node_id_t *node return true; } -void ffd_send_update(ffd_iface_t *iface, ffd_neigh_t *neigh, ffd_announce_t *announce, bool with_data) { - ffd_packet_t *packet = alloca(sizeof(ffd_packet_t)+FFD_PACKET_MAX); +void ffd_send_update(ffd_iface_t *iface, ffd_neigh_t *neigh, ffd_announce_t *announce, bool urgent, bool with_data) { + ffd_packet_t *packet; + if (urgent) + packet = malloc(sizeof(ffd_packet_t)+FFD_PACKET_MAX); + else + packet = alloca(sizeof(ffd_packet_t)+FFD_PACKET_MAX); packet->version_magic = htons(FFD_VERSION_MAGIC); packet->len = 0; @@ -238,7 +296,13 @@ void ffd_send_update(ffd_iface_t *iface, ffd_neigh_t *neigh, ffd_announce_t *ann ffd_announce_t *a; for (a = announce_list; a; a = a->next) { if (!add_update(packet, FFD_PACKET_MAX, &node_id, a, with_data, iface || neigh)) { - send_any(iface, neigh, packet); + if (urgent) { + send_retransmit(iface, neigh, packet); + packet = malloc(sizeof(ffd_packet_t)+FFD_PACKET_MAX); + } + else { + send_any(iface, neigh, packet); + } node_id = FFD_NODE_ID_UNSPEC; packet->len = 0; @@ -251,8 +315,16 @@ void ffd_send_update(ffd_iface_t *iface, ffd_neigh_t *neigh, ffd_announce_t *ann } } - if (packet->len) - send_any(iface, neigh, packet); + if (urgent) { + if (packet->len) + send_retransmit(iface, neigh, packet); + else + free(packet); + } + else { + if (packet->len) + send_any(iface, neigh, packet); + } } void ffd_send_retract(ffd_neigh_t *neigh, ffd_node_id_t node, uint16_t type, uint16_t key) { |