Use poll() instead of select() to remove limits on open file descriptors.

This commit is contained in:
Simon Kelley
2015-07-12 21:09:11 +01:00
parent 0f38fa05a6
commit b842bc97bb
10 changed files with 216 additions and 137 deletions

View File

@@ -73,7 +73,7 @@ objs = cache.o rfc1035.o util.o option.o forward.o network.o \
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \ dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \ helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \ dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \
domain.o dnssec.o blockdata.o tables.o loop.o inotify.o domain.o dnssec.o blockdata.o tables.o loop.o inotify.o poll.o
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \ hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
dns-protocol.h radv-protocol.h ip6addr.h dns-protocol.h radv-protocol.h ip6addr.h

View File

@@ -10,7 +10,7 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
dhcp6.c rfc3315.c dhcp-common.c outpacket.c \ dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
radv.c slaac.c auth.c ipset.c domain.c \ radv.c slaac.c auth.c ipset.c domain.c \
dnssec.c dnssec-openssl.c blockdata.c tables.c \ dnssec.c dnssec-openssl.c blockdata.c tables.c \
loop.c inotify.c loop.c inotify.c poll.c
LOCAL_MODULE := dnsmasq LOCAL_MODULE := dnsmasq

View File

@@ -749,8 +749,7 @@ char *dbus_init(void)
} }
void set_dbus_listeners(int *maxfdp, void set_dbus_listeners(void)
fd_set *rset, fd_set *wset, fd_set *eset)
{ {
struct watch *w; struct watch *w;
@@ -761,16 +760,16 @@ void set_dbus_listeners(int *maxfdp,
int fd = dbus_watch_get_unix_fd(w->watch); int fd = dbus_watch_get_unix_fd(w->watch);
if (flags & DBUS_WATCH_READABLE) if (flags & DBUS_WATCH_READABLE)
bump_maxfd(rset, fd, maxfdp); poll_listen(fd, POLLIN);
if (flags & DBUS_WATCH_WRITABLE) if (flags & DBUS_WATCH_WRITABLE)
bump_maxfd(wset, fd, maxfdp); poll_listen(fd, POLLOUT);
bump_maxfd(eset, fd, maxfdp); poll_listen(fd, POLLERR);
} }
} }
void check_dbus_listeners(fd_set *rset, fd_set *wset, fd_set *eset) void check_dbus_listeners()
{ {
DBusConnection *connection = (DBusConnection *)daemon->dbus; DBusConnection *connection = (DBusConnection *)daemon->dbus;
struct watch *w; struct watch *w;
@@ -781,13 +780,13 @@ void check_dbus_listeners(fd_set *rset, fd_set *wset, fd_set *eset)
unsigned int flags = 0; unsigned int flags = 0;
int fd = dbus_watch_get_unix_fd(w->watch); int fd = dbus_watch_get_unix_fd(w->watch);
if (FD_ISSET(fd, rset)) if (poll_check(fd, POLLIN))
flags |= DBUS_WATCH_READABLE; flags |= DBUS_WATCH_READABLE;
if (FD_ISSET(fd, wset)) if (poll_check(fd, POLLOUT))
flags |= DBUS_WATCH_WRITABLE; flags |= DBUS_WATCH_WRITABLE;
if (FD_ISSET(fd, eset)) if (poll_check(fd, POLLERR))
flags |= DBUS_WATCH_ERROR; flags |= DBUS_WATCH_ERROR;
if (flags != 0) if (flags != 0)

View File

@@ -24,8 +24,8 @@ struct daemon *daemon;
static volatile pid_t pid = 0; static volatile pid_t pid = 0;
static volatile int pipewrite; static volatile int pipewrite;
static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp); static int set_dns_listeners(time_t now);
static void check_dns_listeners(fd_set *set, time_t now); static void check_dns_listeners(time_t now);
static void sig_handler(int sig); static void sig_handler(int sig);
static void async_event(int pipe, time_t now); static void async_event(int pipe, time_t now);
static void fatal_event(struct event_desc *ev, char *msg); static void fatal_event(struct event_desc *ev, char *msg);
@@ -799,10 +799,6 @@ int main (int argc, char **argv)
if (option_bool(OPT_TFTP)) if (option_bool(OPT_TFTP))
{ {
struct tftp_prefix *p; struct tftp_prefix *p;
#ifdef FD_SETSIZE
if (FD_SETSIZE < (unsigned)max_fd)
max_fd = FD_SETSIZE;
#endif
my_syslog(MS_TFTP | LOG_INFO, "TFTP %s%s %s", my_syslog(MS_TFTP | LOG_INFO, "TFTP %s%s %s",
daemon->tftp_prefix ? _("root is ") : _("enabled"), daemon->tftp_prefix ? _("root is ") : _("enabled"),
@@ -862,72 +858,58 @@ int main (int argc, char **argv)
while (1) while (1)
{ {
int maxfd = -1; int t, timeout = -1;
struct timeval t, *tp = NULL;
fd_set rset, wset, eset;
FD_ZERO(&rset); poll_reset();
FD_ZERO(&wset);
FD_ZERO(&eset);
/* if we are out of resources, find how long we have to wait /* if we are out of resources, find how long we have to wait
for some to come free, we'll loop around then and restart for some to come free, we'll loop around then and restart
listening for queries */ listening for queries */
if ((t.tv_sec = set_dns_listeners(now, &rset, &maxfd)) != 0) if ((t = set_dns_listeners(now)) != 0)
{ timeout = t * 1000;
t.tv_usec = 0;
tp = &t;
}
/* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */ /* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */
if (daemon->tftp_trans || if (daemon->tftp_trans ||
(option_bool(OPT_DBUS) && !daemon->dbus)) (option_bool(OPT_DBUS) && !daemon->dbus))
{ timeout = 250;
t.tv_sec = 0;
t.tv_usec = 250000;
tp = &t;
}
/* Wake every second whilst waiting for DAD to complete */ /* Wake every second whilst waiting for DAD to complete */
else if (is_dad_listeners()) else if (is_dad_listeners())
{ timeout = 1000;
t.tv_sec = 1;
t.tv_usec = 0;
tp = &t;
}
#ifdef HAVE_DBUS #ifdef HAVE_DBUS
set_dbus_listeners(&maxfd, &rset, &wset, &eset); set_dbus_listeners();
#endif #endif
#ifdef HAVE_DHCP #ifdef HAVE_DHCP
if (daemon->dhcp || daemon->relay4) if (daemon->dhcp || daemon->relay4)
{ {
bump_maxfd(&rset, daemon->dhcpfd, &maxfd); poll_listen(daemon->dhcpfd, POLLIN);
if (daemon->pxefd != -1) if (daemon->pxefd != -1)
bump_maxfd(&rset, daemon->pxefd, &maxfd); poll_listen(daemon->pxefd, POLLIN);
} }
#endif #endif
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
if (daemon->doing_dhcp6 || daemon->relay6) if (daemon->doing_dhcp6 || daemon->relay6)
bump_maxfd(&rset, daemon->dhcp6fd, &maxfd); poll_listen(daemon->dhcp6fd, POLLIN);
if (daemon->doing_ra) if (daemon->doing_ra)
bump_maxfd(&rset, daemon->icmp6fd, &maxfd); poll_listen(daemon->icmp6fd, POLLIN);
#endif #endif
#ifdef HAVE_INOTIFY #ifdef HAVE_INOTIFY
if (daemon->inotifyfd != -1) if (daemon->inotifyfd != -1)
bump_maxfd(&rset, daemon->inotifyfd, &maxfd); poll_listen(daemon->inotifyfd, POLLIN);
#endif #endif
#if defined(HAVE_LINUX_NETWORK) #if defined(HAVE_LINUX_NETWORK)
bump_maxfd(&rset, daemon->netlinkfd, &maxfd); poll_listen(daemon->netlinkfd, POLLIN);
#elif defined(HAVE_BSD_NETWORK) #elif defined(HAVE_BSD_NETWORK)
bump_maxfd(&rset, daemon->routefd, &maxfd); poll_listen(daemon->routefd, POLLIN);
#endif #endif
bump_maxfd(&rset, piperead, &maxfd); poll_listen(piperead, POLLIN);
#ifdef HAVE_DHCP #ifdef HAVE_DHCP
# ifdef HAVE_SCRIPT # ifdef HAVE_SCRIPT
@@ -938,7 +920,7 @@ int main (int argc, char **argv)
# endif # endif
if (!helper_buf_empty()) if (!helper_buf_empty())
bump_maxfd(&wset, daemon->helperfd, &maxfd); poll_listen(daemon->helperfd, POLLOUT);
# else # else
/* need this for other side-effects */ /* need this for other side-effects */
while (do_script_run(now)); while (do_script_run(now));
@@ -952,17 +934,14 @@ int main (int argc, char **argv)
/* must do this just before select(), when we know no /* must do this just before select(), when we know no
more calls to my_syslog() can occur */ more calls to my_syslog() can occur */
set_log_writer(&wset, &maxfd); set_log_writer();
if (do_poll(timeout) < 0)
continue;
if (select(maxfd+1, &rset, &wset, &eset, tp) < 0)
{
/* otherwise undefined after error */
FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset);
}
now = dnsmasq_time(); now = dnsmasq_time();
check_log_writer(&wset); check_log_writer(0);
/* prime. */ /* prime. */
enumerate_interfaces(1); enumerate_interfaces(1);
@@ -978,15 +957,15 @@ int main (int argc, char **argv)
} }
#if defined(HAVE_LINUX_NETWORK) #if defined(HAVE_LINUX_NETWORK)
if (FD_ISSET(daemon->netlinkfd, &rset)) if (poll_check(daemon->netlinkfd, POLLIN))
netlink_multicast(); netlink_multicast();
#elif defined(HAVE_BSD_NETWORK) #elif defined(HAVE_BSD_NETWORK)
if (FD_ISSET(daemon->routefd, &rset)) if (poll_check(daemon->routefd, POLLIN))
route_sock(); route_sock();
#endif #endif
#ifdef HAVE_INOTIFY #ifdef HAVE_INOTIFY
if (daemon->inotifyfd != -1 && FD_ISSET(daemon->inotifyfd, &rset) && inotify_check(now)) if (daemon->inotifyfd != -1 && poll_check(daemon->inotifyfd, POLLIN) && inotify_check(now))
{ {
if (daemon->port != 0 && !option_bool(OPT_NO_POLL)) if (daemon->port != 0 && !option_bool(OPT_NO_POLL))
poll_resolv(1, 1, now); poll_resolv(1, 1, now);
@@ -1006,7 +985,7 @@ int main (int argc, char **argv)
} }
#endif #endif
if (FD_ISSET(piperead, &rset)) if (poll_check(piperead, POLLIN))
async_event(piperead, now); async_event(piperead, now);
#ifdef HAVE_DBUS #ifdef HAVE_DBUS
@@ -1019,34 +998,34 @@ int main (int argc, char **argv)
if (daemon->dbus) if (daemon->dbus)
my_syslog(LOG_INFO, _("connected to system DBus")); my_syslog(LOG_INFO, _("connected to system DBus"));
} }
check_dbus_listeners(&rset, &wset, &eset); check_dbus_listeners();
#endif #endif
check_dns_listeners(&rset, now); check_dns_listeners(now);
#ifdef HAVE_TFTP #ifdef HAVE_TFTP
check_tftp_listeners(&rset, now); check_tftp_listeners(now);
#endif #endif
#ifdef HAVE_DHCP #ifdef HAVE_DHCP
if (daemon->dhcp || daemon->relay4) if (daemon->dhcp || daemon->relay4)
{ {
if (FD_ISSET(daemon->dhcpfd, &rset)) if (poll_check(daemon->dhcpfd, POLLIN))
dhcp_packet(now, 0); dhcp_packet(now, 0);
if (daemon->pxefd != -1 && FD_ISSET(daemon->pxefd, &rset)) if (daemon->pxefd != -1 && poll_check(daemon->pxefd, POLLIN))
dhcp_packet(now, 1); dhcp_packet(now, 1);
} }
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
if ((daemon->doing_dhcp6 || daemon->relay6) && FD_ISSET(daemon->dhcp6fd, &rset)) if ((daemon->doing_dhcp6 || daemon->relay6) && poll_check(daemon->dhcp6fd, POLLIN))
dhcp6_packet(now); dhcp6_packet(now);
if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset)) if (daemon->doing_ra && poll_check(daemon->icmp6fd, POLLIN))
icmp6_packet(now); icmp6_packet(now);
#endif #endif
# ifdef HAVE_SCRIPT # ifdef HAVE_SCRIPT
if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset)) if (daemon->helperfd != -1 && poll_check(daemon->helperfd, POLLIN))
helper_write(); helper_write();
# endif # endif
#endif #endif
@@ -1451,7 +1430,7 @@ void clear_cache_and_reload(time_t now)
#endif #endif
} }
static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp) static int set_dns_listeners(time_t now)
{ {
struct serverfd *serverfdp; struct serverfd *serverfdp;
struct listener *listener; struct listener *listener;
@@ -1463,7 +1442,7 @@ static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next) for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)
{ {
tftp++; tftp++;
bump_maxfd(set, transfer->sockfd, maxfdp); poll_listen(transfer->sockfd, POLLIN);
} }
#endif #endif
@@ -1472,18 +1451,18 @@ static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
get_new_frec(now, &wait, 0); get_new_frec(now, &wait, 0);
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next) for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
bump_maxfd(set, serverfdp->fd, maxfdp); poll_listen(serverfdp->fd, POLLIN);
if (daemon->port != 0 && !daemon->osport) if (daemon->port != 0 && !daemon->osport)
for (i = 0; i < RANDOM_SOCKS; i++) for (i = 0; i < RANDOM_SOCKS; i++)
if (daemon->randomsocks[i].refcount != 0) if (daemon->randomsocks[i].refcount != 0)
bump_maxfd(set, daemon->randomsocks[i].fd, maxfdp); poll_listen(daemon->randomsocks[i].fd, POLLIN);
for (listener = daemon->listeners; listener; listener = listener->next) for (listener = daemon->listeners; listener; listener = listener->next)
{ {
/* only listen for queries if we have resources */ /* only listen for queries if we have resources */
if (listener->fd != -1 && wait == 0) if (listener->fd != -1 && wait == 0)
bump_maxfd(set, listener->fd, maxfdp); poll_listen(listener->fd, POLLIN);
/* death of a child goes through the select loop, so /* death of a child goes through the select loop, so
we don't need to explicitly arrange to wake up here */ we don't need to explicitly arrange to wake up here */
@@ -1491,13 +1470,13 @@ static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
for (i = 0; i < MAX_PROCS; i++) for (i = 0; i < MAX_PROCS; i++)
if (daemon->tcp_pids[i] == 0) if (daemon->tcp_pids[i] == 0)
{ {
bump_maxfd(set, listener->tcpfd, maxfdp); poll_listen(listener->tcpfd, POLLIN);
break; break;
} }
#ifdef HAVE_TFTP #ifdef HAVE_TFTP
if (tftp <= daemon->tftp_max && listener->tftpfd != -1) if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
bump_maxfd(set, listener->tftpfd, maxfdp); poll_listen(listener->tftpfd, POLLIN);
#endif #endif
} }
@@ -1505,33 +1484,33 @@ static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
return wait; return wait;
} }
static void check_dns_listeners(fd_set *set, time_t now) static void check_dns_listeners(time_t now)
{ {
struct serverfd *serverfdp; struct serverfd *serverfdp;
struct listener *listener; struct listener *listener;
int i; int i;
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next) for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
if (FD_ISSET(serverfdp->fd, set)) if (poll_check(serverfdp->fd, POLLIN))
reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now); reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
if (daemon->port != 0 && !daemon->osport) if (daemon->port != 0 && !daemon->osport)
for (i = 0; i < RANDOM_SOCKS; i++) for (i = 0; i < RANDOM_SOCKS; i++)
if (daemon->randomsocks[i].refcount != 0 && if (daemon->randomsocks[i].refcount != 0 &&
FD_ISSET(daemon->randomsocks[i].fd, set)) poll_check(daemon->randomsocks[i].fd, POLLIN))
reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now); reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
for (listener = daemon->listeners; listener; listener = listener->next) for (listener = daemon->listeners; listener; listener = listener->next)
{ {
if (listener->fd != -1 && FD_ISSET(listener->fd, set)) if (listener->fd != -1 && poll_check(listener->fd, POLLIN))
receive_query(listener, now); receive_query(listener, now);
#ifdef HAVE_TFTP #ifdef HAVE_TFTP
if (listener->tftpfd != -1 && FD_ISSET(listener->tftpfd, set)) if (listener->tftpfd != -1 && poll_check(listener->tftpfd, POLLIN))
tftp_request(listener, now); tftp_request(listener, now);
#endif #endif
if (listener->tcpfd != -1 && FD_ISSET(listener->tcpfd, set)) if (listener->tcpfd != -1 && poll_check(listener->tcpfd, POLLIN))
{ {
int confd, client_ok = 1; int confd, client_ok = 1;
struct irec *iface = NULL; struct irec *iface = NULL;
@@ -1772,51 +1751,41 @@ int icmp_ping(struct in_addr addr)
for (now = start = dnsmasq_time(), timeout_count = 0; for (now = start = dnsmasq_time(), timeout_count = 0;
(difftime(now, start) < (float)PING_WAIT) && (timeout_count < PING_WAIT * 4);) (difftime(now, start) < (float)PING_WAIT) && (timeout_count < PING_WAIT * 4);)
{ {
struct timeval tv;
fd_set rset, wset;
struct sockaddr_in faddr; struct sockaddr_in faddr;
int maxfd = fd;
socklen_t len = sizeof(faddr); socklen_t len = sizeof(faddr);
tv.tv_usec = 250000; poll_reset();
tv.tv_sec = 0; poll_listen(fd, POLLIN);
set_dns_listeners(now);
FD_ZERO(&rset); set_log_writer();
FD_ZERO(&wset);
FD_SET(fd, &rset);
set_dns_listeners(now, &rset, &maxfd);
set_log_writer(&wset, &maxfd);
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
if (daemon->doing_ra) if (daemon->doing_ra)
bump_maxfd(&rset, daemon->icmp6fd, &maxfd); poll_listen(daemon->icmp6fd, POLLIN);
#endif #endif
rc = select(maxfd+1, &rset, &wset, NULL, &tv); rc = do_poll(250);
if (rc < 0) if (rc < 0)
{ continue;
FD_ZERO(&rset);
FD_ZERO(&wset);
}
else if (rc == 0) else if (rc == 0)
timeout_count++; timeout_count++;
now = dnsmasq_time(); now = dnsmasq_time();
check_log_writer(&wset); check_log_writer(0);
check_dns_listeners(&rset, now); check_dns_listeners(now);
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset)) if (daemon->doing_ra && poll_check(daemon->icmp6fd, POLLIN))
icmp6_packet(now); icmp6_packet(now);
#endif #endif
#ifdef HAVE_TFTP #ifdef HAVE_TFTP
check_tftp_listeners(&rset, now); check_tftp_listeners(now);
#endif #endif
if (FD_ISSET(fd, &rset) && if (poll_check(fd, POLLIN) &&
recvfrom(fd, &packet, sizeof(packet), 0, recvfrom(fd, &packet, sizeof(packet), 0,
(struct sockaddr *)&faddr, &len) == sizeof(packet) && (struct sockaddr *)&faddr, &len) == sizeof(packet) &&
saddr.sin_addr.s_addr == faddr.sin_addr.s_addr && saddr.sin_addr.s_addr == faddr.sin_addr.s_addr &&

View File

@@ -82,7 +82,7 @@ typedef unsigned long long u64;
#if defined(HAVE_SOLARIS_NETWORK) #if defined(HAVE_SOLARIS_NETWORK)
# include <sys/sockio.h> # include <sys/sockio.h>
#endif #endif
#include <sys/select.h> #include <sys/poll.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/un.h> #include <sys/un.h>
@@ -1191,7 +1191,6 @@ int memcmp_masked(unsigned char *a, unsigned char *b, int len,
unsigned int mask); unsigned int mask);
int expand_buf(struct iovec *iov, size_t size); int expand_buf(struct iovec *iov, size_t size);
char *print_mac(char *buff, unsigned char *mac, int len); char *print_mac(char *buff, unsigned char *mac, int len);
void bump_maxfd(fd_set *set, int fd, int *max);
int read_write(int fd, unsigned char *packet, int size, int rw); int read_write(int fd, unsigned char *packet, int size, int rw);
int wildcard_match(const char* wildcard, const char* match); int wildcard_match(const char* wildcard, const char* match);
@@ -1202,8 +1201,8 @@ void die(char *message, char *arg1, int exit_code);
int log_start(struct passwd *ent_pw, int errfd); int log_start(struct passwd *ent_pw, int errfd);
int log_reopen(char *log_file); int log_reopen(char *log_file);
void my_syslog(int priority, const char *format, ...); void my_syslog(int priority, const char *format, ...);
void set_log_writer(fd_set *set, int *maxfdp); void set_log_writer(void);
void check_log_writer(fd_set *set); void check_log_writer(int force);
void flush_log(void); void flush_log(void);
/* option.c */ /* option.c */
@@ -1366,8 +1365,8 @@ int iface_enumerate(int family, void *parm, int (callback)());
/* dbus.c */ /* dbus.c */
#ifdef HAVE_DBUS #ifdef HAVE_DBUS
char *dbus_init(void); char *dbus_init(void);
void check_dbus_listeners(fd_set *rset, fd_set *wset, fd_set *eset); void check_dbus_listeners(void);
void set_dbus_listeners(int *maxfdp, fd_set *rset, fd_set *wset, fd_set *eset); void set_dbus_listeners(void);
# ifdef HAVE_DHCP # ifdef HAVE_DHCP
void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname); void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname);
# endif # endif
@@ -1394,7 +1393,7 @@ int helper_buf_empty(void);
/* tftp.c */ /* tftp.c */
#ifdef HAVE_TFTP #ifdef HAVE_TFTP
void tftp_request(struct listener *listen, time_t now); void tftp_request(struct listener *listen, time_t now);
void check_tftp_listeners(fd_set *rset, time_t now); void check_tftp_listeners(time_t now);
int do_tftp_script_run(void); int do_tftp_script_run(void);
#endif #endif
@@ -1511,3 +1510,10 @@ void inotify_dnsmasq_init();
int inotify_check(time_t now); int inotify_check(time_t now);
void set_dynamic_inotify(int flag, int total_size, struct crec **rhash, int revhashsz); void set_dynamic_inotify(int flag, int total_size, struct crec **rhash, int revhashsz);
#endif #endif
/* poll.c */
void poll_reset(void);
int poll_check(int fd, short event);
void poll_listen(int fd, short event);
int do_poll(int timeout);

View File

@@ -1887,7 +1887,7 @@ unsigned char *tcp_request(int confd, time_t now,
dst_addr_4, netmask, now, &ad_question, &do_bit); dst_addr_4, netmask, now, &ad_question, &do_bit);
/* Do this by steam now we're not in the select() loop */ /* Do this by steam now we're not in the select() loop */
check_log_writer(NULL); check_log_writer(1);
if (m == 0) if (m == 0)
{ {
@@ -2108,7 +2108,7 @@ unsigned char *tcp_request(int confd, time_t now,
} }
} }
check_log_writer(NULL); check_log_writer(1);
*length = htons(m); *length = htons(m);

View File

@@ -421,15 +421,15 @@ void my_syslog(int priority, const char *format, ...)
} }
} }
void set_log_writer(fd_set *set, int *maxfdp) void set_log_writer(void)
{ {
if (entries && log_fd != -1 && connection_good) if (entries && log_fd != -1 && connection_good)
bump_maxfd(set, log_fd, maxfdp); poll_listen(log_fd, POLLOUT);
} }
void check_log_writer(fd_set *set) void check_log_writer(int force)
{ {
if (log_fd != -1 && (!set || FD_ISSET(log_fd, set))) if (log_fd != -1 && (force || poll_check(log_fd, POLLOUT)))
log_write(); log_write();
} }

