1 /*
   2  * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /* @test
  25  * @bug 8195160
  26  * @summary Test socketchannel vector IO (use -Dseed=X to set PRNG seed)
  27  * @requires (os.family == "linux")
  28  * @library .. /test/lib /test/jdk/java/nio/channels
  29  * @build jdk.test.lib.RandomFactory
  30  * @build RsocketTest
  31  * @run main/othervm -Djava.net.preferIPv4Stack=true VectorIO
  32  * @key randomness
  33  */
  34 
  35 import java.io.IOException;
  36 import java.net.InetAddress;
  37 import java.net.InetSocketAddress;
  38 import java.nio.ByteBuffer;
  39 import java.nio.channels.ServerSocketChannel;
  40 import java.nio.channels.SocketChannel;
  41 import java.util.Random;
  42 import jdk.test.lib.RandomFactory;
  43 import jdk.net.Sockets;
  44 
  45 public class VectorIO {
  46 
  47     private static Random generator = RandomFactory.getRandom();
  48 
  49     static int testSize;
  50 
  51     // whether to use the write/read variant with a length parameter
  52     static boolean setLength;
  53 
  54     public static void main(String[] args) throws Exception {
  55         if (!RsocketTest.isRsocketAvailable())
  56             return;
  57 
  58         testSize = 1;
  59         setLength = false;
  60         runTest();
  61         for(int i = 15; i < 18; i++) {
  62             testSize = i;
  63             setLength = !setLength;
  64             runTest();
  65         }
  66     }
  67 
  68     static void runTest() throws Exception {
  69         System.err.println("Length " + testSize);
  70         Server sv = new Server(testSize);
  71         sv.start();
  72         bufferTest(sv.port());
  73         if (sv.finish(8000) == 0)
  74             throw new Exception("Failed: Length = " + testSize);
  75     }
  76 
  77     static void bufferTest(int port) throws Exception {
  78         ByteBuffer[] bufs = new ByteBuffer[testSize];
  79         long total = 0L;
  80         for(int i = 0; i < testSize; i++) {
  81             String source = "buffer" + i;
  82             if (generator.nextBoolean())
  83                 bufs[i] = ByteBuffer.allocateDirect(source.length());
  84             else
  85                 bufs[i] = ByteBuffer.allocate(source.length());
  86 
  87             bufs[i].put(source.getBytes("8859_1"));
  88             bufs[i].flip();
  89             total += bufs[i].remaining();
  90         }
  91 
  92         ByteBuffer[] bufsPlus1 = new ByteBuffer[bufs.length + 1];
  93         System.arraycopy(bufs, 0, bufsPlus1, 0, bufs.length);
  94 
  95         // Get a connection to the server
  96         InetAddress lh = InetAddress.getLocalHost();
  97         InetSocketAddress isa = new InetSocketAddress(lh, port);
  98         SocketChannel sc = Sockets.openRdmaSocketChannel();
  99         sc.connect(isa);
 100         sc.configureBlocking(generator.nextBoolean());
 101 
 102         // Write the data out
 103         long rem = total;
 104         while (rem > 0L) {
 105             long bytesWritten;
 106             if (setLength) {
 107                 bytesWritten = sc.write(bufsPlus1, 0, bufs.length);
 108             } else {
 109                 bytesWritten = sc.write(bufs);
 110             }
 111             if (bytesWritten == 0) {
 112                 if (sc.isBlocking()) {
 113                     throw new RuntimeException("write did not block");
 114                 } else {
 115                     System.err.println("Non-blocking write() wrote zero bytes");
 116                 }
 117                 Thread.sleep(50);
 118             } else {
 119                 rem -= bytesWritten;
 120             }
 121         }
 122 
 123         // Clean up
 124         sc.close();
 125     }
 126 
 127     static class Server
 128         extends TestThread
 129     {
 130         final int testSize;
 131         final ServerSocketChannel ssc;
 132 
 133         Server(int testSize) throws IOException {
 134             super("Server " + testSize);
 135             this.testSize = testSize;
 136             this.ssc = Sockets.openRdmaServerSocketChannel().bind(new InetSocketAddress(0));
 137         }
 138 
 139         int port() {
 140             return ssc.socket().getLocalPort();
 141         }
 142 
 143         void go() throws Exception {
 144             bufferTest();
 145         }
 146 
 147         void bufferTest() throws Exception {
 148             long total = 0L;
 149             ByteBuffer[] bufs = new ByteBuffer[testSize];
 150             for(int i=0; i<testSize; i++) {
 151                 String source = "buffer" + i;
 152                 if (generator.nextBoolean())
 153                     bufs[i] = ByteBuffer.allocateDirect(source.length());
 154                 else
 155                     bufs[i] = ByteBuffer.allocate(source.length());
 156                 total += bufs[i].capacity();
 157             }
 158 
 159             ByteBuffer[] bufsPlus1 = new ByteBuffer[bufs.length + 1];
 160             System.arraycopy(bufs, 0, bufsPlus1, 0, bufs.length);
 161 
 162             // Get a connection from client
 163             SocketChannel sc = null;
 164 
 165             try {
 166 
 167                 ssc.configureBlocking(false);
 168 
 169                 for (;;) {
 170                     sc = ssc.accept();
 171                     if (sc != null) {
 172                         System.err.println("accept() succeeded");
 173                         break;
 174                     }
 175                     Thread.sleep(50);
 176                 }
 177 
 178                 sc.configureBlocking(generator.nextBoolean());
 179 
 180                 // Read data into multiple buffers
 181                 long avail = total;
 182                 while (avail > 0) {
 183                     long bytesRead;
 184                     if (setLength) {
 185                         bytesRead = sc.read(bufsPlus1, 0, bufs.length);
 186                     } else {
 187                         bytesRead = sc.read(bufs);
 188                     }
 189                     if (bytesRead < 0)
 190                         break;
 191                     if (bytesRead == 0) {
 192                         if (sc.isBlocking()) {
 193                             throw new RuntimeException("read did not block");
 194                         } else {
 195                             System.err.println
 196                                 ("Non-blocking read() read zero bytes");
 197                         }
 198                         Thread.sleep(50);
 199                     }
 200                     avail -= bytesRead;
 201                 }
 202 
 203                 // Check results
 204                 for(int i=0; i<testSize; i++) {
 205                     String expected = "buffer" + i;
 206                     bufs[i].flip();
 207                     int size = bufs[i].capacity();
 208                     byte[] data = new byte[size];
 209                     for(int j=0; j<size; j++)
 210                         data[j] = bufs[i].get();
 211                     String message = new String(data, "8859_1");
 212                     if (!message.equals(expected))
 213                         throw new Exception("Wrong data: Got "
 214                                             + message + ", expected "
 215                                             + expected);
 216                 }
 217 
 218             } finally {
 219                 // Clean up
 220                 ssc.close();
 221                 if (sc != null)
 222                     sc.close();
 223             }
 224 
 225         }
 226 
 227     }
 228 }