summaryrefslogtreecommitdiff
path: root/channels.c
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2012-04-22 11:21:10 +1000
committerDamien Miller <djm@mindrot.org>2012-04-22 11:21:10 +1000
commita6508753db3c49910068d8fc324bd284d72ff153 (patch)
treede5d49ef31b5ba61e9086316baf0bd2afb78fd1b /channels.c
parentc6081482b2b72caccce938c100c1b55f7b5e30fe (diff)
- djm@cvs.openbsd.org 2012/04/11 13:16:19
[channels.c channels.h clientloop.c serverloop.c] don't spin in accept() when out of fds (ENFILE/ENFILE) - back off for a while; ok deraadt@ markus@
Diffstat (limited to 'channels.c')
-rw-r--r--channels.c52
1 files changed, 44 insertions, 8 deletions
diff --git a/channels.c b/channels.c
index e5783b197..cacd2fe55 100644
--- a/channels.c
+++ b/channels.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: channels.c,v 1.316 2012/03/29 23:54:36 dtucker Exp $ */ 1/* $OpenBSD: channels.c,v 1.317 2012/04/11 13:16:19 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -311,6 +311,7 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd,
311 c->istate = CHAN_INPUT_OPEN; 311 c->istate = CHAN_INPUT_OPEN;
312 c->flags = 0; 312 c->flags = 0;
313 channel_register_fds(c, rfd, wfd, efd, extusage, nonblock, 0); 313 channel_register_fds(c, rfd, wfd, efd, extusage, nonblock, 0);
314 c->notbefore = 0;
314 c->self = found; 315 c->self = found;
315 c->type = type; 316 c->type = type;
316 c->ctype = ctype; 317 c->ctype = ctype;
@@ -1339,6 +1340,8 @@ channel_post_x11_listener(Channel *c, fd_set *readset, fd_set *writeset)
1339 } 1340 }
1340 if (newsock < 0) { 1341 if (newsock < 0) {
1341 error("accept: %.100s", strerror(errno)); 1342 error("accept: %.100s", strerror(errno));
1343 if (errno == EMFILE || errno == ENFILE)
1344 c->notbefore = time(NULL) + 1;
1342 return; 1345 return;
1343 } 1346 }
1344 set_nodelay(newsock); 1347 set_nodelay(newsock);
@@ -1482,6 +1485,8 @@ channel_post_port_listener(Channel *c, fd_set *readset, fd_set *writeset)
1482 newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen); 1485 newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen);
1483 if (newsock < 0) { 1486 if (newsock < 0) {
1484 error("accept: %.100s", strerror(errno)); 1487 error("accept: %.100s", strerror(errno));
1488 if (errno == EMFILE || errno == ENFILE)
1489 c->notbefore = time(NULL) + 1;
1485 return; 1490 return;
1486 } 1491 }
1487 set_nodelay(newsock); 1492 set_nodelay(newsock);
@@ -1514,7 +1519,10 @@ channel_post_auth_listener(Channel *c, fd_set *readset, fd_set *writeset)
1514 addrlen = sizeof(addr); 1519 addrlen = sizeof(addr);
1515 newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen); 1520 newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen);
1516 if (newsock < 0) { 1521 if (newsock < 0) {
1517 error("accept from auth socket: %.100s", strerror(errno)); 1522 error("accept from auth socket: %.100s",
1523 strerror(errno));
1524 if (errno == EMFILE || errno == ENFILE)
1525 c->notbefore = time(NULL) + 1;
1518 return; 1526 return;
1519 } 1527 }
1520 nc = channel_new("accepted auth socket", 1528 nc = channel_new("accepted auth socket",
@@ -1917,6 +1925,8 @@ channel_post_mux_listener(Channel *c, fd_set *readset, fd_set *writeset)
1917 if ((newsock = accept(c->sock, (struct sockaddr*)&addr, 1925 if ((newsock = accept(c->sock, (struct sockaddr*)&addr,
1918 &addrlen)) == -1) { 1926 &addrlen)) == -1) {
1919 error("%s accept: %s", __func__, strerror(errno)); 1927 error("%s accept: %s", __func__, strerror(errno));
1928 if (errno == EMFILE || errno == ENFILE)
1929 c->notbefore = time(NULL) + 1;
1920 return; 1930 return;
1921 } 1931 }
1922 1932
@@ -2067,16 +2077,21 @@ channel_garbage_collect(Channel *c)
2067} 2077}
2068 2078
2069static void 2079static void
2070channel_handler(chan_fn *ftab[], fd_set *readset, fd_set *writeset) 2080channel_handler(chan_fn *ftab[], fd_set *readset, fd_set *writeset,
2081 time_t *unpause_secs)
2071{ 2082{
2072 static int did_init = 0; 2083 static int did_init = 0;
2073 u_int i, oalloc; 2084 u_int i, oalloc;
2074 Channel *c; 2085 Channel *c;
2086 time_t now;
2075 2087
2076 if (!did_init) { 2088 if (!did_init) {
2077 channel_handler_init(); 2089 channel_handler_init();
2078 did_init = 1; 2090 did_init = 1;
2079 } 2091 }
2092 now = time(NULL);
2093 if (unpause_secs != NULL)
2094 *unpause_secs = 0;
2080 for (i = 0, oalloc = channels_alloc; i < oalloc; i++) { 2095 for (i = 0, oalloc = channels_alloc; i < oalloc; i++) {
2081 c = channels[i]; 2096 c = channels[i];
2082 if (c == NULL) 2097 if (c == NULL)
@@ -2087,10 +2102,30 @@ channel_handler(chan_fn *ftab[], fd_set *readset, fd_set *writeset)
2087 else 2102 else
2088 continue; 2103 continue;
2089 } 2104 }
2090 if (ftab[c->type] != NULL) 2105 if (ftab[c->type] != NULL) {
2091 (*ftab[c->type])(c, readset, writeset); 2106 /*
2107 * Run handlers that are not paused.
2108 */
2109 if (c->notbefore <= now)
2110 (*ftab[c->type])(c, readset, writeset);
2111 else if (unpause_secs != NULL) {
2112 /*
2113 * Collect the time that the earliest
2114 * channel comes off pause.
2115 */
2116 debug3("%s: chan %d: skip for %d more seconds",
2117 __func__, c->self,
2118 (int)(c->notbefore - now));
2119 if (*unpause_secs == 0 ||
2120 (c->notbefore - now) < *unpause_secs)
2121 *unpause_secs = c->notbefore - now;
2122 }
2123 }
2092 channel_garbage_collect(c); 2124 channel_garbage_collect(c);
2093 } 2125 }
2126 if (unpause_secs != NULL && *unpause_secs != 0)
2127 debug3("%s: first channel unpauses in %d seconds",
2128 __func__, (int)*unpause_secs);
2094} 2129}
2095 2130
2096/* 2131/*
@@ -2099,7 +2134,7 @@ channel_handler(chan_fn *ftab[], fd_set *readset, fd_set *writeset)
2099 */ 2134 */
2100void 2135void
2101channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp, 2136channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
2102 u_int *nallocp, int rekeying) 2137 u_int *nallocp, int *minwait_secs, int rekeying)
2103{ 2138{
2104 u_int n, sz, nfdset; 2139 u_int n, sz, nfdset;
2105 2140
@@ -2122,7 +2157,8 @@ channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
2122 memset(*writesetp, 0, sz); 2157 memset(*writesetp, 0, sz);
2123 2158
2124 if (!rekeying) 2159 if (!rekeying)
2125 channel_handler(channel_pre, *readsetp, *writesetp); 2160 channel_handler(channel_pre, *readsetp, *writesetp,
2161 minwait_secs);
2126} 2162}
2127 2163
2128/* 2164/*
@@ -2132,7 +2168,7 @@ channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
2132void 2168void
2133channel_after_select(fd_set *readset, fd_set *writeset) 2169channel_after_select(fd_set *readset, fd_set *writeset)
2134{ 2170{
2135 channel_handler(channel_post, readset, writeset); 2171 channel_handler(channel_post, readset, writeset, NULL);
2136} 2172}
2137 2173
2138 2174