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