-/* $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
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;
}
if (newsock < 0) {
error("accept: %.100s", strerror(errno));
+ if (errno == EMFILE || errno == ENFILE)
+ c->notbefore = time(NULL) + 1;
return;
}
set_nodelay(newsock);
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);
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",
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;
}
}
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)
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);
}
/*
*/
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;
memset(*writesetp, 0, sz);
if (!rekeying)
- channel_handler(channel_pre, *readsetp, *writesetp);
+ channel_handler(channel_pre, *readsetp, *writesetp,
+ minwait_secs);
}
/*
void
channel_after_select(fd_set *readset, fd_set *writeset)
{
- channel_handler(channel_post, readset, writeset);
+ channel_handler(channel_post, readset, writeset, NULL);
}
-/* $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>
int wfd_isatty; /* wfd 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.
/* 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);
-/* $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
{
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. */
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 {
-/* $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
{
struct timeval tv, *tvp;
int ret;
+ time_t minwait_secs;
int client_alive_scheduled = 0;
int program_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
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 */