From 8d1bc828ab25fd233e046999f7c7a0ca731dad8d Mon Sep 17 00:00:00 2001 From: dlg Date: Wed, 29 Oct 2014 03:33:14 +0000 Subject: replace the use of select and hand rolled deferral of signal handling with libevent. this has been in snaps for a while without any negative (or positive) feedback. review and tweaks by bluhm@ nicm@ ok bluhm@ deraadt@ --- usr.sbin/inetd/Makefile | 4 +- usr.sbin/inetd/inetd.c | 281 +++++++++++++----------------------------------- 2 files changed, 75 insertions(+), 210 deletions(-) (limited to 'usr.sbin/inetd') diff --git a/usr.sbin/inetd/Makefile b/usr.sbin/inetd/Makefile index ccdc58fe2e0..29b6f742f55 100644 --- a/usr.sbin/inetd/Makefile +++ b/usr.sbin/inetd/Makefile @@ -1,6 +1,8 @@ -# $OpenBSD: Makefile,v 1.3 2000/03/31 01:00:49 deraadt Exp $ +# $OpenBSD: Makefile,v 1.4 2014/10/29 03:33:14 dlg Exp $ PROG= inetd +LDADD= -levent +DPADD= ${LIBEVENT} MAN= inetd.8 MLINKS= inetd.8 inetd.conf.5 diff --git a/usr.sbin/inetd/inetd.c b/usr.sbin/inetd/inetd.c index 5863c7ae052..d74e11554a3 100644 --- a/usr.sbin/inetd/inetd.c +++ b/usr.sbin/inetd/inetd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: inetd.c,v 1.141 2014/10/13 01:53:14 dlg Exp $ */ +/* $OpenBSD: inetd.c,v 1.142 2014/10/29 03:33:14 dlg Exp $ */ /* * Copyright (c) 1983,1991 The Regents of the University of California. @@ -151,6 +151,7 @@ #include #include #include +#include #include "pathnames.h" #define TOOMANY 256 /* don't start more than TOOMANY */ @@ -158,15 +159,11 @@ #define RETRYTIME (60*10) /* retry after bind or server fail */ int debug = 0; -int nsock, maxsock; -fd_set *allsockp; -int allsockn; +int maxsock; int toomany = TOOMANY; int timingout; struct servent *sp; uid_t uid; -sigset_t blockmask; -sigset_t emptymask; #ifndef OPEN_MAX #define OPEN_MAX 64 @@ -214,6 +211,7 @@ struct servtab { int se_count; /* number started since se_time */ struct timeval se_time; /* start of se_count */ struct servtab *se_next; + struct event se_event; } *servtab; void echo_stream(int, struct servtab *); @@ -257,21 +255,19 @@ struct biltin { { 0 } }; -volatile sig_atomic_t wantretry; -volatile sig_atomic_t wantconfig; -volatile sig_atomic_t wantreap; -volatile sig_atomic_t wantdie; - -void config(int); -void doconfig(void); -void reap(int); -void doreap(void); -void retry(int); -void doretry(void); -void die(int); -void dodie(void); -void spawn(struct servtab *, int); -int gettcp(struct servtab *); +struct event evsig_alrm; +struct event evsig_hup; +struct event evsig_chld; +struct event evsig_term; +struct event evsig_int; + +void config(int, short, void *); +void reap(int, short, void *); +void retry(int, short, void *); +void die(int, short, void *); + +void spawn(int, short, void *); +void gettcp(int, short, void *); int setconfig(void); void endconfig(void); void register_rpc(struct servtab *); @@ -288,40 +284,15 @@ int dg_broadcast(struct in_addr *in); #define NUMINT (sizeof(intab) / sizeof(struct inent)) char *CONFIG = _PATH_INETDCONF; -void fd_grow(fd_set **fdsp, int *bytes, int fd); int dg_badinput(struct sockaddr *sa); void inetd_setproctitle(char *a, int s); void initring(void); u_int32_t machtime(void); -void -fd_grow(fd_set **fdsp, int *bytes, int fd) -{ - caddr_t new; - int newbytes; - - newbytes = howmany(fd+1, NFDBITS) * sizeof(fd_mask); - if (newbytes > *bytes) { - newbytes *= 2; /* optimism */ - new = realloc(*fdsp, newbytes); - if (new == NULL) { - syslog(LOG_ERR, "Out of memory."); - exit(1); - } - memset(new + *bytes, 0, newbytes - *bytes); - *fdsp = (fd_set *)new; - *bytes = newbytes; - } -} - -struct sigaction sa, sapipe; - int main(int argc, char *argv[]) { - fd_set *fdsrp = NULL; - int readablen = 0, ch; - struct servtab *sep; + int ch; extern char *optarg; extern int optind; @@ -391,109 +362,38 @@ main(int argc, char *argv[]) rlim_nofile_cur = OPEN_MAX; } - sigemptyset(&emptymask); - sigemptyset(&blockmask); - sigaddset(&blockmask, SIGCHLD); - sigaddset(&blockmask, SIGHUP); - sigaddset(&blockmask, SIGALRM); - - memset(&sa, 0, sizeof(sa)); - sigemptyset(&sa.sa_mask); - sigaddset(&sa.sa_mask, SIGALRM); - sigaddset(&sa.sa_mask, SIGCHLD); - sigaddset(&sa.sa_mask, SIGHUP); - sa.sa_handler = retry; - sigaction(SIGALRM, &sa, NULL); - doconfig(); - sa.sa_handler = config; - sigaction(SIGHUP, &sa, NULL); - sa.sa_handler = reap; - sigaction(SIGCHLD, &sa, NULL); - sa.sa_handler = die; - sigaction(SIGTERM, &sa, NULL); - sa.sa_handler = die; - sigaction(SIGINT, &sa, NULL); - sa.sa_handler = SIG_IGN; - sigaction(SIGPIPE, &sa, &sapipe); + event_init(); - for (;;) { - int n, ctrl = -1; - - restart: - if (nsock == 0) { - (void) sigprocmask(SIG_BLOCK, &blockmask, NULL); - while (nsock == 0) { - if (wantretry || wantconfig || wantreap || wantdie) - break; - sigsuspend(&emptymask); - } - (void) sigprocmask(SIG_SETMASK, &emptymask, NULL); - } + signal_set(&evsig_alrm, SIGALRM, retry, NULL); + signal_add(&evsig_alrm, NULL); - while (wantretry || wantconfig || wantreap || wantdie) { - if (wantretry) { - wantretry = 0; - doretry(); - } - if (wantconfig) { - wantconfig = 0; - doconfig(); - } - if (wantreap) { - wantreap = 0; - doreap(); - } - if (wantdie) - dodie(); - goto restart; - } + config(0, 0, NULL); - if (readablen != allsockn) { - if (fdsrp) - free(fdsrp); - fdsrp = calloc(allsockn, 1); - if (fdsrp == NULL) { - syslog(LOG_ERR, "Out of memory."); - exit(1); - } - readablen = allsockn; - } - bcopy(allsockp, fdsrp, allsockn); + signal_set(&evsig_hup, SIGHUP, config, NULL); + signal_add(&evsig_hup, NULL); + signal_set(&evsig_chld, SIGCHLD, reap, NULL); + signal_add(&evsig_chld, NULL); + signal_set(&evsig_term, SIGTERM, die, NULL); + signal_add(&evsig_term, NULL); + signal_set(&evsig_int, SIGINT, die, NULL); + signal_add(&evsig_int, NULL); - if ((n = select(maxsock + 1, fdsrp, NULL, NULL, NULL)) <= 0) { - if (n < 0 && errno != EINTR) { - syslog(LOG_WARNING, "select: %m"); - sleep(1); - } - continue; - } + signal(SIGPIPE, SIG_IGN); - for (sep = servtab; n && sep; sep = sep->se_next) { - if (sep->se_fd != -1 && - FD_ISSET(sep->se_fd, fdsrp)) { - n--; - if (debug) - fprintf(stderr, "someone wants %s\n", - sep->se_service); - if (!sep->se_wait && - sep->se_socktype == SOCK_STREAM) { - ctrl = gettcp(sep); - if (ctrl == -1) - continue; - } else - ctrl = sep->se_fd; - (void) sigprocmask(SIG_BLOCK, &blockmask, NULL); - spawn(sep, ctrl); /* spawn will unblock */ - } - } - } + event_dispatch(); + + return (0); } -int -gettcp(struct servtab *sep) +void +gettcp(int fd, short events, void *xsep) { + struct servtab *sep = xsep; int ctrl; + if (debug) + fprintf(stderr, "someone wants %s\n", sep->se_service); + ctrl = accept(sep->se_fd, NULL, NULL); if (debug) fprintf(stderr, "accept, ctrl %d\n", ctrl); @@ -502,7 +402,7 @@ gettcp(struct servtab *sep) errno != ECONNABORTED) syslog(LOG_WARNING, "accept (for %s): %m", sep->se_service); - return -1; + return; } if ((sep->se_family == AF_INET || sep->se_family == AF_INET6) && sep->se_socktype == SOCK_STREAM) { @@ -513,7 +413,7 @@ gettcp(struct servtab *sep) if (getpeername(ctrl, (struct sockaddr *)&peer, &plen) < 0) { syslog(LOG_WARNING, "could not getpeername"); close(ctrl); - return -1; + return; } if (getnameinfo((struct sockaddr *)&peer, plen, NULL, 0, sbuf, sizeof(sbuf), NI_NUMERICSERV) == 0 && @@ -522,12 +422,12 @@ gettcp(struct servtab *sep) * ignore things that look like ftp bounce */ close(ctrl); - return -1; + return; } } - return (ctrl); -} + spawn(ctrl, 0, sep); +} int dg_badinput(struct sockaddr *sa) @@ -603,15 +503,8 @@ dg_broadcast(struct in_addr *in) return (0); } -/* ARGSUSED */ void -reap(int sig) -{ - wantreap = 1; -} - -void -doreap(void) +reap(int sig, short event, void *arg) { struct servtab *sep; int status; @@ -640,9 +533,7 @@ doreap(void) "%s: exit signal %d", sep->se_server, WTERMSIG(status)); sep->se_wait = 1; - fd_grow(&allsockp, &allsockn, sep->se_fd); - FD_SET(sep->se_fd, allsockp); - nsock++; + event_add(&sep->se_event, NULL); if (debug) fprintf(stderr, "restored %s, fd %d\n", sep->se_service, sep->se_fd); @@ -650,20 +541,12 @@ doreap(void) } } -/* ARGSUSED */ -void -config(int sig) -{ - wantconfig = 1; -} - void -doconfig(void) +config(int sig, short event, void *arg) { struct servtab *sep, *cp, **sepp; int add; char protoname[10]; - sigset_t omask; if (!setconfig()) { syslog(LOG_ERR, "%s: %m", CONFIG); @@ -682,7 +565,6 @@ doconfig(void) #define SWAP(type, a, b) {type c=(type)a; a=(type)b; b=(type)c;} - sigprocmask(SIG_BLOCK, &blockmask, &omask); /* * sep->se_wait may be holding the pid of a daemon * that we're waiting for. If so, don't overwrite @@ -703,7 +585,6 @@ doconfig(void) unregister_rpc(sep); sep->se_rpcversl = cp->se_rpcversl; sep->se_rpcversh = cp->se_rpcversh; - sigprocmask(SIG_SETMASK, &omask, NULL); freeconfig(cp); add = 1; } else { @@ -778,8 +659,7 @@ doconfig(void) if (port != sep->se_ctrladdr_in.sin_port) { sep->se_ctrladdr_in.sin_port = port; if (sep->se_fd != -1) { - FD_CLR(sep->se_fd, allsockp); - nsock--; + event_del(&sep->se_event); (void) close(sep->se_fd); } sep->se_fd = -1; @@ -834,8 +714,7 @@ doconfig(void) if (port != sep->se_ctrladdr_in6.sin6_port) { sep->se_ctrladdr_in6.sin6_port = port; if (sep->se_fd != -1) { - FD_CLR(sep->se_fd, allsockp); - nsock--; + event_del(&sep->se_event); (void) close(sep->se_fd); } sep->se_fd = -1; @@ -862,7 +741,6 @@ doconfig(void) /* * Purge anything not looked at above. */ - sigprocmask(SIG_BLOCK, &blockmask, &omask); sepp = &servtab; while ((sep = *sepp)) { if (sep->se_checked) { @@ -871,8 +749,7 @@ doconfig(void) } *sepp = sep->se_next; if (sep->se_fd != -1) { - FD_CLR(sep->se_fd, allsockp); - nsock--; + event_del(&sep->se_event); (void) close(sep->se_fd); } if (isrpcservice(sep)) @@ -884,18 +761,10 @@ doconfig(void) freeconfig(sep); free(sep); } - sigprocmask(SIG_SETMASK, &omask, NULL); } -/* ARGSUSED */ void -retry(int sig) -{ - wantretry = 1; -} - -void -doretry(void) +retry(int sig, short events, void *arg) { struct servtab *sep; @@ -915,15 +784,8 @@ doretry(void) } } -/* ARGSUSED */ -void -die(int sig) -{ - wantdie = 1; -} - void -dodie(void) +die(int sig, short events, void *arg) { struct servtab *sep; @@ -1015,9 +877,16 @@ setsockopt(fd, SOL_SOCKET, opt, &on, sizeof (on)) if (sep->se_socktype == SOCK_STREAM) listen(sep->se_fd, 10); - fd_grow(&allsockp, &allsockn, sep->se_fd); - FD_SET(sep->se_fd, allsockp); - nsock++; + if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) { + event_set(&sep->se_event, sep->se_fd, EV_READ|EV_PERSIST, + gettcp, sep); + } else { + event_set(&sep->se_event, sep->se_fd, EV_READ|EV_PERSIST, + spawn, sep); + } + + event_add(&sep->se_event, NULL); + if (sep->se_fd > maxsock) { maxsock = sep->se_fd; if (maxsock > rlim_nofile_cur - FD_MARGIN) @@ -1078,7 +947,6 @@ struct servtab * enter(struct servtab *cp) { struct servtab *sep; - sigset_t omask; sep = malloc(sizeof (*sep)); if (sep == NULL) { @@ -1088,10 +956,8 @@ enter(struct servtab *cp) *sep = *cp; sep->se_fd = -1; sep->se_rpcprog = -1; - sigprocmask(SIG_BLOCK, &blockmask, &omask); sep->se_next = servtab; servtab = sep; - sigprocmask(SIG_SETMASK, &omask, NULL); return (sep); } @@ -1835,14 +1701,18 @@ print_service(char *action, struct servtab *sep) } void -spawn(struct servtab *sep, int ctrl) +spawn(int ctrl, short events, void *xsep) { + struct servtab *sep = xsep; struct passwd *pwd; int tmpint, dofork; struct group *grp = NULL; char buf[50]; pid_t pid; + if (debug) + fprintf(stderr, "someone wants %s\n", sep->se_service); + pid = 0; dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork); if (dofork) { @@ -1869,8 +1739,6 @@ spawn(struct servtab *sep, int ctrl) * Simply ignore the connection. */ --sep->se_count; - sigprocmask(SIG_SETMASK, &emptymask, - NULL); return; } syslog(LOG_ERR, @@ -1879,13 +1747,11 @@ spawn(struct servtab *sep, int ctrl) if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) close(ctrl); - FD_CLR(sep->se_fd, allsockp); + event_del(&sep->se_event); (void) close(sep->se_fd); + sep->se_fd = -1; sep->se_count = 0; - nsock--; - sigprocmask(SIG_SETMASK, &emptymask, - NULL); if (!timingout) { timingout = 1; alarm(RETRYTIME); @@ -1899,16 +1765,13 @@ spawn(struct servtab *sep, int ctrl) syslog(LOG_ERR, "fork: %m"); if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) close(ctrl); - sigprocmask(SIG_SETMASK, &emptymask, NULL); sleep(1); return; } if (pid && sep->se_wait) { sep->se_wait = pid; - FD_CLR(sep->se_fd, allsockp); - nsock--; + event_del(&sep->se_event); } - sigprocmask(SIG_SETMASK, &emptymask, NULL); if (pid == 0) { if (sep->se_bi) (*sep->se_bi->bi_fn)(ctrl, sep); @@ -1965,7 +1828,7 @@ spawn(struct servtab *sep, int ctrl) dup2(STDIN_FILENO, STDERR_FILENO); closelog(); closefrom(3); - sigaction(SIGPIPE, &sapipe, NULL); + signal(SIGPIPE, SIG_DFL); execv(sep->se_server, sep->se_argv); if (sep->se_socktype != SOCK_STREAM) recv(0, buf, sizeof (buf), 0); -- cgit v1.2.3-59-g8ed1b