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