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