Home | History | Annotate | Download | only in channels
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package libcore.java.nio.channels;
     18 
     19 import org.junit.Rule;
     20 
     21 import java.io.IOException;
     22 import java.io.InputStream;
     23 import java.io.OutputStream;
     24 import java.lang.reflect.Field;
     25 import java.net.BindException;
     26 import java.net.ConnectException;
     27 import java.net.Inet4Address;
     28 import java.net.InetAddress;
     29 import java.net.InetSocketAddress;
     30 import java.net.ServerSocket;
     31 import java.net.Socket;
     32 import java.net.SocketImpl;
     33 import java.net.StandardSocketOptions;
     34 import java.nio.ByteBuffer;
     35 import java.nio.channels.AlreadyBoundException;
     36 import java.nio.channels.ClosedChannelException;
     37 import java.nio.channels.NotYetConnectedException;
     38 import java.nio.channels.SelectionKey;
     39 import java.nio.channels.Selector;
     40 import java.nio.channels.SocketChannel;
     41 import libcore.junit.junit3.TestCaseWithRules;
     42 import libcore.junit.util.ResourceLeakageDetector;
     43 import libcore.junit.util.ResourceLeakageDetector.LeakageDetectorRule;
     44 
     45 public class SocketChannelTest extends TestCaseWithRules {
     46 
     47     @Rule
     48     public LeakageDetectorRule guardRule = ResourceLeakageDetector.getRule();
     49 
     50     public void test_read_intoReadOnlyByteArrays() throws Exception {
     51         try (ServerSocket ss = new ServerSocket(0);
     52              SocketChannel sc = SocketChannel.open(ss.getLocalSocketAddress())) {
     53             ByteBuffer readOnly = ByteBuffer.allocate(1).asReadOnlyBuffer();
     54             ss.setReuseAddress(true);
     55             try {
     56                 sc.read(readOnly);
     57                 fail();
     58             } catch (IllegalArgumentException expected) {
     59             }
     60             try {
     61                 sc.read(new ByteBuffer[] { readOnly });
     62                 fail();
     63             } catch (IllegalArgumentException expected) {
     64             }
     65             try {
     66                 sc.read(new ByteBuffer[] { readOnly }, 0, 1);
     67                 fail();
     68             } catch (IllegalArgumentException expected) {
     69             }
     70         }
     71     }
     72 
     73     // https://code.google.com/p/android/issues/detail?id=56684
     74     public void test_56684() throws Exception {
     75         SocketChannel sc = SocketChannel.open();
     76         sc.configureBlocking(false);
     77 
     78         Selector selector = Selector.open();
     79         SelectionKey selectionKey = sc.register(selector, SelectionKey.OP_CONNECT);
     80 
     81         try {
     82             // This test originally mocked the connect syscall to return ENETUNREACH.
     83             // This is not easily doable in openJdk libcore, but a connect to broadcast
     84             // address (255.255.255.255) for a TCP connection produces ENETUNREACH
     85             // Kernel code that does it is at
     86             // http://lxr.free-electrons.com/source/net/ipv4/tcp_ipv4.c?v=3.18#L182
     87             sc.connect(new InetSocketAddress(InetAddress.getByAddress(new byte[] {
     88                     (byte) 255, (byte) 255, (byte) 255, (byte) 255 }), 0));
     89             fail();
     90         } catch (ConnectException ex) {
     91         }
     92 
     93         try {
     94             sc.finishConnect();
     95             fail();
     96         } catch (ClosedChannelException expected) {
     97         }
     98     }
     99 
    100     /** Checks that closing a Socket's output stream also closes the Socket and SocketChannel. */
    101     public void test_channelSocketOutputStreamClosureState() throws Exception {
    102         ServerSocket ss = new ServerSocket(0);
    103 
    104         SocketChannel sc = SocketChannel.open(ss.getLocalSocketAddress());
    105         sc.configureBlocking(true);
    106 
    107         Socket scSocket = sc.socket();
    108         OutputStream os = scSocket.getOutputStream();
    109 
    110         assertTrue(sc.isOpen());
    111         assertFalse(scSocket.isClosed());
    112 
    113         os.close();
    114 
    115         assertFalse(sc.isOpen());
    116         assertTrue(scSocket.isClosed());
    117 
    118         ss.close();
    119     }
    120 
    121     /** Checks that closing a Socket's input stream also closes the Socket and SocketChannel. */
    122     public void test_channelSocketInputStreamClosureState() throws Exception {
    123         ServerSocket ss = new ServerSocket(0);
    124 
    125         SocketChannel sc = SocketChannel.open(ss.getLocalSocketAddress());
    126         sc.configureBlocking(true);
    127 
    128         Socket scSocket = sc.socket();
    129         InputStream is = scSocket.getInputStream();
    130 
    131         assertTrue(sc.isOpen());
    132         assertFalse(scSocket.isClosed());
    133 
    134         is.close();
    135 
    136         assertFalse(sc.isOpen());
    137         assertTrue(scSocket.isClosed());
    138 
    139         ss.close();
    140     }
    141 
    142     /** Checks the state of the SocketChannel and associated Socket after open() */
    143     public void test_open_initialState() throws Exception {
    144         SocketChannel sc = SocketChannel.open();
    145         try {
    146             assertNull(sc.socket().getLocalSocketAddress());
    147 
    148             Socket socket = sc.socket();
    149             assertFalse(socket.isBound());
    150             assertFalse(socket.isClosed());
    151             assertFalse(socket.isConnected());
    152             assertEquals(-1, socket.getLocalPort());
    153             assertTrue(socket.getLocalAddress().isAnyLocalAddress());
    154             assertNull(socket.getLocalSocketAddress());
    155             assertNull(socket.getInetAddress());
    156             assertEquals(0, socket.getPort());
    157             assertNull(socket.getRemoteSocketAddress());
    158             assertFalse(socket.getReuseAddress());
    159 
    160             assertSame(sc, socket.getChannel());
    161         } finally {
    162             sc.close();
    163         }
    164     }
    165 
    166     public void test_bind_unresolvedAddress() throws IOException {
    167         SocketChannel sc = SocketChannel.open();
    168         try {
    169             sc.socket().bind(new InetSocketAddress("unresolvedname", 31415));
    170             fail();
    171         } catch (IOException expected) {
    172         }
    173 
    174         assertNull(sc.socket().getLocalSocketAddress());
    175         assertTrue(sc.isOpen());
    176         assertFalse(sc.isConnected());
    177 
    178         sc.close();
    179     }
    180 
    181     /** Checks that the SocketChannel and associated Socket agree on the socket state. */
    182     public void test_bind_socketStateSync() throws IOException {
    183         SocketChannel sc = SocketChannel.open();
    184         assertNull(sc.socket().getLocalSocketAddress());
    185 
    186         Socket socket = sc.socket();
    187         assertNull(socket.getLocalSocketAddress());
    188         assertFalse(socket.isBound());
    189 
    190         InetSocketAddress bindAddr = new InetSocketAddress("localhost", 0);
    191         sc.socket().bind(bindAddr);
    192 
    193         InetSocketAddress actualAddr = (InetSocketAddress) sc.socket().getLocalSocketAddress();
    194         assertEquals(actualAddr, socket.getLocalSocketAddress());
    195         assertEquals(bindAddr.getHostName(), actualAddr.getHostName());
    196         assertTrue(socket.isBound());
    197         assertFalse(socket.isConnected());
    198         assertFalse(socket.isClosed());
    199 
    200         sc.close();
    201 
    202         assertFalse(sc.isOpen());
    203         assertTrue(socket.isClosed());
    204     }
    205 
    206     /**
    207      * Checks that the SocketChannel and associated Socket agree on the socket state, even if
    208      * the Socket object is requested/created after bind().
    209      */
    210     public void test_bind_socketObjectCreationAfterBind() throws IOException {
    211         SocketChannel sc = SocketChannel.open();
    212         assertNull(sc.socket().getLocalSocketAddress());
    213 
    214         InetSocketAddress bindAddr = new InetSocketAddress("localhost", 0);
    215         sc.socket().bind(bindAddr);
    216 
    217         // Socket object creation after bind().
    218         Socket socket = sc.socket();
    219         InetSocketAddress actualAddr = (InetSocketAddress) sc.socket().getLocalSocketAddress();
    220         assertEquals(actualAddr, socket.getLocalSocketAddress());
    221         assertEquals(bindAddr.getHostName(), actualAddr.getHostName());
    222         assertTrue(socket.isBound());
    223         assertFalse(socket.isConnected());
    224         assertFalse(socket.isClosed());
    225 
    226         sc.close();
    227 
    228         assertFalse(sc.isOpen());
    229         assertTrue(socket.isClosed());
    230     }
    231 
    232     /**
    233      * Tests connect() and object state for a blocking SocketChannel. Blocking mode is the default.
    234      */
    235     public void test_connect_blocking() throws Exception {
    236         ServerSocket ss = new ServerSocket(0);
    237 
    238         SocketChannel sc = SocketChannel.open();
    239         assertTrue(sc.isBlocking());
    240 
    241         assertTrue(sc.connect(ss.getLocalSocketAddress()));
    242 
    243         assertTrue(sc.socket().isBound());
    244         assertTrue(sc.isConnected());
    245         assertTrue(sc.socket().isConnected());
    246         assertFalse(sc.socket().isClosed());
    247         assertTrue(sc.isBlocking());
    248 
    249         ss.close();
    250         sc.close();
    251     }
    252 
    253     /** Tests connect() and object state for a non-blocking SocketChannel. */
    254     public void test_connect_nonBlocking() throws Exception {
    255         ServerSocket ss = new ServerSocket(0);
    256 
    257         SocketChannel sc = SocketChannel.open();
    258         assertTrue(sc.isBlocking());
    259         sc.configureBlocking(false);
    260         assertFalse(sc.isBlocking());
    261 
    262         if (!sc.connect(ss.getLocalSocketAddress())) {
    263             do {
    264                 assertTrue(sc.socket().isBound());
    265                 assertFalse(sc.isConnected());
    266                 assertFalse(sc.socket().isConnected());
    267                 assertFalse(sc.socket().isClosed());
    268             } while (!sc.finishConnect());
    269         }
    270         assertTrue(sc.socket().isBound());
    271         assertTrue(sc.isConnected());
    272         assertTrue(sc.socket().isConnected());
    273         assertFalse(sc.socket().isClosed());
    274         assertFalse(sc.isBlocking());
    275 
    276         ss.close();
    277         sc.close();
    278     }
    279 
    280     public void test_Socket_impl_notNull() throws Exception {
    281         try (SocketChannel sc = SocketChannel.open();
    282              Socket socket = sc.socket()) {
    283             Field f_impl = Socket.class.getDeclaredField("impl");
    284             f_impl.setAccessible(true);
    285             Object implFieldValue = f_impl.get(socket);
    286             assertNotNull(implFieldValue);
    287             assertTrue(implFieldValue instanceof SocketImpl);
    288         }
    289     }
    290 
    291     public void test_setOption() throws Exception {
    292         SocketChannel sc = SocketChannel.open();
    293         sc.setOption(StandardSocketOptions.SO_LINGER, 1000);
    294 
    295         // Assert that we can read back the option from the channel...
    296         assertEquals(1000, (int) sc.<Integer>getOption(StandardSocketOptions.SO_LINGER));
    297         // ... and its socket adaptor.
    298         assertEquals(1000, sc.socket().getSoLinger());
    299 
    300         sc.close();
    301         try {
    302             sc.setOption(StandardSocketOptions.SO_LINGER, 2000);
    303             fail();
    304         } catch (ClosedChannelException expected) {
    305         }
    306     }
    307 
    308     public void test_bind() throws IOException {
    309         InetSocketAddress socketAddress = new InetSocketAddress(Inet4Address.LOOPBACK, 0);
    310         SocketChannel sc = SocketChannel.open();
    311         sc.bind(socketAddress);
    312         assertEquals(socketAddress.getAddress(),
    313                 ((InetSocketAddress) (sc.getLocalAddress())).getAddress());
    314         assertTrue(((InetSocketAddress) (sc.getLocalAddress())).getPort() > 0);
    315 
    316         try {
    317             sc.bind(socketAddress);
    318             fail();
    319         } catch (AlreadyBoundException expected) {
    320         }
    321 
    322         socketAddress = new InetSocketAddress(Inet4Address.LOOPBACK,
    323                 ((InetSocketAddress) (sc.getLocalAddress())).getPort());
    324         try (SocketChannel sc1 = SocketChannel.open()){
    325             sc1.bind(socketAddress);
    326             fail();
    327         } catch (BindException expected) {
    328         }
    329 
    330         sc.close();
    331         socketAddress = new InetSocketAddress(Inet4Address.LOOPBACK, 0);
    332         try {
    333             sc.bind(socketAddress);
    334             fail();
    335         } catch (ClosedChannelException expected) {
    336         }
    337     }
    338 
    339     public void test_getRemoteAddress() throws IOException {
    340         try (SocketChannel sc = SocketChannel.open();
    341              ServerSocket ss = new ServerSocket(0)) {
    342             assertNull(sc.getRemoteAddress());
    343 
    344             sc.connect(ss.getLocalSocketAddress());
    345             assertEquals(sc.getRemoteAddress(), ss.getLocalSocketAddress());
    346         }
    347     }
    348 
    349     public void test_shutdownInput() throws IOException {
    350         try (SocketChannel channel1 = SocketChannel.open();
    351             ServerSocket server1 = new ServerSocket(0)) {
    352             InetSocketAddress localAddr1 = new InetSocketAddress("127.0.0.1",
    353                     server1.getLocalPort());
    354 
    355             // initialize write content
    356             byte[] writeContent = new byte[10];
    357             for (int i = 0; i < writeContent.length; i++) {
    358                 writeContent[i] = (byte) i;
    359             }
    360 
    361             // establish connection
    362             channel1.connect(localAddr1);
    363             Socket acceptedSocket = server1.accept();
    364             // use OutputStream.write to write bytes data.
    365             OutputStream out = acceptedSocket.getOutputStream();
    366             out.write(writeContent);
    367             // use close to guarantee all data is sent
    368             acceptedSocket.close();
    369 
    370             channel1.configureBlocking(false);
    371             ByteBuffer readContent = ByteBuffer.allocate(10 + 1);
    372             channel1.shutdownInput();
    373             assertEquals(-1, channel1.read(readContent));
    374         }
    375     }
    376 
    377     public void test_shutdownOutput() throws IOException {
    378         try (SocketChannel channel1 = SocketChannel.open();
    379             ServerSocket server1 = new ServerSocket(0)) {
    380             InetSocketAddress localAddr1 = new InetSocketAddress(
    381                 "127.0.0.1", server1.getLocalPort());
    382 
    383             // initialize write content
    384             ByteBuffer writeContent = ByteBuffer.allocate(10);
    385             for (int i = 0; i < 10; i++) {
    386                 writeContent.put((byte) i);
    387             }
    388             writeContent.flip();
    389 
    390             try {
    391                 channel1.shutdownOutput();
    392                 fail();
    393             } catch (NotYetConnectedException expected) {
    394             }
    395 
    396             // establish connection
    397             channel1.connect(localAddr1);
    398             channel1.shutdownOutput();
    399 
    400             try {
    401                 channel1.write(writeContent);
    402                 fail();
    403             } catch (ClosedChannelException expected) {
    404             }
    405 
    406             // Closing the channel early to verify that is CloseChannelException thrown by
    407             // #shutdownOutput.
    408             channel1.close();
    409 
    410             try {
    411                 channel1.shutdownOutput();
    412                 fail();
    413             } catch (ClosedChannelException expected) {
    414             }
    415         }
    416     }
    417 }
    418