Commit b842bc97 authored by Simon Kelley's avatar Simon Kelley

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

parent 0f38fa05
......@@ -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 \
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 \
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 \
dns-protocol.h radv-protocol.h ip6addr.h
......
......@@ -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 \
radv.c slaac.c auth.c ipset.c domain.c \
dnssec.c dnssec-openssl.c blockdata.c tables.c \
loop.c inotify.c
loop.c inotify.c poll.c
LOCAL_MODULE := dnsmasq
......
......@@ -749,8 +749,7 @@ char *dbus_init(void)
}
void set_dbus_listeners(int *maxfdp,
fd_set *rset, fd_set *wset, fd_set *eset)
void set_dbus_listeners(void)
{
struct watch *w;
......@@ -761,16 +760,16 @@ void set_dbus_listeners(int *maxfdp,
int fd = dbus_watch_get_unix_fd(w->watch);
if (flags & DBUS_WATCH_READABLE)
bump_maxfd(rset, fd, maxfdp);
poll_listen(fd, POLLIN);
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;
struct watch *w;
......@@ -781,13 +780,13 @@ void check_dbus_listeners(fd_set *rset, fd_set *wset, fd_set *eset)
unsigned int flags = 0;
int fd = dbus_watch_get_unix_fd(w->watch);
if (FD_ISSET(fd, rset))
if (poll_check(fd, POLLIN))
flags |= DBUS_WATCH_READABLE;
if (FD_ISSET(fd, wset))
if (poll_check(fd, POLLOUT))
flags |= DBUS_WATCH_WRITABLE;
if (FD_ISSET(fd, eset))
if (poll_check(fd, POLLERR))
flags |= DBUS_WATCH_ERROR;
if (flags != 0)
......
This diff is collapsed.
......@@ -82,7 +82,7 @@ typedef unsigned long long u64;
#if defined(HAVE_SOLARIS_NETWORK)
# include <sys/sockio.h>
#endif
#include <sys/select.h>
#include <sys/poll.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/un.h>
......@@ -1191,7 +1191,6 @@ int memcmp_masked(unsigned char *a, unsigned char *b, int len,
unsigned int mask);
int expand_buf(struct iovec *iov, size_t size);
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 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_reopen(char *log_file);
void my_syslog(int priority, const char *format, ...);
void set_log_writer(fd_set *set, int *maxfdp);
void check_log_writer(fd_set *set);
void set_log_writer(void);
void check_log_writer(int force);
void flush_log(void);
/* option.c */
......@@ -1366,8 +1365,8 @@ int iface_enumerate(int family, void *parm, int (callback)());
/* dbus.c */
#ifdef HAVE_DBUS
char *dbus_init(void);
void check_dbus_listeners(fd_set *rset, fd_set *wset, fd_set *eset);
void set_dbus_listeners(int *maxfdp, fd_set *rset, fd_set *wset, fd_set *eset);
void check_dbus_listeners(void);
void set_dbus_listeners(void);
# ifdef HAVE_DHCP
void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname);
# endif
......@@ -1394,7 +1393,7 @@ int helper_buf_empty(void);
/* tftp.c */
#ifdef HAVE_TFTP
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);
#endif
......@@ -1511,3 +1510,10 @@ void inotify_dnsmasq_init();
int inotify_check(time_t now);
void set_dynamic_inotify(int flag, int total_size, struct crec **rhash, int revhashsz);
#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);
......@@ -1887,7 +1887,7 @@ unsigned char *tcp_request(int confd, time_t now,
dst_addr_4, netmask, now, &ad_question, &do_bit);
/* Do this by steam now we're not in the select() loop */
check_log_writer(NULL);
check_log_writer(1);
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);
......
......@@ -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)
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();
}
......
/* 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++;
}
}
......@@ -502,7 +502,7 @@ static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix)
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;
ssize_t len;
......@@ -518,7 +518,7 @@ void check_tftp_listeners(fd_set *rset, time_t now)
prettyprint_addr(&transfer->peer, daemon->addrbuff);
if (FD_ISSET(transfer->sockfd, rset))
if (poll_check(transfer->sockfd, POLLIN))
{
/* we overwrote the buffer... */
daemon->srv_save = NULL;
......
......@@ -570,25 +570,6 @@ char *print_mac(char *buff, unsigned char *mac, int len)
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.
Return 1 if we should retry.
Set errno to zero if we succeeded. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment