sock_unix(), which creates a listening Unix socket, doesn't set the
SOCK_NONBLOCK flag. Generally, this doesn't matter because we only
accept() once we've received an epoll event awaiting a connection. However
we will need non-blocking accept() for the upcoming control/configuration
socket. Always add SOCK_NONBLOCK, which is more robust and in keeping with
the normal non-blocking style of passt.
In tap.c, always set SOCK_NONBLOCK and SOCK_CLOEXEC on the accept()ed
sockets as well, which we weren't doing in all cases before. According to
accept(2), in Linux accepted sockets do *not* inherit these flags from the
listening socket. Also check for failures of accept, discarding EAGAIN
silently (a spurious epoll event) and warning for other errors.
In repair.c, similarly always add CLOEXEC. Use NONBLOCK for discard
sockets, but *not* for the final repair socket, since we want blocking
transactions during migration.
Signed-off-by: David Gibson
---
repair.c | 9 +++++++--
tap.c | 12 ++++++++++--
util.c | 2 +-
3 files changed, 18 insertions(+), 5 deletions(-)
diff --git a/repair.c b/repair.c
index 69c53077..6c338da6 100644
--- a/repair.c
+++ b/repair.c
@@ -87,7 +87,7 @@ int repair_listen_handler(struct ctx *c, uint32_t events)
/* Another client is already connected: accept and close right away. */
if (c->fd_repair != -1) {
int discard = accept4(c->fd_repair_listen, NULL, NULL,
- SOCK_NONBLOCK);
+ SOCK_CLOEXEC | SOCK_NONBLOCK);
if (discard == -1)
return errno;
@@ -99,7 +99,12 @@ int repair_listen_handler(struct ctx *c, uint32_t events)
return EEXIST;
}
- if ((c->fd_repair = accept4(c->fd_repair_listen, NULL, NULL, 0)) < 0) {
+ /* We deliberately *don't* set SOCK_NONBLOCK on the accepted socket,
+ * because repair transactions happen during migration, when everything
+ * is blocked anyway.
+ */
+ if ((c->fd_repair = accept4(c->fd_repair_listen, NULL, NULL,
+ SOCK_CLOEXEC)) < 0) {
rc = errno;
debug_perror("accept4() on TCP_REPAIR helper listening socket");
return rc;
diff --git a/tap.c b/tap.c
index 7d06189d..87acd531 100644
--- a/tap.c
+++ b/tap.c
@@ -1415,7 +1415,7 @@ void tap_listen_handler(struct ctx *c, uint32_t events)
/* Another client is already connected: accept and close right away. */
if (c->fd_tap != -1) {
int discard = accept4(c->fd_tap_listen, NULL, NULL,
- SOCK_NONBLOCK);
+ SOCK_NONBLOCK | SOCK_CLOEXEC);
if (discard == -1)
return;
@@ -1428,7 +1428,15 @@ void tap_listen_handler(struct ctx *c, uint32_t events)
return;
}
- c->fd_tap = accept4(c->fd_tap_listen, NULL, NULL, 0);
+ c->fd_tap = accept4(c->fd_tap_listen, NULL, NULL,
+ SOCK_NONBLOCK | SOCK_CLOEXEC);
+ if (c->fd_tap == -1) {
+ /* EAGAIN means a harmless spurious event */
+ if (errno != EAGAIN) {
+ warn_perror("Unable to accept tap client");
+ }
+ return;
+ }
if (!getsockopt(c->fd_tap, SOL_SOCKET, SO_PEERCRED, &ucred, &len))
info("accepted connection from PID %i", ucred.pid);
diff --git a/util.c b/util.c
index 73c9d51d..204391c7 100644
--- a/util.c
+++ b/util.c
@@ -238,7 +238,7 @@ int sock_l4_dualstack_any(const struct ctx *c, enum epoll_type type,
*/
int sock_unix(char *sock_path)
{
- int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
struct sockaddr_un addr = {
.sun_family = AF_UNIX,
};
--
2.53.0