1663 lines · 63.5 KB · Java
RawDownload
/* * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package java.net; import java.io.InputStream;import java.io.OutputStream;import java.io.IOException;import java.io.InterruptedIOException;import java.nio.channels.SocketChannel;import java.security.AccessController;import java.security.PrivilegedExceptionAction;import java.security.PrivilegedAction; /** * This class implements client sockets (also called just * "sockets"). A socket is an endpoint for communication * between two machines. * <p> * The actual work of the socket is performed by an instance of the * <code>SocketImpl</code> class. An application, by changing * the socket factory that creates the socket implementation, * can configure itself to create sockets appropriate to the local * firewall. * * @author  unascribed * @see     java.net.Socket#setSocketImplFactory(java.net.SocketImplFactory) * @see     java.net.SocketImpl * @see     java.nio.channels.SocketChannel * @since   JDK1.0 */publicclass Socket implements java.io.Closeable {    /**     * Various states of this socket.     */    private boolean created = false;    private boolean bound = false;    private boolean connected = false;    private boolean closed = false;    private Object closeLock = new Object();    private boolean shutIn = false;    private boolean shutOut = false;     /**     * The implementation of this Socket.     */    SocketImpl impl;     /**     * Are we using an older SocketImpl?     */    private boolean oldImpl = false;     /**     * Creates an unconnected socket, with the     * system-default type of SocketImpl.     *     * @since   JDK1.1     * @revised 1.4     */    public Socket() {        setImpl();    }     /**     * Creates an unconnected socket, specifying the type of proxy, if any,     * that should be used regardless of any other settings.     * <P>     * If there is a security manager, its <code>checkConnect</code> method     * is called with the proxy host address and port number     * as its arguments. This could result in a SecurityException.     * <P>     * Examples:     * <UL> <LI><code>Socket s = new Socket(Proxy.NO_PROXY);</code> will create     * a plain socket ignoring any other proxy configuration.</LI>     * <LI><code>Socket s = new Socket(new Proxy(Proxy.Type.SOCKS, new InetSocketAddress("socks.mydom.com", 1080)));</code>     * will create a socket connecting through the specified SOCKS proxy     * server.</LI>     * </UL>     *     * @param proxy a {@link java.net.Proxy Proxy} object specifying what kind     *              of proxying should be used.     * @throws IllegalArgumentException if the proxy is of an invalid type     *          or <code>null</code>.     * @throws SecurityException if a security manager is present and     *                           permission to connect to the proxy is     *                           denied.     * @see java.net.ProxySelector     * @see java.net.Proxy     *     * @since   1.5     */    public Socket(Proxy proxy) {        // Create a copy of Proxy as a security measure        if (proxy == null) {            throw new IllegalArgumentException("Invalid Proxy");        }        Proxy p = proxy == Proxy.NO_PROXY ? Proxy.NO_PROXY : sun.net.ApplicationProxy.create(proxy);        if (p.type() == Proxy.Type.SOCKS) {            SecurityManager security = System.getSecurityManager();            InetSocketAddress epoint = (InetSocketAddress) p.address();            if (epoint.getAddress() != null) {                checkAddress (epoint.getAddress(), "Socket");            }            if (security != null) {                if (epoint.isUnresolved())                    epoint = new InetSocketAddress(epoint.getHostName(), epoint.getPort());                if (epoint.isUnresolved())                    security.checkConnect(epoint.getHostName(), epoint.getPort());                else                    security.checkConnect(epoint.getAddress().getHostAddress(),                                  epoint.getPort());            }            impl = new SocksSocketImpl(p);            impl.setSocket(this);        } else {            if (p == Proxy.NO_PROXY) {                if (factory == null) {                    impl = new PlainSocketImpl();                    impl.setSocket(this);                } else                    setImpl();            } else                throw new IllegalArgumentException("Invalid Proxy");        }    }     /**     * Creates an unconnected Socket with a user-specified     * SocketImpl.     * <P>     * @param impl an instance of a <B>SocketImpl</B>     * the subclass wishes to use on the Socket.     *     * @exception SocketException if there is an error in the underlying protocol,     * such as a TCP error.     * @since   JDK1.1     */    protected Socket(SocketImpl impl) throws SocketException {        this.impl = impl;        if (impl != null) {            checkOldImpl();            this.impl.setSocket(this);        }    }     /**     * Creates a stream socket and connects it to the specified port     * number on the named host.     * <p>     * If the specified host is <tt>null</tt> it is the equivalent of     * specifying the address as <tt>{@link java.net.InetAddress#getByName InetAddress.getByName}(null)</tt>.     * In other words, it is equivalent to specifying an address of the     * loopback interface. </p>     * <p>     * If the application has specified a server socket factory, that     * factory's <code>createSocketImpl</code> method is called to create     * the actual socket implementation. Otherwise a "plain" socket is created.     * <p>     * If there is a security manager, its     * <code>checkConnect</code> method is called     * with the host address and <code>port</code>     * as its arguments. This could result in a SecurityException.     *     * @param      host   the host name, or <code>null</code> for the loopback address.     * @param      port   the port number.     *     * @exception  UnknownHostException if the IP address of     * the host could not be determined.     *     * @exception  IOException  if an I/O error occurs when creating the socket.     * @exception  SecurityException  if a security manager exists and its     *             <code>checkConnect</code> method doesn't allow the operation.     * @exception  IllegalArgumentException if the port parameter is outside     *             the specified range of valid port values, which is between     *             0 and 65535, inclusive.     * @see        java.net.Socket#setSocketImplFactory(java.net.SocketImplFactory)     * @see        java.net.SocketImpl     * @see        java.net.SocketImplFactory#createSocketImpl()     * @see        SecurityManager#checkConnect     */    public Socket(String host, int port)        throws UnknownHostException, IOException    {        this(host != null ? new InetSocketAddress(host, port) :             new InetSocketAddress(InetAddress.getByName(null), port),             (SocketAddress) null, true);    }     /**     * Creates a stream socket and connects it to the specified port     * number at the specified IP address.     * <p>     * If the application has specified a socket factory, that factory's     * <code>createSocketImpl</code> method is called to create the     * actual socket implementation. Otherwise a "plain" socket is created.     * <p>     * If there is a security manager, its     * <code>checkConnect</code> method is called     * with the host address and <code>port</code>     * as its arguments. This could result in a SecurityException.     *     * @param      address   the IP address.     * @param      port      the port number.     * @exception  IOException  if an I/O error occurs when creating the socket.     * @exception  SecurityException  if a security manager exists and its     *             <code>checkConnect</code> method doesn't allow the operation.     * @exception  IllegalArgumentException if the port parameter is outside     *             the specified range of valid port values, which is between     *             0 and 65535, inclusive.     * @exception  NullPointerException if <code>address</code> is null.     * @see        java.net.Socket#setSocketImplFactory(java.net.SocketImplFactory)     * @see        java.net.SocketImpl     * @see        java.net.SocketImplFactory#createSocketImpl()     * @see        SecurityManager#checkConnect     */    public Socket(InetAddress address, int port) throws IOException {        this(address != null ? new InetSocketAddress(address, port) : null,             (SocketAddress) null, true);    }     /**     * Creates a socket and connects it to the specified remote host on     * the specified remote port. The Socket will also bind() to the local     * address and port supplied.     * <p>     * If the specified host is <tt>null</tt> it is the equivalent of     * specifying the address as <tt>{@link java.net.InetAddress#getByName InetAddress.getByName}(null)</tt>.     * In other words, it is equivalent to specifying an address of the     * loopback interface. </p>     * <p>     * A local port number of <code>zero</code> will let the system pick up a     * free port in the <code>bind</code> operation.</p>     * <p>     * If there is a security manager, its     * <code>checkConnect</code> method is called     * with the host address and <code>port</code>     * as its arguments. This could result in a SecurityException.     *     * @param host the name of the remote host, or <code>null</code> for the loopback address.     * @param port the remote port     * @param localAddr the local address the socket is bound to, or     *        <code>null</code> for the <code>anyLocal</code> address.     * @param localPort the local port the socket is bound to, or     *        <code>zero</code> for a system selected free port.     * @exception  IOException  if an I/O error occurs when creating the socket.     * @exception  SecurityException  if a security manager exists and its     *             <code>checkConnect</code> method doesn't allow the operation.     * @exception  IllegalArgumentException if the port parameter or localPort     *             parameter is outside the specified range of valid port values,     *             which is between 0 and 65535, inclusive.     * @see        SecurityManager#checkConnect     * @since   JDK1.1     */    public Socket(String host, int port, InetAddress localAddr,                  int localPort) throws IOException {        this(host != null ? new InetSocketAddress(host, port) :               new InetSocketAddress(InetAddress.getByName(null), port),             new InetSocketAddress(localAddr, localPort), true);    }     /**     * Creates a socket and connects it to the specified remote address on     * the specified remote port. The Socket will also bind() to the local     * address and port supplied.     * <p>     * If the specified local address is <tt>null</tt> it is the equivalent of     * specifying the address as the AnyLocal address (see <tt>{@link java.net.InetAddress#isAnyLocalAddress InetAddress.isAnyLocalAddress}()</tt>).     * <p>     * A local port number of <code>zero</code> will let the system pick up a     * free port in the <code>bind</code> operation.</p>     * <p>     * If there is a security manager, its     * <code>checkConnect</code> method is called     * with the host address and <code>port</code>     * as its arguments. This could result in a SecurityException.     *     * @param address the remote address     * @param port the remote port     * @param localAddr the local address the socket is bound to, or     *        <code>null</code> for the <code>anyLocal</code> address.     * @param localPort the local port the socket is bound to or     *        <code>zero</code> for a system selected free port.     * @exception  IOException  if an I/O error occurs when creating the socket.     * @exception  SecurityException  if a security manager exists and its     *             <code>checkConnect</code> method doesn't allow the operation.     * @exception  IllegalArgumentException if the port parameter or localPort     *             parameter is outside the specified range of valid port values,     *             which is between 0 and 65535, inclusive.     * @exception  NullPointerException if <code>address</code> is null.     * @see        SecurityManager#checkConnect     * @since   JDK1.1     */    public Socket(InetAddress address, int port, InetAddress localAddr,                  int localPort) throws IOException {        this(address != null ? new InetSocketAddress(address, port) : null,             new InetSocketAddress(localAddr, localPort), true);    }     /**     * Creates a stream socket and connects it to the specified port     * number on the named host.     * <p>     * If the specified host is <tt>null</tt> it is the equivalent of     * specifying the address as <tt>{@link java.net.InetAddress#getByName InetAddress.getByName}(null)</tt>.     * In other words, it is equivalent to specifying an address of the     * loopback interface. </p>     * <p>     * If the stream argument is <code>true</code>, this creates a     * stream socket. If the stream argument is <code>false</code>, it     * creates a datagram socket.     * <p>     * If the application has specified a server socket factory, that     * factory's <code>createSocketImpl</code> method is called to create     * the actual socket implementation. Otherwise a "plain" socket is created.     * <p>     * If there is a security manager, its     * <code>checkConnect</code> method is called     * with the host address and <code>port</code>     * as its arguments. This could result in a SecurityException.     * <p>     * If a UDP socket is used, TCP/IP related socket options will not apply.     *     * @param      host     the host name, or <code>null</code> for the loopback address.     * @param      port     the port number.     * @param      stream   a <code>boolean</code> indicating whether this is     *                      a stream socket or a datagram socket.     * @exception  IOException  if an I/O error occurs when creating the socket.     * @exception  SecurityException  if a security manager exists and its     *             <code>checkConnect</code> method doesn't allow the operation.     * @exception  IllegalArgumentException if the port parameter is outside     *             the specified range of valid port values, which is between     *             0 and 65535, inclusive.     * @see        java.net.Socket#setSocketImplFactory(java.net.SocketImplFactory)     * @see        java.net.SocketImpl     * @see        java.net.SocketImplFactory#createSocketImpl()     * @see        SecurityManager#checkConnect     * @deprecated Use DatagramSocket instead for UDP transport.     */    @Deprecated    public Socket(String host, int port, boolean stream) throws IOException {        this(host != null ? new InetSocketAddress(host, port) :               new InetSocketAddress(InetAddress.getByName(null), port),             (SocketAddress) null, stream);    }     /**     * Creates a socket and connects it to the specified port number at     * the specified IP address.     * <p>     * If the stream argument is <code>true</code>, this creates a     * stream socket. If the stream argument is <code>false</code>, it     * creates a datagram socket.     * <p>     * If the application has specified a server socket factory, that     * factory's <code>createSocketImpl</code> method is called to create     * the actual socket implementation. Otherwise a "plain" socket is created.     *     * <p>If there is a security manager, its     * <code>checkConnect</code> method is called     * with <code>host.getHostAddress()</code> and <code>port</code>     * as its arguments. This could result in a SecurityException.     * <p>     * If UDP socket is used, TCP/IP related socket options will not apply.     *     * @param      host     the IP address.     * @param      port      the port number.     * @param      stream    if <code>true</code>, create a stream socket;     *                       otherwise, create a datagram socket.     * @exception  IOException  if an I/O error occurs when creating the socket.     * @exception  SecurityException  if a security manager exists and its     *             <code>checkConnect</code> method doesn't allow the operation.     * @exception  IllegalArgumentException if the port parameter is outside     *             the specified range of valid port values, which is between     *             0 and 65535, inclusive.     * @exception  NullPointerException if <code>host</code> is null.     * @see        java.net.Socket#setSocketImplFactory(java.net.SocketImplFactory)     * @see        java.net.SocketImpl     * @see        java.net.SocketImplFactory#createSocketImpl()     * @see        SecurityManager#checkConnect     * @deprecated Use DatagramSocket instead for UDP transport.     */    @Deprecated    public Socket(InetAddress host, int port, boolean stream) throws IOException {        this(host != null ? new InetSocketAddress(host, port) : null,             new InetSocketAddress(0), stream);    }     private Socket(SocketAddress address, SocketAddress localAddr,                   boolean stream) throws IOException {        setImpl();         // backward compatibility        if (address == null)            throw new NullPointerException();         try {            createImpl(stream);            if (localAddr != null)                bind(localAddr);            if (address != null)                connect(address);        } catch (IOException e) {            close();            throw e;        }    }     /**     * Creates the socket implementation.     *     * @param stream a <code>boolean</code> value : <code>true</code> for a TCP socket,     *               <code>false</code> for UDP.     * @throws IOException if creation fails     * @since 1.4     */     void createImpl(boolean stream) throws SocketException {        if (impl == null)            setImpl();        try {            impl.create(stream);            created = true;        } catch (IOException e) {            throw new SocketException(e.getMessage());        }    }     private void checkOldImpl() {        if (impl == null)            return;        // SocketImpl.connect() is a protected method, therefore we need to use        // getDeclaredMethod, therefore we need permission to access the member         oldImpl = AccessController.doPrivileged                                (new PrivilegedAction<Boolean>() {            public Boolean run() {                Class[] cl = new Class[2];                cl[0] = SocketAddress.class;                cl[1] = Integer.TYPE;                Class clazz = impl.getClass();                while (true) {                    try {                        clazz.getDeclaredMethod("connect", cl);                        return Boolean.FALSE;                    } catch (NoSuchMethodException e) {                        clazz = clazz.getSuperclass();                        // java.net.SocketImpl class will always have this abstract method.                        // If we have not found it by now in the hierarchy then it does not                        // exist, we are an old style impl.                        if (clazz.equals(java.net.SocketImpl.class)) {                            return Boolean.TRUE;                        }                    }                }            }        });    }     /**     * Sets impl to the system-default type of SocketImpl.     * @since 1.4     */    void setImpl() {        if (factory != null) {            impl = factory.createSocketImpl();            checkOldImpl();        } else {            // No need to do a checkOldImpl() here, we know it's an up to date            // SocketImpl!            impl = new SocksSocketImpl();        }        if (impl != null)            impl.setSocket(this);    }      /**

Lines 1–500 of 1663.