summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2019-04-24 10:14:51 +0200
committerGitHub <noreply@github.com>2019-04-24 10:14:51 +0200
commit0a6001c134153f03eb989c3692b4a4600e77e200 (patch)
tree1a9770de34823c131f19f2c7f1ee0d4cf48dc5c0
parentd7707faec204874b021566ce10373462f1c4bc62 (diff)
parent67962036f6c6cfd34828c1f1f1fbdc0018fb9898 (diff)
downloadsystemd-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.c24
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)