Use poll() instead of epoll() for ndhc-master.

This commit is contained in:
Nicholas J. Kain 2020-10-20 05:54:00 -04:00
parent af9d45719f
commit 4d33c00e04
6 changed files with 96 additions and 107 deletions

View File

@ -83,7 +83,6 @@ static void arp_min_close_fd(struct client_state_t cs[static 1])
{ {
if (cs->arpFd < 0) if (cs->arpFd < 0)
return; return;
epoll_del(cs->epollFd, cs->arpFd);
close(cs->arpFd); close(cs->arpFd);
cs->arpFd = -1; cs->arpFd = -1;
cs->arp_is_defense = false; cs->arp_is_defense = false;
@ -161,7 +160,6 @@ static int arp_open_fd(struct client_state_t cs[static 1], bool defense)
client_config.interface, __func__, strerror(errno)); client_config.interface, __func__, strerror(errno));
return -1; return -1;
} }
epoll_add(cs->epollFd, cs->arpFd);
return 0; return 0;
} }
@ -754,6 +752,8 @@ server_is_router:
bool arp_packet_get(struct client_state_t cs[static 1]) bool arp_packet_get(struct client_state_t cs[static 1])
{ {
if (cs->arpFd < 0)
return false;
struct arpMsg amsg; struct arpMsg amsg;
ssize_t r = 0; ssize_t r = 0;
size_t bytes_read = 0; size_t bytes_read = 0;

View File

@ -327,14 +327,12 @@ void start_dhcp_listen(struct client_state_t cs[static 1])
if (cs->listenFd < 0) if (cs->listenFd < 0)
suicide("%s: FATAL: Couldn't listen on socket: %s", suicide("%s: FATAL: Couldn't listen on socket: %s",
client_config.interface, strerror(errno)); client_config.interface, strerror(errno));
epoll_add(cs->epollFd, cs->listenFd);
} }
void stop_dhcp_listen(struct client_state_t cs[static 1]) void stop_dhcp_listen(struct client_state_t cs[static 1])
{ {
if (cs->listenFd < 0) if (cs->listenFd < 0)
return; return;
epoll_del(cs->epollFd, cs->listenFd);
close(cs->listenFd); close(cs->listenFd);
cs->listenFd = -1; cs->listenFd = -1;
} }

View File

