Skip to content

Commit daab442

Browse files
authored
Merge pull request #53 from xuwei-k/unix-domain-socket
Add `java.net.UnixDomainSocketAddress` support
2 parents 11dd6aa + 5e045d4 commit daab442

File tree

5 files changed

+401
-0
lines changed

5 files changed

+401
-0
lines changed

.github/workflows/ci.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ on: [pull_request, push]
33

44
jobs:
55
test:
6+
timeout-minutes: 20
67
strategy:
78
fail-fast: false
89
matrix:
@@ -22,6 +23,9 @@ jobs:
2223
- os: windows-latest
2324
java: 8
2425
jobtype: 1
26+
- os: windows-latest
27+
java: 25
28+
jobtype: 2
2529
runs-on: ${{ matrix.os }}
2630
env:
2731
JAVA_OPTS: -Xms800M -Xmx2G -Xss6M -XX:ReservedCodeCacheSize=128M -server -Dsbt.io.virtual=false -Dfile.encoding=UTF-8

build.sbt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,3 +221,11 @@ def eval(cmd: Seq[String], logger: Logger): Unit = {
221221
s"'${cmd mkString " "}' exited with ${proc.exitValue}"
222222
)
223223
}
224+
225+
Test / unmanagedSourceDirectories ++= {
226+
if (scala.util.Properties.isJavaAtLeast("17")) {
227+
Seq((Test / sourceDirectory).value / "java-17")
228+
} else {
229+
Nil
230+
}
231+
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package org.scalasbt.ipcsocket;
2+
3+
import java.io.IOException;
4+
import java.lang.reflect.Method;
5+
import java.net.ProtocolFamily;
6+
import java.net.ServerSocket;
7+
import java.net.SocketAddress;
8+
import java.net.SocketException;
9+
import java.net.StandardProtocolFamily;
10+
import java.nio.channels.ServerSocketChannel;
11+
import java.util.Arrays;
12+
13+
public abstract class ServerSocketWrapper {
14+
private ServerSocketWrapper() {}
15+
16+
private static SocketAddress unixDomainSocketAddress(final String pathName)
17+
throws ReflectiveOperationException {
18+
final Class<?> clazz = Class.forName("java.net.UnixDomainSocketAddress");
19+
final Method method = clazz.getMethod("of", String.class);
20+
return (SocketAddress) method.invoke(null, pathName);
21+
}
22+
23+
private static ProtocolFamily unixProtocolFamily() {
24+
return Arrays.stream(StandardProtocolFamily.class.getEnumConstants())
25+
.filter(a -> "UNIX".equals(a.name()))
26+
.findFirst()
27+
.orElseThrow(() -> new RuntimeException("not found UNIX value in StandardProtocolFamily"));
28+
}
29+
30+
static ServerSocketWrapper newJdkUnixDomainSocket(final String pathName)
31+
throws ReflectiveOperationException, IOException {
32+
final SocketAddress address = unixDomainSocketAddress(pathName);
33+
final ProtocolFamily protocolFamily = unixProtocolFamily();
34+
final Method openMethod =
35+
ServerSocketChannel.class.getMethod("open", java.net.ProtocolFamily.class);
36+
final ServerSocketChannel serverSocketChannel =
37+
(ServerSocketChannel) openMethod.invoke(null, protocolFamily);
38+
serverSocketChannel.bind(address);
39+
return ServerSocketWrapper.fromServerSocketChannel(serverSocketChannel);
40+
}
41+
42+
public static ServerSocketWrapper newUnixDomainSocket(
43+
final String pathName, final boolean jni, final boolean jdk) throws IOException {
44+
ServerSocketWrapper result;
45+
if (jdk) {
46+
try {
47+
result = newJdkUnixDomainSocket(pathName);
48+
} catch (ReflectiveOperationException e) {
49+
result = ServerSocketWrapper.fromServerSocket(new UnixDomainServerSocket(pathName, jni));
50+
}
51+
} else {
52+
result = ServerSocketWrapper.fromServerSocket(new UnixDomainServerSocket(pathName, jni));
53+
}
54+
return result;
55+
}
56+
57+
public abstract void setSoTimeout(int timeout) throws SocketException;
58+
59+
public abstract SocketWrapper accept() throws IOException;
60+
61+
public abstract void close() throws IOException;
62+
63+
public static ServerSocketWrapper fromServerSocket(final ServerSocket socket) {
64+
return new ServerSocketImpl(socket);
65+
}
66+
67+
public static ServerSocketWrapper fromServerSocketChannel(final ServerSocketChannel channel) {
68+
return new ServerSocketChannelImpl(channel);
69+
}
70+
71+
private static final class ServerSocketImpl extends ServerSocketWrapper {
72+
private final ServerSocket socket;
73+
74+
ServerSocketImpl(ServerSocket socket) {
75+
this.socket = socket;
76+
}
77+
78+
@Override
79+
public void setSoTimeout(int timeout) throws SocketException {
80+
socket.setSoTimeout(timeout);
81+
}
82+
83+
@Override
84+
public SocketWrapper accept() throws IOException {
85+
return SocketWrapper.fromSocket(socket.accept());
86+
}
87+
88+
@Override
89+
public void close() throws IOException {
90+
socket.close();
91+
}
92+
}
93+
94+
private static final class ServerSocketChannelImpl extends ServerSocketWrapper {
95+
private final ServerSocketChannel channel;
96+
97+
ServerSocketChannelImpl(ServerSocketChannel channel) {
98+
this.channel = channel;
99+
}
100+
101+
@Override
102+
public void setSoTimeout(int timeout) throws SocketException {}
103+
104+
@Override
105+
public SocketWrapper accept() throws IOException {
106+
return SocketWrapper.fromByteChannel(channel.accept());
107+
}
108+
109+
@Override
110+
public void close() throws IOException {
111+
channel.close();
112+
}
113+
}
114+
}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
package org.scalasbt.ipcsocket;
2+
3+
import java.io.IOException;
4+
import java.lang.reflect.Method;
5+
import java.net.ProtocolFamily;
6+
import java.net.Socket;
7+
import java.net.SocketAddress;
8+
import java.net.StandardProtocolFamily;
9+
import java.nio.ByteBuffer;
10+
import java.nio.channels.ByteChannel;
11+
import java.nio.channels.ServerSocketChannel;
12+
import java.util.Arrays;
13+
14+
public abstract class SocketWrapper {
15+
private SocketWrapper() {}
16+
17+
public abstract void write(int value) throws IOException;
18+
19+
public abstract void write(byte[] value) throws IOException;
20+
21+
public abstract void write(byte[] b, int offset, int len) throws IOException;
22+
23+
public abstract void close() throws IOException;
24+
25+
public abstract int read() throws IOException;
26+
27+
public abstract void flush() throws IOException;
28+
29+
public static SocketWrapper fromSocket(Socket socket) {
30+
return new SocketImpl(socket);
31+
}
32+
33+
public static SocketWrapper fromByteChannel(ByteChannel channel) {
34+
return new ByteChannelImpl(channel);
35+
}
36+
37+
private static final class ByteChannelImpl extends SocketWrapper {
38+
private final ByteChannel channel;
39+
40+
private ByteChannelImpl(ByteChannel channel) {
41+
this.channel = channel;
42+
}
43+
44+
@Override
45+
public void write(int value) throws IOException {
46+
channel.write(ByteBuffer.wrap(new byte[] {(byte) value}));
47+
}
48+
49+
@Override
50+
public void write(byte[] value) throws IOException {
51+
channel.write(ByteBuffer.wrap(value));
52+
}
53+
54+
@Override
55+
public void write(byte[] b, int offset, int len) throws IOException {
56+
channel.write(ByteBuffer.wrap(b, offset, len));
57+
}
58+
59+
@Override
60+
public void close() throws IOException {
61+
channel.close();
62+
}
63+
64+
@Override
65+
public int read() throws IOException {
66+
final ByteBuffer buf = ByteBuffer.allocate(1);
67+
int n;
68+
do {
69+
n = channel.read(buf);
70+
} while (n == 0);
71+
72+
if (-1 == n) {
73+
return -1;
74+
} else {
75+
return buf.get(0) & 0xff;
76+
}
77+
}
78+
79+
@Override
80+
public void flush() {}
81+
}
82+
83+
private static final class SocketImpl extends SocketWrapper {
84+
private final Socket socket;
85+
86+
private SocketImpl(Socket socket) {
87+
this.socket = socket;
88+
}
89+
90+
@Override
91+
public void write(int value) throws IOException {
92+
socket.getOutputStream().write(value);
93+
}
94+
95+
@Override
96+
public void write(byte[] value) throws IOException {
97+
socket.getOutputStream().write(value);
98+
}
99+
100+
@Override
101+
public void write(byte[] b, int offset, int len) throws IOException {
102+
socket.getOutputStream().write(b, offset, len);
103+
}
104+
105+
@Override
106+
public void close() throws IOException {
107+
socket.getOutputStream().close();
108+
socket.getInputStream().close();
109+
}
110+
111+
@Override
112+
public int read() throws IOException {
113+
return socket.getInputStream().read();
114+
}
115+
116+
@Override
117+
public void flush() throws IOException {
118+
socket.getOutputStream().flush();
119+
}
120+
}
121+
}

0 commit comments

Comments
 (0)