1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package io.netty.channel.socket.nio;
18
19 import io.netty.channel.ChannelConfig;
20 import io.netty.channel.ChannelException;
21 import io.netty.channel.ChannelMetadata;
22 import io.netty.channel.ChannelOption;
23 import io.netty.channel.ChannelOutboundBuffer;
24 import io.netty.channel.DefaultChannelConfig;
25 import io.netty.channel.ServerChannelRecvByteBufAllocator;
26 import io.netty.channel.nio.AbstractNioMessageChannel;
27 import io.netty.util.NetUtil;
28 import io.netty.util.internal.PlatformDependent;
29 import io.netty.util.internal.SocketUtils;
30 import io.netty.util.internal.SuppressJava6Requirement;
31 import io.netty.util.internal.logging.InternalLogger;
32 import io.netty.util.internal.logging.InternalLoggerFactory;
33
34 import java.io.IOException;
35 import java.lang.reflect.Method;
36
37 import java.net.SocketAddress;
38 import java.nio.channels.SelectionKey;
39 import java.nio.channels.ServerSocketChannel;
40 import java.nio.channels.SocketChannel;
41 import java.nio.channels.spi.SelectorProvider;
42 import java.util.ArrayList;
43 import java.util.List;
44 import java.util.Map;
45
46 import static io.netty.channel.ChannelOption.SO_BACKLOG;
47 import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
48
49
50
51
52
53
54 public final class NioServerDomainSocketChannel extends AbstractNioMessageChannel
55 implements io.netty.channel.ServerChannel {
56 private static final Method OPEN_SERVER_SOCKET_CHANNEL_WITH_FAMILY =
57 SelectorProviderUtil.findOpenMethod("openServerSocketChannel");
58 private static final InternalLogger logger = InternalLoggerFactory.getInstance(NioServerDomainSocketChannel.class);
59 private static final ChannelMetadata METADATA = new ChannelMetadata(false, 16);
60 private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();
61 private final NioDomainServerSocketChannelConfig config;
62 private volatile boolean bound;
63
64
65 static ServerSocketChannel newChannel(SelectorProvider provider) {
66 if (PlatformDependent.javaVersion() < 16) {
67 throw new UnsupportedOperationException("Only supported with Java 16+");
68 }
69 try {
70 ServerSocketChannel channel =
71 SelectorProviderUtil.newDomainSocketChannel(OPEN_SERVER_SOCKET_CHANNEL_WITH_FAMILY, provider);
72 if (channel == null) {
73 throw new ChannelException("Failed to open a socket.");
74 }
75 return channel;
76 } catch (IOException e) {
77 throw new ChannelException("Failed to open a socket.", e);
78 }
79 }
80
81 @Override
82 protected ServerSocketChannel javaChannel() {
83 return (ServerSocketChannel) super.javaChannel();
84 }
85
86
87
88
89 public NioServerDomainSocketChannel() {
90 this(DEFAULT_SELECTOR_PROVIDER);
91 }
92
93
94
95
96 public NioServerDomainSocketChannel(SelectorProvider provider) {
97 this(newChannel(provider));
98 }
99
100
101
102
103 @SuppressJava6Requirement(reason = "Usage guarded by java version check")
104 public NioServerDomainSocketChannel(ServerSocketChannel channel) {
105 super(null, channel, SelectionKey.OP_ACCEPT);
106 if (PlatformDependent.javaVersion() < 16) {
107 throw new UnsupportedOperationException("Only supported with Java 16+");
108 }
109 config = new NioDomainServerSocketChannelConfig(this);
110 try {
111
112 bound = channel.getLocalAddress() != null;
113 } catch (IOException e) {
114 throw new ChannelException(e);
115 }
116 }
117
118 @Override
119 public ChannelConfig config() {
120 return config;
121 }
122
123 @Override
124 public ChannelMetadata metadata() {
125 return METADATA;
126 }
127
128 @Override
129 public boolean isActive() {
130
131
132 return isOpen() && bound;
133 }
134
135 @SuppressJava6Requirement(reason = "Usage guarded by java version check")
136 @Override
137 protected void doBind(SocketAddress localAddress) throws Exception {
138 javaChannel().bind(localAddress, config.getBacklog());
139 bound = true;
140 }
141
142 @Override
143 protected void doDisconnect() throws Exception {
144 throw new UnsupportedOperationException();
145 }
146
147 @Override
148 protected int doReadMessages(List<Object> buf) throws Exception {
149 SocketChannel ch = SocketUtils.accept(javaChannel());
150 try {
151 if (ch != null) {
152 buf.add(new NioDomainSocketChannel(this, ch));
153 return 1;
154 }
155 } catch (Throwable t) {
156 logger.warn("Failed to create a new channel from an accepted socket.", t);
157
158 try {
159 ch.close();
160 } catch (Throwable t2) {
161 logger.warn("Failed to close a socket.", t2);
162 }
163 }
164
165 return 0;
166 }
167
168 @Override
169 protected boolean doWriteMessage(Object msg, ChannelOutboundBuffer in) throws Exception {
170 throw new UnsupportedOperationException();
171 }
172
173 @Override
174 protected void doClose() throws Exception {
175
176
177 SocketAddress local = localAddress();
178 try {
179 super.doClose();
180 } finally {
181 javaChannel().close();
182 if (local != null) {
183 NioDomainSocketUtil.deleteSocketFile(local);
184 }
185 }
186 }
187
188 @SuppressJava6Requirement(reason = "Usage guarded by java version check")
189 @Override
190 protected SocketAddress localAddress0() {
191
192
193 try {
194 return javaChannel().getLocalAddress();
195 } catch (Exception ignore) {
196
197 }
198 return null;
199 }
200
201 @Override
202 protected SocketAddress remoteAddress0() {
203 return null;
204 }
205
206 private final class NioDomainServerSocketChannelConfig extends DefaultChannelConfig {
207
208 private volatile int backlog = NetUtil.SOMAXCONN;
209
210 private NioDomainServerSocketChannelConfig(NioServerDomainSocketChannel channel) {
211 super(channel, new ServerChannelRecvByteBufAllocator());
212 }
213
214 @Override
215 protected void autoReadCleared() {
216 clearReadPending();
217 }
218
219 @Override
220 public Map<ChannelOption<?>, Object> getOptions() {
221 List<ChannelOption<?>> options = new ArrayList<ChannelOption<?>>();
222 options.add(SO_BACKLOG);
223 for (ChannelOption<?> opt : NioChannelOption.getOptions(jdkChannel())) {
224 options.add(opt);
225 }
226 return getOptions(super.getOptions(), options.toArray(new ChannelOption[0]));
227 }
228
229 @SuppressWarnings("unchecked")
230 @Override
231 public <T> T getOption(ChannelOption<T> option) {
232 if (option == SO_BACKLOG) {
233 return (T) Integer.valueOf(getBacklog());
234 }
235 if (option instanceof NioChannelOption) {
236 return NioChannelOption.getOption(jdkChannel(), (NioChannelOption<T>) option);
237 }
238
239 return super.getOption(option);
240 }
241
242 @Override
243 public <T> boolean setOption(ChannelOption<T> option, T value) {
244 if (option == SO_BACKLOG) {
245 validate(option, value);
246 setBacklog((Integer) value);
247 } else if (option instanceof NioChannelOption) {
248 return NioChannelOption.setOption(jdkChannel(), (NioChannelOption<T>) option, value);
249 } else {
250 return super.setOption(option, value);
251 }
252
253 return true;
254 }
255
256 private int getBacklog() {
257 return backlog;
258 }
259
260 private NioDomainServerSocketChannelConfig setBacklog(int backlog) {
261 checkPositiveOrZero(backlog, "backlog");
262 this.backlog = backlog;
263 return this;
264 }
265
266 private ServerSocketChannel jdkChannel() {
267 return ((NioServerDomainSocketChannel) channel).javaChannel();
268 }
269 }
270
271
272 @Override
273 protected boolean closeOnReadError(Throwable cause) {
274 return super.closeOnReadError(cause);
275 }
276
277 @Override
278 protected boolean doConnect(
279 SocketAddress remoteAddress, SocketAddress localAddress) throws Exception {
280 throw new UnsupportedOperationException();
281 }
282
283 @Override
284 protected void doFinishConnect() throws Exception {
285 throw new UnsupportedOperationException();
286 }
287 }