aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/msgpack_rpc/server.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/msgpack_rpc/server.c')
-rw-r--r--src/nvim/msgpack_rpc/server.c71
1 files changed, 39 insertions, 32 deletions
diff --git a/src/nvim/msgpack_rpc/server.c b/src/nvim/msgpack_rpc/server.c
index f15ce82917..c9e707aa92 100644
--- a/src/nvim/msgpack_rpc/server.c
+++ b/src/nvim/msgpack_rpc/server.c
@@ -23,7 +23,6 @@
#define MAX_CONNECTIONS 32
#define ENV_LISTEN "NVIM_LISTEN_ADDRESS" // deprecated
-#define ENV_NVIM "NVIM"
static garray_T watchers = GA_EMPTY_INIT_VALUE;
@@ -43,7 +42,7 @@ bool server_init(const char *listen_addr)
int rv = listen_addr ? server_start(listen_addr) : 1;
if (0 != rv) {
- listen_addr = server_address_new();
+ listen_addr = server_address_new(NULL);
if (!listen_addr) {
return false;
}
@@ -56,6 +55,11 @@ bool server_init(const char *listen_addr)
os_unsetenv(ENV_LISTEN);
}
+ // TODO(justinmk): this is for logging_spec. Can remove this after nvim_log #7062 is merged.
+ if (os_env_exists("__NVIM_TEST_LOG")) {
+ ELOG("test log message");
+ }
+
return rv == 0;
}
@@ -83,23 +87,26 @@ void server_teardown(void)
/// Generates unique address for local server.
///
-/// In Windows this is a named pipe in the format
-/// \\.\pipe\nvim-<PID>-<COUNTER>.
-///
-/// For other systems it is a path returned by vim_tempname().
-///
-/// This function is NOT thread safe
-char *server_address_new(void)
+/// Named pipe format:
+/// - Windows: "\\.\pipe\<name>.<pid>.<counter>"
+/// - Other: "~/.local/state/nvim/<name>.<pid>.<counter>"
+char *server_address_new(const char *name)
{
-#ifdef WIN32
static uint32_t count = 0;
- char template[ADDRESS_MAX_SIZE];
- snprintf(template, ADDRESS_MAX_SIZE,
- "\\\\.\\pipe\\nvim-%" PRIu64 "-%" PRIu32, os_get_pid(), count++);
- return xstrdup(template);
+ char fmt[ADDRESS_MAX_SIZE];
+#ifdef WIN32
+ int r = snprintf(fmt, sizeof(fmt), "\\\\.\\pipe\\%s.%" PRIu64 ".%" PRIu32,
+ name ? name : "nvim", os_get_pid(), count++);
#else
- return (char *)vim_tempname();
+ char *dir = get_xdg_home(kXDGStateHome);
+ int r = snprintf(fmt, sizeof(fmt), "%s/%s.%" PRIu64 ".%" PRIu32,
+ dir, name ? name : "nvim", os_get_pid(), count++);
+ xfree(dir);
#endif
+ if ((size_t)r >= sizeof(fmt)) {
+ ELOG("truncated server address");
+ }
+ return xstrdup(fmt);
}
/// Check if this instance owns a pipe address.
@@ -114,35 +121,35 @@ bool server_owns_pipe_address(const char *path)
return false;
}
-/// Starts listening for API calls.
+/// Starts listening for RPC calls.
///
-/// The socket type is determined by parsing `endpoint`: If it's a valid IPv4
-/// or IPv6 address in 'ip:[port]' format, then it will be a TCP socket.
-/// Otherwise it will be a Unix socket or named pipe (Windows).
+/// Socket type is decided by the format of `addr`:
+/// - TCP socket if it looks like an IPv4/6 address ("ip:[port]").
+/// - If [port] is omitted, a random one is assigned.
+/// - Unix socket (or named pipe on Windows) otherwise.
+/// - If the name doesn't contain slashes it is appended to a generated path. #8519
///
-/// If no port is given, a random one will be assigned.
-///
-/// @param endpoint Address of the server. Either a 'ip:[port]' string or an
-/// arbitrary identifier (trimmed to 256 bytes) for the Unix
-/// socket or named pipe.
-/// @returns 0: success, 1: validation error, 2: already listening,
-/// -errno: failed to bind or listen.
-int server_start(const char *endpoint)
+/// @param addr Server address: a "ip:[port]" string or arbitrary name or filepath (max 256 bytes)
+/// for the Unix socket or named pipe.
+/// @returns 0: success, 1: validation error, 2: already listening, -errno: failed to bind/listen.
+int server_start(const char *addr)
{
- if (endpoint == NULL || endpoint[0] == '\0') {
- WLOG("Empty or NULL endpoint");
+ if (addr == NULL || addr[0] == '\0') {
+ WLOG("Empty or NULL address");
return 1;
}
+ bool isname = !strstr(addr, ":") && !strstr(addr, "/") && !strstr(addr, "\\");
+ char *addr_gen = isname ? server_address_new(addr) : NULL;
SocketWatcher *watcher = xmalloc(sizeof(SocketWatcher));
-
- int result = socket_watcher_init(&main_loop, watcher, endpoint);
+ int result = socket_watcher_init(&main_loop, watcher, isname ? addr_gen : addr);
+ xfree(addr_gen);
if (result < 0) {
xfree(watcher);
return result;
}
- // Check if a watcher for the endpoint already exists
+ // Check if a watcher for the address already exists.
for (int i = 0; i < watchers.ga_len; i++) {
if (!strcmp(watcher->addr, ((SocketWatcher **)watchers.ga_data)[i]->addr)) {
ELOG("Already listening on %s", watcher->addr);