PlainSocketImpl.java revision b46dab348e2007bc08abaf7ecae34d89a2474e50
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;
350eb70e31581a977afa5df3292d1c96e42e548821Elliott Hughesimport java.nio.ByteOrder;
36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.AccessController;
37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.PrivilegedAction;
380eb70e31581a977afa5df3292d1c96e42e548821Elliott Hughesimport org.apache.harmony.luni.platform.OSMemory;
39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.apache.harmony.luni.platform.Platform;
40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * A concrete connected-socket implementation.
43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
44f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilsonpublic class PlainSocketImpl extends SocketImpl {
45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // For SOCKS support. A SOCKS bind() uses the last
47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // host connected to in its request.
48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    static private InetAddress lastConnectedAddress;
49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    static private int lastConnectedPort;
51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static Field fdField;
53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
547738141c52b931e103efe7ad62d32a12785bf6b1Elliott Hughes    private boolean streaming = true;
55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
567738141c52b931e103efe7ad62d32a12785bf6b1Elliott Hughes    private boolean shutdownInput;
57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
587738141c52b931e103efe7ad62d32a12785bf6b1Elliott Hughes    private Proxy proxy;
59adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
6012f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom    private final CloseGuard guard = CloseGuard.get();
61f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom
62f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    public PlainSocketImpl(FileDescriptor fd) {
63f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        this.fd = fd;
64f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        if (fd.valid()) {
65f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            guard.open("close");
66f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        }
67f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    }
68f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
69f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    public PlainSocketImpl(Proxy proxy) {
706b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson        this(new FileDescriptor());
71f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        this.proxy = proxy;
72f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    }
73f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
746b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson    public PlainSocketImpl() {
756b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson        this(new FileDescriptor());
766b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson    }
776b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson
78f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    public PlainSocketImpl(FileDescriptor fd, int localport, InetAddress addr, int port) {
79f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        super();
80f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        this.fd = fd;
81f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        this.localport = localport;
82f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        this.address = addr;
83f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        this.port = port;
84f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        if (fd.valid()) {
85f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            guard.open("close");
86f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        }
87f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    }
88f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void accept(SocketImpl newImpl) throws IOException {
910917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes        if (usingSocks()) {
92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ((PlainSocketImpl) newImpl).socksBind();
93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ((PlainSocketImpl) newImpl).socksAccept();
94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return;
95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (newImpl instanceof PlainSocketImpl) {
99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                PlainSocketImpl newPlainSocketImpl = (PlainSocketImpl) newImpl;
1003db0d1b07a79c3c871b0aa0929674adae3081b4fElliott Hughes                Platform.NETWORK.accept(fd, newImpl, newPlainSocketImpl.getFileDescriptor());
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // if newImpl is not an instance of PlainSocketImpl, use
103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // reflection to get/set protected fields.
1048cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes                if (fdField == null) {
105f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                    fdField = getSocketImplField("fd");
106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                FileDescriptor newFd = (FileDescriptor) fdField.get(newImpl);
1083db0d1b07a79c3c871b0aa0929674adae3081b4fElliott Hughes                Platform.NETWORK.accept(fd, newImpl, newFd);
109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (IllegalAccessException e) {
111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // empty
112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1150917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes    private boolean usingSocks() {
1160917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes        return proxy != null && proxy.type() == Proxy.Type.SOCKS;
1170917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes    }
1180917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes
119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * gets SocketImpl field by reflection.
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private Field getSocketImplField(final String fieldName) {
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return AccessController.doPrivileged(new PrivilegedAction<Field>() {
124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            public Field run() {
125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                Field field = null;
126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                try {
127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    field = SocketImpl.class.getDeclaredField(fieldName);
128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    field.setAccessible(true);
129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                } catch (NoSuchFieldException e) {
130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    throw new Error(e);
131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return field;
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        });
135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1378cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    public void initLocalPort(int localPort) {
1388cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        this.localport = localPort;
1398cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    }
1408cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes
1418cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    public void initRemoteAddressAndPort(InetAddress remoteAddress, int remotePort) {
1428cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        this.address = remoteAddress;
1438cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        this.port = remotePort;
1448cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    }
1458cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes
146f9e1294b67778f9b290b9fb6eeda2d7cc7c1c3eeElliott Hughes    private void checkNotClosed() throws IOException {
147f9e1294b67778f9b290b9fb6eeda2d7cc7c1c3eeElliott Hughes        if (!fd.valid()) {
148f9e1294b67778f9b290b9fb6eeda2d7cc7c1c3eeElliott Hughes            throw new SocketException("Socket is closed");
149f9e1294b67778f9b290b9fb6eeda2d7cc7c1c3eeElliott Hughes        }
150f9e1294b67778f9b290b9fb6eeda2d7cc7c1c3eeElliott Hughes    }
151f9e1294b67778f9b290b9fb6eeda2d7cc7c1c3eeElliott Hughes
152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected synchronized int available() throws IOException {
154f9e1294b67778f9b290b9fb6eeda2d7cc7c1c3eeElliott Hughes        checkNotClosed();
155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // we need to check if the input has been shutdown. If so
156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // we should return that there is no data to be read
15797144c87ada735a82221d7cdf65555b8f063a05aElliott Hughes        if (shutdownInput) {
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return 0;
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
1603db0d1b07a79c3c871b0aa0929674adae3081b4fElliott Hughes        return Platform.FILE_SYSTEM.ioctlAvailable(fd);
161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
1648cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    protected void bind(InetAddress address, int port) throws IOException {
1653db0d1b07a79c3c871b0aa0929674adae3081b4fElliott Hughes        Platform.NETWORK.bind(fd, address, port);
1668cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        this.address = address;
1678cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        if (port != 0) {
1688cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes            this.localport = port;
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
1703db0d1b07a79c3c871b0aa0929674adae3081b4fElliott Hughes            this.localport = Platform.NETWORK.getSocketLocalPort(fd);
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
17558e5a8e6eeaf94d78522e0e9994c4565a3b33fdbJesse Wilson    protected synchronized void close() throws IOException {
176f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        guard.close();
177c6e0981e5a2d23a0758ed71a8086c4278a7832efJesse Wilson        Platform.NETWORK.close(fd);
178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void connect(String aHost, int aPort) throws IOException {
18297144c87ada735a82221d7cdf65555b8f063a05aElliott Hughes        connect(InetAddress.getByName(aHost), aPort);
183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void connect(InetAddress anAddr, int aPort) throws IOException {
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        connect(anAddr, aPort, 0);
188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Connects this socket to the specified remote host address/port.
192f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param anAddr
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the remote host address to connect to
195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param aPort
196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the remote port to connect to
197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param timeout
198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            a timeout where supported. 0 means no timeout
199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException
200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if an error occurs while connecting
201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
2028cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    private void connect(InetAddress anAddr, int aPort, int timeout) throws IOException {
203f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        InetAddress normalAddr = anAddr.isAnyLocalAddress() ? InetAddress.getLocalHost() : anAddr;
204adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
2050917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes            if (streaming && usingSocks()) {
206036ffc75d2b7ece42bcd97f290c026e215868ba9Elliott Hughes                socksConnect(anAddr, aPort, 0);
207adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
2083db0d1b07a79c3c871b0aa0929674adae3081b4fElliott Hughes                Platform.NETWORK.connect(fd, normalAddr, aPort, timeout);
209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (ConnectException e) {
2118cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes            throw new ConnectException(anAddr + ":" + aPort + " - " + e.getMessage());
212adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
213adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        super.address = normalAddr;
214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        super.port = aPort;
215adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
216adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
217adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
218adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void create(boolean streaming) throws IOException {
219adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.streaming = streaming;
2203db0d1b07a79c3c871b0aa0929674adae3081b4fElliott Hughes        Platform.NETWORK.socket(fd, streaming);
221adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
222adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
223e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom    @Override protected void finalize() throws Throwable {
224e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        try {
22512f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom            if (guard != null) {
22612f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom                guard.warnIfOpen();
22712f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom            }
228e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            close();
229e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        } finally {
230e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            super.finalize();
231e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        }
232adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
233adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
234adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
235adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected synchronized InputStream getInputStream() throws IOException {
236f9e1294b67778f9b290b9fb6eeda2d7cc7c1c3eeElliott Hughes        checkNotClosed();
237adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return new SocketInputStream(this);
238adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
239adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
240adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
241adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public Object getOption(int optID) throws SocketException {
2423db0d1b07a79c3c871b0aa0929674adae3081b4fElliott Hughes        return Platform.NETWORK.getSocketOption(fd, optID);
243adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
245adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected synchronized OutputStream getOutputStream() throws IOException {
247f9e1294b67778f9b290b9fb6eeda2d7cc7c1c3eeElliott Hughes        checkNotClosed();
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return new SocketOutputStream(this);
249adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
250adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
251adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
252adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void listen(int backlog) throws IOException {
2530917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes        if (usingSocks()) {
254adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // Do nothing for a SOCKS connection. The listen occurs on the
255adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // server during the bind.
256adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return;
257adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
2583db0d1b07a79c3c871b0aa0929674adae3081b4fElliott Hughes        Platform.NETWORK.listen(fd, backlog);
259adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
260adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
262adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void setOption(int optID, Object val) throws SocketException {
2633db0d1b07a79c3c871b0aa0929674adae3081b4fElliott Hughes        Platform.NETWORK.setSocketOption(fd, optID, val);
264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
265adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
266adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
267adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets the SOCKS proxy server port.
268adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
269adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private int socksGetServerPort() {
270adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // get socks server port from proxy. It is unnecessary to check
271adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // "socksProxyPort" property, since proxy setting should only be
272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // determined by ProxySelector.
273adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        InetSocketAddress addr = (InetSocketAddress) proxy.address();
274adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return addr.getPort();
275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
276adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
277adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
278adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets the InetAddress of the SOCKS proxy server.
280adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
281adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private InetAddress socksGetServerAddress() throws UnknownHostException {
282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String proxyName;
283adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // get socks server address from proxy. It is unnecessary to check
284adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // "socksProxyHost" property, since all proxy setting should be
285adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // determined by ProxySelector.
286adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        InetSocketAddress addr = (InetSocketAddress) proxy.address();
287adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        proxyName = addr.getHostName();
288b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes        if (proxyName == null) {
289adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            proxyName = addr.getAddress().getHostAddress();
290adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
29197144c87ada735a82221d7cdf65555b8f063a05aElliott Hughes        return InetAddress.getByName(proxyName);
292adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
293adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
294adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
295adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Connect using a SOCKS server.
296adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
297adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void socksConnect(InetAddress applicationServerAddress,
298adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int applicationServerPort, int timeout) throws IOException {
299adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
3003db0d1b07a79c3c871b0aa0929674adae3081b4fElliott Hughes            Platform.NETWORK.connect(fd, socksGetServerAddress(), socksGetServerPort(), timeout);
301adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (Exception e) {
302b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw new SocketException("SOCKS connection failed: " + e);
303adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
304adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
305adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        socksRequestConnection(applicationServerAddress, applicationServerPort);
306adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
307adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        lastConnectedAddress = applicationServerAddress;
308adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        lastConnectedPort = applicationServerPort;
309adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
310adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
311adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
312adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Request a SOCKS connection to the application server given. If the
313adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * request fails to complete successfully, an exception is thrown.
314adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
315adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void socksRequestConnection(InetAddress applicationServerAddress,
316adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int applicationServerPort) throws IOException {
317adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        socksSendRequest(Socks4Message.COMMAND_CONNECT,
318adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                applicationServerAddress, applicationServerPort);
319adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Socks4Message reply = socksReadReply();
320adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (reply.getCommandOrResult() != Socks4Message.RETURN_SUCCESS) {
321adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IOException(reply.getErrorString(reply
322adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    .getCommandOrResult()));
323adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
324adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
325adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
326adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
327adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Perform an accept for a SOCKS bind.
328adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
329adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void socksAccept() throws IOException {
330adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Socks4Message reply = socksReadReply();
331adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (reply.getCommandOrResult() != Socks4Message.RETURN_SUCCESS) {
332adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IOException(reply.getErrorString(reply
333adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    .getCommandOrResult()));
334adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
335adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
336adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
337adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
338adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Shutdown the input portion of the socket.
339adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
340adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
341adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void shutdownInput() throws IOException {
342adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        shutdownInput = true;
3433db0d1b07a79c3c871b0aa0929674adae3081b4fElliott Hughes        Platform.NETWORK.shutdownInput(fd);
344adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
345adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
346adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
347adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Shutdown the output portion of the socket.
348adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
349adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
350adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void shutdownOutput() throws IOException {
3513db0d1b07a79c3c871b0aa0929674adae3081b4fElliott Hughes        Platform.NETWORK.shutdownOutput(fd);
352adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
353adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
354adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
355adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Bind using a SOCKS server.
356adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
357adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void socksBind() throws IOException {
358adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
3593db0d1b07a79c3c871b0aa0929674adae3081b4fElliott Hughes            Platform.NETWORK.connect(fd, socksGetServerAddress(), socksGetServerPort(), 0);
360adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (Exception e) {
361b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw new IOException("Unable to connect to SOCKS server: " + e);
362adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
363adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
364adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // There must be a connection to an application host for the bind to
365adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // work.
366adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (lastConnectedAddress == null) {
367b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw new SocketException("Invalid SOCKS client");
368adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
369adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
370adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Use the last connected address and port in the bind request.
371adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        socksSendRequest(Socks4Message.COMMAND_BIND, lastConnectedAddress,
372adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                lastConnectedPort);
373adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Socks4Message reply = socksReadReply();
374adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
375adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (reply.getCommandOrResult() != Socks4Message.RETURN_SUCCESS) {
3760eb70e31581a977afa5df3292d1c96e42e548821Elliott Hughes            throw new IOException(reply.getErrorString(reply.getCommandOrResult()));
377adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
378adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
379adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // A peculiarity of socks 4 - if the address returned is 0, use the
380adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // original socks server address.
381adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (reply.getIP() == 0) {
382adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            address = socksGetServerAddress();
383adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
384adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // IPv6 support not yet required as
385adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // currently the Socks4Message.getIP() only returns int,
386adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // so only works with IPv4 4byte addresses
387adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            byte[] replyBytes = new byte[4];
3880eb70e31581a977afa5df3292d1c96e42e548821Elliott Hughes            OSMemory.pokeInt(replyBytes, 0, reply.getIP(), ByteOrder.BIG_ENDIAN);
389adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            address = InetAddress.getByAddress(replyBytes);
390adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
391adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        localport = reply.getPort();
392adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
393adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
394adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
395adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Send a SOCKS V4 request.
396adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
3970eb70e31581a977afa5df3292d1c96e42e548821Elliott Hughes    private void socksSendRequest(int command, InetAddress address, int port) throws IOException {
398adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Socks4Message request = new Socks4Message();
399adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        request.setCommandOrResult(command);
400adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        request.setPort(port);
401adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        request.setIP(address.getAddress());
402f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        request.setUserId("default");
403adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
404adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        getOutputStream().write(request.getBytes(), 0, request.getLength());
405adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
406adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
407adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
408adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Read a SOCKS V4 reply.
409adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
410adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private Socks4Message socksReadReply() throws IOException {
411adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Socks4Message reply = new Socks4Message();
412adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int bytesRead = 0;
413adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while (bytesRead < Socks4Message.REPLY_LENGTH) {
414adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int count = getInputStream().read(reply.getBytes(), bytesRead,
415adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    Socks4Message.REPLY_LENGTH - bytesRead);
416adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (-1 == count) {
417adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                break;
418adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
419adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            bytesRead += count;
420adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
421adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (Socks4Message.REPLY_LENGTH != bytesRead) {
422b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw new SocketException("Malformed reply from SOCKS server");
423adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
424adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return reply;
425adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
426adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
427adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
428adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void connect(SocketAddress remoteAddr, int timeout)
429adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throws IOException {
430adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        InetSocketAddress inetAddr = (InetSocketAddress) remoteAddr;
431adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        connect(inetAddr.getAddress(), inetAddr.getPort(), timeout);
432adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
433adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
434adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
435adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected boolean supportsUrgentData() {
43679ff4e73fd689dae6667a8137ee57137962ff13aElliott Hughes        return true;
437adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
438adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
439adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
440adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void sendUrgentData(int value) throws IOException {
4413db0d1b07a79c3c871b0aa0929674adae3081b4fElliott Hughes        Platform.NETWORK.sendUrgentData(fd, (byte) value);
442adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
443adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
444adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    int read(byte[] buffer, int offset, int count) throws IOException {
445adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (shutdownInput) {
446adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return -1;
447adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
4483db0d1b07a79c3c871b0aa0929674adae3081b4fElliott Hughes        int read = Platform.NETWORK.read(fd, buffer, offset, count);
449f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        // Return of zero bytes for a blocking socket means a timeout occurred
450f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        if (read == 0) {
451f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            throw new SocketTimeoutException();
452f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
453f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        // Return of -1 indicates the peer was closed
454f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        if (read == -1) {
455f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            shutdownInput = true;
456adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
457f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        return read;
458adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
459adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
460adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    int write(byte[] buffer, int offset, int count) throws IOException {
461221d0ccb4cc23ee0bf0646e9abe471fb48b3a1a8Elliott Hughes        if (streaming) {
4623db0d1b07a79c3c871b0aa0929674adae3081b4fElliott Hughes            return Platform.NETWORK.write(fd, buffer, offset, count);
463221d0ccb4cc23ee0bf0646e9abe471fb48b3a1a8Elliott Hughes        } else {
4643db0d1b07a79c3c871b0aa0929674adae3081b4fElliott Hughes            return Platform.NETWORK.send(fd, buffer, offset, count, port, address);
465adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
466adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
467adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
468