FileDocCategorySizeDatePackage
PlainSocketImpl.javaAPI DocAndroid 1.5 API19426Wed May 06 22:41:04 BST 2009org.apache.harmony.luni.net

PlainSocketImpl

public class PlainSocketImpl extends SocketImpl
A concrete connected-socket implementation.

Fields Summary
static final int
MULTICAST_IF
static final int
MULTICAST_TTL
static final int
TCP_NODELAY
static final int
FLAG_SHUTDOWN
private static InetAddress
lastConnectedAddress
private static int
lastConnectedPort
private static Field
fdField
private static Field
localportField
private boolean
tcpNoDelay
private int
trafficClass
used to store the trafficClass value which is simply returned as the value that was set. We also need it to pass it to methods that specify an address packets are going to be sent to
protected org.apache.harmony.luni.platform.INetworkSystem
netImpl
public int
receiveTimeout
public boolean
streaming
public boolean
shutdownInput
Proxy
proxy
Constructors Summary
public PlainSocketImpl()


      
        super();
        fd = new FileDescriptor();
    
Methods Summary
protected voidaccept(java.net.SocketImpl newImpl)

        if (NetUtil.usingSocks(proxy)) {
            ((PlainSocketImpl) newImpl).socksBind();
            ((PlainSocketImpl) newImpl).socksAccept();
            return;
        }

        try {
            if (newImpl instanceof PlainSocketImpl) {
                PlainSocketImpl newPlainSocketImpl = (PlainSocketImpl) newImpl;
                // BEGIN android-changed
                // call accept instead of acceptStreamImpl (native impl is identical)
                netImpl.accept(fd, newImpl, newPlainSocketImpl
                        .getFileDescriptor(), receiveTimeout);
                // END android-changed
                newPlainSocketImpl.setLocalport(getLocalPort());
            } else {
                // if newImpl is not an instance of PlainSocketImpl, use
                // reflection to get/set protected fields.
                if (null == fdField) {
                    fdField = getSocketImplField("fd"); //$NON-NLS-1$
                }
                FileDescriptor newFd = (FileDescriptor) fdField.get(newImpl);
                // BEGIN android-changed
                // call accept instead of acceptStreamImpl (native impl is identical)
                netImpl.accept(fd, newImpl, newFd, receiveTimeout);
                // END android-cahnged

                if (null == localportField) {
                    localportField = getSocketImplField("localport"); //$NON-NLS-1$
                }
                localportField.setInt(newImpl, getLocalPort());
            }
        } catch (InterruptedIOException e) {
            throw new SocketTimeoutException(e.getMessage());
        } catch (IllegalAccessException e) {
            // empty
        }
    
protected synchronized intavailable()

        // we need to check if the input has been shutdown. If so
        // we should return that there is no data to be read
        if (shutdownInput == true) {
            return 0;
        }
        return netImpl.availableStream(fd);
    
protected voidbind(java.net.InetAddress anAddr, int aPort)

        netImpl.bind(fd, aPort, anAddr);
        // PlainSocketImpl2.socketBindImpl2(fd, aPort, anAddr);
        address = anAddr;
        if (0 != aPort) {
            localport = aPort;
        } else {
            localport = netImpl.getSocketLocalPort(fd, NetUtil
                    .preferIPv6Addresses());
        }
    
protected voidclose()

        synchronized (fd) {
            if (fd.valid()) {
                if ((netImpl.getSocketFlags() & FLAG_SHUTDOWN) != 0) {
                    try {
                        shutdownOutput();
                    } catch (Exception e) {
                    }
                }
                netImpl.socketClose(fd);
                fd = new FileDescriptor();
            }
        }
    
protected voidconnect(java.net.SocketAddress remoteAddr, int timeout)

        InetSocketAddress inetAddr = (InetSocketAddress) remoteAddr;
        connect(inetAddr.getAddress(), inetAddr.getPort(), timeout);
    
protected voidconnect(java.lang.String aHost, int aPort)

        InetAddress anAddr = netImpl.getHostByName(aHost, NetUtil
                .preferIPv6Addresses());
        connect(anAddr, aPort);
    
protected voidconnect(java.net.InetAddress anAddr, int aPort)

        connect(anAddr, aPort, 0);
    
private voidconnect(java.net.InetAddress anAddr, int aPort, int timeout)
Connects this socket to the specified remote host address/port.

param
anAddr the remote host address to connect to
param
aPort the remote port to connect to
param
timeout a timeout where supported. 0 means no timeout
throws
IOException if an error occurs while connecting

        InetAddress normalAddr = anAddr.isAnyLocalAddress() ? InetAddress
                .getLocalHost() : anAddr;

        try {
            if (streaming) {
                if (NetUtil.usingSocks(proxy)) {
                    socksConnect(anAddr, aPort, 0);
                } else {
                    if (timeout == 0) {
                        netImpl.connect(fd, trafficClass, normalAddr, aPort);
                    } else {
                        netImpl.connectStreamWithTimeoutSocket(fd, aPort,
                                timeout, trafficClass, normalAddr);
                    }
                }
            } else {
                netImpl.connectDatagram(fd, aPort, trafficClass, normalAddr);
            }
        } catch (ConnectException e) {
            throw new ConnectException(anAddr + ":" + aPort + " - "
                    + e.getMessage());
        }
        super.address = normalAddr;
        super.port = aPort;
    
