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 }
--- EOF ---