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