summaryrefslogtreecommitdiff
blob: 4849c4c0789e2665f23d88b61256d1d476e39605 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
From f3d75364fbebf2ddb6393e54db5e10b6f6234e14 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Thu, 18 Apr 2019 15:13:54 +0200
Subject: [PATCH] socket-util: make sure flush_accept() doesn't hang on
 unexpected EOPNOTSUPP

So apparently there are two reasons why accept() can return EOPNOTSUPP:
because the socket is not a listening stream socket (or similar), or
because the incoming TCP connection for some reason wasn't acceptable to
the host. THe latter should be a transient error, as suggested on
accept(2). The former however should be considered fatal for
flush_accept(). Let's fix this by explicitly checking whether the socket
is a listening socket beforehand.
---
 src/basic/socket-util.c | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c
index 904bafb76f9..e787d53d8f4 100644
--- a/src/basic/socket-util.c
+++ b/src/basic/socket-util.c
@@ -1225,9 +1225,22 @@ int flush_accept(int fd) {
                 .fd = fd,
                 .events = POLLIN,
         };
-        int r;
+        int r, b;
+        socklen_t l = sizeof(b);
+
+        /* Similar to flush_fd() but flushes all incoming connection by accepting them and immediately
+         * closing them.  */
+
+        if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &b, &l) < 0)
+                return -errno;
 
-        /* Similar to flush_fd() but flushes all incoming connection by accepting them and immediately closing them. */
+        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. */
+                return -ENOTTY;
 
         for (;;) {
                 int cfd;