PlainSocketImpl.java revision 79ff4e73fd689dae6667a8137ee57137962ff13a
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
20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.FileDescriptor;
21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.IOException;
22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.InputStream;
23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.InterruptedIOException;
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.SocketOptions;
34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.SocketTimeoutException;
35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.UnknownHostException;
36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.AccessController;
37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.PrivilegedAction;
38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.apache.harmony.luni.platform.INetworkSystem;
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
54adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * used to store the trafficClass value which is simply returned as the
56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * value that was set. We also need it to pass it to methods that specify an
57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * address packets are going to be sent to
58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
59adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private int trafficClass;
60adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected INetworkSystem netImpl = Platform.getNetworkSystem();
62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
63adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public int receiveTimeout = 0;
64adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
65adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean streaming = true;
66adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
67adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean shutdownInput;
68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
69adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    Proxy proxy;
70adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
71f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    public PlainSocketImpl(FileDescriptor fd) {
72f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        this.fd = fd;
73f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    }
74f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
75f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    public PlainSocketImpl(Proxy proxy) {
766b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson        this(new FileDescriptor());
77f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        this.proxy = proxy;
78f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    }
79f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
806b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson    public PlainSocketImpl() {
816b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson        this(new FileDescriptor());
826b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson    }
836b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson
84f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    public PlainSocketImpl(FileDescriptor fd, int localport, InetAddress addr, int port) {
85f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        super();
86f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        this.fd = fd;
87f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        this.localport = localport;
88f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        this.address = addr;
89f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        this.port = port;
90f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    }
91f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void accept(SocketImpl newImpl) throws IOException {
94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (NetUtil.usingSocks(proxy)) {
95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ((PlainSocketImpl) newImpl).socksBind();
96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ((PlainSocketImpl) newImpl).socksAccept();
97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return;
98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (newImpl instanceof PlainSocketImpl) {
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                PlainSocketImpl newPlainSocketImpl = (PlainSocketImpl) newImpl;
1038cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes                netImpl.accept(fd, newImpl, newPlainSocketImpl.getFileDescriptor(), receiveTimeout);
104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // if newImpl is not an instance of PlainSocketImpl, use
106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // reflection to get/set protected fields.
1078cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes                if (fdField == null) {
108f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                    fdField = getSocketImplField("fd");
109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                FileDescriptor newFd = (FileDescriptor) fdField.get(newImpl);
111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                netImpl.accept(fd, newImpl, newFd, receiveTimeout);
112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (InterruptedIOException e) {
114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new SocketTimeoutException(e.getMessage());
115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (IllegalAccessException e) {
116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // empty
117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * gets SocketImpl field by reflection.
122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private Field getSocketImplField(final String fieldName) {
124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return AccessController.doPrivileged(new PrivilegedAction<Field>() {
125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            public Field run() {
126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                Field field = null;
127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                try {
128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    field = SocketImpl.class.getDeclaredField(fieldName);
129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    field.setAccessible(true);
130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                } catch (NoSuchFieldException e) {
131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    throw new Error(e);
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return field;
134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        });
136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1388cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    public void initLocalPort(int localPort) {
1398cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        this.localport = localPort;
1408cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    }
1418cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes
1428cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    public void initRemoteAddressAndPort(InetAddress remoteAddress, int remotePort) {
1438cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        this.address = remoteAddress;
1448cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        this.port = remotePort;
1458cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    }
1468cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes
147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected synchronized int available() throws IOException {
149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // we need to check if the input has been shutdown. If so
150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // we should return that there is no data to be read
15197144c87ada735a82221d7cdf65555b8f063a05aElliott Hughes        if (shutdownInput) {
152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return 0;
153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
15449e79cdc1aadb2922178e8905a7907df0bdaf7b3Elliott Hughes        return Platform.getFileSystem().ioctlAvailable(fd);
155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
1588cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    protected void bind(InetAddress address, int port) throws IOException {
1598cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        netImpl.bind(fd, address, port);
1608cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        this.address = address;
1618cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        if (port != 0) {
1628cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes            this.localport = port;
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
1648cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes            this.localport = netImpl.getSocketLocalPort(fd);
165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void close() throws IOException {
170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (fd) {
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (fd.valid()) {
17279ff4e73fd689dae6667a8137ee57137962ff13aElliott Hughes                netImpl.close(fd);
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                fd = new FileDescriptor();
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
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 {
203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (streaming) {
204adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (NetUtil.usingSocks(proxy)) {
205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    socksConnect(anAddr, aPort, 0);
206adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                } else {
207adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    if (timeout == 0) {
208adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        netImpl.connect(fd, trafficClass, normalAddr, aPort);
209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    } else {
210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        netImpl.connectStreamWithTimeoutSocket(fd, aPort,
211adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                timeout, trafficClass, normalAddr);
212adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
213adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
2158cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes                netImpl.connectDatagram(fd, aPort, trafficClass, normalAddr);
216adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
217adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (ConnectException e) {
2188cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes            throw new ConnectException(anAddr + ":" + aPort + " - " + e.getMessage());
219adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
220adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        super.address = normalAddr;
221adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        super.port = aPort;
222adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
223adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
224adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
225adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void create(boolean streaming) throws IOException {
226adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.streaming = streaming;
227adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (streaming) {
228f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            netImpl.createStreamSocket(fd, NetUtil.preferIPv4Stack());
229adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
230adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            netImpl.createDatagramSocket(fd, NetUtil.preferIPv4Stack());
231adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
232adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
233adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
234adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
235adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void finalize() throws IOException {
236adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        close();
237adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
238adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
239adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
240adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected synchronized InputStream getInputStream() throws IOException {
241adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (!fd.valid()) {
242b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw new SocketException("Socket is closed");
243adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
245adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return new SocketInputStream(this);
246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
247adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
249adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public Object getOption(int optID) throws SocketException {
250adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (optID == SocketOptions.SO_TIMEOUT) {
251adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return Integer.valueOf(receiveTimeout);
252adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else if (optID == SocketOptions.IP_TOS) {
253adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return Integer.valueOf(trafficClass);
254adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
255fdd13e86ec613e46b68376f90d2c89c2ac33b4b5Elliott Hughes            return netImpl.getSocketOption(fd, optID);
256adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
257adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
258adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
259adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
260adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected synchronized OutputStream getOutputStream() throws IOException {
261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (!fd.valid()) {
262b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw new SocketException("Socket is closed");
263adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return new SocketOutputStream(this);
265adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
266adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
267adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
268adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void listen(int backlog) throws IOException {
269adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (NetUtil.usingSocks(proxy)) {
270adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // Do nothing for a SOCKS connection. The listen occurs on the
271adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // server during the bind.
272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return;
273adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
27497144c87ada735a82221d7cdf65555b8f063a05aElliott Hughes        netImpl.listen(fd, backlog);
275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
276adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
277adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
278adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void setOption(int optID, Object val) throws SocketException {
279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (optID == SocketOptions.SO_TIMEOUT) {
280adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            receiveTimeout = ((Integer) val).intValue();
281adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            try {
283adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                netImpl.setSocketOption(fd, optID, val);
284adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } catch (SocketException e) {
285adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // we don't throw an exception for IP_TOS even if the platform
286adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // won't let us set the requested value
287adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (optID != SocketOptions.IP_TOS) {
288adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    throw e;
289adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
290adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
291adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
292adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            /*
293adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * save this value as it is actually used differently for IPv4 and
294adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * IPv6 so we cannot get the value using the getOption. The option
295adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * is actually only set for IPv4 and a masked version of the value
296adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * will be set as only a subset of the values are allowed on the
297adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * socket. Therefore we need to retain it to return the value that
298adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * was set. We also need the value to be passed into a number of
299adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * natives so that it can be used properly with IPv6
300adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             */
301adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (optID == SocketOptions.IP_TOS) {
302adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                trafficClass = ((Integer) val).intValue();
303adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
304adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
305adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
306adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
307adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
308adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets the SOCKS proxy server port.
309adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
310adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private int socksGetServerPort() {
311adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // get socks server port from proxy. It is unnecessary to check
312adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // "socksProxyPort" property, since proxy setting should only be
313adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // determined by ProxySelector.
314adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        InetSocketAddress addr = (InetSocketAddress) proxy.address();
315adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return addr.getPort();
316adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
317adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
318adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
319adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
320adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets the InetAddress of the SOCKS proxy server.
321adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
322adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private InetAddress socksGetServerAddress() throws UnknownHostException {
323adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String proxyName;
324adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // get socks server address from proxy. It is unnecessary to check
325adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // "socksProxyHost" property, since all proxy setting should be
326adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // determined by ProxySelector.
327adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        InetSocketAddress addr = (InetSocketAddress) proxy.address();
328adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        proxyName = addr.getHostName();
329adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (null == proxyName) {
330adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            proxyName = addr.getAddress().getHostAddress();
331adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
33297144c87ada735a82221d7cdf65555b8f063a05aElliott Hughes        return InetAddress.getByName(proxyName);
333adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
334adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
335adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
336adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Connect using a SOCKS server.
337adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
338adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void socksConnect(InetAddress applicationServerAddress,
339adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int applicationServerPort, int timeout) throws IOException {
340adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
341adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (timeout == 0) {
342adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                netImpl.connect(fd, trafficClass, socksGetServerAddress(),
343adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        socksGetServerPort());
344adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
345adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                netImpl.connectStreamWithTimeoutSocket(fd,
346adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        socksGetServerPort(), timeout, trafficClass,
347adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        socksGetServerAddress());
348adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
349adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
350adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (Exception e) {
351b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw new SocketException("SOCKS connection failed: " + e);
352adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
353adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
354adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        socksRequestConnection(applicationServerAddress, applicationServerPort);
355adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
356adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        lastConnectedAddress = applicationServerAddress;
357adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        lastConnectedPort = applicationServerPort;
358adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
359adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
360adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
361adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Request a SOCKS connection to the application server given. If the
362adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * request fails to complete successfully, an exception is thrown.
363adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
364adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void socksRequestConnection(InetAddress applicationServerAddress,
365adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int applicationServerPort) throws IOException {
366adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        socksSendRequest(Socks4Message.COMMAND_CONNECT,
367adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                applicationServerAddress, applicationServerPort);
368adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Socks4Message reply = socksReadReply();
369adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (reply.getCommandOrResult() != Socks4Message.RETURN_SUCCESS) {
370adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IOException(reply.getErrorString(reply
371adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    .getCommandOrResult()));
372adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
373adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
374adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
375adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
376adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Perform an accept for a SOCKS bind.
377adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
378adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void socksAccept() throws IOException {
379adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Socks4Message reply = socksReadReply();
380adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (reply.getCommandOrResult() != Socks4Message.RETURN_SUCCESS) {
381adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IOException(reply.getErrorString(reply
382adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    .getCommandOrResult()));
383adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
384adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
385adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
386adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
387adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Shutdown the input portion of the socket.
388adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
389adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
390adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void shutdownInput() throws IOException {
391adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        shutdownInput = true;
392adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        netImpl.shutdownInput(fd);
393adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
394adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
395adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
396adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Shutdown the output portion of the socket.
397adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
398adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
399adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void shutdownOutput() throws IOException {
400adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        netImpl.shutdownOutput(fd);
401adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
402adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
403adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
404adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Bind using a SOCKS server.
405adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
406adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void socksBind() throws IOException {
407adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
408b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            netImpl.connect(fd, trafficClass, socksGetServerAddress(), socksGetServerPort());
409adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (Exception e) {
410b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw new IOException("Unable to connect to SOCKS server: " + e);
411adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
412adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
413adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // There must be a connection to an application host for the bind to
414adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // work.
415adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (lastConnectedAddress == null) {
416b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw new SocketException("Invalid SOCKS client");
417adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
418adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
419adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Use the last connected address and port in the bind request.
420adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        socksSendRequest(Socks4Message.COMMAND_BIND, lastConnectedAddress,
421adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                lastConnectedPort);
422adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Socks4Message reply = socksReadReply();
423adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
424adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (reply.getCommandOrResult() != Socks4Message.RETURN_SUCCESS) {
425adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IOException(reply.getErrorString(reply
426adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    .getCommandOrResult()));
427adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
428adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
429adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // A peculiarity of socks 4 - if the address returned is 0, use the
430adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // original socks server address.
431adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (reply.getIP() == 0) {
432adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            address = socksGetServerAddress();
433adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
434adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // IPv6 support not yet required as
435adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // currently the Socks4Message.getIP() only returns int,
436adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // so only works with IPv4 4byte addresses
437adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            byte[] replyBytes = new byte[4];
438adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            NetUtil.intToBytes(reply.getIP(), replyBytes, 0);
439adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            address = InetAddress.getByAddress(replyBytes);
440adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
441adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        localport = reply.getPort();
442adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
443adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
444adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
445adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Send a SOCKS V4 request.
446adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
447adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void socksSendRequest(int command, InetAddress address, int port)
448adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throws IOException {
449adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Socks4Message request = new Socks4Message();
450adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        request.setCommandOrResult(command);
451adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        request.setPort(port);
452adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        request.setIP(address.getAddress());
453f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        request.setUserId("default");
454adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
455adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        getOutputStream().write(request.getBytes(), 0, request.getLength());
456adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
457adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
458adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
459adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Read a SOCKS V4 reply.
460adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
461adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private Socks4Message socksReadReply() throws IOException {
462adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Socks4Message reply = new Socks4Message();
463adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int bytesRead = 0;
464adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while (bytesRead < Socks4Message.REPLY_LENGTH) {
465adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int count = getInputStream().read(reply.getBytes(), bytesRead,
466adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    Socks4Message.REPLY_LENGTH - bytesRead);
467adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (-1 == count) {
468adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                break;
469adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
470adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            bytesRead += count;
471adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
472adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (Socks4Message.REPLY_LENGTH != bytesRead) {
473b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw new SocketException("Malformed reply from SOCKS server");
474adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
475adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return reply;
476adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
477adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
478adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
479adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void connect(SocketAddress remoteAddr, int timeout)
480adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throws IOException {
481adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        InetSocketAddress inetAddr = (InetSocketAddress) remoteAddr;
482adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        connect(inetAddr.getAddress(), inetAddr.getPort(), timeout);
483adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
484adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
485adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
486adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected boolean supportsUrgentData() {
48779ff4e73fd689dae6667a8137ee57137962ff13aElliott Hughes        return true;
488adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
489adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
490adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
491adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void sendUrgentData(int value) throws IOException {
492adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        netImpl.sendUrgentData(fd, (byte) value);
493adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
494adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
495adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    FileDescriptor getFD() {
496adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return fd;
497adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
498adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
499adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    int read(byte[] buffer, int offset, int count) throws IOException {
500adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (shutdownInput) {
501adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return -1;
502adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
50370882923fb227de7a54a9b1a2a4dd2c6ec8b51aeElliott Hughes        int read = netImpl.read(fd, buffer, offset, count, receiveTimeout);
504f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        // Return of zero bytes for a blocking socket means a timeout occurred
505f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        if (read == 0) {
506f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            throw new SocketTimeoutException();
507f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
508f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        // Return of -1 indicates the peer was closed
509f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        if (read == -1) {
510f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            shutdownInput = true;
511adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
512f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        return read;
513adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
514adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
515adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    int write(byte[] buffer, int offset, int count) throws IOException {
516adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (!streaming) {
517adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return netImpl.sendDatagram2(fd, buffer, offset, count, port,
518adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    address);
519adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
520d9179c4701153caeb821cf3da639b28465317508Elliott Hughes        return netImpl.write(fd, buffer, offset, count);
521adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
522adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
523