33 import java.net.SocketAddress; |
33 import java.net.SocketAddress; |
34 import java.net.SocketOption; |
34 import java.net.SocketOption; |
35 import java.net.StandardProtocolFamily; |
35 import java.net.StandardProtocolFamily; |
36 import java.net.StandardSocketOptions; |
36 import java.net.StandardSocketOptions; |
37 import java.nio.channels.AlreadyBoundException; |
37 import java.nio.channels.AlreadyBoundException; |
|
38 import java.nio.channels.AsynchronousCloseException; |
38 import java.nio.channels.ClosedChannelException; |
39 import java.nio.channels.ClosedChannelException; |
39 import java.nio.channels.NotYetBoundException; |
40 import java.nio.channels.NotYetBoundException; |
40 import java.nio.channels.SelectionKey; |
41 import java.nio.channels.SelectionKey; |
41 import java.nio.channels.ServerSocketChannel; |
42 import java.nio.channels.ServerSocketChannel; |
42 import java.nio.channels.SocketChannel; |
43 import java.nio.channels.SocketChannel; |
43 import java.nio.channels.spi.SelectorProvider; |
44 import java.nio.channels.spi.SelectorProvider; |
44 import java.util.Collections; |
45 import java.util.Collections; |
45 import java.util.HashSet; |
46 import java.util.HashSet; |
|
47 import java.util.Objects; |
46 import java.util.Set; |
48 import java.util.Set; |
47 import java.util.concurrent.locks.ReentrantLock; |
49 import java.util.concurrent.locks.ReentrantLock; |
48 |
50 |
49 import sun.net.NetHooks; |
51 import sun.net.NetHooks; |
50 |
52 |
54 |
56 |
55 class ServerSocketChannelImpl |
57 class ServerSocketChannelImpl |
56 extends ServerSocketChannel |
58 extends ServerSocketChannel |
57 implements SelChImpl |
59 implements SelChImpl |
58 { |
60 { |
59 |
|
60 // Used to make native close and configure calls |
61 // Used to make native close and configure calls |
61 private static NativeDispatcher nd; |
62 private static NativeDispatcher nd; |
62 |
63 |
63 // Our file descriptor |
64 // Our file descriptor |
64 private final FileDescriptor fd; |
65 private final FileDescriptor fd; |
65 private final int fdVal; |
66 private final int fdVal; |
66 |
67 |
67 // ID of native thread currently blocked in this channel, for signalling |
68 // Lock held by thread currently blocked on this channel |
68 private volatile long thread; |
|
69 |
|
70 // Lock held by thread currently blocked in this channel |
|
71 private final ReentrantLock acceptLock = new ReentrantLock(); |
69 private final ReentrantLock acceptLock = new ReentrantLock(); |
72 |
70 |
73 // Lock held by any thread that modifies the state fields declared below |
71 // Lock held by any thread that modifies the state fields declared below |
74 // DO NOT invoke a blocking I/O operation while holding this lock! |
72 // DO NOT invoke a blocking I/O operation while holding this lock! |
75 private final Object stateLock = new Object(); |
73 private final Object stateLock = new Object(); |
76 |
74 |
77 // -- The following fields are protected by stateLock |
75 // -- The following fields are protected by stateLock |
78 |
76 |
79 // Channel state, increases monotonically |
77 // Channel state, increases monotonically |
80 private static final int ST_UNINITIALIZED = -1; |
|
81 private static final int ST_INUSE = 0; |
78 private static final int ST_INUSE = 0; |
82 private static final int ST_KILLED = 1; |
79 private static final int ST_CLOSING = 1; |
83 private int state = ST_UNINITIALIZED; |
80 private static final int ST_KILLPENDING = 2; |
|
81 private static final int ST_KILLED = 3; |
|
82 private int state; |
|
83 |
|
84 // ID of native thread currently blocked in this channel, for signalling |
|
85 private long thread; |
84 |
86 |
85 // Binding |
87 // Binding |
86 private InetSocketAddress localAddress; // null => unbound |
88 private InetSocketAddress localAddress; // null => unbound |
87 |
89 |
88 // set true when exclusive binding is on and SO_REUSEADDR is emulated |
90 // set true when exclusive binding is on and SO_REUSEADDR is emulated |
96 |
98 |
97 ServerSocketChannelImpl(SelectorProvider sp) throws IOException { |
99 ServerSocketChannelImpl(SelectorProvider sp) throws IOException { |
98 super(sp); |
100 super(sp); |
99 this.fd = Net.serverSocket(true); |
101 this.fd = Net.serverSocket(true); |
100 this.fdVal = IOUtil.fdVal(fd); |
102 this.fdVal = IOUtil.fdVal(fd); |
101 this.state = ST_INUSE; |
103 } |
102 } |
104 |
103 |
105 ServerSocketChannelImpl(SelectorProvider sp, FileDescriptor fd, boolean bound) |
104 ServerSocketChannelImpl(SelectorProvider sp, |
|
105 FileDescriptor fd, |
|
106 boolean bound) |
|
107 throws IOException |
106 throws IOException |
108 { |
107 { |
109 super(sp); |
108 super(sp); |
110 this.fd = fd; |
109 this.fd = fd; |
111 this.fdVal = IOUtil.fdVal(fd); |
110 this.fdVal = IOUtil.fdVal(fd); |
112 this.state = ST_INUSE; |
111 if (bound) { |
113 if (bound) |
112 synchronized (stateLock) { |
114 localAddress = Net.localAddress(fd); |
113 localAddress = Net.localAddress(fd); |
115 } |
114 } |
116 |
115 } |
|
116 } |
|
117 |
|
118 // @throws ClosedChannelException if channel is closed |
|
119 private void ensureOpen() throws ClosedChannelException { |
|
120 if (!isOpen()) |
|
121 throw new ClosedChannelException(); |
|
122 } |
|
123 |
|
124 @Override |
117 public ServerSocket socket() { |
125 public ServerSocket socket() { |
118 synchronized (stateLock) { |
126 synchronized (stateLock) { |
119 if (socket == null) |
127 if (socket == null) |
120 socket = ServerSocketAdaptor.create(this); |
128 socket = ServerSocketAdaptor.create(this); |
121 return socket; |
129 return socket; |
123 } |
131 } |
124 |
132 |
125 @Override |
133 @Override |
126 public SocketAddress getLocalAddress() throws IOException { |
134 public SocketAddress getLocalAddress() throws IOException { |
127 synchronized (stateLock) { |
135 synchronized (stateLock) { |
128 if (!isOpen()) |
136 ensureOpen(); |
129 throw new ClosedChannelException(); |
137 return (localAddress == null) |
130 return localAddress == null ? localAddress |
138 ? null |
131 : Net.getRevealedLocalAddress( |
139 : Net.getRevealedLocalAddress(localAddress); |
132 Net.asInetSocketAddress(localAddress)); |
|
133 } |
140 } |
134 } |
141 } |
135 |
142 |
136 @Override |
143 @Override |
137 public <T> ServerSocketChannel setOption(SocketOption<T> name, T value) |
144 public <T> ServerSocketChannel setOption(SocketOption<T> name, T value) |
138 throws IOException |
145 throws IOException |
139 { |
146 { |
140 if (name == null) |
147 Objects.requireNonNull(name); |
141 throw new NullPointerException(); |
|
142 if (!supportedOptions().contains(name)) |
148 if (!supportedOptions().contains(name)) |
143 throw new UnsupportedOperationException("'" + name + "' not supported"); |
149 throw new UnsupportedOperationException("'" + name + "' not supported"); |
144 synchronized (stateLock) { |
150 synchronized (stateLock) { |
145 if (!isOpen()) |
151 ensureOpen(); |
146 throw new ClosedChannelException(); |
|
147 |
152 |
148 if (name == StandardSocketOptions.IP_TOS) { |
153 if (name == StandardSocketOptions.IP_TOS) { |
149 ProtocolFamily family = Net.isIPv6Available() ? |
154 ProtocolFamily family = Net.isIPv6Available() ? |
150 StandardProtocolFamily.INET6 : StandardProtocolFamily.INET; |
155 StandardProtocolFamily.INET6 : StandardProtocolFamily.INET; |
151 Net.setSocketOption(fd, family, name, value); |
156 Net.setSocketOption(fd, family, name, value); |
152 return this; |
157 return this; |
153 } |
158 } |
154 |
159 |
155 if (name == StandardSocketOptions.SO_REUSEADDR && |
160 if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) { |
156 Net.useExclusiveBind()) |
|
157 { |
|
158 // SO_REUSEADDR emulated when using exclusive bind |
161 // SO_REUSEADDR emulated when using exclusive bind |
159 isReuseAddress = (Boolean)value; |
162 isReuseAddress = (Boolean)value; |
160 } else { |
163 } else { |
161 // no options that require special handling |
164 // no options that require special handling |
162 Net.setSocketOption(fd, Net.UNSPEC, name, value); |
165 Net.setSocketOption(fd, Net.UNSPEC, name, value); |
168 @Override |
171 @Override |
169 @SuppressWarnings("unchecked") |
172 @SuppressWarnings("unchecked") |
170 public <T> T getOption(SocketOption<T> name) |
173 public <T> T getOption(SocketOption<T> name) |
171 throws IOException |
174 throws IOException |
172 { |
175 { |
173 if (name == null) |
176 Objects.requireNonNull(name); |
174 throw new NullPointerException(); |
|
175 if (!supportedOptions().contains(name)) |
177 if (!supportedOptions().contains(name)) |
176 throw new UnsupportedOperationException("'" + name + "' not supported"); |
178 throw new UnsupportedOperationException("'" + name + "' not supported"); |
177 |
179 |
178 synchronized (stateLock) { |
180 synchronized (stateLock) { |
179 if (!isOpen()) |
181 ensureOpen(); |
180 throw new ClosedChannelException(); |
182 if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) { |
181 if (name == StandardSocketOptions.SO_REUSEADDR && |
|
182 Net.useExclusiveBind()) |
|
183 { |
|
184 // SO_REUSEADDR emulated when using exclusive bind |
183 // SO_REUSEADDR emulated when using exclusive bind |
185 return (T)Boolean.valueOf(isReuseAddress); |
184 return (T)Boolean.valueOf(isReuseAddress); |
186 } |
185 } |
187 // no options that require special handling |
186 // no options that require special handling |
188 return (T) Net.getSocketOption(fd, Net.UNSPEC, name); |
187 return (T) Net.getSocketOption(fd, Net.UNSPEC, name); |
207 @Override |
206 @Override |
208 public final Set<SocketOption<?>> supportedOptions() { |
207 public final Set<SocketOption<?>> supportedOptions() { |
209 return DefaultOptionsHolder.defaultOptions; |
208 return DefaultOptionsHolder.defaultOptions; |
210 } |
209 } |
211 |
210 |
212 public boolean isBound() { |
|
213 synchronized (stateLock) { |
|
214 return localAddress != null; |
|
215 } |
|
216 } |
|
217 |
|
218 public InetSocketAddress localAddress() { |
|
219 synchronized (stateLock) { |
|
220 return localAddress; |
|
221 } |
|
222 } |
|
223 |
|
224 @Override |
211 @Override |
225 public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException { |
212 public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException { |
226 acceptLock.lock(); |
213 acceptLock.lock(); |
227 try { |
214 try { |
228 if (!isOpen()) |
|
229 throw new ClosedChannelException(); |
|
230 if (isBound()) |
|
231 throw new AlreadyBoundException(); |
|
232 InetSocketAddress isa = (local == null) ? new InetSocketAddress(0) : |
|
233 Net.checkAddress(local); |
|
234 SecurityManager sm = System.getSecurityManager(); |
|
235 if (sm != null) |
|
236 sm.checkListen(isa.getPort()); |
|
237 NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort()); |
|
238 Net.bind(fd, isa.getAddress(), isa.getPort()); |
|
239 Net.listen(fd, backlog < 1 ? 50 : backlog); |
|
240 synchronized (stateLock) { |
215 synchronized (stateLock) { |
|
216 ensureOpen(); |
|
217 if (localAddress != null) |
|
218 throw new AlreadyBoundException(); |
|
219 InetSocketAddress isa = (local == null) |
|
220 ? new InetSocketAddress(0) |
|
221 : Net.checkAddress(local); |
|
222 SecurityManager sm = System.getSecurityManager(); |
|
223 if (sm != null) |
|
224 sm.checkListen(isa.getPort()); |
|
225 NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort()); |
|
226 Net.bind(fd, isa.getAddress(), isa.getPort()); |
|
227 Net.listen(fd, backlog < 1 ? 50 : backlog); |
241 localAddress = Net.localAddress(fd); |
228 localAddress = Net.localAddress(fd); |
242 } |
229 } |
243 } finally { |
230 } finally { |
244 acceptLock.unlock(); |
231 acceptLock.unlock(); |
245 } |
232 } |
246 return this; |
233 return this; |
247 } |
234 } |
248 |
235 |
|
236 /** |
|
237 * Marks the beginning of an I/O operation that might block. |
|
238 * |
|
239 * @throws ClosedChannelException if the channel is closed |
|
240 * @throws NotYetBoundException if the channel's socket has not been bound yet |
|
241 */ |
|
242 private void begin(boolean blocking) throws ClosedChannelException { |
|
243 if (blocking) |
|
244 begin(); // set blocker to close channel if interrupted |
|
245 synchronized (stateLock) { |
|
246 ensureOpen(); |
|
247 if (localAddress == null) |
|
248 throw new NotYetBoundException(); |
|
249 if (blocking) |
|
250 thread = NativeThread.current(); |
|
251 } |
|
252 } |
|
253 |
|
254 /** |
|
255 * Marks the end of an I/O operation that may have blocked. |
|
256 * |
|
257 * @throws AsynchronousCloseException if the channel was closed due to this |
|
258 * thread being interrupted on a blocking I/O operation. |
|
259 */ |
|
260 private void end(boolean blocking, boolean completed) |
|
261 throws AsynchronousCloseException |
|
262 { |
|
263 if (blocking) { |
|
264 synchronized (stateLock) { |
|
265 thread = 0; |
|
266 // notify any thread waiting in implCloseSelectableChannel |
|
267 if (state == ST_CLOSING) { |
|
268 stateLock.notifyAll(); |
|
269 } |
|
270 } |
|
271 end(completed); |
|
272 } |
|
273 } |
|
274 |
|
275 @Override |
249 public SocketChannel accept() throws IOException { |
276 public SocketChannel accept() throws IOException { |
250 acceptLock.lock(); |
277 acceptLock.lock(); |
251 try { |
278 try { |
252 if (!isOpen()) |
|
253 throw new ClosedChannelException(); |
|
254 if (!isBound()) |
|
255 throw new NotYetBoundException(); |
|
256 SocketChannel sc = null; |
|
257 |
|
258 int n = 0; |
279 int n = 0; |
259 FileDescriptor newfd = new FileDescriptor(); |
280 FileDescriptor newfd = new FileDescriptor(); |
260 InetSocketAddress[] isaa = new InetSocketAddress[1]; |
281 InetSocketAddress[] isaa = new InetSocketAddress[1]; |
261 |
282 |
|
283 boolean blocking = isBlocking(); |
262 try { |
284 try { |
263 begin(); |
285 begin(blocking); |
264 if (!isOpen()) |
286 do { |
265 return null; |
|
266 thread = NativeThread.current(); |
|
267 for (;;) { |
|
268 n = accept(this.fd, newfd, isaa); |
287 n = accept(this.fd, newfd, isaa); |
269 if ((n == IOStatus.INTERRUPTED) && isOpen()) |
288 } while (n == IOStatus.INTERRUPTED && isOpen()); |
270 continue; |
|
271 break; |
|
272 } |
|
273 } finally { |
289 } finally { |
274 thread = 0; |
290 end(blocking, n > 0); |
275 end(n > 0); |
|
276 assert IOStatus.check(n); |
291 assert IOStatus.check(n); |
277 } |
292 } |
278 |
293 |
279 if (n < 1) |
294 if (n < 1) |
280 return null; |
295 return null; |
281 |
296 |
|
297 // newly accepted socket is initially in blocking mode |
282 IOUtil.configureBlocking(newfd, true); |
298 IOUtil.configureBlocking(newfd, true); |
|
299 |
283 InetSocketAddress isa = isaa[0]; |
300 InetSocketAddress isa = isaa[0]; |
284 sc = new SocketChannelImpl(provider(), newfd, isa); |
301 SocketChannel sc = new SocketChannelImpl(provider(), newfd, isa); |
|
302 |
|
303 // check permitted to accept connections from the remote address |
285 SecurityManager sm = System.getSecurityManager(); |
304 SecurityManager sm = System.getSecurityManager(); |
286 if (sm != null) { |
305 if (sm != null) { |
287 try { |
306 try { |
288 sm.checkAccept(isa.getAddress().getHostAddress(), |
307 sm.checkAccept(isa.getAddress().getHostAddress(), isa.getPort()); |
289 isa.getPort()); |
|
290 } catch (SecurityException x) { |
308 } catch (SecurityException x) { |
291 sc.close(); |
309 sc.close(); |
292 throw x; |
310 throw x; |
293 } |
311 } |
294 } |
312 } |
297 } finally { |
315 } finally { |
298 acceptLock.unlock(); |
316 acceptLock.unlock(); |
299 } |
317 } |
300 } |
318 } |
301 |
319 |
|
320 @Override |
302 protected void implConfigureBlocking(boolean block) throws IOException { |
321 protected void implConfigureBlocking(boolean block) throws IOException { |
303 IOUtil.configureBlocking(fd, block); |
322 acceptLock.lock(); |
304 } |
323 try { |
305 |
324 synchronized (stateLock) { |
|
325 ensureOpen(); |
|
326 IOUtil.configureBlocking(fd, block); |
|
327 } |
|
328 } finally { |
|
329 acceptLock.unlock(); |
|
330 } |
|
331 } |
|
332 |
|
333 /** |
|
334 * Invoked by implCloseChannel to close the channel. |
|
335 * |
|
336 * This method waits for outstanding I/O operations to complete. When in |
|
337 * blocking mode, the socket is pre-closed and the threads in blocking I/O |
|
338 * operations are signalled to ensure that the outstanding I/O operations |
|
339 * complete quickly. |
|
340 * |
|
341 * The socket is closed by this method when it is not registered with a |
|
342 * Selector. Note that a channel configured blocking may be registered with |
|
343 * a Selector. This arises when a key is canceled and the channel configured |
|
344 * to blocking mode before the key is flushed from the Selector. |
|
345 */ |
|
346 @Override |
306 protected void implCloseSelectableChannel() throws IOException { |
347 protected void implCloseSelectableChannel() throws IOException { |
307 synchronized (stateLock) { |
348 assert !isOpen(); |
308 if (state != ST_KILLED) |
349 |
309 nd.preClose(fd); |
350 boolean interrupted = false; |
310 long th = thread; |
351 boolean blocking; |
311 if (th != 0) |
352 |
312 NativeThread.signal(th); |
353 // set state to ST_CLOSING |
313 if (!isRegistered()) |
354 synchronized (stateLock) { |
314 kill(); |
355 assert state < ST_CLOSING; |
315 } |
356 state = ST_CLOSING; |
316 } |
357 blocking = isBlocking(); |
317 |
358 } |
|
359 |
|
360 // wait for any outstanding accept to complete |
|
361 if (blocking) { |
|
362 synchronized (stateLock) { |
|
363 assert state == ST_CLOSING; |
|
364 long th = thread; |
|
365 if (th != 0) { |
|
366 nd.preClose(fd); |
|
367 NativeThread.signal(th); |
|
368 |
|
369 // wait for accept operation to end |
|
370 while (thread != 0) { |
|
371 try { |
|
372 stateLock.wait(); |
|
373 } catch (InterruptedException e) { |
|
374 interrupted = true; |
|
375 } |
|
376 } |
|
377 } |
|
378 } |
|
379 } else { |
|
380 // non-blocking mode: wait for accept to complete |
|
381 acceptLock.lock(); |
|
382 acceptLock.unlock(); |
|
383 } |
|
384 |
|
385 // set state to ST_KILLPENDING |
|
386 synchronized (stateLock) { |
|
387 assert state == ST_CLOSING; |
|
388 state = ST_KILLPENDING; |
|
389 } |
|
390 |
|
391 // close socket if not registered with Selector |
|
392 if (!isRegistered()) |
|
393 kill(); |
|
394 |
|
395 // restore interrupt status |
|
396 if (interrupted) |
|
397 Thread.currentThread().interrupt(); |
|
398 } |
|
399 |
|
400 @Override |
318 public void kill() throws IOException { |
401 public void kill() throws IOException { |
319 synchronized (stateLock) { |
402 synchronized (stateLock) { |
320 if (state == ST_KILLED) |
403 if (state == ST_KILLPENDING) { |
321 return; |
|
322 if (state == ST_UNINITIALIZED) { |
|
323 state = ST_KILLED; |
404 state = ST_KILLED; |
324 return; |
405 nd.close(fd); |
325 } |
406 } |
326 assert !isOpen() && !isRegistered(); |
407 } |
327 nd.close(fd); |
408 } |
328 state = ST_KILLED; |
409 |
|
410 /** |
|
411 * Returns true if channel's socket is bound |
|
412 */ |
|
413 boolean isBound() { |
|
414 synchronized (stateLock) { |
|
415 return localAddress != null; |
|
416 } |
|
417 } |
|
418 |
|
419 /** |
|
420 * Returns the local address, or null if not bound |
|
421 */ |
|
422 InetSocketAddress localAddress() { |
|
423 synchronized (stateLock) { |
|
424 return localAddress; |
|
425 } |
|
426 } |
|
427 |
|
428 /** |
|
429 * Poll this channel's socket for a new connection up to the given timeout. |
|
430 * @return {@code true} if there is a connection to accept |
|
431 */ |
|
432 boolean pollAccept(long timeout) throws IOException { |
|
433 assert Thread.holdsLock(blockingLock()) && isBlocking(); |
|
434 acceptLock.lock(); |
|
435 try { |
|
436 boolean polled = false; |
|
437 try { |
|
438 begin(true); |
|
439 int n = Net.poll(fd, Net.POLLIN, timeout); |
|
440 polled = (n > 0); |
|
441 } finally { |
|
442 end(true, polled); |
|
443 } |
|
444 return polled; |
|
445 } finally { |
|
446 acceptLock.unlock(); |
329 } |
447 } |
330 } |
448 } |
331 |
449 |
332 /** |
450 /** |
333 * Translates native poll revent set into a ready operation set |
451 * Translates native poll revent set into a ready operation set |
450 // Accepts a new connection, setting the given file descriptor to refer to |
544 // Accepts a new connection, setting the given file descriptor to refer to |
451 // the new socket and setting isaa[0] to the socket's remote address. |
545 // the new socket and setting isaa[0] to the socket's remote address. |
452 // Returns 1 on success, or IOStatus.UNAVAILABLE (if non-blocking and no |
546 // Returns 1 on success, or IOStatus.UNAVAILABLE (if non-blocking and no |
453 // connections are pending) or IOStatus.INTERRUPTED. |
547 // connections are pending) or IOStatus.INTERRUPTED. |
454 // |
548 // |
455 private native int accept0(FileDescriptor ssfd, FileDescriptor newfd, |
549 private native int accept0(FileDescriptor ssfd, |
|
550 FileDescriptor newfd, |
456 InetSocketAddress[] isaa) |
551 InetSocketAddress[] isaa) |
457 throws IOException; |
552 throws IOException; |
458 |
553 |
459 private static native void initIDs(); |
554 private static native void initIDs(); |
460 |
555 |