PlainSocketImpl.java revision f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8a
1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Licensed to the Apache Software Foundation (ASF) under one or more
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  contributor license agreements.  See the NOTICE file distributed with
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  this work for additional information regarding copyright ownership.
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  The ASF licenses this file to You under the Apache License, Version 2.0
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  (the "License"); you may not use this file except in compliance with
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  the License.  You may obtain a copy of the License at
8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Unless required by applicable law or agreed to in writing, software
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  distributed under the License is distributed on an "AS IS" BASIS,
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  See the License for the specific language governing permissions and
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  limitations under the License.
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage org.apache.harmony.luni.net;
19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
20f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstromimport dalvik.system.CloseGuard;
21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.FileDescriptor;
22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.IOException;
23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.InputStream;
24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.OutputStream;
25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.lang.reflect.Field;
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.ConnectException;
27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.InetAddress;
28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.InetSocketAddress;
29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.Proxy;
30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.SocketAddress;
31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.SocketException;
32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.SocketImpl;
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.SocketTimeoutException;
34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.UnknownHostException;
35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.AccessController;
36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.PrivilegedAction;
37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.apache.harmony.luni.platform.Platform;
38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * A concrete connected-socket implementation.
41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
42f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilsonpublic class PlainSocketImpl extends SocketImpl {
43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // For SOCKS support. A SOCKS bind() uses the last
45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // host connected to in its request.
46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    static private InetAddress lastConnectedAddress;
47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    static private int lastConnectedPort;
49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static Field fdField;
51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
527738141c52b931e103efe7ad62d32a12785bf6b1Elliott Hughes    private boolean streaming = true;
53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
547738141c52b931e103efe7ad62d32a12785bf6b1Elliott Hughes    private boolean shutdownInput;
55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
567738141c52b931e103efe7ad62d32a12785bf6b1Elliott Hughes    private Proxy proxy;
57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
58f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom    private final CloseGuard guard = CloseGuard.getUnopened();
59f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom
60f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    public PlainSocketImpl(FileDescriptor fd) {
61f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        this.fd = fd;
62f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        if (fd.valid()) {
63f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            guard.open("close");
64f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        }
65f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    }
66f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
67f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    public PlainSocketImpl(Proxy proxy) {
686b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson        this(new FileDescriptor());
69f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        this.proxy = proxy;
70f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    }
71f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
726b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson    public PlainSocketImpl() {
736b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson        this(new FileDescriptor());
746b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson    }
756b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson
76f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    public PlainSocketImpl(FileDescriptor fd, int localport, InetAddress addr, int port) {
77f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        super();
78f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        this.fd = fd;
79f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        this.localport = localport;
80f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        this.address = addr;
81f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        this.port = port;
82f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        if (fd.valid()) {
83f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            guard.open("close");
84f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        }
85f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    }
86f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void accept(SocketImpl newImpl) throws IOException {
890917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes        if (usingSocks()) {
90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ((PlainSocketImpl) newImpl).socksBind();
91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ((PlainSocketImpl) newImpl).socksAccept();
92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return;
93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (newImpl instanceof PlainSocketImpl) {
97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                PlainSocketImpl newPlainSocketImpl = (PlainSocketImpl) newImpl;
983db0d1b07a79c3c871b0aa0929674adae3081b4fElliott Hughes                Platform.NETWORK.accept(fd, newImpl, newPlainSocketImpl.getFileDescriptor());
99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // if newImpl is not an instance of PlainSocketImpl, use
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // reflection to get/set protected fields.
1028cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes                if (fdField == null) {
103f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                    fdField = getSocketImplField("fd");
104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                FileDescriptor newFd = (FileDescriptor) fdField.get(newImpl);
1063db0d1b07a79c3c871b0aa0929674adae3081b4fElliott Hughes                Platform.NETWORK.accept(fd, newImpl, newFd);
107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (IllegalAccessException e) {
109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // empty
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1130917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes    private boolean usingSocks() {
1140917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes        return proxy != null && proxy.type() == Proxy.Type.SOCKS;
1150917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes    }
1160917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes
117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * gets SocketImpl field by reflection.
119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private Field getSocketImplField(final String fieldName) {
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return AccessController.doPrivileged(new PrivilegedAction<Field>() {
122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            public Field run() {
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                Field field = null;
124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                try {
125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    field = SocketImpl.class.getDeclaredField(fieldName);
126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    field.setAccessible(true);
127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                } catch (NoSuchFieldException e) {
128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    throw new Error(e);
129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return field;
131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        });
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1358cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    public void initLocalPort(int localPort) {
1368cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        this.localport = localPort;
1378cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    }
1388cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes
1398cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    public void initRemoteAddressAndPort(InetAddress remoteAddress, int remotePort) {
1408cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        this.address = remoteAddress;
1418cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        this.port = remotePort;
1428cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    }
1438cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes
144f9e1294b67778f9b290b9fb6eeda2d7cc7c1c3eeElliott Hughes    private void checkNotClosed() throws IOException {
145f9e1294b67778f9b290b9fb6eeda2d7cc7c1c3eeElliott Hughes        if (!fd.valid()) {
146f9e1294b67778f9b290b9fb6eeda2d7cc7c1c3eeElliott Hughes            throw new SocketException("Socket is closed");
147f9e1294b67778f9b290b9fb6eeda2d7cc7c1c3eeElliott Hughes        }
148f9e1294b67778f9b290b9fb6eeda2d7cc7c1c3eeElliott Hughes    }
149f9e1294b67778f9b290b9fb6eeda2d7cc7c1c3eeElliott Hughes
150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
151adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected synchronized int available() throws IOException {
152f9e1294b67778f9b290b9fb6eeda2d7cc7c1c3eeElliott Hughes        checkNotClosed();
153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // we need to check if the input has been shutdown. If so
154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // we should return that there is no data to be read
15597144c87ada735a82221d7cdf65555b8f063a05aElliott Hughes        if (shutdownInput) {
156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return 0;
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
1583db0d1b07a79c3c871b0aa0929674adae3081b4fElliott Hughes        return Platform.FILE_SYSTEM.ioctlAvailable(fd);
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
1628cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    protected void bind(InetAddress address, int port) throws IOException {
1633db0d1b07a79c3c871b0aa0929674adae3081b4fElliott Hughes        Platform.NETWORK.bind(fd, address, port);
1648cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        this.address = address;
1658cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        if (port != 0) {
1668cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes            this.localport = port;
167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
1683db0d1b07a79c3c871b0aa0929674adae3081b4fElliott Hughes            this.localport = Platform.NETWORK.getSocketLocalPort(fd);
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
17358e5a8e6eeaf94d78522e0e9994c4565a3b33fdbJesse Wilson    protected synchronized void close() throws IOException {
174f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        guard.close();
175c6e0981e5a2d23a0758ed71a8086c4278a7832efJesse Wilson        Platform.NETWORK.close(fd);
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void connect(String aHost, int aPort) throws IOException {
18097144c87ada735a82221d7cdf65555b8f063a05aElliott Hughes        connect(InetAddress.getByName(aHost), aPort);
181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void connect(InetAddress anAddr, int aPort) throws IOException {
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        connect(anAddr, aPort, 0);
186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Connects this socket to the specified remote host address/port.
190f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param anAddr
192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the remote host address to connect to
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param aPort
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the remote port to connect to
195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param timeout
196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            a timeout where supported. 0 means no timeout
197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException
198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if an error occurs while connecting
199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
2008cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    private void connect(InetAddress anAddr, int aPort, int timeout) throws IOException {
201f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        InetAddress normalAddr = anAddr.isAnyLocalAddress() ? InetAddress.getLocalHost() : anAddr;
202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
2030917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes            if (streaming && usingSocks()) {
204036ffc75d2b7ece42bcd97f290c026e215868ba9Elliott Hughes                socksConnect(anAddr, aPort, 0);
205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
2063db0d1b07a79c3c871b0aa0929674adae3081b4fElliott Hughes                Platform.NETWORK.connect(fd, normalAddr, aPort, timeout);
207adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
208adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (ConnectException e) {
2098cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes            throw new ConnectException(anAddr + ":" + aPort + " - " + e.getMessage());
210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
211adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        super.address = normalAddr;
212adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        super.port = aPort;
213adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
215adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
216adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void create(boolean streaming) throws IOException {
217adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.streaming = streaming;
2183db0d1b07a79c3c871b0aa0929674adae3081b4fElliott Hughes        Platform.NETWORK.socket(fd, streaming);
219adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
220adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
221e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom    @Override protected void finalize() throws Throwable {
222e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        try {
223f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            guard.warnIfOpen();
224e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            close();
225e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        } finally {
226e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            super.finalize();
227e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        }
228adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
229adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
230adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
231adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected synchronized InputStream getInputStream() throws IOException {
232f9e1294b67778f9b290b9fb6eeda2d7cc7c1c3eeElliott Hughes        checkNotClosed();
233adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return new SocketInputStream(this);
234adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
235adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
236adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
237adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public Object getOption(int optID) throws SocketException {
2383db0d1b07a79c3c871b0aa0929674adae3081b4fElliott Hughes        return Platform.NETWORK.getSocketOption(fd, optID);
239adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
240adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
241adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
242adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected synchronized OutputStream getOutputStream() throws IOException {
243f9e1294b67778f9b290b9fb6eeda2d7cc7c1c3eeElliott Hughes        checkNotClosed();
244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return new SocketOutputStream(this);
245adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
247adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void listen(int backlog) throws IOException {
2490917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes        if (usingSocks()) {
250adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // Do nothing for a SOCKS connection. The listen occurs on the
251adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // server during the bind.
252adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return;
253adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
2543db0d1b07a79c3c871b0aa0929674adae3081b4fElliott Hughes        Platform.NETWORK.listen(fd, backlog);
255adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
256adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
257adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
258adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void setOption(int optID, Object val) throws SocketException {
2593db0d1b07a79c3c871b0aa0929674adae3081b4fElliott Hughes        Platform.NETWORK.setSocketOption(fd, optID, val);
260adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
262adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
263adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets the SOCKS proxy server port.
264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
265adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private int socksGetServerPort() {
266adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // get socks server port from proxy. It is unnecessary to check
267adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // "socksProxyPort" property, since proxy setting should only be
268adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // determined by ProxySelector.
269adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        InetSocketAddress addr = (InetSocketAddress) proxy.address();
270adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return addr.getPort();
271adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
273adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
274adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets the InetAddress of the SOCKS proxy server.
276adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
277adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private InetAddress socksGetServerAddress() throws UnknownHostException {
278adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String proxyName;
279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // get socks server address from proxy. It is unnecessary to check
280adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // "socksProxyHost" property, since all proxy setting should be
281adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // determined by ProxySelector.
282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        InetSocketAddress addr = (InetSocketAddress) proxy.address();
283adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        proxyName = addr.getHostName();
284adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (null == proxyName) {
285adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            proxyName = addr.getAddress().getHostAddress();
286adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
28797144c87ada735a82221d7cdf65555b8f063a05aElliott Hughes        return InetAddress.getByName(proxyName);
288adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
289adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
290adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
291adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Connect using a SOCKS server.
292adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
293adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void socksConnect(InetAddress applicationServerAddress,
294adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int applicationServerPort, int timeout) throws IOException {
295adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
2963db0d1b07a79c3c871b0aa0929674adae3081b4fElliott Hughes            Platform.NETWORK.connect(fd, socksGetServerAddress(), socksGetServerPort(), timeout);
297adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (Exception e) {
298b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw new SocketException("SOCKS connection failed: " + e);
299adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
300adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
301adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        socksRequestConnection(applicationServerAddress, applicationServerPort);
302adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
303adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        lastConnectedAddress = applicationServerAddress;
304adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        lastConnectedPort = applicationServerPort;
305adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
306adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
307adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
308adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Request a SOCKS connection to the application server given. If the
309adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * request fails to complete successfully, an exception is thrown.
310adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
311adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void socksRequestConnection(InetAddress applicationServerAddress,
312adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int applicationServerPort) throws IOException {
313adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        socksSendRequest(Socks4Message.COMMAND_CONNECT,
314adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                applicationServerAddress, applicationServerPort);
315adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Socks4Message reply = socksReadReply();
316adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (reply.getCommandOrResult() != Socks4Message.RETURN_SUCCESS) {
317adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IOException(reply.getErrorString(reply
318adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    .getCommandOrResult()));
319adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
320adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
321adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
322adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
323adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Perform an accept for a SOCKS bind.
324adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
325adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void socksAccept() throws IOException {
326adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Socks4Message reply = socksReadReply();
327adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (reply.getCommandOrResult() != Socks4Message.RETURN_SUCCESS) {
328adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IOException(reply.getErrorString(reply
329adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    .getCommandOrResult()));
330adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
331adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
332adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
333adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
334adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Shutdown the input portion of the socket.
335adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
336adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
337adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void shutdownInput() throws IOException {
338adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        shutdownInput = true;
3393db0d1b07a79c3c871b0aa0929674adae3081b4fElliott Hughes        Platform.NETWORK.shutdownInput(fd);
340adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
341adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
342adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
343adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Shutdown the output portion of the socket.
344adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
345adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
346adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void shutdownOutput() throws IOException {
3473db0d1b07a79c3c871b0aa0929674adae3081b4fElliott Hughes        Platform.NETWORK.shutdownOutput(fd);
348adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
349adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
350adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
351adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Bind using a SOCKS server.
352adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
353adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void socksBind() throws IOException {
354adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
3553db0d1b07a79c3c871b0aa0929674adae3081b4fElliott Hughes            Platform.NETWORK.connect(fd, socksGetServerAddress(), socksGetServerPort(), 0);
356adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (Exception e) {
357b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw new IOException("Unable to connect to SOCKS server: " + e);
358adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
359adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
360adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // There must be a connection to an application host for the bind to
361adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // work.
362adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (lastConnectedAddress == null) {
363b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw new SocketException("Invalid SOCKS client");
364adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
365adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
366adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Use the last connected address and port in the bind request.
367adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        socksSendRequest(Socks4Message.COMMAND_BIND, lastConnectedAddress,
368adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                lastConnectedPort);
369adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Socks4Message reply = socksReadReply();
370adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
371adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (reply.getCommandOrResult() != Socks4Message.RETURN_SUCCESS) {
372adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IOException(reply.getErrorString(reply
373adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    .getCommandOrResult()));
374adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
375adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
376adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // A peculiarity of socks 4 - if the address returned is 0, use the
377adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // original socks server address.
378adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (reply.getIP() == 0) {
379adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            address = socksGetServerAddress();
380adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
381adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // IPv6 support not yet required as
382adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // currently the Socks4Message.getIP() only returns int,
383adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // so only works with IPv4 4byte addresses
384adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            byte[] replyBytes = new byte[4];
3850917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes            intToBytes(reply.getIP(), replyBytes, 0);
386adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            address = InetAddress.getByAddress(replyBytes);
387adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
388adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        localport = reply.getPort();
389adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
390adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
391171dc20afe5071d5cbfad7103903bfa2c1f8d00fElliott Hughes    private static void intToBytes(int value, byte[] bytes, int start) {
3920917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes        /*
3930917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes         * Shift the int so the current byte is right-most Use a byte mask of
3940917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes         * 255 to single out the last byte.
3950917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes         */
3960917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes        bytes[start] = (byte) ((value >> 24) & 255);
3970917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes        bytes[start + 1] = (byte) ((value >> 16) & 255);
3980917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes        bytes[start + 2] = (byte) ((value >> 8) & 255);
3990917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes        bytes[start + 3] = (byte) (value & 255);
4000917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes    }
4010917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes
402adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
403adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Send a SOCKS V4 request.
404adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
405adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void socksSendRequest(int command, InetAddress address, int port)
406adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throws IOException {
407adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Socks4Message request = new Socks4Message();
408adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        request.setCommandOrResult(command);
409adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        request.setPort(port);
410adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        request.setIP(address.getAddress());
411f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        request.setUserId("default");
412adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
413adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        getOutputStream().write(request.getBytes(), 0, request.getLength());
414adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
415adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
416adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
417adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Read a SOCKS V4 reply.
418adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
419adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private Socks4Message socksReadReply() throws IOException {
420adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Socks4Message reply = new Socks4Message();
421adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int bytesRead = 0;
422adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while (bytesRead < Socks4Message.REPLY_LENGTH) {
423adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int count = getInputStream().read(reply.getBytes(), bytesRead,
424adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    Socks4Message.REPLY_LENGTH - bytesRead);
425adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (-1 == count) {
426adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                break;
427adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
428adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            bytesRead += count;
429adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
430adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (Socks4Message.REPLY_LENGTH != bytesRead) {
431b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw new SocketException("Malformed reply from SOCKS server");
432adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
433adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return reply;
434adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
435adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
436adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
437adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void connect(SocketAddress remoteAddr, int timeout)
438adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throws IOException {
439adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        InetSocketAddress inetAddr = (InetSocketAddress) remoteAddr;
440adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        connect(inetAddr.getAddress(), inetAddr.getPort(), timeout);
441adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
442adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
443adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
444adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected boolean supportsUrgentData() {
44579ff4e73fd689dae6667a8137ee57137962ff13aElliott Hughes        return true;
446adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
447adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
448adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
449adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void sendUrgentData(int value) throws IOException {
4503db0d1b07a79c3c871b0aa0929674adae3081b4fElliott Hughes        Platform.NETWORK.sendUrgentData(fd, (byte) value);
451adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
452adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
453adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    int read(byte[] buffer, int offset, int count) throws IOException {
454adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (shutdownInput) {
455adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return -1;
456adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
4573db0d1b07a79c3c871b0aa0929674adae3081b4fElliott Hughes        int read = Platform.NETWORK.read(fd, buffer, offset, count);
458f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        // Return of zero bytes for a blocking socket means a timeout occurred
459f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        if (read == 0) {
460f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            throw new SocketTimeoutException();
461f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
462f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        // Return of -1 indicates the peer was closed
463f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        if (read == -1) {
464f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            shutdownInput = true;
465adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
466f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        return read;
467adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
468adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
469adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    int write(byte[] buffer, int offset, int count) throws IOException {
470221d0ccb4cc23ee0bf0646e9abe471fb48b3a1a8Elliott Hughes        if (streaming) {
4713db0d1b07a79c3c871b0aa0929674adae3081b4fElliott Hughes            return Platform.NETWORK.write(fd, buffer, offset, count);
472221d0ccb4cc23ee0bf0646e9abe471fb48b3a1a8Elliott Hughes        } else {
4733db0d1b07a79c3c871b0aa0929674adae3081b4fElliott Hughes            return Platform.NETWORK.send(fd, buffer, offset, count, port, address);
474adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
475adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
476adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
477