124
src/poll.c Normal file
View File

@@ -0,0 +1,124 @@
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 dated June, 1991, or
(at your option) version 3 dated 29 June, 2007.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dnsmasq.h"
/* Wrapper for poll(). Allocates and extends array of struct pollfds,
keeps them in fd order so that we can set and test conditions on
fd using a simple but efficient binary chop. */
/* poll_reset()
poll_listen(fd, event)
.
.
poll_listen(fd, event);
hits = do_poll(timeout);
if (poll_check(fd, event)
.
.
if (poll_check(fd, event)
.
.
event is OR of POLLIN, POLLOUT, POLLERR, etc
*/
static struct pollfd *pollfds = NULL;
static nfds_t nfds, arrsize = 0;
/* Binary search. Returns either the pollfd with fd, or
if the fd doesn't match, or return equals nfds, the entry
to the left of which a new record should be inserted. */
static nfds_t fd_search(int fd)
{
nfds_t left, right, mid;
if ((right = nfds) == 0)
return 0;
left = 0;
while (1)
{
if (right == left + 1)
return (pollfds[left].fd >= fd) ? left : right;
mid = (left + right)/2;
if (pollfds[mid].fd > fd)
right = mid;
else
left = mid;
}
}
void poll_reset(void)
{
nfds = 0;
}
int do_poll(int timeout)
{
return poll(pollfds, nfds, timeout);
}
int poll_check(int fd, short event)
{
nfds_t i = fd_search(fd);
if (i < nfds && pollfds[i].fd == fd)
return pollfds[i].revents & event;
return 0;
}
void poll_listen(int fd, short event)
{
nfds_t i = fd_search(fd);
if (i < nfds && pollfds[i].fd == fd)
pollfds[i].events |= event;
else
{
if (arrsize != nfds)
memmove(&pollfds[i+1], &pollfds[i], (nfds - i) * sizeof(struct pollfd));
else
{
/* Array too small, extend. */
struct pollfd *new;
arrsize += 64;
if (!(new = whine_malloc(arrsize * sizeof(struct pollfd))))
return;
if (pollfds)
{
memcpy(new, pollfds, i * sizeof(struct pollfd));
memcpy(&new[i+1], &pollfds[i], (nfds - i) * sizeof(struct pollfd));
free(pollfds);
}
pollfds = new;
}
pollfds[i].fd = fd;
pollfds[i].events = event;
nfds++;
}
}

