mirror of https://github.com/sbt/sbt.git
Only the first session starts the server
Currently the server will try to start even if there are existing sbt sessions. This causes the second session to take over the server for Unix domain socket. This adds a check before the server comes up and make sure that the socket is not taken.
This commit is contained in:
parent
2b2c1f0568
commit
322f9b31cd
|
|
@ -29,6 +29,8 @@ import java.nio.ByteBuffer;
|
|||
|
||||
import java.net.Socket;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* Implements a {@link Socket} backed by a native Unix domain socket.
|
||||
*
|
||||
|
|
@ -41,6 +43,25 @@ public class NGUnixDomainSocket extends Socket {
|
|||
private final InputStream is;
|
||||
private final OutputStream os;
|
||||
|
||||
public NGUnixDomainSocket(String path) throws IOException {
|
||||
try {
|
||||
AtomicInteger fd = new AtomicInteger(
|
||||
NGUnixDomainSocketLibrary.socket(
|
||||
NGUnixDomainSocketLibrary.PF_LOCAL,
|
||||
NGUnixDomainSocketLibrary.SOCK_STREAM,
|
||||
0));
|
||||
NGUnixDomainSocketLibrary.SockaddrUn address =
|
||||
new NGUnixDomainSocketLibrary.SockaddrUn(path);
|
||||
int socketFd = fd.get();
|
||||
NGUnixDomainSocketLibrary.connect(socketFd, address, address.size());
|
||||
this.fd = new ReferenceCountedFileDescriptor(socketFd);
|
||||
this.is = new NGUnixDomainSocketInputStream();
|
||||
this.os = new NGUnixDomainSocketOutputStream();
|
||||
} catch (LastErrorException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Unix domain socket backed by a native file descriptor.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -131,6 +131,8 @@ public class NGUnixDomainSocketLibrary {
|
|||
public static native int listen(int fd, int backlog) throws LastErrorException;
|
||||
public static native int accept(int fd, SockaddrUn address, IntByReference addressLen)
|
||||
throws LastErrorException;
|
||||
public static native int connect(int fd, SockaddrUn address, int addressLen)
|
||||
throws LastErrorException;
|
||||
public static native int read(int fd, ByteBuffer buffer, int count)
|
||||
throws LastErrorException;
|
||||
public static native int write(int fd, ByteBuffer buffer, int count)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ package sbt
|
|||
package internal
|
||||
package server
|
||||
|
||||
import java.io.File
|
||||
import java.io.{ File, IOException }
|
||||
import java.net.{ SocketTimeoutException, InetAddress, ServerSocket, Socket }
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import java.nio.file.attribute.{ UserPrincipal, AclEntry, AclEntryPermission, AclEntryType }
|
||||
|
|
@ -54,15 +54,17 @@ private[sbt] object Server {
|
|||
val serverThread = new Thread("sbt-socket-server") {
|
||||
override def run(): Unit = {
|
||||
Try {
|
||||
ErrorHandling.translate(s"server failed to start on ${connection.shortName}. ") {
|
||||
connection.connectionType match {
|
||||
case ConnectionType.Local if isWindows =>
|
||||
new NGWin32NamedPipeServerSocket(pipeName)
|
||||
case ConnectionType.Local =>
|
||||
prepareSocketfile()
|
||||
new NGUnixDomainServerSocket(socketfile.getAbsolutePath)
|
||||
case ConnectionType.Tcp => new ServerSocket(port, 50, InetAddress.getByName(host))
|
||||
}
|
||||
connection.connectionType match {
|
||||
case ConnectionType.Local if isWindows =>
|
||||
// Named pipe already has an exclusive lock.
|
||||
addServerError(new NGWin32NamedPipeServerSocket(pipeName))
|
||||
case ConnectionType.Local =>
|
||||
tryClient(new NGUnixDomainSocket(socketfile.getAbsolutePath))
|
||||
prepareSocketfile()
|
||||
addServerError(new NGUnixDomainServerSocket(socketfile.getAbsolutePath))
|
||||
case ConnectionType.Tcp =>
|
||||
tryClient(new Socket(InetAddress.getByName(host), port))
|
||||
addServerError(new ServerSocket(port, 50, InetAddress.getByName(host)))
|
||||
}
|
||||
} match {
|
||||
case Failure(e) => p.failure(e)
|
||||
|
|
@ -87,6 +89,24 @@ private[sbt] object Server {
|
|||
}
|
||||
serverThread.start()
|
||||
|
||||
// Try the socket as a client to make sure that the server is not already up.
|
||||
// f tries to connect to the server, and flip the result.
|
||||
def tryClient(f: => Socket): Unit = {
|
||||
if (portfile.exists) {
|
||||
Try { f } match {
|
||||
case Failure(e) => ()
|
||||
case Success(socket) =>
|
||||
socket.close()
|
||||
throw new IOException("sbt server is already running.")
|
||||
}
|
||||
} else ()
|
||||
}
|
||||
|
||||
def addServerError(f: => ServerSocket): ServerSocket =
|
||||
ErrorHandling.translate(s"server failed to start on ${connection.shortName}. ") {
|
||||
f
|
||||
}
|
||||
|
||||
override def authenticate(challenge: String): Boolean = synchronized {
|
||||
if (token == challenge) {
|
||||
token = nextToken
|
||||
|
|
|
|||
Loading…
Reference in New Issue