Merge pull request #12367 from keszybz/accept-check

Put a limit on the loop to flush connections
This commit is contained in:
Lennart Poettering 2019-04-24 10:14:51 +02:00 committed by GitHub
commit 0a6001c134
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -1219,6 +1219,10 @@ fallback:
return (ssize_t) k;
}
/* Put a limit on how many times will attempt to call accept4(). We loop
* only on "transient" errors, but let's make sure we don't loop forever. */
#define MAX_FLUSH_ITERATIONS 1024
int flush_accept(int fd) {
struct pollfd pollfd = {
@ -1228,21 +1232,21 @@ int flush_accept(int fd) {
int r, b;
socklen_t l = sizeof(b);
/* Similar to flush_fd() but flushes all incoming connection by accepting them and immediately
* closing them. */
/* Similar to flush_fd() but flushes all incoming connections by accepting and immediately closing
* them. */
if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &b, &l) < 0)
return -errno;
assert(l == sizeof(b));
if (!b) /* Let's check if this is a socket accepting connections before calling accept(). That's
* because accept4() can return EOPNOTSUPP in the fd we are called on is not a listening
* socket, or in case the incoming TCP connection transiently triggered that (see accept(2)
* man page for details). The latter case is a transient error we should continue looping
* on. The former case however is fatal. */
if (!b) /* Let's check if this socket accepts connections before calling accept(). accept4() can
* return EOPNOTSUPP if the fd is not a listening socket, which we should treat as a fatal
* error, or in case the incoming TCP connection triggered a network issue, which we want to
* treat as a transient error. Thus, let's rule out the first reason for EOPNOTSUPP early, so
* we can loop safely on transient errors below. */
return -ENOTTY;
for (;;) {
for (unsigned iteration = 0;; iteration++) {
int cfd;
r = poll(&pollfd, 1, 0);
@ -1255,6 +1259,10 @@ int flush_accept(int fd) {
if (r == 0)
return 0;
if (iteration >= MAX_FLUSH_ITERATIONS)
return log_debug_errno(SYNTHETIC_ERRNO(EBUSY),
"Failed to flush connections within " STRINGIFY(MAX_FLUSH_ITERATIONS) " iterations.");
cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
if (cfd < 0) {
if (errno == EAGAIN)