diff --git a/main-command/src/main/scala/sbt/internal/client/NetworkClient.scala b/main-command/src/main/scala/sbt/internal/client/NetworkClient.scala index 3dc6ebeab..746ffc4b9 100644 --- a/main-command/src/main/scala/sbt/internal/client/NetworkClient.scala +++ b/main-command/src/main/scala/sbt/internal/client/NetworkClient.scala @@ -337,6 +337,13 @@ class NetworkClient( conn } + private def bootSocketOpt(bootSocketName: String): Option[Socket] = + Try(ClientSocket.bootSocket(bootSocketName)).toOption match + case Some(x) => Some(x) + case None if Util.isWindows => + Try(ClientSocket.localSocket(bootSocketName, useJNI)).toOption + case _ => None + /** * Forks another instance of sbt in the background. * This instance must be shutdown explicitly via `sbt -client shutdown` @@ -351,9 +358,7 @@ class NetworkClient( * For unknown reasons, linux sometimes struggles to connect to the socket in some * scenarios. */ - var socket: Option[Socket] = - if (!Properties.isLinux) Try(ClientSocket.bootSocket(bootSocketName, useJNI)).toOption - else None + var socket: Option[Socket] = bootSocketOpt(bootSocketName) val term = Terminal.console term.exitRawMode() var serverStderrFile: Option[File] = None @@ -436,7 +441,7 @@ class NetworkClient( if (!startServer) { val deadline = 5.seconds.fromNow while (socket.isEmpty && !deadline.isOverdue()) { - socket = Try(ClientSocket.bootSocket(bootSocketName, useJNI)).toOption + socket = bootSocketOpt(bootSocketName) if (socket.isEmpty) Thread.sleep(20) } } @@ -457,7 +462,7 @@ class NetworkClient( val buffer = mutable.ArrayBuffer.empty[Byte] while (readThreadAlive.get) { if (socket.isEmpty) { - socket = Try(ClientSocket.bootSocket(bootSocketName, useJNI)).toOption + socket = bootSocketOpt(bootSocketName) } socket.foreach { s => try { diff --git a/protocol/src/main/scala/sbt/protocol/ClientSocket.scala b/protocol/src/main/scala/sbt/protocol/ClientSocket.scala index 08616bb4c..8e65ab0df 100644 --- a/protocol/src/main/scala/sbt/protocol/ClientSocket.scala +++ b/protocol/src/main/scala/sbt/protocol/ClientSocket.scala @@ -9,8 +9,9 @@ package sbt package protocol -import java.io.File -import java.net.{ Socket, URI, InetAddress } +import java.io.{ File, InputStream, OutputStream } +import java.net.{ InetAddress, Socket, StandardProtocolFamily, URI, UnixDomainSocketAddress } +import java.nio.channels.{ Channels, SocketChannel } import sjsonnew.BasicJsonProtocol import sjsonnew.support.scalajson.unsafe.{ Parser, Converter } import sjsonnew.shaded.scalajson.ast.unsafe.JValue @@ -46,6 +47,14 @@ object ClientSocket { if (isWindows) new Win32NamedPipeSocket(s"\\\\.\\pipe\\$name", useJNI) else new UnixDomainSocket(name, useJNI) - /** Connects to a Unix domain socket at the given path on all platforms (including Windows 10+). */ - def bootSocket(path: String, useJNI: Boolean): Socket = new UnixDomainSocket(path, useJNI) + def bootSocket(path: String): Socket = + val ch = SocketChannel.open(StandardProtocolFamily.UNIX) + ch.connect(UnixDomainSocketAddress.of(path)) + new Socket: + private val in = Channels.newInputStream(ch) + private val out = Channels.newOutputStream(ch) + override def getInputStream: InputStream = in + override def getOutputStream: OutputStream = out + override def close(): Unit = ch.close() + override def isClosed: Boolean = !ch.isOpen }