protected voidcreate(boolean streaming)

        this.streaming = streaming;
        if (streaming) {
            // BEGIN android-changed
            // call createSocket instead of createStreamSocket
            netImpl.createSocket(fd, NetUtil.preferIPv4Stack());
            // END android-changed
        } else {
            netImpl.createDatagramSocket(fd, NetUtil.preferIPv4Stack());
        }
    
protected voidfinalize()

        close();
    
java.io.FileDescriptorgetFD()

        return fd;
    
protected synchronized java.io.InputStreamgetInputStream()

        if (!fd.valid()) {
            throw new SocketException(Msg.getString("K003d"));
        }

        return new SocketInputStream(this);
    
public java.lang.ObjectgetOption(int optID)

        if (optID == SocketOptions.SO_TIMEOUT) {
            return Integer.valueOf(receiveTimeout);
        } else if (optID == SocketOptions.IP_TOS) {
            return Integer.valueOf(trafficClass);
        } else {
            // Call the native first so there will be
            // an exception if the socket if closed.
            Object result = netImpl.getSocketOption(fd, optID);
            if (optID == SocketOptions.TCP_NODELAY
                    && (netImpl.getSocketFlags() & TCP_NODELAY) != 0) {
                return Boolean.valueOf(tcpNoDelay);
            }
            return result;
        }
    
protected synchronized java.io.OutputStreamgetOutputStream()

        if (!fd.valid()) {
            throw new SocketException(Msg.getString("K003d")); //$NON-NLS-1$
        }
        return new SocketOutputStream(this);
    
private java.lang.reflect.FieldgetSocketImplField(java.lang.String fieldName)
gets SocketImpl field by reflection.

        return AccessController.doPrivileged(new PrivilegedAction<Field>() {
            public Field run() {
                Field field = null;
                try {
                    field = SocketImpl.class.getDeclaredField(fieldName);
                    field.setAccessible(true);
                } catch (NoSuchFieldException e) {
                    throw new Error(e);
                }
                return field;
            }
        });
    
protected voidlisten(int backlog)

        if (NetUtil.usingSocks(proxy)) {
            // Do nothing for a SOCKS connection. The listen occurs on the
            // server during the bind.
            return;
        }
        netImpl.listenStreamSocket(fd, backlog);
    
intread(byte[] buffer, int offset, int count)

        if (shutdownInput) {
            return -1;
        }
        try {
            int read = netImpl.receiveStream(fd, buffer, offset, count,
                    receiveTimeout);
            if (read == -1) {
                shutdownInput = true;
            }
            return read;
        } catch (InterruptedIOException e) {
            throw new SocketTimeoutException(e.getMessage());
        }
    
protected voidsendUrgentData(int value)

        netImpl.sendUrgentData(fd, (byte) value);
    
private voidsetLocalport(int localport)

        this.localport = localport;
    
public voidsetOption(int optID, java.lang.Object val)

        if (optID == SocketOptions.SO_TIMEOUT) {
            receiveTimeout = ((Integer) val).intValue();
        } else {
            try {
                netImpl.setSocketOption(fd, optID, val);
                if (optID == SocketOptions.TCP_NODELAY
                        && (netImpl.getSocketFlags() & TCP_NODELAY) != 0) {
                    tcpNoDelay = ((Boolean) val).booleanValue();
                }
            } catch (SocketException e) {
                // we don't throw an exception for IP_TOS even if the platform
                // won't let us set the requested value
                if (optID != SocketOptions.IP_TOS) {
                    throw e;
                }
            }

            /*
             * save this value as it is actually used differently for IPv4 and
             * IPv6 so we cannot get the value using the getOption. The option
             * is actually only set for IPv4 and a masked version of the value
             * will be set as only a subset of the values are allowed on the
             * socket. Therefore we need to retain it to return the value that
             * was set. We also need the value to be passed into a number of
             * natives so that it can be used properly with IPv6
             */
            if (optID == SocketOptions.IP_TOS) {
                trafficClass = ((Integer) val).intValue();
            }
        }
    
protected voidshutdownInput()
Shutdown the input portion of the socket.

        shutdownInput = true;
        netImpl.shutdownInput(fd);
    
protected voidshutdownOutput()
Shutdown the output portion of the socket.

        netImpl.shutdownOutput(fd);
    
public voidsocksAccept()
Perform an accept for a SOCKS bind.

        Socks4Message reply = socksReadReply();
        if (reply.getCommandOrResult() != Socks4Message.RETURN_SUCCESS) {
            throw new IOException(reply.getErrorString(reply
                    .getCommandOrResult()));
        }
    
