Home | History | Annotate | Download | only in ch
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  * Copyright (c) 2000, 2011, 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.*;
     30 import java.lang.ref.*;
     31 import java.net.*;
     32 import java.nio.*;
     33 import java.nio.channels.*;
     34 import java.security.AccessController;
     35 import java.security.PrivilegedExceptionAction;
     36 import java.util.*;
     37 
     38 import sun.misc.IoTrace;
     39 
     40 
     41 // Make a socket channel look like a socket.
     42 //
     43 // The only aspects of java.net.Socket-hood that we don't attempt to emulate
     44 // here are the interrupted-I/O exceptions (which our Solaris implementations
     45 // attempt to support) and the sending of urgent data.  Otherwise an adapted
     46 // socket should look enough like a real java.net.Socket to fool most of the
     47 // developers most of the time, right down to the exception message strings.
     48 //
     49 // The methods in this class are defined in exactly the same order as in
     50 // java.net.Socket so as to simplify tracking future changes to that class.
     51 //
     52 
     53 public class SocketAdaptor
     54     extends Socket
     55 {
     56 
     57     // The channel being adapted
     58     private final SocketChannelImpl sc;
     59 
     60     // Timeout "option" value for reads
     61     private volatile int timeout = 0;
     62 
     63     private SocketAdaptor(SocketChannelImpl sc) throws SocketException {
     64         super(new FileDescriptorHolderSocketImpl(sc.getFD()));
     65         this.sc = sc;
     66     }
     67 
     68     public static Socket create(SocketChannelImpl sc) {
     69         try {
     70             return new SocketAdaptor(sc);
     71         } catch (SocketException e) {
     72             throw new InternalError("Should not reach here");
     73         }
     74     }
     75 
     76     public SocketChannel getChannel() {
     77         return sc;
     78     }
     79 
     80     // Override this method just to protect against changes in the superclass
     81     //
     82     public void connect(SocketAddress remote) throws IOException {
     83         connect(remote, 0);
     84     }
     85 
     86     public void connect(SocketAddress remote, int timeout) throws IOException {
     87         if (remote == null)
     88             throw new IllegalArgumentException("connect: The address can't be null");
     89         if (timeout < 0)
     90             throw new IllegalArgumentException("connect: timeout can't be negative");
     91 
     92         synchronized (sc.blockingLock()) {
     93             if (!sc.isBlocking())
     94                 throw new IllegalBlockingModeException();
     95 
     96             try {
     97 
     98                 if (timeout == 0) {
     99                     // Android-changed: Be consistent
    100                     try {
    101                         sc.connect(remote);
    102                     } catch (Exception ex) {
    103                         Net.translateException(ex);
    104                     }
    105 
    106                     return;
    107                 }
    108 
    109                 // Implement timeout with a selector
    110                 SelectionKey sk = null;
    111                 Selector sel = null;
    112                 sc.configureBlocking(false);
    113                 try {
    114                     if (sc.connect(remote))
    115                         return;
    116                     sel = Util.getTemporarySelector(sc);
    117                     sk = sc.register(sel, SelectionKey.OP_CONNECT);
    118                     long to = timeout;
    119                     for (;;) {
    120                         if (!sc.isOpen())
    121                             throw new ClosedChannelException();
    122                         long st = System.currentTimeMillis();
    123                         int ns = sel.select(to);
    124                         if (ns > 0 &&
    125                             sk.isConnectable() && sc.finishConnect())
    126                             break;
    127                         sel.selectedKeys().remove(sk);
    128                         to -= System.currentTimeMillis() - st;
    129                         if (to <= 0) {
    130                             try {
    131                                 sc.close();
    132                             } catch (IOException x) { }
    133                             throw new SocketTimeoutException();
    134                         }
    135                     }
    136                 } finally {
    137                     if (sk != null)
    138                         sk.cancel();
    139                     if (sc.isOpen())
    140                         sc.configureBlocking(true);
    141                     if (sel != null)
    142                         Util.releaseTemporarySelector(sel);
    143                 }
    144 
    145             } catch (Exception x) {
    146                 Net.translateException(x, true);
    147             }
    148         }
    149 
    150     }
    151 
    152     public void bind(SocketAddress local) throws IOException {
    153         try {
    154             sc.bind(local);
    155         } catch (Exception x) {
    156             Net.translateException(x);
    157         }
    158     }
    159 
    160     public InetAddress getInetAddress() {
    161         // Use #remoteAddress and do manual isConnected check. #getRemoteAddress() returns
    162         // non-null result before connection.
    163         if (!isConnected()) {
    164             return null;
    165         }
    166         SocketAddress remote = sc.remoteAddress();
    167         if (remote == null) {
    168             return null;
    169         } else {
    170             return ((InetSocketAddress)remote).getAddress();
    171         }
    172     }
    173 
    174     public InetAddress getLocalAddress() {
    175         if (sc.isOpen()) {
    176             InetSocketAddress local = sc.localAddress();
    177             if (local != null)
    178                 return Net.getRevealedLocalAddress(local).getAddress();
    179         }
    180         return new InetSocketAddress(0).getAddress();
    181     }
    182 
    183     public int getPort() {
    184         // Use #remoteAddress and do manual isConnected check. #getRemoteAddress() returns
    185         // non-null result before connection.
    186         if (!isConnected()) {
    187           return 0;
    188         }
    189         SocketAddress remote = sc.remoteAddress();
    190         if (remote == null) {
    191             return 0;
    192         } else {
    193             return ((InetSocketAddress)remote).getPort();
    194         }
    195     }
    196 
    197     public int getLocalPort() {
    198         SocketAddress local = sc.localAddress();
    199         if (local == null) {
    200             return -1;
    201         } else {
    202             return ((InetSocketAddress)local).getPort();
    203         }
    204     }
    205 
    206     private class SocketInputStream
    207         extends ChannelInputStream
    208     {
    209         private SocketInputStream() {
    210             super(sc);
    211         }
    212 
    213         protected int read(ByteBuffer bb)
    214             throws IOException
    215         {
    216             synchronized (sc.blockingLock()) {
    217                 if (!sc.isBlocking())
    218                     throw new IllegalBlockingModeException();
    219                 if (timeout == 0)
    220                     return sc.read(bb);
    221 
    222                 // Implement timeout with a selector
    223                 SelectionKey sk = null;
    224                 Selector sel = null;
    225                 sc.configureBlocking(false);
    226                 int n = 0;
    227                 Object traceContext = IoTrace.socketReadBegin();
    228                 try {
    229                     if ((n = sc.read(bb)) != 0)
    230                         return n;
    231                     sel = Util.getTemporarySelector(sc);
    232                     sk = sc.register(sel, SelectionKey.OP_READ);
    233                     long to = timeout;
    234                     for (;;) {
    235                         if (!sc.isOpen())
    236                             throw new ClosedChannelException();
    237                         long st = System.currentTimeMillis();
    238                         int ns = sel.select(to);
    239                         if (ns > 0 && sk.isReadable()) {
    240                             if ((n = sc.read(bb)) != 0)
    241                                 return n;
    242                         }
    243                         sel.selectedKeys().remove(sk);
    244                         to -= System.currentTimeMillis() - st;
    245                         if (to <= 0)
    246                             throw new SocketTimeoutException();
    247                     }
    248                 } finally {
    249                     IoTrace.socketReadEnd(traceContext, getInetAddress(),
    250                                           getPort(), timeout, n > 0 ? n : 0);
    251                     if (sk != null)
    252                         sk.cancel();
    253                     if (sc.isOpen())
    254                         sc.configureBlocking(true);
    255                     if (sel != null)
    256                         Util.releaseTemporarySelector(sel);
    257                 }
    258 
    259             }
    260         }
    261     }
    262 
    263     private InputStream socketInputStream = null;
    264 
    265     public InputStream getInputStream() throws IOException {
    266         if (!sc.isOpen())
    267             throw new SocketException("Socket is closed");
    268         if (!sc.isConnected())
    269             throw new SocketException("Socket is not connected");
    270         if (!sc.isInputOpen())
    271             throw new SocketException("Socket input is shutdown");
    272         if (socketInputStream == null) {
    273             try {
    274                 socketInputStream = AccessController.doPrivileged(
    275                     new PrivilegedExceptionAction<InputStream>() {
    276                         public InputStream run() throws IOException {
    277                             return new SocketInputStream();
    278                         }
    279                     });
    280             } catch (java.security.PrivilegedActionException e) {
    281                 throw (IOException)e.getException();
    282             }
    283         }
    284         return socketInputStream;
    285     }
    286 
    287     public OutputStream getOutputStream() throws IOException {
    288         if (!sc.isOpen())
    289             throw new SocketException("Socket is closed");
    290         if (!sc.isConnected())
    291             throw new SocketException("Socket is not connected");
    292         if (!sc.isOutputOpen())
    293             throw new SocketException("Socket output is shutdown");
    294         OutputStream os = null;
    295         try {
    296             os = AccessController.doPrivileged(
    297                 new PrivilegedExceptionAction<OutputStream>() {
    298                     public OutputStream run() throws IOException {
    299                         return Channels.newOutputStream(sc);
    300                     }
    301                 });
    302         } catch (java.security.PrivilegedActionException e) {
    303             throw (IOException)e.getException();
    304         }
    305         return os;
    306     }
    307 
    308     private void setBooleanOption(SocketOption<Boolean> name, boolean value)
    309         throws SocketException
    310     {
    311         try {
    312             sc.setOption(name, value);
    313         } catch (IOException x) {
    314             Net.translateToSocketException(x);
    315         }
    316     }
    317 
    318     private void setIntOption(SocketOption<Integer> name, int value)
    319         throws SocketException
    320     {
    321         try {
    322             sc.setOption(name, value);
    323         } catch (IOException x) {
    324             Net.translateToSocketException(x);
    325         }
    326     }
    327 
    328     private boolean getBooleanOption(SocketOption<Boolean> name) throws SocketException {
    329         try {
    330             return sc.getOption(name).booleanValue();
    331         } catch (IOException x) {
    332             Net.translateToSocketException(x);
    333             return false;       // keep compiler happy
    334         }
    335     }
    336 
    337     private int getIntOption(SocketOption<Integer> name) throws SocketException {
    338         try {
    339             return sc.getOption(name).intValue();
    340         } catch (IOException x) {
    341             Net.translateToSocketException(x);
    342             return -1;          // keep compiler happy
    343         }
    344     }
    345 
    346     public void setTcpNoDelay(boolean on) throws SocketException {
    347         setBooleanOption(StandardSocketOptions.TCP_NODELAY, on);
    348     }
    349 
    350     public boolean getTcpNoDelay() throws SocketException {
    351         return getBooleanOption(StandardSocketOptions.TCP_NODELAY);
    352     }
    353 
    354     public void setSoLinger(boolean on, int linger) throws SocketException {
    355         if (!on)
    356             linger = -1;
    357         setIntOption(StandardSocketOptions.SO_LINGER, linger);
    358     }
    359 
    360     public int getSoLinger() throws SocketException {
    361         return getIntOption(StandardSocketOptions.SO_LINGER);
    362     }
    363 
    364     public void sendUrgentData(int data) throws IOException {
    365         synchronized (sc.blockingLock()) {
    366             if (!sc.isBlocking())
    367                 throw new IllegalBlockingModeException();
    368             int n = sc.sendOutOfBandData((byte)data);
    369             assert n == 1;
    370         }
    371     }
    372 
    373     public void setOOBInline(boolean on) throws SocketException {
    374         setBooleanOption(ExtendedSocketOption.SO_OOBINLINE, on);
    375     }
    376 
    377     public boolean getOOBInline() throws SocketException {
    378         return getBooleanOption(ExtendedSocketOption.SO_OOBINLINE);
    379     }
    380 
    381     public void setSoTimeout(int timeout) throws SocketException {
    382         if (timeout < 0)
    383             throw new IllegalArgumentException("timeout can't be negative");
    384         this.timeout = timeout;
    385     }
    386 
    387     public int getSoTimeout() throws SocketException {
    388         return timeout;
    389     }
    390 
    391     public void setSendBufferSize(int size) throws SocketException {
    392         // size 0 valid for SocketChannel, invalid for Socket
    393         if (size <= 0)
    394             throw new IllegalArgumentException("Invalid send size");
    395         setIntOption(StandardSocketOptions.SO_SNDBUF, size);
    396     }
    397 
    398     public int getSendBufferSize() throws SocketException {
    399         return getIntOption(StandardSocketOptions.SO_SNDBUF);
    400     }
    401 
    402     public void setReceiveBufferSize(int size) throws SocketException {
    403         // size 0 valid for SocketChannel, invalid for Socket
    404         if (size <= 0)
    405             throw new IllegalArgumentException("Invalid receive size");
    406         setIntOption(StandardSocketOptions.SO_RCVBUF, size);
    407     }
    408 
    409     public int getReceiveBufferSize() throws SocketException {
    410         return getIntOption(StandardSocketOptions.SO_RCVBUF);
    411     }
    412 
    413     public void setKeepAlive(boolean on) throws SocketException {
    414         setBooleanOption(StandardSocketOptions.SO_KEEPALIVE, on);
    415     }
    416 
    417     public boolean getKeepAlive() throws SocketException {
    418         return getBooleanOption(StandardSocketOptions.SO_KEEPALIVE);
    419     }
    420 
    421     public void setTrafficClass(int tc) throws SocketException {
    422         setIntOption(StandardSocketOptions.IP_TOS, tc);
    423     }
    424 
    425     public int getTrafficClass() throws SocketException {
    426         return getIntOption(StandardSocketOptions.IP_TOS);
    427     }
    428 
    429     public void setReuseAddress(boolean on) throws SocketException {
    430         setBooleanOption(StandardSocketOptions.SO_REUSEADDR, on);
    431     }
    432 
    433     public boolean getReuseAddress() throws SocketException {
    434         return getBooleanOption(StandardSocketOptions.SO_REUSEADDR);
    435     }
    436 
    437     public void close() throws IOException {
    438         sc.close();
    439     }
    440 
    441     public void shutdownInput() throws IOException {
    442         try {
    443             sc.shutdownInput();
    444         } catch (Exception x) {
    445             Net.translateException(x);
    446         }
    447     }
    448 
    449     public void shutdownOutput() throws IOException {
    450         try {
    451             sc.shutdownOutput();
    452         } catch (Exception x) {
    453             Net.translateException(x);
    454         }
    455     }
    456 
    457     public String toString() {
    458         if (sc.isConnected())
    459             return "Socket[addr=" + getInetAddress() +
    460                 ",port=" + getPort() +
    461                 ",localport=" + getLocalPort() + "]";
    462         return "Socket[unconnected]";
    463     }
    464 
    465     public boolean isConnected() {
    466         return sc.isConnected();
    467     }
    468 
    469     public boolean isBound() {
    470         return sc.localAddress() != null;
    471     }
    472 
    473     public boolean isClosed() {
    474         return !sc.isOpen();
    475     }
    476 
    477     public boolean isInputShutdown() {
    478         return !sc.isInputOpen();
    479     }
    480 
    481     public boolean isOutputShutdown() {
    482         return !sc.isOutputOpen();
    483     }
    484 
    485     @Override
    486     public FileDescriptor getFileDescriptor$() {
    487         return sc.getFD();
    488     }
    489 }
    490