@@ -16,9 +16,10 @@
#include <stdbool.h>
#include <stdint.h>
#include <time.h>
-#include <sys/select.h>
+#include <sys/epoll.h>
#include <sys/types.h>
#include "bitops.h"
+#include "epoll_handle.h"
#include "list.h"
#include "packet.h"
@@ -30,6 +31,10 @@
#define ALFRED_SOCK_PATH_DEFAULT "/var/run/alfred.sock"
#define NO_FILTER -1
+#ifndef __unused
+#define __unused __attribute__((unused))
+#endif
+
#define FIXED_TLV_LEN(__tlv_type) \
htons(sizeof(__tlv_type) - sizeof((__tlv_type).header))
@@ -101,9 +106,12 @@ struct interface {
alfred_addr address;
uint32_t scope_id;
char *interface;
+
int netsock;
int netsock_mcast;
- int netsock_arp;
+
+ struct epoll_handle netsock_epoll;
+ struct epoll_handle netsock_mcast_epoll;
struct hashtable_t *server_hash;
@@ -124,9 +132,13 @@ struct globals {
uint8_t ipv4mode:1;
uint8_t force:1;
+ int epollfd;
+
int check_timerfd;
+ struct epoll_handle check_epoll;
int unix_sock;
+ struct epoll_handle unix_epoll;
const char *unix_path;
const char *update_command;
@@ -182,7 +194,6 @@ int sync_data(struct globals *globals);
ssize_t send_alfred_packet(struct globals *globals, struct interface *interface,
const alfred_addr *dest, void *buf, int length);
/* unix_sock.c */
-int unix_sock_read(struct globals *globals);
int unix_sock_open_daemon(struct globals *globals);
int unix_sock_open_client(struct globals *globals);
int unix_sock_close(struct globals *globals);
@@ -197,9 +208,6 @@ void netsock_close_all(struct globals *globals);
int netsock_set_interfaces(struct globals *globals, char *interfaces);
struct interface *netsock_first_interface(struct globals *globals);
void netsock_reopen(struct globals *globals);
-int netsock_prepare_select(struct globals *globals, fd_set *fds, int maxsock);
-void netsock_check_error(struct globals *globals, fd_set *errfds);
-int netsock_receive_packet(struct globals *globals, fd_set *fds);
int netsock_own_address(const struct globals *globals,
const alfred_addr *address);
/* util.c */
@@ -26,10 +26,6 @@
#include "batadv_query.h"
#include "netlink.h"
-#ifndef __unused
-#define __unused __attribute__((unused))
-#endif
-
static const int translate_mac_netlink_mandatory[] = {
BATADV_ATTR_TT_ADDRESS,
BATADV_ATTR_ORIG_ADDRESS,
new file mode 100644
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) B.A.T.M.A.N. contributors:
+ *
+ * Sven Eckelmann
+ *
+ * License-Filename: LICENSES/preferred/GPL-2.0
+ */
+
+#ifndef _ALFRED_EPOLL_HANDLE_H
+#define _ALFRED_EPOLL_HANDLE_H
+
+#include <sys/epoll.h>
+
+struct globals;
+struct epoll_handle;
+
+typedef void (*epoll_handler)(struct globals *globals,
+ struct epoll_handle *handle,
+ struct epoll_event *ev);
+
+struct epoll_handle {
+ epoll_handler handler;
+};
+
+#endif /* _ALFRED_EPOLL_HANDLE_H */
@@ -20,7 +20,7 @@
#include <stdint.h>
#include <sys/types.h>
#include <stdlib.h>
-#include <sys/select.h>
+#include <sys/epoll.h>
#ifdef CONFIG_ALFRED_CAPABILITIES
#include <sys/capability.h>
#endif
@@ -203,12 +203,59 @@ out:
return ret;
}
-static int netsock_open(struct interface *interface)
+static void netsock_close_error(struct interface *interface)
+{
+ fprintf(stderr, "Error on netsock detected\n");
+
+ if (interface->netsock >= 0)
+ close(interface->netsock);
+
+ if (interface->netsock_mcast >= 0)
+ close(interface->netsock_mcast);
+
+ interface->netsock = -1;
+ interface->netsock_mcast = -1;
+}
+
+static void netsock_handle_event(struct globals *globals,
+ struct epoll_handle *handle,
+ struct epoll_event *ev)
+{
+ struct interface *interface;
+
+ interface = container_of(handle, struct interface, netsock_epoll);
+
+ if (ev->events & EPOLLERR) {
+ netsock_close_error(interface);
+ return;
+ }
+
+ recv_alfred_packet(globals, interface, interface->netsock);
+}
+
+static void netsock_mcast_handle_event(struct globals *globals,
+ struct epoll_handle *handle,
+ struct epoll_event *ev)
+{
+ struct interface *interface;
+
+ interface = container_of(handle, struct interface, netsock_mcast_epoll);
+
+ if (ev->events & EPOLLERR) {
+ netsock_close_error(interface);
+ return;
+ }
+
+ recv_alfred_packet(globals, interface, interface->netsock_mcast);
+}
+
+static int netsock_open(struct globals *globals, struct interface *interface)
{
int sock;
int sock_mc;
struct sockaddr_in6 sin6, sin6_mc;
struct ipv6_mreq mreq;
+ struct epoll_event ev;
struct ifreq ifr;
int ret;
@@ -318,6 +365,26 @@ static int netsock_open(struct interface *interface)
goto err;
}
+ ev.events = EPOLLIN;
+ ev.data.ptr = &interface->netsock_epoll;
+ interface->netsock_epoll.handler = netsock_handle_event;
+
+ if (epoll_ctl(globals->epollfd, EPOLL_CTL_ADD, sock,
+ &ev) == -1) {
+ perror("Failed to add epoll for netsock");
+ goto err;
+ }
+
+ ev.events = EPOLLIN;
+ ev.data.ptr = &interface->netsock_mcast_epoll;
+ interface->netsock_mcast_epoll.handler = netsock_mcast_handle_event;
+
+ if (epoll_ctl(globals->epollfd, EPOLL_CTL_ADD, sock_mc,
+ &ev) == -1) {
+ perror("Failed to add epoll for netsock_mcast");
+ goto err;
+ }
+
interface->netsock = sock;
interface->netsock_mcast = sock_mc;
@@ -328,11 +395,12 @@ err:
return -1;
}
-static int netsock_open4(struct interface *interface)
+static int netsock_open4(struct globals *globals, struct interface *interface)
{
int sock;
int sock_mc;
struct sockaddr_in sin4, sin_mc;
+ struct epoll_event ev;
struct ip_mreq mreq;
struct ifreq ifr;
int ret;
@@ -446,6 +514,26 @@ static int netsock_open4(struct interface *interface)
goto err;
}
+ ev.events = EPOLLIN;
+ ev.data.ptr = &interface->netsock_epoll;
+ interface->netsock_epoll.handler = netsock_handle_event;
+
+ if (epoll_ctl(globals->epollfd, EPOLL_CTL_ADD, sock,
+ &ev) == -1) {
+ perror("Failed to add epoll for netsock");
+ goto err;
+ }
+
+ ev.events = EPOLLIN;
+ ev.data.ptr = &interface->netsock_mcast_epoll;
+ interface->netsock_mcast_epoll.handler = netsock_mcast_handle_event;
+
+ if (epoll_ctl(globals->epollfd, EPOLL_CTL_ADD, sock_mc,
+ &ev) == -1) {
+ perror("Failed to add epoll for netsock_mcast");
+ goto err;
+ }
+
interface->netsock = sock;
interface->netsock_mcast = sock_mc;
@@ -464,9 +552,9 @@ int netsock_open_all(struct globals *globals)
list_for_each_entry(interface, &globals->interfaces, list) {
if (globals->ipv4mode)
- ret = netsock_open4(interface);
+ ret = netsock_open4(globals, interface);
else
- ret = netsock_open(interface);
+ ret = netsock_open(globals, interface);
if (ret >= 0)
num_socks++;
@@ -493,82 +581,13 @@ void netsock_reopen(struct globals *globals)
list_for_each_entry(interface, &globals->interfaces, list) {
if (interface->netsock < 0) {
if (globals->ipv4mode)
- netsock_open4(interface);
+ netsock_open4(globals, interface);
else
- netsock_open(interface);
+ netsock_open(globals, interface);
}
}
}
-int netsock_prepare_select(struct globals *globals, fd_set *fds, int maxsock)
-{
- struct interface *interface;
-
- list_for_each_entry(interface, &globals->interfaces, list) {
- if (interface->netsock >= 0) {
- FD_SET(interface->netsock, fds);
- if (maxsock < interface->netsock)
- maxsock = interface->netsock;
- }
-
- if (interface->netsock_mcast >= 0) {
- FD_SET(interface->netsock_mcast, fds);
- if (maxsock < interface->netsock_mcast)
- maxsock = interface->netsock_mcast;
- }
- }
-
- return maxsock;
-}
-
-void netsock_check_error(struct globals *globals, fd_set *errfds)
-{
- struct interface *interface;
-
- list_for_each_entry(interface, &globals->interfaces, list) {
- if ((interface->netsock < 0 ||
- !FD_ISSET(interface->netsock, errfds)) &&
- (interface->netsock_mcast < 0 ||
- !FD_ISSET(interface->netsock_mcast, errfds)))
- continue;
-
- fprintf(stderr, "Error on netsock detected\n");
-
- if (interface->netsock >= 0)
- close(interface->netsock);
-
- if (interface->netsock_mcast >= 0)
- close(interface->netsock_mcast);
-
- interface->netsock = -1;
- interface->netsock_mcast = -1;
- }
-}
-
-int netsock_receive_packet(struct globals *globals, fd_set *fds)
-{
- struct interface *interface;
- int recvs = 0;
-
- list_for_each_entry(interface, &globals->interfaces, list) {
- if (interface->netsock >= 0 &&
- FD_ISSET(interface->netsock, fds)) {
- recv_alfred_packet(globals, interface,
- interface->netsock);
- recvs++;
- }
-
- if (interface->netsock_mcast >= 0 &&
- FD_ISSET(interface->netsock_mcast, fds)) {
- recv_alfred_packet(globals, interface,
- interface->netsock_mcast);
- recvs++;
- }
- }
-
- return recvs;
-}
-
int netsock_own_address(const struct globals *globals,
const alfred_addr *address)
{
@@ -16,7 +16,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/select.h>
+#include <sys/epoll.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/time.h>
@@ -367,9 +367,62 @@ static void execute_update_command(struct globals *globals)
free(command);
}
+static void process_events(struct globals *globals)
+{
+ /* WARNING only processing one event because it could be that
+ * netsock + their fds are getting deleted
+ */
+ struct epoll_event events[1];
+ struct epoll_handle *handle;
+ int nfds;
+
+ nfds = epoll_wait(globals->epollfd, events,
+ sizeof(events) / sizeof(*events), -1);
+ if (nfds == -1) {
+ if (errno == EINTR)
+ return;
+
+ perror("main loop select failed ...");
+ return;
+ }
+
+ for (int i = 0; i < nfds; i++) {
+ handle = (struct epoll_handle *)events[i].data.ptr;
+ handle->handler(globals, handle, &events[i]);
+ }
+}
+
+static void sync_period_timer(struct globals *globals,
+ struct epoll_handle *handle __unused,
+ struct epoll_event *ev __unused)
+{
+ struct timespec now;
+ uint64_t timer_exp;
+
+ read(globals->check_timerfd, &timer_exp, sizeof(timer_exp));
+ clock_gettime(CLOCK_MONOTONIC, &now);
+
+ if (globals->opmode == OPMODE_PRIMARY) {
+ /* we are a primary */
+ printf("[%ld.%09ld] announce primary ...\n",
+ now.tv_sec, now.tv_nsec);
+ announce_primary(globals);
+ sync_data(globals);
+ } else {
+ /* send local data to server */
+ update_server_info(globals);
+ push_local_data(globals);
+ }
+
+ purge_data(globals);
+ check_if_sockets(globals);
+ execute_update_command(globals);
+}
+
static int create_sync_period_timer(struct globals *globals)
{
struct itimerspec sync_timer;
+ struct epoll_event ev;
int ret;
globals->check_timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
@@ -387,21 +440,34 @@ static int create_sync_period_timer(struct globals *globals)
return -1;
}
+ ev.events = EPOLLIN;
+ ev.data.ptr = &globals->check_epoll;
+ globals->check_epoll.handler = sync_period_timer;
+
+ if (epoll_ctl(globals->epollfd, EPOLL_CTL_ADD, globals->check_timerfd,
+ &ev) == -1) {
+ perror("Failed to add epoll for check_timer");
+ return -1;
+ }
+
return 0;
}
int alfred_server(struct globals *globals)
{
- int maxsock, ret, recvs;
- struct timespec now;
- fd_set fds, errfds;
size_t num_interfaces;
- uint64_t timer_exp;
+ struct timespec now;
int num_socks;
if (create_hashes(globals))
return -1;
+ globals->epollfd = epoll_create1(0);
+ if (globals->epollfd == -1) {
+ perror("Could not create epoll for main thread");
+ return -1;
+ }
+
if (create_sync_period_timer(globals))
return -1;
@@ -447,56 +513,7 @@ int alfred_server(struct globals *globals)
while (1) {
netsock_reopen(globals);
-
- FD_ZERO(&fds);
- FD_ZERO(&errfds);
- FD_SET(globals->unix_sock, &fds);
- maxsock = globals->unix_sock;
-
- FD_SET(globals->check_timerfd, &fds);
- if (maxsock < globals->check_timerfd)
- maxsock = globals->check_timerfd;
-
- maxsock = netsock_prepare_select(globals, &fds, maxsock);
- maxsock = netsock_prepare_select(globals, &errfds, maxsock);
-
- ret = pselect(maxsock + 1, &fds, NULL, &errfds, NULL, NULL);
-
- if (ret == -1) {
- perror("main loop select failed ...");
- } else if (ret) {
- netsock_check_error(globals, &errfds);
-
- if (FD_ISSET(globals->unix_sock, &fds)) {
- unix_sock_read(globals);
- continue;
- } else {
- recvs = netsock_receive_packet(globals, &fds);
- if (recvs > 0)
- continue;
- }
- }
-
- if (FD_ISSET(globals->check_timerfd, &fds)) {
- read(globals->check_timerfd, &timer_exp,
- sizeof(timer_exp));
- clock_gettime(CLOCK_MONOTONIC, &now);
-
- if (globals->opmode == OPMODE_PRIMARY) {
- /* we are a primary */
- printf("[%ld.%09ld] announce primary ...\n",
- now.tv_sec, now.tv_nsec);
- announce_primary(globals);
- sync_data(globals);
- } else {
- /* send local data to server */
- update_server_info(globals);
- push_local_data(globals);
- }
- purge_data(globals);
- check_if_sockets(globals);
- execute_update_command(globals);
- }
+ process_events(globals);
}
netsock_close_all(globals);
@@ -23,9 +23,14 @@
#include "hash.h"
#include "packet.h"
+static void unix_sock_read(struct globals *globals,
+ struct epoll_handle *handle __unused,
+ struct epoll_event *ev __unused);
+
int unix_sock_open_daemon(struct globals *globals)
{
struct sockaddr_un addr;
+ struct epoll_event ev;
unlink(globals->unix_path);
@@ -51,6 +56,16 @@ int unix_sock_open_daemon(struct globals *globals)
return -1;
}
+ ev.events = EPOLLIN;
+ ev.data.ptr = &globals->unix_epoll;
+ globals->unix_epoll.handler = unix_sock_read;
+
+ if (epoll_ctl(globals->epollfd, EPOLL_CTL_ADD, globals->unix_sock,
+ &ev) == -1) {
+ perror("Failed to add epoll for check_timer");
+ return -1;
+ }
+
return 0;
}
@@ -472,20 +487,22 @@ err:
return ret;
}
-int unix_sock_read(struct globals *globals)
+static void unix_sock_read(struct globals *globals,
+ struct epoll_handle *handle __unused,
+ struct epoll_event *ev __unused)
{
int client_sock;
struct sockaddr_un sun_addr;
socklen_t sun_size = sizeof(sun_addr);
struct alfred_tlv *packet;
uint8_t buf[MAX_PAYLOAD];
- int length, headsize, ret = -1;
+ int length, headsize;
client_sock = accept(globals->unix_sock, (struct sockaddr *)&sun_addr,
&sun_size);
if (client_sock < 0) {
perror("can't accept unix connection");
- return -1;
+ return;
}
/* we assume that we can instantly read here. */
@@ -510,44 +527,42 @@ int unix_sock_read(struct globals *globals)
switch (packet->type) {
case ALFRED_PUSH_DATA:
- ret = unix_sock_add_data(globals,
- (struct alfred_push_data_v0 *)packet,
- client_sock);
+ unix_sock_add_data(globals,
+ (struct alfred_push_data_v0 *)packet,
+ client_sock);
break;
case ALFRED_REQUEST:
- ret = unix_sock_req_data(globals,
- (struct alfred_request_v0 *)packet,
- client_sock);
+ unix_sock_req_data(globals,
+ (struct alfred_request_v0 *)packet,
+ client_sock);
break;
case ALFRED_MODESWITCH:
- ret = unix_sock_modesw(globals,
- (struct alfred_modeswitch_v0 *)packet,
- client_sock);
+ unix_sock_modesw(globals,
+ (struct alfred_modeswitch_v0 *)packet,
+ client_sock);
break;
case ALFRED_CHANGE_INTERFACE:
- ret = unix_sock_change_iface(globals,
- (struct alfred_change_interface_v0 *)packet,
- client_sock);
+ unix_sock_change_iface(globals,
+ (struct alfred_change_interface_v0 *)packet,
+ client_sock);
break;
case ALFRED_CHANGE_BAT_IFACE:
- ret = unix_sock_change_bat_iface(globals,
- (struct alfred_change_bat_iface_v0 *)packet,
- client_sock);
+ unix_sock_change_bat_iface(globals,
+ (struct alfred_change_bat_iface_v0 *)packet,
+ client_sock);
break;
case ALFRED_SERVER_STATUS:
- ret = unix_sock_server_status(globals, client_sock);
+ unix_sock_server_status(globals, client_sock);
break;
default:
/* unknown packet type */
- ret = -1;
goto err;
}
- return ret;
+ return;
err:
close(client_sock);
- return ret;
}
int unix_sock_close(struct globals *globals)