diff options
author | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2019-04-23 15:03:29 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-04-23 15:03:29 +0200 |
commit | f5f899ef044e4b159e723b273ff35fda935f6427 (patch) | |
tree | e8e037d2c0167b3f38e6ebf17f282b025497877e /src | |
parent | 4b198b2a442a77b26a4938d84d06641054bb0dfb (diff) | |
parent | 6cdc62aa976b9f258cc6c86a19efa8d8b9ee0ba4 (diff) | |
download | systemd-f5f899ef044e4b159e723b273ff35fda935f6427.tar.gz |
Merge pull request #12346 from poettering/accept-flush
socket-util: make sure accept_flush() doesn't hang on EOPNOTSUPP
Diffstat (limited to 'src')
-rw-r--r-- | src/basic/socket-util.c | 17 | ||||
-rw-r--r-- | src/test/test-socket-util.c | 62 | ||||
-rw-r--r-- | src/udev/udev-rules.c | 2 |
3 files changed, 78 insertions, 3 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; diff --git a/src/test/test-socket-util.c b/src/test/test-socket-util.c index 057840d76f..4e9a0bddf4 100644 --- a/src/test/test-socket-util.c +++ b/src/test/test-socket-util.c @@ -810,6 +810,67 @@ static void test_send_emptydata(void) { assert_se(fd == -999); } +static void test_flush_accept(void) { + _cleanup_close_ int listen_stream = -1, listen_dgram = -1, listen_seqpacket = 1, connect_stream = -1, connect_dgram = -1, connect_seqpacket = -1; + static const union sockaddr_union sa = { .un.sun_family = AF_UNIX }; + union sockaddr_union lsa; + socklen_t l; + + listen_stream = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + assert_se(listen_stream >= 0); + + listen_dgram = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + assert_se(listen_dgram >= 0); + + listen_seqpacket = socket(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + assert_se(listen_seqpacket >= 0); + + assert_se(flush_accept(listen_stream) < 0); + assert_se(flush_accept(listen_dgram) < 0); + assert_se(flush_accept(listen_seqpacket) < 0); + + assert_se(bind(listen_stream, &sa.sa, sizeof(sa_family_t)) >= 0); + assert_se(bind(listen_dgram, &sa.sa, sizeof(sa_family_t)) >= 0); + assert_se(bind(listen_seqpacket, &sa.sa, sizeof(sa_family_t)) >= 0); + + assert_se(flush_accept(listen_stream) < 0); + assert_se(flush_accept(listen_dgram) < 0); + assert_se(flush_accept(listen_seqpacket) < 0); + + assert_se(listen(listen_stream, SOMAXCONN) >= 0); + assert_se(listen(listen_dgram, SOMAXCONN) < 0); + assert_se(listen(listen_seqpacket, SOMAXCONN) >= 0); + + assert_se(flush_accept(listen_stream) >= 0); + assert_se(flush_accept(listen_dgram) < 0); + assert_se(flush_accept(listen_seqpacket) >= 0); + + connect_stream = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + assert_se(connect_stream >= 0); + + connect_dgram = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + assert_se(connect_dgram >= 0); + + connect_seqpacket = socket(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + assert_se(connect_seqpacket >= 0); + + l = sizeof(lsa); + assert_se(getsockname(listen_stream, &lsa.sa, &l) >= 0); + assert_se(connect(connect_stream, &lsa.sa, l) >= 0); + + l = sizeof(lsa); + assert_se(getsockname(listen_dgram, &lsa.sa, &l) >= 0); + assert_se(connect(connect_dgram, &lsa.sa, l) >= 0); + + l = sizeof(lsa); + assert_se(getsockname(listen_seqpacket, &lsa.sa, &l) >= 0); + assert_se(connect(connect_seqpacket, &lsa.sa, l) >= 0); + + assert_se(flush_accept(listen_stream) >= 0); + assert_se(flush_accept(listen_dgram) < 0); + assert_se(flush_accept(listen_seqpacket) >= 0); +} + int main(int argc, char *argv[]) { test_setup_logging(LOG_DEBUG); @@ -843,6 +904,7 @@ int main(int argc, char *argv[]) { test_receive_nopassfd(); test_send_nodata_nofd(); test_send_emptydata(); + test_flush_accept(); return 0; } diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c index 63a967633b..96840b272c 100644 --- a/src/udev/udev-rules.c +++ b/src/udev/udev-rules.c @@ -2442,7 +2442,7 @@ int udev_rules_apply_to_event( case TK_A_RUN_BUILTIN: case TK_A_RUN_PROGRAM: { _cleanup_free_ char *cmd = NULL; - + if (event->run_final) break; if (cur->key.op == OP_ASSIGN_FINAL) |