You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
209 lines
7.4 KiB
209 lines
7.4 KiB
/* |
|
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. |
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
* |
|
* This code is free software; you can redistribute it and/or modify it |
|
* under the terms of the GNU General Public License version 2 only, as |
|
* published by the Free Software Foundation. |
|
* |
|
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
* version 2 for more details (a copy is included in the LICENSE file that |
|
* accompanied this code). |
|
* |
|
* You should have received a copy of the GNU General Public License version |
|
* 2 along with this work; if not, write to the Free Software Foundation, |
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
* |
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
* or visit www.oracle.com if you need additional information or have any |
|
* questions. |
|
*/ |
|
|
|
/* @test |
|
* @bug 7176630 7074436 |
|
* @summary Check for short writes on SocketChannels configured in blocking mode |
|
* @key randomness |
|
*/ |
|
|
|
import java.net.*; |
|
import java.nio.ByteBuffer; |
|
import java.nio.channels.*; |
|
import java.util.concurrent.*; |
|
import java.util.Random; |
|
import java.util.zip.CRC32; |
|
|
|
public class ShortWrite { |
|
|
|
static final Random rand = new Random(); |
|
|
|
/** |
|
* Returns a checksum on the remaining bytes in the given buffers. |
|
*/ |
|
static long computeChecksum(ByteBuffer... bufs) { |
|
CRC32 crc32 = new CRC32(); |
|
for (int i=0; i<bufs.length; i++) |
|
crc32.update(bufs[i]); |
|
return crc32.getValue(); |
|
} |
|
|
|
/** |
|
* A task that reads the expected number of bytes and returns the CRC32 |
|
* of those bytes. |
|
*/ |
|
static class Reader implements Callable<Long> { |
|
final SocketChannel sc; |
|
final ByteBuffer buf; |
|
|
|
Reader(SocketChannel sc, int expectedSize) { |
|
this.sc = sc; |
|
this.buf = ByteBuffer.allocate(expectedSize); |
|
} |
|
|
|
public Long call() throws Exception { |
|
while (buf.hasRemaining()) { |
|
int n = sc.read(buf); |
|
if (n == -1) |
|
throw new RuntimeException("Premature EOF encountered"); |
|
} |
|
buf.flip(); |
|
return computeChecksum(buf); |
|
} |
|
} |
|
|
|
/** |
|
* Exercise write(ByteBuffer) with given number of bytes. |
|
*/ |
|
static void test1(ExecutorService pool, |
|
SocketChannel source, |
|
SocketChannel sink, |
|
int size) |
|
throws Exception |
|
{ |
|
System.out.println("write(ByteBuffer), size=" + size); |
|
|
|
// random bytes in the buffer |
|
ByteBuffer buf = ByteBuffer.allocate(size); |
|
rand.nextBytes(buf.array()); |
|
|
|
// submit task to read the bytes |
|
Future<Long> result = pool.submit(new Reader(sink, size)); |
|
|
|
// write the bytes |
|
int n = source.write(buf); |
|
if (n != size) |
|
throw new RuntimeException("Short write detected"); |
|
|
|
// check the bytes that were received match |
|
buf.rewind(); |
|
long expected = computeChecksum(buf); |
|
long actual = result.get(); |
|
if (actual != expected) |
|
throw new RuntimeException("Checksum did not match"); |
|
} |
|
|
|
/** |
|
* Exercise write(ByteBuffer[]) with buffers of the given sizes. |
|
*/ |
|
static void testN(ExecutorService pool, |
|
SocketChannel source, |
|
SocketChannel sink, |
|
int... sizes) |
|
throws Exception |
|
{ |
|
System.out.print("write(ByteBuffer[]), sizes="); |
|
for (int size: sizes) |
|
System.out.print(size + " "); |
|
System.out.println(); |
|
|
|
int total = 0; |
|
int len = sizes.length; |
|
ByteBuffer[] bufs = new ByteBuffer[len]; |
|
for (int i=0; i<len; i++) { |
|
int size = sizes[i]; |
|
ByteBuffer buf = ByteBuffer.allocate(size); |
|
rand.nextBytes(buf.array()); |
|
bufs[i] = buf; |
|
total += size; |
|
} |
|
|
|
// submit task to read the bytes |
|
Future<Long> result = pool.submit(new Reader(sink, total)); |
|
|
|
// write the bytes |
|
long n = source.write(bufs); |
|
if (n != total) |
|
throw new RuntimeException("Short write detected"); |
|
|
|
// check the bytes that were received match |
|
for (int i=0; i<len; i++) |
|
bufs[i].rewind(); |
|
long expected = computeChecksum(bufs); |
|
long actual = result.get(); |
|
if (actual != expected) |
|
throw new RuntimeException("Checksum did not match"); |
|
} |
|
|
|
public static void main(String[] args) throws Exception { |
|
ExecutorService pool = Executors.newSingleThreadExecutor(); |
|
try { |
|
try (ServerSocketChannel ssc = ServerSocketChannel.open()) { |
|
ssc.bind(new InetSocketAddress(0)); |
|
InetAddress lh = InetAddress.getLocalHost(); |
|
int port = ssc.socket().getLocalPort(); |
|
SocketAddress sa = new InetSocketAddress(lh, port); |
|
|
|
try (SocketChannel source = SocketChannel.open(sa); |
|
SocketChannel sink = ssc.accept()) |
|
{ |
|
// Exercise write(BufferBuffer) on sizes around 128k |
|
int BOUNDARY = 128 * 1024; |
|
for (int size=(BOUNDARY-2); size<=(BOUNDARY+2); size++) { |
|
test1(pool, source, sink, size); |
|
} |
|
|
|
// Exercise write(BufferBuffer) on random sizes |
|
for (int i=0; i<20; i++) { |
|
int size = rand.nextInt(1024*1024); |
|
test1(pool, source, sink, size); |
|
} |
|
|
|
// Exercise write(BufferBuffer[]) on sizes around 128k |
|
for (int i=BOUNDARY-2; i<=BOUNDARY+2; i++) { |
|
testN(pool, source, sink, i); |
|
testN(pool, source, sink, 0, i); |
|
testN(pool, source, sink, i, 0); |
|
for (int j=BOUNDARY-2; j<=BOUNDARY+2; j++) { |
|
testN(pool, source, sink, i, j); |
|
testN(pool, source, sink, 0, i, j); |
|
testN(pool, source, sink, i, 0, j); |
|
testN(pool, source, sink, i, j, 0); |
|
for (int k=BOUNDARY-2; k<=BOUNDARY+2; k++) { |
|
testN(pool, source, sink, i, j, k); |
|
testN(pool, source, sink, 0, i, j, k); |
|
testN(pool, source, sink, i, 0, j, k); |
|
testN(pool, source, sink, i, j, 0, k); |
|
testN(pool, source, sink, i, j, k, 0); |
|
} |
|
} |
|
} |
|
|
|
// Exercise write(BufferBuffer[]) on random sizes |
|
// (assumes IOV_MAX >= 8) |
|
for (int i=0; i<20; i++) { |
|
int n = rand.nextInt(9); |
|
int[] sizes = new int[n]; |
|
for (int j=0; j<n; j++) { |
|
sizes[j] = rand.nextInt(1024*1024); |
|
} |
|
testN(pool, source, sink, sizes); |
|
} |
|
} |
|
} |
|
|
|
} finally { |
|
pool.shutdown(); |
|
} |
|
} |
|
}
|
|
|