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
205d930cadc8f62aee5f18e7921296fe66a54f18abElliott Hughesimport android.system.ErrnoException;
21f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstromimport dalvik.system.CloseGuard;
22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.FileDescriptor;
23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.InputStream;
245d930cadc8f62aee5f18e7921296fe66a54f18abElliott Hughesimport java.io.IOException;
25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.OutputStream;
260eb70e31581a977afa5df3292d1c96e42e548821Elliott Hughesimport java.nio.ByteOrder;
27608263018762d64a07276b7c8f58102455ccecc8Elliott Hughesimport java.util.Arrays;
280b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughesimport libcore.io.IoBridge;
2959e4744d27231f260271dbbca406e0cc39768116Elliott Hughesimport libcore.io.Libcore;
30f934c3d2c8dd9e6bc5299cef41adace2a671637dElliott Hughesimport libcore.io.Memory;
31ff8234c90ecab9f1db368924bf92a5b16460f9b5Elliott Hughesimport libcore.io.Streams;
325d930cadc8f62aee5f18e7921296fe66a54f18abElliott Hughesimport static android.system.OsConstants.*;
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
358de7cf6bff36093dda9e25a1ab3718720cb54906Elliott Hughes * @hide used in java.nio.
36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
37f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilsonpublic class PlainSocketImpl extends SocketImpl {
38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // For SOCKS support. A SOCKS bind() uses the last
40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // host connected to in its request.
418de7cf6bff36093dda9e25a1ab3718720cb54906Elliott Hughes    private static InetAddress lastConnectedAddress;
42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
438de7cf6bff36093dda9e25a1ab3718720cb54906Elliott Hughes    private static int lastConnectedPort;
44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
457738141c52b931e103efe7ad62d32a12785bf6b1Elliott Hughes    private boolean streaming = true;
46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
477738141c52b931e103efe7ad62d32a12785bf6b1Elliott Hughes    private boolean shutdownInput;
48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
497738141c52b931e103efe7ad62d32a12785bf6b1Elliott Hughes    private Proxy proxy;
50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
5112f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom    private final CloseGuard guard = CloseGuard.get();
52f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom
53f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    public PlainSocketImpl(FileDescriptor fd) {
54f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        this.fd = fd;
55f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        if (fd.valid()) {
56f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            guard.open("close");
57f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        }
58f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    }
59f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
60f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    public PlainSocketImpl(Proxy proxy) {
616b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson        this(new FileDescriptor());
62f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        this.proxy = proxy;
63f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    }
64f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
656b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson    public PlainSocketImpl() {
666b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson        this(new FileDescriptor());
676b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson    }
686b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson
69f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    public PlainSocketImpl(FileDescriptor fd, int localport, InetAddress addr, int port) {
70f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        this.fd = fd;
71f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        this.localport = localport;
72f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        this.address = addr;
73f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        this.port = port;
74f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        if (fd.valid()) {
75f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            guard.open("close");
76f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        }
77f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    }
78f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void accept(SocketImpl newImpl) throws IOException {
810917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes        if (usingSocks()) {
82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ((PlainSocketImpl) newImpl).socksBind();
83adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ((PlainSocketImpl) newImpl).socksAccept();
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return;
85adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
86553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes
87553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes        try {
88553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes            InetSocketAddress peerAddress = new InetSocketAddress();
89553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes            FileDescriptor clientFd = Libcore.os.accept(fd, peerAddress);
90553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes
91553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes            // TODO: we can't just set newImpl.fd to clientFd because a nio SocketChannel may
92553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes            // be sharing the FileDescriptor. http://b//4452981.
93553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes            newImpl.fd.setInt$(clientFd.getInt$());
94553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes
95553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes            newImpl.address = peerAddress.getAddress();
96553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes            newImpl.port = peerAddress.getPort();
97553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes        } catch (ErrnoException errnoException) {
98f4a4259d8a548ab172ca98b702feafcd0ceb1411Elliott Hughes            if (errnoException.errno == EAGAIN) {
99553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes                throw new SocketTimeoutException(errnoException);
100553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes            }
101553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes            throw errnoException.rethrowAsSocketException();
102553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes        }
10349ff8b8582bca20a1adbda1d957220526332a8caElliott Hughes
10449ff8b8582bca20a1adbda1d957220526332a8caElliott Hughes        // Reset the client's inherited read timeout to the Java-specified default of 0.
10549ff8b8582bca20a1adbda1d957220526332a8caElliott Hughes        newImpl.setOption(SocketOptions.SO_TIMEOUT, Integer.valueOf(0));
10649ff8b8582bca20a1adbda1d957220526332a8caElliott Hughes
1070b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        newImpl.localport = IoBridge.getSocketLocalPort(newImpl.fd);
108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1100917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes    private boolean usingSocks() {
1110917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes        return proxy != null && proxy.type() == Proxy.Type.SOCKS;
1120917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes    }
1130917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes
114f9e1294b67778f9b290b9fb6eeda2d7cc7c1c3eeElliott Hughes    private void checkNotClosed() throws IOException {
115f9e1294b67778f9b290b9fb6eeda2d7cc7c1c3eeElliott Hughes        if (!fd.valid()) {
116f9e1294b67778f9b290b9fb6eeda2d7cc7c1c3eeElliott Hughes            throw new SocketException("Socket is closed");
117f9e1294b67778f9b290b9fb6eeda2d7cc7c1c3eeElliott Hughes        }
118f9e1294b67778f9b290b9fb6eeda2d7cc7c1c3eeElliott Hughes    }
119f9e1294b67778f9b290b9fb6eeda2d7cc7c1c3eeElliott Hughes
120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected synchronized int available() throws IOException {
122f9e1294b67778f9b290b9fb6eeda2d7cc7c1c3eeElliott Hughes        checkNotClosed();
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // we need to check if the input has been shutdown. If so
124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // we should return that there is no data to be read
12597144c87ada735a82221d7cdf65555b8f063a05aElliott Hughes        if (shutdownInput) {
126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return 0;
127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
1280b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        return IoBridge.available(fd);
129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1310b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    @Override protected void bind(InetAddress address, int port) throws IOException {
1320b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        IoBridge.bind(fd, address, port);
1338cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        if (port != 0) {
1348cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes            this.localport = port;
135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
1360b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            this.localport = IoBridge.getSocketLocalPort(fd);
137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
141933fbbf606268eec9fc430632b8bca7002a833b3Neil Fuller    public void onBind(InetAddress localAddress, int localPort) {
142933fbbf606268eec9fc430632b8bca7002a833b3Neil Fuller        localport = localPort;
143933fbbf606268eec9fc430632b8bca7002a833b3Neil Fuller    }
144933fbbf606268eec9fc430632b8bca7002a833b3Neil Fuller
145933fbbf606268eec9fc430632b8bca7002a833b3Neil Fuller    @Override
14658e5a8e6eeaf94d78522e0e9994c4565a3b33fdbJesse Wilson    protected synchronized void close() throws IOException {
147f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        guard.close();
148f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller        IoBridge.closeAndSignalBlockedThreads(fd);
149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
151adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
152933fbbf606268eec9fc430632b8bca7002a833b3Neil Fuller    public void onClose() {
153933fbbf606268eec9fc430632b8bca7002a833b3Neil Fuller        guard.close();
154933fbbf606268eec9fc430632b8bca7002a833b3Neil Fuller    }
155933fbbf606268eec9fc430632b8bca7002a833b3Neil Fuller
156933fbbf606268eec9fc430632b8bca7002a833b3Neil Fuller    @Override
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void connect(String aHost, int aPort) throws IOException {
15897144c87ada735a82221d7cdf65555b8f063a05aElliott Hughes        connect(InetAddress.getByName(aHost), aPort);
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void connect(InetAddress anAddr, int aPort) throws IOException {
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        connect(anAddr, aPort, 0);
164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Connects this socket to the specified remote host address/port.
168f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param anAddr
170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the remote host address to connect to
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param aPort
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the remote port to connect to
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param timeout
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            a timeout where supported. 0 means no timeout
175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if an error occurs while connecting
177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
1788cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    private void connect(InetAddress anAddr, int aPort, int timeout) throws IOException {
179f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        InetAddress normalAddr = anAddr.isAnyLocalAddress() ? InetAddress.getLocalHost() : anAddr;
180996bf79565ac88402920bd826d6f85952c83be20Elliott Hughes        if (streaming && usingSocks()) {
181996bf79565ac88402920bd826d6f85952c83be20Elliott Hughes            socksConnect(anAddr, aPort, 0);
182996bf79565ac88402920bd826d6f85952c83be20Elliott Hughes        } else {
1830b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            IoBridge.connect(fd, normalAddr, aPort, timeout);
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
185933fbbf606268eec9fc430632b8bca7002a833b3Neil Fuller        address = normalAddr;
186933fbbf606268eec9fc430632b8bca7002a833b3Neil Fuller        port = aPort;
187933fbbf606268eec9fc430632b8bca7002a833b3Neil Fuller    }
188933fbbf606268eec9fc430632b8bca7002a833b3Neil Fuller
189933fbbf606268eec9fc430632b8bca7002a833b3Neil Fuller    @Override
190933fbbf606268eec9fc430632b8bca7002a833b3Neil Fuller    public void onConnect(InetAddress remoteAddress, int remotePort) {
191933fbbf606268eec9fc430632b8bca7002a833b3Neil Fuller        address = remoteAddress;
192933fbbf606268eec9fc430632b8bca7002a833b3Neil Fuller        port = remotePort;
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void create(boolean streaming) throws IOException {
197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.streaming = streaming;
1980b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        this.fd = IoBridge.socket(streaming);
199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
201e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom    @Override protected void finalize() throws Throwable {
202e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        try {
20312f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom            if (guard != null) {
20412f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom                guard.warnIfOpen();
20512f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom            }
206e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            close();
207e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        } finally {
208e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            super.finalize();
209e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        }
210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
211adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
212608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes    @Override protected synchronized InputStream getInputStream() throws IOException {
213f9e1294b67778f9b290b9fb6eeda2d7cc7c1c3eeElliott Hughes        checkNotClosed();
214608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        return new PlainSocketInputStream(this);
215608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes    }
216608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes
217608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes    private static class PlainSocketInputStream extends InputStream {
218608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        private final PlainSocketImpl socketImpl;
219608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes
220608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        public PlainSocketInputStream(PlainSocketImpl socketImpl) {
221608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes            this.socketImpl = socketImpl;
222608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        }
223608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes
224608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        @Override public int available() throws IOException {
225608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes            return socketImpl.available();
226608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        }
227608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes
228608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        @Override public void close() throws IOException {
229608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes            socketImpl.close();
230608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        }
231608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes
232608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        @Override public int read() throws IOException {
233ff8234c90ecab9f1db368924bf92a5b16460f9b5Elliott Hughes            return Streams.readSingleByte(this);
234608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        }
235608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes
236325ff8c68ed5e530e9e1d487b9e2e6d8f8e2bd37Elliott Hughes        @Override public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException {
237325ff8c68ed5e530e9e1d487b9e2e6d8f8e2bd37Elliott Hughes            return socketImpl.read(buffer, byteOffset, byteCount);
238608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        }
239adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
240adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
2410a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    @Override public Object getOption(int option) throws SocketException {
2420b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        return IoBridge.getSocketOption(fd, option);
243adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
245608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes    @Override protected synchronized OutputStream getOutputStream() throws IOException {
246f9e1294b67778f9b290b9fb6eeda2d7cc7c1c3eeElliott Hughes        checkNotClosed();
247608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        return new PlainSocketOutputStream(this);
248608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes    }
249608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes
250608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes    private static class PlainSocketOutputStream extends OutputStream {
251608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        private final PlainSocketImpl socketImpl;
252608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes
253608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        public PlainSocketOutputStream(PlainSocketImpl socketImpl) {
254608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes            this.socketImpl = socketImpl;
255608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        }
256608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes
257608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        @Override public void close() throws IOException {
258608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes            socketImpl.close();
259608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        }
260608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes
261608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        @Override public void write(int oneByte) throws IOException {
262ff8234c90ecab9f1db368924bf92a5b16460f9b5Elliott Hughes            Streams.writeSingleByte(this, oneByte);
263608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        }
264608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes
265608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        @Override public void write(byte[] buffer, int offset, int byteCount) throws IOException {
266608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes            socketImpl.write(buffer, offset, byteCount);
267608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        }
268adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
269adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
270adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
271adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void listen(int backlog) throws IOException {
2720917c4a9d5d0115950450cdd0bb46e43a48da5dbElliott Hughes        if (usingSocks()) {
273adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // Do nothing for a SOCKS connection. The listen occurs on the
274adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // server during the bind.
275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return;
276adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
277e1502d64e937001636fca3d62b2552ef2a34d05fElliott Hughes        try {
278e1502d64e937001636fca3d62b2552ef2a34d05fElliott Hughes            Libcore.os.listen(fd, backlog);
279e1502d64e937001636fca3d62b2552ef2a34d05fElliott Hughes        } catch (ErrnoException errnoException) {
280e1502d64e937001636fca3d62b2552ef2a34d05fElliott Hughes            throw errnoException.rethrowAsSocketException();
281e1502d64e937001636fca3d62b2552ef2a34d05fElliott Hughes        }
282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
283adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
284adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
285c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes    public void setOption(int option, Object value) throws SocketException {
2860b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        IoBridge.setSocketOption(fd, option, value);
287adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
288adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
289adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
290adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets the SOCKS proxy server port.
291adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
292adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private int socksGetServerPort() {
293adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // get socks server port from proxy. It is unnecessary to check
294adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // "socksProxyPort" property, since proxy setting should only be
295adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // determined by ProxySelector.
296adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        InetSocketAddress addr = (InetSocketAddress) proxy.address();
297adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return addr.getPort();
298adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
299adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
300adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
301adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets the InetAddress of the SOCKS proxy server.
302adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
303adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private InetAddress socksGetServerAddress() throws UnknownHostException {
304adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String proxyName;
305adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // get socks server address from proxy. It is unnecessary to check
306adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // "socksProxyHost" property, since all proxy setting should be
307adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // determined by ProxySelector.
308adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        InetSocketAddress addr = (InetSocketAddress) proxy.address();
309adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        proxyName = addr.getHostName();
310b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes        if (proxyName == null) {
311adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            proxyName = addr.getAddress().getHostAddress();
312adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
31397144c87ada735a82221d7cdf65555b8f063a05aElliott Hughes        return InetAddress.getByName(proxyName);
314adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
315adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
316adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
317adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Connect using a SOCKS server.
318adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
319220c0af1763283b75617226efe3919c3e3b044c8Elliott Hughes    private void socksConnect(InetAddress applicationServerAddress, int applicationServerPort, int timeout) throws IOException {
320adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
3210b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            IoBridge.connect(fd, socksGetServerAddress(), socksGetServerPort(), timeout);
322adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (Exception e) {
323220c0af1763283b75617226efe3919c3e3b044c8Elliott Hughes            throw new SocketException("SOCKS connection failed", e);
324adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
325adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
326adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        socksRequestConnection(applicationServerAddress, applicationServerPort);
327adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
328adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        lastConnectedAddress = applicationServerAddress;
329adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        lastConnectedPort = applicationServerPort;
330adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
331adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
332adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
333adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Request a SOCKS connection to the application server given. If the
334adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * request fails to complete successfully, an exception is thrown.
335adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
336adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void socksRequestConnection(InetAddress applicationServerAddress,
337adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int applicationServerPort) throws IOException {
338adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        socksSendRequest(Socks4Message.COMMAND_CONNECT,
339adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                applicationServerAddress, applicationServerPort);
340adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Socks4Message reply = socksReadReply();
341adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (reply.getCommandOrResult() != Socks4Message.RETURN_SUCCESS) {
3428de7cf6bff36093dda9e25a1ab3718720cb54906Elliott Hughes            throw new IOException(reply.getErrorString(reply.getCommandOrResult()));
343adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
344adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
345adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
346adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
347adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Perform an accept for a SOCKS bind.
348adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
349adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void socksAccept() throws IOException {
350adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Socks4Message reply = socksReadReply();
351adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (reply.getCommandOrResult() != Socks4Message.RETURN_SUCCESS) {
3528de7cf6bff36093dda9e25a1ab3718720cb54906Elliott Hughes            throw new IOException(reply.getErrorString(reply.getCommandOrResult()));
353adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
354adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
355adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
356adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
357adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Shutdown the input portion of the socket.
358adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
359adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
360adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void shutdownInput() throws IOException {
361adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        shutdownInput = true;
36259e4744d27231f260271dbbca406e0cc39768116Elliott Hughes        try {
36359e4744d27231f260271dbbca406e0cc39768116Elliott Hughes            Libcore.os.shutdown(fd, SHUT_RD);
36459e4744d27231f260271dbbca406e0cc39768116Elliott Hughes        } catch (ErrnoException errnoException) {
365454a95f6a28855aa3c88d168b15a45bf315efc99Elliott Hughes            throw errnoException.rethrowAsSocketException();
36659e4744d27231f260271dbbca406e0cc39768116Elliott Hughes        }
367adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
368adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
369adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
370adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Shutdown the output portion of the socket.
371adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
372adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
373adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void shutdownOutput() throws IOException {
37459e4744d27231f260271dbbca406e0cc39768116Elliott Hughes        try {
37559e4744d27231f260271dbbca406e0cc39768116Elliott Hughes            Libcore.os.shutdown(fd, SHUT_WR);
37659e4744d27231f260271dbbca406e0cc39768116Elliott Hughes        } catch (ErrnoException errnoException) {
377454a95f6a28855aa3c88d168b15a45bf315efc99Elliott Hughes            throw errnoException.rethrowAsSocketException();
37859e4744d27231f260271dbbca406e0cc39768116Elliott Hughes        }
379adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
380adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
381adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
382adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Bind using a SOCKS server.
383adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
384adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void socksBind() throws IOException {
385adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
3860b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            IoBridge.connect(fd, socksGetServerAddress(), socksGetServerPort());
387adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (Exception e) {
388220c0af1763283b75617226efe3919c3e3b044c8Elliott Hughes            throw new IOException("Unable to connect to SOCKS server", e);
389adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
390adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
391220c0af1763283b75617226efe3919c3e3b044c8Elliott Hughes        // There must be a connection to an application host for the bind to work.
392adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (lastConnectedAddress == null) {
393b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw new SocketException("Invalid SOCKS client");
394adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
395adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
396adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Use the last connected address and port in the bind request.
397adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        socksSendRequest(Socks4Message.COMMAND_BIND, lastConnectedAddress,
398adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                lastConnectedPort);
399adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Socks4Message reply = socksReadReply();
400adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
401adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (reply.getCommandOrResult() != Socks4Message.RETURN_SUCCESS) {
4020eb70e31581a977afa5df3292d1c96e42e548821Elliott Hughes            throw new IOException(reply.getErrorString(reply.getCommandOrResult()));
403adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
404adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
405adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // A peculiarity of socks 4 - if the address returned is 0, use the
406adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // original socks server address.
407adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (reply.getIP() == 0) {
408adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            address = socksGetServerAddress();
409adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
410adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // IPv6 support not yet required as
411adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // currently the Socks4Message.getIP() only returns int,
412adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // so only works with IPv4 4byte addresses
413adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            byte[] replyBytes = new byte[4];
414f934c3d2c8dd9e6bc5299cef41adace2a671637dElliott Hughes            Memory.pokeInt(replyBytes, 0, reply.getIP(), ByteOrder.BIG_ENDIAN);
415adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            address = InetAddress.getByAddress(replyBytes);
416adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
417adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        localport = reply.getPort();
418adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
419adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
420adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
421adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Send a SOCKS V4 request.
422adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
4230eb70e31581a977afa5df3292d1c96e42e548821Elliott Hughes    private void socksSendRequest(int command, InetAddress address, int port) throws IOException {
424adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Socks4Message request = new Socks4Message();
425adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        request.setCommandOrResult(command);
426adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        request.setPort(port);
427adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        request.setIP(address.getAddress());
428f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        request.setUserId("default");
429adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
430adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        getOutputStream().write(request.getBytes(), 0, request.getLength());
431adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
432adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
433adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
434adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Read a SOCKS V4 reply.
435adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
436adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private Socks4Message socksReadReply() throws IOException {
437adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Socks4Message reply = new Socks4Message();
438adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int bytesRead = 0;
439adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while (bytesRead < Socks4Message.REPLY_LENGTH) {
440adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int count = getInputStream().read(reply.getBytes(), bytesRead,
441adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    Socks4Message.REPLY_LENGTH - bytesRead);
4428de7cf6bff36093dda9e25a1ab3718720cb54906Elliott Hughes            if (count == -1) {
443adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                break;
444adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
445adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            bytesRead += count;
446adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
447adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (Socks4Message.REPLY_LENGTH != bytesRead) {
448b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw new SocketException("Malformed reply from SOCKS server");
449adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
450adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return reply;
451adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
452adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
453adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
4548de7cf6bff36093dda9e25a1ab3718720cb54906Elliott Hughes    protected void connect(SocketAddress remoteAddr, int timeout) throws IOException {
455adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        InetSocketAddress inetAddr = (InetSocketAddress) remoteAddr;
456adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        connect(inetAddr.getAddress(), inetAddr.getPort(), timeout);
457adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
458adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
459adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
460adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected boolean supportsUrgentData() {
46179ff4e73fd689dae6667a8137ee57137962ff13aElliott Hughes        return true;
462adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
463adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
464adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
465adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected void sendUrgentData(int value) throws IOException {
46690d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes        try {
46790d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes            byte[] buffer = new byte[] { (byte) value };
46890d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes            Libcore.os.sendto(fd, buffer, 0, 1, MSG_OOB, null, 0);
46990d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes        } catch (ErrnoException errnoException) {
47090d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes            throw errnoException.rethrowAsSocketException();
47190d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes        }
472adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
473adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
474608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes    /**
475608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes     * For PlainSocketInputStream.
476608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes     */
477608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes    private int read(byte[] buffer, int offset, int byteCount) throws IOException {
478608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        if (byteCount == 0) {
479608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes            return 0;
480608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        }
481608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        Arrays.checkOffsetAndCount(buffer.length, offset, byteCount);
482adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (shutdownInput) {
483adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return -1;
484adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
4850b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        int readCount = IoBridge.recvfrom(true, fd, buffer, offset, byteCount, 0, null, false);
486f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        // Return of zero bytes for a blocking socket means a timeout occurred
48723ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes        if (readCount == 0) {
488f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            throw new SocketTimeoutException();
489f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
490f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        // Return of -1 indicates the peer was closed
49123ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes        if (readCount == -1) {
492f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            shutdownInput = true;
493adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
49423ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes        return readCount;
495adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
496adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
497608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes    /**
498608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes     * For PlainSocketOutputStream.
499608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes     */
500608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes    private void write(byte[] buffer, int offset, int byteCount) throws IOException {
501608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes        Arrays.checkOffsetAndCount(buffer.length, offset, byteCount);
502221d0ccb4cc23ee0bf0646e9abe471fb48b3a1a8Elliott Hughes        if (streaming) {
503608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes            while (byteCount > 0) {
5040b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                int bytesWritten = IoBridge.sendto(fd, buffer, offset, byteCount, 0, null, 0);
505608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes                byteCount -= bytesWritten;
506608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes                offset += bytesWritten;
507608263018762d64a07276b7c8f58102455ccecc8Elliott Hughes            }
508221d0ccb4cc23ee0bf0646e9abe471fb48b3a1a8Elliott Hughes        } else {
5093393bc90a5bd4498add5b70df1c43e54e5a2f843Elliott Hughes            // Unlike writes to a streaming socket, writes to a datagram
5103393bc90a5bd4498add5b70df1c43e54e5a2f843Elliott Hughes            // socket are all-or-nothing, so we don't need a loop here.
5113393bc90a5bd4498add5b70df1c43e54e5a2f843Elliott Hughes            // http://code.google.com/p/android/issues/detail?id=15304
5120b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            IoBridge.sendto(fd, buffer, offset, byteCount, 0, address, port);
513adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
514adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
515adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
516