Skip to content

Commit 9451ad9

Browse files
authored
Merge pull request #54 from eed3si9n/wip/channel
Add ServerSocketChannels (JDK 17 IPC Socket support)
2 parents b767e37 + 9d9abbb commit 9451ad9

8 files changed

Lines changed: 438 additions & 298 deletions

File tree

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
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.SocketOption;
9+
import java.net.StandardProtocolFamily;
10+
import java.nio.channels.ServerSocketChannel;
11+
import java.nio.channels.SocketChannel;
12+
import java.nio.channels.spi.SelectorProvider;
13+
import java.util.Arrays;
14+
import java.util.Collections;
15+
import java.util.List;
16+
import java.util.Properties;
17+
import java.util.Set;
18+
import java.util.stream.Collectors;
19+
20+
public abstract class ServerSocketChannels {
21+
22+
static final boolean isWin = System.getProperty("os.name", "").toLowerCase().startsWith("win");
23+
24+
public static ServerSocketChannel newServerSocketChannel(final String pathName, final boolean jni)
25+
throws IOException {
26+
if (isWin) {
27+
return ServerSocketChannels.fromServerSocket(
28+
new Win32NamedPipeServerSocket(pathName, jni, Win32SecurityLevel.LOGON_DACL));
29+
} else {
30+
return newUnixDomainSocket(pathName, jni);
31+
}
32+
}
33+
34+
public static ServerSocketChannel newUnixDomainSocket(final String pathName, final boolean jni)
35+
throws IOException {
36+
ServerSocketChannel result;
37+
if (isJava17Plus()) {
38+
try {
39+
result = newJdkUnixDomainSocket(pathName);
40+
} catch (ReflectiveOperationException e) {
41+
throw new IOException("failed to create " + pathName, e);
42+
}
43+
} else {
44+
result = ServerSocketChannels.fromServerSocket(new UnixDomainServerSocket(pathName, jni));
45+
}
46+
return result;
47+
}
48+
49+
static boolean isJava17Plus() {
50+
return getJavaVersion() >= 17;
51+
}
52+
53+
private static int getJavaVersion() {
54+
List<Integer> versions =
55+
Arrays.asList(System.getProperty("java.specification.version").split("\\."))
56+
.stream()
57+
.map(Integer::parseInt)
58+
.collect(Collectors.toList());
59+
if (versions.size() >= 2) {
60+
int major = versions.get(0);
61+
int minor = versions.get(1);
62+
if (major == 1) {
63+
return minor;
64+
} else {
65+
return major;
66+
}
67+
} else if (versions.size() >= 1) {
68+
return versions.get(0);
69+
} else {
70+
return 0;
71+
}
72+
}
73+
74+
static ServerSocketChannel newJdkUnixDomainSocket(final String pathName)
75+
throws ReflectiveOperationException, IOException {
76+
final SocketAddress address = unixDomainSocketAddress(pathName);
77+
final ProtocolFamily protocolFamily = unixProtocolFamily();
78+
final Method openMethod =
79+
ServerSocketChannel.class.getMethod("open", java.net.ProtocolFamily.class);
80+
final ServerSocketChannel serverSocketChannel =
81+
(ServerSocketChannel) openMethod.invoke(null, protocolFamily);
82+
serverSocketChannel.bind(address);
83+
return serverSocketChannel;
84+
}
85+
86+
static SocketAddress unixDomainSocketAddress(final String pathName)
87+
throws ReflectiveOperationException {
88+
final Class<?> clazz = Class.forName("java.net.UnixDomainSocketAddress");
89+
final Method method = clazz.getMethod("of", String.class);
90+
return (SocketAddress) method.invoke(null, pathName);
91+
}
92+
93+
static ProtocolFamily unixProtocolFamily() {
94+
return Arrays.stream(StandardProtocolFamily.class.getEnumConstants())
95+
.filter(a -> "UNIX".equals(a.name()))
96+
.findFirst()
97+
.orElseThrow(() -> new RuntimeException("not found UNIX value in StandardProtocolFamily"));
98+
}
99+
100+
public static ServerSocketChannel fromServerSocket(final ServerSocket socket) {
101+
return new ForwardingServerSocketChannel(socket);
102+
}
103+
104+
private static final class ForwardingServerSocketChannel extends ServerSocketChannel {
105+
private final ServerSocket socket;
106+
107+
ForwardingServerSocketChannel(ServerSocket socket) {
108+
super(SelectorProvider.provider());
109+
this.socket = socket;
110+
}
111+
112+
@Override
113+
public String toString() {
114+
return "ForwardingServerSocketChannel(" + this.socket.toString() + ")";
115+
}
116+
117+
@Override
118+
public SocketAddress getLocalAddress() {
119+
return this.socket.getLocalSocketAddress();
120+
}
121+
122+
@Override
123+
public ServerSocket socket() {
124+
return this.socket;
125+
}
126+
127+
@Override
128+
public SocketChannel accept() throws IOException {
129+
return SocketChannels.fromSocket(this.socket.accept());
130+
}
131+
132+
@Override
133+
public final <A1> ServerSocketChannel setOption(SocketOption<A1> name, A1 value)
134+
throws IOException {
135+
return this;
136+
}
137+
138+
@Override
139+
public final ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException {
140+
this.socket.bind(local, backlog);
141+
return this;
142+
}
143+
144+
@Override
145+
protected final void implConfigureBlocking(boolean block) throws IOException {}
146+
147+
@Override
148+
protected final void implCloseSelectableChannel() throws IOException {
149+
this.socket.close();
150+
}
151+
152+
@Override
153+
public final Set<SocketOption<?>> supportedOptions() {
154+
return Collections.EMPTY_SET;
155+
}
156+
157+
@Override
158+
public final <A1> A1 getOption(SocketOption<A1> name) {
159+
return null;
160+
}
161+
}
162+
}

src/main/java/org/scalasbt/ipcsocket/ServerSocketWrapper.java

Lines changed: 0 additions & 114 deletions
This file was deleted.

0 commit comments

Comments
 (0)