Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2008 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 android.net.cts;
     18 
     19 import junit.framework.TestCase;
     20 
     21 import android.net.Credentials;
     22 import android.net.LocalServerSocket;
     23 import android.net.LocalSocket;
     24 import android.net.LocalSocketAddress;
     25 import android.system.Os;
     26 import android.system.OsConstants;
     27 
     28 import java.io.FileDescriptor;
     29 import java.io.IOException;
     30 import java.io.InputStream;
     31 import java.io.OutputStream;
     32 import java.util.concurrent.Callable;
     33 import java.util.concurrent.CountDownLatch;
     34 import java.util.concurrent.ExecutorService;
     35 import java.util.concurrent.Executors;
     36 import java.util.concurrent.Future;
     37 import java.util.concurrent.TimeUnit;
     38 
     39 public class LocalSocketTest extends TestCase {
     40     private final static String ADDRESS_PREFIX = "com.android.net.LocalSocketTest";
     41 
     42     public void testLocalConnections() throws IOException {
     43         String address = ADDRESS_PREFIX + "_testLocalConnections";
     44         // create client and server socket
     45         LocalServerSocket localServerSocket = new LocalServerSocket(address);
     46         LocalSocket clientSocket = new LocalSocket();
     47 
     48         // establish connection between client and server
     49         LocalSocketAddress locSockAddr = new LocalSocketAddress(address);
     50         assertFalse(clientSocket.isConnected());
     51         clientSocket.connect(locSockAddr);
     52         assertTrue(clientSocket.isConnected());
     53 
     54         LocalSocket serverSocket = localServerSocket.accept();
     55         assertTrue(serverSocket.isConnected());
     56         assertTrue(serverSocket.isBound());
     57         try {
     58             serverSocket.bind(localServerSocket.getLocalSocketAddress());
     59             fail("Cannot bind a LocalSocket from accept()");
     60         } catch (IOException expected) {
     61         }
     62         try {
     63             serverSocket.connect(locSockAddr);
     64             fail("Cannot connect a LocalSocket from accept()");
     65         } catch (IOException expected) {
     66         }
     67 
     68         Credentials credent = clientSocket.getPeerCredentials();
     69         assertTrue(0 != credent.getPid());
     70 
     71         // send data from client to server
     72         OutputStream clientOutStream = clientSocket.getOutputStream();
     73         clientOutStream.write(12);
     74         InputStream serverInStream = serverSocket.getInputStream();
     75         assertEquals(12, serverInStream.read());
     76 
     77         //send data from server to client
     78         OutputStream serverOutStream = serverSocket.getOutputStream();
     79         serverOutStream.write(3);
     80         InputStream clientInStream = clientSocket.getInputStream();
     81         assertEquals(3, clientInStream.read());
     82 
     83         // Test sending and receiving file descriptors
     84         clientSocket.setFileDescriptorsForSend(new FileDescriptor[]{FileDescriptor.in});
     85         clientOutStream.write(32);
     86         assertEquals(32, serverInStream.read());
     87 
     88         FileDescriptor[] out = serverSocket.getAncillaryFileDescriptors();
     89         assertEquals(1, out.length);
     90         FileDescriptor fd = clientSocket.getFileDescriptor();
     91         assertTrue(fd.valid());
     92 
     93         //shutdown input stream of client
     94         clientSocket.shutdownInput();
     95         assertEquals(-1, clientInStream.read());
     96 
     97         //shutdown output stream of client
     98         clientSocket.shutdownOutput();
     99         try {
    100             clientOutStream.write(10);
    101             fail("testLocalSocket shouldn't come to here");
    102         } catch (IOException e) {
    103             // expected
    104         }
    105 
    106         //shutdown input stream of server
    107         serverSocket.shutdownInput();
    108         assertEquals(-1, serverInStream.read());
    109 
    110         //shutdown output stream of server
    111         serverSocket.shutdownOutput();
    112         try {
    113             serverOutStream.write(10);
    114             fail("testLocalSocket shouldn't come to here");
    115         } catch (IOException e) {
    116             // expected
    117         }
    118 
    119         //close client socket
    120         clientSocket.close();
    121         try {
    122             clientInStream.read();
    123             fail("testLocalSocket shouldn't come to here");
    124         } catch (IOException e) {
    125             // expected
    126         }
    127 
    128         //close server socket
    129         serverSocket.close();
    130         try {
    131             serverInStream.read();
    132             fail("testLocalSocket shouldn't come to here");
    133         } catch (IOException e) {
    134             // expected
    135         }
    136     }
    137 
    138     public void testAccessors() throws IOException {
    139         String address = ADDRESS_PREFIX + "_testAccessors";
    140         LocalSocket socket = new LocalSocket();
    141         LocalSocketAddress addr = new LocalSocketAddress(address);
    142 
    143         assertFalse(socket.isBound());
    144         socket.bind(addr);
    145         assertTrue(socket.isBound());
    146         assertEquals(addr, socket.getLocalSocketAddress());
    147 
    148         String str = socket.toString();
    149         assertTrue(str.contains("impl:android.net.LocalSocketImpl"));
    150 
    151         socket.setReceiveBufferSize(1999);
    152         assertEquals(1999 << 1, socket.getReceiveBufferSize());
    153 
    154         socket.setSendBufferSize(3998);
    155         assertEquals(3998 << 1, socket.getSendBufferSize());
    156 
    157         assertEquals(0, socket.getSoTimeout());
    158         socket.setSoTimeout(1996);
    159         assertTrue(socket.getSoTimeout() > 0);
    160 
    161         try {
    162             socket.getRemoteSocketAddress();
    163             fail("testLocalSocketSecondary shouldn't come to here");
    164         } catch (UnsupportedOperationException e) {
    165             // expected
    166         }
    167 
    168         try {
    169             socket.isClosed();
    170             fail("testLocalSocketSecondary shouldn't come to here");
    171         } catch (UnsupportedOperationException e) {
    172             // expected
    173         }
    174 
    175         try {
    176             socket.isInputShutdown();
    177             fail("testLocalSocketSecondary shouldn't come to here");
    178         } catch (UnsupportedOperationException e) {
    179             // expected
    180         }
    181 
    182         try {
    183             socket.isOutputShutdown();
    184             fail("testLocalSocketSecondary shouldn't come to here");
    185         } catch (UnsupportedOperationException e) {
    186             // expected
    187         }
    188 
    189         try {
    190             socket.connect(addr, 2005);
    191             fail("testLocalSocketSecondary shouldn't come to here");
    192         } catch (UnsupportedOperationException e) {
    193             // expected
    194         }
    195 
    196         socket.close();
    197     }
    198 
    199     // http://b/31205169
    200     public void testSetSoTimeout_readTimeout() throws Exception {
    201         String address = ADDRESS_PREFIX + "_testSetSoTimeout_readTimeout";
    202 
    203         try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) {
    204             final LocalSocket clientSocket = socketPair.clientSocket;
    205 
    206             // Set the timeout in millis.
    207             int timeoutMillis = 1000;
    208             clientSocket.setSoTimeout(timeoutMillis);
    209 
    210             // Avoid blocking the test run if timeout doesn't happen by using a separate thread.
    211             Callable<Result> reader = () -> {
    212                 try {
    213                     clientSocket.getInputStream().read();
    214                     return Result.noException("Did not block");
    215                 } catch (IOException e) {
    216                     return Result.exception(e);
    217                 }
    218             };
    219             // Allow the configured timeout, plus some slop.
    220             int allowedTime = timeoutMillis + 2000;
    221             Result result = runInSeparateThread(allowedTime, reader);
    222 
    223             // Check the message was a timeout, it's all we have to go on.
    224             String expectedMessage = Os.strerror(OsConstants.EAGAIN);
    225             result.assertThrewIOException(expectedMessage);
    226         }
    227     }
    228 
    229     // http://b/31205169
    230     public void testSetSoTimeout_writeTimeout() throws Exception {
    231         String address = ADDRESS_PREFIX + "_testSetSoTimeout_writeTimeout";
    232 
    233         try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) {
    234             final LocalSocket clientSocket = socketPair.clientSocket;
    235 
    236             // Set the timeout in millis.
    237             int timeoutMillis = 1000;
    238             clientSocket.setSoTimeout(timeoutMillis);
    239 
    240             // Set a small buffer size so we know we can flood it.
    241             clientSocket.setSendBufferSize(100);
    242             final int bufferSize = clientSocket.getSendBufferSize();
    243 
    244             // Avoid blocking the test run if timeout doesn't happen by using a separate thread.
    245             Callable<Result> writer = () -> {
    246                 try {
    247                     byte[] toWrite = new byte[bufferSize * 2];
    248                     clientSocket.getOutputStream().write(toWrite);
    249                     return Result.noException("Did not block");
    250                 } catch (IOException e) {
    251                     return Result.exception(e);
    252                 }
    253             };
    254             // Allow the configured timeout, plus some slop.
    255             int allowedTime = timeoutMillis + 2000;
    256 
    257             Result result = runInSeparateThread(allowedTime, writer);
    258 
    259             // Check the message was a timeout, it's all we have to go on.
    260             String expectedMessage = Os.strerror(OsConstants.EAGAIN);
    261             result.assertThrewIOException(expectedMessage);
    262         }
    263     }
    264 
    265     public void testAvailable() throws Exception {
    266         String address = ADDRESS_PREFIX + "_testAvailable";
    267 
    268         try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) {
    269             LocalSocket clientSocket = socketPair.clientSocket;
    270             LocalSocket serverSocket = socketPair.serverSocket.accept();
    271 
    272             OutputStream clientOutputStream = clientSocket.getOutputStream();
    273             InputStream serverInputStream = serverSocket.getInputStream();
    274             assertEquals(0, serverInputStream.available());
    275 
    276             byte[] buffer = new byte[50];
    277             clientOutputStream.write(buffer);
    278             assertEquals(50, serverInputStream.available());
    279 
    280             InputStream clientInputStream = clientSocket.getInputStream();
    281             OutputStream serverOutputStream = serverSocket.getOutputStream();
    282             assertEquals(0, clientInputStream.available());
    283             serverOutputStream.write(buffer);
    284             assertEquals(50, serverInputStream.available());
    285 
    286             serverSocket.close();
    287         }
    288     }
    289 
    290     // http://b/34095140
    291     public void testLocalSocketCreatedFromFileDescriptor() throws Exception {
    292         String address = ADDRESS_PREFIX + "_testLocalSocketCreatedFromFileDescriptor";
    293 
    294         // Establish connection between a local client and server to get a valid client socket file
    295         // descriptor.
    296         try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) {
    297             // Extract the client FileDescriptor we can use.
    298             FileDescriptor fileDescriptor = socketPair.clientSocket.getFileDescriptor();
    299             assertTrue(fileDescriptor.valid());
    300 
    301             // Create the LocalSocket we want to test.
    302             LocalSocket clientSocketCreatedFromFileDescriptor =
    303                     LocalSocket.createConnectedLocalSocket(fileDescriptor);
    304             assertTrue(clientSocketCreatedFromFileDescriptor.isConnected());
    305             assertTrue(clientSocketCreatedFromFileDescriptor.isBound());
    306 
    307             // Test the LocalSocket can be used for communication.
    308             LocalSocket serverSocket = socketPair.serverSocket.accept();
    309             OutputStream clientOutputStream =
    310                     clientSocketCreatedFromFileDescriptor.getOutputStream();
    311             InputStream serverInputStream = serverSocket.getInputStream();
    312 
    313             clientOutputStream.write(12);
    314             assertEquals(12, serverInputStream.read());
    315 
    316             // Closing clientSocketCreatedFromFileDescriptor does not close the file descriptor.
    317             clientSocketCreatedFromFileDescriptor.close();
    318             assertTrue(fileDescriptor.valid());
    319 
    320             // .. while closing the LocalSocket that owned the file descriptor does.
    321             socketPair.clientSocket.close();
    322             assertFalse(fileDescriptor.valid());
    323         }
    324     }
    325 
    326     public void testFlush() throws Exception {
    327         String address = ADDRESS_PREFIX + "_testFlush";
    328 
    329         try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) {
    330             LocalSocket clientSocket = socketPair.clientSocket;
    331             LocalSocket serverSocket = socketPair.serverSocket.accept();
    332 
    333             OutputStream clientOutputStream = clientSocket.getOutputStream();
    334             InputStream serverInputStream = serverSocket.getInputStream();
    335             testFlushWorks(clientOutputStream, serverInputStream);
    336 
    337             OutputStream serverOutputStream = serverSocket.getOutputStream();
    338             InputStream clientInputStream = clientSocket.getInputStream();
    339             testFlushWorks(serverOutputStream, clientInputStream);
    340 
    341             serverSocket.close();
    342         }
    343     }
    344 
    345     private void testFlushWorks(OutputStream outputStream, InputStream inputStream)
    346             throws Exception {
    347         final int bytesToTransfer = 50;
    348         StreamReader inputStreamReader = new StreamReader(inputStream, bytesToTransfer);
    349 
    350         byte[] buffer = new byte[bytesToTransfer];
    351         outputStream.write(buffer);
    352         assertEquals(bytesToTransfer, inputStream.available());
    353 
    354         // Start consuming the data.
    355         inputStreamReader.start();
    356 
    357         // This doesn't actually flush any buffers, it just polls until the reader has read all the
    358         // bytes.
    359         outputStream.flush();
    360 
    361         inputStreamReader.waitForCompletion(5000);
    362         inputStreamReader.assertBytesRead(bytesToTransfer);
    363         assertEquals(0, inputStream.available());
    364     }
    365 
    366     private static class StreamReader extends Thread {
    367         private final InputStream is;
    368         private final int expectedByteCount;
    369         private final CountDownLatch completeLatch = new CountDownLatch(1);
    370 
    371         private volatile Exception exception;
    372         private int bytesRead;
    373 
    374         private StreamReader(InputStream is, int expectedByteCount) {
    375             this.is = is;
    376             this.expectedByteCount = expectedByteCount;
    377         }
    378 
    379         @Override
    380         public void run() {
    381             try {
    382                 byte[] buffer = new byte[10];
    383                 int readCount;
    384                 while ((readCount = is.read(buffer)) >= 0) {
    385                     bytesRead += readCount;
    386                     if (bytesRead >= expectedByteCount) {
    387                         break;
    388                     }
    389                 }
    390             } catch (IOException e) {
    391                 exception = e;
    392             } finally {
    393                 completeLatch.countDown();
    394             }
    395         }
    396 
    397         public void waitForCompletion(long waitMillis) throws Exception {
    398             if (!completeLatch.await(waitMillis, TimeUnit.MILLISECONDS)) {
    399                 fail("Timeout waiting for completion");
    400             }
    401             if (exception != null) {
    402                 throw new Exception("Read failed", exception);
    403             }
    404         }
    405 
    406         public void assertBytesRead(int expected) {
    407             assertEquals(expected, bytesRead);
    408         }
    409     }
    410 
    411     private static class Result {
    412         private final String type;
    413         private final Exception e;
    414 
    415         private Result(String type, Exception e) {
    416             this.type = type;
    417             this.e = e;
    418         }
    419 
    420         static Result noException(String description) {
    421             return new Result(description, null);
    422         }
    423 
    424         static Result exception(Exception e) {
    425             return new Result(e.getClass().getName(), e);
    426         }
    427 
    428         void assertThrewIOException(String expectedMessage) {
    429             assertEquals("Unexpected result type", IOException.class.getName(), type);
    430             assertEquals("Unexpected exception message", expectedMessage, e.getMessage());
    431         }
    432     }
    433 
    434     private static Result runInSeparateThread(int allowedTime, final Callable<Result> callable)
    435             throws Exception {
    436         ExecutorService service = Executors.newSingleThreadScheduledExecutor();
    437         Future<Result> future = service.submit(callable);
    438         Result result = future.get(allowedTime, TimeUnit.MILLISECONDS);
    439         if (!future.isDone()) {
    440             fail("Worker thread appears blocked");
    441         }
    442         return result;
    443     }
    444 
    445     private static class LocalSocketPair implements AutoCloseable {
    446         static LocalSocketPair createConnectedSocketPair(String address) throws Exception {
    447             LocalServerSocket localServerSocket = new LocalServerSocket(address);
    448             final LocalSocket clientSocket = new LocalSocket();
    449 
    450             // Establish connection between client and server
    451             LocalSocketAddress locSockAddr = new LocalSocketAddress(address);
    452             clientSocket.connect(locSockAddr);
    453             assertTrue(clientSocket.isConnected());
    454             return new LocalSocketPair(localServerSocket, clientSocket);
    455         }
    456 
    457         final LocalServerSocket serverSocket;
    458         final LocalSocket clientSocket;
    459 
    460         LocalSocketPair(LocalServerSocket serverSocket, LocalSocket clientSocket) {
    461             this.serverSocket = serverSocket;
    462             this.clientSocket = clientSocket;
    463         }
    464 
    465         public void close() throws Exception {
    466             serverSocket.close();
    467             clientSocket.close();
    468         }
    469     }
    470 }
    471