Merge pull request #12346 from poettering/accept-flush

socket-util: make sure accept_flush() doesn't hang on EOPNOTSUPP
This commit is contained in:
Zbigniew Jędrzejewski-Szmek
2019-04-23 15:03:29 +02:00
committed by GitHub
3 changed files with 78 additions and 3 deletions
+15 -2
View File
@@ -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. */
/* 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;
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;
+62
View File
@@ -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;
}
+1 -1
View File
@@ -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)