66import java .security .SecureRandom ;
77import java .security .cert .X509Certificate ;
88import java .util .concurrent .CountDownLatch ;
9- import java .util .concurrent .atomic .AtomicInteger ;
109
1110import javax .net .ssl .KeyManagerFactory ;
1211import javax .net .ssl .SSLContext ;
2625class NamedGroupTestUtil
2726{
2827 private static final String HOST = "localhost" ;
29- private static final AtomicInteger PORT_NO = new AtomicInteger (19700 );
3028
3129 static final char [] KEY_PASSWORD = "keyPassword" .toCharArray ();
3230
@@ -86,10 +84,9 @@ static SSLContext createClientContext(Provider tlsProv, KeyStore ts)
8684 static void runNamedGroupTest (String namedGroup , SSLContext clientContext , SSLContext serverContext )
8785 throws Exception
8886 {
89- int port = PORT_NO . incrementAndGet ( );
87+ NamedGroupServer server = new NamedGroupServer ( serverContext , namedGroup );
9088
91- TestProtocolUtil .runClientAndServer (new NamedGroupServer (serverContext , port , namedGroup ),
92- new NamedGroupClient (clientContext , port , namedGroup ));
89+ TestProtocolUtil .runClientAndServer (server , new NamedGroupClient (clientContext , server , namedGroup ));
9390 }
9491
9592 /**
@@ -100,10 +97,8 @@ static void runNamedGroupTest(String namedGroup, SSLContext clientContext, SSLCo
10097 static boolean defaultServerAccepts (String namedGroup , SSLContext clientContext , SSLContext serverContext )
10198 throws Exception
10299 {
103- int port = PORT_NO .incrementAndGet ();
104-
105- NamedGroupClient client = new NamedGroupClient (clientContext , port , namedGroup );
106- NamedGroupServer server = new NamedGroupServer (serverContext , port , null );
100+ NamedGroupServer server = new NamedGroupServer (serverContext , null );
101+ NamedGroupClient client = new NamedGroupClient (clientContext , server , namedGroup );
107102
108103 TestProtocolUtil .Task serverTask = new TestProtocolUtil .Task (server );
109104 Thread serverThread = new Thread (serverTask );
@@ -140,14 +135,19 @@ private static class NamedGroupClient
140135 implements TestProtocolUtil .BlockingCallable
141136 {
142137 private final SSLContext clientContext ;
143- private final int port ;
138+ private final NamedGroupServer server ;
144139 private final String namedGroup ;
145140 private final CountDownLatch latch = new CountDownLatch (1 );
146141
147- NamedGroupClient (SSLContext clientContext , int port , String namedGroup )
142+ /**
143+ * Takes the server rather than a port because the port is not known until the server has
144+ * bound. Both call sites start the client only after the server's await() has returned, so
145+ * getBoundPort() is answerable by the time call() runs.
146+ */
147+ NamedGroupClient (SSLContext clientContext , NamedGroupServer server , String namedGroup )
148148 {
149149 this .clientContext = clientContext ;
150- this .port = port ;
150+ this .server = server ;
151151 this .namedGroup = namedGroup ;
152152 }
153153
@@ -156,7 +156,7 @@ public Exception call() throws Exception
156156 try
157157 {
158158 SSLSocketFactory fact = clientContext .getSocketFactory ();
159- SSLSocket cSock = (SSLSocket )fact .createSocket (HOST , port );
159+ SSLSocket cSock = (SSLSocket )fact .createSocket (HOST , server . getBoundPort () );
160160
161161 restrictToNamedGroup (cSock , namedGroup );
162162
@@ -185,26 +185,51 @@ private static class NamedGroupServer
185185 implements TestProtocolUtil .BlockingCallable
186186 {
187187 private final SSLContext serverContext ;
188- private final int port ;
189188 private final String namedGroup ;
190189 private final CountDownLatch latch = new CountDownLatch (1 );
191190
192- NamedGroupServer (SSLContext serverContext , int port , String namedGroup )
191+ private volatile int boundPort = -1 ;
192+
193+ NamedGroupServer (SSLContext serverContext , String namedGroup )
193194 {
194195 this .serverContext = serverContext ;
195- this .port = port ;
196196 this .namedGroup = namedGroup ;
197197 }
198198
199+ /**
200+ * The port the kernel handed out, readable once await() has returned.
201+ *
202+ * @throws IllegalStateException where the server never got as far as binding, so that a
203+ * caller connecting too early fails here rather than against some unrelated port.
204+ */
205+ int getBoundPort ()
206+ {
207+ int port = boundPort ;
208+
209+ if (port < 0 )
210+ {
211+ throw new IllegalStateException ("server has not bound a port" );
212+ }
213+
214+ return port ;
215+ }
216+
199217 public Exception call () throws Exception
200218 {
201219 try
202220 {
203221 SSLServerSocketFactory fact = serverContext .getServerSocketFactory ();
204- SSLServerSocket sSock = (SSLServerSocket )fact .createServerSocket (port );
222+
223+ // port 0: the kernel picks a free one. A fixed port, or one from a counter seeded
224+ // the same way in every JVM, collides as soon as two test JVMs run at once - and
225+ // forkEvery = 1 means each test class already gets its own JVM.
226+ SSLServerSocket sSock = (SSLServerSocket )fact .createServerSocket (0 );
205227
206228 sSock .setEnabledProtocols (new String []{ "TLSv1.3" });
207229
230+ // published before the latch fires, so the client sees it the moment await() returns
231+ boundPort = sSock .getLocalPort ();
232+
208233 latch .countDown ();
209234
210235 SSLSocket sslSock = (SSLSocket )sSock .accept ();
0 commit comments