Home | History | Annotate | Download | only in net
      1 /*
      2  *  Licensed to the Apache Software Foundation (ASF) under one or more
      3  *  contributor license agreements.  See the NOTICE file distributed with
      4  *  this work for additional information regarding copyright ownership.
      5  *  The ASF licenses this file to You under the Apache License, Version 2.0
      6  *  (the "License"); you may not use this file except in compliance with
      7  *  the License.  You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  */
     17 
     18 package java.net;
     19 
     20 import dalvik.system.CloseGuard;
     21 import java.io.FileDescriptor;
     22 import java.io.IOException;
     23 import java.io.InputStream;
     24 import java.io.OutputStream;
     25 import java.net.ConnectException;
     26 import java.net.InetAddress;
     27 import java.net.InetSocketAddress;
     28 import java.net.Proxy;
     29 import java.net.SocketAddress;
     30 import java.net.SocketException;
     31 import java.net.SocketImpl;
     32 import java.net.SocketTimeoutException;
     33 import java.net.UnknownHostException;
     34 import java.nio.ByteOrder;
     35 import java.util.Arrays;
     36 import libcore.io.ErrnoException;
     37 import libcore.io.IoBridge;
     38 import libcore.io.Libcore;
     39 import libcore.io.Memory;
     40 import libcore.io.Streams;
     41 import static libcore.io.OsConstants.*;
     42 
     43 /**
     44  * @hide used in java.nio.
     45  */
     46 public class PlainSocketImpl extends SocketImpl {
     47 
     48     // For SOCKS support. A SOCKS bind() uses the last
     49     // host connected to in its request.
     50     private static InetAddress lastConnectedAddress;
     51 
     52     private static int lastConnectedPort;
     53 
     54     private boolean streaming = true;
     55 
     56     private boolean shutdownInput;
     57 
     58     private Proxy proxy;
     59 
     60     private final CloseGuard guard = CloseGuard.get();
     61 
     62     public PlainSocketImpl(FileDescriptor fd) {
     63         this.fd = fd;
     64         if (fd.valid()) {
     65             guard.open("close");
     66         }
     67     }
     68 
     69     public PlainSocketImpl(Proxy proxy) {
     70         this(new FileDescriptor());
     71         this.proxy = proxy;
     72     }
     73 
     74     public PlainSocketImpl() {
     75         this(new FileDescriptor());
     76     }
     77 
     78     public PlainSocketImpl(FileDescriptor fd, int localport, InetAddress addr, int port) {
     79         this.fd = fd;
     80         this.localport = localport;
     81         this.address = addr;
     82         this.port = port;
     83         if (fd.valid()) {
     84             guard.open("close");
     85         }
     86     }
     87 
     88     @Override
     89     protected void accept(SocketImpl newImpl) throws IOException {
     90         if (usingSocks()) {
     91             ((PlainSocketImpl) newImpl).socksBind();
     92             ((PlainSocketImpl) newImpl).socksAccept();
     93             return;
     94         }
     95 
     96         try {
     97             InetSocketAddress peerAddress = new InetSocketAddress();
     98             FileDescriptor clientFd = Libcore.os.accept(fd, peerAddress);
     99 
    100             // TODO: we can't just set newImpl.fd to clientFd because a nio SocketChannel may
    101             // be sharing the FileDescriptor. http://b//4452981.
    102             newImpl.fd.setInt$(clientFd.getInt$());
    103 
    104             newImpl.address = peerAddress.getAddress();
    105             newImpl.port = peerAddress.getPort();
    106         } catch (ErrnoException errnoException) {
    107             if (errnoException.errno == EAGAIN) {
    108                 throw new SocketTimeoutException(errnoException);
    109             }
    110             throw errnoException.rethrowAsSocketException();
    111         }
    112 
    113         // Reset the client's inherited read timeout to the Java-specified default of 0.
    114         newImpl.setOption(SocketOptions.SO_TIMEOUT, Integer.valueOf(0));
    115 
    116         newImpl.localport = IoBridge.getSocketLocalPort(newImpl.fd);
    117     }
    118 
    119     private boolean usingSocks() {
    120         return proxy != null && proxy.type() == Proxy.Type.SOCKS;
    121     }
    122 
    123     public void initLocalPort(int localPort) {
    124         this.localport = localPort;
    125     }
    126 
    127     public void initRemoteAddressAndPort(InetAddress remoteAddress, int remotePort) {
    128         this.address = remoteAddress;
    129         this.port = remotePort;
    130     }
    131 
    132     private void checkNotClosed() throws IOException {
    133         if (!fd.valid()) {
    134             throw new SocketException("Socket is closed");
    135         }
    136     }
    137 
    138     @Override
    139     protected synchronized int available() throws IOException {
    140         checkNotClosed();
    141         // we need to check if the input has been shutdown. If so
    142         // we should return that there is no data to be read
    143         if (shutdownInput) {
    144             return 0;
    145         }
    146         return IoBridge.available(fd);
    147     }
    148 
    149     @Override protected void bind(InetAddress address, int port) throws IOException {
    150         IoBridge.bind(fd, address, port);
    151         this.address = address;
    152         if (port != 0) {
    153             this.localport = port;
    154         } else {
    155             this.localport = IoBridge.getSocketLocalPort(fd);
    156         }
    157     }
    158 
    159     @Override
    160     protected synchronized void close() throws IOException {
    161         guard.close();
    162         IoBridge.closeSocket(fd);
    163     }
    164 
    165     @Override
    166     protected void connect(String aHost, int aPort) throws IOException {
    167         connect(InetAddress.getByName(aHost), aPort);
    168     }
    169 
    170     @Override
    171     protected void connect(InetAddress anAddr, int aPort) throws IOException {
    172         connect(anAddr, aPort, 0);
    173     }
    174 
    175     /**
    176      * Connects this socket to the specified remote host address/port.
    177      *
    178      * @param anAddr
    179      *            the remote host address to connect to
    180      * @param aPort
    181      *            the remote port to connect to
    182      * @param timeout
    183      *            a timeout where supported. 0 means no timeout
    184      * @throws IOException
    185      *             if an error occurs while connecting
    186      */
    187     private void connect(InetAddress anAddr, int aPort, int timeout) throws IOException {
    188         InetAddress normalAddr = anAddr.isAnyLocalAddress() ? InetAddress.getLocalHost() : anAddr;
    189         if (streaming && usingSocks()) {
    190             socksConnect(anAddr, aPort, 0);
    191         } else {
    192             IoBridge.connect(fd, normalAddr, aPort, timeout);
    193         }
    194         super.address = normalAddr;
    195         super.port = aPort;
    196     }
    197 
    198     @Override
    199     protected void create(boolean streaming) throws IOException {
    200         this.streaming = streaming;
    201         this.fd = IoBridge.socket(streaming);
    202     }
    203 
    204     @Override protected void finalize() throws Throwable {
    205         try {
    206             if (guard != null) {
    207                 guard.warnIfOpen();
    208             }
    209             close();
    210         } finally {
    211             super.finalize();
    212         }
    213     }
    214 
    215     @Override protected synchronized InputStream getInputStream() throws IOException {
    216         checkNotClosed();
    217         return new PlainSocketInputStream(this);
    218     }
    219 
    220     private static class PlainSocketInputStream extends InputStream {
    221         private final PlainSocketImpl socketImpl;
    222 
    223         public PlainSocketInputStream(PlainSocketImpl socketImpl) {
    224             this.socketImpl = socketImpl;
    225         }
    226 
    227         @Override public int available() throws IOException {
    228             return socketImpl.available();
    229         }
    230 
    231         @Override public void close() throws IOException {
    232             socketImpl.close();
    233         }
    234 
    235         @Override public int read() throws IOException {
    236             return Streams.readSingleByte(this);
    237         }
    238 
    239         @Override public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException {
    240             return socketImpl.read(buffer, byteOffset, byteCount);
    241         }
    242     }
    243 
    244     @Override public Object getOption(int option) throws SocketException {
    245         return IoBridge.getSocketOption(fd, option);
    246     }
    247 
    248     @Override protected synchronized OutputStream getOutputStream() throws IOException {
    249         checkNotClosed();
    250         return new PlainSocketOutputStream(this);
    251     }
    252 
    253     private static class PlainSocketOutputStream extends OutputStream {
    254         private final PlainSocketImpl socketImpl;
    255 
    256         public PlainSocketOutputStream(PlainSocketImpl socketImpl) {
    257             this.socketImpl = socketImpl;
    258         }
    259 
    260         @Override public void close() throws IOException {
    261             socketImpl.close();
    262         }
    263 
    264         @Override public void write(int oneByte) throws IOException {
    265             Streams.writeSingleByte(this, oneByte);
    266         }
    267 
    268         @Override public void write(byte[] buffer, int offset, int byteCount) throws IOException {
    269             socketImpl.write(buffer, offset, byteCount);
    270         }
    271     }
    272 
    273     @Override
    274     protected void listen(int backlog) throws IOException {
    275         if (usingSocks()) {
    276             // Do nothing for a SOCKS connection. The listen occurs on the
    277             // server during the bind.
    278             return;
    279         }
    280         try {
    281             Libcore.os.listen(fd, backlog);
    282         } catch (ErrnoException errnoException) {
    283             throw errnoException.rethrowAsSocketException();
    284         }
    285     }
    286 
    287     @Override
    288     public void setOption(int option, Object value) throws SocketException {
    289         IoBridge.setSocketOption(fd, option, value);
    290     }
    291 
    292     /**
    293      * Gets the SOCKS proxy server port.
    294      */
    295     private int socksGetServerPort() {
    296         // get socks server port from proxy. It is unnecessary to check
    297         // "socksProxyPort" property, since proxy setting should only be
    298         // determined by ProxySelector.
    299         InetSocketAddress addr = (InetSocketAddress) proxy.address();
    300         return addr.getPort();
    301     }
    302 
    303     /**
    304      * Gets the InetAddress of the SOCKS proxy server.
    305      */
    306     private InetAddress socksGetServerAddress() throws UnknownHostException {
    307         String proxyName;
    308         // get socks server address from proxy. It is unnecessary to check
    309         // "socksProxyHost" property, since all proxy setting should be
    310         // determined by ProxySelector.
    311         InetSocketAddress addr = (InetSocketAddress) proxy.address();
    312         proxyName = addr.getHostName();
    313         if (proxyName == null) {
    314             proxyName = addr.getAddress().getHostAddress();
    315         }
    316         return InetAddress.getByName(proxyName);
    317     }
    318 
    319     /**
    320      * Connect using a SOCKS server.
    321      */
    322     private void socksConnect(InetAddress applicationServerAddress, int applicationServerPort, int timeout) throws IOException {
    323         try {
    324             IoBridge.connect(fd, socksGetServerAddress(), socksGetServerPort(), timeout);
    325         } catch (Exception e) {
    326             throw new SocketException("SOCKS connection failed", e);
    327         }
    328 
    329         socksRequestConnection(applicationServerAddress, applicationServerPort);
    330 
    331         lastConnectedAddress = applicationServerAddress;
    332         lastConnectedPort = applicationServerPort;
    333     }
    334 
    335     /**
    336      * Request a SOCKS connection to the application server given. If the
    337      * request fails to complete successfully, an exception is thrown.
    338      */
    339     private void socksRequestConnection(InetAddress applicationServerAddress,
    340             int applicationServerPort) throws IOException {
    341         socksSendRequest(Socks4Message.COMMAND_CONNECT,
    342                 applicationServerAddress, applicationServerPort);
    343         Socks4Message reply = socksReadReply();
    344         if (reply.getCommandOrResult() != Socks4Message.RETURN_SUCCESS) {
    345             throw new IOException(reply.getErrorString(reply.getCommandOrResult()));
    346         }
    347     }
    348 
    349     /**
    350      * Perform an accept for a SOCKS bind.
    351      */
    352     public void socksAccept() throws IOException {
    353         Socks4Message reply = socksReadReply();
    354         if (reply.getCommandOrResult() != Socks4Message.RETURN_SUCCESS) {
    355             throw new IOException(reply.getErrorString(reply.getCommandOrResult()));
    356         }
    357     }
    358 
    359     /**
    360      * Shutdown the input portion of the socket.
    361      */
    362     @Override
    363     protected void shutdownInput() throws IOException {
    364         shutdownInput = true;
    365         try {
    366             Libcore.os.shutdown(fd, SHUT_RD);
    367         } catch (ErrnoException errnoException) {
    368             throw errnoException.rethrowAsSocketException();
    369         }
    370     }
    371 
    372     /**
    373      * Shutdown the output portion of the socket.
    374      */
    375     @Override
    376     protected void shutdownOutput() throws IOException {
    377         try {
    378             Libcore.os.shutdown(fd, SHUT_WR);
    379         } catch (ErrnoException errnoException) {
    380             throw errnoException.rethrowAsSocketException();
    381         }
    382     }
    383 
    384     /**
    385      * Bind using a SOCKS server.
    386      */
    387     private void socksBind() throws IOException {
    388         try {
    389             IoBridge.connect(fd, socksGetServerAddress(), socksGetServerPort());
    390         } catch (Exception e) {
    391             throw new IOException("Unable to connect to SOCKS server", e);
    392         }
    393 
    394         // There must be a connection to an application host for the bind to work.
    395         if (lastConnectedAddress == null) {
    396             throw new SocketException("Invalid SOCKS client");
    397         }
    398 
    399         // Use the last connected address and port in the bind request.
    400         socksSendRequest(Socks4Message.COMMAND_BIND, lastConnectedAddress,
    401                 lastConnectedPort);
    402         Socks4Message reply = socksReadReply();
    403 
    404         if (reply.getCommandOrResult() != Socks4Message.RETURN_SUCCESS) {
    405             throw new IOException(reply.getErrorString(reply.getCommandOrResult()));
    406         }
    407 
    408         // A peculiarity of socks 4 - if the address returned is 0, use the
    409         // original socks server address.
    410         if (reply.getIP() == 0) {
    411             address = socksGetServerAddress();
    412         } else {
    413             // IPv6 support not yet required as
    414             // currently the Socks4Message.getIP() only returns int,
    415             // so only works with IPv4 4byte addresses
    416             byte[] replyBytes = new byte[4];
    417             Memory.pokeInt(replyBytes, 0, reply.getIP(), ByteOrder.BIG_ENDIAN);
    418             address = InetAddress.getByAddress(replyBytes);
    419         }
    420         localport = reply.getPort();
    421     }
    422 
    423     /**
    424      * Send a SOCKS V4 request.
    425      */
    426     private void socksSendRequest(int command, InetAddress address, int port) throws IOException {
    427         Socks4Message request = new Socks4Message();
    428         request.setCommandOrResult(command);
    429         request.setPort(port);
    430         request.setIP(address.getAddress());
    431         request.setUserId("default");
    432 
    433         getOutputStream().write(request.getBytes(), 0, request.getLength());
    434     }
    435 
    436     /**
    437      * Read a SOCKS V4 reply.
    438      */
    439     private Socks4Message socksReadReply() throws IOException {
    440         Socks4Message reply = new Socks4Message();
    441         int bytesRead = 0;
    442         while (bytesRead < Socks4Message.REPLY_LENGTH) {
    443             int count = getInputStream().read(reply.getBytes(), bytesRead,
    444                     Socks4Message.REPLY_LENGTH - bytesRead);
    445             if (count == -1) {
    446                 break;
    447             }
    448             bytesRead += count;
    449         }
    450         if (Socks4Message.REPLY_LENGTH != bytesRead) {
    451             throw new SocketException("Malformed reply from SOCKS server");
    452         }
    453         return reply;
    454     }
    455 
    456     @Override
    457     protected void connect(SocketAddress remoteAddr, int timeout) throws IOException {
    458         InetSocketAddress inetAddr = (InetSocketAddress) remoteAddr;
    459         connect(inetAddr.getAddress(), inetAddr.getPort(), timeout);
    460     }
    461 
    462     @Override
    463     protected boolean supportsUrgentData() {
    464         return true;
    465     }
    466 
    467     @Override
    468     protected void sendUrgentData(int value) throws IOException {
    469         try {
    470             byte[] buffer = new byte[] { (byte) value };
    471             Libcore.os.sendto(fd, buffer, 0, 1, MSG_OOB, null, 0);
    472         } catch (ErrnoException errnoException) {
    473             throw errnoException.rethrowAsSocketException();
    474         }
    475     }
    476 
    477     /**
    478      * For PlainSocketInputStream.
    479      */
    480     private int read(byte[] buffer, int offset, int byteCount) throws IOException {
    481         if (byteCount == 0) {
    482             return 0;
    483         }
    484         Arrays.checkOffsetAndCount(buffer.length, offset, byteCount);
    485         if (shutdownInput) {
    486             return -1;
    487         }
    488         int readCount = IoBridge.recvfrom(true, fd, buffer, offset, byteCount, 0, null, false);
    489         // Return of zero bytes for a blocking socket means a timeout occurred
    490         if (readCount == 0) {
    491             throw new SocketTimeoutException();
    492         }
    493         // Return of -1 indicates the peer was closed
    494         if (readCount == -1) {
    495             shutdownInput = true;
    496         }
    497         return readCount;
    498     }
    499 
    500     /**
    501      * For PlainSocketOutputStream.
    502      */
    503     private void write(byte[] buffer, int offset, int byteCount) throws IOException {
    504         Arrays.checkOffsetAndCount(buffer.length, offset, byteCount);
    505         if (streaming) {
    506             while (byteCount > 0) {
    507                 int bytesWritten = IoBridge.sendto(fd, buffer, offset, byteCount, 0, null, 0);
    508                 byteCount -= bytesWritten;
    509                 offset += bytesWritten;
    510             }
    511         } else {
    512             // Unlike writes to a streaming socket, writes to a datagram
    513             // socket are all-or-nothing, so we don't need a loop here.
    514             // http://code.google.com/p/android/issues/detail?id=15304
    515             IoBridge.sendto(fd, buffer, offset, byteCount, 0, address, port);
    516         }
    517     }
    518 }
    519