diff options
author | Lennart Poettering <lennart@poettering.net> | 2019-04-24 10:14:51 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-04-24 10:14:51 +0200 |
commit | 0a6001c134153f03eb989c3692b4a4600e77e200 (patch) | |
tree | 1a9770de34823c131f19f2c7f1ee0d4cf48dc5c0 | |
parent | d7707faec204874b021566ce10373462f1c4bc62 (diff) | |
parent | 67962036f6c6cfd34828c1f1f1fbdc0018fb9898 (diff) | |
download | systemd-0a6001c134153f03eb989c3692b4a4600e77e200.tar.gz |
Merge pull request #12367 from keszybz/accept-check
Put a limit on the loop to flush connections
-rw-r--r-- | src/basic/socket-util.c | 24 |
1 files changed, 16 insertions, 8 deletions
diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c index e787d53d8f..32a0d9c5d0 100644 --- a/src/basic/socket-util.c +++ b/src/basic/socket-util.c @@ -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) |