Home | History | Annotate | Download | only in internal
      1 /*
      2  *  Licensed to the Apache Software Foundation (ASF) under one or more
      3  *  contributor license agreements.  See the NOTICE file distributed with
      4  *  this work for additional information regarding copyright ownership.
      5  *  The ASF licenses this file to You under the Apache License, Version 2.0
      6  *  (the "License"); you may not use this file except in compliance with
      7  *  the License.  You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  */
     17 
     18 package org.apache.harmony.nio.internal;
     19 
     20 // BEGIN android-note
     21 // In this class the address length was changed from long to int.
     22 // END android-note
     23 
     24 import java.io.FileDescriptor;
     25 import java.io.IOException;
     26 import java.io.InputStream;
     27 import java.io.OutputStream;
     28 import java.net.ConnectException;
     29 import java.net.InetAddress;
     30 import java.net.InetSocketAddress;
     31 import java.net.Socket;
     32 import java.net.SocketAddress;
     33 import java.net.SocketException;
     34 import java.net.SocketImpl;
     35 import java.net.SocketOptions;
     36 import java.net.UnknownHostException;
     37 import java.nio.ByteBuffer;
     38 import java.nio.channels.AlreadyConnectedException;
     39 import java.nio.channels.ClosedChannelException;
     40 import java.nio.channels.ConnectionPendingException;
     41 import java.nio.channels.IllegalBlockingModeException;
     42 import java.nio.channels.NoConnectionPendingException;
     43 import java.nio.channels.NotYetConnectedException;
     44 import java.nio.channels.SocketChannel;
     45 import java.nio.channels.UnresolvedAddressException;
     46 import java.nio.channels.UnsupportedAddressTypeException;
     47 import java.nio.channels.spi.SelectorProvider;
     48 
     49 import org.apache.harmony.luni.net.PlainSocketImpl;
     50 import org.apache.harmony.luni.platform.FileDescriptorHandler;
     51 import org.apache.harmony.luni.platform.INetworkSystem;
     52 import org.apache.harmony.luni.platform.Platform;
     53 //import org.apache.harmony.luni.util.ErrorCodeException; android-removed
     54 import org.apache.harmony.luni.util.Msg;
     55 import org.apache.harmony.nio.AddressUtil;
     56 import org.apache.harmony.nio.internal.nls.Messages;
     57 
     58 /*
     59  * The default implementation class of java.nio.channels.SocketChannel.
     60  */
     61 class SocketChannelImpl extends SocketChannel implements FileDescriptorHandler {
     62 
     63     private static final int EOF = -1;
     64 
     65     // android-removed: private static final int ERRCODE_SOCKET_NONBLOCKING_WOULD_BLOCK = -211;
     66 
     67     // The singleton to do the native network operation.
     68     static final INetworkSystem networkSystem = Platform.getNetworkSystem();
     69 
     70     // Status un-init, not initialized.
     71     static final int SOCKET_STATUS_UNINIT = EOF;
     72 
     73     // Status before connect.
     74     static final int SOCKET_STATUS_UNCONNECTED = 0;
     75 
     76     // Status connection pending.
     77     static final int SOCKET_STATUS_PENDING = 1;
     78 
     79     // Status after connection success.
     80     static final int SOCKET_STATUS_CONNECTED = 2;
     81 
     82     // Status closed.
     83     static final int SOCKET_STATUS_CLOSED = 3;
     84 
     85     // Timeout used for non-block mode.
     86     private static final int TIMEOUT_NONBLOCK = 0;
     87 
     88     // Timeout used for block mode.
     89     private static final int TIMEOUT_BLOCK = EOF;
     90 
     91     // Step used for connect.
     92     private static final int HY_SOCK_STEP_START = 0;
     93 
     94     // Step used for finishConnect.
     95     private static final int HY_PORT_SOCKET_STEP_CHECK = 1;
     96 
     97     // Connect success.
     98     private static final int CONNECT_SUCCESS = 0;
     99 
    100     // The descriptor to interact with native code.
    101     FileDescriptor fd;
    102 
    103     // Our internal Socket.
    104     private Socket socket = null;
    105 
    106     // The address to be connected.
    107     InetSocketAddress connectAddress = null;
    108 
    109     // Local address of the this socket (package private for adapter).
    110     InetAddress localAddress = null;
    111 
    112     // Local port number.
    113     int localPort;
    114 
    115     // At first, uninitialized.
    116     int status = SOCKET_STATUS_UNINIT;
    117 
    118     // Whether the socket is bound.
    119     volatile boolean isBound = false;
    120 
    121     private static class ReadLock {}
    122     private final Object readLock = new ReadLock();
    123 
    124     private static class WriteLock {}
    125     private final Object writeLock = new WriteLock();
    126 
    127     // BEGIN android-changed
    128     // this content is a struct used in connect_withtimeout().
    129     // The structure its holding has a size of 392 bytes.
    130     private byte[] connectContext = new byte[392];
    131     // END android-changed
    132 
    133     // Used to store the trafficClass value which is simply returned
    134     // as the value that was set. We also need it to pass it to methods
    135     // that specify an address packets are going to be sent to.
    136     private int trafficClass = 0;
    137 
    138     /*
    139      * Constructor for creating a connected socket channel.
    140      */
    141     public SocketChannelImpl(SelectorProvider selectorProvider)
    142             throws IOException {
    143         this(selectorProvider, true);
    144     }
    145 
    146     /*
    147      * Constructor for creating an optionally connected socket channel.
    148      */
    149     public SocketChannelImpl(SelectorProvider selectorProvider, boolean connect)
    150             throws IOException {
    151         super(selectorProvider);
    152         fd = new FileDescriptor();
    153         status = SOCKET_STATUS_UNCONNECTED;
    154         if (connect) {
    155             networkSystem.createStreamSocket(fd, true);
    156         }
    157     }
    158 
    159     /*
    160      * For native call.
    161      */
    162     @SuppressWarnings("unused")
    163     private SocketChannelImpl() {
    164         super(SelectorProvider.provider());
    165         fd = new FileDescriptor();
    166         connectAddress = new InetSocketAddress(0);
    167         status = SOCKET_STATUS_CONNECTED;
    168     }
    169 
    170     // Keep this to see if need next version
    171     // SocketChannelImpl(SelectorProvider selectorProvider, FileDescriptor fd,
    172     // SocketImpl si) {
    173     // super(selectorProvider);
    174     // fd = fd;
    175     // networkSystem = OSNetworkSystem.getOSNetworkSystem();
    176     // status = SOCKET_STATUS_UNCONNECTED;
    177     // networkSystem.createSocket(fd, true);
    178     // }
    179 
    180     /*
    181      * Package private constructor.
    182      */
    183     SocketChannelImpl(Socket aSocket, FileDescriptor aFd) {
    184         super(SelectorProvider.provider());
    185         socket = aSocket;
    186         fd = aFd;
    187         status = SOCKET_STATUS_UNCONNECTED;
    188     }
    189 
    190     /*
    191      * Getting the internal Socket If we have not the socket, we create a new
    192      * one.
    193      */
    194     @Override
    195     synchronized public Socket socket() {
    196         if (null == socket) {
    197             try {
    198                 InetAddress addr = null;
    199                 int port = 0;
    200                 if (connectAddress != null) {
    201                     addr = connectAddress.getAddress();
    202                     port = connectAddress.getPort();
    203                 }
    204                 socket = new SocketAdapter(
    205                         new PlainSocketImpl(fd, localPort, addr, port), this);
    206             } catch (SocketException e) {
    207                 return null;
    208             }
    209         }
    210         return socket;
    211     }
    212 
    213     /**
    214      * @see java.nio.channels.SocketChannel#isConnected()
    215      */
    216     @Override
    217     synchronized public boolean isConnected() {
    218         return status == SOCKET_STATUS_CONNECTED;
    219     }
    220 
    221     /*
    222      * Status setting used by other class.
    223      */
    224     synchronized void setConnected() {
    225         status = SOCKET_STATUS_CONNECTED;
    226     }
    227 
    228     void setBound(boolean flag) {
    229         isBound = flag;
    230     }
    231 
    232     /**
    233      * @see java.nio.channels.SocketChannel#isConnectionPending()
    234      */
    235     @Override
    236     synchronized public boolean isConnectionPending() {
    237         return status == SOCKET_STATUS_PENDING;
    238     }
    239 
    240     /**
    241      * @see java.nio.channels.SocketChannel#connect(java.net.SocketAddress)
    242      */
    243     @Override
    244     public boolean connect(SocketAddress socketAddress) throws IOException {
    245         // status must be open and unconnected
    246         checkUnconnected();
    247 
    248         // check the address
    249         InetSocketAddress inetSocketAddress = validateAddress(socketAddress);
    250         InetAddress normalAddr = inetSocketAddress.getAddress();
    251 
    252         // When connecting, map ANY address to Localhost
    253         if (normalAddr.isAnyLocalAddress()) {
    254             normalAddr = InetAddress.getLocalHost();
    255         }
    256 
    257         int port = inetSocketAddress.getPort();
    258         String hostName = normalAddr.getHostName();
    259         // security check
    260         SecurityManager sm = System.getSecurityManager();
    261         if (sm != null) {
    262             sm.checkConnect(hostName, port);
    263         }
    264 
    265         // connect result
    266         int result = EOF;
    267         boolean finished = false;
    268 
    269         try {
    270             if (isBlocking()) {
    271                 begin();
    272                 networkSystem.connect(fd, trafficClass, normalAddr, port);
    273                 result = CONNECT_SUCCESS; // Or we'd have thrown an exception.
    274             } else {
    275                 result = networkSystem.connectWithTimeout(fd, 0, trafficClass,
    276                         normalAddr, port, HY_SOCK_STEP_START, connectContext);
    277                 // set back to nonblocking to work around with a bug in portlib
    278                 if (!this.isBlocking()) {
    279                     networkSystem.setNonBlocking(fd, true);
    280                 }
    281             }
    282             finished = (CONNECT_SUCCESS == result);
    283             isBound = finished;
    284         } catch (IOException e) {
    285             if (e instanceof ConnectException && !isBlocking()) {
    286                 status = SOCKET_STATUS_PENDING;
    287             } else {
    288                 if (isOpen()) {
    289                     close();
    290                     finished = true;
    291                 }
    292                 throw e;
    293             }
    294         } finally {
    295             if (isBlocking()) {
    296                 end(finished);
    297             }
    298         }
    299 
    300         // set local port
    301         localPort = networkSystem.getSocketLocalPort(fd);
    302         localAddress = networkSystem.getSocketLocalAddress(fd);
    303 
    304         // set the connected address.
    305         connectAddress = inetSocketAddress;
    306         synchronized (this) {
    307             if (isBlocking()) {
    308                 status = (finished ? SOCKET_STATUS_CONNECTED
    309                         : SOCKET_STATUS_UNCONNECTED);
    310             } else {
    311                 status = SOCKET_STATUS_PENDING;
    312             }
    313         }
    314         return finished;
    315     }
    316 
    317     /**
    318      * @see java.nio.channels.SocketChannel#finishConnect()
    319      */
    320     @Override
    321     public boolean finishConnect() throws IOException {
    322         // status check
    323         synchronized (this) {
    324             if (!isOpen()) {
    325                 throw new ClosedChannelException();
    326             }
    327             if (status == SOCKET_STATUS_CONNECTED) {
    328                 return true;
    329             }
    330             if (status != SOCKET_STATUS_PENDING) {
    331                 throw new NoConnectionPendingException();
    332             }
    333         }
    334 
    335         // finish result
    336         int result = EOF;
    337         boolean finished = false;
    338 
    339         try {
    340             begin();
    341             result = networkSystem.connectWithTimeout(fd,
    342                     isBlocking() ? -1 : 0, trafficClass, connectAddress
    343                             .getAddress(), connectAddress.getPort(),
    344                     HY_PORT_SOCKET_STEP_CHECK, connectContext);
    345             finished = (result == CONNECT_SUCCESS);
    346             isBound = finished;
    347             localAddress = networkSystem.getSocketLocalAddress(fd);
    348         } catch (ConnectException e) {
    349             if (isOpen()) {
    350                 close();
    351                 finished = true;
    352             }
    353             throw e;
    354         } finally {
    355             end(finished);
    356         }
    357 
    358         synchronized (this) {
    359             status = (finished ? SOCKET_STATUS_CONNECTED : status);
    360             isBound = finished;
    361             // TPE: Workaround for bug that turns socket back to blocking
    362             if (!isBlocking()) implConfigureBlocking(false);
    363         }
    364         return finished;
    365     }
    366 
    367     /**
    368      * @see java.nio.channels.SocketChannel#read(java.nio.ByteBuffer)
    369      */
    370     @Override
    371     public int read(ByteBuffer target) throws IOException {
    372         if (null == target) {
    373             throw new NullPointerException();
    374         }
    375         checkOpenConnected();
    376         if (!target.hasRemaining()) {
    377             return 0;
    378         }
    379 
    380         int readCount;
    381         if (target.isDirect() || target.hasArray()) {
    382             readCount = readImpl(target);
    383             if (readCount > 0) {
    384                 target.position(target.position() + readCount);
    385             }
    386         } else {
    387             ByteBuffer readBuffer = null;
    388             byte[] readArray = null;
    389             readArray = new byte[target.remaining()];
    390             readBuffer = ByteBuffer.wrap(readArray);
    391             readCount = readImpl(readBuffer);
    392             if (readCount > 0) {
    393                 target.put(readArray, 0, readCount);
    394             }
    395         }
    396         return readCount;
    397     }
    398 
    399     /**
    400      * @see java.nio.channels.SocketChannel#read(java.nio.ByteBuffer[], int,
    401      *      int)
    402      */
    403     @Override
    404     public long read(ByteBuffer[] targets, int offset, int length)
    405             throws IOException {
    406         if (!isIndexValid(targets, offset, length)) {
    407             throw new IndexOutOfBoundsException();
    408         }
    409 
    410         checkOpenConnected();
    411         int totalCount = calculateByteBufferArray(targets, offset, length);
    412         if (0 == totalCount) {
    413             return 0;
    414         }
    415         byte[] readArray = new byte[totalCount];
    416         ByteBuffer readBuffer = ByteBuffer.wrap(readArray);
    417         int readCount;
    418         // read data to readBuffer, and then transfer data from readBuffer to
    419         // targets.
    420         readCount = readImpl(readBuffer);
    421         if (readCount > 0) {
    422             int left = readCount;
    423             int index = offset;
    424             // transfer data from readArray to targets
    425             while (left > 0) {
    426                 int putLength = Math.min(targets[index].remaining(), left);
    427                 targets[index].put(readArray, readCount - left, putLength);
    428                 index++;
    429                 left -= putLength;
    430             }
    431         }
    432         return readCount;
    433     }
    434 
    435     private boolean isIndexValid(ByteBuffer[] targets, int offset, int length) {
    436         return (length >= 0) && (offset >= 0)
    437                 && ((long) length + (long) offset <= targets.length);
    438     }
    439 
    440     /**
    441      * Read from channel, and store the result in the target.
    442      *
    443      * @param target
    444      *            output parameter
    445      */
    446     private int readImpl(ByteBuffer target) throws IOException {
    447         synchronized (readLock) {
    448             int readCount = 0;
    449             try {
    450                 if (isBlocking()) {
    451                     begin();
    452                 }
    453                 int offset = target.position();
    454                 int length = target.remaining();
    455                 if (target.isDirect()) {
    456                     // BEGIN android-changed
    457                     // changed address from long to int
    458                     int address = AddressUtil.getDirectBufferAddress(target);
    459                     readCount = networkSystem.readDirect(fd, address + offset,
    460                             length, (isBlocking() ? TIMEOUT_BLOCK
    461                                     : TIMEOUT_NONBLOCK));
    462                     // END android-changed
    463                 } else {
    464                     // target is assured to have array.
    465                     byte[] array = target.array();
    466                     offset += target.arrayOffset();
    467                     readCount = networkSystem.read(fd, array, offset, length,
    468                             (isBlocking() ? TIMEOUT_BLOCK : TIMEOUT_NONBLOCK));
    469                 }
    470                 return readCount;
    471             } finally {
    472                 if (isBlocking()) {
    473                     end(readCount > 0);
    474                 }
    475             }
    476         }
    477     }
    478 
    479     /**
    480      * @see java.nio.channels.SocketChannel#write(java.nio.ByteBuffer)
    481      */
    482     @Override
    483     public int write(ByteBuffer source) throws IOException {
    484         if (null == source) {
    485             throw new NullPointerException();
    486         }
    487         checkOpenConnected();
    488         if (!source.hasRemaining()) {
    489             return 0;
    490         }
    491         return writeImpl(source);
    492     }
    493 
    494     /**
    495      * @see java.nio.channels.SocketChannel#write(java.nio.ByteBuffer[], int,
    496      *      int)
    497      */
    498     @Override
    499     public long write(ByteBuffer[] sources, int offset, int length)
    500             throws IOException {
    501         if (!isIndexValid(sources, offset, length)) {
    502             throw new IndexOutOfBoundsException();
    503         }
    504 
    505         checkOpenConnected();
    506         int count = calculateByteBufferArray(sources, offset, length);
    507         if (0 == count) {
    508             return 0;
    509         }
    510         ByteBuffer writeBuf = ByteBuffer.allocate(count);
    511         for (int val = offset; val < length + offset; val++) {
    512             ByteBuffer source = sources[val];
    513             int oldPosition = source.position();
    514             writeBuf.put(source);
    515             source.position(oldPosition);
    516         }
    517         writeBuf.flip();
    518         int result = writeImpl(writeBuf);
    519         int val = offset;
    520         int written = result;
    521         while (result > 0) {
    522             ByteBuffer source = sources[val];
    523             int gap = Math.min(result, source.remaining());
    524             source.position(source.position() + gap);
    525             val++;
    526             result -= gap;
    527         }
    528         return written;
    529     }
    530 
    531     private int calculateByteBufferArray(ByteBuffer[] sources, int offset,
    532             int length) {
    533         int sum = 0;
    534         for (int val = offset; val < offset + length; val++) {
    535             sum = sum + sources[val].remaining();
    536         }
    537         return sum;
    538     }
    539 
    540     /*
    541      * Write the source. return the count of bytes written.
    542      */
    543     private int writeImpl(ByteBuffer source) throws IOException {
    544         synchronized (writeLock) {
    545             if (!source.hasRemaining()) {
    546                 return 0;
    547             }
    548             int writeCount = 0;
    549             try {
    550                 int pos = source.position();
    551                 int length = source.remaining();
    552                 if (isBlocking()) {
    553                     begin();
    554                 }
    555                 if (source.isDirect()) {
    556                     // BEGIN android-changed
    557                     // changed address from long to int; split address and pos parameters
    558                     int address = AddressUtil.getDirectBufferAddress(source);
    559                     writeCount = networkSystem.writeDirect(fd, address, pos,
    560                             length);
    561                     // END android-changed
    562                 } else if (source.hasArray()) {
    563                     pos += source.arrayOffset();
    564                     writeCount = networkSystem.write(fd, source.array(), pos,
    565                             length);
    566                 } else {
    567                     byte[] array = new byte[length];
    568                     source.get(array);
    569                     writeCount = networkSystem.write(fd, array, 0, length);
    570                 }
    571                 source.position(pos + writeCount);
    572                 // android-removed: bogus catch (SocketException e) and use of ErrorCodeException.
    573             } finally {
    574                 if (isBlocking()) {
    575                     end(writeCount >= 0);
    576                 }
    577             }
    578             return writeCount;
    579         }
    580     }
    581 
    582     /*
    583      * Status check, open and "connected", when read and write.
    584      */
    585     synchronized private void checkOpenConnected()
    586             throws ClosedChannelException {
    587         if (!isOpen()) {
    588             throw new ClosedChannelException();
    589         }
    590         if (!isConnected()) {
    591             throw new NotYetConnectedException();
    592         }
    593     }
    594 
    595     /*
    596      * Status check, open and "unconnected", before connection.
    597      */
    598     synchronized private void checkUnconnected() throws IOException {
    599         if (!isOpen()) {
    600             throw new ClosedChannelException();
    601         }
    602         if (status == SOCKET_STATUS_CONNECTED) {
    603             throw new AlreadyConnectedException();
    604         }
    605         if (status == SOCKET_STATUS_PENDING) {
    606             throw new ConnectionPendingException();
    607         }
    608     }
    609 
    610     /*
    611      * Shared by this class and DatagramChannelImpl, to do the address transfer
    612      * and check.
    613      */
    614     static InetSocketAddress validateAddress(SocketAddress socketAddress) {
    615         if (null == socketAddress) {
    616             throw new IllegalArgumentException();
    617         }
    618         if (!(socketAddress instanceof InetSocketAddress)) {
    619             throw new UnsupportedAddressTypeException();
    620         }
    621         InetSocketAddress inetSocketAddress = (InetSocketAddress) socketAddress;
    622         if (inetSocketAddress.isUnresolved()) {
    623             throw new UnresolvedAddressException();
    624         }
    625         return inetSocketAddress;
    626     }
    627 
    628     /*
    629      * Get local address.
    630      */
    631     public InetAddress getLocalAddress() throws UnknownHostException {
    632         byte[] any_bytes = { 0, 0, 0, 0 };
    633         if (!isBound) {
    634             return InetAddress.getByAddress(any_bytes);
    635         }
    636         return localAddress;
    637     }
    638 
    639     /*
    640      * Do really closing action here.
    641      */
    642     @Override
    643     synchronized protected void implCloseSelectableChannel() throws IOException {
    644         if (SOCKET_STATUS_CLOSED != status) {
    645             status = SOCKET_STATUS_CLOSED;
    646             if (null != socket && !socket.isClosed()) {
    647                 socket.close();
    648             } else {
    649                 networkSystem.socketClose(fd);
    650             }
    651         }
    652     }
    653 
    654     /**
    655      * @see java.nio.channels.spi.AbstractSelectableChannel#implConfigureBlocking(boolean)
    656      */
    657     @Override
    658     protected void implConfigureBlocking(boolean blockMode) throws IOException {
    659         synchronized (blockingLock()) {
    660             networkSystem.setNonBlocking(fd, !blockMode);
    661         }
    662     }
    663 
    664     /*
    665      * Get the fd.
    666      */
    667     public FileDescriptor getFD() {
    668         return fd;
    669     }
    670 
    671     /*
    672      * Adapter classes for internal socket.
    673      */
    674     private static class SocketAdapter extends Socket {
    675 
    676         SocketChannelImpl channel;
    677 
    678         SocketImpl socketImpl;
    679 
    680         SocketAdapter(SocketImpl socketimpl, SocketChannelImpl channel)
    681                 throws SocketException {
    682             super(socketimpl);
    683             socketImpl = socketimpl;
    684             this.channel = channel;
    685         }
    686 
    687         /**
    688          * @see java.net.Socket#getChannel()
    689          */
    690         @Override
    691         public SocketChannel getChannel() {
    692             return channel;
    693         }
    694 
    695         /**
    696          * @see java.net.Socket#isBound()
    697          */
    698         @Override
    699         public boolean isBound() {
    700             return channel.isBound;
    701         }
    702 
    703         /**
    704          * @see java.net.Socket#isConnected()
    705          */
    706         @Override
    707         public boolean isConnected() {
    708             return channel.isConnected();
    709         }
    710 
    711         /**
    712          * @see java.net.Socket#getLocalAddress()
    713          */
    714         @Override
    715         public InetAddress getLocalAddress() {
    716             try {
    717                 return channel.getLocalAddress();
    718             } catch (UnknownHostException e) {
    719                 return null;
    720             }
    721         }
    722 
    723         /**
    724          * @see java.net.Socket#connect(java.net.SocketAddress, int)
    725          */
    726         @Override
    727         public void connect(SocketAddress remoteAddr, int timeout)
    728                 throws IOException {
    729             if (!channel.isBlocking()) {
    730                 throw new IllegalBlockingModeException();
    731             }
    732             if (isConnected()) {
    733                 throw new AlreadyConnectedException();
    734             }
    735             super.connect(remoteAddr, timeout);
    736             channel.localAddress = networkSystem.getSocketLocalAddress(channel.fd);
    737             if (super.isConnected()) {
    738                 channel.setConnected();
    739                 channel.isBound = super.isBound();
    740             }
    741         }
    742 
    743         /**
    744          * @see java.net.Socket#bind(java.net.SocketAddress)
    745          */
    746         @Override
    747         public void bind(SocketAddress localAddr) throws IOException {
    748             if (channel.isConnected()) {
    749                 throw new AlreadyConnectedException();
    750             }
    751             if (SocketChannelImpl.SOCKET_STATUS_PENDING == channel.status) {
    752                 throw new ConnectionPendingException();
    753             }
    754             super.bind(localAddr);
    755             // keep here to see if need next version
    756             // channel.Address = getLocalSocketAddress();
    757             // channel.localport = getLocalPort();
    758             channel.isBound = true;
    759 
    760         }
    761 
    762         /**
    763          * @see java.net.Socket#close()
    764          */
    765         @Override
    766         public void close() throws IOException {
    767             synchronized (channel) {
    768                 if (channel.isOpen()) {
    769                     channel.close();
    770                 } else {
    771                     super.close();
    772                 }
    773                 channel.status = SocketChannelImpl.SOCKET_STATUS_CLOSED;
    774             }
    775         }
    776 
    777         @Override
    778         public boolean getReuseAddress() throws SocketException {
    779             checkOpen();
    780             return ((Boolean) socketImpl.getOption(SocketOptions.SO_REUSEADDR))
    781                     .booleanValue();
    782         }
    783 
    784         @Override
    785         public synchronized int getReceiveBufferSize() throws SocketException {
    786             checkOpen();
    787             return ((Integer) socketImpl.getOption(SocketOptions.SO_RCVBUF))
    788                     .intValue();
    789         }
    790 
    791         @Override
    792         public synchronized int getSendBufferSize() throws SocketException {
    793             checkOpen();
    794             return ((Integer) socketImpl.getOption(SocketOptions.SO_SNDBUF))
    795                     .intValue();
    796         }
    797 
    798         @Override
    799         public synchronized int getSoTimeout() throws SocketException {
    800             checkOpen();
    801             return ((Integer) socketImpl.getOption(SocketOptions.SO_TIMEOUT))
    802                     .intValue();
    803         }
    804 
    805         @Override
    806         public int getTrafficClass() throws SocketException {
    807             checkOpen();
    808             return ((Number) socketImpl.getOption(SocketOptions.IP_TOS))
    809                     .intValue();
    810         }
    811 
    812         /**
    813          * @see java.net.Socket#getKeepAlive()
    814          */
    815         @Override
    816         public boolean getKeepAlive() throws SocketException {
    817             checkOpen();
    818             return ((Boolean) socketImpl.getOption(SocketOptions.SO_KEEPALIVE))
    819                     .booleanValue();
    820         }
    821 
    822         /**
    823          * @see java.net.Socket#getOOBInline()
    824          */
    825         @Override
    826         public boolean getOOBInline() throws SocketException {
    827             checkOpen();
    828             return ((Boolean) socketImpl.getOption(SocketOptions.SO_OOBINLINE))
    829                     .booleanValue();
    830         }
    831 
    832         /**
    833          * @see java.net.Socket#getSoLinger()
    834          */
    835         @Override
    836         public int getSoLinger() throws SocketException {
    837             checkOpen();
    838             return ((Integer) socketImpl.getOption(SocketOptions.SO_LINGER))
    839                     .intValue();
    840         }
    841 
    842         /**
    843          * @see java.net.Socket#getTcpNoDelay()
    844          */
    845         @Override
    846         public boolean getTcpNoDelay() throws SocketException {
    847             checkOpen();
    848             return ((Boolean) socketImpl.getOption(SocketOptions.TCP_NODELAY))
    849                     .booleanValue();
    850         }
    851 
    852         @Override
    853         public void setKeepAlive(boolean value) throws SocketException {
    854             checkOpen();
    855             socketImpl.setOption(SocketOptions.SO_KEEPALIVE, value ? Boolean.TRUE
    856                     : Boolean.FALSE);
    857         }
    858 
    859         @Override
    860         public void setOOBInline(boolean oobinline) throws SocketException {
    861             checkOpen();
    862             socketImpl.setOption(SocketOptions.SO_OOBINLINE, oobinline ? Boolean.TRUE
    863                     : Boolean.FALSE);
    864         }
    865 
    866         @Override
    867         public synchronized void setReceiveBufferSize(int size)
    868                 throws SocketException {
    869             checkOpen();
    870             if (size < 1) {
    871                 throw new IllegalArgumentException(Msg.getString("K0035")); //$NON-NLS-1$
    872             }
    873             socketImpl
    874                     .setOption(SocketOptions.SO_RCVBUF, Integer.valueOf(size));
    875         }
    876 
    877         @Override
    878         public void setReuseAddress(boolean reuse) throws SocketException {
    879             checkOpen();
    880             socketImpl.setOption(SocketOptions.SO_REUSEADDR, reuse ? Boolean.TRUE
    881                     : Boolean.FALSE);
    882         }
    883 
    884         @Override
    885         public synchronized void setSendBufferSize(int size) throws SocketException {
    886             checkOpen();
    887             if (size < 1) {
    888                 throw new IllegalArgumentException(Msg.getString("K0035")); //$NON-NLS-1$
    889             }
    890             socketImpl.setOption(SocketOptions.SO_SNDBUF, Integer.valueOf(size));
    891         }
    892 
    893         @Override
    894         public void setSoLinger(boolean on, int timeout) throws SocketException {
    895             checkOpen();
    896             if (on && timeout < 0) {
    897                 throw new IllegalArgumentException(Msg.getString("K0045")); //$NON-NLS-1$
    898             }
    899             int val = on ? (65535 < timeout ? 65535 : timeout) : -1;
    900             socketImpl.setOption(SocketOptions.SO_LINGER, Integer.valueOf(val));
    901         }
    902 
    903         @Override
    904         public synchronized void setSoTimeout(int timeout) throws SocketException {
    905             checkOpen();
    906             if (timeout < 0) {
    907                 throw new IllegalArgumentException(Msg.getString("K0036")); //$NON-NLS-1$
    908             }
    909             socketImpl.setOption(SocketOptions.SO_TIMEOUT, Integer.valueOf(timeout));
    910         }
    911 
    912         @Override
    913         public void setTcpNoDelay(boolean on) throws SocketException {
    914             checkOpen();
    915             socketImpl.setOption(SocketOptions.TCP_NODELAY, Boolean.valueOf(on));
    916         }
    917 
    918         @Override
    919         public void setTrafficClass(int value) throws SocketException {
    920             checkOpen();
    921             if (value < 0 || value > 255) {
    922                 throw new IllegalArgumentException();
    923             }
    924             socketImpl.setOption(SocketOptions.IP_TOS, Integer.valueOf(value));
    925         }
    926 
    927         /**
    928          * @see java.net.Socket#getOutputStream()
    929          */
    930         @Override
    931         public OutputStream getOutputStream() throws IOException {
    932             if (!channel.isOpen()) {
    933                 // nio.00=Socket is closed
    934                 throw new SocketException(Messages.getString("nio.00")); //$NON-NLS-1$
    935             }
    936             if (!channel.isConnected()) {
    937                 // nio.01=Socket is not connected
    938                 throw new SocketException(Messages.getString("nio.01")); //$NON-NLS-1$
    939             }
    940             if (isOutputShutdown()) {
    941                 // nio.02=Socket output is shutdown
    942                 throw new SocketException(Messages.getString("nio.02")); //$NON-NLS-1$
    943             }
    944             return new SocketChannelOutputStream(channel);
    945         }
    946 
    947         /**
    948          * @see java.net.Socket#getInputStream()
    949          */
    950         @Override
    951         public InputStream getInputStream() throws IOException {
    952             if (!channel.isOpen()) {
    953                 // nio.00=Socket is closed
    954                 throw new SocketException(Messages.getString("nio.00")); //$NON-NLS-1$
    955             }
    956             if (!channel.isConnected()) {
    957                 // nio.01=Socket is not connected
    958                 throw new SocketException(Messages.getString("nio.01")); //$NON-NLS-1$
    959             }
    960             if (isInputShutdown()) {
    961                 // nio.03=Socket input is shutdown
    962                 throw new SocketException(Messages.getString("nio.03")); //$NON-NLS-1$
    963             }
    964             return new SocketChannelInputStream(channel);
    965         }
    966 
    967         /*
    968          * Checks whether the channel is open.
    969          */
    970         private void checkOpen() throws SocketException {
    971             if (isClosed()) {
    972                 // nio.00=Socket is closed
    973                 throw new SocketException(Messages.getString("nio.00")); //$NON-NLS-1$
    974             }
    975         }
    976 
    977         /*
    978          * Used for net and nio exchange.
    979          */
    980         public SocketImpl getImpl() {
    981             return socketImpl;
    982         }
    983     }
    984 
    985     /*
    986      * This output stream delegates all operations to the associated channel.
    987      * Throws an IllegalBlockingModeException if the channel is in non-blocking
    988      * mode when performing write operations.
    989      */
    990     private static class SocketChannelOutputStream extends OutputStream {
    991         SocketChannel channel;
    992 
    993         public SocketChannelOutputStream(SocketChannel channel) {
    994             this.channel = channel;
    995         }
    996 
    997         /*
    998          * Closes this stream and channel.
    999          *
   1000          * @exception IOException thrown if an error occurs during the close
   1001          */
   1002         @Override
   1003         public void close() throws IOException {
   1004             channel.close();
   1005         }
   1006 
   1007         /**
   1008          * @see java.io.OutputStream#write(byte[], int, int)
   1009          */
   1010         @Override
   1011         public void write(byte[] buffer, int offset, int count)
   1012                 throws IOException {
   1013             if (0 > offset || 0 > count || count + offset > buffer.length) {
   1014                 throw new IndexOutOfBoundsException();
   1015             }
   1016             ByteBuffer buf = ByteBuffer.wrap(buffer, offset, count);
   1017             if (!channel.isBlocking()) {
   1018                 throw new IllegalBlockingModeException();
   1019             }
   1020             channel.write(buf);
   1021         }
   1022 
   1023         /**
   1024          * @see java.io.OutputStream#write(int)
   1025          */
   1026         @Override
   1027         public void write(int oneByte) throws IOException {
   1028             if (!channel.isBlocking()) {
   1029                 throw new IllegalBlockingModeException();
   1030             }
   1031             ByteBuffer buffer = ByteBuffer.allocate(1);
   1032             buffer.put(0, (byte) (oneByte & 0xFF));
   1033             channel.write(buffer);
   1034         }
   1035     }
   1036 
   1037     /*
   1038      * This input stream delegates all operations to the associated channel.
   1039      * Throws an IllegalBlockingModeException if the channel is in non-blocking
   1040      * mode when performing read operations.
   1041      */
   1042     private static class SocketChannelInputStream extends InputStream {
   1043         SocketChannel channel;
   1044 
   1045         public SocketChannelInputStream(SocketChannel channel) {
   1046             this.channel = channel;
   1047         }
   1048 
   1049         /*
   1050          * Closes this stream and channel.
   1051          */
   1052         @Override
   1053         public void close() throws IOException {
   1054             channel.close();
   1055         }
   1056 
   1057         /**
   1058          * @see java.io.InputStream#read()
   1059          */
   1060         @Override
   1061         public int read() throws IOException {
   1062             if (!channel.isBlocking()) {
   1063                 throw new IllegalBlockingModeException();
   1064             }
   1065             ByteBuffer buf = ByteBuffer.allocate(1);
   1066             int result = channel.read(buf);
   1067             // BEGIN android-changed: input was already consumed
   1068             return (-1 == result) ? result : buf.get(0) & 0xFF;
   1069             // END android-changed
   1070         }
   1071 
   1072         /**
   1073          * @see java.io.InputStream#read(byte[], int, int)
   1074          */
   1075         @Override
   1076         public int read(byte[] buffer, int offset, int count)
   1077                 throws IOException {
   1078             if (0 > offset || 0 > count || count + offset > buffer.length) {
   1079                 throw new IndexOutOfBoundsException();
   1080             }
   1081             if (!channel.isBlocking()) {
   1082                 throw new IllegalBlockingModeException();
   1083             }
   1084             ByteBuffer buf = ByteBuffer.wrap(buffer, offset, count);
   1085             return channel.read(buf);
   1086         }
   1087     }
   1088 }
   1089