From 03cb255254235b9cfd068f2fea58e6006c396328 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 18 Apr 2019 15:13:54 +0200 Subject: [PATCH 06/29] 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. (cherry picked from commit f3d75364fbebf2ddb6393e54db5e10b6f6234e14) --- 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 904bafb76f..e787d53d8f 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; -- 2.21.0