1 /* 2 * Copyright (c) 2012, 2013, 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 7176630 7074436 26 * @summary Check for short writes on SocketChannels configured in blocking mode 27 * @key randomness 28 */ 29 30 import java.net.*; 31 import java.nio.ByteBuffer; 32 import java.nio.channels.*; 33 import java.util.concurrent.*; 34 import java.util.Random; 35 import java.util.zip.CRC32; 36 37 public class ShortWrite { 38 39 static final Random rand = new Random(); 40 41 /** 42 * Returns a checksum on the remaining bytes in the given buffers. 43 */ 44 static long computeChecksum(ByteBuffer... bufs) { 45 CRC32 crc32 = new CRC32(); 46 for (int i=0; i<bufs.length; i++) 47 crc32.update(bufs[i]); 48 return crc32.getValue(); 49 } 50 51 /** 52 * A task that reads the expected number of bytes and returns the CRC32 53 * of those bytes. 54 */ 55 static class Reader implements Callable<Long> { 56 final SocketChannel sc; 57 final ByteBuffer buf; 58 59 Reader(SocketChannel sc, int expectedSize) { 60 this.sc = sc; 61 this.buf = ByteBuffer.allocate(expectedSize); 62 } 63 64 public Long call() throws Exception { 65 while (buf.hasRemaining()) { 66 int n = sc.read(buf); 67 if (n == -1) 68 throw new RuntimeException("Premature EOF encountered"); 69 } 70 buf.flip(); 71 return computeChecksum(buf); 72 } 73 } 74 75 /** 76 * Exercise write(ByteBuffer) with given number of bytes. 77 */ 78 static void test1(ExecutorService pool, 79 SocketChannel source, 80 SocketChannel sink, 81 int size) 82 throws Exception 83 { 84 System.out.println("write(ByteBuffer), size=" + size); 85 86 // random bytes in the buffer 87 ByteBuffer buf = ByteBuffer.allocate(size); 88 rand.nextBytes(buf.array()); 89 90 // submit task to read the bytes 91 Future<Long> result = pool.submit(new Reader(sink, size)); 92 93 // write the bytes 94 int n = source.write(buf); 95 if (n != size) 96 throw new RuntimeException("Short write detected"); 97 98 // check the bytes that were received match 99 buf.rewind(); 100 long expected = computeChecksum(buf); 101 long actual = result.get(); 102 if (actual != expected) 103 throw new RuntimeException("Checksum did not match"); 104 } 105 106 /** 107 * Exercise write(ByteBuffer[]) with buffers of the given sizes. 108 */ 109 static void testN(ExecutorService pool, 110 SocketChannel source, 111 SocketChannel sink, 112 int... sizes) 113 throws Exception 114 { 115 System.out.print("write(ByteBuffer[]), sizes="); 116 for (int size: sizes) 117 System.out.print(size + " "); 118 System.out.println(); 119 120 int total = 0; 121 int len = sizes.length; 122 ByteBuffer[] bufs = new ByteBuffer[len]; 123 for (int i=0; i<len; i++) { 124 int size = sizes[i]; 125 ByteBuffer buf = ByteBuffer.allocate(size); 126 rand.nextBytes(buf.array()); 127 bufs[i] = buf; 128 total += size; 129 } 130 131 // submit task to read the bytes 132 Future<Long> result = pool.submit(new Reader(sink, total)); 133 134 // write the bytes 135 long n = source.write(bufs); 136 if (n != total) 137 throw new RuntimeException("Short write detected"); 138 139 // check the bytes that were received match 140 for (int i=0; i<len; i++) 141 bufs[i].rewind(); 142 long expected = computeChecksum(bufs); 143 long actual = result.get(); 144 if (actual != expected) 145 throw new RuntimeException("Checksum did not match"); 146 } 147 148 public static void main(String[] args) throws Exception { 149 ExecutorService pool = Executors.newSingleThreadExecutor(); 150 try { 151 try (ServerSocketChannel ssc = ServerSocketChannel.open()) { 152 ssc.bind(new InetSocketAddress(0)); 153 InetAddress lh = InetAddress.getLocalHost(); 154 int port = ssc.socket().getLocalPort(); 155 SocketAddress sa = new InetSocketAddress(lh, port); 156 157 try (SocketChannel source = SocketChannel.open(sa); 158 SocketChannel sink = ssc.accept()) 159 { 160 // Exercise write(BufferBuffer) on sizes around 128k 161 int BOUNDARY = 128 * 1024; 162 for (int size=(BOUNDARY-2); size<=(BOUNDARY+2); size++) { 163 test1(pool, source, sink, size); 164 } 165 166 // Exercise write(BufferBuffer) on random sizes 167 for (int i=0; i<20; i++) { 168 int size = rand.nextInt(1024*1024); 169 test1(pool, source, sink, size); 170 } 171 172 // Exercise write(BufferBuffer[]) on sizes around 128k 173 for (int i=BOUNDARY-2; i<=BOUNDARY+2; i++) { 174 testN(pool, source, sink, i); 175 testN(pool, source, sink, 0, i); 176 testN(pool, source, sink, i, 0); 177 for (int j=BOUNDARY-2; j<=BOUNDARY+2; j++) { 178 testN(pool, source, sink, i, j); 179 testN(pool, source, sink, 0, i, j); 180 testN(pool, source, sink, i, 0, j); 181 testN(pool, source, sink, i, j, 0); 182 for (int k=BOUNDARY-2; k<=BOUNDARY+2; k++) { 183 testN(pool, source, sink, i, j, k); 184 testN(pool, source, sink, 0, i, j, k); 185 testN(pool, source, sink, i, 0, j, k); 186 testN(pool, source, sink, i, j, 0, k); 187 testN(pool, source, sink, i, j, k, 0); 188 } 189 } 190 } 191 192 // Exercise write(BufferBuffer[]) on random sizes 193 // (assumes IOV_MAX >= 8) 194 for (int i=0; i<20; i++) { 195 int n = rand.nextInt(9); 196 int[] sizes = new int[n]; 197 for (int j=0; j<n; j++) { 198 sizes[j] = rand.nextInt(1024*1024); 199 } 200 testN(pool, source, sink, sizes); 201 } 202 } 203 } 204 205 } finally { 206 pool.shutdown(); 207 } 208 } 209 }