summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordjm <djm@openbsd.org>2012-04-11 13:16:19 +0000
committerdjm <djm@openbsd.org>2012-04-11 13:16:19 +0000
commit4ebe786817d2138ef79f88d787d3a2defe037293 (patch)
tree375c03a2909ecbac88edd4266d1a66a5c8295d63
parentadd -H to usage(); (diff)
downloadwireguard-openbsd-4ebe786817d2138ef79f88d787d3a2defe037293.tar.xz
wireguard-openbsd-4ebe786817d2138ef79f88d787d3a2defe037293.zip
don't spin in accept() when out of fds (ENFILE/ENFILE) - back off for a
while; ok deraadt@ markus@
-rw-r--r--usr.bin/ssh/channels.c52
-rw-r--r--usr.bin/ssh/channels.h6
-rw-r--r--usr.bin/ssh/clientloop.c8
-rw-r--r--usr.bin/ssh/serverloop.c14
4 files changed, 64 insertions, 16 deletions
diff --git a/usr.bin/ssh/channels.c b/usr.bin/ssh/channels.c
index c1af7029a97..05cb66a8e55 100644
--- a/usr.bin/ssh/channels.c
+++ b/usr.bin/ssh/channels.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: channels.c,v 1.316 2012/03/29 23:54:36 dtucker Exp $ */
+/* $OpenBSD: channels.c,v 1.317 2012/04/11 13:16:19 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -306,6 +306,7 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd,
c->istate = CHAN_INPUT_OPEN;
c->flags = 0;
channel_register_fds(c, rfd, wfd, efd, extusage, nonblock, 0);
+ c->notbefore = 0;
c->self = found;
c->type = type;
c->ctype = ctype;
@@ -1334,6 +1335,8 @@ channel_post_x11_listener(Channel *c, fd_set *readset, fd_set *writeset)
}
if (newsock < 0) {
error("accept: %.100s", strerror(errno));
+ if (errno == EMFILE || errno == ENFILE)
+ c->notbefore = time(NULL) + 1;
return;
}
set_nodelay(newsock);
@@ -1477,6 +1480,8 @@ channel_post_port_listener(Channel *c, fd_set *readset, fd_set *writeset)
newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen);
if (newsock < 0) {
error("accept: %.100s", strerror(errno));
+ if (errno == EMFILE || errno == ENFILE)
+ c->notbefore = time(NULL) + 1;
return;
}
set_nodelay(newsock);
@@ -1509,7 +1514,10 @@ channel_post_auth_listener(Channel *c, fd_set *readset, fd_set *writeset)
addrlen = sizeof(addr);
newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen);
if (newsock < 0) {
- error("accept from auth socket: %.100s", strerror(errno));
+ error("accept from auth socket: %.100s",
+ strerror(errno));
+ if (errno == EMFILE || errno == ENFILE)
+ c->notbefore = time(NULL) + 1;
return;
}
nc = channel_new("accepted auth socket",
@@ -1895,6 +1903,8 @@ channel_post_mux_listener(Channel *c, fd_set *readset, fd_set *writeset)
if ((newsock = accept(c->sock, (struct sockaddr*)&addr,
&addrlen)) == -1) {
error("%s accept: %s", __func__, strerror(errno));
+ if (errno == EMFILE || errno == ENFILE)
+ c->notbefore = time(NULL) + 1;
return;
}
@@ -2045,16 +2055,21 @@ channel_garbage_collect(Channel *c)
}
static void
-channel_handler(chan_fn *ftab[], fd_set *readset, fd_set *writeset)
+channel_handler(chan_fn *ftab[], fd_set *readset, fd_set *writeset,
+ time_t *unpause_secs)
{
static int did_init = 0;
u_int i, oalloc;
Channel *c;
+ time_t now;
if (!did_init) {
channel_handler_init();
did_init = 1;
}
+ now = time(NULL);
+ if (unpause_secs != NULL)
+ *unpause_secs = 0;
for (i = 0, oalloc = channels_alloc; i < oalloc; i++) {
c = channels[i];
if (c == NULL)
@@ -2065,10 +2080,30 @@ channel_handler(chan_fn *ftab[], fd_set *readset, fd_set *writeset)
else
continue;
}
- if (ftab[c->type] != NULL)
- (*ftab[c->type])(c, readset, writeset);
+ if (ftab[c->type] != NULL) {
+ /*
+ * Run handlers that are not paused.
+ */
+ if (c->notbefore <= now)
+ (*ftab[c->type])(c, readset, writeset);
+ else if (unpause_secs != NULL) {
+ /*
+ * Collect the time that the earliest
+ * channel comes off pause.
+ */
+ debug3("%s: chan %d: skip for %d more seconds",
+ __func__, c->self,
+ (int)(c->notbefore - now));
+ if (*unpause_secs == 0 ||
+ (c->notbefore - now) < *unpause_secs)
+ *unpause_secs = c->notbefore - now;
+ }
+ }
channel_garbage_collect(c);
}
+ if (unpause_secs != NULL && *unpause_secs != 0)
+ debug3("%s: first channel unpauses in %d seconds",
+ __func__, (int)*unpause_secs);
}
/*
@@ -2077,7 +2112,7 @@ channel_handler(chan_fn *ftab[], fd_set *readset, fd_set *writeset)
*/
void
channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
- u_int *nallocp, int rekeying)
+ u_int *nallocp, int *minwait_secs, int rekeying)
{
u_int n, sz, nfdset;
@@ -2100,7 +2135,8 @@ channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
memset(*writesetp, 0, sz);
if (!rekeying)
- channel_handler(channel_pre, *readsetp, *writesetp);
+ channel_handler(channel_pre, *readsetp, *writesetp,
+ minwait_secs);
}
/*
@@ -2110,7 +2146,7 @@ channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
void
channel_after_select(fd_set *readset, fd_set *writeset)
{
- channel_handler(channel_post, readset, writeset);
+ channel_handler(channel_post, readset, writeset, NULL);
}
diff --git a/usr.bin/ssh/channels.h b/usr.bin/ssh/channels.h
index 44a39fbbbdd..a2ae4071051 100644
--- a/usr.bin/ssh/channels.h
+++ b/usr.bin/ssh/channels.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: channels.h,v 1.110 2012/03/29 23:54:36 dtucker Exp $ */
+/* $OpenBSD: channels.h,v 1.111 2012/04/11 13:16:19 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -104,6 +104,7 @@ struct Channel {
int isatty; /* rfd is a tty */
int client_tty; /* (client) TTY has been requested */
int force_drain; /* force close on iEOF */
+ time_t notbefore; /* Pause IO until deadline (time_t) */
int delayed; /* post-select handlers for newly created
* channels are delayed until the first call
* to a matching pre-select handler.
@@ -237,7 +238,8 @@ void channel_input_status_confirm(int, u_int32_t, void *);
/* file descriptor handling (read/write) */
-void channel_prepare_select(fd_set **, fd_set **, int *, u_int*, int);
+void channel_prepare_select(fd_set **, fd_set **, int *, u_int*,
+ time_t*, int);
void channel_after_select(fd_set *, fd_set *);
void channel_output_poll(void);
diff --git a/usr.bin/ssh/clientloop.c b/usr.bin/ssh/clientloop.c
index 1930b4bf7e5..f2d7169d462 100644
--- a/usr.bin/ssh/clientloop.c
+++ b/usr.bin/ssh/clientloop.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: clientloop.c,v 1.238 2012/01/18 21:46:43 dtucker Exp $ */
+/* $OpenBSD: clientloop.c,v 1.239 2012/04/11 13:16:19 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -575,10 +575,12 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp,
{
struct timeval tv, *tvp;
int timeout_secs;
+ time_t minwait_secs;
int ret;
/* Add any selections by the channel mechanism. */
- channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, rekeying);
+ channel_prepare_select(readsetp, writesetp, maxfdp, nallocp,
+ &minwait_secs, rekeying);
if (!compat20) {
/* Read from the connection, unless our buffers are full. */
@@ -631,6 +633,8 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp,
if (timeout_secs < 0)
timeout_secs = 0;
}
+ if (minwait_secs != 0)
+ timeout_secs = MIN(timeout_secs, (int)minwait_secs);
if (timeout_secs == INT_MAX)
tvp = NULL;
else {
diff --git a/usr.bin/ssh/serverloop.c b/usr.bin/ssh/serverloop.c
index f0299e55833..a888443a579 100644
--- a/usr.bin/ssh/serverloop.c
+++ b/usr.bin/ssh/serverloop.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: serverloop.c,v 1.160 2011/05/15 08:09:01 djm Exp $ */
+/* $OpenBSD: serverloop.c,v 1.161 2012/04/11 13:16:19 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -275,8 +275,17 @@ wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
{
struct timeval tv, *tvp;
int ret;
+ time_t minwait_secs;
int client_alive_scheduled = 0;
+ /* Allocate and update select() masks for channel descriptors. */
+ channel_prepare_select(readsetp, writesetp, maxfdp, nallocp,
+ &minwait_secs, 0);
+
+ if (minwait_secs != 0)
+ max_time_milliseconds = MIN(max_time_milliseconds,
+ (u_int)minwait_secs * 1000);
+
/*
* if using client_alive, set the max timeout accordingly,
* and indicate that this particular timeout was for client
@@ -291,9 +300,6 @@ wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
max_time_milliseconds = options.client_alive_interval * 1000;
}
- /* Allocate and update select() masks for channel descriptors. */
- channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, 0);
-
if (compat20) {
#if 0
/* wrong: bad condition XXX */