From 83dcb6f4856198b92431a0281922f26f0734ff56 Mon Sep 17 00:00:00 2001 From: "C. McEnroe" Date: Mon, 23 Nov 2020 16:49:22 -0500 Subject: Unlink existing UNIX socket if it can't be connected to I think this emulates SO_REUSEADDR, which for some reason doesn't work on PF_UNIX. If the socket exists, check if connect(2) works, rather than clobbering the socket being used by a still-running instance. --- local.c | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/local.c b/local.c index 21e7cb1..ff879c8 100644 --- a/local.c +++ b/local.c @@ -158,21 +158,37 @@ static void unixUnlink(void) { if (error) warn("unlinkat"); } -size_t localUnix(int fds[], size_t cap, const char *path) { - if (!cap) return 0; - - int sock = socket(PF_UNIX, SOCK_STREAM, 0); - if (sock < 0) err(EX_OSERR, "socket"); - +static int unixBind(int sock, const char *path) { struct sockaddr_un addr = { .sun_family = AF_UNIX }; - int len = snprintf( - addr.sun_path, sizeof(addr.sun_path), "%s", path - ); + int len = snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", path); if ((size_t)len >= sizeof(addr.sun_path)) { errx(EX_CONFIG, "path too long: %s", path); } int error = bind(sock, (struct sockaddr *)&addr, SUN_LEN(&addr)); + if (!error || errno != EADDRINUSE) return error; + + int check = socket(PF_UNIX, SOCK_STREAM, 0); + if (check < 0) err(EX_OSERR, "socket"); + + error = connect(check, (struct sockaddr *)&addr, SUN_LEN(&addr)); + close(check); + if (!error) { + errno = EADDRINUSE; + return -1; + } + + unlink(path); + return bind(sock, (struct sockaddr *)&addr, SUN_LEN(&addr)); +} + +size_t localUnix(int fds[], size_t cap, const char *path) { + if (!cap) return 0; + + int sock = socket(PF_UNIX, SOCK_STREAM, 0); + if (sock < 0) err(EX_OSERR, "socket"); + + int error = unixBind(sock, path); if (error) err(EX_UNAVAILABLE, "%s", path); char dir[PATH_MAX] = "."; @@ -227,8 +243,8 @@ int localAccept(struct tls **client, int bind) { if (unix) { int sent = recvfd(fd); - if (sent < 0) err(EX_IOERR, "recvfd"); close(fd); + if (sent < 0) return sent; fd = sent; } -- cgit 1.4.1