PageRenderTime 86ms CodeModel.GetById 17ms app.highlight 61ms RepoModel.GetById 1ms app.codeStats 1ms

/luni/src/main/java/java/net/Socket.java

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