PlainSocketImpl.java revision f4a4259d8a548ab172ca98b702feafcd0ceb1411
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
188de7cf6bff36093dda9e25a1ab3718720cb54906Elliott Hughespackage java.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.net.ConnectException;
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.InetAddress;
27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.InetSocketAddress;
28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.Proxy;
29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.SocketAddress;
30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.SocketException;
31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.SocketImpl;
32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.SocketTimeoutException;
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.UnknownHostException;
340eb70e31581a977afa5df3292d1c96e42e548821Elliott Hughesimport java.nio.ByteOrder;
35608263018762d64a07276b7c8f58102455ccecc8Elliott Hughesimport java.util.Arrays;
3659e4744d27231f260271dbbca406e0cc39768116Elliott Hughesimport libcore.io.ErrnoException;
370b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughesimport libcore.io.IoBridge;
3859e4744d27231f260271dbbca406e0cc39768116Elliott Hughesimport libcore.io.Libcore;
39f934c3d2c8dd9e6bc5299cef41adace2a671637dElliott Hughesimport libcore.io.Memory;
40ff8234c90ecab9f1db368924bf92a5b16460f9b5Elliott Hughesimport libcore.io.Streams;
4159e4744d27231f260271dbbca406e0cc39768116Elliott Hughesimport static libcore.io.OsConstants.*;
42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
448de7cf6bff36093dda9e25a1ab3718720cb54906Elliott Hughes * @hide used in java.nio.
45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
46f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilsonpublic class PlainSocketImpl extends SocketImpl {
47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // For SOCKS support. A SOCKS bind() uses the last
49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // host connected to in its request.
508de7cf6bff36093dda9e25a1ab3718720cb54906Elliott Hughes    private static InetAddress lastConnectedAddress;
51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
528de7cf6bff36093dda9e25a1ab3718720cb54906Elliott Hughes    private static int lastConnectedPort;
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        this.fd = fd;
80f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        this.localport = localport;
81f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        this.address = addr;
82f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        this.port = port;
83f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        if (fd.valid()) {
84f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            guard.open("close");
85f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        }
86f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    }
87f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void accept(SocketImpl newImpl) throws IOException {
900917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes        if (usingSocks()) {
91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ((PlainSocketImpl) newImpl).socksBind();
92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ((PlainSocketImpl) newImpl).socksAccept();
93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return;
94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
95553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes
96553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes        try {
97553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes            InetSocketAddress peerAddress = new InetSocketAddress();
98553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes            FileDescriptor clientFd = Libcore.os.accept(fd, peerAddress);
99553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes
100553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes            // TODO: we can't just set newImpl.fd to clientFd because a nio SocketChannel may
101553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes            // be sharing the FileDescriptor. http://b//4452981.
102553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes            newImpl.fd.setInt$(clientFd.getInt$());
103553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes
104553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes            newImpl.address = peerAddress.getAddress();
105553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes            newImpl.port = peerAddress.getPort();
106553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes        } catch (ErrnoException errnoException) {
107f4a4259d8a548ab172ca98b702feafcd0ceb1411Elliott Hughes            if (errnoException.errno == EAGAIN) {
108553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes                throw new SocketTimeoutException(errnoException);
109553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes            }
110553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes            throw errnoException.rethrowAsSocketException();
111553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes        }
11249ff8b8582bca20a1adbda1d957220526332a8caElliott Hughes
11349ff8b8582bca20a1adbda1d957220526332a8caElliott Hughes        // Reset the client's inherited read timeout to the Java-specified default of 0.
11449ff8b8582bca20a1adbda1d957220526332a8caElliott Hughes        newImpl.setOption(SocketOptions.SO_TIMEOUT, Integer.valueOf(0));
11549ff8b8582bca20a1adbda1d957220526332a8caElliott Hughes
1160b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        newImpl.localport = IoBridge.getSocketLocalPort(newImpl.fd);
117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1190917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes    private boolean usingSocks() {
1200917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes        return proxy != null && proxy.type() == Proxy.Type.SOCKS;
1210917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes    }
1220917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes
1238cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    public void initLocalPort(int localPort) {
1248cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        this.localport = localPort;
1258cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    }
1268cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes
1278cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    public void initRemoteAddressAndPort(InetAddress remoteAddress, int remotePort) {
1288cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        this.address = remoteAddress;
1298cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        this.port = remotePort;
1308cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    }
1318cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes
132f9e1294b67778f9b290b9fb6eeda2d7cc7c1c3eeElliott Hughes    private void checkNotClosed() throws IOException {
133f9e1294b67778f9b290b9fb6eeda2d7cc7c1c3eeElliott Hughes        if (!fd.valid()) {
134f9e1294b67778f9b290b9fb6eeda2d7cc7c1c3eeElliott Hughes            throw new SocketException("Socket is closed");
135f9e1294b67778f9b290b9fb6eeda2d7cc7c1c3eeElliott Hughes        }
136f9e1294b67778f9b290b9fb6eeda2d7cc7c1c3eeElliott Hughes    }
137f9e1294b67778f9b290b9fb6eeda2d7cc7c1c3eeElliott Hughes
138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected synchronized int available() throws IOException {
140f9e1294b67778f9b290b9fb6eeda2d7cc7c1c3eeElliott Hughes        checkNotClosed();
141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // we need to check if the input has been shutdown. If so
142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // we should return that there is no data to be read
14397144c87ada735a82221d7cdf65555b8f063a05aElliott Hughes        if (shutdownInput) {
144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return 0;
145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
1460b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        return IoBridge.available(fd);
147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1490b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    @Override protected void bind(InetAddress address, int port) throws IOException {
1500b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        IoBridge.bind(fd, address, port);
1518cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        this.address = address;
1528cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        if (port != 0) {
1538cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes            this.localport = port;
154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
1550b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            this.localport = IoBridge.getSocketLocalPort(fd);
156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
16058e5a8e6eeaf94d78522e0e9994c4565a3b33fdbJesse Wilson    protected synchronized void close() throws IOException {
161f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        guard.close();
1620b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        IoBridge.closeSocket(fd);
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void connect(String aHost, int aPort) throws IOException {
16797144c87ada735a82221d7cdf65555b8f063a05aElliott Hughes        connect(InetAddress.getByName(aHost), aPort);
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void connect(InetAddress anAddr, int aPort) throws IOException {
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        connect(anAddr, aPort, 0);
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Connects this socket to the specified remote host address/port.
177f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param anAddr
179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the remote host address to connect to
180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param aPort
181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the remote port to connect to
182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param timeout
183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            a timeout where supported. 0 means no timeout
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if an error occurs while connecting
186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
1878cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    private void connect(InetAddress anAddr, int aPort, int timeout) throws IOException {
188f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        InetAddress normalAddr = anAddr.isAnyLocalAddress() ? InetAddress.getLocalHost() : anAddr;
189996bf79565ac88402920bd826d6f85952c83be20Elliott Hughes        if (streaming && usingSocks()) {
190996bf79565ac88402920bd826d6f85952c83be20Elliott Hughes            socksConnect(anAddr, aPort, 0);
191996bf79565ac88402920bd826d6f85952c83be20Elliott Hughes        } else {
1920b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            IoBridge.connect(fd, normalAddr, aPort, timeout);
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        super.address = normalAddr;
195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        super.port = aPort;
196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void create(boolean streaming) throws IOException {
200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.streaming = streaming;
2010b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        this.fd = IoBridge.socket(streaming);
202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
204e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom    @Override protected void finalize() throws Throwable {
205e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        try {
20612f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom            if (guard != null) {
20712f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom                guard.warnIfOpen();
20812f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom            }
209e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            close();
210e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        } finally {
211e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            super.finalize();
212e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        }
213adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
215608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes    @Override protected synchronized InputStream getInputStream() throws IOException {
216f9e1294b67778f9b290b9fb6eeda2d7cc7c1c3eeElliott Hughes        checkNotClosed();
217608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        return new PlainSocketInputStream(this);
218608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes    }
219608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes
220608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes    private static class PlainSocketInputStream extends InputStream {
221608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        private final PlainSocketImpl socketImpl;
222608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes
223608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        public PlainSocketInputStream(PlainSocketImpl socketImpl) {
224608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes            this.socketImpl = socketImpl;
225608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        }
226608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes
227608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        @Override public int available() throws IOException {
228608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes            return socketImpl.available();
229608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        }
230608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes
231608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        @Override public void close() throws IOException {
232608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes            socketImpl.close();
233608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        }
234608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes
235608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        @Override public int read() throws IOException {
236ff8234c90ecab9f1db368924bf92a5b16460f9b5Elliott Hughes            return Streams.readSingleByte(this);
237608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        }
238608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes
239608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        @Override public int read(byte[] buffer, int offset, int byteCount) throws IOException {
240608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes            return socketImpl.read(buffer, offset, byteCount);
241608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        }
242adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
243adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
2440a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    @Override public Object getOption(int option) throws SocketException {
2450b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        return IoBridge.getSocketOption(fd, option);
246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
247adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
248608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes    @Override protected synchronized OutputStream getOutputStream() throws IOException {
249f9e1294b67778f9b290b9fb6eeda2d7cc7c1c3eeElliott Hughes        checkNotClosed();
250608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        return new PlainSocketOutputStream(this);
251608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes    }
252608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes
253608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes    private static class PlainSocketOutputStream extends OutputStream {
254608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        private final PlainSocketImpl socketImpl;
255608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes
256608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        public PlainSocketOutputStream(PlainSocketImpl socketImpl) {
257608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes            this.socketImpl = socketImpl;
258608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        }
259608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes
260608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        @Override public void close() throws IOException {
261608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes            socketImpl.close();
262608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        }
263608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes
264608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        @Override public void write(int oneByte) throws IOException {
265ff8234c90ecab9f1db368924bf92a5b16460f9b5Elliott Hughes            Streams.writeSingleByte(this, oneByte);
266608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        }
267608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes
268608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        @Override public void write(byte[] buffer, int offset, int byteCount) throws IOException {
269608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes            socketImpl.write(buffer, offset, byteCount);
270608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        }
271adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
273adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
274adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void listen(int backlog) throws IOException {
2750917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes        if (usingSocks()) {
276adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // Do nothing for a SOCKS connection. The listen occurs on the
277adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // server during the bind.
278adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return;
279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
280e1502d64e937001636fca3d62b2552ef2a34d05fElliott Hughes        try {
281e1502d64e937001636fca3d62b2552ef2a34d05fElliott Hughes            Libcore.os.listen(fd, backlog);
282e1502d64e937001636fca3d62b2552ef2a34d05fElliott Hughes        } catch (ErrnoException errnoException) {
283e1502d64e937001636fca3d62b2552ef2a34d05fElliott Hughes            throw errnoException.rethrowAsSocketException();
284e1502d64e937001636fca3d62b2552ef2a34d05fElliott Hughes        }
285adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
286adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
287adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
288c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes    public void setOption(int option, Object value) throws SocketException {
2890b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        IoBridge.setSocketOption(fd, option, value);
290adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
291adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
292adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
293adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets the SOCKS proxy server port.
294adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
295adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private int socksGetServerPort() {
296adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // get socks server port from proxy. It is unnecessary to check
297adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // "socksProxyPort" property, since proxy setting should only be
298adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // determined by ProxySelector.
299adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        InetSocketAddress addr = (InetSocketAddress) proxy.address();
300adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return addr.getPort();
301adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
302adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
303adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
304adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets the InetAddress of the SOCKS proxy server.
305adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
306adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private InetAddress socksGetServerAddress() throws UnknownHostException {
307adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String proxyName;
308adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // get socks server address from proxy. It is unnecessary to check
309adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // "socksProxyHost" property, since all proxy setting should be
310adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // determined by ProxySelector.
311adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        InetSocketAddress addr = (InetSocketAddress) proxy.address();
312adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        proxyName = addr.getHostName();
313b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes        if (proxyName == null) {
314adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            proxyName = addr.getAddress().getHostAddress();
315adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
31697144c87ada735a82221d7cdf65555b8f063a05aElliott Hughes        return InetAddress.getByName(proxyName);
317adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
318adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
319adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
320adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Connect using a SOCKS server.
321adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
322220c0af1763283b75617226efe3919c3e3b044c8Elliott Hughes    private void socksConnect(InetAddress applicationServerAddress, int applicationServerPort, int timeout) throws IOException {
323adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
3240b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            IoBridge.connect(fd, socksGetServerAddress(), socksGetServerPort(), timeout);
325adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (Exception e) {
326220c0af1763283b75617226efe3919c3e3b044c8Elliott Hughes            throw new SocketException("SOCKS connection failed", e);
327adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
328adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
329adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        socksRequestConnection(applicationServerAddress, applicationServerPort);
330adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
331adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        lastConnectedAddress = applicationServerAddress;
332adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        lastConnectedPort = applicationServerPort;
333adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
334adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
335adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
336adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Request a SOCKS connection to the application server given. If the
337adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * request fails to complete successfully, an exception is thrown.
338adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
339adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void socksRequestConnection(InetAddress applicationServerAddress,
340adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int applicationServerPort) throws IOException {
341adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        socksSendRequest(Socks4Message.COMMAND_CONNECT,
342adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                applicationServerAddress, applicationServerPort);
343adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Socks4Message reply = socksReadReply();
344adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (reply.getCommandOrResult() != Socks4Message.RETURN_SUCCESS) {
3458de7cf6bff36093dda9e25a1ab3718720cb54906Elliott Hughes            throw new IOException(reply.getErrorString(reply.getCommandOrResult()));
346adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
347adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
348adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
349adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
350adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Perform an accept for a SOCKS bind.
351adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
352adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void socksAccept() throws IOException {
353adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Socks4Message reply = socksReadReply();
354adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (reply.getCommandOrResult() != Socks4Message.RETURN_SUCCESS) {
3558de7cf6bff36093dda9e25a1ab3718720cb54906Elliott Hughes            throw new IOException(reply.getErrorString(reply.getCommandOrResult()));
356adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
357adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
358adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
359adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
360adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Shutdown the input portion of the socket.
361adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
362adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
363adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void shutdownInput() throws IOException {
364adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        shutdownInput = true;
36559e4744d27231f260271dbbca406e0cc39768116Elliott Hughes        try {
36659e4744d27231f260271dbbca406e0cc39768116Elliott Hughes            Libcore.os.shutdown(fd, SHUT_RD);
36759e4744d27231f260271dbbca406e0cc39768116Elliott Hughes        } catch (ErrnoException errnoException) {
368454a95f6a28855aa3c88d168b15a45bf315efc99Elliott Hughes            throw errnoException.rethrowAsSocketException();
36959e4744d27231f260271dbbca406e0cc39768116Elliott Hughes        }
370adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
371adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
372adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
373adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Shutdown the output portion of the socket.
374adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
375adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
376adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void shutdownOutput() throws IOException {
37759e4744d27231f260271dbbca406e0cc39768116Elliott Hughes        try {
37859e4744d27231f260271dbbca406e0cc39768116Elliott Hughes            Libcore.os.shutdown(fd, SHUT_WR);
37959e4744d27231f260271dbbca406e0cc39768116Elliott Hughes        } catch (ErrnoException errnoException) {
380454a95f6a28855aa3c88d168b15a45bf315efc99Elliott Hughes            throw errnoException.rethrowAsSocketException();
38159e4744d27231f260271dbbca406e0cc39768116Elliott Hughes        }
382adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
383adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
384adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
385adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Bind using a SOCKS server.
386adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
387adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void socksBind() throws IOException {
388adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
3890b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            IoBridge.connect(fd, socksGetServerAddress(), socksGetServerPort());
390adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (Exception e) {
391220c0af1763283b75617226efe3919c3e3b044c8Elliott Hughes            throw new IOException("Unable to connect to SOCKS server", e);
392adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
393adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
394220c0af1763283b75617226efe3919c3e3b044c8Elliott Hughes        // There must be a connection to an application host for the bind to work.
395adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (lastConnectedAddress == null) {
396b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw new SocketException("Invalid SOCKS client");
397adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
398adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
399adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Use the last connected address and port in the bind request.
400adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        socksSendRequest(Socks4Message.COMMAND_BIND, lastConnectedAddress,
401adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                lastConnectedPort);
402adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Socks4Message reply = socksReadReply();
403adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
404adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (reply.getCommandOrResult() != Socks4Message.RETURN_SUCCESS) {
4050eb70e31581a977afa5df3292d1c96e42e548821Elliott Hughes            throw new IOException(reply.getErrorString(reply.getCommandOrResult()));
406adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
407adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
408adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // A peculiarity of socks 4 - if the address returned is 0, use the
409adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // original socks server address.
410adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (reply.getIP() == 0) {
411adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            address = socksGetServerAddress();
412adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
413adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // IPv6 support not yet required as
414adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // currently the Socks4Message.getIP() only returns int,
415adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // so only works with IPv4 4byte addresses
416adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            byte[] replyBytes = new byte[4];
417f934c3d2c8dd9e6bc5299cef41adace2a671637dElliott Hughes            Memory.pokeInt(replyBytes, 0, reply.getIP(), ByteOrder.BIG_ENDIAN);
418adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            address = InetAddress.getByAddress(replyBytes);
419adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
420adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        localport = reply.getPort();
421adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
422adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
423adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
424adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Send a SOCKS V4 request.
425adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
4260eb70e31581a977afa5df3292d1c96e42e548821Elliott Hughes    private void socksSendRequest(int command, InetAddress address, int port) throws IOException {
427adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Socks4Message request = new Socks4Message();
428adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        request.setCommandOrResult(command);
429adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        request.setPort(port);
430adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        request.setIP(address.getAddress());
431f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        request.setUserId("default");
432adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
433adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        getOutputStream().write(request.getBytes(), 0, request.getLength());
434adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
435adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
436adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
437adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Read a SOCKS V4 reply.
438adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
439adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private Socks4Message socksReadReply() throws IOException {
440adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Socks4Message reply = new Socks4Message();
441adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int bytesRead = 0;
442adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while (bytesRead < Socks4Message.REPLY_LENGTH) {
443adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int count = getInputStream().read(reply.getBytes(), bytesRead,
444adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    Socks4Message.REPLY_LENGTH - bytesRead);
4458de7cf6bff36093dda9e25a1ab3718720cb54906Elliott Hughes            if (count == -1) {
446adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                break;
447adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
448adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            bytesRead += count;
449adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
450adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (Socks4Message.REPLY_LENGTH != bytesRead) {
451b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw new SocketException("Malformed reply from SOCKS server");
452adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
453adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return reply;
454adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
455adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
456adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
4578de7cf6bff36093dda9e25a1ab3718720cb54906Elliott Hughes    protected void connect(SocketAddress remoteAddr, int timeout) throws IOException {
458adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        InetSocketAddress inetAddr = (InetSocketAddress) remoteAddr;
459adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        connect(inetAddr.getAddress(), inetAddr.getPort(), timeout);
460adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
461adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
462adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
463adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected boolean supportsUrgentData() {
46479ff4e73fd689dae6667a8137ee57137962ff13aElliott Hughes        return true;
465adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
466adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
467adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
468adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void sendUrgentData(int value) throws IOException {
46990d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes        try {
47090d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes            byte[] buffer = new byte[] { (byte) value };
47190d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes            Libcore.os.sendto(fd, buffer, 0, 1, MSG_OOB, null, 0);
47290d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes        } catch (ErrnoException errnoException) {
47390d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes            throw errnoException.rethrowAsSocketException();
47490d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes        }
475adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
476adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
477608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes    /**
478608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes     * For PlainSocketInputStream.
479608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes     */
480608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes    private int read(byte[] buffer, int offset, int byteCount) throws IOException {
481608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        if (byteCount == 0) {
482608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes            return 0;
483608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        }
484608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        Arrays.checkOffsetAndCount(buffer.length, offset, byteCount);
485adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (shutdownInput) {
486adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return -1;
487adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
4880b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        int readCount = IoBridge.recvfrom(true, fd, buffer, offset, byteCount, 0, null, false);
489f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        // Return of zero bytes for a blocking socket means a timeout occurred
49023ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes        if (readCount == 0) {
491f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            throw new SocketTimeoutException();
492f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
493f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        // Return of -1 indicates the peer was closed
49423ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes        if (readCount == -1) {
495f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            shutdownInput = true;
496adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
49723ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes        return readCount;
498adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
499adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
500608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes    /**
501608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes     * For PlainSocketOutputStream.
502608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes     */
503608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes    private void write(byte[] buffer, int offset, int byteCount) throws IOException {
504608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        Arrays.checkOffsetAndCount(buffer.length, offset, byteCount);
505221d0ccb4cc23ee0bf0646e9abe471fb48b3a1a8Elliott Hughes        if (streaming) {
506608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes            while (byteCount > 0) {
5070b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                int bytesWritten = IoBridge.sendto(fd, buffer, offset, byteCount, 0, null, 0);
508608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes                byteCount -= bytesWritten;
509608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes                offset += bytesWritten;
510608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes            }
511221d0ccb4cc23ee0bf0646e9abe471fb48b3a1a8Elliott Hughes        } else {
5123393bc90a5bd4498add5b70df1c43e54e5a2f843Elliott Hughes            // Unlike writes to a streaming socket, writes to a datagram
5133393bc90a5bd4498add5b70df1c43e54e5a2f843Elliott Hughes            // socket are all-or-nothing, so we don't need a loop here.
5143393bc90a5bd4498add5b70df1c43e54e5a2f843Elliott Hughes            // http://code.google.com/p/android/issues/detail?id=15304
5150b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            IoBridge.sendto(fd, buffer, offset, byteCount, 0, address, port);
516adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
517adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
518adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
519