Basic.java revision 893:f06f30b29f36
1/*
2 * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20 * CA 95054 USA or visit www.sun.com if you need additional information or
21 * have any questions.
22 */
23
24/* @test
25 * @bug 4607272
26 * @summary Unit test for AsynchronousSocketChannel
27 * @run main/timeout=600 Basic
28 */
29
30import java.nio.ByteBuffer;
31import java.nio.channels.*;
32import static java.net.StandardSocketOption.*;
33import java.net.*;
34import java.util.Random;
35import java.util.concurrent.*;
36import java.util.concurrent.atomic.*;
37import java.io.IOException;
38
39public class Basic {
40    static final Random rand = new Random();
41
42    public static void main(String[] args) throws Exception {
43        testBind();
44        testSocketOptions();
45        testConnect();
46        testCloseWhenPending();
47        testCancel();
48        testRead1();
49        testRead2();
50        testRead3();
51        testWrite1();
52        testWrite2();
53        testTimeout();
54        testShutdown();
55    }
56
57    static class Server {
58        private final ServerSocketChannel ssc;
59        private final InetSocketAddress address;
60
61        Server() throws IOException {
62            ssc = ServerSocketChannel.open().bind(new InetSocketAddress(0));
63
64            InetAddress lh = InetAddress.getLocalHost();
65            int port = ((InetSocketAddress)(ssc.getLocalAddress())).getPort();
66            address = new InetSocketAddress(lh, port);
67        }
68
69        InetSocketAddress address() {
70            return address;
71        }
72
73        SocketChannel accept() throws IOException {
74            return ssc.accept();
75        }
76
77        void close() {
78            try {
79                ssc.close();
80            } catch (IOException ignore) { }
81        }
82
83    }
84
85    static void testBind() throws Exception {
86        System.out.println("-- bind --");
87
88        AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();
89        if (ch.getLocalAddress() != null)
90            throw new RuntimeException("Local address should be 'null'");
91        ch.bind(new InetSocketAddress(0));
92
93        // check local address after binding
94        InetSocketAddress local = (InetSocketAddress)ch.getLocalAddress();
95        if (local.getPort() == 0)
96            throw new RuntimeException("Unexpected port");
97        if (!local.getAddress().isAnyLocalAddress())
98            throw new RuntimeException("Not bound to a wildcard address");
99
100        // try to re-bind
101        try {
102            ch.bind(new InetSocketAddress(0));
103            throw new RuntimeException("AlreadyBoundException expected");
104        } catch (AlreadyBoundException x) {
105        }
106        ch.close();
107
108        // check ClosedChannelException
109        ch = AsynchronousSocketChannel.open();
110        ch.close();
111        try {
112            ch.bind(new InetSocketAddress(0));
113            throw new RuntimeException("ClosedChannelException  expected");
114        } catch (ClosedChannelException  x) {
115        }
116    }
117
118    static void testSocketOptions() throws Exception {
119        System.out.println("-- socket options --");
120
121        AsynchronousSocketChannel ch = AsynchronousSocketChannel.open()
122            .setOption(SO_RCVBUF, 128*1024)
123            .setOption(SO_SNDBUF, 128*1024)
124            .setOption(SO_REUSEADDR, true)
125            .bind(new InetSocketAddress(0));
126
127        // default values
128        if ((Boolean)ch.getOption(SO_KEEPALIVE))
129            throw new RuntimeException("Default of SO_KEEPALIVE should be 'false'");
130        if ((Boolean)ch.getOption(TCP_NODELAY))
131            throw new RuntimeException("Default of TCP_NODELAY should be 'false'");
132
133        // set and check
134        if (!(Boolean)ch.setOption(SO_KEEPALIVE, true).getOption(SO_KEEPALIVE))
135            throw new RuntimeException("SO_KEEPALIVE did not change");
136        if (!(Boolean)ch.setOption(TCP_NODELAY, true).getOption(TCP_NODELAY))
137            throw new RuntimeException("SO_KEEPALIVE did not change");
138
139        // read others (can't check as actual value is implementation dependent)
140        ch.getOption(SO_RCVBUF);
141        ch.getOption(SO_SNDBUF);
142
143        ch.close();
144    }
145
146    static void testConnect() throws Exception {
147        System.out.println("-- connect --");
148
149        Server server = new Server();
150        AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();
151        ch.connect(server.address()).get();
152
153        // check local address
154        if (ch.getLocalAddress() == null)
155            throw new RuntimeException("Not bound to local address");
156
157        // check remote address
158        InetSocketAddress remote = (InetSocketAddress)ch.getRemoteAddress();
159        if (remote.getPort() != server.address().getPort())
160            throw new RuntimeException("Connected to unexpected port");
161        if (!remote.getAddress().equals(server.address().getAddress()))
162            throw new RuntimeException("Connected to unexpected address");
163
164        // try to connect again
165        try {
166            ch.connect(server.address()).get();
167            throw new RuntimeException("AlreadyConnectedException expected");
168        } catch (AlreadyConnectedException x) {
169        }
170        ch.close();
171
172        // check that connect fails with ClosedChannelException)
173        ch = AsynchronousSocketChannel.open();
174        ch.close();
175        try {
176            ch.connect(server.address()).get();
177            throw new RuntimeException("ExecutionException expected");
178        } catch (ExecutionException x) {
179            if (!(x.getCause() instanceof ClosedChannelException))
180                throw new RuntimeException("Cause of ClosedChannelException expected");
181        }
182        final AtomicReference<Throwable> connectException =
183            new AtomicReference<Throwable>();
184        ch.connect(server.address(), null, new CompletionHandler<Void,Void>() {
185            public void completed(Void result, Void att) {
186            }
187            public void failed(Throwable exc, Void att) {
188                connectException.set(exc);
189            }
190            public void cancelled(Void att) {
191            }
192        });
193        while (connectException.get() == null) {
194            Thread.sleep(100);
195        }
196        if (!(connectException.get() instanceof ClosedChannelException))
197            throw new RuntimeException("ClosedChannelException expected");
198
199        System.out.println("-- connect to non-existent host --");
200
201        // test failure
202        InetAddress badHost = InetAddress.getByName("1.2.3.4");
203        if (!badHost.isReachable(10*1000)) {
204
205            ch = AsynchronousSocketChannel.open();
206            try {
207                ch.connect(new InetSocketAddress(badHost, 9876)).get();
208                throw new RuntimeException("Connection should not be established");
209            } catch (ExecutionException x) {
210            }
211            if (ch.isOpen())
212                throw new RuntimeException("Channel should be closed");
213        }
214
215        server.close();
216    }
217
218    static void testCloseWhenPending() throws Exception {
219        System.out.println("-- asynchronous close when connecting --");
220
221        AsynchronousSocketChannel ch;
222
223        // asynchronous close while connecting
224        InetAddress rh = InetAddress.getByName("1.2.3.4");
225        if (!rh.isReachable(3000)) {
226            InetSocketAddress isa = new InetSocketAddress(rh, 1234);
227
228            ch = AsynchronousSocketChannel.open();
229            Future<Void> result = ch.connect(isa);
230
231            // give time to initiate the connect (SYN)
232            Thread.sleep(50);
233
234            // close
235            ch.close();
236
237            // check that AsynchronousCloseException is thrown
238            try {
239                result.get();
240                throw new RuntimeException("Should not connect");
241            } catch (ExecutionException x) {
242                if (!(x.getCause() instanceof AsynchronousCloseException))
243                    throw new RuntimeException(x);
244            }
245        }
246
247        System.out.println("-- asynchronous close when reading --");
248
249        Server server = new Server();
250        ch = AsynchronousSocketChannel.open();
251        ch.connect(server.address()).get();
252
253        ByteBuffer dst = ByteBuffer.allocateDirect(100);
254        Future<Integer> result = ch.read(dst);
255
256        // attempt a second read - should fail with ReadPendingException
257        ByteBuffer buf = ByteBuffer.allocateDirect(100);
258        try {
259            ch.read(buf);
260            throw new RuntimeException("ReadPendingException expected");
261        } catch (ReadPendingException x) {
262        }
263
264        // close channel (should cause initial read to complete)
265        ch.close();
266
267        // check that AsynchronousCloseException is thrown
268        try {
269            result.get();
270            throw new RuntimeException("Should not read");
271        } catch (ExecutionException x) {
272            if (!(x.getCause() instanceof AsynchronousCloseException))
273                throw new RuntimeException(x);
274        }
275
276        System.out.println("-- asynchronous close when writing --");
277
278        ch = AsynchronousSocketChannel.open();
279        ch.connect(server.address()).get();
280
281        final AtomicReference<Throwable> writeException =
282            new AtomicReference<Throwable>();
283
284        // write bytes to fill socket buffer
285        ch.write(genBuffer(), ch, new CompletionHandler<Integer,AsynchronousSocketChannel>() {
286            public void completed(Integer result, AsynchronousSocketChannel ch) {
287                ch.write(genBuffer(), ch, this);
288            }
289            public void failed(Throwable x, AsynchronousSocketChannel ch) {
290                writeException.set(x);
291            }
292            public void cancelled(AsynchronousSocketChannel ch) {
293            }
294        });
295
296        // give time for socket buffer to fill up.
297        Thread.sleep(5*1000);
298
299        //  attempt a concurrent write - should fail with WritePendingException
300        try {
301            ch.write(genBuffer());
302            throw new RuntimeException("WritePendingException expected");
303        } catch (WritePendingException x) {
304        }
305
306        // close channel - should cause initial write to complete
307        ch.close();
308
309        // wait for exception
310        while (writeException.get() == null) {
311            Thread.sleep(100);
312        }
313        if (!(writeException.get() instanceof AsynchronousCloseException))
314            throw new RuntimeException("AsynchronousCloseException expected");
315
316        server.close();
317    }
318
319    static void testCancel() throws Exception {
320        System.out.println("-- cancel --");
321
322        Server server = new Server();
323
324        for (int i=0; i<2; i++) {
325            boolean mayInterruptIfRunning = (i == 0) ? false : true;
326
327            // establish loopback connection
328            AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();
329            ch.connect(server.address()).get();
330            SocketChannel peer = server.accept();
331
332            // start read operation
333            final CountDownLatch latch = new CountDownLatch(1);
334            ByteBuffer buf = ByteBuffer.allocate(1);
335            Future<Integer> res = ch.read(buf, null,
336                new CompletionHandler<Integer,Void>() {
337                    public void completed(Integer result, Void att) {
338                    }
339                    public void failed(Throwable exc, Void att) {
340                    }
341                    public void cancelled(Void att) {
342                        latch.countDown();
343                    }
344            });
345
346            // cancel operation
347            boolean cancelled = res.cancel(mayInterruptIfRunning);
348
349            // check post-conditions
350            if (!res.isDone())
351                throw new RuntimeException("isDone should return true");
352            if (res.isCancelled() != cancelled)
353                throw new RuntimeException("isCancelled not consistent");
354            try {
355                res.get();
356                throw new RuntimeException("CancellationException expected");
357            } catch (CancellationException x) {
358            }
359            try {
360                res.get(1, TimeUnit.SECONDS);
361                throw new RuntimeException("CancellationException expected");
362            } catch (CancellationException x) {
363            }
364
365            // check that completion handler executed.
366            latch.await();
367
368            ch.close();
369            peer.close();
370        }
371
372        server.close();
373    }
374
375    static void testRead1() throws Exception {
376        System.out.println("-- read (1) --");
377
378        Server server = new Server();
379        final AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();
380        ch.connect(server.address()).get();
381
382        // read with 0 bytes remaining should complete immediately
383        ByteBuffer buf = ByteBuffer.allocate(1);
384        buf.put((byte)0);
385        int n = ch.read(buf).get();
386        if (n != 0)
387            throw new RuntimeException("0 expected");
388
389        // write bytes and close connection
390        SocketChannel sc = server.accept();
391        ByteBuffer src = genBuffer();
392        sc.setOption(StandardSocketOption.SO_SNDBUF, src.remaining());
393        while (src.hasRemaining())
394            sc.write(src);
395        sc.close();
396
397        // reads should complete immediately
398        final ByteBuffer dst = ByteBuffer.allocateDirect(src.capacity() + 100);
399        final CountDownLatch latch = new CountDownLatch(1);
400        ch.read(dst, null, new CompletionHandler<Integer,Void>() {
401            public void completed(Integer result, Void att) {
402                int n = result;
403                if (n > 0) {
404                    ch.read(dst, null, this);
405                } else {
406                    latch.countDown();
407                }
408            }
409            public void failed(Throwable exc, Void att) {
410            }
411            public void cancelled(Void att) {
412            }
413        });
414
415        latch.await();
416
417        // check buffers
418        src.flip();
419        dst.flip();
420        if (!src.equals(dst)) {
421            throw new RuntimeException("Contents differ");
422        }
423
424        // close channel
425        ch.close();
426
427        // check read fails with ClosedChannelException
428        try {
429            ch.read(dst).get();
430            throw new RuntimeException("ExecutionException expected");
431        } catch (ExecutionException x) {
432            if (!(x.getCause() instanceof ClosedChannelException))
433                throw new RuntimeException("Cause of ClosedChannelException expected");
434        }
435
436        server.close();
437    }
438
439    static void testRead2() throws Exception {
440        System.out.println("-- read (2) --");
441
442        Server server = new Server();
443
444        final AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();
445        ch.connect(server.address()).get();
446        SocketChannel sc = server.accept();
447
448        ByteBuffer src = genBuffer();
449
450        // read until the buffer is full
451        final ByteBuffer dst = ByteBuffer.allocateDirect(src.capacity());
452        final CountDownLatch latch = new CountDownLatch(1);
453        ch.read(dst, null, new CompletionHandler<Integer,Void>() {
454            public void completed(Integer result, Void att) {
455                if (dst.hasRemaining()) {
456                    ch.read(dst, null, this);
457                } else {
458                    latch.countDown();
459                }
460            }
461            public void failed(Throwable exc, Void att) {
462            }
463            public void cancelled(Void att) {
464            }
465        });
466
467        // trickle the writing
468        do {
469            int rem = src.remaining();
470            int size = (rem <= 100) ? rem : 50 + rand.nextInt(rem - 100);
471            ByteBuffer buf = ByteBuffer.allocate(size);
472            for (int i=0; i<size; i++)
473                buf.put(src.get());
474            buf.flip();
475            Thread.sleep(50 + rand.nextInt(1500));
476            while (buf.hasRemaining())
477                sc.write(buf);
478        } while (src.hasRemaining());
479
480        // wait until ascynrhonous reading has completed
481        latch.await();
482
483        // check buffers
484        src.flip();
485        dst.flip();
486        if (!src.equals(dst)) {
487           throw new RuntimeException("Contents differ");
488        }
489
490        sc.close();
491        ch.close();
492        server.close();
493    }
494
495    // exercise scattering read
496    static void testRead3() throws Exception {
497        System.out.println("-- read (3) --");
498
499        Server server = new Server();
500        final AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();
501        ch.connect(server.address()).get();
502        SocketChannel sc = server.accept();
503
504        ByteBuffer[] dsts = new ByteBuffer[3];
505        for (int i=0; i<dsts.length; i++) {
506            dsts[i] = ByteBuffer.allocateDirect(100);
507        }
508
509        // scattering read that completes ascynhronously
510        final CountDownLatch latch = new CountDownLatch(1);
511        ch.read(dsts, 0, dsts.length, 0L, TimeUnit.SECONDS, null,
512            new CompletionHandler<Long,Void>() {
513                public void completed(Long result, Void att) {
514                    long n = result;
515                    if (n <= 0)
516                        throw new RuntimeException("No bytes read");
517                    latch.countDown();
518                }
519                public void failed(Throwable exc, Void att) {
520                }
521                public void cancelled(Void att) {
522                }
523        });
524
525        // write some bytes
526        sc.write(genBuffer());
527
528        // read should now complete
529        latch.await();
530
531        // write more bytes
532        sc.write(genBuffer());
533
534        // read should complete immediately
535        for (int i=0; i<dsts.length; i++) {
536            dsts[i].rewind();
537        }
538        long n = ch
539            .read(dsts, 0, dsts.length, 0L, TimeUnit.SECONDS, null, null).get();
540        if (n <= 0)
541            throw new RuntimeException("No bytes read");
542
543        ch.close();
544        sc.close();
545        server.close();
546    }
547
548    static void testWrite1() throws Exception {
549        System.out.println("-- write (1) --");
550
551        Server server = new Server();
552        final AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();
553        ch.connect(server.address()).get();
554        SocketChannel sc = server.accept();
555
556        // write with 0 bytes remaining should complete immediately
557        ByteBuffer buf = ByteBuffer.allocate(1);
558        buf.put((byte)0);
559        int n = ch.write(buf).get();
560        if (n != 0)
561            throw new RuntimeException("0 expected");
562
563        // write all bytes and close connection when done
564        final ByteBuffer src = genBuffer();
565        ch.write(src, null, new CompletionHandler<Integer,Void>() {
566            public void completed(Integer result, Void att) {
567                if (src.hasRemaining()) {
568                    ch.write(src, null, this);
569                } else {
570                    try {
571                        ch.close();
572                    } catch (IOException ignore) { }
573                }
574            }
575            public void failed(Throwable exc, Void att) {
576            }
577            public void cancelled(Void att) {
578            }
579        });
580
581        // read to EOF or buffer full
582        ByteBuffer dst = ByteBuffer.allocateDirect(src.capacity() + 100);
583        do {
584            n = sc.read(dst);
585        } while (n > 0);
586        sc.close();
587
588        // check buffers
589        src.flip();
590        dst.flip();
591        if (!src.equals(dst)) {
592            throw new RuntimeException("Contents differ");
593        }
594
595        // check write fails with ClosedChannelException
596        try {
597            ch.read(dst).get();
598            throw new RuntimeException("ExecutionException expected");
599        } catch (ExecutionException x) {
600            if (!(x.getCause() instanceof ClosedChannelException))
601                throw new RuntimeException("Cause of ClosedChannelException expected");
602        }
603
604        server.close();
605    }
606
607    // exercise gathering write
608    static void testWrite2() throws Exception {
609        System.out.println("-- write (2) --");
610
611        Server server = new Server();
612        final AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();
613        ch.connect(server.address()).get();
614        SocketChannel sc = server.accept();
615
616        // write buffers (should complete immediately)
617        ByteBuffer[] srcs = genBuffers(1);
618        long n = ch
619            .write(srcs, 0, srcs.length, 0L, TimeUnit.SECONDS, null, null).get();
620        if (n <= 0)
621            throw new RuntimeException("No bytes written");
622
623        // set to true to signal that no more buffers should be written
624        final AtomicBoolean continueWriting = new AtomicBoolean(true);
625
626        // number of bytes written
627        final AtomicLong bytesWritten = new AtomicLong(n);
628
629        // write until socket buffer is full so as to create the conditions
630        // for when a write does not complete immediately
631        srcs = genBuffers(1);
632        ch.write(srcs, 0, srcs.length, 0L, TimeUnit.SECONDS, null,
633            new CompletionHandler<Long,Void>() {
634                public void completed(Long result, Void att) {
635                    long n = result;
636                    if (n <= 0)
637                        throw new RuntimeException("No bytes written");
638                    bytesWritten.addAndGet(n);
639                    if (continueWriting.get()) {
640                        ByteBuffer[] srcs = genBuffers(8);
641                        ch.write(srcs, 0, srcs.length, 0L, TimeUnit.SECONDS,
642                            null, this);
643                    }
644                }
645                public void failed(Throwable exc, Void att) {
646                }
647                public void cancelled(Void att) {
648                }
649        });
650
651        // give time for socket buffer to fill up.
652        Thread.sleep(5*1000);
653
654        // signal handler to stop further writing
655        continueWriting.set(false);
656
657        // read until done
658        ByteBuffer buf = ByteBuffer.allocateDirect(4096);
659        long total = 0L;
660        do {
661            n = sc.read(buf);
662            if (n <= 0)
663                throw new RuntimeException("No bytes read");
664            buf.rewind();
665            total += n;
666        } while (total < bytesWritten.get());
667
668        ch.close();
669        sc.close();
670        server.close();
671    }
672
673    static void testShutdown() throws Exception {
674        System.out.println("-- shutdown--");
675
676        Server server = new Server();
677        AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();
678        ch.connect(server.address()).get();
679        SocketChannel sc = server.accept();
680
681        ByteBuffer buf = ByteBuffer.allocateDirect(1000);
682        int n;
683
684        // check read
685        ch.shutdownInput();
686        n = ch.read(buf).get();
687        if (n != -1)
688            throw new RuntimeException("-1 expected");
689        // check full with full buffer
690        buf.put(new byte[100]);
691        n = ch.read(buf).get();
692        if (n != -1)
693            throw new RuntimeException("-1 expected");
694
695        // check write
696        ch.shutdownOutput();
697        try {
698            ch.write(buf).get();
699            throw new RuntimeException("ClosedChannelException expected");
700        } catch (ExecutionException x) {
701            if (!(x.getCause() instanceof ClosedChannelException))
702                throw new RuntimeException("ClosedChannelException expected");
703        }
704
705        sc.close();
706        ch.close();
707        server.close();
708    }
709
710    static void testTimeout() throws Exception {
711        Server server = new Server();
712        AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();
713        ch.connect(server.address()).get();
714
715        System.out.println("-- timeout when reading --");
716
717        // this read should timeout
718        ByteBuffer dst = ByteBuffer.allocate(512);
719        try {
720            ch.read(dst, 3, TimeUnit.SECONDS, null, null).get();
721            throw new RuntimeException("Read did not timeout");
722        } catch (ExecutionException x) {
723            if (!(x.getCause() instanceof InterruptedByTimeoutException))
724                throw new RuntimeException("InterruptedByTimeoutException expected");
725        }
726
727        // after a timeout then further reading should throw unspecified runtime exception
728        boolean exceptionThrown = false;
729        try {
730            ch.read(dst);
731        } catch (RuntimeException x) {
732            exceptionThrown = true;
733        }
734        if (!exceptionThrown)
735            throw new RuntimeException("RuntimeException expected after timeout.");
736
737
738        System.out.println("-- timeout when writing --");
739
740        final AtomicReference<Throwable> writeException = new AtomicReference<Throwable>();
741
742        final long timeout = 5;
743        final TimeUnit unit = TimeUnit.SECONDS;
744
745        // write bytes to fill socket buffer
746        ch.write(genBuffer(), timeout, unit, ch,
747            new CompletionHandler<Integer,AsynchronousSocketChannel>()
748        {
749            public void completed(Integer result, AsynchronousSocketChannel ch) {
750                ch.write(genBuffer(), timeout, unit, ch, this);
751            }
752            public void failed(Throwable exc, AsynchronousSocketChannel ch) {
753                writeException.set(exc);
754            }
755            public void cancelled(AsynchronousSocketChannel ch) {
756            }
757        });
758
759        // wait for exception
760        while (writeException.get() == null) {
761            Thread.sleep(100);
762        }
763        if (!(writeException.get() instanceof InterruptedByTimeoutException))
764            throw new RuntimeException("InterruptedByTimeoutException expected");
765
766        // after a timeout then further writing should throw unspecified runtime exception
767        exceptionThrown = false;
768        try {
769            ch.write(genBuffer());
770        } catch (RuntimeException x) {
771            exceptionThrown = true;
772        }
773        if (!exceptionThrown)
774            throw new RuntimeException("RuntimeException expected after timeout.");
775
776        ch.close();
777    }
778
779   // returns ByteBuffer with random bytes
780   static ByteBuffer genBuffer() {
781       int size = 1024 + rand.nextInt(16000);
782       byte[] buf = new byte[size];
783       rand.nextBytes(buf);
784       boolean useDirect = rand.nextBoolean();
785       if (useDirect) {
786           ByteBuffer bb = ByteBuffer.allocateDirect(buf.length);
787           bb.put(buf);
788           bb.flip();
789           return bb;
790       } else {
791           return ByteBuffer.wrap(buf);
792       }
793   }
794
795   // return ByteBuffer[] with random bytes
796   static ByteBuffer[] genBuffers(int max) {
797       int len = 1;
798       if (max > 1)
799           len += rand.nextInt(max);
800       ByteBuffer[] bufs = new ByteBuffer[len];
801       for (int i=0; i<len; i++)
802           bufs[i] = genBuffer();
803       return bufs;
804   }
805}
806