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
18ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughespackage java.nio;
19f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.FileDescriptor;
21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.IOException;
22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.InputStream;
23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.OutputStream;
24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.ConnectException;
259229d47c1288e25ead3a2dc27fac8a4a2ee932a3Elliott Hughesimport java.net.Inet4Address;
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.InetAddress;
27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.InetSocketAddress;
288de7cf6bff36093dda9e25a1ab3718720cb54906Elliott Hughesimport java.net.PlainSocketImpl;
29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.Socket;
30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.SocketAddress;
31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.SocketException;
320371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughesimport java.net.SocketUtils;
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.UnknownHostException;
34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.channels.AlreadyConnectedException;
35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.channels.ClosedChannelException;
36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.channels.ConnectionPendingException;
37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.channels.IllegalBlockingModeException;
38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.channels.NoConnectionPendingException;
39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.channels.NotYetConnectedException;
40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.channels.SocketChannel;
41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.channels.UnresolvedAddressException;
42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.channels.UnsupportedAddressTypeException;
43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.channels.spi.SelectorProvider;
44a1603838fe9e865575c87982e32c6343740e464cElliott Hughesimport java.util.Arrays;
45454a95f6a28855aa3c88d168b15a45bf315efc99Elliott Hughesimport libcore.io.ErrnoException;
46454a95f6a28855aa3c88d168b15a45bf315efc99Elliott Hughesimport libcore.io.Libcore;
470b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughesimport libcore.io.IoBridge;
4899a89dd6f0a0e1396aa9b3feebf15ea31f703d3aElliott Hughesimport libcore.io.IoUtils;
49454a95f6a28855aa3c88d168b15a45bf315efc99Elliott Hughesimport static libcore.io.OsConstants.*;
50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The default implementation class of java.nio.channels.SocketChannel.
53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
54d320e321d5567a4ac94b6e5874eda4b1f1189e13Elliott Hughesclass SocketChannelImpl extends SocketChannel implements FileDescriptorChannel {
5549ff8b8582bca20a1adbda1d957220526332a8caElliott Hughes    private static final int SOCKET_STATUS_UNINITIALIZED = -1;
56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
57f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    // Status before connect.
5849ff8b8582bca20a1adbda1d957220526332a8caElliott Hughes    private static final int SOCKET_STATUS_UNCONNECTED = 0;
59adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
60f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    // Status connection pending.
6149ff8b8582bca20a1adbda1d957220526332a8caElliott Hughes    private static final int SOCKET_STATUS_PENDING = 1;
62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
63f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    // Status after connection success.
6449ff8b8582bca20a1adbda1d957220526332a8caElliott Hughes    private static final int SOCKET_STATUS_CONNECTED = 2;
65adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
66f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    // Status closed.
6749ff8b8582bca20a1adbda1d957220526332a8caElliott Hughes    private static final int SOCKET_STATUS_CLOSED = 3;
68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
6949ff8b8582bca20a1adbda1d957220526332a8caElliott Hughes    private final FileDescriptor fd;
70adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // Our internal Socket.
728cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    private SocketAdapter socket = null;
73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // The address to be connected.
7549ff8b8582bca20a1adbda1d957220526332a8caElliott Hughes    private InetSocketAddress connectAddress = null;
76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7749ff8b8582bca20a1adbda1d957220526332a8caElliott Hughes    private InetAddress localAddress = null;
7849ff8b8582bca20a1adbda1d957220526332a8caElliott Hughes    private int localPort;
79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
8049ff8b8582bca20a1adbda1d957220526332a8caElliott Hughes    private int status = SOCKET_STATUS_UNINITIALIZED;
81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
82f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    // Whether the socket is bound.
8349ff8b8582bca20a1adbda1d957220526332a8caElliott Hughes    private volatile boolean isBound = false;
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
855e23b687ef8b3c696d54d1880b454942875665b7Elliott Hughes    private final Object readLock = new Object();
86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
875e23b687ef8b3c696d54d1880b454942875665b7Elliott Hughes    private final Object writeLock = new Object();
88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
90f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * Constructor for creating a connected socket channel.
91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
928cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    public SocketChannelImpl(SelectorProvider selectorProvider) throws IOException {
93f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        this(selectorProvider, true);
94f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    }
95f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
96f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    /*
97f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * Constructor for creating an optionally connected socket channel.
98f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     */
998cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    public SocketChannelImpl(SelectorProvider selectorProvider, boolean connect) throws IOException {
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        super(selectorProvider);
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        status = SOCKET_STATUS_UNCONNECTED;
1020b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        fd = (connect ? IoBridge.socket(true) : new FileDescriptor());
103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
1063218082325b6b8713a8ac15731482e3da86a7df9Elliott Hughes     * Constructor for use by Pipe.SinkChannel and Pipe.SourceChannel.
1073218082325b6b8713a8ac15731482e3da86a7df9Elliott Hughes     */
1083218082325b6b8713a8ac15731482e3da86a7df9Elliott Hughes    public SocketChannelImpl(SelectorProvider selectorProvider, FileDescriptor existingFd) throws IOException {
1093218082325b6b8713a8ac15731482e3da86a7df9Elliott Hughes        super(selectorProvider);
1103218082325b6b8713a8ac15731482e3da86a7df9Elliott Hughes        status = SOCKET_STATUS_CONNECTED;
1113218082325b6b8713a8ac15731482e3da86a7df9Elliott Hughes        fd = existingFd;
1123218082325b6b8713a8ac15731482e3da86a7df9Elliott Hughes    }
1133218082325b6b8713a8ac15731482e3da86a7df9Elliott Hughes
1143218082325b6b8713a8ac15731482e3da86a7df9Elliott Hughes    /*
115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Getting the internal Socket If we have not the socket, we create a new
116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * one.
117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    synchronized public Socket socket() {
1208cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        if (socket == null) {
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            try {
122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                InetAddress addr = null;
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                int port = 0;
124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (connectAddress != null) {
125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    addr = connectAddress.getAddress();
126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    port = connectAddress.getPort();
127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
1288cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes                socket = new SocketAdapter(new PlainSocketImpl(fd, localPort, addr, port), this);
129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } catch (SocketException e) {
130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return null;
131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return socket;
134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    synchronized public boolean isConnected() {
138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return status == SOCKET_STATUS_CONNECTED;
139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
142f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * Status setting used by other class.
143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    synchronized void setConnected() {
145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        status = SOCKET_STATUS_CONNECTED;
146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    void setBound(boolean flag) {
149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        isBound = flag;
150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
151adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    synchronized public boolean isConnectionPending() {
154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return status == SOCKET_STATUS_PENDING;
155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean connect(SocketAddress socketAddress) throws IOException {
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // status must be open and unconnected
160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        checkUnconnected();
161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // check the address
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        InetSocketAddress inetSocketAddress = validateAddress(socketAddress);
164f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        InetAddress normalAddr = inetSocketAddress.getAddress();
16562e34a21db1cbef5d2cec186ee4f15c5ec39d187Elliott Hughes        int port = inetSocketAddress.getPort();
166f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
167220c0af1763283b75617226efe3919c3e3b044c8Elliott Hughes        // When connecting, map ANY address to localhost
168f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        if (normalAddr.isAnyLocalAddress()) {
169f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            normalAddr = InetAddress.getLocalHost();
170f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        boolean finished = false;
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (isBlocking()) {
175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                begin();
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
1770b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            finished = IoBridge.connect(fd, normalAddr, port);
178d6ecf9222ec65a08e99f15fcc4ec024f0fffd13aElliott Hughes            isBound = finished;
179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (IOException e) {
180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (e instanceof ConnectException && !isBlocking()) {
181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                status = SOCKET_STATUS_PENDING;
182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (isOpen()) {
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    close();
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    finished = true;
186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throw e;
188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } finally {
190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (isBlocking()) {
191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                end(finished);
192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1958cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        initLocalAddressAndPort();
196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        connectAddress = inetSocketAddress;
1978cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        if (socket != null) {
1988cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes            socket.socketImpl().initRemoteAddressAndPort(connectAddress.getAddress(),
1998cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes                    connectAddress.getPort());
2008cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        }
2018cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes
202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (this) {
203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (isBlocking()) {
2048cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes                status = (finished ? SOCKET_STATUS_CONNECTED : SOCKET_STATUS_UNCONNECTED);
205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
206adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                status = SOCKET_STATUS_PENDING;
207adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
208adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return finished;
210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
211adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
2128cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    private void initLocalAddressAndPort() {
2139b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes        SocketAddress sa;
2149b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes        try {
2159b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes            sa = Libcore.os.getsockname(fd);
2169b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes        } catch (ErrnoException errnoException) {
2179b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes            throw new AssertionError(errnoException);
2189b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes        }
2190a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes        InetSocketAddress isa = (InetSocketAddress) sa;
2200a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes        localAddress = isa.getAddress();
2210a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes        localPort = isa.getPort();
2228cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        if (socket != null) {
2238cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes            socket.socketImpl().initLocalPort(localPort);
2248cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        }
2258cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    }
2268cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes
227adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
228adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean finishConnect() throws IOException {
229adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (this) {
230adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (!isOpen()) {
231adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throw new ClosedChannelException();
232adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
233adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (status == SOCKET_STATUS_CONNECTED) {
234adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return true;
235adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
236adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (status != SOCKET_STATUS_PENDING) {
237adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throw new NoConnectionPendingException();
238adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
239adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
240adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
241adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        boolean finished = false;
242adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
243adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            begin();
2442bad9bff258de6275bd3847e5e9f3169b0a93c61Elliott Hughes            InetAddress inetAddress = connectAddress.getAddress();
2452bad9bff258de6275bd3847e5e9f3169b0a93c61Elliott Hughes            int port = connectAddress.getPort();
2460b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            finished = IoBridge.isConnected(fd, inetAddress, port, 0, 0); // Return immediately.
247adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            isBound = finished;
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (ConnectException e) {
249adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (isOpen()) {
250adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                close();
251adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                finished = true;
252adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
253adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw e;
254adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } finally {
255adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            end(finished);
256adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
257adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
258adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (this) {
259adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            status = (finished ? SOCKET_STATUS_CONNECTED : status);
260adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            isBound = finished;
261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
262adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return finished;
263adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
2658cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    void finishAccept() {
2668cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        initLocalAddressAndPort();
2678cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes    }
2688cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes
269adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
27023ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes    public int read(ByteBuffer dst) throws IOException {
271e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes        dst.checkWritable();
272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        checkOpenConnected();
27323ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes        if (!dst.hasRemaining()) {
274adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return 0;
275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
27623ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes        return readImpl(dst);
277adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
278adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
280d85168bd730e513cb0bd561030da3f7ea5044725Elliott Hughes    public long read(ByteBuffer[] targets, int offset, int length) throws IOException {
281a1603838fe9e865575c87982e32c6343740e464cElliott Hughes        Arrays.checkOffsetAndCount(targets.length, offset, length);
282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        checkOpenConnected();
2832620ff9a08ce7fc6d66b60784b1eecd78eb001baElliott Hughes        int totalCount = FileChannelImpl.calculateTotalRemaining(targets, offset, length, true);
284d85168bd730e513cb0bd561030da3f7ea5044725Elliott Hughes        if (totalCount == 0) {
285adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return 0;
286adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
287adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        byte[] readArray = new byte[totalCount];
288adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        ByteBuffer readBuffer = ByteBuffer.wrap(readArray);
289adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int readCount;
29023ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes        // read data to readBuffer, and then transfer data from readBuffer to targets.
291adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        readCount = readImpl(readBuffer);
29223ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes        readBuffer.flip();
293adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (readCount > 0) {
294adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int left = readCount;
295adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int index = offset;
296adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // transfer data from readArray to targets
297adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            while (left > 0) {
298adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                int putLength = Math.min(targets[index].remaining(), left);
299adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                targets[index].put(readArray, readCount - left, putLength);
300adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                index++;
301adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                left -= putLength;
302adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
303adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
304adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return readCount;
305adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
306adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
30723ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes    private int readImpl(ByteBuffer dst) throws IOException {
308f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        synchronized (readLock) {
309adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int readCount = 0;
310adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            try {
311adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (isBlocking()) {
312adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    begin();
313adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
3140b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                readCount = IoBridge.recvfrom(true, fd, dst, 0, null, false);
315a28bc96d63595a77fa918da8ccdda50e9eaae95eElliott Hughes                if (readCount > 0) {
316a28bc96d63595a77fa918da8ccdda50e9eaae95eElliott Hughes                    dst.position(dst.position() + readCount);
317a28bc96d63595a77fa918da8ccdda50e9eaae95eElliott Hughes                }
318adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } finally {
319adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (isBlocking()) {
320adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    end(readCount > 0);
321adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
322adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
32323ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes            return readCount;
324adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
325adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
326adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
327adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
32823ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes    public int write(ByteBuffer src) throws IOException {
32923ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes        if (src == null) {
330d43b9ef11a1095967a3396b246639b563e1a4128Kenny Root            throw new NullPointerException("src == null");
331adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
332adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        checkOpenConnected();
33323ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes        if (!src.hasRemaining()) {
334adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return 0;
335adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
33623ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes        return writeImpl(src);
337adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
338adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
339adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
340d85168bd730e513cb0bd561030da3f7ea5044725Elliott Hughes    public long write(ByteBuffer[] sources, int offset, int length) throws IOException {
341a1603838fe9e865575c87982e32c6343740e464cElliott Hughes        Arrays.checkOffsetAndCount(sources.length, offset, length);
342adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        checkOpenConnected();
3432620ff9a08ce7fc6d66b60784b1eecd78eb001baElliott Hughes        int count = FileChannelImpl.calculateTotalRemaining(sources, offset, length, false);
344d85168bd730e513cb0bd561030da3f7ea5044725Elliott Hughes        if (count == 0) {
345adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return 0;
346adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
347adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        ByteBuffer writeBuf = ByteBuffer.allocate(count);
348f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        for (int val = offset; val < length + offset; val++) {
349adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ByteBuffer source = sources[val];
350adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int oldPosition = source.position();
351adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            writeBuf.put(source);
352adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            source.position(oldPosition);
353adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
354adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        writeBuf.flip();
355adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int result = writeImpl(writeBuf);
356adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int val = offset;
357adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int written = result;
358adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while (result > 0) {
359adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ByteBuffer source = sources[val];
360adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int gap = Math.min(result, source.remaining());
361adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            source.position(source.position() + gap);
362adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            val++;
363adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            result -= gap;
364adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
365adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return written;
366adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
367adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
36823ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes    private int writeImpl(ByteBuffer src) throws IOException {
369f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        synchronized (writeLock) {
37023ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes            if (!src.hasRemaining()) {
371adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return 0;
372adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
373adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int writeCount = 0;
374adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            try {
375adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (isBlocking()) {
376adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    begin();
377adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
3780b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                writeCount = IoBridge.sendto(fd, src, 0, null, 0);
379a28bc96d63595a77fa918da8ccdda50e9eaae95eElliott Hughes                if (writeCount > 0) {
380a28bc96d63595a77fa918da8ccdda50e9eaae95eElliott Hughes                    src.position(src.position() + writeCount);
381a28bc96d63595a77fa918da8ccdda50e9eaae95eElliott Hughes                }
382adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } finally {
383adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (isBlocking()) {
384adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    end(writeCount >= 0);
385adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
386adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
387adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return writeCount;
388adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
389adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
390adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
391adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
392f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * Status check, open and "connected", when read and write.
393adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
3942620ff9a08ce7fc6d66b60784b1eecd78eb001baElliott Hughes    synchronized private void checkOpenConnected() throws ClosedChannelException {
395adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (!isOpen()) {
396adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new ClosedChannelException();
397adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
398adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (!isConnected()) {
399adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new NotYetConnectedException();
400adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
401adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
402adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
403adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
404f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * Status check, open and "unconnected", before connection.
405adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
406adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    synchronized private void checkUnconnected() throws IOException {
407adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (!isOpen()) {
408adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new ClosedChannelException();
409adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
410adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (status == SOCKET_STATUS_CONNECTED) {
411adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new AlreadyConnectedException();
412adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
413adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (status == SOCKET_STATUS_PENDING) {
414adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new ConnectionPendingException();
415adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
416adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
417adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
418adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
419f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * Shared by this class and DatagramChannelImpl, to do the address transfer
420adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * and check.
421adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
422adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    static InetSocketAddress validateAddress(SocketAddress socketAddress) {
423b46dab348e2007bc08abaf7ecae34d89a2474e50Elliott Hughes        if (socketAddress == null) {
424126ab1b546c71137a97cef68cc89267e7f7be634Elliott Hughes            throw new IllegalArgumentException("socketAddress == null");
425adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
426adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (!(socketAddress instanceof InetSocketAddress)) {
427adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new UnsupportedAddressTypeException();
428adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
429adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        InetSocketAddress inetSocketAddress = (InetSocketAddress) socketAddress;
430adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (inetSocketAddress.isUnresolved()) {
431adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new UnresolvedAddressException();
432adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
433adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return inetSocketAddress;
434adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
435adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
436adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
437f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * Get local address.
438adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
439adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public InetAddress getLocalAddress() throws UnknownHostException {
4409229d47c1288e25ead3a2dc27fac8a4a2ee932a3Elliott Hughes        return isBound ? localAddress : Inet4Address.ANY;
441adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
442adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
443adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
444f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * Do really closing action here.
445adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
446adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
447c6e0981e5a2d23a0758ed71a8086c4278a7832efJesse Wilson    protected synchronized void implCloseSelectableChannel() throws IOException {
448c6e0981e5a2d23a0758ed71a8086c4278a7832efJesse Wilson        if (status != SOCKET_STATUS_CLOSED) {
449adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            status = SOCKET_STATUS_CLOSED;
450c6e0981e5a2d23a0758ed71a8086c4278a7832efJesse Wilson            if (socket != null && !socket.isClosed()) {
451adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                socket.close();
452adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
4530b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                IoBridge.closeSocket(fd);
454adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
455adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
456adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
457adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
458a3b57e9cb41fb00ac607cd330fa73270b564b66cElliott Hughes    @Override protected void implConfigureBlocking(boolean blocking) throws IOException {
459adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (blockingLock()) {
460a3b57e9cb41fb00ac607cd330fa73270b564b66cElliott Hughes            IoUtils.setBlocking(fd, blocking);
461adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
462adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
463adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
464adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
465f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * Get the fd.
466adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
467adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public FileDescriptor getFD() {
468adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return fd;
469adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
470adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
471f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    /*
472f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * Adapter classes for internal socket.
473f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     */
474adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static class SocketAdapter extends Socket {
4758cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        private final SocketChannelImpl channel;
4768cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        private final PlainSocketImpl socketImpl;
477adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
4788cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        SocketAdapter(PlainSocketImpl socketImpl, SocketChannelImpl channel) throws SocketException {
4798cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes            super(socketImpl);
4808cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes            this.socketImpl = socketImpl;
481adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            this.channel = channel;
4820371d85fa3ecb5f162d107cdbff0a99cd987fdccElliott Hughes            SocketUtils.setCreated(this);
483adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
484adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
4858cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        PlainSocketImpl socketImpl() {
4868cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes            return socketImpl;
4878cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        }
4888cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes
489adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        @Override
490adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public SocketChannel getChannel() {
491adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return channel;
492adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
493adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
494adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        @Override
495adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public boolean isBound() {
496adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return channel.isBound;
497adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
498adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
499adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        @Override
500adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public boolean isConnected() {
501adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return channel.isConnected();
502adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
503adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
504adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        @Override
505adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public InetAddress getLocalAddress() {
506adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            try {
507adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return channel.getLocalAddress();
508adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } catch (UnknownHostException e) {
509adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return null;
510adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
511adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
512adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
513adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        @Override
5148cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        public void connect(SocketAddress remoteAddr, int timeout) throws IOException {
515adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (!channel.isBlocking()) {
516adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throw new IllegalBlockingModeException();
517adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
518adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (isConnected()) {
519adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throw new AlreadyConnectedException();
520adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
521adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            super.connect(remoteAddr, timeout);
5228cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes            channel.initLocalAddressAndPort();
523adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (super.isConnected()) {
524adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                channel.setConnected();
525adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                channel.isBound = super.isBound();
526adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
527adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
528adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
529adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        @Override
530adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public void bind(SocketAddress localAddr) throws IOException {
531adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (channel.isConnected()) {
532adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throw new AlreadyConnectedException();
533adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
534adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (SocketChannelImpl.SOCKET_STATUS_PENDING == channel.status) {
535adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throw new ConnectionPendingException();
536adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
537adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            super.bind(localAddr);
538be0b5bd592bed1edaed2447e7ab1764b93eceaabJesse Wilson            channel.initLocalAddressAndPort();
539adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            channel.isBound = true;
540adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
541adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
542adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        @Override
543adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public void close() throws IOException {
544adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            synchronized (channel) {
545adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (channel.isOpen()) {
546adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    channel.close();
547adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                } else {
548adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    super.close();
549adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
550adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                channel.status = SocketChannelImpl.SOCKET_STATUS_CLOSED;
551adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
552adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
553adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
554adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        @Override
555adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public OutputStream getOutputStream() throws IOException {
55603c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes            checkOpenAndConnected();
557adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (isOutputShutdown()) {
55803c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes                throw new SocketException("Socket output is shutdown");
559adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
560adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return new SocketChannelOutputStream(channel);
561adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
562adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
563adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        @Override
564adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public InputStream getInputStream() throws IOException {
56503c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes            checkOpenAndConnected();
56603c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes            if (isInputShutdown()) {
56703c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes                throw new SocketException("Socket input is shutdown");
56803c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes            }
56903c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes            return new SocketChannelInputStream(channel);
57003c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes        }
571f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
57203c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes        private void checkOpenAndConnected() throws SocketException {
573adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (!channel.isOpen()) {
57403c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes                throw new SocketException("Socket is closed");
575adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
576adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (!channel.isConnected()) {
57703c0a8e681c776fdba0389ab8593282139afc6d6Elliott Hughes                throw new SocketException("Socket is not connected");
578adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
579adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
5803267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey
5813267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey        @Override
5823267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey        public FileDescriptor getFileDescriptor$() {
5833267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey            return socketImpl.getFD$();
5843267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey        }
585adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
586adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
587adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
588adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This output stream delegates all operations to the associated channel.
589adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Throws an IllegalBlockingModeException if the channel is in non-blocking
590adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * mode when performing write operations.
591adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
592adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static class SocketChannelOutputStream extends OutputStream {
5938cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        private final SocketChannel channel;
594adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
595adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public SocketChannelOutputStream(SocketChannel channel) {
596adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            this.channel = channel;
597adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
598adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
599adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /*
600f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson         * Closes this stream and channel.
601f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes         *
602adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * @exception IOException thrown if an error occurs during the close
603adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
604adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        @Override
605adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public void close() throws IOException {
606adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            channel.close();
607adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
608adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
609adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        @Override
610a1603838fe9e865575c87982e32c6343740e464cElliott Hughes        public void write(byte[] buffer, int offset, int byteCount) throws IOException {
611a1603838fe9e865575c87982e32c6343740e464cElliott Hughes            Arrays.checkOffsetAndCount(buffer.length, offset, byteCount);
612a1603838fe9e865575c87982e32c6343740e464cElliott Hughes            ByteBuffer buf = ByteBuffer.wrap(buffer, offset, byteCount);
613adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (!channel.isBlocking()) {
614adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throw new IllegalBlockingModeException();
615adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
616adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            channel.write(buf);
617adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
618adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
619adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        @Override
620adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public void write(int oneByte) throws IOException {
621adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (!channel.isBlocking()) {
622adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throw new IllegalBlockingModeException();
623adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
624adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ByteBuffer buffer = ByteBuffer.allocate(1);
625adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            buffer.put(0, (byte) (oneByte & 0xFF));
626adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            channel.write(buffer);
627adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
628adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
629adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
630adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
631adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This input stream delegates all operations to the associated channel.
632adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Throws an IllegalBlockingModeException if the channel is in non-blocking
633adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * mode when performing read operations.
634adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
635adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static class SocketChannelInputStream extends InputStream {
6368cc54e9f098c4f299d2b88bb2b9110ce44354ed7Elliott Hughes        private final SocketChannel channel;
637adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
638adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public SocketChannelInputStream(SocketChannel channel) {
639adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            this.channel = channel;
640adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
641adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
642adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /*
643adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * Closes this stream and channel.
644adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
645adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        @Override
646adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public void close() throws IOException {
647adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            channel.close();
648adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
649adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
650adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        @Override
651adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public int read() throws IOException {
652adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (!channel.isBlocking()) {
653adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throw new IllegalBlockingModeException();
654adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
655adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ByteBuffer buf = ByteBuffer.allocate(1);
656adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int result = channel.read(buf);
657fb0ec0e650bf8be35acb0d47da0311a7c446aa33Elliott Hughes            return (result == -1) ? result : (buf.get(0) & 0xff);
658adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
659adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
660adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        @Override
661a1603838fe9e865575c87982e32c6343740e464cElliott Hughes        public int read(byte[] buffer, int offset, int byteCount) throws IOException {
662a1603838fe9e865575c87982e32c6343740e464cElliott Hughes            Arrays.checkOffsetAndCount(buffer.length, offset, byteCount);
663adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (!channel.isBlocking()) {
664adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throw new IllegalBlockingModeException();
665adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
666a1603838fe9e865575c87982e32c6343740e464cElliott Hughes            ByteBuffer buf = ByteBuffer.wrap(buffer, offset, byteCount);
667adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return channel.read(buf);
668adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
669adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
670adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
671