private voidsocksBind()
Bind using a SOCKS server.

        try {
            netImpl.connect(fd, trafficClass, socksGetServerAddress(),
                    socksGetServerPort());
        } catch (Exception e) {
            throw new IOException(Msg.getString("K003f", e)); //$NON-NLS-1$
        }

        // There must be a connection to an application host for the bind to
        // work.
        if (lastConnectedAddress == null) {
            throw new SocketException(Msg.getString("K0040")); //$NON-NLS-1$
        }

        // Use the last connected address and port in the bind request.
        socksSendRequest(Socks4Message.COMMAND_BIND, lastConnectedAddress,
                lastConnectedPort);
        Socks4Message reply = socksReadReply();

        if (reply.getCommandOrResult() != Socks4Message.RETURN_SUCCESS) {
            throw new IOException(reply.getErrorString(reply
                    .getCommandOrResult()));
        }

        // A peculiarity of socks 4 - if the address returned is 0, use the
        // original socks server address.
        if (reply.getIP() == 0) {
            address = socksGetServerAddress();
        } else {
            // IPv6 support not yet required as
            // currently the Socks4Message.getIP() only returns int,
            // so only works with IPv4 4byte addresses
            byte[] replyBytes = new byte[4];
            NetUtil.intToBytes(reply.getIP(), replyBytes, 0);
            address = InetAddress.getByAddress(replyBytes);
        }
        localport = reply.getPort();
    
private voidsocksConnect(java.net.InetAddress applicationServerAddress, int applicationServerPort, int timeout)
Connect using a SOCKS server.

        try {
            if (timeout == 0) {
                netImpl.connect(fd, trafficClass, socksGetServerAddress(),
                        socksGetServerPort());
            } else {
                netImpl.connectStreamWithTimeoutSocket(fd,
                        socksGetServerPort(), timeout, trafficClass,
                        socksGetServerAddress());
            }

        } catch (Exception e) {
            throw new SocketException(Msg.getString("K003e", e)); //$NON-NLS-1$
        }

        socksRequestConnection(applicationServerAddress, applicationServerPort);

        lastConnectedAddress = applicationServerAddress;
        lastConnectedPort = applicationServerPort;
    
private java.net.InetAddresssocksGetServerAddress()
Gets the InetAddress of the SOCKS proxy server.

        String proxyName;
        // get socks server address from proxy. It is unnecessary to check
        // "socksProxyHost" property, since all proxy setting should be
        // determined by ProxySelector.
        InetSocketAddress addr = (InetSocketAddress) proxy.address();
        proxyName = addr.getHostName();
        if (null == proxyName) {
            proxyName = addr.getAddress().getHostAddress();
        }

        InetAddress anAddr = netImpl.getHostByName(proxyName, NetUtil
                .preferIPv6Addresses());
        return anAddr;
    
private intsocksGetServerPort()
Gets the SOCKS proxy server port.

        // get socks server port from proxy. It is unnecessary to check
        // "socksProxyPort" property, since proxy setting should only be
        // determined by ProxySelector.
        InetSocketAddress addr = (InetSocketAddress) proxy.address();
        return addr.getPort();

    
private Socks4MessagesocksReadReply()
Read a SOCKS V4 reply.

        Socks4Message reply = new Socks4Message();
        int bytesRead = 0;
        while (bytesRead < Socks4Message.REPLY_LENGTH) {
            int count = getInputStream().read(reply.getBytes(), bytesRead,
                    Socks4Message.REPLY_LENGTH - bytesRead);
            if (-1 == count) {
                break;
            }
            bytesRead += count;
        }
        if (Socks4Message.REPLY_LENGTH != bytesRead) {
            throw new SocketException(Msg.getString("KA011")); //$NON-NLS-1$
        }
        return reply;
    
private voidsocksRequestConnection(java.net.InetAddress applicationServerAddress, int applicationServerPort)
Request a SOCKS connection to the application server given. If the request fails to complete successfully, an exception is thrown.

        socksSendRequest(Socks4Message.COMMAND_CONNECT,
                applicationServerAddress, applicationServerPort);
        Socks4Message reply = socksReadReply();
        if (reply.getCommandOrResult() != Socks4Message.RETURN_SUCCESS) {
            throw new IOException(reply.getErrorString(reply
                    .getCommandOrResult()));
        }
    
private voidsocksSendRequest(int command, java.net.InetAddress address, int port)
Send a SOCKS V4 request.

        Socks4Message request = new Socks4Message();
        request.setCommandOrResult(command);
        request.setPort(port);
        request.setIP(address.getAddress());
        request.setUserId("default"); //$NON-NLS-1$

        getOutputStream().write(request.getBytes(), 0, request.getLength());
    
protected booleansupportsUrgentData()
Answer if the socket supports urgent data.

        return !streaming || netImpl.supportsUrgentData(fd);
    
intwrite(byte[] buffer, int offset, int count)

        if (!streaming) {
            return netImpl.sendDatagram2(fd, buffer, offset, count, port,
                    address);
        }
        return netImpl.sendStream(fd, buffer, offset, count);