diff options
author | June McEnroe <june@causal.agency> | 2020-11-23 16:49:22 -0500 |
---|---|---|
committer | June McEnroe <june@causal.agency> | 2020-11-23 17:11:02 -0500 |
commit | 83dcb6f4856198b92431a0281922f26f0734ff56 (patch) | |
tree | 58392d12252615aead511c7f96157057b24120f9 | |
parent | Clean up main loop loops (diff) | |
download | pounce-2.1.tar.gz pounce-2.1.zip |
Unlink existing UNIX socket if it can't be connected to 2.1
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.
-rw-r--r-- | local.c | 36 |
1 files 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; } |