View File

@@ -502,7 +502,7 @@ static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix)
return NULL; return NULL;
} }
void check_tftp_listeners(fd_set *rset, time_t now) void check_tftp_listeners(time_t now)
{ {
struct tftp_transfer *transfer, *tmp, **up; struct tftp_transfer *transfer, *tmp, **up;
ssize_t len; ssize_t len;
@@ -518,7 +518,7 @@ void check_tftp_listeners(fd_set *rset, time_t now)
prettyprint_addr(&transfer->peer, daemon->addrbuff); prettyprint_addr(&transfer->peer, daemon->addrbuff);
if (FD_ISSET(transfer->sockfd, rset)) if (poll_check(transfer->sockfd, POLLIN))
{ {
/* we overwrote the buffer... */ /* we overwrote the buffer... */
daemon->srv_save = NULL; daemon->srv_save = NULL;

View File

@@ -570,25 +570,6 @@ char *print_mac(char *buff, unsigned char *mac, int len)
return buff; return buff;
} }
void bump_maxfd(fd_set *set, int fd, int *max)
{
#ifdef FD_SETSIZE
if (fd >= FD_SETSIZE)
{
static int logged = 0;
if (!logged)
my_syslog(LOG_ERR, _("File descriptor overflows FD_SET"));
logged = 1;
}
else
#endif
{
FD_SET(fd, set);
if (fd > *max)
*max = fd;
}
}
/* rc is return from sendto and friends. /* rc is return from sendto and friends.
Return 1 if we should retry. Return 1 if we should retry.
Set errno to zero if we succeeded. */ Set errno to zero if we succeeded. */