The announcements are currently only sent by alfred instances in master mode. Slave instances don't announce themself and thus don't detect the broken socket. To also catch such problems, it is useful to handle the detection of EPERM during the send in send_alfred_packet which is always called when a link-local UDP packet is send over the network.
Signed-off-by: Sven Eckelmann sven@open-mesh.com --- send.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-)
diff --git a/send.c b/send.c index 89e9c07..dc0e428 100644 --- a/send.c +++ b/send.c @@ -32,7 +32,6 @@
int announce_master(struct globals *globals) { - ssize_t ret; struct alfred_announce_master_v0 announcement;
if (globals->netsock < 0) @@ -42,14 +41,8 @@ int announce_master(struct globals *globals) announcement.header.version = ALFRED_VERSION; announcement.header.length = htons(0);
- ret = send_alfred_packet(globals, &in6addr_localmcast, &announcement, - sizeof(announcement)); - if (ret == -EPERM) { - fprintf(stderr, "Error during announcement\n"); - netsock_close(globals->netsock); - globals->netsock = -1; - } - + send_alfred_packet(globals, &in6addr_localmcast, &announcement, + sizeof(announcement));
return 0; } @@ -176,6 +169,11 @@ ssize_t send_alfred_packet(struct globals *globals, const struct in6_addr *dest, ret = sendto(globals->netsock, buf, length, 0, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr_in6)); + if (ret == -EPERM) { + fprintf(stderr, "Error during sent\n"); + netsock_close(globals->netsock); + globals->netsock = -1; + }
return ret; }
The interface may have been recreated or the mac address was changed. In this situations socket has to be recreated to avoid proplems with the link-local IPv6 address and the scope_id (interface id).
These properties are polled and checked every 60 seconds and the appropriate measures are taken when an error/change occurs.
Signed-off-by: Sven Eckelmann sven@open-mesh.com --- alfred.h | 3 +++ server.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+)
diff --git a/alfred.h b/alfred.h index ba2e416..e3b6d86 100644 --- a/alfred.h +++ b/alfred.h @@ -31,6 +31,7 @@ #include "packet.h"
#define ALFRED_INTERVAL 10 +#define ALFRED_IF_CHECK_INTERVAL 60 #define ALFRED_REQUEST_TIMEOUT 10 #define ALFRED_SERVER_TIMEOUT 60 #define ALFRED_DATA_TIMEOUT 600 @@ -102,6 +103,8 @@ struct globals { int netsock; int unix_sock;
+ struct timespec if_check; + struct hashtable_t *server_hash; struct hashtable_t *data_hash; struct hashtable_t *transaction_hash; diff --git a/server.c b/server.c index fd8572b..fdd97d4 100644 --- a/server.c +++ b/server.c @@ -20,14 +20,19 @@ */
#include <errno.h> +#include <inttypes.h> #include <net/ethernet.h> +#include <net/if.h> #include <stddef.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/select.h> +#include <sys/socket.h> +#include <sys/ioctl.h> #include <sys/time.h> +#include <unistd.h> #include <time.h> #include "alfred.h" #include "batadv_query.h" @@ -212,6 +217,64 @@ static int purge_data(struct globals *globals) return 0; }
+static void check_if_socket(struct globals *globals) +{ + struct timespec now, diff; + int sock; + struct ifreq ifr; + + clock_gettime(CLOCK_MONOTONIC, &now); + time_diff(&now, &globals->if_check, &diff); + + if (diff.tv_sec < ALFRED_IF_CHECK_INTERVAL) + return; + + globals->if_check = now; + + if (globals->netsock < 0) + return; + + sock = socket(PF_INET6, SOCK_DGRAM, 0); + if (sock < 0) { + fprintf(stderr, "can't open socket: %s\n", strerror(errno)); + return; + } + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, globals->interface, IFNAMSIZ); + if (ioctl(sock, SIOCGIFINDEX, &ifr) == -1) { + fprintf(stderr, "can't get interface: %s, closing netsock\n", + strerror(errno)); + goto close; + } + + if (globals->scope_id != (uint32_t)ifr.ifr_ifindex) { + fprintf(stderr, + "iface index changed from %"PRIu32" to %d, closing netsock\n", + globals->scope_id, ifr.ifr_ifindex); + goto close; + } + + if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) { + fprintf(stderr, "can't get MAC address: %s, closing netsock\n", + strerror(errno)); + goto close; + } + + if (memcmp(&globals->hwaddr, &ifr.ifr_hwaddr.sa_data, 6) != 0) { + fprintf(stderr, "iface mac changed, closing netsock\n"); + goto close; + } + + close(sock); + return; + +close: + netsock_close(globals->netsock); + globals->netsock = -1; + close(sock); +} + int alfred_server(struct globals *globals) { int maxsock, ret; @@ -237,6 +300,7 @@ int alfred_server(struct globals *globals) return -1;
clock_gettime(CLOCK_MONOTONIC, &last_check); + globals->if_check = last_check;
while (1) { clock_gettime(CLOCK_MONOTONIC, &now); @@ -297,6 +361,7 @@ int alfred_server(struct globals *globals) push_local_data(globals); } purge_data(globals); + check_if_socket(globals); }
if (globals->netsock >= 0)
The announcements are currently only sent by alfred instances in master mode. Slave instances don't announce themself and thus don't detect the broken socket. To also catch such problems, it is useful to handle the detection of EPERM during the send in send_alfred_packet which is always called when a link-local UDP packet is send over the network.
Signed-off-by: Sven Eckelmann sven@open-mesh.com
Sorry, I forgot to reply:
Both patches have been merged:
839cfd5 alfred: Check for changed interface properties fcd4b0a alfred: Handle EPERM on every sendto
Thank you!! Simon
send.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-)
diff --git a/send.c b/send.c index 89e9c07..dc0e428 100644 --- a/send.c +++ b/send.c @@ -32,7 +32,6 @@
int announce_master(struct globals *globals) {
ssize_t ret; struct alfred_announce_master_v0 announcement;
if (globals->netsock < 0)
@@ -42,14 +41,8 @@ int announce_master(struct globals *globals) announcement.header.version = ALFRED_VERSION; announcement.header.length = htons(0);
- ret = send_alfred_packet(globals, &in6addr_localmcast, &announcement,
sizeof(announcement));
- if (ret == -EPERM) {
fprintf(stderr, "Error during announcement\n");
netsock_close(globals->netsock);
globals->netsock = -1;
- }
send_alfred_packet(globals, &in6addr_localmcast, &announcement,
sizeof(announcement));
return 0;
} @@ -176,6 +169,11 @@ ssize_t send_alfred_packet(struct globals *globals, const struct in6_addr *dest, ret = sendto(globals->netsock, buf, length, 0, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr_in6));
if (ret == -EPERM) {
fprintf(stderr, "Error during sent\n");
netsock_close(globals->netsock);
globals->netsock = -1;
}
return ret;
}
b.a.t.m.a.n@lists.open-mesh.org