This converts spamd from select() to poll(). It might be a little
cleaner to embed a pointer to the pfd in struct con to avoid the
"pfd[PFD_FIRSTCON + i]" bits but I don't think it is a big deal.
The numcon bit is just to prevent the kernel from having to copy
and inspect a lot of unused entries.
- todd
Index: libexec/spamd/spamd.c
===================================================================
RCS file: /cvs/src/libexec/spamd/spamd.c,v
retrieving revision 1.117
diff -u -r1.117 spamd.c
--- libexec/spamd/spamd.c 29 Dec 2014 20:39:27 -0000 1.117
+++ libexec/spamd/spamd.c 30 Dec 2014 00:02:44 -0000
@@ -29,6 +29,7 @@
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
+#include <poll.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
@@ -1031,13 +1032,21 @@
return(maxfiles - 200);
}
+/* Symbolic indexes for pfd[] below */
+#define PFD_SMTPLISTEN 0
+#define PFD_CONFLISTEN 1
+#define PFD_SYNCFD 2
+#define PFD_CONFFD 3
+#define PFD_TRAPFD 4
+#define PFD_FIRSTCON 5
+
int
main(int argc, char *argv[])
{
- fd_set *fdsr = NULL, *fdsw = NULL;
+ struct pollfd *pfd;
struct sockaddr_in sin;
struct sockaddr_in lin;
- int ch, s, conflisten = 0, syncfd = 0, i, omax = 0, one = 1;
+ int ch, smtplisten, conflisten, syncfd = -1, i, one = 1;
u_short port;
long long passt, greyt, whitet;
struct servent *ent;
@@ -1192,11 +1201,11 @@
signal(SIGPIPE, SIG_IGN);
- s = socket(AF_INET, SOCK_STREAM, 0);
- if (s == -1)
+ smtplisten = socket(AF_INET, SOCK_STREAM, 0);
+ if (smtplisten == -1)
err(1, "socket");
- if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one,
+ if (setsockopt(smtplisten, SOL_SOCKET, SO_REUSEADDR, &one,
sizeof(one)) == -1)
return (-1);
@@ -1218,7 +1227,7 @@
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
- if (bind(s, (struct sockaddr *)&sin, sizeof sin) == -1)
+ if (bind(smtplisten, (struct sockaddr *)&sin, sizeof sin) == -1)
err(1, "bind");
memset(&lin, 0, sizeof sin);
@@ -1317,7 +1326,7 @@
setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
err(1, "failed to drop privs");
- if (listen(s, 10) == -1)
+ if (listen(smtplisten, 10) == -1)
err(1, "listen");
if (listen(conflisten, 10) == -1)
@@ -1327,90 +1336,87 @@
printf("listening for incoming connections.\n");
syslog_r(LOG_WARNING, &sdata, "listening for incoming connections.");
+ pfd = reallocarray(NULL, PFD_FIRSTCON + maxcon, sizeof(*pfd));
+ if (pfd == NULL)
+ err(1, "reallocarray");
+
+ /* We always check for trap and sync events if configured. */
+ if (trapfd != -1) {
+ pfd[PFD_TRAPFD].fd = trapfd;
+ pfd[PFD_TRAPFD].events = POLLIN;
+ } else {
+ pfd[PFD_TRAPFD].fd = -1;
+ pfd[PFD_TRAPFD].events = 0;
+ }
+ if (syncrecv) {
+ pfd[PFD_SYNCFD].fd = syncfd;
+ pfd[PFD_SYNCFD].events = POLLIN;
+ } else {
+ pfd[PFD_SYNCFD].fd = -1;
+ pfd[PFD_SYNCFD].events = 0;
+ }
+
+ /* events and pfd entries for con[] are filled in below. */
+ pfd[PFD_SMTPLISTEN].fd = smtplisten;
+ pfd[PFD_CONFLISTEN].fd = conflisten;
+
while (1) {
- struct timeval tv, *tvp;
- int max, n;
- int writers;
-
- max = MAX(s, conflisten);
- if (syncrecv)
- max = MAX(max, syncfd);
- max = MAX(max, conffd);
- max = MAX(max, trapfd);
+ int numcon = 0, n, timeout, writers;
time(&t);
- for (i = 0; i < maxcon; i++)
- if (con[i].fd != -1)
- max = MAX(max, con[i].fd);
-
- if (max > omax) {
- free(fdsr);
- fdsr = NULL;
- free(fdsw);
- fdsw = NULL;
- fdsr = (fd_set *)calloc(howmany(max+1, NFDBITS),
- sizeof(fd_mask));
- if (fdsr == NULL)
- err(1, "calloc");
- fdsw = (fd_set *)calloc(howmany(max+1, NFDBITS),
- sizeof(fd_mask));
- if (fdsw == NULL)
- err(1, "calloc");
- omax = max;
- } else {
- memset(fdsr, 0, howmany(max+1, NFDBITS) *
- sizeof(fd_mask));
- memset(fdsw, 0, howmany(max+1, NFDBITS) *
- sizeof(fd_mask));
- }
writers = 0;
for (i = 0; i < maxcon; i++) {
- if (con[i].fd != -1 && con[i].r) {
+ pfd[PFD_FIRSTCON + i].fd = -1;
+ pfd[PFD_FIRSTCON + i].events = 0;
+ if (con[i].fd == -1)
+ continue;
+ if (i + 1 > numcon)
+ numcon = i + 1;
+ if (con[i].r) {
if (con[i].r + MAXTIME <= t) {
closecon(&con[i]);
continue;
}
- FD_SET(con[i].fd, fdsr);
+ pfd[PFD_FIRSTCON + i].fd = con[i].fd;
+ pfd[PFD_FIRSTCON + i].events |= POLLIN;
}
- if (con[i].fd != -1 && con[i].w) {
+ if (con[i].w) {
if (con[i].w + MAXTIME <= t) {
closecon(&con[i]);
continue;
}
- if (con[i].w <= t)
- FD_SET(con[i].fd, fdsw);
+ if (con[i].w <= t) {
+ pfd[PFD_FIRSTCON + i].fd = con[i].fd;
+ pfd[PFD_FIRSTCON + i].events |= POLLOUT;
+ }
writers = 1;
}
}
+ pfd[PFD_SMTPLISTEN].events = 0;
+ pfd[PFD_CONFLISTEN].events = 0;
+ pfd[PFD_CONFFD].events = 0;
+ pfd[PFD_CONFFD].fd = conffd;
if (slowdowntill == 0) {
- FD_SET(s, fdsr);
+ pfd[PFD_SMTPLISTEN].events = POLLIN;
/* only one active config conn at a time */
if (conffd == -1)
- FD_SET(conflisten, fdsr);
+ pfd[PFD_CONFLISTEN].events = POLLIN;
else
- FD_SET(conffd, fdsr);
+ pfd[PFD_CONFFD].events = POLLIN;
}
- if (trapfd != -1)
- FD_SET(trapfd, fdsr);
- if (syncrecv)
- FD_SET(syncfd, fdsr);
-
/* If we are not listening, wake up at least once a second */
- if (writers == 0 && slowdowntill == 0) {
- tvp = NULL;
- } else {
- tv.tv_sec = 1;
- tv.tv_usec = 0;
- tvp = &tv;
- }
+ if (writers == 0 && slowdowntill == 0)
+ timeout = INFTIM;
+ else
+ timeout = 1000;
- n = select(max+1, fdsr, fdsw, NULL, tvp);
+ n = poll(pfd, PFD_FIRSTCON + numcon, timeout);
if (n == -1) {
if (errno != EINTR)
- err(1, "select");
+ err(1, "poll");
continue;
}
@@ -1419,17 +1425,23 @@
slowdowntill = 0;
for (i = 0; i < maxcon; i++) {
- if (con[i].fd != -1 && FD_ISSET(con[i].fd, fdsr))
+ if (con[i].fd == -1)
+ continue;
+ if (pfd[PFD_FIRSTCON + i].revents & POLLHUP) {
+ closecon(&con[i]);
+ continue;
+ }
+ if (pfd[PFD_FIRSTCON + i].revents & POLLIN)
handler(&con[i]);
- if (con[i].fd != -1 && FD_ISSET(con[i].fd, fdsw))
+ if (pfd[PFD_FIRSTCON + i].revents & POLLOUT)
handlew(&con[i], clients + 5 < maxcon);
}
- if (FD_ISSET(s, fdsr)) {
+ if (pfd[PFD_SMTPLISTEN].revents & (POLLIN|POLLHUP)) {
socklen_t sinlen;
int s2;
sinlen = sizeof(sin);
- s2 = accept(s, (struct sockaddr *)&sin, &sinlen);
+ s2 = accept(smtplisten, (struct sockaddr *)&sin,
&sinlen);
if (s2 == -1) {
switch (errno) {
case EINTR:
@@ -1463,7 +1475,7 @@
}
}
}
- if (FD_ISSET(conflisten, fdsr)) {
+ if (pfd[PFD_CONFLISTEN].revents & (POLLIN|POLLHUP)) {
socklen_t sinlen;
sinlen = sizeof(lin);
@@ -1486,11 +1498,11 @@
conffd = -1;
slowdowntill = 0;
}
- } else if (conffd != -1 && FD_ISSET(conffd, fdsr))
+ } else if (pfd[PFD_CONFFD].revents & (POLLIN|POLLHUP))
do_config();
- if (trapfd != -1 && FD_ISSET(trapfd, fdsr))
+ if (pfd[PFD_TRAPFD].revents & (POLLIN|POLLHUP))
read_configline(trapcfg);
- if (syncrecv && FD_ISSET(syncfd, fdsr))
+ if (pfd[PFD_SYNCFD].revents & (POLLIN|POLLHUP))
sync_recv();
}
exit(1);