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