diff --git a/bench/main.c b/bench/main.c index 3bd4e51..c88347d 100644 --- a/bench/main.c +++ b/bench/main.c @@ -4,8 +4,6 @@ #include #include #include -#include -#include #include "../ipc.h" typedef struct Key Key; @@ -81,15 +79,8 @@ loadkeys(char *file) static void dial(void) { - struct sockaddr_un addr; - - fd = socket(AF_UNIX, SOCK_STREAM, 0); + fd = ipcconnect(); if(fd < 0) - die("socket"); - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - snprintf(addr.sun_path, sizeof(addr.sun_path), IPCPATH, getuid()); - if(connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) die("connect"); } diff --git a/gtk/main.c b/gtk/main.c index 2f7ef43..987faa6 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -2,8 +2,6 @@ #include #include #include -#include -#include #include #include "ipc.h" @@ -27,20 +25,9 @@ static GType imtype; static void srvconnect(Im *im) { - struct sockaddr_un addr; - if(im->fd >= 0) return; - im->fd = socket(AF_UNIX, SOCK_STREAM, 0); - if(im->fd < 0) - return; - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - snprintf(addr.sun_path, sizeof(addr.sun_path), IPCPATH, getuid()); - if(connect(im->fd, (struct sockaddr*)&addr, sizeof(addr)) < 0){ - close(im->fd); - im->fd = -1; - } + im->fd = ipcconnect(); } static void diff --git a/ipc.c b/ipc.c index 275bb09..38cba70 100644 --- a/ipc.c +++ b/ipc.c @@ -1,7 +1,10 @@ #include +#include +#include #include #include #include +#include #include "ipc.h" #if !defined(MSG_NOSIGNAL) && !defined(SO_NOSIGPIPE) @@ -21,6 +24,49 @@ getlen(const unsigned char p[Ipclensz]) return p[0] | (p[1] << 8); } +int +ipcpath(char *dst, size_t cap) +{ + const char *dir, *sep; + int n; + + if(dst == NULL || cap == 0) + return -1; + dir = getenv("XDG_RUNTIME_DIR"); + if(dir != NULL && dir[0] == '/'){ + sep = dir[strlen(dir)-1] == '/' ? "" : "/"; + n = snprintf(dst, cap, "%s%sstrans.sock", dir, sep); + }else + n = snprintf(dst, cap, "/tmp/strans.%lu", + (unsigned long)getuid()); + if(n < 0 || (size_t)n >= cap) + return -1; + return 0; +} + +int +ipcconnect(void) +{ + struct sockaddr_un addr; + int e, fd; + + memset(&addr, 0, sizeof addr); + addr.sun_family = AF_UNIX; + if(ipcpath(addr.sun_path, sizeof addr.sun_path) < 0){ + errno = ENAMETOOLONG; + return -1; + } + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if(fd < 0) + return -1; + if(connect(fd, (struct sockaddr*)&addr, sizeof addr) == 0) + return fd; + e = errno; + close(fd); + errno = e; + return -1; +} + void ipcpackreq(unsigned char req[Ipcreqsz], int want, unsigned int mod, unsigned int key) diff --git a/ipc.h b/ipc.h index a56f588..0cbf70d 100644 --- a/ipc.h +++ b/ipc.h @@ -3,8 +3,6 @@ #include -#define IPCPATH "/tmp/strans.%d" - /* * Request: [flags, modifiers, key byte 0, ..., key byte 3]. * Flags request preedit and distinguish lifecycle reset from physical Escape. @@ -61,5 +59,7 @@ int ipcpackresp(unsigned char*, size_t, int, const char*, size_t, const char*, s int ipcreadn(int, void*, size_t); int ipcsend(int, const void*, size_t); int ipcreadresp(int, int, char*, size_t, char*, size_t, Ipcresp*); +int ipcpath(char*, size_t); +int ipcconnect(void); #endif diff --git a/srv.c b/srv.c index 1148fce..938e5c4 100644 --- a/srv.c +++ b/srv.c @@ -1,7 +1,10 @@ #include "dat.h" #include "fn.h" -static char adir[40]; +#include +#include + +static char adir[256]; static Channel *clientc; typedef struct Client Client; @@ -71,12 +74,16 @@ clientthread(void *arg) static void srvinit(void) { - char addr[64]; + char addr[128], path[sizeof(((struct sockaddr_un*)0)->sun_path)]; - snprint(addr, sizeof(addr), "unix!" IPCPATH, getuid()); - remove(addr + 5); + if(ipcpath(path, sizeof path) < 0) + die("IPC path is too long"); + if(snprint(addr, sizeof addr, "unix!%s", path) >= (int)sizeof addr) + die("IPC address is too long"); if(announce(addr, adir) < 0) - die("announce: %r"); + die("IPC endpoint is already in use: %r"); + if(chmod(path, 0600) < 0) + die("can't protect IPC endpoint: %s", path); } void diff --git a/tests/ipc_test.c b/tests/ipc_test.c index 3c9bdaf..ac51bf2 100644 --- a/tests/ipc_test.c +++ b/tests/ipc_test.c @@ -1,3 +1,7 @@ +#define _POSIX_C_SOURCE 200809L + +#include +#include #include "test.h" void @@ -21,3 +25,29 @@ ipc_masks_modifiers(struct ct *t) CT_EQ_UINT(t, 0, key); CT_CHECK(t, ipcreqreset(buf)); } + +void +ipc_runtime_path(struct ct *t) +{ + char buf[128], fallback[128], *old, *saved; + + old = getenv("XDG_RUNTIME_DIR"); + saved = old == nil ? nil : strdup(old); + setenv("XDG_RUNTIME_DIR", "/tmp/strans-runtime-test", 1); + CT_EQ_INT(t, 0, ipcpath(buf, sizeof buf)); + CT_EQ_STR(t, "/tmp/strans-runtime-test/strans.sock", buf); + setenv("XDG_RUNTIME_DIR", "/tmp/strans-runtime-test/", 1); + CT_EQ_INT(t, 0, ipcpath(buf, sizeof buf)); + CT_EQ_STR(t, "/tmp/strans-runtime-test/strans.sock", buf); + setenv("XDG_RUNTIME_DIR", "relative", 1); + CT_EQ_INT(t, 0, ipcpath(buf, sizeof buf)); + snprint(fallback, sizeof fallback, "/tmp/strans.%d", getuid()); + CT_EQ_STR(t, fallback, buf); + CT_EQ_INT(t, -1, ipcpath(buf, 4)); + CT_EQ_INT(t, -1, ipcpath(nil, sizeof buf)); + if(saved != nil){ + setenv("XDG_RUNTIME_DIR", saved, 1); + free(saved); + }else + unsetenv("XDG_RUNTIME_DIR"); +} diff --git a/tests/test.h b/tests/test.h index 756c6cc..b360b82 100644 --- a/tests/test.h +++ b/tests/test.h @@ -64,5 +64,6 @@ void dictionary_candidates(struct ct*); void dictionary_misses_clear_result(struct ct*); void dictionary_emoji_identity(struct ct*); void ipc_masks_modifiers(struct ct*); +void ipc_runtime_path(struct ct*); #endif diff --git a/tests/unit_test.c b/tests/unit_test.c index 6a87032..ce28a33 100644 --- a/tests/unit_test.c +++ b/tests/unit_test.c @@ -113,6 +113,7 @@ static const struct ct_test tests[] = { { "dict/misses-clear-result", dictionary_misses_clear_result }, { "dict/emoji-identity", dictionary_emoji_identity }, { "ipc/masks-modifiers", ipc_masks_modifiers }, + { "ipc/runtime-path", ipc_runtime_path }, }; void diff --git a/xim/main.c b/xim/main.c index 8e6ea5f..f010f02 100644 --- a/xim/main.c +++ b/xim/main.c @@ -2,8 +2,6 @@ #include #include #include -#include -#include #include #include #include @@ -119,22 +117,11 @@ srvclose(Ic *state) static int srvconnect(Ic *state) { - struct sockaddr_un addr; - int fd; - if(state->fd >= 0) return 0; - fd = socket(AF_UNIX, SOCK_STREAM, 0); - if(fd < 0) + state->fd = ipcconnect(); + if(state->fd < 0) return -1; - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - snprintf(addr.sun_path, sizeof(addr.sun_path), IPCPATH, getuid()); - if(connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0){ - close(fd); - return -1; - } - state->fd = fd; return 0; }