1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This code is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License version 2 only, as
8  * published by the Free Software Foundation.  Oracle designates this
9  * particular file as subject to the "Classpath" exception as provided
10  * by Oracle in the LICENSE file that accompanied this code.
11  *
12  * This code is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15  * version 2 for more details (a copy is included in the LICENSE file that
16  * accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License version
19  * 2 along with this work; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21  *
22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23  * or visit www.oracle.com if you need additional information or have any
24  * questions.
25  */
26 
27 package sun.nio.ch;
28 
29 import java.io.FileDescriptor;
30 import java.io.IOException;
31 import java.net.*;
32 import java.nio.ByteBuffer;
33 import java.nio.channels.*;
34 import java.nio.channels.spi.*;
35 import java.util.*;
36 
37 import dalvik.system.BlockGuard;
38 import sun.net.NetHooks;
39 import sun.misc.IoTrace;
40 
41 /**
42  * An implementation of SocketChannels
43  */
44 
45 class SocketChannelImpl
46     extends SocketChannel
47     implements SelChImpl
48 {
49 
50     // Used to make native read and write calls
51     private static NativeDispatcher nd;
52 
53     // Our file descriptor object
54     private final FileDescriptor fd;
55 
56     // fd value needed for dev/poll. This value will remain valid
57     // even after the value in the file descriptor object has been set to -1
58     private final int fdVal;
59 
60     // IDs of native threads doing reads and writes, for signalling
61     private volatile long readerThread = 0;
62     private volatile long writerThread = 0;
63 
64     // Lock held by current reading or connecting thread
65     private final Object readLock = new Object();
66 
67     // Lock held by current writing or connecting thread
68     private final Object writeLock = new Object();
69 
70     // 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!
72     private final Object stateLock = new Object();
73 
74     // -- The following fields are protected by stateLock
75 
76     // set true when exclusive binding is on and SO_REUSEADDR is emulated
77     private boolean isReuseAddress;
78 
79     // State, increases monotonically
80     private static final int ST_UNINITIALIZED = -1;
81     private static final int ST_UNCONNECTED = 0;
82     private static final int ST_PENDING = 1;
83     private static final int ST_CONNECTED = 2;
84     private static final int ST_KILLPENDING = 3;
85     private static final int ST_KILLED = 4;
86     private int state = ST_UNINITIALIZED;
87 
88     // Binding
89     private InetSocketAddress localAddress;
90     private InetSocketAddress remoteAddress;
91 
92     // Input/Output open
93     private boolean isInputOpen = true;
94     private boolean isOutputOpen = true;
95     private boolean readyToConnect = false;
96 
97     // Socket adaptor, created on demand
98     private Socket socket;
99 
100     // -- End of fields protected by stateLock
101 
102 
103     // Constructor for normal connecting sockets
104     //
SocketChannelImpl(SelectorProvider sp)105     SocketChannelImpl(SelectorProvider sp) throws IOException {
106         super(sp);
107         this.fd = Net.socket(true);
108         this.fdVal = IOUtil.fdVal(fd);
109         this.state = ST_UNCONNECTED;
110     }
111 
SocketChannelImpl(SelectorProvider sp, FileDescriptor fd, boolean bound)112     SocketChannelImpl(SelectorProvider sp,
113                       FileDescriptor fd,
114                       boolean bound)
115         throws IOException
116     {
117         super(sp);
118         this.fd = fd;
119         this.fdVal = IOUtil.fdVal(fd);
120         this.state = ST_UNCONNECTED;
121         if (bound)
122             this.localAddress = Net.localAddress(fd);
123     }
124 
125     // Constructor for sockets obtained from server sockets
126     //
SocketChannelImpl(SelectorProvider sp, FileDescriptor fd, InetSocketAddress remote)127     SocketChannelImpl(SelectorProvider sp,
128                       FileDescriptor fd, InetSocketAddress remote)
129         throws IOException
130     {
131         super(sp);
132         this.fd = fd;
133         this.fdVal = IOUtil.fdVal(fd);
134         this.state = ST_CONNECTED;
135         this.localAddress = Net.localAddress(fd);
136         this.remoteAddress = remote;
137     }
138 
socket()139     public Socket socket() {
140         synchronized (stateLock) {
141             if (socket == null)
142                 socket = SocketAdaptor.create(this);
143             return socket;
144         }
145     }
146 
147     @Override
getLocalAddress()148     public SocketAddress getLocalAddress() throws IOException {
149         synchronized (stateLock) {
150             if (!isOpen())
151                 throw new ClosedChannelException();
152             return  Net.getRevealedLocalAddress(localAddress);
153         }
154     }
155 
156     @Override
getRemoteAddress()157     public SocketAddress getRemoteAddress() throws IOException {
158         synchronized (stateLock) {
159             if (!isOpen())
160                 throw new ClosedChannelException();
161             return remoteAddress;
162         }
163     }
164 
165     @Override
setOption(SocketOption<T> name, T value)166     public <T> SocketChannel setOption(SocketOption<T> name, T value)
167         throws IOException
168     {
169         if (name == null)
170             throw new NullPointerException();
171         if (!supportedOptions().contains(name))
172             throw new UnsupportedOperationException("'" + name + "' not supported");
173 
174         synchronized (stateLock) {
175             if (!isOpen())
176                 throw new ClosedChannelException();
177 
178             // special handling for IP_TOS: no-op when IPv6
179             if (name == StandardSocketOptions.IP_TOS) {
180                 if (!Net.isIPv6Available())
181                     Net.setSocketOption(fd, StandardProtocolFamily.INET, name, value);
182                 return this;
183             } else if (name == StandardSocketOptions.SO_REUSEADDR &&
184                            Net.useExclusiveBind())
185             {
186                 // SO_REUSEADDR emulated when using exclusive bind
187                 isReuseAddress = (Boolean)value;
188                 return this;
189             }
190 
191             // no options that require special handling
192             Net.setSocketOption(fd, Net.UNSPEC, name, value);
193             return this;
194         }
195     }
196 
197     @Override
198     @SuppressWarnings("unchecked")
getOption(SocketOption<T> name)199     public <T> T getOption(SocketOption<T> name)
200         throws IOException
201     {
202         if (name == null)
203             throw new NullPointerException();
204         if (!supportedOptions().contains(name))
205             throw new UnsupportedOperationException("'" + name + "' not supported");
206 
207         synchronized (stateLock) {
208             if (!isOpen())
209                 throw new ClosedChannelException();
210 
211             if (name == StandardSocketOptions.SO_REUSEADDR &&
212                     Net.useExclusiveBind())
213             {
214                 // SO_REUSEADDR emulated when using exclusive bind
215                 return (T)Boolean.valueOf(isReuseAddress);
216             }
217 
218             // special handling for IP_TOS: always return 0 when IPv6
219             if (name == StandardSocketOptions.IP_TOS) {
220                 return (Net.isIPv6Available()) ? (T) Integer.valueOf(0) :
221                     (T) Net.getSocketOption(fd, StandardProtocolFamily.INET, name);
222             }
223 
224             // no options that require special handling
225             return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
226         }
227     }
228 
229     private static class DefaultOptionsHolder {
230         static final Set<SocketOption<?>> defaultOptions = defaultOptions();
231 
defaultOptions()232         private static Set<SocketOption<?>> defaultOptions() {
233             HashSet<SocketOption<?>> set = new HashSet<SocketOption<?>>(8);
234             set.add(StandardSocketOptions.SO_SNDBUF);
235             set.add(StandardSocketOptions.SO_RCVBUF);
236             set.add(StandardSocketOptions.SO_KEEPALIVE);
237             set.add(StandardSocketOptions.SO_REUSEADDR);
238             set.add(StandardSocketOptions.SO_LINGER);
239             set.add(StandardSocketOptions.TCP_NODELAY);
240             // additional options required by socket adaptor
241             set.add(StandardSocketOptions.IP_TOS);
242             set.add(ExtendedSocketOption.SO_OOBINLINE);
243             return Collections.unmodifiableSet(set);
244         }
245     }
246 
247     @Override
supportedOptions()248     public final Set<SocketOption<?>> supportedOptions() {
249         return DefaultOptionsHolder.defaultOptions;
250     }
251 
ensureReadOpen()252     private boolean ensureReadOpen() throws ClosedChannelException {
253         synchronized (stateLock) {
254             if (!isOpen())
255                 throw new ClosedChannelException();
256             if (!isConnected())
257                 throw new NotYetConnectedException();
258             if (!isInputOpen)
259                 return false;
260             else
261                 return true;
262         }
263     }
264 
ensureWriteOpen()265     private void ensureWriteOpen() throws ClosedChannelException {
266         synchronized (stateLock) {
267             if (!isOpen())
268                 throw new ClosedChannelException();
269             if (!isOutputOpen)
270                 throw new ClosedChannelException();
271             if (!isConnected())
272                 throw new NotYetConnectedException();
273         }
274     }
275 
readerCleanup()276     private void readerCleanup() throws IOException {
277         synchronized (stateLock) {
278             readerThread = 0;
279             if (state == ST_KILLPENDING)
280                 kill();
281         }
282     }
283 
writerCleanup()284     private void writerCleanup() throws IOException {
285         synchronized (stateLock) {
286             writerThread = 0;
287             if (state == ST_KILLPENDING)
288                 kill();
289         }
290     }
291 
read(ByteBuffer buf)292     public int read(ByteBuffer buf) throws IOException {
293 
294         if (buf == null)
295             throw new NullPointerException();
296 
297         synchronized (readLock) {
298             if (!ensureReadOpen())
299                 return -1;
300             Object traceContext = null;
301             if (isBlocking()) {
302                 traceContext = IoTrace.socketReadBegin();
303             }
304             int n = 0;
305             try {
306 
307                 // Set up the interruption machinery; see
308                 // AbstractInterruptibleChannel for details
309                 //
310                 begin();
311 
312                 synchronized (stateLock) {
313                     if (!isOpen()) {
314                     // Either the current thread is already interrupted, so
315                     // begin() closed the channel, or another thread closed the
316                     // channel since we checked it a few bytecodes ago.  In
317                     // either case the value returned here is irrelevant since
318                     // the invocation of end() in the finally block will throw
319                     // an appropriate exception.
320                     //
321                         return 0;
322 
323                     }
324 
325                     // Save this thread so that it can be signalled on those
326                     // platforms that require it
327                     //
328                     readerThread = NativeThread.current();
329                 }
330 
331                 // Between the previous test of isOpen() and the return of the
332                 // IOUtil.read invocation below, this channel might be closed
333                 // or this thread might be interrupted.  We rely upon the
334                 // implicit synchronization point in the kernel read() call to
335                 // make sure that the right thing happens.  In either case the
336                 // implCloseSelectableChannel method is ultimately invoked in
337                 // some other thread, so there are three possibilities:
338                 //
339                 //   - implCloseSelectableChannel() invokes nd.preClose()
340                 //     before this thread invokes read(), in which case the
341                 //     read returns immediately with either EOF or an error,
342                 //     the latter of which will cause an IOException to be
343                 //     thrown.
344                 //
345                 //   - implCloseSelectableChannel() invokes nd.preClose() after
346                 //     this thread is blocked in read().  On some operating
347                 //     systems (e.g., Solaris and Windows) this causes the read
348                 //     to return immediately with either EOF or an error
349                 //     indication.
350                 //
351                 //   - implCloseSelectableChannel() invokes nd.preClose() after
352                 //     this thread is blocked in read() but the operating
353                 //     system (e.g., Linux) doesn't support preemptive close,
354                 //     so implCloseSelectableChannel() proceeds to signal this
355                 //     thread, thereby causing the read to return immediately
356                 //     with IOStatus.INTERRUPTED.
357                 //
358                 // In all three cases the invocation of end() in the finally
359                 // clause will notice that the channel has been closed and
360                 // throw an appropriate exception (AsynchronousCloseException
361                 // or ClosedByInterruptException) if necessary.
362                 //
363                 // *There is A fourth possibility. implCloseSelectableChannel()
364                 // invokes nd.preClose(), signals reader/writer thred and quickly
365                 // moves on to nd.close() in kill(), which does a real close.
366                 // Then a third thread accepts a new connection, opens file or
367                 // whatever that causes the released "fd" to be recycled. All
368                 // above happens just between our last isOpen() check and the
369                 // next kernel read reached, with the recycled "fd". The solution
370                 // is to postpone the real kill() if there is a reader or/and
371                 // writer thread(s) over there "waiting", leave the cleanup/kill
372                 // to the reader or writer thread. (the preClose() still happens
373                 // so the connection gets cut off as usual).
374                 //
375                 // For socket channels there is the additional wrinkle that
376                 // asynchronous shutdown works much like asynchronous close,
377                 // except that the channel is shutdown rather than completely
378                 // closed.  This is analogous to the first two cases above,
379                 // except that the shutdown operation plays the role of
380                 // nd.preClose().
381                 for (;;) {
382                     n = IOUtil.read(fd, buf, -1, nd);
383                     if ((n == IOStatus.INTERRUPTED) && isOpen()) {
384                         // The system call was interrupted but the channel
385                         // is still open, so retry
386                         continue;
387                     }
388                     return IOStatus.normalize(n);
389                 }
390 
391             } finally {
392                 readerCleanup();        // Clear reader thread
393 
394                 if (isBlocking()) {
395                     IoTrace.socketReadEnd(traceContext, remoteAddress.getAddress(),
396                                           remoteAddress.getPort(), 0, n > 0 ? n : 0);
397                 }
398 
399                 // The end method, which is defined in our superclass
400                 // AbstractInterruptibleChannel, resets the interruption
401                 // machinery.  If its argument is true then it returns
402                 // normally; otherwise it checks the interrupt and open state
403                 // of this channel and throws an appropriate exception if
404                 // necessary.
405                 //
406                 // So, if we actually managed to do any I/O in the above try
407                 // block then we pass true to the end method.  We also pass
408                 // true if the channel was in non-blocking mode when the I/O
409                 // operation was initiated but no data could be transferred;
410                 // this prevents spurious exceptions from being thrown in the
411                 // rare event that a channel is closed or a thread is
412                 // interrupted at the exact moment that a non-blocking I/O
413                 // request is made.
414                 //
415                 end(n > 0 || (n == IOStatus.UNAVAILABLE));
416 
417                 // Extra case for socket channels: Asynchronous shutdown
418                 //
419                 synchronized (stateLock) {
420                     if ((n <= 0) && (!isInputOpen))
421                         return IOStatus.EOF;
422                 }
423 
424                 assert IOStatus.check(n);
425 
426             }
427         }
428     }
429 
read(ByteBuffer[] dsts, int offset, int length)430     public long read(ByteBuffer[] dsts, int offset, int length)
431         throws IOException
432     {
433         if ((offset < 0) || (length < 0) || (offset > dsts.length - length))
434             throw new IndexOutOfBoundsException();
435         synchronized (readLock) {
436             if (!ensureReadOpen())
437                 return -1;
438             long n = 0;
439             Object traceContext = null;
440             if (isBlocking()) {
441                 traceContext = IoTrace.socketReadBegin();
442             }
443             try {
444                 begin();
445                 synchronized (stateLock) {
446                     if (!isOpen())
447                         return 0;
448                     readerThread = NativeThread.current();
449                 }
450 
451                 for (;;) {
452                     n = IOUtil.read(fd, dsts, offset, length, nd);
453                     if ((n == IOStatus.INTERRUPTED) && isOpen())
454                         continue;
455                     return IOStatus.normalize(n);
456                 }
457             } finally {
458                 readerCleanup();
459                 if (isBlocking()) {
460                     IoTrace.socketReadEnd(traceContext, remoteAddress.getAddress(),
461                                           remoteAddress.getPort(), 0, n > 0 ? n : 0);
462                 }
463                 end(n > 0 || (n == IOStatus.UNAVAILABLE));
464                 synchronized (stateLock) {
465                     if ((n <= 0) && (!isInputOpen))
466                         return IOStatus.EOF;
467                 }
468                 assert IOStatus.check(n);
469             }
470         }
471     }
472 
write(ByteBuffer buf)473     public int write(ByteBuffer buf) throws IOException {
474         if (buf == null)
475             throw new NullPointerException();
476         synchronized (writeLock) {
477             ensureWriteOpen();
478             int n = 0;
479             Object traceContext =
480                 IoTrace.socketWriteBegin();
481 
482             try {
483                 begin();
484                 synchronized (stateLock) {
485                     if (!isOpen())
486                         return 0;
487                     writerThread = NativeThread.current();
488                 }
489                 for (;;) {
490                     n = IOUtil.write(fd, buf, -1, nd);
491                     if ((n == IOStatus.INTERRUPTED) && isOpen())
492                         continue;
493                     return IOStatus.normalize(n);
494                 }
495             } finally {
496                 writerCleanup();
497                 IoTrace.socketWriteEnd(traceContext, remoteAddress.getAddress(),
498                                        remoteAddress.getPort(), n > 0 ? n : 0);
499                 end(n > 0 || (n == IOStatus.UNAVAILABLE));
500                 synchronized (stateLock) {
501                     if ((n <= 0) && (!isOutputOpen))
502                         throw new AsynchronousCloseException();
503                 }
504                 assert IOStatus.check(n);
505             }
506         }
507     }
508 
write(ByteBuffer[] srcs, int offset, int length)509     public long write(ByteBuffer[] srcs, int offset, int length)
510         throws IOException
511     {
512         if ((offset < 0) || (length < 0) || (offset > srcs.length - length))
513             throw new IndexOutOfBoundsException();
514         synchronized (writeLock) {
515             ensureWriteOpen();
516             long n = 0;
517             Object traceContext =
518                 IoTrace.socketWriteBegin();
519             try {
520                 begin();
521                 synchronized (stateLock) {
522                     if (!isOpen())
523                         return 0;
524                     writerThread = NativeThread.current();
525                 }
526                 for (;;) {
527                     n = IOUtil.write(fd, srcs, offset, length, nd);
528                     if ((n == IOStatus.INTERRUPTED) && isOpen())
529                         continue;
530                     return IOStatus.normalize(n);
531                 }
532             } finally {
533                 writerCleanup();
534                 IoTrace.socketWriteEnd(traceContext, remoteAddress.getAddress(),
535                                        remoteAddress.getPort(), n > 0 ? n : 0);
536                 end((n > 0) || (n == IOStatus.UNAVAILABLE));
537                 synchronized (stateLock) {
538                     if ((n <= 0) && (!isOutputOpen))
539                         throw new AsynchronousCloseException();
540                 }
541                 assert IOStatus.check(n);
542             }
543         }
544     }
545 
546     // package-private
sendOutOfBandData(byte b)547     int sendOutOfBandData(byte b) throws IOException {
548         synchronized (writeLock) {
549             ensureWriteOpen();
550             int n = 0;
551             try {
552                 begin();
553                 synchronized (stateLock) {
554                     if (!isOpen())
555                         return 0;
556                     writerThread = NativeThread.current();
557                 }
558                 for (;;) {
559                     n = sendOutOfBandData(fd, b);
560                     if ((n == IOStatus.INTERRUPTED) && isOpen())
561                         continue;
562                     return IOStatus.normalize(n);
563                 }
564             } finally {
565                 writerCleanup();
566                 end((n > 0) || (n == IOStatus.UNAVAILABLE));
567                 synchronized (stateLock) {
568                     if ((n <= 0) && (!isOutputOpen))
569                         throw new AsynchronousCloseException();
570                 }
571                 assert IOStatus.check(n);
572             }
573         }
574     }
575 
implConfigureBlocking(boolean block)576     protected void implConfigureBlocking(boolean block) throws IOException {
577         IOUtil.configureBlocking(fd, block);
578     }
579 
localAddress()580     public InetSocketAddress localAddress() {
581         synchronized (stateLock) {
582             return localAddress;
583         }
584     }
585 
remoteAddress()586     public SocketAddress remoteAddress() {
587         synchronized (stateLock) {
588             return remoteAddress;
589         }
590     }
591 
592     @Override
bind(SocketAddress local)593     public SocketChannel bind(SocketAddress local) throws IOException {
594         synchronized (readLock) {
595             synchronized (writeLock) {
596                 synchronized (stateLock) {
597                     if (!isOpen())
598                         throw new ClosedChannelException();
599                     if (state == ST_PENDING)
600                         throw new ConnectionPendingException();
601                     if (localAddress != null)
602                         throw new AlreadyBoundException();
603                     InetSocketAddress isa = (local == null) ?
604                         new InetSocketAddress(0) : Net.checkAddress(local);
605                     NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
606                     Net.bind(fd, isa.getAddress(), isa.getPort());
607                     localAddress = Net.localAddress(fd);
608                 }
609             }
610         }
611         return this;
612     }
613 
isConnected()614     public boolean isConnected() {
615         synchronized (stateLock) {
616             return (state == ST_CONNECTED);
617         }
618     }
619 
isConnectionPending()620     public boolean isConnectionPending() {
621         synchronized (stateLock) {
622             return (state == ST_PENDING);
623         }
624     }
625 
ensureOpenAndUnconnected()626     void ensureOpenAndUnconnected() throws IOException { // package-private
627         synchronized (stateLock) {
628             if (!isOpen())
629                 throw new ClosedChannelException();
630             if (state == ST_CONNECTED)
631                 throw new AlreadyConnectedException();
632             if (state == ST_PENDING)
633                 throw new ConnectionPendingException();
634         }
635     }
636 
connect(SocketAddress sa)637     public boolean connect(SocketAddress sa) throws IOException {
638         int localPort = 0;
639 
640         synchronized (readLock) {
641             synchronized (writeLock) {
642                 ensureOpenAndUnconnected();
643                 InetSocketAddress isa = Net.checkAddress(sa);
644                 SecurityManager sm = System.getSecurityManager();
645                 if (sm != null)
646                     sm.checkConnect(isa.getAddress().getHostAddress(),
647                                     isa.getPort());
648                 synchronized (blockingLock()) {
649                     int n = 0;
650                     try {
651                         try {
652                             begin();
653                             synchronized (stateLock) {
654                                 if (!isOpen()) {
655                                     return false;
656                                 }
657                                 // notify hook only if unbound
658                                 if (localAddress == null) {
659                                     NetHooks.beforeTcpConnect(fd,
660                                                            isa.getAddress(),
661                                                            isa.getPort());
662                                 }
663                                 readerThread = NativeThread.current();
664                             }
665                             for (;;) {
666                                 InetAddress ia = isa.getAddress();
667                                 if (ia.isAnyLocalAddress())
668                                     ia = InetAddress.getLocalHost();
669                                 n = Net.connect(fd,
670                                                 ia,
671                                                 isa.getPort());
672                                 if (  (n == IOStatus.INTERRUPTED)
673                                       && isOpen())
674                                     continue;
675                                 break;
676                             }
677 
678                         } finally {
679                             readerCleanup();
680                             end((n > 0) || (n == IOStatus.UNAVAILABLE));
681                             assert IOStatus.check(n);
682                         }
683                     } catch (IOException x) {
684                         // If an exception was thrown, close the channel after
685                         // invoking end() so as to avoid bogus
686                         // AsynchronousCloseExceptions
687                         close();
688                         throw x;
689                     }
690                     synchronized (stateLock) {
691                         remoteAddress = isa;
692                         if (n > 0) {
693 
694                             // Connection succeeded; disallow further
695                             // invocation
696                             state = ST_CONNECTED;
697                             if (isOpen())
698                                 localAddress = Net.localAddress(fd);
699                             return true;
700                         }
701                         // If nonblocking and no exception then connection
702                         // pending; disallow another invocation
703                         if (!isBlocking()) {
704                             state = ST_PENDING;
705                             if (isOpen()) {
706                                 localAddress = Net.localAddress(fd);
707                             }
708                         }
709                     }
710                 }
711                 return false;
712             }
713         }
714     }
715 
finishConnect()716     public boolean finishConnect() throws IOException {
717         synchronized (readLock) {
718             synchronized (writeLock) {
719                 synchronized (stateLock) {
720                     if (!isOpen())
721                         throw new ClosedChannelException();
722                     if (state == ST_CONNECTED)
723                         return true;
724                     if (state != ST_PENDING)
725                         throw new NoConnectionPendingException();
726                 }
727                 int n = 0;
728                 try {
729                     try {
730                         begin();
731                         synchronized (blockingLock()) {
732                             synchronized (stateLock) {
733                                 if (!isOpen()) {
734                                     return false;
735                                 }
736                                 readerThread = NativeThread.current();
737                             }
738 
739                             BlockGuard.getThreadPolicy().onNetwork();
740                             if (!isBlocking()) {
741                                 for (;;) {
742                                     n = checkConnect(fd, false,
743                                                      readyToConnect);
744                                     if (  (n == IOStatus.INTERRUPTED)
745                                           && isOpen())
746                                         continue;
747                                     break;
748                                 }
749                             } else {
750                                 for (;;) {
751                                     n = checkConnect(fd, true,
752                                                      readyToConnect);
753                                     if (n == 0) {
754                                         // Loop in case of
755                                         // spurious notifications
756                                         continue;
757                                     }
758                                     if (  (n == IOStatus.INTERRUPTED)
759                                           && isOpen())
760                                         continue;
761                                     break;
762                                 }
763                             }
764                         }
765                     } finally {
766                         synchronized (stateLock) {
767                             readerThread = 0;
768                             if (state == ST_KILLPENDING) {
769                                 kill();
770                                 // poll()/getsockopt() does not report
771                                 // error (throws exception, with n = 0)
772                                 // on Linux platform after dup2 and
773                                 // signal-wakeup. Force n to 0 so the
774                                 // end() can throw appropriate exception
775                                 n = 0;
776                             }
777                         }
778                         end((n > 0) || (n == IOStatus.UNAVAILABLE));
779                         assert IOStatus.check(n);
780                     }
781                 } catch (IOException x) {
782                     // If an exception was thrown, close the channel after
783                     // invoking end() so as to avoid bogus
784                     // AsynchronousCloseExceptions
785                     close();
786                     throw x;
787                 }
788                 if (n > 0) {
789                     synchronized (stateLock) {
790                         state = ST_CONNECTED;
791                         if (isOpen())
792                             localAddress = Net.localAddress(fd);
793                     }
794                     return true;
795                 }
796                 return false;
797             }
798         }
799     }
800 
801     @Override
shutdownInput()802     public SocketChannel shutdownInput() throws IOException {
803         synchronized (stateLock) {
804             if (!isOpen())
805                 throw new ClosedChannelException();
806             if (!isConnected())
807                 throw new NotYetConnectedException();
808             if (isInputOpen) {
809                 Net.shutdown(fd, Net.SHUT_RD);
810                 if (readerThread != 0)
811                     NativeThread.signal(readerThread);
812                 isInputOpen = false;
813             }
814             return this;
815         }
816     }
817 
818     @Override
shutdownOutput()819     public SocketChannel shutdownOutput() throws IOException {
820         synchronized (stateLock) {
821             if (!isOpen())
822                 throw new ClosedChannelException();
823             if (!isConnected())
824                 throw new NotYetConnectedException();
825             if (isOutputOpen) {
826                 Net.shutdown(fd, Net.SHUT_WR);
827                 if (writerThread != 0)
828                     NativeThread.signal(writerThread);
829                 isOutputOpen = false;
830             }
831             return this;
832         }
833     }
834 
isInputOpen()835     public boolean isInputOpen() {
836         synchronized (stateLock) {
837             return isInputOpen;
838         }
839     }
840 
isOutputOpen()841     public boolean isOutputOpen() {
842         synchronized (stateLock) {
843             return isOutputOpen;
844         }
845     }
846 
847     // AbstractInterruptibleChannel synchronizes invocations of this method
848     // using AbstractInterruptibleChannel.closeLock, and also ensures that this
849     // method is only ever invoked once.  Before we get to this method, isOpen
850     // (which is volatile) will have been set to false.
851     //
implCloseSelectableChannel()852     protected void implCloseSelectableChannel() throws IOException {
853         synchronized (stateLock) {
854             isInputOpen = false;
855             isOutputOpen = false;
856 
857             // Close the underlying file descriptor and dup it to a known fd
858             // that's already closed.  This prevents other operations on this
859             // channel from using the old fd, which might be recycled in the
860             // meantime and allocated to an entirely different channel.
861             //
862             if (state != ST_KILLED)
863                 nd.preClose(fd);
864 
865             // Signal native threads, if needed.  If a target thread is not
866             // currently blocked in an I/O operation then no harm is done since
867             // the signal handler doesn't actually do anything.
868             //
869             if (readerThread != 0)
870                 NativeThread.signal(readerThread);
871 
872             if (writerThread != 0)
873                 NativeThread.signal(writerThread);
874 
875             // If this channel is not registered then it's safe to close the fd
876             // immediately since we know at this point that no thread is
877             // blocked in an I/O operation upon the channel and, since the
878             // channel is marked closed, no thread will start another such
879             // operation.  If this channel is registered then we don't close
880             // the fd since it might be in use by a selector.  In that case
881             // closing this channel caused its keys to be cancelled, so the
882             // last selector to deregister a key for this channel will invoke
883             // kill() to close the fd.
884             //
885             if (!isRegistered())
886                 kill();
887         }
888     }
889 
kill()890     public void kill() throws IOException {
891         synchronized (stateLock) {
892             if (state == ST_KILLED)
893                 return;
894             if (state == ST_UNINITIALIZED) {
895                 state = ST_KILLED;
896                 return;
897             }
898             assert !isOpen() && !isRegistered();
899 
900             // Postpone the kill if there is a waiting reader
901             // or writer thread. See the comments in read() for
902             // more detailed explanation.
903             if (readerThread == 0 && writerThread == 0) {
904                 nd.close(fd);
905                 state = ST_KILLED;
906             } else {
907                 state = ST_KILLPENDING;
908             }
909         }
910     }
911 
912     /**
913      * Translates native poll revent ops into a ready operation ops
914      */
translateReadyOps(int ops, int initialOps, SelectionKeyImpl sk)915     public boolean translateReadyOps(int ops, int initialOps,
916                                      SelectionKeyImpl sk) {
917         int intOps = sk.nioInterestOps(); // Do this just once, it synchronizes
918         int oldOps = sk.nioReadyOps();
919         int newOps = initialOps;
920 
921         if ((ops & PollArrayWrapper.POLLNVAL) != 0) {
922             // This should only happen if this channel is pre-closed while a
923             // selection operation is in progress
924             // ## Throw an error if this channel has not been pre-closed
925             return false;
926         }
927 
928         if ((ops & (PollArrayWrapper.POLLERR
929                     | PollArrayWrapper.POLLHUP)) != 0) {
930             newOps = intOps;
931             sk.nioReadyOps(newOps);
932             // No need to poll again in checkConnect,
933             // the error will be detected there
934             readyToConnect = true;
935             return (newOps & ~oldOps) != 0;
936         }
937 
938         if (((ops & PollArrayWrapper.POLLIN) != 0) &&
939             ((intOps & SelectionKey.OP_READ) != 0) &&
940             (state == ST_CONNECTED))
941             newOps |= SelectionKey.OP_READ;
942 
943         if (((ops & PollArrayWrapper.POLLCONN) != 0) &&
944             ((intOps & SelectionKey.OP_CONNECT) != 0) &&
945             ((state == ST_UNCONNECTED) || (state == ST_PENDING))) {
946             newOps |= SelectionKey.OP_CONNECT;
947             readyToConnect = true;
948         }
949 
950         if (((ops & PollArrayWrapper.POLLOUT) != 0) &&
951             ((intOps & SelectionKey.OP_WRITE) != 0) &&
952             (state == ST_CONNECTED))
953             newOps |= SelectionKey.OP_WRITE;
954 
955         sk.nioReadyOps(newOps);
956         return (newOps & ~oldOps) != 0;
957     }
958 
translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk)959     public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {
960         return translateReadyOps(ops, sk.nioReadyOps(), sk);
961     }
962 
translateAndSetReadyOps(int ops, SelectionKeyImpl sk)963     public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {
964         return translateReadyOps(ops, 0, sk);
965     }
966 
967     /**
968      * Translates an interest operation set into a native poll event set
969      */
translateAndSetInterestOps(int ops, SelectionKeyImpl sk)970     public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
971         int newOps = 0;
972         if ((ops & SelectionKey.OP_READ) != 0)
973             newOps |= PollArrayWrapper.POLLIN;
974         if ((ops & SelectionKey.OP_WRITE) != 0)
975             newOps |= PollArrayWrapper.POLLOUT;
976         if ((ops & SelectionKey.OP_CONNECT) != 0)
977             newOps |= PollArrayWrapper.POLLCONN;
978         sk.selector.putEventOps(sk, newOps);
979     }
980 
getFD()981     public FileDescriptor getFD() {
982         return fd;
983     }
984 
getFDVal()985     public int getFDVal() {
986         return fdVal;
987     }
988 
989     @Override
toString()990     public String toString() {
991         StringBuffer sb = new StringBuffer();
992         sb.append(this.getClass().getSuperclass().getName());
993         sb.append('[');
994         if (!isOpen())
995             sb.append("closed");
996         else {
997             synchronized (stateLock) {
998                 switch (state) {
999                 case ST_UNCONNECTED:
1000                     sb.append("unconnected");
1001                     break;
1002                 case ST_PENDING:
1003                     sb.append("connection-pending");
1004                     break;
1005                 case ST_CONNECTED:
1006                     sb.append("connected");
1007                     if (!isInputOpen)
1008                         sb.append(" ishut");
1009                     if (!isOutputOpen)
1010                         sb.append(" oshut");
1011                     break;
1012                 }
1013                 InetSocketAddress addr = localAddress();
1014                 if (addr != null) {
1015                     sb.append(" local=");
1016                     sb.append(Net.getRevealedLocalAddressAsString(addr));
1017                 }
1018                 if (remoteAddress() != null) {
1019                     sb.append(" remote=");
1020                     sb.append(remoteAddress().toString());
1021                 }
1022             }
1023         }
1024         sb.append(']');
1025         return sb.toString();
1026     }
1027 
1028 
1029     // -- Native methods --
1030 
checkConnect(FileDescriptor fd, boolean block, boolean ready)1031     private static native int checkConnect(FileDescriptor fd,
1032                                            boolean block, boolean ready)
1033         throws IOException;
1034 
sendOutOfBandData(FileDescriptor fd, byte data)1035     private static native int sendOutOfBandData(FileDescriptor fd, byte data)
1036         throws IOException;
1037 
1038     static {
1039         nd = new SocketDispatcher();
1040     }
1041 
1042 }
1043