changeset 54620 | 13b67c1420b8 |
parent 54246 | f04e3492fd88 |
child 54754 | 193a8f1a4f3b |
child 57339 | 40fdbdd92617 |
54619:b43cc3b9ef40 | 54620:13b67c1420b8 |
---|---|
32 import java.net.ProtocolFamily; |
32 import java.net.ProtocolFamily; |
33 import java.net.Socket; |
33 import java.net.Socket; |
34 import java.net.SocketAddress; |
34 import java.net.SocketAddress; |
35 import java.net.SocketException; |
35 import java.net.SocketException; |
36 import java.net.SocketOption; |
36 import java.net.SocketOption; |
37 import java.net.SocketTimeoutException; |
|
37 import java.net.StandardProtocolFamily; |
38 import java.net.StandardProtocolFamily; |
38 import java.net.StandardSocketOptions; |
39 import java.net.StandardSocketOptions; |
39 import java.nio.ByteBuffer; |
40 import java.nio.ByteBuffer; |
40 import java.nio.channels.AlreadyBoundException; |
41 import java.nio.channels.AlreadyBoundException; |
41 import java.nio.channels.AlreadyConnectedException; |
42 import java.nio.channels.AlreadyConnectedException; |
42 import java.nio.channels.AsynchronousCloseException; |
43 import java.nio.channels.AsynchronousCloseException; |
43 import java.nio.channels.ClosedChannelException; |
44 import java.nio.channels.ClosedChannelException; |
44 import java.nio.channels.ConnectionPendingException; |
45 import java.nio.channels.ConnectionPendingException; |
46 import java.nio.channels.IllegalBlockingModeException; |
|
45 import java.nio.channels.NoConnectionPendingException; |
47 import java.nio.channels.NoConnectionPendingException; |
46 import java.nio.channels.NotYetConnectedException; |
48 import java.nio.channels.NotYetConnectedException; |
47 import java.nio.channels.SelectionKey; |
49 import java.nio.channels.SelectionKey; |
48 import java.nio.channels.SocketChannel; |
50 import java.nio.channels.SocketChannel; |
49 import java.nio.channels.spi.SelectorProvider; |
51 import java.nio.channels.spi.SelectorProvider; |
50 import java.util.Collections; |
52 import java.util.Collections; |
51 import java.util.HashSet; |
53 import java.util.HashSet; |
52 import java.util.Objects; |
54 import java.util.Objects; |
53 import java.util.Set; |
55 import java.util.Set; |
56 import java.util.concurrent.locks.Condition; |
|
54 import java.util.concurrent.locks.ReentrantLock; |
57 import java.util.concurrent.locks.ReentrantLock; |
55 |
58 |
56 import sun.net.ConnectionResetException; |
59 import sun.net.ConnectionResetException; |
57 import sun.net.NetHooks; |
60 import sun.net.NetHooks; |
58 import sun.net.ext.ExtendedSocketOptions; |
61 import sun.net.ext.ExtendedSocketOptions; |
79 // Lock held by current writing or connecting thread |
82 // Lock held by current writing or connecting thread |
80 private final ReentrantLock writeLock = new ReentrantLock(); |
83 private final ReentrantLock writeLock = new ReentrantLock(); |
81 |
84 |
82 // Lock held by any thread that modifies the state fields declared below |
85 // Lock held by any thread that modifies the state fields declared below |
83 // DO NOT invoke a blocking I/O operation while holding this lock! |
86 // DO NOT invoke a blocking I/O operation while holding this lock! |
84 private final Object stateLock = new Object(); |
87 private final ReentrantLock stateLock = new ReentrantLock(); |
88 private final Condition stateCondition = stateLock.newCondition(); |
|
85 |
89 |
86 // Input/Output closed |
90 // Input/Output closed |
87 private volatile boolean isInputClosed; |
91 private volatile boolean isInputClosed; |
88 private volatile boolean isOutputClosed; |
92 private volatile boolean isOutputClosed; |
89 |
93 |
131 { |
135 { |
132 super(sp); |
136 super(sp); |
133 this.fd = fd; |
137 this.fd = fd; |
134 this.fdVal = IOUtil.fdVal(fd); |
138 this.fdVal = IOUtil.fdVal(fd); |
135 if (bound) { |
139 if (bound) { |
136 synchronized (stateLock) { |
140 stateLock.lock(); |
141 try { |
|
137 this.localAddress = Net.localAddress(fd); |
142 this.localAddress = Net.localAddress(fd); |
143 } finally { |
|
144 stateLock.unlock(); |
|
138 } |
145 } |
139 } |
146 } |
140 } |
147 } |
141 |
148 |
142 // Constructor for sockets obtained from server sockets |
149 // Constructor for sockets obtained from server sockets |
145 throws IOException |
152 throws IOException |
146 { |
153 { |
147 super(sp); |
154 super(sp); |
148 this.fd = fd; |
155 this.fd = fd; |
149 this.fdVal = IOUtil.fdVal(fd); |
156 this.fdVal = IOUtil.fdVal(fd); |
150 synchronized (stateLock) { |
157 stateLock.lock(); |
158 try { |
|
151 this.localAddress = Net.localAddress(fd); |
159 this.localAddress = Net.localAddress(fd); |
152 this.remoteAddress = isa; |
160 this.remoteAddress = isa; |
153 this.state = ST_CONNECTED; |
161 this.state = ST_CONNECTED; |
162 } finally { |
|
163 stateLock.unlock(); |
|
154 } |
164 } |
155 } |
165 } |
156 |
166 |
157 /** |
167 /** |
158 * Checks that the channel is open. |
168 * Checks that the channel is open. |
185 } |
195 } |
186 } |
196 } |
187 |
197 |
188 @Override |
198 @Override |
189 public Socket socket() { |
199 public Socket socket() { |
190 synchronized (stateLock) { |
200 stateLock.lock(); |
201 try { |
|
191 if (socket == null) |
202 if (socket == null) |
192 socket = SocketAdaptor.create(this); |
203 socket = SocketAdaptor.create(this); |
193 return socket; |
204 return socket; |
205 } finally { |
|
206 stateLock.unlock(); |
|
194 } |
207 } |
195 } |
208 } |
196 |
209 |
197 @Override |
210 @Override |
198 public SocketAddress getLocalAddress() throws IOException { |
211 public SocketAddress getLocalAddress() throws IOException { |
199 synchronized (stateLock) { |
212 stateLock.lock(); |
213 try { |
|
200 ensureOpen(); |
214 ensureOpen(); |
201 return Net.getRevealedLocalAddress(localAddress); |
215 return Net.getRevealedLocalAddress(localAddress); |
216 } finally { |
|
217 stateLock.unlock(); |
|
202 } |
218 } |
203 } |
219 } |
204 |
220 |
205 @Override |
221 @Override |
206 public SocketAddress getRemoteAddress() throws IOException { |
222 public SocketAddress getRemoteAddress() throws IOException { |
207 synchronized (stateLock) { |
223 stateLock.lock(); |
224 try { |
|
208 ensureOpen(); |
225 ensureOpen(); |
209 return remoteAddress; |
226 return remoteAddress; |
227 } finally { |
|
228 stateLock.unlock(); |
|
210 } |
229 } |
211 } |
230 } |
212 |
231 |
213 @Override |
232 @Override |
214 public <T> SocketChannel setOption(SocketOption<T> name, T value) |
233 public <T> SocketChannel setOption(SocketOption<T> name, T value) |
216 { |
235 { |
217 Objects.requireNonNull(name); |
236 Objects.requireNonNull(name); |
218 if (!supportedOptions().contains(name)) |
237 if (!supportedOptions().contains(name)) |
219 throw new UnsupportedOperationException("'" + name + "' not supported"); |
238 throw new UnsupportedOperationException("'" + name + "' not supported"); |
220 |
239 |
221 synchronized (stateLock) { |
240 stateLock.lock(); |
241 try { |
|
222 ensureOpen(); |
242 ensureOpen(); |
223 |
243 |
224 if (name == StandardSocketOptions.IP_TOS) { |
244 if (name == StandardSocketOptions.IP_TOS) { |
225 ProtocolFamily family = Net.isIPv6Available() ? |
245 ProtocolFamily family = Net.isIPv6Available() ? |
226 StandardProtocolFamily.INET6 : StandardProtocolFamily.INET; |
246 StandardProtocolFamily.INET6 : StandardProtocolFamily.INET; |
235 } |
255 } |
236 |
256 |
237 // no options that require special handling |
257 // no options that require special handling |
238 Net.setSocketOption(fd, name, value); |
258 Net.setSocketOption(fd, name, value); |
239 return this; |
259 return this; |
260 } finally { |
|
261 stateLock.unlock(); |
|
240 } |
262 } |
241 } |
263 } |
242 |
264 |
243 @Override |
265 @Override |
244 @SuppressWarnings("unchecked") |
266 @SuppressWarnings("unchecked") |
247 { |
269 { |
248 Objects.requireNonNull(name); |
270 Objects.requireNonNull(name); |
249 if (!supportedOptions().contains(name)) |
271 if (!supportedOptions().contains(name)) |
250 throw new UnsupportedOperationException("'" + name + "' not supported"); |
272 throw new UnsupportedOperationException("'" + name + "' not supported"); |
251 |
273 |
252 synchronized (stateLock) { |
274 stateLock.lock(); |
275 try { |
|
253 ensureOpen(); |
276 ensureOpen(); |
254 |
277 |
255 if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) { |
278 if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) { |
256 // SO_REUSEADDR emulated when using exclusive bind |
279 // SO_REUSEADDR emulated when using exclusive bind |
257 return (T)Boolean.valueOf(isReuseAddress); |
280 return (T)Boolean.valueOf(isReuseAddress); |
264 return (T) Net.getSocketOption(fd, family, name); |
287 return (T) Net.getSocketOption(fd, family, name); |
265 } |
288 } |
266 |
289 |
267 // no options that require special handling |
290 // no options that require special handling |
268 return (T) Net.getSocketOption(fd, name); |
291 return (T) Net.getSocketOption(fd, name); |
292 } finally { |
|
293 stateLock.unlock(); |
|
269 } |
294 } |
270 } |
295 } |
271 |
296 |
272 private static class DefaultOptionsHolder { |
297 private static class DefaultOptionsHolder { |
273 static final Set<SocketOption<?>> defaultOptions = defaultOptions(); |
298 static final Set<SocketOption<?>> defaultOptions = defaultOptions(); |
305 private void beginRead(boolean blocking) throws ClosedChannelException { |
330 private void beginRead(boolean blocking) throws ClosedChannelException { |
306 if (blocking) { |
331 if (blocking) { |
307 // set hook for Thread.interrupt |
332 // set hook for Thread.interrupt |
308 begin(); |
333 begin(); |
309 |
334 |
310 synchronized (stateLock) { |
335 stateLock.lock(); |
336 try { |
|
311 ensureOpenAndConnected(); |
337 ensureOpenAndConnected(); |
312 // record thread so it can be signalled if needed |
338 // record thread so it can be signalled if needed |
313 readerThread = NativeThread.current(); |
339 readerThread = NativeThread.current(); |
340 } finally { |
|
341 stateLock.unlock(); |
|
314 } |
342 } |
315 } else { |
343 } else { |
316 ensureOpenAndConnected(); |
344 ensureOpenAndConnected(); |
317 } |
345 } |
318 } |
346 } |
325 */ |
353 */ |
326 private void endRead(boolean blocking, boolean completed) |
354 private void endRead(boolean blocking, boolean completed) |
327 throws AsynchronousCloseException |
355 throws AsynchronousCloseException |
328 { |
356 { |
329 if (blocking) { |
357 if (blocking) { |
330 synchronized (stateLock) { |
358 stateLock.lock(); |
359 try { |
|
331 readerThread = 0; |
360 readerThread = 0; |
332 // notify any thread waiting in implCloseSelectableChannel |
361 // notify any thread waiting in implCloseSelectableChannel |
333 if (state == ST_CLOSING) { |
362 if (state == ST_CLOSING) { |
334 stateLock.notifyAll(); |
363 stateCondition.signalAll(); |
335 } |
364 } |
365 } finally { |
|
366 stateLock.unlock(); |
|
336 } |
367 } |
337 // remove hook for Thread.interrupt |
368 // remove hook for Thread.interrupt |
338 end(completed); |
369 end(completed); |
339 } |
370 } |
340 } |
371 } |
360 |
391 |
361 // check if input is shutdown |
392 // check if input is shutdown |
362 if (isInputClosed) |
393 if (isInputClosed) |
363 return IOStatus.EOF; |
394 return IOStatus.EOF; |
364 |
395 |
396 n = IOUtil.read(fd, buf, -1, nd); |
|
365 if (blocking) { |
397 if (blocking) { |
366 do { |
398 while (IOStatus.okayToRetry(n) && isOpen()) { |
399 park(Net.POLLIN); |
|
367 n = IOUtil.read(fd, buf, -1, nd); |
400 n = IOUtil.read(fd, buf, -1, nd); |
368 } while (n == IOStatus.INTERRUPTED && isOpen()); |
401 } |
369 } else { |
|
370 n = IOUtil.read(fd, buf, -1, nd); |
|
371 } |
402 } |
372 } catch (ConnectionResetException e) { |
403 } catch (ConnectionResetException e) { |
373 connectionReset = true; |
404 connectionReset = true; |
374 throwConnectionReset(); |
405 throwConnectionReset(); |
375 } finally { |
406 } finally { |
402 |
433 |
403 // check if input is shutdown |
434 // check if input is shutdown |
404 if (isInputClosed) |
435 if (isInputClosed) |
405 return IOStatus.EOF; |
436 return IOStatus.EOF; |
406 |
437 |
438 n = IOUtil.read(fd, dsts, offset, length, nd); |
|
407 if (blocking) { |
439 if (blocking) { |
408 do { |
440 while (IOStatus.okayToRetry(n) && isOpen()) { |
441 park(Net.POLLIN); |
|
409 n = IOUtil.read(fd, dsts, offset, length, nd); |
442 n = IOUtil.read(fd, dsts, offset, length, nd); |
410 } while (n == IOStatus.INTERRUPTED && isOpen()); |
443 } |
411 } else { |
|
412 n = IOUtil.read(fd, dsts, offset, length, nd); |
|
413 } |
444 } |
414 } catch (ConnectionResetException e) { |
445 } catch (ConnectionResetException e) { |
415 connectionReset = true; |
446 connectionReset = true; |
416 throwConnectionReset(); |
447 throwConnectionReset(); |
417 } finally { |
448 } finally { |
434 private void beginWrite(boolean blocking) throws ClosedChannelException { |
465 private void beginWrite(boolean blocking) throws ClosedChannelException { |
435 if (blocking) { |
466 if (blocking) { |
436 // set hook for Thread.interrupt |
467 // set hook for Thread.interrupt |
437 begin(); |
468 begin(); |
438 |
469 |
439 synchronized (stateLock) { |
470 stateLock.lock(); |
471 try { |
|
440 ensureOpenAndConnected(); |
472 ensureOpenAndConnected(); |
441 if (isOutputClosed) |
473 if (isOutputClosed) |
442 throw new ClosedChannelException(); |
474 throw new ClosedChannelException(); |
443 // record thread so it can be signalled if needed |
475 // record thread so it can be signalled if needed |
444 writerThread = NativeThread.current(); |
476 writerThread = NativeThread.current(); |
477 } finally { |
|
478 stateLock.unlock(); |
|
445 } |
479 } |
446 } else { |
480 } else { |
447 ensureOpenAndConnected(); |
481 ensureOpenAndConnected(); |
448 } |
482 } |
449 } |
483 } |
456 */ |
490 */ |
457 private void endWrite(boolean blocking, boolean completed) |
491 private void endWrite(boolean blocking, boolean completed) |
458 throws AsynchronousCloseException |
492 throws AsynchronousCloseException |
459 { |
493 { |
460 if (blocking) { |
494 if (blocking) { |
461 synchronized (stateLock) { |
495 stateLock.lock(); |
496 try { |
|
462 writerThread = 0; |
497 writerThread = 0; |
463 // notify any thread waiting in implCloseSelectableChannel |
498 // notify any thread waiting in implCloseSelectableChannel |
464 if (state == ST_CLOSING) { |
499 if (state == ST_CLOSING) { |
465 stateLock.notifyAll(); |
500 stateCondition.signalAll(); |
466 } |
501 } |
502 } finally { |
|
503 stateLock.unlock(); |
|
467 } |
504 } |
468 // remove hook for Thread.interrupt |
505 // remove hook for Thread.interrupt |
469 end(completed); |
506 end(completed); |
470 } |
507 } |
471 } |
508 } |
478 try { |
515 try { |
479 boolean blocking = isBlocking(); |
516 boolean blocking = isBlocking(); |
480 int n = 0; |
517 int n = 0; |
481 try { |
518 try { |
482 beginWrite(blocking); |
519 beginWrite(blocking); |
520 n = IOUtil.write(fd, buf, -1, nd); |
|
483 if (blocking) { |
521 if (blocking) { |
484 do { |
522 while (IOStatus.okayToRetry(n) && isOpen()) { |
523 park(Net.POLLOUT); |
|
485 n = IOUtil.write(fd, buf, -1, nd); |
524 n = IOUtil.write(fd, buf, -1, nd); |
486 } while (n == IOStatus.INTERRUPTED && isOpen()); |
525 } |
487 } else { |
|
488 n = IOUtil.write(fd, buf, -1, nd); |
|
489 } |
526 } |
490 } finally { |
527 } finally { |
491 endWrite(blocking, n > 0); |
528 endWrite(blocking, n > 0); |
492 if (n <= 0 && isOutputClosed) |
529 if (n <= 0 && isOutputClosed) |
493 throw new AsynchronousCloseException(); |
530 throw new AsynchronousCloseException(); |
508 try { |
545 try { |
509 boolean blocking = isBlocking(); |
546 boolean blocking = isBlocking(); |
510 long n = 0; |
547 long n = 0; |
511 try { |
548 try { |
512 beginWrite(blocking); |
549 beginWrite(blocking); |
550 n = IOUtil.write(fd, srcs, offset, length, nd); |
|
513 if (blocking) { |
551 if (blocking) { |
514 do { |
552 while (IOStatus.okayToRetry(n) && isOpen()) { |
553 park(Net.POLLOUT); |
|
515 n = IOUtil.write(fd, srcs, offset, length, nd); |
554 n = IOUtil.write(fd, srcs, offset, length, nd); |
516 } while (n == IOStatus.INTERRUPTED && isOpen()); |
555 } |
517 } else { |
|
518 n = IOUtil.write(fd, srcs, offset, length, nd); |
|
519 } |
556 } |
520 } finally { |
557 } finally { |
521 endWrite(blocking, n > 0); |
558 endWrite(blocking, n > 0); |
522 if (n <= 0 && isOutputClosed) |
559 if (n <= 0 && isOutputClosed) |
523 throw new AsynchronousCloseException(); |
560 throw new AsynchronousCloseException(); |
560 protected void implConfigureBlocking(boolean block) throws IOException { |
597 protected void implConfigureBlocking(boolean block) throws IOException { |
561 readLock.lock(); |
598 readLock.lock(); |
562 try { |
599 try { |
563 writeLock.lock(); |
600 writeLock.lock(); |
564 try { |
601 try { |
565 synchronized (stateLock) { |
602 lockedConfigureBlocking(block); |
566 ensureOpen(); |
|
567 IOUtil.configureBlocking(fd, block); |
|
568 } |
|
569 } finally { |
603 } finally { |
570 writeLock.unlock(); |
604 writeLock.unlock(); |
571 } |
605 } |
572 } finally { |
606 } finally { |
573 readLock.unlock(); |
607 readLock.unlock(); |
574 } |
608 } |
575 } |
609 } |
576 |
610 |
577 /** |
611 /** |
612 * Adjust the blocking mode while holding the readLock or writeLock. |
|
613 */ |
|
614 private void lockedConfigureBlocking(boolean block) throws IOException { |
|
615 assert readLock.isHeldByCurrentThread() || writeLock.isHeldByCurrentThread(); |
|
616 stateLock.lock(); |
|
617 try { |
|
618 ensureOpen(); |
|
619 IOUtil.configureBlocking(fd, block); |
|
620 } finally { |
|
621 stateLock.unlock(); |
|
622 } |
|
623 } |
|
624 |
|
625 /** |
|
578 * Returns the local address, or null if not bound |
626 * Returns the local address, or null if not bound |
579 */ |
627 */ |
580 InetSocketAddress localAddress() { |
628 InetSocketAddress localAddress() { |
581 synchronized (stateLock) { |
629 stateLock.lock(); |
630 try { |
|
582 return localAddress; |
631 return localAddress; |
632 } finally { |
|
633 stateLock.unlock(); |
|
583 } |
634 } |
584 } |
635 } |
585 |
636 |
586 /** |
637 /** |
587 * Returns the remote address, or null if not connected |
638 * Returns the remote address, or null if not connected |
588 */ |
639 */ |
589 InetSocketAddress remoteAddress() { |
640 InetSocketAddress remoteAddress() { |
590 synchronized (stateLock) { |
641 stateLock.lock(); |
642 try { |
|
591 return remoteAddress; |
643 return remoteAddress; |
644 } finally { |
|
645 stateLock.unlock(); |
|
592 } |
646 } |
593 } |
647 } |
594 |
648 |
595 @Override |
649 @Override |
596 public SocketChannel bind(SocketAddress local) throws IOException { |
650 public SocketChannel bind(SocketAddress local) throws IOException { |
597 readLock.lock(); |
651 readLock.lock(); |
598 try { |
652 try { |
599 writeLock.lock(); |
653 writeLock.lock(); |
600 try { |
654 try { |
601 synchronized (stateLock) { |
655 stateLock.lock(); |
656 try { |
|
602 ensureOpen(); |
657 ensureOpen(); |
603 if (state == ST_CONNECTIONPENDING) |
658 if (state == ST_CONNECTIONPENDING) |
604 throw new ConnectionPendingException(); |
659 throw new ConnectionPendingException(); |
605 if (localAddress != null) |
660 if (localAddress != null) |
606 throw new AlreadyBoundException(); |
661 throw new AlreadyBoundException(); |
611 sm.checkListen(isa.getPort()); |
666 sm.checkListen(isa.getPort()); |
612 } |
667 } |
613 NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort()); |
668 NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort()); |
614 Net.bind(fd, isa.getAddress(), isa.getPort()); |
669 Net.bind(fd, isa.getAddress(), isa.getPort()); |
615 localAddress = Net.localAddress(fd); |
670 localAddress = Net.localAddress(fd); |
671 } finally { |
|
672 stateLock.unlock(); |
|
616 } |
673 } |
617 } finally { |
674 } finally { |
618 writeLock.unlock(); |
675 writeLock.unlock(); |
619 } |
676 } |
620 } finally { |
677 } finally { |
647 { |
704 { |
648 if (blocking) { |
705 if (blocking) { |
649 // set hook for Thread.interrupt |
706 // set hook for Thread.interrupt |
650 begin(); |
707 begin(); |
651 } |
708 } |
652 synchronized (stateLock) { |
709 stateLock.lock(); |
710 try { |
|
653 ensureOpen(); |
711 ensureOpen(); |
654 int state = this.state; |
712 int state = this.state; |
655 if (state == ST_CONNECTED) |
713 if (state == ST_CONNECTED) |
656 throw new AlreadyConnectedException(); |
714 throw new AlreadyConnectedException(); |
657 if (state == ST_CONNECTIONPENDING) |
715 if (state == ST_CONNECTIONPENDING) |
665 |
723 |
666 if (blocking) { |
724 if (blocking) { |
667 // record thread so it can be signalled if needed |
725 // record thread so it can be signalled if needed |
668 readerThread = NativeThread.current(); |
726 readerThread = NativeThread.current(); |
669 } |
727 } |
728 } finally { |
|
729 stateLock.unlock(); |
|
670 } |
730 } |
671 } |
731 } |
672 |
732 |
673 /** |
733 /** |
674 * Marks the end of a connect operation that may have blocked. |
734 * Marks the end of a connect operation that may have blocked. |
681 throws IOException |
741 throws IOException |
682 { |
742 { |
683 endRead(blocking, completed); |
743 endRead(blocking, completed); |
684 |
744 |
685 if (completed) { |
745 if (completed) { |
686 synchronized (stateLock) { |
746 stateLock.lock(); |
747 try { |
|
687 if (state == ST_CONNECTIONPENDING) { |
748 if (state == ST_CONNECTIONPENDING) { |
688 localAddress = Net.localAddress(fd); |
749 localAddress = Net.localAddress(fd); |
689 state = ST_CONNECTED; |
750 state = ST_CONNECTED; |
690 } |
751 } |
691 } |
752 } finally { |
692 } |
753 stateLock.unlock(); |
693 } |
754 } |
694 |
755 } |
695 @Override |
756 } |
696 public boolean connect(SocketAddress sa) throws IOException { |
757 |
758 /** |
|
759 * Checks the remote address to which this channel is to be connected. |
|
760 */ |
|
761 private InetSocketAddress checkRemote(SocketAddress sa) throws IOException { |
|
697 InetSocketAddress isa = Net.checkAddress(sa); |
762 InetSocketAddress isa = Net.checkAddress(sa); |
698 SecurityManager sm = System.getSecurityManager(); |
763 SecurityManager sm = System.getSecurityManager(); |
699 if (sm != null) |
764 if (sm != null) { |
700 sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort()); |
765 sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort()); |
701 |
766 } |
702 InetAddress ia = isa.getAddress(); |
767 if (isa.getAddress().isAnyLocalAddress()) { |
703 if (ia.isAnyLocalAddress()) |
768 return new InetSocketAddress(InetAddress.getLocalHost(), isa.getPort()); |
704 ia = InetAddress.getLocalHost(); |
769 } else { |
705 |
770 return isa; |
771 } |
|
772 } |
|
773 |
|
774 @Override |
|
775 public boolean connect(SocketAddress remote) throws IOException { |
|
776 InetSocketAddress isa = checkRemote(remote); |
|
706 try { |
777 try { |
707 readLock.lock(); |
778 readLock.lock(); |
708 try { |
779 try { |
709 writeLock.lock(); |
780 writeLock.lock(); |
710 try { |
781 try { |
711 int n = 0; |
|
712 boolean blocking = isBlocking(); |
782 boolean blocking = isBlocking(); |
783 boolean connected = false; |
|
713 try { |
784 try { |
714 beginConnect(blocking, isa); |
785 beginConnect(blocking, isa); |
715 do { |
786 int n = Net.connect(fd, isa.getAddress(), isa.getPort()); |
716 n = Net.connect(fd, ia, isa.getPort()); |
787 if (n > 0) { |
717 } while (n == IOStatus.INTERRUPTED && isOpen()); |
788 connected = true; |
789 } else if (blocking) { |
|
790 assert IOStatus.okayToRetry(n); |
|
791 boolean polled = false; |
|
792 while (!polled && isOpen()) { |
|
793 park(Net.POLLOUT); |
|
794 polled = Net.pollConnectNow(fd); |
|
795 } |
|
796 connected = polled && isOpen(); |
|
797 } |
|
718 } finally { |
798 } finally { |
719 endConnect(blocking, (n > 0)); |
799 endConnect(blocking, connected); |
720 } |
800 } |
721 assert IOStatus.check(n); |
801 return connected; |
722 return n > 0; |
|
723 } finally { |
802 } finally { |
724 writeLock.unlock(); |
803 writeLock.unlock(); |
725 } |
804 } |
726 } finally { |
805 } finally { |
727 readLock.unlock(); |
806 readLock.unlock(); |
742 private void beginFinishConnect(boolean blocking) throws ClosedChannelException { |
821 private void beginFinishConnect(boolean blocking) throws ClosedChannelException { |
743 if (blocking) { |
822 if (blocking) { |
744 // set hook for Thread.interrupt |
823 // set hook for Thread.interrupt |
745 begin(); |
824 begin(); |
746 } |
825 } |
747 synchronized (stateLock) { |
826 stateLock.lock(); |
827 try { |
|
748 ensureOpen(); |
828 ensureOpen(); |
749 if (state != ST_CONNECTIONPENDING) |
829 if (state != ST_CONNECTIONPENDING) |
750 throw new NoConnectionPendingException(); |
830 throw new NoConnectionPendingException(); |
751 if (blocking) { |
831 if (blocking) { |
752 // record thread so it can be signalled if needed |
832 // record thread so it can be signalled if needed |
753 readerThread = NativeThread.current(); |
833 readerThread = NativeThread.current(); |
754 } |
834 } |
835 } finally { |
|
836 stateLock.unlock(); |
|
755 } |
837 } |
756 } |
838 } |
757 |
839 |
758 /** |
840 /** |
759 * Marks the end of a finishConnect operation that may have blocked. |
841 * Marks the end of a finishConnect operation that may have blocked. |
766 throws IOException |
848 throws IOException |
767 { |
849 { |
768 endRead(blocking, completed); |
850 endRead(blocking, completed); |
769 |
851 |
770 if (completed) { |
852 if (completed) { |
771 synchronized (stateLock) { |
853 stateLock.lock(); |
854 try { |
|
772 if (state == ST_CONNECTIONPENDING) { |
855 if (state == ST_CONNECTIONPENDING) { |
773 localAddress = Net.localAddress(fd); |
856 localAddress = Net.localAddress(fd); |
774 state = ST_CONNECTED; |
857 state = ST_CONNECTED; |
775 } |
858 } |
859 } finally { |
|
860 stateLock.unlock(); |
|
776 } |
861 } |
777 } |
862 } |
778 } |
863 } |
779 |
864 |
780 @Override |
865 @Override |
790 |
875 |
791 boolean blocking = isBlocking(); |
876 boolean blocking = isBlocking(); |
792 boolean connected = false; |
877 boolean connected = false; |
793 try { |
878 try { |
794 beginFinishConnect(blocking); |
879 beginFinishConnect(blocking); |
880 boolean polled = Net.pollConnectNow(fd); |
|
795 if (blocking) { |
881 if (blocking) { |
796 do { |
882 while (!polled && isOpen()) { |
797 connected = Net.pollConnect(fd, -1); |
883 park(Net.POLLOUT); |
798 } while (!connected && isOpen()); |
884 polled = Net.pollConnectNow(fd); |
799 } else { |
885 } |
800 connected = Net.pollConnect(fd, 0); |
|
801 } |
886 } |
887 connected = polled && isOpen(); |
|
802 } finally { |
888 } finally { |
803 endFinishConnect(blocking, connected); |
889 endFinishConnect(blocking, connected); |
804 } |
890 } |
805 assert (blocking && connected) ^ !blocking; |
891 assert (blocking && connected) ^ !blocking; |
806 return connected; |
892 return connected; |
841 boolean blocking; |
927 boolean blocking; |
842 boolean connected; |
928 boolean connected; |
843 boolean interrupted = false; |
929 boolean interrupted = false; |
844 |
930 |
845 // set state to ST_CLOSING |
931 // set state to ST_CLOSING |
846 synchronized (stateLock) { |
932 stateLock.lock(); |
933 try { |
|
847 assert state < ST_CLOSING; |
934 assert state < ST_CLOSING; |
848 blocking = isBlocking(); |
935 blocking = isBlocking(); |
849 connected = (state == ST_CONNECTED); |
936 connected = (state == ST_CONNECTED); |
850 state = ST_CLOSING; |
937 state = ST_CLOSING; |
938 } finally { |
|
939 stateLock.unlock(); |
|
851 } |
940 } |
852 |
941 |
853 // wait for any outstanding I/O operations to complete |
942 // wait for any outstanding I/O operations to complete |
854 if (blocking) { |
943 if (blocking) { |
855 synchronized (stateLock) { |
944 stateLock.lock(); |
945 try { |
|
856 assert state == ST_CLOSING; |
946 assert state == ST_CLOSING; |
857 long reader = readerThread; |
947 long reader = readerThread; |
858 long writer = writerThread; |
948 long writer = writerThread; |
859 if (reader != 0 || writer != 0) { |
949 if (reader != 0 || writer != 0) { |
860 nd.preClose(fd); |
950 nd.preClose(fd); |
866 NativeThread.signal(writer); |
956 NativeThread.signal(writer); |
867 |
957 |
868 // wait for blocking I/O operations to end |
958 // wait for blocking I/O operations to end |
869 while (readerThread != 0 || writerThread != 0) { |
959 while (readerThread != 0 || writerThread != 0) { |
870 try { |
960 try { |
871 stateLock.wait(); |
961 stateCondition.await(); |
872 } catch (InterruptedException e) { |
962 } catch (InterruptedException e) { |
873 interrupted = true; |
963 interrupted = true; |
874 } |
964 } |
875 } |
965 } |
876 } |
966 } |
967 } finally { |
|
968 stateLock.unlock(); |
|
877 } |
969 } |
878 } else { |
970 } else { |
879 // non-blocking mode: wait for read/write to complete |
971 // non-blocking mode: wait for read/write to complete |
880 readLock.lock(); |
972 readLock.lock(); |
881 try { |
973 try { |
885 readLock.unlock(); |
977 readLock.unlock(); |
886 } |
978 } |
887 } |
979 } |
888 |
980 |
889 // set state to ST_KILLPENDING |
981 // set state to ST_KILLPENDING |
890 synchronized (stateLock) { |
982 stateLock.lock(); |
983 try { |
|
891 assert state == ST_CLOSING; |
984 assert state == ST_CLOSING; |
892 // if connected and the channel is registered with a Selector then |
985 // if connected and the channel is registered with a Selector then |
893 // shutdown the output if possible so that the peer reads EOF. If |
986 // shutdown the output if possible so that the peer reads EOF. If |
894 // SO_LINGER is enabled and set to a non-zero value then it needs to |
987 // SO_LINGER is enabled and set to a non-zero value then it needs to |
895 // be disabled so that the Selector does not wait when it closes |
988 // be disabled so that the Selector does not wait when it closes |
906 Net.shutdown(fd, Net.SHUT_WR); |
999 Net.shutdown(fd, Net.SHUT_WR); |
907 } |
1000 } |
908 } catch (IOException ignore) { } |
1001 } catch (IOException ignore) { } |
909 } |
1002 } |
910 state = ST_KILLPENDING; |
1003 state = ST_KILLPENDING; |
1004 } finally { |
|
1005 stateLock.unlock(); |
|
911 } |
1006 } |
912 |
1007 |
913 // close socket if not registered with Selector |
1008 // close socket if not registered with Selector |
914 if (!isRegistered()) |
1009 if (!isRegistered()) |
915 kill(); |
1010 kill(); |
919 Thread.currentThread().interrupt(); |
1014 Thread.currentThread().interrupt(); |
920 } |
1015 } |
921 |
1016 |
922 @Override |
1017 @Override |
923 public void kill() throws IOException { |
1018 public void kill() throws IOException { |
924 synchronized (stateLock) { |
1019 stateLock.lock(); |
1020 try { |
|
925 if (state == ST_KILLPENDING) { |
1021 if (state == ST_KILLPENDING) { |
926 state = ST_KILLED; |
1022 state = ST_KILLED; |
927 nd.close(fd); |
1023 nd.close(fd); |
928 } |
1024 } |
1025 } finally { |
|
1026 stateLock.unlock(); |
|
929 } |
1027 } |
930 } |
1028 } |
931 |
1029 |
932 @Override |
1030 @Override |
933 public SocketChannel shutdownInput() throws IOException { |
1031 public SocketChannel shutdownInput() throws IOException { |
934 synchronized (stateLock) { |
1032 stateLock.lock(); |
1033 try { |
|
935 ensureOpen(); |
1034 ensureOpen(); |
936 if (!isConnected()) |
1035 if (!isConnected()) |
937 throw new NotYetConnectedException(); |
1036 throw new NotYetConnectedException(); |
938 if (!isInputClosed) { |
1037 if (!isInputClosed) { |
939 Net.shutdown(fd, Net.SHUT_RD); |
1038 Net.shutdown(fd, Net.SHUT_RD); |
941 if (thread != 0) |
1040 if (thread != 0) |
942 NativeThread.signal(thread); |
1041 NativeThread.signal(thread); |
943 isInputClosed = true; |
1042 isInputClosed = true; |
944 } |
1043 } |
945 return this; |
1044 return this; |
1045 } finally { |
|
1046 stateLock.unlock(); |
|
946 } |
1047 } |
947 } |
1048 } |
948 |
1049 |
949 @Override |
1050 @Override |
950 public SocketChannel shutdownOutput() throws IOException { |
1051 public SocketChannel shutdownOutput() throws IOException { |
951 synchronized (stateLock) { |
1052 stateLock.lock(); |
1053 try { |
|
952 ensureOpen(); |
1054 ensureOpen(); |
953 if (!isConnected()) |
1055 if (!isConnected()) |
954 throw new NotYetConnectedException(); |
1056 throw new NotYetConnectedException(); |
955 if (!isOutputClosed) { |
1057 if (!isOutputClosed) { |
956 Net.shutdown(fd, Net.SHUT_WR); |
1058 Net.shutdown(fd, Net.SHUT_WR); |
958 if (thread != 0) |
1060 if (thread != 0) |
959 NativeThread.signal(thread); |
1061 NativeThread.signal(thread); |
960 isOutputClosed = true; |
1062 isOutputClosed = true; |
961 } |
1063 } |
962 return this; |
1064 return this; |
1065 } finally { |
|
1066 stateLock.unlock(); |
|
963 } |
1067 } |
964 } |
1068 } |
965 |
1069 |
966 boolean isInputOpen() { |
1070 boolean isInputOpen() { |
967 return !isInputClosed; |
1071 return !isInputClosed; |
970 boolean isOutputOpen() { |
1074 boolean isOutputOpen() { |
971 return !isOutputClosed; |
1075 return !isOutputClosed; |
972 } |
1076 } |
973 |
1077 |
974 /** |
1078 /** |
975 * Poll this channel's socket for reading up to the given timeout. |
1079 * Waits for a connection attempt to finish with a timeout |
976 * @return {@code true} if the socket is polled |
1080 * @throws SocketTimeoutException if the connect timeout elapses |
977 */ |
1081 */ |
978 boolean pollRead(long timeout) throws IOException { |
1082 private boolean finishTimedConnect(long nanos) throws IOException { |
979 boolean blocking = isBlocking(); |
1083 long startNanos = System.nanoTime(); |
980 assert Thread.holdsLock(blockingLock()) && blocking; |
1084 boolean polled = Net.pollConnectNow(fd); |
1085 while (!polled && isOpen()) { |
|
1086 long remainingNanos = nanos - (System.nanoTime() - startNanos); |
|
1087 if (remainingNanos <= 0) { |
|
1088 throw new SocketTimeoutException("Connect timed out"); |
|
1089 } |
|
1090 park(Net.POLLOUT, remainingNanos); |
|
1091 polled = Net.pollConnectNow(fd); |
|
1092 } |
|
1093 return polled && isOpen(); |
|
1094 } |
|
1095 |
|
1096 /** |
|
1097 * Attempts to establish a connection to the given socket address with a |
|
1098 * timeout. Closes the socket if connection cannot be established. |
|
1099 * |
|
1100 * @apiNote This method is for use by the socket adaptor. |
|
1101 * |
|
1102 * @throws IllegalBlockingModeException if the channel is non-blocking |
|
1103 * @throws SocketTimeoutException if the read timeout elapses |
|
1104 */ |
|
1105 void blockingConnect(SocketAddress remote, long nanos) throws IOException { |
|
1106 InetSocketAddress isa = checkRemote(remote); |
|
1107 try { |
|
1108 readLock.lock(); |
|
1109 try { |
|
1110 writeLock.lock(); |
|
1111 try { |
|
1112 if (!isBlocking()) |
|
1113 throw new IllegalBlockingModeException(); |
|
1114 boolean connected = false; |
|
1115 try { |
|
1116 beginConnect(true, isa); |
|
1117 // change socket to non-blocking |
|
1118 lockedConfigureBlocking(false); |
|
1119 try { |
|
1120 int n = Net.connect(fd, isa.getAddress(), isa.getPort()); |
|
1121 connected = (n > 0) ? true : finishTimedConnect(nanos); |
|
1122 } finally { |
|
1123 // restore socket to blocking mode |
|
1124 lockedConfigureBlocking(true); |
|
1125 } |
|
1126 } finally { |
|
1127 endConnect(true, connected); |
|
1128 } |
|
1129 } finally { |
|
1130 writeLock.unlock(); |
|
1131 } |
|
1132 } finally { |
|
1133 readLock.unlock(); |
|
1134 } |
|
1135 } catch (IOException ioe) { |
|
1136 // connect failed, close the channel |
|
1137 close(); |
|
1138 throw SocketExceptions.of(ioe, isa); |
|
1139 } |
|
1140 } |
|
1141 |
|
1142 /** |
|
1143 * Attempts to read bytes from the socket into the given byte array. |
|
1144 */ |
|
1145 private int tryRead(byte[] b, int off, int len) throws IOException { |
|
1146 ByteBuffer dst = Util.getTemporaryDirectBuffer(len); |
|
1147 assert dst.position() == 0; |
|
1148 try { |
|
1149 int n = nd.read(fd, ((DirectBuffer)dst).address(), len); |
|
1150 if (n > 0) { |
|
1151 dst.get(b, off, n); |
|
1152 } |
|
1153 return n; |
|
1154 } finally{ |
|
1155 Util.offerFirstTemporaryDirectBuffer(dst); |
|
1156 } |
|
1157 } |
|
1158 |
|
1159 /** |
|
1160 * Reads bytes from the socket into the given byte array with a timeout. |
|
1161 * @throws SocketTimeoutException if the read timeout elapses |
|
1162 */ |
|
1163 private int timedRead(byte[] b, int off, int len, long nanos) throws IOException { |
|
1164 long startNanos = System.nanoTime(); |
|
1165 int n = tryRead(b, off, len); |
|
1166 while (n == IOStatus.UNAVAILABLE && isOpen()) { |
|
1167 long remainingNanos = nanos - (System.nanoTime() - startNanos); |
|
1168 if (remainingNanos <= 0) { |
|
1169 throw new SocketTimeoutException("Read timed out"); |
|
1170 } |
|
1171 park(Net.POLLIN, remainingNanos); |
|
1172 n = tryRead(b, off, len); |
|
1173 } |
|
1174 return n; |
|
1175 } |
|
1176 |
|
1177 /** |
|
1178 * Reads bytes from the socket into the given byte array. |
|
1179 * |
|
1180 * @apiNote This method is for use by the socket adaptor. |
|
1181 * |
|
1182 * @throws IllegalBlockingModeException if the channel is non-blocking |
|
1183 * @throws SocketTimeoutException if the read timeout elapses |
|
1184 */ |
|
1185 int blockingRead(byte[] b, int off, int len, long nanos) throws IOException { |
|
1186 Objects.checkFromIndexSize(off, len, b.length); |
|
1187 if (len == 0) { |
|
1188 // nothing to do |
|
1189 return 0; |
|
1190 } |
|
981 |
1191 |
982 readLock.lock(); |
1192 readLock.lock(); |
983 try { |
1193 try { |
984 boolean polled = false; |
1194 // check that channel is configured blocking |
985 try { |
1195 if (!isBlocking()) |
986 beginRead(blocking); |
1196 throw new IllegalBlockingModeException(); |
987 int events = Net.poll(fd, Net.POLLIN, timeout); |
1197 |
988 polled = (events != 0); |
1198 int n = 0; |
989 } finally { |
1199 try { |
990 endRead(blocking, polled); |
1200 beginRead(true); |
991 } |
1201 |
992 return polled; |
1202 // check if connection has been reset |
1203 if (connectionReset) |
|
1204 throwConnectionReset(); |
|
1205 |
|
1206 // check if input is shutdown |
|
1207 if (isInputClosed) |
|
1208 return IOStatus.EOF; |
|
1209 |
|
1210 if (nanos > 0) { |
|
1211 // change socket to non-blocking |
|
1212 lockedConfigureBlocking(false); |
|
1213 try { |
|
1214 n = timedRead(b, off, len, nanos); |
|
1215 } finally { |
|
1216 // restore socket to blocking mode |
|
1217 lockedConfigureBlocking(true); |
|
1218 } |
|
1219 } else { |
|
1220 // read, no timeout |
|
1221 n = tryRead(b, off, len); |
|
1222 while (IOStatus.okayToRetry(n) && isOpen()) { |
|
1223 park(Net.POLLIN); |
|
1224 n = tryRead(b, off, len); |
|
1225 } |
|
1226 } |
|
1227 } catch (ConnectionResetException e) { |
|
1228 connectionReset = true; |
|
1229 throwConnectionReset(); |
|
1230 } finally { |
|
1231 endRead(true, n > 0); |
|
1232 if (n <= 0 && isInputClosed) |
|
1233 return IOStatus.EOF; |
|
1234 } |
|
1235 assert n > 0 || n == -1; |
|
1236 return n; |
|
993 } finally { |
1237 } finally { |
994 readLock.unlock(); |
1238 readLock.unlock(); |
995 } |
1239 } |
996 } |
1240 } |
997 |
1241 |
998 /** |
1242 /** |
999 * Poll this channel's socket for a connection, up to the given timeout. |
1243 * Attempts to write a sequence of bytes to the socket from the given |
1000 * @return {@code true} if the socket is polled |
1244 * byte array. |
1001 */ |
1245 */ |
1002 boolean pollConnected(long timeout) throws IOException { |
1246 private int tryWrite(byte[] b, int off, int len) throws IOException { |
1003 boolean blocking = isBlocking(); |
1247 ByteBuffer src = Util.getTemporaryDirectBuffer(len); |
1004 assert Thread.holdsLock(blockingLock()) && blocking; |
1248 assert src.position() == 0; |
1005 |
1249 try { |
1006 readLock.lock(); |
1250 src.put(b, off, len); |
1007 try { |
1251 return nd.write(fd, ((DirectBuffer)src).address(), len); |
1008 writeLock.lock(); |
1252 } finally { |
1009 try { |
1253 Util.offerFirstTemporaryDirectBuffer(src); |
1010 boolean polled = false; |
1254 } |
1011 try { |
1255 } |
1012 beginFinishConnect(blocking); |
1256 |
1013 int events = Net.poll(fd, Net.POLLCONN, timeout); |
1257 /** |
1014 polled = (events != 0); |
1258 * Writes a sequence of bytes to the socket from the given byte array. |
1015 } finally { |
1259 * |
1016 // invoke endFinishConnect with completed = false so that |
1260 * @apiNote This method is for use by the socket adaptor. |
1017 // the state is not changed to ST_CONNECTED. The socket |
1261 */ |
1018 // adaptor will use finishConnect to finish. |
1262 void blockingWriteFully(byte[] b, int off, int len) throws IOException { |
1019 endFinishConnect(blocking, /*completed*/false); |
1263 Objects.checkFromIndexSize(off, len, b.length); |
1020 } |
1264 if (len == 0) { |
1021 return polled; |
1265 // nothing to do |
1022 } finally { |
1266 return; |
1023 writeLock.unlock(); |
1267 } |
1024 } |
1268 |
1025 } finally { |
1269 writeLock.lock(); |
1026 readLock.unlock(); |
1270 try { |
1271 // check that channel is configured blocking |
|
1272 if (!isBlocking()) |
|
1273 throw new IllegalBlockingModeException(); |
|
1274 |
|
1275 // loop until all bytes have been written |
|
1276 int pos = off; |
|
1277 int end = off + len; |
|
1278 beginWrite(true); |
|
1279 try { |
|
1280 while (pos < end && isOpen()) { |
|
1281 int size = end - pos; |
|
1282 int n = tryWrite(b, pos, size); |
|
1283 while (IOStatus.okayToRetry(n) && isOpen()) { |
|
1284 park(Net.POLLOUT); |
|
1285 n = tryWrite(b, pos, size); |
|
1286 } |
|
1287 if (n > 0) { |
|
1288 pos += n; |
|
1289 } |
|
1290 } |
|
1291 } finally { |
|
1292 endWrite(true, pos >= end); |
|
1293 } |
|
1294 } finally { |
|
1295 writeLock.unlock(); |
|
1027 } |
1296 } |
1028 } |
1297 } |
1029 |
1298 |
1030 /** |
1299 /** |
1031 * Return the number of bytes in the socket input buffer. |
1300 * Return the number of bytes in the socket input buffer. |
1032 */ |
1301 */ |
1033 int available() throws IOException { |
1302 int available() throws IOException { |
1034 synchronized (stateLock) { |
1303 stateLock.lock(); |
1304 try { |
|
1035 ensureOpenAndConnected(); |
1305 ensureOpenAndConnected(); |
1036 if (isInputClosed) { |
1306 if (isInputClosed) { |
1037 return 0; |
1307 return 0; |
1038 } else { |
1308 } else { |
1039 return Net.available(fd); |
1309 return Net.available(fd); |
1040 } |
1310 } |
1311 } finally { |
|
1312 stateLock.unlock(); |
|
1041 } |
1313 } |
1042 } |
1314 } |
1043 |
1315 |
1044 /** |
1316 /** |
1045 * Translates native poll revent ops into a ready operation ops |
1317 * Translates native poll revent ops into a ready operation ops |
1115 sb.append(this.getClass().getSuperclass().getName()); |
1387 sb.append(this.getClass().getSuperclass().getName()); |
1116 sb.append('['); |
1388 sb.append('['); |
1117 if (!isOpen()) |
1389 if (!isOpen()) |
1118 sb.append("closed"); |
1390 sb.append("closed"); |
1119 else { |
1391 else { |
1120 synchronized (stateLock) { |
1392 stateLock.lock(); |
1393 try { |
|
1121 switch (state) { |
1394 switch (state) { |
1122 case ST_UNCONNECTED: |
1395 case ST_UNCONNECTED: |
1123 sb.append("unconnected"); |
1396 sb.append("unconnected"); |
1124 break; |
1397 break; |
1125 case ST_CONNECTIONPENDING: |
1398 case ST_CONNECTIONPENDING: |
1140 } |
1413 } |
1141 if (remoteAddress() != null) { |
1414 if (remoteAddress() != null) { |
1142 sb.append(" remote="); |
1415 sb.append(" remote="); |
1143 sb.append(remoteAddress().toString()); |
1416 sb.append(remoteAddress().toString()); |
1144 } |
1417 } |
1418 } finally { |
|
1419 stateLock.unlock(); |
|
1145 } |
1420 } |
1146 } |
1421 } |
1147 sb.append(']'); |
1422 sb.append(']'); |
1148 return sb.toString(); |
1423 return sb.toString(); |
1149 } |
1424 } |