11/*
2- * Copyright (c) 2015, 2021 , Oracle and/or its affiliates. All rights reserved.
2+ * Copyright (c) 2015, 2022 , Oracle and/or its affiliates. All rights reserved.
33 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44 *
55 * This code is free software; you can redistribute it and/or modify it
3333 * @run main/othervm DTLSOverDatagram
3434 */
3535
36+ import java .io .IOException ;
3637import java .nio .*;
3738import java .net .*;
3839import java .util .*;
4243import jdk .test .lib .security .SSLContextBuilder ;
4344
4445import java .util .concurrent .*;
46+ import java .util .concurrent .atomic .AtomicBoolean ;
4547
4648import jdk .test .lib .hexdump .HexPrinter ;
4749
5052 */
5153public class DTLSOverDatagram {
5254
53- private static final int MAX_HANDSHAKE_LOOPS = 200 ;
54- private static final int MAX_APP_READ_LOOPS = 60 ;
5555 private static final int SOCKET_TIMEOUT = 10 * 1000 ; // in millis
5656 private static final int BUFFER_SIZE = 1024 ;
5757 private static final int MAXIMUM_PACKET_SIZE = 1024 ;
@@ -75,8 +75,9 @@ public class DTLSOverDatagram {
7575 private static final ByteBuffer CLIENT_APP =
7676 ByteBuffer .wrap ("Hi Server, I'm Client" .getBytes ());
7777
78- private static Exception clientException = null ;
79- private static Exception serverException = null ;
78+ private final AtomicBoolean exceptionOccurred = new AtomicBoolean (false );
79+
80+ private final CountDownLatch serverStarted = new CountDownLatch (1 );
8081 /*
8182 * =============================================================
8283 * The test case
@@ -148,18 +149,12 @@ void handshake(SSLEngine engine, DatagramSocket socket,
148149 SocketAddress peerAddr , String side ) throws Exception {
149150
150151 boolean endLoops = false ;
151- int loops = MAX_HANDSHAKE_LOOPS ;
152+ int loops = 0 ;
152153 engine .beginHandshake ();
153- while (!endLoops &&
154- (serverException == null ) && (clientException == null )) {
155-
156- if (--loops < 0 ) {
157- throw new RuntimeException (
158- "Too many loops to produce handshake packets" );
159- }
154+ while (!endLoops && !exceptionOccurred .get ()) {
160155
161156 SSLEngineResult .HandshakeStatus hs = engine .getHandshakeStatus ();
162- log (side , "=======handshake(" + loops + ", " + hs + ")=======" );
157+ log (side , "=======handshake(" + ++ loops + ", " + hs + ")=======" );
163158
164159 switch (hs ) {
165160 case NEED_UNWRAP , NEED_UNWRAP_AGAIN -> {
@@ -313,16 +308,10 @@ void deliverAppData(SSLEngine engine, DatagramSocket socket,
313308 void receiveAppData (SSLEngine engine ,
314309 DatagramSocket socket , ByteBuffer expectedApp ) throws Exception {
315310
316- int loops = MAX_APP_READ_LOOPS ;
317- while ((serverException == null ) && (clientException == null )) {
318- if (--loops < 0 ) {
319- throw new RuntimeException (
320- "Too much loops to receive application data" );
321- }
322-
311+ while (!exceptionOccurred .get ()) {
323312 byte [] buf = new byte [BUFFER_SIZE ];
324- DatagramPacket packet = new DatagramPacket ( buf , buf . length );
325- socket . receive ( packet );
313+ DatagramPacket packet = readFromSocket ( socket , buf );
314+
326315 ByteBuffer netBuffer = ByteBuffer .wrap (buf , 0 , packet .getLength ());
327316 ByteBuffer recBuffer = ByteBuffer .allocate (BUFFER_SIZE );
328317 SSLEngineResult rs = engine .unwrap (netBuffer , recBuffer );
@@ -338,19 +327,31 @@ void receiveAppData(SSLEngine engine,
338327 }
339328 }
340329
330+ /*
331+ Some tests failed with receive time-out errors when the client tried to read
332+ from the server. The server thread had exited normally so the read _should_
333+ succeed. So let's try to read a couple of times before giving up.
334+ */
335+ DatagramPacket readFromSocket (DatagramSocket socket , byte [] buffer ) throws IOException {
336+ for (int i = 1 ; i <= 2 ; ++i ) {
337+ try {
338+ DatagramPacket packet = new DatagramPacket (buffer , buffer .length );
339+ socket .receive (packet );
340+ return packet ;
341+ } catch (SocketTimeoutException exc ) {
342+ System .out .println ("Attempt " + i + ": Timeout occurred reading from socket." );
343+ }
344+ }
345+ throw new IOException ("Did not receive data after 2 attempts." );
346+ }
347+
341348 // produce handshake packets
342349 boolean produceHandshakePackets (SSLEngine engine , SocketAddress socketAddr ,
343350 String side , List <DatagramPacket > packets ) throws Exception {
344351
345352 boolean endLoops = false ;
346- int loops = MAX_HANDSHAKE_LOOPS / 2 ;
347- while (!endLoops &&
348- (serverException == null ) && (clientException == null )) {
349-
350- if (--loops < 0 ) {
351- throw new RuntimeException (
352- "Too many loops to produce handshake packets" );
353- }
353+ int loops = 0 ;
354+ while (!endLoops && !exceptionOccurred .get ()) {
354355
355356 ByteBuffer oNet = ByteBuffer .allocate (32768 );
356357 ByteBuffer oApp = ByteBuffer .allocate (0 );
@@ -360,7 +361,7 @@ boolean produceHandshakePackets(SSLEngine engine, SocketAddress socketAddr,
360361 SSLEngineResult .Status rs = r .getStatus ();
361362 SSLEngineResult .HandshakeStatus hs = r .getHandshakeStatus ();
362363 log (side , "----produce handshake packet(" +
363- loops + ", " + rs + ", " + hs + ")----" );
364+ ++ loops + ", " + rs + ", " + hs + ")----" );
364365
365366 verifySSLEngineResultStatus (r , side );
366367
@@ -518,10 +519,6 @@ SSLContext getDTLSContext() throws Exception {
518519 * The remainder is support stuff to kickstart the testing.
519520 */
520521
521- // Will the handshaking and application data exchange succeed?
522- public boolean isGoodJob () {
523- return true ;
524- }
525522
526523 public final void runTest (DTLSOverDatagram testCase ) throws Exception {
527524 InetSocketAddress serverSocketAddress = new InetSocketAddress
@@ -541,97 +538,51 @@ public final void runTest(DTLSOverDatagram testCase) throws Exception {
541538 InetSocketAddress clientSocketAddr = new InetSocketAddress (
542539 InetAddress .getLoopbackAddress (), clientSocket .getLocalPort ());
543540
544- ExecutorService pool = Executors .newFixedThreadPool (2 );
545- Future <String > server , client ;
541+ ExecutorService pool = Executors .newFixedThreadPool (1 );
542+ Future <Void > server ;
546543
547- try {
548- server = pool .submit (new ServerCallable (
544+ server = pool .submit (() -> runServer (
549545 testCase , serverSocket , clientSocketAddr ));
550- client = pool .submit (new ClientCallable (
551- testCase , clientSocket , serverSocketAddr ));
552- } finally {
553- pool .shutdown ();
554- }
555-
556- boolean failed = false ;
546+ pool .shutdown ();
557547
558- // wait for client to finish
559- try {
560- System .out .println ("Client finished: " + client .get ());
561- } catch (CancellationException | InterruptedException
562- | ExecutionException e ) {
563- System .out .println ("Exception on client side: " );
564- e .printStackTrace (System .out );
565- failed = true ;
566- }
567-
568- // wait for server to finish
569- try {
570- System .out .println ("Client finished: " + server .get ());
571- } catch (CancellationException | InterruptedException
572- | ExecutionException e ) {
573- System .out .println ("Exception on server side: " );
574- e .printStackTrace (System .out );
575- failed = true ;
576- }
577-
578- if (failed ) {
579- throw new RuntimeException ("Test failed" );
580- }
548+ runClient (testCase , clientSocket , serverSocketAddr );
549+ server .get ();
581550 }
582551 }
583552
584- record ServerCallable (DTLSOverDatagram testCase , DatagramSocket socket ,
585- InetSocketAddress clientSocketAddr ) implements Callable <String > {
553+ Void runServer (DTLSOverDatagram testCase , DatagramSocket socket ,
554+ InetSocketAddress clientSocketAddr ) throws Exception {
555+ try {
556+ serverStarted .countDown ();
557+ testCase .doServerSide (socket , clientSocketAddr );
586558
587- @ Override
588- public String call () throws Exception {
589- try {
590- testCase .doServerSide (socket , clientSocketAddr );
591- } catch (Exception e ) {
592- System .out .println ("Exception in ServerCallable.call():" );
593- e .printStackTrace (System .out );
594- serverException = e ;
595-
596- if (testCase .isGoodJob ()) {
597- throw e ;
598- } else {
599- return "Well done, server!" ;
600- }
601- }
559+ } catch (Exception exc ) {
560+ exceptionOccurred .set (true );
602561
603- if (testCase .isGoodJob ()) {
604- return "Well done, server!" ;
605- } else {
606- throw new Exception ("No expected exception" );
607- }
562+ // log for debugging clarity
563+ System .out .println ("Unexpected exception in server" );
564+ exc .printStackTrace (System .err );
565+ throw exc ;
608566 }
567+
568+ return null ;
609569 }
610570
611- record ClientCallable (DTLSOverDatagram testCase , DatagramSocket socket ,
612- InetSocketAddress serverSocketAddr ) implements Callable <String > {
571+ private void runClient (DTLSOverDatagram testCase , DatagramSocket socket ,
572+ InetSocketAddress serverSocketAddr ) throws Exception {
573+ if (!serverStarted .await (5 , TimeUnit .SECONDS )) {
574+ throw new Exception ("Server did not start within 5 seconds." );
575+ }
613576
614- @ Override
615- public String call () throws Exception {
616- try {
617- testCase .doClientSide (socket , serverSocketAddr );
618- } catch (Exception e ) {
619- System .out .println ("Exception in ClientCallable.call():" );
620- e .printStackTrace (System .out );
621- clientException = e ;
622-
623- if (testCase .isGoodJob ()) {
624- throw e ;
625- } else {
626- return "Well done, client!" ;
627- }
628- }
577+ try {
578+ testCase .doClientSide (socket , serverSocketAddr );
579+ } catch (Exception exc ) {
580+ exceptionOccurred .set (true );
629581
630- if (testCase .isGoodJob ()) {
631- return "Well done, client!" ;
632- } else {
633- throw new Exception ("No expected exception" );
634- }
582+ // log for debugging clarity
583+ System .out .println ("Unexpected exception in client." );
584+ exc .printStackTrace (System .err );
585+ throw exc ;
635586 }
636587 }
637588
0 commit comments