Lots of bugfixes, correctly handle announcements

This commit is contained in:
Matthias Schiffer 2012-08-30 01:04:47 +02:00
parent 87d8cbe72d
commit 044be347c8

View file

@ -126,6 +126,13 @@ static const eth_addr_t eth_addr_unspec = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}
static const eth_addr_t ffd_addr = {{0x03, 0x00, 0x00, 0x00, 0x0f, 0xfd}};
static int sockfd;
static char *mesh = "bat0";
static struct timespec now;
static ffvisd_announce_t *announcements = NULL;
static inline bool is_eth_addr_unspec(const eth_addr_t *address) {
const uint8_t *a = address->address;
@ -135,16 +142,19 @@ static inline bool is_eth_addr_unspec(const eth_addr_t *address) {
return true;
}
static inline bool are_eth_addrs_equal(const eth_addr_t *address1, const eth_addr_t *address2) {
const uint8_t *a = address1->address;
const uint8_t *b = address2->address;
#define ETH_ADDR_IS_UNSPEC(a) (!((a).address[0]||(a).address[0]||(a).address[0]||(a).address[0]||(a).address[0]||(a).address[0]))
return (a[0]==b[0] && a[1]==b[1] && a[2]==b[2] && a[3]==b[3] && a[4]==b[4] && a[5]==b[5]);
}
static inline bool are_ipv6_host_addrs_equal(const ffvisd_ipv6_host_addr_t *address1, const ffvisd_ipv6_host_addr_t *address2) {
const uint8_t *a = address1->address;
const uint8_t *b = address2->address;
static int sockfd;
static char *mesh = "bat0";
ffvisd_announce_t *announcements = NULL;
return (a[0]==b[0] && a[1]==b[1] && a[2]==b[2] && a[3]==b[3] && a[4]==b[4] && a[5]==b[5] && a[6]==b[6] && a[7]==b[7]);
}
/* returns (tp1 - tp2) in milliseconds */
static inline int timespec_diff(const struct timespec *tp1, const struct timespec *tp2) {
@ -152,6 +162,23 @@ static inline int timespec_diff(const struct timespec *tp1, const struct timespe
}
static inline bool are_announcements_equal(const ffvisd_packet_server_announce_t *a1, const ffvisd_packet_server_announce_t *a2) {
return (are_eth_addrs_equal(&a1->eth_address, &a2->eth_address) && are_ipv6_host_addrs_equal(&a1->address, &a2->address));
}
static inline bool is_announcement_local(const ffvisd_announce_t *a) {
return (a->received.tv_sec == 0);
}
static inline bool is_announcement_valid(const ffvisd_announce_t *a) {
if (is_announcement_local(a))
return true;
int diff = timespec_diff(&now, &a->received);
return (diff < ANNOUNCE_TIMEOUT*1000);
}
static bool file_readv(const char *file, const char *format, va_list ap) {
FILE *f = fopen(file, "r");
if (!f)
@ -322,13 +349,13 @@ static void pr_announcement_packet(const ffvisd_packet_server_announce_t *announ
const uint8_t *e = announce->eth_address.address, *a = announce->address.address;
printf("seqno: %u, ether: %02x:%02x:%02x:%02x:%02x:%02x, address: fe80::%02x%02x:%02x%02x:%02x%02x:%02x%02x\n",
announce->seqno,
ntohs(announce->seqno),
e[0], e[1], e[2], e[3], e[4], e[5],
a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
}
static void pr_announcement(const ffvisd_announce_t *announce) {
if (!announce->received.tv_sec) {
if (is_announcement_local(announce)) {
printf("local, ");
}
else {
@ -337,6 +364,8 @@ static void pr_announcement(const ffvisd_announce_t *announce) {
printf("age: %.1fs, ", timespec_diff(&tv, &announce->received)/1000.0);
}
printf("valid: %s, ", is_announcement_valid(announce) ? "yes" : "no");
pr_announcement_packet(&announce->announce);
}
@ -394,15 +423,34 @@ static bool init_announcements() {
}
static void maintenance() {
ffvisd_announce_t **announce;
clock_gettime(CLOCK_MONOTONIC, &now);
for(announce = &announcements; *announce; announce = &(*announce)->next) {
if (!(*announce)->received.tv_sec) /* announcement is local */
ffvisd_announce_t **announce, **next;
for(announce = &announcements; *announce; announce = next) {
next = &(*announce)->next;
if (is_announcement_local(*announce)) {
(*announce)->announce.seqno = htons(ntohs((*announce)->announce.seqno)+1);
continue;
}
int diff = timespec_diff(&now, &(*announce)->received);
if (diff >= ANNOUNCE_PRUNE*1000) {
ffvisd_announce_t *del = *announce;
*announce = *next;
next = announce;
free(del);
}
}
}
static void send_announcement(const char *ifname, unsigned ifindex, void *arg) {
char *if_mesh = iface_get_mesh(ifname);
if (if_mesh && !strcmp(if_mesh, mesh)) {
ffvisd_packet_announce_t *packet = arg;
struct sockaddr_ll sa;
@ -416,6 +464,8 @@ static void send_announcement(const char *ifname, unsigned ifindex, void *arg) {
sendto(sockfd, packet, sizeof(ffvisd_packet_announce_t) + ntohs(packet->n_servers)*sizeof(ffvisd_packet_server_announce_t), 0, (struct sockaddr*)&sa, sizeof(sa));
}
free(if_mesh);
}
static void send_announcements() {
ffvisd_packet_announce_t *packet = alloca(sizeof(ffvisd_packet_announce_t) + 75*sizeof(ffvisd_packet_server_announce_t));
@ -427,6 +477,9 @@ static void send_announcements() {
uint16_t n_servers = 0;
ffvisd_announce_t *announce;
for(announce = announcements; announce; announce = announce->next) {
if (!is_announcement_valid(announce))
continue;
packet->servers[n_servers++] = announce->announce;
}
@ -462,6 +515,38 @@ static void receive_announcement() {
for(i = 0; i < n_servers; i++)
pr_announcement_packet(&packet->servers[i]);
puts("");
clock_gettime(CLOCK_MONOTONIC, &now);
for(i = 0; i < n_servers; i++) {
ffvisd_announce_t *announce;
for(announce = announcements; announce; announce = announce->next) {
if (!are_announcements_equal(&packet->servers[i], &announce->announce))
continue;
if (is_announcement_local(announce))
break;
uint16_t seqno_diff = ntohs(packet->servers[i].seqno) - ntohs(announce->announce.seqno);
if (seqno_diff > 0 && seqno_diff < 0x8000) {
announce->received = now;
announce->announce = packet->servers[i];
}
break;
}
if (!announce) { /* no matching annouce was found */
announce = calloc(1, sizeof(ffvisd_announce_t));
announce->received = now;
announce->announce = packet->servers[i];
announce->next = announcements;
announcements = announce;
}
}
}
int main() {
@ -493,7 +578,6 @@ int main() {
next_announce.tv_sec += ANNOUNCE_INTERVAL;
while (true) {
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
int timeout = timespec_diff(&next_announce, &now);