From 7180f4eaa716b68dde371d5a6eab694128d72d20 Mon Sep 17 00:00:00 2001 From: lucas lelievre Date: Mon, 3 Nov 2025 18:01:25 +0100 Subject: [PATCH] Make socket recover if slimevr crashed (#1604) --- .../desktop/platform/linux/SocketUtils.java | 20 +++++++++++++++++++ .../platform/linux/UnixSocketBridge.java | 11 +++++++++- .../platform/linux/UnixSocketRpcBridge.java | 16 +++++++++++++-- 3 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 server/desktop/src/main/java/dev/slimevr/desktop/platform/linux/SocketUtils.java diff --git a/server/desktop/src/main/java/dev/slimevr/desktop/platform/linux/SocketUtils.java b/server/desktop/src/main/java/dev/slimevr/desktop/platform/linux/SocketUtils.java new file mode 100644 index 000000000..f36af175c --- /dev/null +++ b/server/desktop/src/main/java/dev/slimevr/desktop/platform/linux/SocketUtils.java @@ -0,0 +1,20 @@ +package dev.slimevr.desktop.platform.linux; + +import java.io.IOException; +import java.net.StandardProtocolFamily; +import java.net.UnixDomainSocketAddress; +import java.nio.channels.SocketChannel; + + +public class SocketUtils { + + static boolean isSocketInUse(String socketPath) { + try (SocketChannel testChannel = SocketChannel.open(StandardProtocolFamily.UNIX)) { + testChannel.connect(UnixDomainSocketAddress.of(socketPath)); + return true; + } catch (IOException e) { + return false; + } + } + +} diff --git a/server/desktop/src/main/java/dev/slimevr/desktop/platform/linux/UnixSocketBridge.java b/server/desktop/src/main/java/dev/slimevr/desktop/platform/linux/UnixSocketBridge.java index 3b3580c73..d9b49bff3 100644 --- a/server/desktop/src/main/java/dev/slimevr/desktop/platform/linux/UnixSocketBridge.java +++ b/server/desktop/src/main/java/dev/slimevr/desktop/platform/linux/UnixSocketBridge.java @@ -46,7 +46,16 @@ public class UnixSocketBridge extends SteamVRBridge implements AutoCloseable { File socketFile = new File(socketPath); if (socketFile.exists()) { - throw new RuntimeException(socketPath + " socket already exists."); + if (SocketUtils.isSocketInUse(socketPath)) { + throw new RuntimeException( + socketPath + " socket is already in use by another process." + ); + } else { + LogManager.warning("[" + bridgeName + "] Cleaning up stale socket: " + socketPath); + if (!socketFile.delete()) { + throw new RuntimeException("Failed to delete stale socket: " + socketPath); + } + } } socketFile.deleteOnExit(); } diff --git a/server/desktop/src/main/java/dev/slimevr/desktop/platform/linux/UnixSocketRpcBridge.java b/server/desktop/src/main/java/dev/slimevr/desktop/platform/linux/UnixSocketRpcBridge.java index 82f2901fa..198ab3e51 100644 --- a/server/desktop/src/main/java/dev/slimevr/desktop/platform/linux/UnixSocketRpcBridge.java +++ b/server/desktop/src/main/java/dev/slimevr/desktop/platform/linux/UnixSocketRpcBridge.java @@ -35,10 +35,22 @@ public class UnixSocketRpcBridge implements dev.slimevr.bridge.Bridge, ) { this.socketPath = socketPath; this.protocolAPI = server.protocolAPI; + File socketFile = new File(socketPath); - if (socketFile.exists()) - throw new RuntimeException(socketPath + " socket already exists."); + if (socketFile.exists()) { + if (SocketUtils.isSocketInUse(socketPath)) { + throw new RuntimeException( + socketPath + " socket is already in use by another process." + ); + } else { + LogManager.warning("[SolarXR Bridge] Cleaning up stale socket: " + socketPath); + if (!socketFile.delete()) { + throw new RuntimeException("Failed to delete stale socket: " + socketPath); + } + } + } socketFile.deleteOnExit(); + try { socket = ServerSocketChannel.open(StandardProtocolFamily.UNIX); selector = Selector.open();