diff options
author | Damien Miller <djm@mindrot.org> | 2012-04-22 11:21:10 +1000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2012-04-22 11:21:10 +1000 |
commit | a6508753db3c49910068d8fc324bd284d72ff153 (patch) | |
tree | de5d49ef31b5ba61e9086316baf0bd2afb78fd1b /channels.c | |
parent | c6081482b2b72caccce938c100c1b55f7b5e30fe (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.c | 52 |
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 | ||
2069 | static void | 2079 | static void |
2070 | channel_handler(chan_fn *ftab[], fd_set *readset, fd_set *writeset) | 2080 | channel_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 | */ |
2100 | void | 2135 | void |
2101 | channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp, | 2136 | channel_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, | |||
2132 | void | 2168 | void |
2133 | channel_after_select(fd_set *readset, fd_set *writeset) | 2169 | channel_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 | ||