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 java.io.Closeable;
     21 import java.io.FileDescriptor;
     22 import java.io.IOException;
     23 import java.io.InputStream;
     24 import java.io.OutputStream;
     25 import java.nio.channels.SocketChannel;
     26 import libcore.io.IoBridge;
     27 
     28 /**
     29  * Provides a client-side TCP socket.
     30  */
     31 public class Socket implements Closeable {
     32     private static SocketImplFactory factory;
     33 
     34     final SocketImpl impl;
     35     private final Proxy proxy;
     36 
     37     volatile boolean isCreated = false;
     38     private boolean isBound = false;
     39     private boolean isConnected = false;
     40     private boolean isClosed = false;
     41     private boolean isInputShutdown = false;
     42     private boolean isOutputShutdown = false;
     43 
     44     private InetAddress localAddress = Inet4Address.ANY;
     45 
     46     private final Object connectLock = new Object();
     47 
     48     /**
     49      * Creates a new unconnected socket. When a SocketImplFactory is defined it
     50      * creates the internal socket implementation, otherwise the default socket
     51      * implementation will be used for this socket.
     52      *
     53      * @see SocketImplFactory
     54      * @see SocketImpl
     55      */
     56     public Socket() {
     57         this.impl = factory != null ? factory.createSocketImpl() : new PlainSocketImpl();
     58         this.proxy = null;
     59     }
     60 
     61     /**
     62      * Creates a new unconnected socket using the given proxy type. When a
     63      * {@code SocketImplFactory} is defined it creates the internal socket
     64      * implementation, otherwise the default socket implementation will be used
     65      * for this socket.
     66      * <p>
     67      * Example that will create a socket connection through a {@code SOCKS}
     68      * proxy server: <br>
     69      * {@code Socket sock = new Socket(new Proxy(Proxy.Type.SOCKS, new
     70      * InetSocketAddress("test.domain.org", 2130)));}
     71      *
     72      * @param proxy
     73      *            the specified proxy for this socket.
     74      * @throws IllegalArgumentException
     75      *             if the argument {@code proxy} is {@code null} or of an
     76      *             invalid type.
     77      * @see SocketImplFactory
     78      * @see SocketImpl
     79      */
     80     public Socket(Proxy proxy) {
     81         if (proxy == null || proxy.type() == Proxy.Type.HTTP) {
     82             throw new IllegalArgumentException("Invalid proxy: " + proxy);
     83         }
     84         this.proxy = proxy;
     85         this.impl = factory != null ? factory.createSocketImpl() : new PlainSocketImpl(proxy);
     86     }
     87 
     88     /**
     89      * Tries to connect a socket to all IP addresses of the given hostname.
     90      *
     91      * @param dstName
     92      *            the target host name or IP address to connect to.
     93      * @param dstPort
     94      *            the port on the target host to connect to.
     95      * @param localAddress
     96      *            the address on the local host to bind to.
     97      * @param localPort
     98      *            the port on the local host to bind to.
     99      * @param streaming
    100      *            if {@code true} a streaming socket is returned, a datagram
    101      *            socket otherwise.
    102      * @throws UnknownHostException
    103      *             if the host name could not be resolved into an IP address.
    104      * @throws IOException
    105      *             if an error occurs while creating the socket.
    106      */
    107     private void tryAllAddresses(String dstName, int dstPort, InetAddress
    108             localAddress, int localPort, boolean streaming) throws IOException {
    109         InetAddress[] dstAddresses = InetAddress.getAllByName(dstName);
    110         // Loop through all the destination addresses except the last, trying to
    111         // connect to each one and ignoring errors. There must be at least one
    112         // address, or getAllByName would have thrown UnknownHostException.
    113         InetAddress dstAddress;
    114         for (int i = 0; i < dstAddresses.length - 1; i++) {
    115             dstAddress = dstAddresses[i];
    116             try {
    117                 checkDestination(dstAddress, dstPort);
    118                 startupSocket(dstAddress, dstPort, localAddress, localPort, streaming);
    119                 return;
    120             } catch (IOException ex) {
    121             }
    122         }
    123 
    124         // Now try to connect to the last address in the array, handing back to
    125         // the caller any exceptions that are thrown.
    126         dstAddress = dstAddresses[dstAddresses.length - 1];
    127         checkDestination(dstAddress, dstPort);
    128         startupSocket(dstAddress, dstPort, localAddress, localPort, streaming);
    129     }
    130 
    131     /**
    132      * Creates a new streaming socket connected to the target host specified by
    133      * the parameters {@code dstName} and {@code dstPort}. The socket is bound
    134      * to any available port on the local host.
    135      *
    136      * <p>This implementation tries each IP address for the given hostname (in
    137      * <a href="http://www.ietf.org/rfc/rfc3484.txt">RFC 3484</a> order)
    138      * until it either connects successfully or it exhausts the set.
    139      *
    140      * @param dstName
    141      *            the target host name or IP address to connect to.
    142      * @param dstPort
    143      *            the port on the target host to connect to.
    144      * @throws UnknownHostException
    145      *             if the host name could not be resolved into an IP address.
    146      * @throws IOException
    147      *             if an error occurs while creating the socket.
    148      */
    149     public Socket(String dstName, int dstPort) throws UnknownHostException, IOException {
    150         this(dstName, dstPort, null, 0);
    151     }
    152 
    153     /**
    154      * Creates a new streaming socket connected to the target host specified by
    155      * the parameters {@code dstName} and {@code dstPort}. On the local endpoint
    156      * the socket is bound to the given address {@code localAddress} on port
    157      * {@code localPort}. If {@code host} is {@code null} a loopback address is used to connect to.
    158      *
    159      * <p>This implementation tries each IP address for the given hostname (in
    160      * <a href="http://www.ietf.org/rfc/rfc3484.txt">RFC 3484</a> order)
    161      * until it either connects successfully or it exhausts the set.
    162      *
    163      * @param dstName
    164      *            the target host name or IP address to connect to.
    165      * @param dstPort
    166      *            the port on the target host to connect to.
    167      * @param localAddress
    168      *            the address on the local host to bind to.
    169      * @param localPort
    170      *            the port on the local host to bind to.
    171      * @throws UnknownHostException
    172      *             if the host name could not be resolved into an IP address.
    173      * @throws IOException
    174      *             if an error occurs while creating the socket.
    175      */
    176     public Socket(String dstName, int dstPort, InetAddress localAddress, int localPort) throws IOException {
    177         this();
    178         tryAllAddresses(dstName, dstPort, localAddress, localPort, true);
    179     }
    180 
    181     /**
    182      * Creates a new streaming or datagram socket connected to the target host
    183      * specified by the parameters {@code hostName} and {@code port}. The socket
    184      * is bound to any available port on the local host.
    185      *
    186      * <p>This implementation tries each IP address for the given hostname (in
    187      * <a href="http://www.ietf.org/rfc/rfc3484.txt">RFC 3484</a> order)
    188      * until it either connects successfully or it exhausts the set.
    189      *
    190      * @param hostName
    191      *            the target host name or IP address to connect to.
    192      * @param port
    193      *            the port on the target host to connect to.
    194      * @param streaming
    195      *            if {@code true} a streaming socket is returned, a datagram
    196      *            socket otherwise.
    197      * @throws UnknownHostException
    198      *             if the host name could not be resolved into an IP address.
    199      * @throws IOException
    200      *             if an error occurs while creating the socket.
    201      * @deprecated Use {@code Socket(String, int)} instead of this for streaming
    202      *             sockets or an appropriate constructor of {@code
    203      *             DatagramSocket} for UDP transport.
    204      */
    205     @Deprecated
    206     public Socket(String hostName, int port, boolean streaming) throws IOException {
    207         this();
    208         tryAllAddresses(hostName, port, null, 0, streaming);
    209     }
    210 
    211     /**
    212      * Creates a new streaming socket connected to the target host specified by
    213      * the parameters {@code dstAddress} and {@code dstPort}. The socket is
    214      * bound to any available port on the local host.
    215      *
    216      * @param dstAddress
    217      *            the target host address to connect to.
    218      * @param dstPort
    219      *            the port on the target host to connect to.
    220      * @throws IOException
    221      *             if an error occurs while creating the socket.
    222      */
    223     public Socket(InetAddress dstAddress, int dstPort) throws IOException {
    224         this();
    225         checkDestination(dstAddress, dstPort);
    226         startupSocket(dstAddress, dstPort, null, 0, true);
    227     }
    228 
    229     /**
    230      * Creates a new streaming socket connected to the target host specified by
    231      * the parameters {@code dstAddress} and {@code dstPort}. On the local
    232      * endpoint the socket is bound to the given address {@code localAddress} on
    233      * port {@code localPort}.
    234      *
    235      * @param dstAddress
    236      *            the target host address to connect to.
    237      * @param dstPort
    238      *            the port on the target host to connect to.
    239      * @param localAddress
    240      *            the address on the local host to bind to.
    241      * @param localPort
    242      *            the port on the local host to bind to.
    243      * @throws IOException
    244      *             if an error occurs while creating the socket.
    245      */
    246     public Socket(InetAddress dstAddress, int dstPort,
    247             InetAddress localAddress, int localPort) throws IOException {
    248         this();
    249         checkDestination(dstAddress, dstPort);
    250         startupSocket(dstAddress, dstPort, localAddress, localPort, true);
    251     }
    252 
    253     /**
    254      * Creates a new streaming or datagram socket connected to the target host
    255      * specified by the parameters {@code addr} and {@code port}. The socket is
    256      * bound to any available port on the local host.
    257      *
    258      * @param addr
    259      *            the Internet address to connect to.
    260      * @param port
    261      *            the port on the target host to connect to.
    262      * @param streaming
    263      *            if {@code true} a streaming socket is returned, a datagram
    264      *            socket otherwise.
    265      * @throws IOException
    266      *             if an error occurs while creating the socket.
    267      * @deprecated Use {@code Socket(InetAddress, int)} instead of this for
    268      *             streaming sockets or an appropriate constructor of {@code
    269      *             DatagramSocket} for UDP transport.
    270      */
    271     @Deprecated
    272     public Socket(InetAddress addr, int port, boolean streaming) throws IOException {
    273         this();
    274         checkDestination(addr, port);
    275         startupSocket(addr, port, null, 0, streaming);
    276     }
    277 
    278     /**
    279      * Creates an unconnected socket with the given socket implementation.
    280      *
    281      * @param impl
    282      *            the socket implementation to be used.
    283      * @throws SocketException
    284      *             if an error occurs while creating the socket.
    285      */
    286     protected Socket(SocketImpl impl) throws SocketException {
    287         this.impl = impl;
    288         this.proxy = null;
    289     }
    290 
    291     /**
    292      * Checks whether the connection destination satisfies the security policy
    293      * and the validity of the port range.
    294      *
    295      * @param destAddr
    296      *            the destination host address.
    297      * @param dstPort
    298      *            the port on the destination host.
    299      */
    300     private void checkDestination(InetAddress destAddr, int dstPort) {
    301         if (dstPort < 0 || dstPort > 65535) {
    302             throw new IllegalArgumentException("Port out of range: " + dstPort);
    303         }
    304     }
    305 
    306     /**
    307      * Closes the socket. It is not possible to reconnect or rebind to this
    308      * socket thereafter which means a new socket instance has to be created.
    309      *
    310      * @throws IOException
    311      *             if an error occurs while closing the socket.
    312      */
    313     public synchronized void close() throws IOException {
    314         isClosed = true;
    315         isConnected = false;
    316         // RI compatibility: the RI returns the any address (but the original local port) after
    317         // close.
    318         localAddress = Inet4Address.ANY;
    319         impl.close();
    320     }
    321 
    322     /**
    323      * Sets the Socket and its related SocketImpl state as if a successful close() took place,
    324      * without actually performing an OS close().
    325      *
    326      * @hide used in java.nio
    327      */
    328     public void onClose() {
    329         isClosed = true;
    330         isConnected = false;
    331         // RI compatibility: the RI returns the any address (but the original local port) after
    332         // close.
    333         localAddress = Inet4Address.ANY;
    334         impl.onClose();
    335     }
    336 
    337     /**
    338      * Returns the IP address of the target host this socket is connected to, or null if this
    339      * socket is not yet connected.
    340      */
    341     public InetAddress getInetAddress() {
    342         if (!isConnected()) {
    343             return null;
    344         }
    345         return impl.getInetAddress();
    346     }
    347 
    348     /**
    349      * Returns an input stream to read data from this socket. If the socket has an associated
    350      * {@link SocketChannel} and that channel is in non-blocking mode then reads from the
    351      * stream will throw a {@link java.nio.channels.IllegalBlockingModeException}.
    352      *
    353      * @return the byte-oriented input stream.
    354      * @throws IOException
    355      *             if an error occurs while creating the input stream or the
    356      *             socket is in an invalid state.
    357      */
    358     public InputStream getInputStream() throws IOException {
    359         checkOpenAndCreate(false);
    360         if (isInputShutdown()) {
    361             throw new SocketException("Socket input is shutdown");
    362         }
    363         return impl.getInputStream();
    364     }
    365 
    366     /**
    367      * Returns this socket's {@link SocketOptions#SO_KEEPALIVE} setting.
    368      */
    369     public boolean getKeepAlive() throws SocketException {
    370         checkOpenAndCreate(true);
    371         return (Boolean) impl.getOption(SocketOptions.SO_KEEPALIVE);
    372     }
    373 
    374     /**
    375      * Returns the local IP address this socket is bound to, or an address for which
    376      * {@link InetAddress#isAnyLocalAddress()} returns true if the socket is closed or unbound.
    377      */
    378     public InetAddress getLocalAddress() {
    379         return localAddress;
    380     }
    381 
    382     /**
    383      * Returns the local port this socket is bound to, or -1 if the socket is unbound. If the socket
    384      * has been closed this method will still return the local port the socket was bound to.
    385      */
    386     public int getLocalPort() {
    387         if (!isBound()) {
    388             return -1;
    389         }
    390         return impl.getLocalPort();
    391     }
    392 
    393     /**
    394      * Returns an output stream to write data into this socket. If the socket has an associated
    395      * {@link SocketChannel} and that channel is in non-blocking mode then writes to the
    396      * stream will throw a {@link java.nio.channels.IllegalBlockingModeException}.
    397      *
    398      * @return the byte-oriented output stream.
    399      * @throws IOException
    400      *             if an error occurs while creating the output stream or the
    401      *             socket is in an invalid state.
    402      */
    403     public OutputStream getOutputStream() throws IOException {
    404         checkOpenAndCreate(false);
    405         if (isOutputShutdown()) {
    406             throw new SocketException("Socket output is shutdown");
    407         }
    408         return impl.getOutputStream();
    409     }
    410 
    411     /**
    412      * Returns the port number of the target host this socket is connected to, or 0 if this socket
    413      * is not yet connected.
    414      */
    415     public int getPort() {
    416         if (!isConnected()) {
    417             return 0;
    418         }
    419         return impl.getPort();
    420     }
    421 
    422     /**
    423      * Returns this socket's {@link SocketOptions#SO_LINGER linger} timeout in seconds, or -1
    424      * for no linger (i.e. {@code close} will return immediately).
    425      */
    426     public int getSoLinger() throws SocketException {
    427         checkOpenAndCreate(true);
    428         // The RI explicitly guarantees this idiocy in the SocketOptions.setOption documentation.
    429         Object value = impl.getOption(SocketOptions.SO_LINGER);
    430         if (value instanceof Integer) {
    431             return (Integer) value;
    432         } else {
    433             return -1;
    434         }
    435     }
    436 
    437     /**
    438      * Returns this socket's {@link SocketOptions#SO_RCVBUF receive buffer size}.
    439      */
    440     public synchronized int getReceiveBufferSize() throws SocketException {
    441         checkOpenAndCreate(true);
    442         return (Integer) impl.getOption(SocketOptions.SO_RCVBUF);
    443     }
    444 
    445     /**
    446      * Returns this socket's {@link SocketOptions#SO_SNDBUF send buffer size}.
    447      */
    448     public synchronized int getSendBufferSize() throws SocketException {
    449         checkOpenAndCreate(true);
    450         return (Integer) impl.getOption(SocketOptions.SO_SNDBUF);
    451     }
    452 
    453     /**
    454      * Returns this socket's {@link SocketOptions#SO_TIMEOUT receive timeout}.
    455      */
    456     public synchronized int getSoTimeout() throws SocketException {
    457         checkOpenAndCreate(true);
    458         return (Integer) impl.getOption(SocketOptions.SO_TIMEOUT);
    459     }
    460 
    461     /**
    462      * Returns this socket's {@code SocketOptions#TCP_NODELAY} setting.
    463      */
    464     public boolean getTcpNoDelay() throws SocketException {
    465         checkOpenAndCreate(true);
    466         return (Boolean) impl.getOption(SocketOptions.TCP_NODELAY);
    467     }
    468 
    469     /**
    470      * Sets this socket's {@link SocketOptions#SO_KEEPALIVE} option.
    471      */
    472     public void setKeepAlive(boolean keepAlive) throws SocketException {
    473         if (impl != null) {
    474             checkOpenAndCreate(true);
    475             impl.setOption(SocketOptions.SO_KEEPALIVE, Boolean.valueOf(keepAlive));
    476         }
    477     }
    478 
    479     /**
    480      * Sets the internal factory for creating socket implementations. This may
    481      * only be executed once during the lifetime of the application.
    482      *
    483      * @param fac
    484      *            the socket implementation factory to be set.
    485      * @throws IOException
    486      *             if the factory has been already set.
    487      */
    488     public static synchronized void setSocketImplFactory(SocketImplFactory fac)
    489             throws IOException {
    490         if (factory != null) {
    491             throw new SocketException("Factory already set");
    492         }
    493         factory = fac;
    494     }
    495 
    496     /**
    497      * Sets this socket's {@link SocketOptions#SO_SNDBUF send buffer size}.
    498      */
    499     public synchronized void setSendBufferSize(int size) throws SocketException {
    500         checkOpenAndCreate(true);
    501         if (size < 1) {
    502             throw new IllegalArgumentException("size < 1");
    503         }
    504         impl.setOption(SocketOptions.SO_SNDBUF, Integer.valueOf(size));
    505     }
    506 
    507     /**
    508      * Sets this socket's {@link SocketOptions#SO_RCVBUF receive buffer size}.
    509      */
    510     public synchronized void setReceiveBufferSize(int size) throws SocketException {
    511         checkOpenAndCreate(true);
    512         if (size < 1) {
    513             throw new IllegalArgumentException("size < 1");
    514         }
    515         impl.setOption(SocketOptions.SO_RCVBUF, Integer.valueOf(size));
    516     }
    517 
    518     /**
    519      * Sets this socket's {@link SocketOptions#SO_LINGER linger} timeout in seconds.
    520      * If {@code on} is false, {@code timeout} is irrelevant.
    521      */
    522     public void setSoLinger(boolean on, int timeout) throws SocketException {
    523         checkOpenAndCreate(true);
    524         // The RI explicitly guarantees this idiocy in the SocketOptions.setOption documentation.
    525         if (on && timeout < 0) {
    526             throw new IllegalArgumentException("timeout < 0");
    527         }
    528         if (on) {
    529             impl.setOption(SocketOptions.SO_LINGER, Integer.valueOf(timeout));
    530         } else {
    531             impl.setOption(SocketOptions.SO_LINGER, Boolean.FALSE);
    532         }
    533     }
    534 
    535     /**
    536      * Sets this socket's {@link SocketOptions#SO_TIMEOUT read timeout} in milliseconds.
    537      * Use 0 for no timeout.
    538      * To take effect, this option must be set before the blocking method was called.
    539      */
    540     public synchronized void setSoTimeout(int timeout) throws SocketException {
    541         checkOpenAndCreate(true);
    542         if (timeout < 0) {
    543             throw new IllegalArgumentException("timeout < 0");
    544         }
    545         impl.setOption(SocketOptions.SO_TIMEOUT, Integer.valueOf(timeout));
    546     }
    547 
    548     /**
    549      * Sets this socket's {@link SocketOptions#TCP_NODELAY} option.
    550      */
    551     public void setTcpNoDelay(boolean on) throws SocketException {
    552         checkOpenAndCreate(true);
    553         impl.setOption(SocketOptions.TCP_NODELAY, Boolean.valueOf(on));
    554     }
    555 
    556     /**
    557      * Creates a stream socket, binds it to the nominated local address/port,
    558      * then connects it to the nominated destination address/port.
    559      *
    560      * @param dstAddress
    561      *            the destination host address.
    562      * @param dstPort
    563      *            the port on the destination host.
    564      * @param localAddress
    565      *            the address on the local machine to bind.
    566      * @param localPort
    567      *            the port on the local machine to bind.
    568      * @throws IOException
    569      *             thrown if an error occurs during the bind or connect
    570      *             operations.
    571      */
    572     private void startupSocket(InetAddress dstAddress, int dstPort,
    573             InetAddress localAddress, int localPort, boolean streaming)
    574             throws IOException {
    575 
    576         if (localPort < 0 || localPort > 65535) {
    577             throw new IllegalArgumentException("Local port out of range: " + localPort);
    578         }
    579 
    580         InetAddress addr = localAddress == null ? Inet4Address.ANY : localAddress;
    581         synchronized (this) {
    582             impl.create(streaming);
    583             isCreated = true;
    584             try {
    585                 if (!streaming || !usingSocks()) {
    586                     impl.bind(addr, localPort);
    587                 }
    588                 isBound = true;
    589                 cacheLocalAddress();
    590                 impl.connect(dstAddress, dstPort);
    591                 isConnected = true;
    592                 cacheLocalAddress();
    593             } catch (IOException e) {
    594                 impl.close();
    595                 throw e;
    596             }
    597         }
    598     }
    599 
    600     private boolean usingSocks() {
    601         return proxy != null && proxy.type() == Proxy.Type.SOCKS;
    602     }
    603 
    604     /**
    605      * Returns a {@code String} containing a concise, human-readable description of the
    606      * socket.
    607      *
    608      * @return the textual representation of this socket.
    609      */
    610     @Override
    611     public String toString() {
    612         if (!isConnected()) {
    613             return "Socket[unconnected]";
    614         }
    615         return impl.toString();
    616     }
    617 
    618     /**
    619      * Closes the input stream of this socket. Any further data sent to this
    620      * socket will be discarded. Reading from this socket after this method has
    621      * been called will return the value {@code EOF}.
    622      *
    623      * @throws IOException
    624      *             if an error occurs while closing the socket input stream.
    625      * @throws SocketException
    626      *             if the input stream is already closed.
    627      */
    628     public void shutdownInput() throws IOException {
    629         if (isInputShutdown()) {
    630             throw new SocketException("Socket input is shutdown");
    631         }
    632         checkOpenAndCreate(false);
    633         impl.shutdownInput();
    634         isInputShutdown = true;
    635     }
    636 
    637     /**
    638      * Closes the output stream of this socket. All buffered data will be sent
    639      * followed by the termination sequence. Writing to the closed output stream
    640      * will cause an {@code IOException}.
    641      *
    642      * @throws IOException
    643      *             if an error occurs while closing the socket output stream.
    644      * @throws SocketException
    645      *             if the output stream is already closed.
    646      */
    647     public void shutdownOutput() throws IOException {
    648         if (isOutputShutdown()) {
    649             throw new SocketException("Socket output is shutdown");
    650         }
    651         checkOpenAndCreate(false);
    652         impl.shutdownOutput();
    653         isOutputShutdown = true;
    654     }
    655 
    656     /**
    657      * Checks whether the socket is closed, and throws an exception. Otherwise
    658      * creates the underlying SocketImpl.
    659      *
    660      * @throws SocketException
    661      *             if the socket is closed.
    662      */
    663     private void checkOpenAndCreate(boolean create) throws SocketException {
    664         if (isClosed()) {
    665             throw new SocketException("Socket is closed");
    666         }
    667         if (!create) {
    668             if (!isConnected()) {
    669                 throw new SocketException("Socket is not connected");
    670                 // a connected socket must be created
    671             }
    672 
    673             /*
    674              * return directly to fix a possible bug, if !create, should return
    675              * here
    676              */
    677             return;
    678         }
    679         if (isCreated) {
    680             return;
    681         }
    682         synchronized (this) {
    683             if (isCreated) {
    684                 return;
    685             }
    686             try {
    687                 impl.create(true);
    688             } catch (SocketException e) {
    689                 throw e;
    690             } catch (IOException e) {
    691                 throw new SocketException(e.toString());
    692             }
    693             isCreated = true;
    694         }
    695     }
    696 
    697     /**
    698      * Returns the local address and port of this socket as a SocketAddress or null if the socket
    699      * has never been bound. If the socket is closed but has previously been bound then an address
    700      * for which {@link InetAddress#isAnyLocalAddress()} returns true will be returned with the
    701      * previously-bound port. This is useful on multihomed hosts.
    702      */
    703     public SocketAddress getLocalSocketAddress() {
    704         if (!isBound()) {
    705             return null;
    706         }
    707         return new InetSocketAddress(getLocalAddress(), getLocalPort());
    708     }
    709 
    710     /**
    711      * Returns the remote address and port of this socket as a {@code
    712      * SocketAddress} or null if the socket is not connected.
    713      *
    714      * @return the remote socket address and port.
    715      */
    716     public SocketAddress getRemoteSocketAddress() {
    717         if (!isConnected()) {
    718             return null;
    719         }
    720         return new InetSocketAddress(getInetAddress(), getPort());
    721     }
    722 
    723     /**
    724      * Returns whether this socket is bound to a local address and port.
    725      *
    726      * @return {@code true} if the socket is bound to a local address, {@code
    727      *         false} otherwise.
    728      */
    729     public boolean isBound() {
    730         return isBound;
    731     }
    732 
    733     /**
    734      * Returns whether this socket is connected to a remote host.
    735      *
    736      * @return {@code true} if the socket is connected, {@code false} otherwise.
    737      */
    738     public boolean isConnected() {
    739         return isConnected;
    740     }
    741 
    742     /**
    743      * Returns whether this socket is closed.
    744      *
    745      * @return {@code true} if the socket is closed, {@code false} otherwise.
    746      */
    747     public boolean isClosed() {
    748         return isClosed;
    749     }
    750 
    751     /**
    752      * Binds this socket to the given local host address and port specified by
    753      * the SocketAddress {@code localAddr}. If {@code localAddr} is set to
    754      * {@code null}, this socket will be bound to an available local address on
    755      * any free port.
    756      *
    757      * @param localAddr
    758      *            the specific address and port on the local machine to bind to.
    759      * @throws IllegalArgumentException
    760      *             if the given SocketAddress is invalid or not supported.
    761      * @throws IOException
    762      *             if the socket is already bound or an error occurs while
    763      *             binding.
    764      */
    765     public void bind(SocketAddress localAddr) throws IOException {
    766         checkOpenAndCreate(true);
    767         if (isBound()) {
    768             throw new BindException("Socket is already bound");
    769         }
    770 
    771         int port;
    772         InetAddress addr;
    773         if (localAddr == null) {
    774             port = 0;
    775             addr = Inet4Address.ANY;
    776         } else {
    777             if (!(localAddr instanceof InetSocketAddress)) {
    778                 throw new IllegalArgumentException("Local address not an InetSocketAddress: " +
    779                         localAddr.getClass());
    780             }
    781             InetSocketAddress inetAddr = (InetSocketAddress) localAddr;
    782             if ((addr = inetAddr.getAddress()) == null) {
    783                 throw new UnknownHostException("Host is unresolved: " + inetAddr.getHostName());
    784             }
    785             port = inetAddr.getPort();
    786         }
    787 
    788         synchronized (this) {
    789             try {
    790                 impl.bind(addr, port);
    791                 isBound = true;
    792                 cacheLocalAddress();
    793             } catch (IOException e) {
    794                 impl.close();
    795                 throw e;
    796             }
    797         }
    798     }
    799 
    800     /**
    801      * Sets the Socket and its related SocketImpl state as if a successful bind() took place,
    802      * without actually performing an OS bind().
    803      *
    804      * @hide used in java.nio
    805      */
    806     public void onBind(InetAddress localAddress, int localPort) {
    807         isBound = true;
    808         this.localAddress = localAddress;
    809         impl.onBind(localAddress, localPort);
    810     }
    811 
    812     /**
    813      * Connects this socket to the given remote host address and port specified
    814      * by the SocketAddress {@code remoteAddr}.
    815      *
    816      * @param remoteAddr
    817      *            the address and port of the remote host to connect to.
    818      * @throws IllegalArgumentException
    819      *             if the given SocketAddress is invalid or not supported.
    820      * @throws IOException
    821      *             if the socket is already connected or an error occurs while
    822      *             connecting.
    823      */
    824     public void connect(SocketAddress remoteAddr) throws IOException {
    825         connect(remoteAddr, 0);
    826     }
    827 
    828     /**
    829      * Connects this socket to the given remote host address and port specified
    830      * by the SocketAddress {@code remoteAddr} with the specified timeout. The
    831      * connecting method will block until the connection is established or an
    832      * error occurred.
    833      *
    834      * @param remoteAddr
    835      *            the address and port of the remote host to connect to.
    836      * @param timeout
    837      *            the timeout value in milliseconds or {@code 0} for an infinite
    838      *            timeout.
    839      * @throws IllegalArgumentException
    840      *             if the given SocketAddress is invalid or not supported or the
    841      *             timeout value is negative.
    842      * @throws IOException
    843      *             if the socket is already connected or an error occurs while
    844      *             connecting.
    845      */
    846     public void connect(SocketAddress remoteAddr, int timeout) throws IOException {
    847         checkOpenAndCreate(true);
    848         if (timeout < 0) {
    849             throw new IllegalArgumentException("timeout < 0");
    850         }
    851         if (isConnected()) {
    852             throw new SocketException("Already connected");
    853         }
    854         if (remoteAddr == null) {
    855             throw new IllegalArgumentException("remoteAddr == null");
    856         }
    857 
    858         if (!(remoteAddr instanceof InetSocketAddress)) {
    859             throw new IllegalArgumentException("Remote address not an InetSocketAddress: " +
    860                     remoteAddr.getClass());
    861         }
    862         InetSocketAddress inetAddr = (InetSocketAddress) remoteAddr;
    863         InetAddress addr;
    864         if ((addr = inetAddr.getAddress()) == null) {
    865             throw new UnknownHostException("Host is unresolved: " + inetAddr.getHostName());
    866         }
    867         int port = inetAddr.getPort();
    868 
    869         checkDestination(addr, port);
    870         synchronized (connectLock) {
    871             try {
    872                 if (!isBound()) {
    873                     // socket already created at this point by earlier call or
    874                     // checkOpenAndCreate this caused us to lose socket
    875                     // options on create
    876                     // impl.create(true);
    877                     if (!usingSocks()) {
    878                         impl.bind(Inet4Address.ANY, 0);
    879                     }
    880                     isBound = true;
    881                 }
    882                 impl.connect(remoteAddr, timeout);
    883                 isConnected = true;
    884                 cacheLocalAddress();
    885             } catch (IOException e) {
    886                 impl.close();
    887                 throw e;
    888             }
    889         }
    890     }
    891 
    892     /**
    893      * Sets the Socket and its related SocketImpl state as if a successful connect() took place,
    894      * without actually performing an OS connect().
    895      *
    896      * @hide internal use only
    897      */
    898     public void onConnect(InetAddress remoteAddress, int remotePort) {
    899         isConnected = true;
    900         impl.onConnect(remoteAddress, remotePort);
    901     }
    902 
    903     /**
    904      * Returns whether the incoming channel of the socket has already been
    905      * closed.
    906      *
    907      * @return {@code true} if reading from this socket is not possible anymore,
    908      *         {@code false} otherwise.
    909      */
    910     public boolean isInputShutdown() {
    911         return isInputShutdown;
    912     }
    913 
    914     /**
    915      * Returns whether the outgoing channel of the socket has already been
    916      * closed.
    917      *
    918      * @return {@code true} if writing to this socket is not possible anymore,
    919      *         {@code false} otherwise.
    920      */
    921     public boolean isOutputShutdown() {
    922         return isOutputShutdown;
    923     }
    924 
    925     /**
    926      * Sets this socket's {@link SocketOptions#SO_REUSEADDR} option.
    927      */
    928     public void setReuseAddress(boolean reuse) throws SocketException {
    929         checkOpenAndCreate(true);
    930         impl.setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(reuse));
    931     }
    932 
    933     /**
    934      * Returns this socket's {@link SocketOptions#SO_REUSEADDR} setting.
    935      */
    936     public boolean getReuseAddress() throws SocketException {
    937         checkOpenAndCreate(true);
    938         return (Boolean) impl.getOption(SocketOptions.SO_REUSEADDR);
    939     }
    940 
    941     /**
    942      * Sets this socket's {@link SocketOptions#SO_OOBINLINE} option.
    943      */
    944     public void setOOBInline(boolean oobinline) throws SocketException {
    945         checkOpenAndCreate(true);
    946         impl.setOption(SocketOptions.SO_OOBINLINE, Boolean.valueOf(oobinline));
    947     }
    948 
    949     /**
    950      * Returns this socket's {@link SocketOptions#SO_OOBINLINE} setting.
    951      */
    952     public boolean getOOBInline() throws SocketException {
    953         checkOpenAndCreate(true);
    954         return (Boolean) impl.getOption(SocketOptions.SO_OOBINLINE);
    955     }
    956 
    957     /**
    958      * Sets this socket's {@link SocketOptions#IP_TOS} value for every packet sent by this socket.
    959      */
    960     public void setTrafficClass(int value) throws SocketException {
    961         checkOpenAndCreate(true);
    962         if (value < 0 || value > 255) {
    963             throw new IllegalArgumentException("Value doesn't fit in an unsigned byte: " + value);
    964         }
    965         impl.setOption(SocketOptions.IP_TOS, Integer.valueOf(value));
    966     }
    967 
    968     /**
    969      * Returns this socket's {@see SocketOptions#IP_TOS} setting.
    970      */
    971     public int getTrafficClass() throws SocketException {
    972         checkOpenAndCreate(true);
    973         return (Integer) impl.getOption(SocketOptions.IP_TOS);
    974     }
    975 
    976     /**
    977      * Sends the given single byte data which is represented by the lowest octet
    978      * of {@code value} as "TCP urgent data".
    979      *
    980      * @param value
    981      *            the byte of urgent data to be sent.
    982      * @throws IOException
    983      *             if an error occurs while sending urgent data.
    984      */
    985     public void sendUrgentData(int value) throws IOException {
    986         impl.sendUrgentData(value);
    987     }
    988 
    989     /**
    990      * Set the appropriate flags for a socket created by {@code
    991      * ServerSocket.accept()}.
    992      *
    993      * @see ServerSocket#implAccept
    994      */
    995     void accepted() throws SocketException {
    996         isCreated = isBound = isConnected = true;
    997         cacheLocalAddress();
    998     }
    999 
   1000     private void cacheLocalAddress() throws SocketException {
   1001         this.localAddress = IoBridge.getSocketLocalAddress(impl.fd);
   1002     }
   1003 
   1004     /**
   1005      * Returns this socket's {@code SocketChannel}, if one exists. A channel is
   1006      * available only if this socket wraps a channel. (That is, you can go from a
   1007      * channel to a socket and back again, but you can't go from an arbitrary socket to a channel.)
   1008      * In practice, this means that the socket must have been created by
   1009      * {@link java.nio.channels.ServerSocketChannel#accept} or
   1010      * {@link java.nio.channels.SocketChannel#open}.
   1011      */
   1012     public SocketChannel getChannel() {
   1013         return null;
   1014     }
   1015 
   1016     /**
   1017      * @hide internal use only
   1018      */
   1019     public FileDescriptor getFileDescriptor$() {
   1020         return impl.fd;
   1021     }
   1022 
   1023     /**
   1024      * Sets performance preferences for connectionTime, latency and bandwidth.
   1025      *
   1026      * <p>This method does currently nothing.
   1027      *
   1028      * @param connectionTime
   1029      *            the value representing the importance of a short connecting
   1030      *            time.
   1031      * @param latency
   1032      *            the value representing the importance of low latency.
   1033      * @param bandwidth
   1034      *            the value representing the importance of high bandwidth.
   1035      */
   1036     public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) {
   1037         // Our socket implementation only provide one protocol: TCP/IP, so
   1038         // we do nothing for this method
   1039     }
   1040 }
   1041