jdk/test/javax/net/ssl/DTLS/DTLSOverDatagram.java
changeset 30904 ec0224270f90
child 31536 3090612af7dd
equal deleted inserted replaced
30903:0c7d705209c6 30904:ec0224270f90
       
     1 /*
       
     2  * Copyright (c) 2015, 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 // SunJSSE does not support dynamic system properties, no way to re-use
       
    25 // system properties in samevm/agentvm mode.
       
    26 
       
    27 /*
       
    28  * @test
       
    29  * @bug 8043758
       
    30  * @summary Datagram Transport Layer Security (DTLS)
       
    31  * @run main/othervm DTLSOverDatagram
       
    32  */
       
    33 
       
    34 import java.io.*;
       
    35 import java.nio.*;
       
    36 import java.net.*;
       
    37 import java.util.*;
       
    38 import java.security.*;
       
    39 import java.security.cert.*;
       
    40 import javax.net.ssl.*;
       
    41 import java.util.concurrent.*;
       
    42 
       
    43 import sun.misc.HexDumpEncoder;
       
    44 
       
    45 /**
       
    46  * An example to show the way to use SSLEngine in datagram connections.
       
    47  */
       
    48 public class DTLSOverDatagram {
       
    49     private static int MAX_HANDSHAKE_LOOPS = 60;
       
    50     private static int MAX_APP_READ_LOOPS = 10;
       
    51 
       
    52     /*
       
    53      * The following is to set up the keystores.
       
    54      */
       
    55     private static String pathToStores = "../etc";
       
    56     private static String keyStoreFile = "keystore";
       
    57     private static String trustStoreFile = "truststore";
       
    58     private static String passwd = "passphrase";
       
    59 
       
    60     private static String keyFilename =
       
    61             System.getProperty("test.src", ".") + "/" + pathToStores +
       
    62                 "/" + keyStoreFile;
       
    63     private static String trustFilename =
       
    64             System.getProperty("test.src", ".") + "/" + pathToStores +
       
    65                 "/" + trustStoreFile;
       
    66     private static Exception clientException = null;
       
    67     private static Exception serverException = null;
       
    68 
       
    69     private static ByteBuffer serverApp =
       
    70                 ByteBuffer.wrap("Hi Client, I'm Server".getBytes());
       
    71     private static ByteBuffer clientApp =
       
    72                 ByteBuffer.wrap("Hi Server, I'm Client".getBytes());
       
    73 
       
    74     /*
       
    75      * =============================================================
       
    76      * The test case
       
    77      */
       
    78     public static void main(String[] args) throws Exception {
       
    79         DTLSOverDatagram testCase = new DTLSOverDatagram();
       
    80         testCase.runTest(testCase);
       
    81     }
       
    82 
       
    83     /*
       
    84      * Define the server side of the test.
       
    85      */
       
    86     void doServerSide() throws Exception {
       
    87         DatagramSocket socket = serverDatagramSocket;
       
    88         socket.setSoTimeout(10000);   // 10 second
       
    89 
       
    90         // create SSLEngine
       
    91         SSLEngine engine = createSSLEngine(false);
       
    92 
       
    93         // handshaking
       
    94         handshake(engine, socket, clientSocketAddr);
       
    95 
       
    96         // read client application data
       
    97         receiveAppData(engine, socket, clientApp);
       
    98 
       
    99         // write server application data
       
   100         deliverAppData(engine, socket, serverApp, clientSocketAddr);
       
   101 
       
   102         socket.close();
       
   103     }
       
   104 
       
   105     /*
       
   106      * Define the client side of the test.
       
   107      */
       
   108     void doClientSide() throws Exception {
       
   109         DatagramSocket socket = clientDatagramSocket;
       
   110         socket.setSoTimeout(1000);     // 1 second read timeout
       
   111 
       
   112         // create SSLEngine
       
   113         SSLEngine engine = createSSLEngine(true);
       
   114 
       
   115         // handshaking
       
   116         handshake(engine, socket, serverSocketAddr);
       
   117 
       
   118         // write client application data
       
   119         deliverAppData(engine, socket, clientApp, serverSocketAddr);
       
   120 
       
   121         // read server application data
       
   122         receiveAppData(engine, socket, serverApp);
       
   123     }
       
   124 
       
   125     /*
       
   126      * =============================================================
       
   127      * The remainder is support stuff for DTLS operations.
       
   128      */
       
   129     SSLEngine createSSLEngine(boolean isClient) throws Exception {
       
   130         SSLContext context = getDTLSContext();
       
   131         SSLEngine engine = context.createSSLEngine();
       
   132 
       
   133         SSLParameters paras = engine.getSSLParameters();
       
   134         paras.setMaximumPacketSize(1024);
       
   135 
       
   136         engine.setUseClientMode(isClient);
       
   137         engine.setSSLParameters(paras);
       
   138 
       
   139         return engine;
       
   140     }
       
   141 
       
   142     // handshake
       
   143     void handshake(SSLEngine engine, DatagramSocket socket,
       
   144             SocketAddress peerAddr) throws Exception {
       
   145 
       
   146         boolean endLoops = false;
       
   147         int loops = MAX_HANDSHAKE_LOOPS;
       
   148         engine.beginHandshake();
       
   149         while (!endLoops &&
       
   150                 (serverException == null) && (clientException == null)) {
       
   151 
       
   152             if (--loops < 0) {
       
   153                 throw new RuntimeException(
       
   154                         "Too much loops to produce handshake packets");
       
   155             }
       
   156 
       
   157             SSLEngineResult.HandshakeStatus hs = engine.getHandshakeStatus();
       
   158             if (hs == SSLEngineResult.HandshakeStatus.NEED_UNWRAP ||
       
   159                 hs == SSLEngineResult.HandshakeStatus.NEED_UNWRAP_AGAIN) {
       
   160 
       
   161                 ByteBuffer iNet;
       
   162                 ByteBuffer iApp;
       
   163                 if (hs == SSLEngineResult.HandshakeStatus.NEED_UNWRAP) {
       
   164                     // receive ClientHello request and other SSL/TLS records
       
   165                     byte[] buf = new byte[1024];
       
   166                     DatagramPacket packet = new DatagramPacket(buf, buf.length);
       
   167                     try {
       
   168                         socket.receive(packet);
       
   169                     } catch (SocketTimeoutException ste) {
       
   170                         List<DatagramPacket> packets =
       
   171                                 onReceiveTimeout(engine, peerAddr);
       
   172                         for (DatagramPacket p : packets) {
       
   173                             socket.send(p);
       
   174                         }
       
   175 
       
   176                         continue;
       
   177                     }
       
   178 
       
   179                     iNet = ByteBuffer.wrap(buf, 0, packet.getLength());
       
   180                     iApp = ByteBuffer.allocate(1024);
       
   181                 } else {
       
   182                     iNet = ByteBuffer.allocate(0);
       
   183                     iApp = ByteBuffer.allocate(1024);
       
   184                 }
       
   185 
       
   186                 SSLEngineResult r = engine.unwrap(iNet, iApp);
       
   187                 SSLEngineResult.Status rs = r.getStatus();
       
   188                 hs = r.getHandshakeStatus();
       
   189                 if (rs == SSLEngineResult.Status.BUFFER_OVERFLOW) {
       
   190                     // the client maximum fragment size config does not work?
       
   191                     throw new Exception("Buffer overflow: " +
       
   192                         "incorrect client maximum fragment size");
       
   193                 } else if (rs == SSLEngineResult.Status.BUFFER_UNDERFLOW) {
       
   194                     // bad packet, or the client maximum fragment size
       
   195                     // config does not work?
       
   196                     if (hs != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
       
   197                         throw new Exception("Buffer underflow: " +
       
   198                             "incorrect client maximum fragment size");
       
   199                     } // otherwise, ignore this packet
       
   200                 } else if (rs == SSLEngineResult.Status.CLOSED) {
       
   201                     endLoops = true;
       
   202                 }   // otherwise, SSLEngineResult.Status.OK:
       
   203 
       
   204                 if (rs != SSLEngineResult.Status.OK) {
       
   205                     continue;
       
   206                 }
       
   207             } else if (hs == SSLEngineResult.HandshakeStatus.NEED_WRAP) {
       
   208                 List<DatagramPacket> packets =
       
   209                         produceHandshakePackets(engine, peerAddr);
       
   210                 for (DatagramPacket p : packets) {
       
   211                     socket.send(p);
       
   212                 }
       
   213             } else if (hs == SSLEngineResult.HandshakeStatus.NEED_TASK) {
       
   214                 runDelegatedTasks(engine);
       
   215             } else if (hs == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
       
   216                 // OK, time to do application data exchange.
       
   217                 endLoops = true;
       
   218             } else if (hs == SSLEngineResult.HandshakeStatus.FINISHED) {
       
   219                 endLoops = true;
       
   220             }
       
   221         }
       
   222 
       
   223         SSLEngineResult.HandshakeStatus hs = engine.getHandshakeStatus();
       
   224         if (hs != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
       
   225             throw new Exception("Not ready for application data yet");
       
   226         }
       
   227     }
       
   228 
       
   229     // deliver application data
       
   230     void deliverAppData(SSLEngine engine, DatagramSocket socket,
       
   231             ByteBuffer appData, SocketAddress peerAddr) throws Exception {
       
   232 
       
   233         // Note: have not consider the packet loses
       
   234         List<DatagramPacket> packets =
       
   235                 produceApplicationPackets(engine, appData, peerAddr);
       
   236         appData.flip();
       
   237         for (DatagramPacket p : packets) {
       
   238             socket.send(p);
       
   239         }
       
   240     }
       
   241 
       
   242     // receive application data
       
   243     void receiveAppData(SSLEngine engine,
       
   244             DatagramSocket socket, ByteBuffer expectedApp) throws Exception {
       
   245 
       
   246         int loops = MAX_APP_READ_LOOPS;
       
   247         while ((serverException == null) && (clientException == null)) {
       
   248             if (--loops < 0) {
       
   249                 throw new RuntimeException(
       
   250                         "Too much loops to receive application data");
       
   251             }
       
   252 
       
   253             byte[] buf = new byte[1024];
       
   254             DatagramPacket packet = new DatagramPacket(buf, buf.length);
       
   255             socket.receive(packet);
       
   256             ByteBuffer netBuffer = ByteBuffer.wrap(buf, 0, packet.getLength());
       
   257             ByteBuffer recBuffer = ByteBuffer.allocate(1024);
       
   258             SSLEngineResult rs = engine.unwrap(netBuffer, recBuffer);
       
   259             recBuffer.flip();
       
   260             if (recBuffer.remaining() != 0) {
       
   261                 printHex("Received application data", recBuffer);
       
   262                 if (!recBuffer.equals(expectedApp)) {
       
   263                     System.out.println("Engine status is " + rs);
       
   264                     throw new Exception("Not the right application data");
       
   265                 }
       
   266                 break;
       
   267             }
       
   268         }
       
   269     }
       
   270 
       
   271     // produce handshake packets
       
   272     List<DatagramPacket> produceHandshakePackets(
       
   273             SSLEngine engine, SocketAddress socketAddr) throws Exception {
       
   274 
       
   275         List<DatagramPacket> packets = new ArrayList<>();
       
   276         boolean endLoops = false;
       
   277         int loops = MAX_HANDSHAKE_LOOPS;
       
   278         while (!endLoops &&
       
   279                 (serverException == null) && (clientException == null)) {
       
   280 
       
   281             if (--loops < 0) {
       
   282                 throw new RuntimeException(
       
   283                         "Too much loops to produce handshake packets");
       
   284             }
       
   285 
       
   286             ByteBuffer oNet = ByteBuffer.allocate(32768);
       
   287             ByteBuffer oApp = ByteBuffer.allocate(0);
       
   288             SSLEngineResult r = engine.wrap(oApp, oNet);
       
   289             oNet.flip();
       
   290 
       
   291             SSLEngineResult.Status rs = r.getStatus();
       
   292             SSLEngineResult.HandshakeStatus hs = r.getHandshakeStatus();
       
   293             if (rs == SSLEngineResult.Status.BUFFER_OVERFLOW) {
       
   294                 // the client maximum fragment size config does not work?
       
   295                 throw new Exception("Buffer overflow: " +
       
   296                             "incorrect server maximum fragment size");
       
   297             } else if (rs == SSLEngineResult.Status.BUFFER_UNDERFLOW) {
       
   298                 // bad packet, or the client maximum fragment size
       
   299                 // config does not work?
       
   300                 if (hs != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
       
   301                     throw new Exception("Buffer underflow: " +
       
   302                             "incorrect server maximum fragment size");
       
   303                 } // otherwise, ignore this packet
       
   304             } else if (rs == SSLEngineResult.Status.CLOSED) {
       
   305                 throw new Exception("SSLEngine has closed");
       
   306             }   // otherwise, SSLEngineResult.Status.OK
       
   307 
       
   308             // SSLEngineResult.Status.OK:
       
   309             if (oNet.hasRemaining()) {
       
   310                 byte[] ba = new byte[oNet.remaining()];
       
   311                 oNet.get(ba);
       
   312                 DatagramPacket packet = createHandshakePacket(ba, socketAddr);
       
   313                 packets.add(packet);
       
   314             }
       
   315             boolean endInnerLoop = false;
       
   316             SSLEngineResult.HandshakeStatus nhs = hs;
       
   317             while (!endInnerLoop) {
       
   318                 if (nhs == SSLEngineResult.HandshakeStatus.NEED_TASK) {
       
   319                     runDelegatedTasks(engine);
       
   320                     nhs = engine.getHandshakeStatus();
       
   321                 } else if ((nhs == SSLEngineResult.HandshakeStatus.FINISHED) ||
       
   322                     (nhs == SSLEngineResult.HandshakeStatus.NEED_UNWRAP) ||
       
   323                     (nhs == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING)) {
       
   324 
       
   325                     endInnerLoop = true;
       
   326                     endLoops = true;
       
   327                 } else if (nhs == SSLEngineResult.HandshakeStatus.NEED_WRAP) {
       
   328                     endInnerLoop = true;
       
   329                 }
       
   330             }
       
   331         }
       
   332 
       
   333         return packets;
       
   334     }
       
   335 
       
   336     DatagramPacket createHandshakePacket(byte[] ba, SocketAddress socketAddr) {
       
   337         return new DatagramPacket(ba, ba.length, socketAddr);
       
   338     }
       
   339 
       
   340     // produce application packets
       
   341     List<DatagramPacket> produceApplicationPackets(
       
   342             SSLEngine engine, ByteBuffer source,
       
   343             SocketAddress socketAddr) throws Exception {
       
   344 
       
   345         List<DatagramPacket> packets = new ArrayList<>();
       
   346         ByteBuffer appNet = ByteBuffer.allocate(32768);
       
   347         SSLEngineResult r = engine.wrap(source, appNet);
       
   348         appNet.flip();
       
   349 
       
   350         SSLEngineResult.Status rs = r.getStatus();
       
   351         if (rs == SSLEngineResult.Status.BUFFER_OVERFLOW) {
       
   352             // the client maximum fragment size config does not work?
       
   353             throw new Exception("Buffer overflow: " +
       
   354                         "incorrect server maximum fragment size");
       
   355         } else if (rs == SSLEngineResult.Status.BUFFER_UNDERFLOW) {
       
   356             // unlikely
       
   357             throw new Exception("Buffer underflow during wraping");
       
   358         } else if (rs == SSLEngineResult.Status.CLOSED) {
       
   359                 throw new Exception("SSLEngine has closed");
       
   360         }   // otherwise, SSLEngineResult.Status.OK
       
   361 
       
   362         // SSLEngineResult.Status.OK:
       
   363         if (appNet.hasRemaining()) {
       
   364             byte[] ba = new byte[appNet.remaining()];
       
   365             appNet.get(ba);
       
   366             DatagramPacket packet =
       
   367                     new DatagramPacket(ba, ba.length, socketAddr);
       
   368             packets.add(packet);
       
   369         }
       
   370 
       
   371         return packets;
       
   372     }
       
   373 
       
   374     // run delegated tasks
       
   375     void runDelegatedTasks(SSLEngine engine) throws Exception {
       
   376         Runnable runnable;
       
   377         while ((runnable = engine.getDelegatedTask()) != null) {
       
   378             runnable.run();
       
   379         }
       
   380 
       
   381         SSLEngineResult.HandshakeStatus hs = engine.getHandshakeStatus();
       
   382         if (hs == SSLEngineResult.HandshakeStatus.NEED_TASK) {
       
   383             throw new Exception("handshake shouldn't need additional tasks");
       
   384         }
       
   385     }
       
   386 
       
   387     // retransmission if timeout
       
   388     List<DatagramPacket> onReceiveTimeout(
       
   389             SSLEngine engine, SocketAddress socketAddr) throws Exception {
       
   390 
       
   391         SSLEngineResult.HandshakeStatus hs = engine.getHandshakeStatus();
       
   392         if (hs == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
       
   393             return new ArrayList<DatagramPacket>();
       
   394         } else {
       
   395             // retransmission of handshake messages
       
   396             return produceHandshakePackets(engine, socketAddr);
       
   397         }
       
   398     }
       
   399 
       
   400     // get DTSL context
       
   401     SSLContext getDTLSContext() throws Exception {
       
   402         KeyStore ks = KeyStore.getInstance("JKS");
       
   403         KeyStore ts = KeyStore.getInstance("JKS");
       
   404 
       
   405         char[] passphrase = "passphrase".toCharArray();
       
   406 
       
   407         ks.load(new FileInputStream(keyFilename), passphrase);
       
   408         ts.load(new FileInputStream(trustFilename), passphrase);
       
   409 
       
   410         KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
       
   411         kmf.init(ks, passphrase);
       
   412 
       
   413         TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
       
   414         tmf.init(ts);
       
   415 
       
   416         SSLContext sslCtx = SSLContext.getInstance("DTLS");
       
   417 
       
   418         sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
       
   419 
       
   420         return sslCtx;
       
   421     }
       
   422 
       
   423 
       
   424     /*
       
   425      * =============================================================
       
   426      * The remainder is support stuff to kickstart the testing.
       
   427      */
       
   428 
       
   429     // the server side SocketAddress
       
   430     volatile static SocketAddress serverSocketAddr = null;
       
   431 
       
   432     // the client side SocketAddress
       
   433     volatile static SocketAddress clientSocketAddr = null;
       
   434 
       
   435     // the server side DatagramSocket instance
       
   436     volatile static DatagramSocket serverDatagramSocket = null;
       
   437 
       
   438     // the server side DatagramSocket instance
       
   439     volatile static DatagramSocket clientDatagramSocket = null;
       
   440 
       
   441     // get server side SocketAddress object
       
   442     public SocketAddress getServerSocketAddress() {
       
   443         return serverSocketAddr;
       
   444     }
       
   445 
       
   446     // get client side SocketAddress object
       
   447     public SocketAddress getClientSocketAddress() {
       
   448         return clientSocketAddr;
       
   449     }
       
   450 
       
   451     // get server side DatagramSocket object
       
   452     public DatagramSocket getServerDatagramSocket() {
       
   453         return serverDatagramSocket;
       
   454     }
       
   455 
       
   456     // get client side DatagramSocket object
       
   457     public DatagramSocket getClientDatagramSocket() {
       
   458         return clientDatagramSocket;
       
   459     }
       
   460 
       
   461     // Will the handshaking and application data exchange succeed?
       
   462     public boolean isGoodJob() {
       
   463         return true;
       
   464     }
       
   465 
       
   466     public final void runTest(DTLSOverDatagram testCase) throws Exception {
       
   467         serverDatagramSocket = new DatagramSocket();
       
   468         serverSocketAddr = new InetSocketAddress(
       
   469             InetAddress.getLocalHost(), serverDatagramSocket.getLocalPort());
       
   470 
       
   471         clientDatagramSocket = new DatagramSocket();
       
   472         clientSocketAddr = new InetSocketAddress(
       
   473             InetAddress.getLocalHost(), clientDatagramSocket.getLocalPort());
       
   474 
       
   475         ExecutorService pool = Executors.newFixedThreadPool(2);
       
   476         List<Future<String>> list = new ArrayList<Future<String>>();
       
   477 
       
   478         try {
       
   479             list.add(pool.submit(new ServerCallable(testCase)));  // server task
       
   480             list.add(pool.submit(new ClientCallable(testCase)));  // client task
       
   481         } finally {
       
   482             pool.shutdown();
       
   483         }
       
   484 
       
   485         Exception reserved = null;
       
   486         for (Future<String> fut : list) {
       
   487             try {
       
   488                 System.out.println(fut.get());
       
   489             } catch (CancellationException |
       
   490                     InterruptedException | ExecutionException cie) {
       
   491                 if (reserved != null) {
       
   492                     cie.addSuppressed(reserved);
       
   493                     reserved = cie;
       
   494                 } else {
       
   495                     reserved = cie;
       
   496                 }
       
   497             }
       
   498         }
       
   499 
       
   500         if (reserved != null) {
       
   501             throw reserved;
       
   502         }
       
   503     }
       
   504 
       
   505     final static class ServerCallable implements Callable<String> {
       
   506         DTLSOverDatagram testCase;
       
   507 
       
   508         ServerCallable(DTLSOverDatagram testCase) {
       
   509             this.testCase = testCase;
       
   510         }
       
   511 
       
   512         @Override
       
   513         public String call() throws Exception {
       
   514             try {
       
   515                 testCase.doServerSide();
       
   516             } catch (Exception e) {
       
   517                 e.printStackTrace(System.out);
       
   518                 serverException = e;
       
   519 
       
   520                 if (testCase.isGoodJob()) {
       
   521                     throw e;
       
   522                 } else {
       
   523                     return "Well done, server!";
       
   524                 }
       
   525             } finally {
       
   526                 if (serverDatagramSocket != null) {
       
   527                     serverDatagramSocket.close();
       
   528                 }
       
   529             }
       
   530 
       
   531             if (testCase.isGoodJob()) {
       
   532                 return "Well done, server!";
       
   533             } else {
       
   534                 throw new Exception("No expected exception");
       
   535             }
       
   536         }
       
   537     }
       
   538 
       
   539     final static class ClientCallable implements Callable<String> {
       
   540         DTLSOverDatagram testCase;
       
   541 
       
   542         ClientCallable(DTLSOverDatagram testCase) {
       
   543             this.testCase = testCase;
       
   544         }
       
   545 
       
   546         @Override
       
   547         public String call() throws Exception {
       
   548             try {
       
   549                 testCase.doClientSide();
       
   550             } catch (Exception e) {
       
   551                 e.printStackTrace(System.out);
       
   552                 clientException = e;
       
   553                 if (testCase.isGoodJob()) {
       
   554                     throw e;
       
   555                 } else {
       
   556                     return "Well done, client!";
       
   557                 }
       
   558             } finally {
       
   559                 if (clientDatagramSocket != null) {
       
   560                     clientDatagramSocket.close();
       
   561                 }
       
   562             }
       
   563 
       
   564             if (testCase.isGoodJob()) {
       
   565                 return "Well done, client!";
       
   566             } else {
       
   567                 throw new Exception("No expected exception");
       
   568             }
       
   569         }
       
   570     }
       
   571 
       
   572     final static void printHex(String prefix, ByteBuffer bb) {
       
   573         HexDumpEncoder  dump = new HexDumpEncoder();
       
   574 
       
   575         synchronized (System.out) {
       
   576             System.out.println(prefix);
       
   577             try {
       
   578                 dump.encodeBuffer(bb.slice(), System.out);
       
   579             } catch (Exception e) {
       
   580                 // ignore
       
   581             }
       
   582             System.out.flush();
       
   583         }
       
   584     }
       
   585 
       
   586     final static void printHex(String prefix,
       
   587             byte[] bytes, int offset, int length) {
       
   588 
       
   589         HexDumpEncoder  dump = new HexDumpEncoder();
       
   590 
       
   591         synchronized (System.out) {
       
   592             System.out.println(prefix);
       
   593             try {
       
   594                 ByteBuffer bb = ByteBuffer.wrap(bytes, offset, length);
       
   595                 dump.encodeBuffer(bb, System.out);
       
   596             } catch (Exception e) {
       
   597                 // ignore
       
   598             }
       
   599             System.out.flush();
       
   600         }
       
   601     }
       
   602 }