mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-08-18 13:16:02 +00:00
Removes ipc port file after shutdown, reduced so timeout for rmi clients
This commit is contained in:
+54
-35
@@ -9,6 +9,7 @@ import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
@@ -56,11 +57,9 @@ abstract class InterProcessCommunicator implements InterProcessCommunicationProt
|
||||
// visible for testing
|
||||
static InterProcessCommunicator start(Path portFilePath, InterProcessCommunicationProtocol endpoint) throws IOException {
|
||||
System.setProperty("java.rmi.server.hostname", "localhost");
|
||||
// try to connect to existing server:
|
||||
int port = readPort(portFilePath);
|
||||
LOG.debug("Connecting to running process on TCP port {}...", port);
|
||||
try {
|
||||
ClientCommunicator client = new ClientCommunicator(port);
|
||||
// try to connect to existing server:
|
||||
ClientCommunicator client = new ClientCommunicator(portFilePath);
|
||||
LOG.trace("Connected to running process.");
|
||||
return client;
|
||||
} catch (ConnectException | ConnectIOException | NotBoundException e) {
|
||||
@@ -70,8 +69,7 @@ abstract class InterProcessCommunicator implements InterProcessCommunicationProt
|
||||
|
||||
// spawn a new server:
|
||||
LOG.trace("Spawning new server...");
|
||||
ServerCommunicator server = new ServerCommunicator(endpoint);
|
||||
writePort(portFilePath, server.getPort());
|
||||
ServerCommunicator server = new ServerCommunicator(endpoint, portFilePath);
|
||||
LOG.debug("Server listening on port {}.", server.getPort());
|
||||
return server;
|
||||
}
|
||||
@@ -98,12 +96,30 @@ abstract class InterProcessCommunicator implements InterProcessCommunicationProt
|
||||
|
||||
private final IpcProtocolRemote remote;
|
||||
|
||||
private ClientCommunicator(int port) throws ConnectException, NotBoundException, RemoteException {
|
||||
if (port == 0) {
|
||||
throw new ConnectException("Can not connect to port 0.");
|
||||
private ClientCommunicator(Path portFilePath) throws ConnectException, NotBoundException, RemoteException {
|
||||
if (Files.notExists(portFilePath)) {
|
||||
throw new ConnectException("No IPC port file.");
|
||||
}
|
||||
try {
|
||||
int port = ClientCommunicator.readPort(portFilePath);
|
||||
LOG.debug("Connecting to port {}...");
|
||||
Registry registry = LocateRegistry.getRegistry("localhost", port, new ClientSocketFactory());
|
||||
this.remote = (IpcProtocolRemote) registry.lookup(RMI_NAME);
|
||||
} catch (IOException e) {
|
||||
throw new ConnectException("Error reading IPC port file.");
|
||||
}
|
||||
}
|
||||
|
||||
private static int readPort(Path portFilePath) throws IOException {
|
||||
ByteBuffer buf = ByteBuffer.allocate(Integer.BYTES);
|
||||
try (ReadableByteChannel ch = Files.newByteChannel(portFilePath, StandardOpenOption.READ)) {
|
||||
if (ch.read(buf) == Integer.BYTES) {
|
||||
buf.flip();
|
||||
return buf.getInt();
|
||||
} else {
|
||||
throw new IOException("Invalid IPC port file.");
|
||||
}
|
||||
}
|
||||
Registry registry = LocateRegistry.getRegistry("localhost", port);
|
||||
this.remote = (IpcProtocolRemote) registry.lookup(RMI_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -132,8 +148,9 @@ abstract class InterProcessCommunicator implements InterProcessCommunicationProt
|
||||
private final ServerSocket socket;
|
||||
private final Registry registry;
|
||||
private final IpcProtocolRemoteImpl remote;
|
||||
private final Path portFilePath;
|
||||
|
||||
private ServerCommunicator(InterProcessCommunicationProtocol delegate) throws IOException {
|
||||
private ServerCommunicator(InterProcessCommunicationProtocol delegate, Path portFilePath) throws IOException {
|
||||
this.socket = new ServerSocket(0, Byte.MAX_VALUE, InetAddress.getByName("localhost"));
|
||||
RMIClientSocketFactory csf = RMISocketFactory.getDefaultSocketFactory();
|
||||
SingletonServerSocketFactory ssf = new SingletonServerSocketFactory(socket);
|
||||
@@ -141,6 +158,20 @@ abstract class InterProcessCommunicator implements InterProcessCommunicationProt
|
||||
this.remote = new IpcProtocolRemoteImpl(delegate);
|
||||
UnicastRemoteObject.exportObject(remote, 0);
|
||||
registry.rebind(RMI_NAME, remote);
|
||||
this.portFilePath = portFilePath;
|
||||
ServerCommunicator.writePort(portFilePath, socket.getLocalPort());
|
||||
}
|
||||
|
||||
private static void writePort(Path portFilePath, int port) throws IOException {
|
||||
ByteBuffer buf = ByteBuffer.allocate(Integer.BYTES);
|
||||
buf.putInt(port);
|
||||
buf.flip();
|
||||
MoreFiles.createParentDirectories(portFilePath);
|
||||
try (WritableByteChannel ch = Files.newByteChannel(portFilePath, StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) {
|
||||
if (ch.write(buf) != Integer.BYTES) {
|
||||
throw new IOException("Did not write expected number of bytes.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -163,6 +194,7 @@ abstract class InterProcessCommunicator implements InterProcessCommunicationProt
|
||||
registry.unbind(RMI_NAME);
|
||||
UnicastRemoteObject.unexportObject(remote, true);
|
||||
socket.close();
|
||||
Files.deleteIfExists(portFilePath);
|
||||
LOG.debug("Server shut down.");
|
||||
} catch (NotBoundException | IOException e) {
|
||||
LOG.warn("Failed to close IPC Server.", e);
|
||||
@@ -211,31 +243,18 @@ abstract class InterProcessCommunicator implements InterProcessCommunicationProt
|
||||
|
||||
}
|
||||
|
||||
private static int readPort(Path path) throws IOException {
|
||||
if (Files.notExists(path)) {
|
||||
return 0;
|
||||
}
|
||||
ByteBuffer buf = ByteBuffer.allocate(Integer.BYTES);
|
||||
try (ReadableByteChannel ch = Files.newByteChannel(path, StandardOpenOption.READ)) {
|
||||
if (ch.read(buf) == Integer.BYTES) {
|
||||
buf.flip();
|
||||
return buf.getInt();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Creates client sockets with short timeouts.
|
||||
*/
|
||||
private static class ClientSocketFactory implements RMIClientSocketFactory {
|
||||
|
||||
private static void writePort(Path path, int port) throws IOException {
|
||||
ByteBuffer buf = ByteBuffer.allocate(Integer.BYTES);
|
||||
buf.putInt(port);
|
||||
buf.flip();
|
||||
MoreFiles.createParentDirectories(path);
|
||||
try (WritableByteChannel ch = Files.newByteChannel(path, StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) {
|
||||
if (ch.write(buf) != Integer.BYTES) {
|
||||
throw new IOException("Did not write expected number of bytes.");
|
||||
}
|
||||
@Override
|
||||
public Socket createSocket(String host, int port) throws IOException {
|
||||
Socket socket = new Socket(host, port);
|
||||
socket.setSoTimeout(1000); // 1s
|
||||
return socket;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user