29 import java.io.IOException; |
29 import java.io.IOException; |
30 import java.net.InetSocketAddress; |
30 import java.net.InetSocketAddress; |
31 import java.net.ServerSocket; |
31 import java.net.ServerSocket; |
32 import java.net.SocketAddress; |
32 import java.net.SocketAddress; |
33 import java.net.SocketOption; |
33 import java.net.SocketOption; |
|
34 import java.net.SocketTimeoutException; |
34 import java.net.StandardSocketOptions; |
35 import java.net.StandardSocketOptions; |
35 import java.nio.channels.AlreadyBoundException; |
36 import java.nio.channels.AlreadyBoundException; |
36 import java.nio.channels.AsynchronousCloseException; |
37 import java.nio.channels.AsynchronousCloseException; |
37 import java.nio.channels.ClosedChannelException; |
38 import java.nio.channels.ClosedChannelException; |
|
39 import java.nio.channels.IllegalBlockingModeException; |
38 import java.nio.channels.NotYetBoundException; |
40 import java.nio.channels.NotYetBoundException; |
39 import java.nio.channels.SelectionKey; |
41 import java.nio.channels.SelectionKey; |
40 import java.nio.channels.ServerSocketChannel; |
42 import java.nio.channels.ServerSocketChannel; |
41 import java.nio.channels.SocketChannel; |
43 import java.nio.channels.SocketChannel; |
42 import java.nio.channels.spi.SelectorProvider; |
44 import java.nio.channels.spi.SelectorProvider; |
43 import java.util.Collections; |
45 import java.util.Collections; |
44 import java.util.HashSet; |
46 import java.util.HashSet; |
45 import java.util.Objects; |
47 import java.util.Objects; |
46 import java.util.Set; |
48 import java.util.Set; |
|
49 import java.util.concurrent.locks.Condition; |
47 import java.util.concurrent.locks.ReentrantLock; |
50 import java.util.concurrent.locks.ReentrantLock; |
48 |
51 |
49 import sun.net.NetHooks; |
52 import sun.net.NetHooks; |
50 import sun.net.ext.ExtendedSocketOptions; |
53 import sun.net.ext.ExtendedSocketOptions; |
51 |
54 |
67 // Lock held by thread currently blocked on this channel |
70 // Lock held by thread currently blocked on this channel |
68 private final ReentrantLock acceptLock = new ReentrantLock(); |
71 private final ReentrantLock acceptLock = new ReentrantLock(); |
69 |
72 |
70 // Lock held by any thread that modifies the state fields declared below |
73 // Lock held by any thread that modifies the state fields declared below |
71 // DO NOT invoke a blocking I/O operation while holding this lock! |
74 // DO NOT invoke a blocking I/O operation while holding this lock! |
72 private final Object stateLock = new Object(); |
75 private final ReentrantLock stateLock = new ReentrantLock(); |
|
76 private final Condition stateCondition = stateLock.newCondition(); |
73 |
77 |
74 // -- The following fields are protected by stateLock |
78 // -- The following fields are protected by stateLock |
75 |
79 |
76 // Channel state, increases monotonically |
80 // Channel state, increases monotonically |
77 private static final int ST_INUSE = 0; |
81 private static final int ST_INUSE = 0; |
120 throw new ClosedChannelException(); |
127 throw new ClosedChannelException(); |
121 } |
128 } |
122 |
129 |
123 @Override |
130 @Override |
124 public ServerSocket socket() { |
131 public ServerSocket socket() { |
125 synchronized (stateLock) { |
132 stateLock.lock(); |
|
133 try { |
126 if (socket == null) |
134 if (socket == null) |
127 socket = ServerSocketAdaptor.create(this); |
135 socket = ServerSocketAdaptor.create(this); |
128 return socket; |
136 return socket; |
|
137 } finally { |
|
138 stateLock.unlock(); |
129 } |
139 } |
130 } |
140 } |
131 |
141 |
132 @Override |
142 @Override |
133 public SocketAddress getLocalAddress() throws IOException { |
143 public SocketAddress getLocalAddress() throws IOException { |
134 synchronized (stateLock) { |
144 stateLock.lock(); |
|
145 try { |
135 ensureOpen(); |
146 ensureOpen(); |
136 return (localAddress == null) |
147 return (localAddress == null) |
137 ? null |
148 ? null |
138 : Net.getRevealedLocalAddress(localAddress); |
149 : Net.getRevealedLocalAddress(localAddress); |
|
150 } finally { |
|
151 stateLock.unlock(); |
139 } |
152 } |
140 } |
153 } |
141 |
154 |
142 @Override |
155 @Override |
143 public <T> ServerSocketChannel setOption(SocketOption<T> name, T value) |
156 public <T> ServerSocketChannel setOption(SocketOption<T> name, T value) |
144 throws IOException |
157 throws IOException |
145 { |
158 { |
146 Objects.requireNonNull(name); |
159 Objects.requireNonNull(name); |
147 if (!supportedOptions().contains(name)) |
160 if (!supportedOptions().contains(name)) |
148 throw new UnsupportedOperationException("'" + name + "' not supported"); |
161 throw new UnsupportedOperationException("'" + name + "' not supported"); |
149 synchronized (stateLock) { |
162 stateLock.lock(); |
|
163 try { |
150 ensureOpen(); |
164 ensureOpen(); |
151 |
165 |
152 if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) { |
166 if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) { |
153 // SO_REUSEADDR emulated when using exclusive bind |
167 // SO_REUSEADDR emulated when using exclusive bind |
154 isReuseAddress = (Boolean)value; |
168 isReuseAddress = (Boolean)value; |
155 } else { |
169 } else { |
156 // no options that require special handling |
170 // no options that require special handling |
157 Net.setSocketOption(fd, Net.UNSPEC, name, value); |
171 Net.setSocketOption(fd, Net.UNSPEC, name, value); |
158 } |
172 } |
159 return this; |
173 return this; |
|
174 } finally { |
|
175 stateLock.unlock(); |
160 } |
176 } |
161 } |
177 } |
162 |
178 |
163 @Override |
179 @Override |
164 @SuppressWarnings("unchecked") |
180 @SuppressWarnings("unchecked") |
167 { |
183 { |
168 Objects.requireNonNull(name); |
184 Objects.requireNonNull(name); |
169 if (!supportedOptions().contains(name)) |
185 if (!supportedOptions().contains(name)) |
170 throw new UnsupportedOperationException("'" + name + "' not supported"); |
186 throw new UnsupportedOperationException("'" + name + "' not supported"); |
171 |
187 |
172 synchronized (stateLock) { |
188 stateLock.lock(); |
|
189 try { |
173 ensureOpen(); |
190 ensureOpen(); |
174 if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) { |
191 if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) { |
175 // SO_REUSEADDR emulated when using exclusive bind |
192 // SO_REUSEADDR emulated when using exclusive bind |
176 return (T)Boolean.valueOf(isReuseAddress); |
193 return (T)Boolean.valueOf(isReuseAddress); |
177 } |
194 } |
178 // no options that require special handling |
195 // no options that require special handling |
179 return (T) Net.getSocketOption(fd, Net.UNSPEC, name); |
196 return (T) Net.getSocketOption(fd, Net.UNSPEC, name); |
|
197 } finally { |
|
198 stateLock.unlock(); |
180 } |
199 } |
181 } |
200 } |
182 |
201 |
183 private static class DefaultOptionsHolder { |
202 private static class DefaultOptionsHolder { |
184 static final Set<SocketOption<?>> defaultOptions = defaultOptions(); |
203 static final Set<SocketOption<?>> defaultOptions = defaultOptions(); |
200 return DefaultOptionsHolder.defaultOptions; |
219 return DefaultOptionsHolder.defaultOptions; |
201 } |
220 } |
202 |
221 |
203 @Override |
222 @Override |
204 public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException { |
223 public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException { |
205 synchronized (stateLock) { |
224 stateLock.lock(); |
|
225 try { |
206 ensureOpen(); |
226 ensureOpen(); |
207 if (localAddress != null) |
227 if (localAddress != null) |
208 throw new AlreadyBoundException(); |
228 throw new AlreadyBoundException(); |
209 InetSocketAddress isa = (local == null) |
229 InetSocketAddress isa = (local == null) |
210 ? new InetSocketAddress(0) |
230 ? new InetSocketAddress(0) |
214 sm.checkListen(isa.getPort()); |
234 sm.checkListen(isa.getPort()); |
215 NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort()); |
235 NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort()); |
216 Net.bind(fd, isa.getAddress(), isa.getPort()); |
236 Net.bind(fd, isa.getAddress(), isa.getPort()); |
217 Net.listen(fd, backlog < 1 ? 50 : backlog); |
237 Net.listen(fd, backlog < 1 ? 50 : backlog); |
218 localAddress = Net.localAddress(fd); |
238 localAddress = Net.localAddress(fd); |
|
239 } finally { |
|
240 stateLock.unlock(); |
219 } |
241 } |
220 return this; |
242 return this; |
221 } |
243 } |
222 |
244 |
223 /** |
245 /** |
227 * @throws NotYetBoundException if the channel's socket has not been bound yet |
249 * @throws NotYetBoundException if the channel's socket has not been bound yet |
228 */ |
250 */ |
229 private void begin(boolean blocking) throws ClosedChannelException { |
251 private void begin(boolean blocking) throws ClosedChannelException { |
230 if (blocking) |
252 if (blocking) |
231 begin(); // set blocker to close channel if interrupted |
253 begin(); // set blocker to close channel if interrupted |
232 synchronized (stateLock) { |
254 stateLock.lock(); |
|
255 try { |
233 ensureOpen(); |
256 ensureOpen(); |
234 if (localAddress == null) |
257 if (localAddress == null) |
235 throw new NotYetBoundException(); |
258 throw new NotYetBoundException(); |
236 if (blocking) |
259 if (blocking) |
237 thread = NativeThread.current(); |
260 thread = NativeThread.current(); |
|
261 } finally { |
|
262 stateLock.unlock(); |
238 } |
263 } |
239 } |
264 } |
240 |
265 |
241 /** |
266 /** |
242 * Marks the end of an I/O operation that may have blocked. |
267 * Marks the end of an I/O operation that may have blocked. |
246 */ |
271 */ |
247 private void end(boolean blocking, boolean completed) |
272 private void end(boolean blocking, boolean completed) |
248 throws AsynchronousCloseException |
273 throws AsynchronousCloseException |
249 { |
274 { |
250 if (blocking) { |
275 if (blocking) { |
251 synchronized (stateLock) { |
276 stateLock.lock(); |
|
277 try { |
252 thread = 0; |
278 thread = 0; |
253 // notify any thread waiting in implCloseSelectableChannel |
279 // notify any thread waiting in implCloseSelectableChannel |
254 if (state == ST_CLOSING) { |
280 if (state == ST_CLOSING) { |
255 stateLock.notifyAll(); |
281 stateCondition.signalAll(); |
256 } |
282 } |
|
283 } finally { |
|
284 stateLock.unlock(); |
257 } |
285 } |
258 end(completed); |
286 end(completed); |
259 } |
287 } |
260 } |
288 } |
261 |
289 |
268 acceptLock.lock(); |
296 acceptLock.lock(); |
269 try { |
297 try { |
270 boolean blocking = isBlocking(); |
298 boolean blocking = isBlocking(); |
271 try { |
299 try { |
272 begin(blocking); |
300 begin(blocking); |
273 do { |
301 n = Net.accept(this.fd, newfd, isaa); |
274 n = Net.accept(this.fd, newfd, isaa); |
302 if (blocking) { |
275 } while (n == IOStatus.INTERRUPTED && isOpen()); |
303 while (IOStatus.okayToRetry(n) && isOpen()) { |
|
304 park(Net.POLLIN); |
|
305 n = Net.accept(this.fd, newfd, isaa); |
|
306 } |
|
307 } |
276 } finally { |
308 } finally { |
277 end(blocking, n > 0); |
309 end(blocking, n > 0); |
278 assert IOStatus.check(n); |
310 assert IOStatus.check(n); |
279 } |
311 } |
280 |
|
281 } finally { |
312 } finally { |
282 acceptLock.unlock(); |
313 acceptLock.unlock(); |
283 } |
314 } |
284 |
315 |
285 if (n < 1) |
316 if (n > 0) { |
|
317 return finishAccept(newfd, isaa[0]); |
|
318 } else { |
286 return null; |
319 return null; |
287 |
320 } |
288 InetSocketAddress isa = isaa[0]; |
321 } |
|
322 |
|
323 /** |
|
324 * Accepts a new connection with a given timeout. This method requires the |
|
325 * channel to be configured in blocking mode. |
|
326 * |
|
327 * @apiNote This method is for use by the socket adaptor. |
|
328 * |
|
329 * @param nanos the timeout, in nanoseconds |
|
330 * @throws IllegalBlockingModeException if the channel is configured non-blocking |
|
331 * @throws SocketTimeoutException if the timeout expires |
|
332 */ |
|
333 SocketChannel blockingAccept(long nanos) throws IOException { |
|
334 int n = 0; |
|
335 FileDescriptor newfd = new FileDescriptor(); |
|
336 InetSocketAddress[] isaa = new InetSocketAddress[1]; |
|
337 |
|
338 acceptLock.lock(); |
|
339 try { |
|
340 // check that channel is configured blocking |
|
341 if (!isBlocking()) |
|
342 throw new IllegalBlockingModeException(); |
|
343 |
|
344 try { |
|
345 begin(true); |
|
346 // change socket to non-blocking |
|
347 lockedConfigureBlocking(false); |
|
348 try { |
|
349 long startNanos = System.nanoTime(); |
|
350 n = Net.accept(fd, newfd, isaa); |
|
351 while (n == IOStatus.UNAVAILABLE && isOpen()) { |
|
352 long remainingNanos = nanos - (System.nanoTime() - startNanos); |
|
353 if (remainingNanos <= 0) { |
|
354 throw new SocketTimeoutException("Accept timed out"); |
|
355 } |
|
356 park(Net.POLLIN, remainingNanos); |
|
357 n = Net.accept(fd, newfd, isaa); |
|
358 } |
|
359 } finally { |
|
360 // restore socket to blocking mode |
|
361 lockedConfigureBlocking(true); |
|
362 } |
|
363 } finally { |
|
364 end(true, n > 0); |
|
365 } |
|
366 } finally { |
|
367 acceptLock.unlock(); |
|
368 } |
|
369 |
|
370 assert n > 0; |
|
371 return finishAccept(newfd, isaa[0]); |
|
372 } |
|
373 |
|
374 private SocketChannel finishAccept(FileDescriptor newfd, InetSocketAddress isa) |
|
375 throws IOException |
|
376 { |
289 try { |
377 try { |
290 // newly accepted socket is initially in blocking mode |
378 // newly accepted socket is initially in blocking mode |
291 IOUtil.configureBlocking(newfd, true); |
379 IOUtil.configureBlocking(newfd, true); |
292 |
380 |
293 // check permitted to accept connections from the remote address |
381 // check permitted to accept connections from the remote address |
304 |
392 |
305 @Override |
393 @Override |
306 protected void implConfigureBlocking(boolean block) throws IOException { |
394 protected void implConfigureBlocking(boolean block) throws IOException { |
307 acceptLock.lock(); |
395 acceptLock.lock(); |
308 try { |
396 try { |
309 synchronized (stateLock) { |
397 lockedConfigureBlocking(block); |
310 ensureOpen(); |
|
311 IOUtil.configureBlocking(fd, block); |
|
312 } |
|
313 } finally { |
398 } finally { |
314 acceptLock.unlock(); |
399 acceptLock.unlock(); |
|
400 } |
|
401 } |
|
402 |
|
403 /** |
|
404 * Adjust the blocking mode while holding acceptLock. |
|
405 */ |
|
406 private void lockedConfigureBlocking(boolean block) throws IOException { |
|
407 assert acceptLock.isHeldByCurrentThread(); |
|
408 stateLock.lock(); |
|
409 try { |
|
410 ensureOpen(); |
|
411 IOUtil.configureBlocking(fd, block); |
|
412 } finally { |
|
413 stateLock.unlock(); |
315 } |
414 } |
316 } |
415 } |
317 |
416 |
318 /** |
417 /** |
319 * Invoked by implCloseChannel to close the channel. |
418 * Invoked by implCloseChannel to close the channel. |
334 |
433 |
335 boolean interrupted = false; |
434 boolean interrupted = false; |
336 boolean blocking; |
435 boolean blocking; |
337 |
436 |
338 // set state to ST_CLOSING |
437 // set state to ST_CLOSING |
339 synchronized (stateLock) { |
438 stateLock.lock(); |
|
439 try { |
340 assert state < ST_CLOSING; |
440 assert state < ST_CLOSING; |
341 state = ST_CLOSING; |
441 state = ST_CLOSING; |
342 blocking = isBlocking(); |
442 blocking = isBlocking(); |
|
443 } finally { |
|
444 stateLock.unlock(); |
343 } |
445 } |
344 |
446 |
345 // wait for any outstanding accept to complete |
447 // wait for any outstanding accept to complete |
346 if (blocking) { |
448 if (blocking) { |
347 synchronized (stateLock) { |
449 stateLock.lock(); |
|
450 try { |
348 assert state == ST_CLOSING; |
451 assert state == ST_CLOSING; |
349 long th = thread; |
452 long th = thread; |
350 if (th != 0) { |
453 if (th != 0) { |
351 nd.preClose(fd); |
454 nd.preClose(fd); |
352 NativeThread.signal(th); |
455 NativeThread.signal(th); |
353 |
456 |
354 // wait for accept operation to end |
457 // wait for accept operation to end |
355 while (thread != 0) { |
458 while (thread != 0) { |
356 try { |
459 try { |
357 stateLock.wait(); |
460 stateCondition.await(); |
358 } catch (InterruptedException e) { |
461 } catch (InterruptedException e) { |
359 interrupted = true; |
462 interrupted = true; |
360 } |
463 } |
361 } |
464 } |
362 } |
465 } |
|
466 } finally { |
|
467 stateLock.unlock(); |
363 } |
468 } |
364 } else { |
469 } else { |
365 // non-blocking mode: wait for accept to complete |
470 // non-blocking mode: wait for accept to complete |
366 acceptLock.lock(); |
471 acceptLock.lock(); |
367 acceptLock.unlock(); |
472 acceptLock.unlock(); |
368 } |
473 } |
369 |
474 |
370 // set state to ST_KILLPENDING |
475 // set state to ST_KILLPENDING |
371 synchronized (stateLock) { |
476 stateLock.lock(); |
|
477 try { |
372 assert state == ST_CLOSING; |
478 assert state == ST_CLOSING; |
373 state = ST_KILLPENDING; |
479 state = ST_KILLPENDING; |
|
480 } finally { |
|
481 stateLock.unlock(); |
374 } |
482 } |
375 |
483 |
376 // close socket if not registered with Selector |
484 // close socket if not registered with Selector |
377 if (!isRegistered()) |
485 if (!isRegistered()) |
378 kill(); |
486 kill(); |
382 Thread.currentThread().interrupt(); |
490 Thread.currentThread().interrupt(); |
383 } |
491 } |
384 |
492 |
385 @Override |
493 @Override |
386 public void kill() throws IOException { |
494 public void kill() throws IOException { |
387 synchronized (stateLock) { |
495 stateLock.lock(); |
|
496 try { |
388 if (state == ST_KILLPENDING) { |
497 if (state == ST_KILLPENDING) { |
389 state = ST_KILLED; |
498 state = ST_KILLED; |
390 nd.close(fd); |
499 nd.close(fd); |
391 } |
500 } |
|
501 } finally { |
|
502 stateLock.unlock(); |
392 } |
503 } |
393 } |
504 } |
394 |
505 |
395 /** |
506 /** |
396 * Returns true if channel's socket is bound |
507 * Returns true if channel's socket is bound |
397 */ |
508 */ |
398 boolean isBound() { |
509 boolean isBound() { |
399 synchronized (stateLock) { |
510 stateLock.lock(); |
|
511 try { |
400 return localAddress != null; |
512 return localAddress != null; |
|
513 } finally { |
|
514 stateLock.unlock(); |
401 } |
515 } |
402 } |
516 } |
403 |
517 |
404 /** |
518 /** |
405 * Returns the local address, or null if not bound |
519 * Returns the local address, or null if not bound |
406 */ |
520 */ |
407 InetSocketAddress localAddress() { |
521 InetSocketAddress localAddress() { |
408 synchronized (stateLock) { |
522 stateLock.lock(); |
|
523 try { |
409 return localAddress; |
524 return localAddress; |
410 } |
525 } finally { |
411 } |
526 stateLock.unlock(); |
412 |
|
413 /** |
|
414 * Poll this channel's socket for a new connection up to the given timeout. |
|
415 * @return {@code true} if there is a connection to accept |
|
416 */ |
|
417 boolean pollAccept(long timeout) throws IOException { |
|
418 assert Thread.holdsLock(blockingLock()) && isBlocking(); |
|
419 acceptLock.lock(); |
|
420 try { |
|
421 boolean polled = false; |
|
422 try { |
|
423 begin(true); |
|
424 int events = Net.poll(fd, Net.POLLIN, timeout); |
|
425 polled = (events != 0); |
|
426 } finally { |
|
427 end(true, polled); |
|
428 } |
|
429 return polled; |
|
430 } finally { |
|
431 acceptLock.unlock(); |
|
432 } |
527 } |
433 } |
528 } |
434 |
529 |
435 /** |
530 /** |
436 * Translates native poll revent set into a ready operation set |
531 * Translates native poll revent set into a ready operation set |