@ -40,7 +40,7 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <sys/epoll.h> #include <poll.h>
#include <sys/prctl.h> #include <sys/prctl.h>
#include <net/if.h> #include <net/if.h>
#include <errno.h> #include <errno.h>
@ -73,7 +73,6 @@
struct client_state_t cs = { struct client_state_t cs = {
.program_init = true, .program_init = true,
.epollFd = -1,
.listenFd = -1, .listenFd = -1,
.arpFd = -1, .arpFd = -1,
.nlFd = -1, .nlFd = -1,
@ -279,33 +278,35 @@ static void do_ndhc_work(void)
static bool rfkill_set; // Is the rfkill switch set? static bool rfkill_set; // Is the rfkill switch set?
static bool rfkill_nl_carrier_wentup; // iface carrier changed to up during rfkill static bool rfkill_nl_carrier_wentup; // iface carrier changed to up during rfkill
struct dhcpmsg dhcp_packet; struct dhcpmsg dhcp_packet;
struct epoll_event events[1];
long long nowts; long long nowts;
int timeout = 0; int timeout = 0;
bool had_event; bool had_event;
cs.epollFd = epoll_create1(0);
if (cs.epollFd < 0)
suicide("epoll_create1 failed");
setup_signals_ndhc(); setup_signals_ndhc();
epoll_add(cs.epollFd, cs.nlFd);
epoll_add(cs.epollFd, ifchStream[0]);
epoll_add(cs.epollFd, sockdStream[0]);
if (client_config.enable_rfkill && cs.rfkillFd != -1)
epoll_add(cs.epollFd, cs.rfkillFd);
start_dhcp_listen(&cs); start_dhcp_listen(&cs);
struct pollfd pfds[6] = {0};
pfds[0].fd = cs.nlFd;
pfds[0].events = POLLIN|POLLHUP|POLLERR|POLLRDHUP;
pfds[1].fd = ifchStream[0];
pfds[1].events = POLLHUP|POLLERR|POLLRDHUP;
pfds[2].fd = sockdStream[0];
pfds[2].events = POLLHUP|POLLERR|POLLRDHUP;
pfds[3].fd = cs.rfkillFd;
pfds[3].events = POLLIN|POLLHUP|POLLERR|POLLRDHUP;
// These can change on the fly.
pfds[4].events = POLLIN|POLLHUP|POLLERR|POLLRDHUP;
pfds[5].events = POLLIN|POLLHUP|POLLERR|POLLRDHUP;
for (;;) { for (;;) {
pfds[4].fd = cs.arpFd;
pfds[5].fd = cs.listenFd;
had_event = false; had_event = false;
int maxi = epoll_wait(cs.epollFd, events, 1, timeout); if (poll(pfds, 6, timeout) < 0) {
if (maxi < 0) { if (errno == EINTR) continue;
if (errno == EINTR) else suicide("poll failed");
continue;
else
suicide("epoll_wait failed");
} }
bool sev_dhcp = false; bool sev_dhcp = false;
uint32_t dhcp_srcaddr; uint32_t dhcp_srcaddr;
uint8_t dhcp_msgtype; uint8_t dhcp_msgtype;
@ -313,34 +314,54 @@ static void do_ndhc_work(void)
int sev_nl = IFS_NONE; int sev_nl = IFS_NONE;
int sev_rfk = RFK_NONE; int sev_rfk = RFK_NONE;
bool force_fingerprint = false; bool force_fingerprint = false;
for (int i = 0; i < maxi; ++i) { if (pfds[0].revents & POLLIN) {
pfds[0].revents &= ~POLLIN;
had_event = true; had_event = true;
int fd = events[i].data.fd; sev_nl = nl_event_get(&cs);
if (fd == cs.listenFd) { }
if (!(events[i].events & EPOLLIN)) if (pfds[0].revents & (POLLHUP|POLLERR|POLLRDHUP)) {
suicide("listenfd closed unexpectedly"); pfds[0].revents &= ~(POLLHUP|POLLERR|POLLRDHUP);
suicide("nlfd closed unexpectedly");
}
if (pfds[1].revents & (POLLHUP|POLLERR|POLLRDHUP)) {
pfds[1].revents &= ~(POLLHUP|POLLERR|POLLRDHUP);
exit(EXIT_FAILURE);
}
if (pfds[2].revents & (POLLHUP|POLLERR|POLLRDHUP)) {
pfds[2].revents &= ~(POLLHUP|POLLERR|POLLRDHUP);
exit(EXIT_FAILURE);
}
if (pfds[3].revents & POLLIN) {
pfds[3].revents &= ~POLLIN;
had_event = true;
sev_rfk = rfkill_get(&cs, 1, client_config.rfkillIdx);
}
if (pfds[3].revents & (POLLHUP|POLLERR|POLLRDHUP)) {
pfds[3].revents &= ~(POLLHUP|POLLERR|POLLRDHUP);
suicide("rfkillfd closed unexpectedly");
}
if (pfds[4].revents & POLLIN) {
pfds[4].revents &= ~POLLIN;
had_event = true;
// Make sure the fd is still the same.
if (pfds[4].fd == cs.arpFd)
sev_arp = arp_packet_get(&cs);
}
if (pfds[4].revents & (POLLHUP|POLLERR|POLLRDHUP)) {
pfds[4].revents &= ~(POLLHUP|POLLERR|POLLRDHUP);
suicide("arpfd closed unexpectedly");
}
if (pfds[5].revents & POLLIN) {
pfds[5].revents &= ~POLLIN;
had_event = true;
// Make sure the fd is still the same.
if (pfds[5].fd == cs.listenFd)
sev_dhcp = dhcp_packet_get(&cs, &dhcp_packet, &dhcp_msgtype, sev_dhcp = dhcp_packet_get(&cs, &dhcp_packet, &dhcp_msgtype,
&dhcp_srcaddr); &dhcp_srcaddr);
} else if (fd == cs.arpFd) { }
if (!(events[i].events & EPOLLIN)) if (pfds[5].revents & (POLLHUP|POLLERR|POLLRDHUP)) {
suicide("arpfd closed unexpectedly"); pfds[5].revents &= ~(POLLHUP|POLLERR|POLLRDHUP);
sev_arp = arp_packet_get(&cs); suicide("listenfd closed unexpectedly");
} else if (fd == cs.nlFd) {
if (!(events[i].events & EPOLLIN))
suicide("nlfd closed unexpectedly");
sev_nl = nl_event_get(&cs);
} else if (fd == ifchStream[0]) {
if (events[i].events & (EPOLLHUP|EPOLLERR|EPOLLRDHUP))
exit(EXIT_FAILURE);
} else if (fd == sockdStream[0]) {
if (events[i].events & (EPOLLHUP|EPOLLERR|EPOLLRDHUP))
exit(EXIT_FAILURE);
} else if (fd == cs.rfkillFd && client_config.enable_rfkill) {
if (!(events[i].events & EPOLLIN))
suicide("rfkillfd closed unexpectedly");
sev_rfk = rfkill_get(&cs, 1, client_config.rfkillIdx);
} else
suicide("epoll_wait: unknown fd");
} }
if (sev_rfk == RFK_ENABLED) { if (sev_rfk == RFK_ENABLED) {
@ -371,6 +392,10 @@ static void do_ndhc_work(void)
continue; continue;
} }
// These two can change on the fly; make sure the event is current.
if (pfds[4].fd != cs.arpFd) sev_arp = false;
if (pfds[5].fd != cs.listenFd) sev_dhcp = false;
nowts = curms(); nowts = curms();
long long arp_wake_ts = arp_get_wake_ts(); long long arp_wake_ts = arp_get_wake_ts();
int dhcp_ok = dhcp_handle(&cs, nowts, sev_dhcp, &dhcp_packet, int dhcp_ok = dhcp_handle(&cs, nowts, sev_dhcp, &dhcp_packet,
@ -514,42 +539,37 @@ void background(void)
static void wait_for_rfkill() static void wait_for_rfkill()
{ {
struct epoll_event events[2];
cs.rfkillFd = rfkill_open(&client_config.enable_rfkill); cs.rfkillFd = rfkill_open(&client_config.enable_rfkill);
if (cs.rfkillFd < 0) if (cs.rfkillFd < 0)
suicide("can't wait for rfkill to end if /dev/rfkill can't be opened"); suicide("can't wait for rfkill to end if /dev/rfkill can't be opened");
int epfd = epoll_create1(0);
if (epfd < 0) struct pollfd pfds[1] = {0};
suicide("epoll_create1 failed"); pfds[0].events = POLLIN|POLLHUP|POLLERR|POLLRDHUP;
epoll_add(epfd, cs.rfkillFd);
for (;;) { for (;;) {
int r = epoll_wait(epfd, events, 2, -1); pfds[0].fd = cs.rfkillFd;
if (r < 0) { if (poll(pfds, 1, -1) < 0) {
if (errno == EINTR) if (errno == EINTR) continue;
continue; else suicide("poll failed");
else
suicide("epoll_wait failed");
} }
for (int i = 0; i < r; ++i) { if (pfds[0].revents & POLLIN) {
int fd = events[i].data.fd; pfds[0].revents &= ~POLLIN;
if (fd != cs.rfkillFd) if (rfkill_get(&cs, 0, 0) == RFK_DISABLED) {
suicide("epoll_wait: unknown fd"); switch (perform_ifup()) {
if (events[i].events & EPOLLIN) { case 1:
int rfk = rfkill_get(&cs, 0, 0); case 0: goto rfkill_gone;
if (rfk == RFK_DISABLED) { case -3:
switch (perform_ifup()) { log_line("rfkill: radio immediately blocked again; spurious?");
case 1: case 0: goto rfkill_gone; break;
case -3: default: suicide("failed to set the interface to up state");
log_line("rfkill: radio immediately blocked again; spurious?");
break;
default: suicide("failed to set the interface to up state");
}
} }
} }
} }
if (pfds[0].revents & (POLLHUP|POLLERR|POLLRDHUP)) {
pfds[0].revents &= ~(POLLHUP|POLLERR|POLLRDHUP);
suicide("rfkillFd closed unexpectedly");
}
} }
rfkill_gone: rfkill_gone:
close(epfd);
// We always close because ifchd and sockd shouldn't keep // We always close because ifchd and sockd shouldn't keep
// an rfkill fd open. // an rfkill fd open.
close(cs.rfkillFd); close(cs.rfkillFd);

View File

@ -45,7 +45,7 @@ struct client_state_t {
long long leaseStartTime, renewTime, rebindTime; long long leaseStartTime, renewTime, rebindTime;
long long dhcp_wake_ts; long long dhcp_wake_ts;
int ifDeconfig; // Set if the interface has already been deconfigured. int ifDeconfig; // Set if the interface has already been deconfigured.
int epollFd, listenFd, arpFd, nlFd, rfkillFd; int listenFd, arpFd, nlFd, rfkillFd;
int server_arp_sent, router_arp_sent; int server_arp_sent, router_arp_sent;
uint32_t nlPortId; uint32_t nlPortId;
unsigned int num_dhcp_requests, num_dhcp_renews; unsigned int num_dhcp_requests, num_dhcp_renews;

View File

@ -1,4 +1,4 @@
/* sys.c - linux-specific signal and epoll functions /* sys.c - misc portable functions
* *
* Copyright 2010-2020 Nicholas J. Kain <njkain at gmail dot com> * Copyright 2010-2020 Nicholas J. Kain <njkain at gmail dot com>
* All rights reserved. * All rights reserved.
@ -26,14 +26,11 @@
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <unistd.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <signal.h> #include <signal.h>
#include <sys/epoll.h> #include <time.h>
#include "nk/log.h" #include "nk/log.h"
#include "nk/io.h"
#include "ndhc.h" #include "ndhc.h"
#include "sys.h" #include "sys.h"
@ -47,28 +44,6 @@ long long IMPL_curms(const char *parent_function)
return ts.tv_sec * 1000LL + ts.tv_nsec / 1000000LL; return ts.tv_sec * 1000LL + ts.tv_nsec / 1000000LL;
} }
void epoll_add(int epfd, int fd)
{
struct epoll_event ev;
int r;
ev.events = EPOLLIN | EPOLLRDHUP | EPOLLERR | EPOLLHUP;
ev.data.fd = fd;
r = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);
if (r < 0)
suicide("epoll_add failed %s", strerror(errno));
}
void epoll_del(int epfd, int fd)
{
struct epoll_event ev;
int r;
ev.events = EPOLLIN | EPOLLRDHUP | EPOLLERR | EPOLLHUP;
ev.data.fd = fd;
r = epoll_ctl(epfd, EPOLL_CTL_DEL, fd, &ev);
if (r < 0)
suicide("epoll_del failed %s", strerror(errno));
}
void setup_signals_subprocess(void) void setup_signals_subprocess(void)
{ {
sigset_t mask; sigset_t mask;

View File

@ -1,4 +1,4 @@
/* sys.h - linux-specific signal and epoll functions /* sys.h - misc portable functions
* *
* Copyright 2010-2020 Nicholas J. Kain <njkain at gmail dot com> * Copyright 2010-2020 Nicholas J. Kain <njkain at gmail dot com>
* All rights reserved. * All rights reserved.
@ -28,7 +28,6 @@
#ifndef SYS_H_ #ifndef SYS_H_
#define SYS_H_ #define SYS_H_
#include <time.h>
#include "ndhc-defines.h" #include "ndhc-defines.h"
static inline size_t min_size_t(size_t a, size_t b) static inline size_t min_size_t(size_t a, size_t b)
@ -38,11 +37,8 @@ static inline size_t min_size_t(size_t a, size_t b)
#define curms() IMPL_curms(__func__) #define curms() IMPL_curms(__func__)
long long IMPL_curms(const char *parent_function); long long IMPL_curms(const char *parent_function);
void epoll_add(int epfd, int fd);
void epoll_del(int epfd, int fd);
void setup_signals_subprocess(void); void setup_signals_subprocess(void);
void signal_dispatch_subprocess(int sfd, const char pname[static 1]);
#endif /* SYS_H_ */ #endif /* SYS_H_ */