Skip to content

Commit 09a18db

Browse files
committed
add multi-threaded JSSE provider client and server example
1 parent 4f60a88 commit 09a18db

3 files changed

Lines changed: 267 additions & 30 deletions

File tree

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
/* MultiThreadedSSLClient.java
2+
*
3+
* Copyright (C) 2006-2021 wolfSSL Inc.
4+
*
5+
* This file is part of wolfSSL.
6+
*
7+
* wolfSSL is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation; either version 2 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* wolfSSL is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
20+
*/
21+
22+
/**
23+
* Multi threaded SSLSocket example that connects a specified number of
24+
* client threads to a server. Intended to test multi-threading with wolfJSSE.
25+
*
26+
* This example creates a specified number of client threads to a server
27+
* located at 127.0.0.1:11118. This example is set up to use the SSLSocket
28+
* class. It makes one connection (handshake), sends/receives data, and shuts
29+
* down.
30+
*
31+
* A random amount of time is injected into each client thread before:
32+
* 1) The SSL/TLS handshake
33+
* 2) Doing I/O operations after the handshake
34+
*
35+
* The maximum amount of sleep time for each of those is "maxSleep", or
36+
* 3 seconds by default. This is intended to add some randomness into the
37+
* the client thread operations.
38+
*
39+
* Example usage:
40+
*
41+
* $ ant examples
42+
* $ ./examples/provider/MultiThreadedSSLClient.java
43+
*
44+
* This example is designed to connect against the MultiThreadedSSLServer
45+
* example:
46+
*
47+
* $ ./examples/provider/MultiThreadedSSLServer.java
48+
*
49+
* This example also prints out average SSL/TLS handshake time, which is
50+
* measured in milliseconds on the "startHandshake()" API call.
51+
*/
52+
53+
import java.util.*;
54+
import java.io.*;
55+
import java.net.*;
56+
import javax.net.ssl.*;
57+
import java.security.*;
58+
import java.util.concurrent.CountDownLatch;
59+
import java.util.concurrent.ExecutorService;
60+
import java.util.concurrent.Executor;
61+
import java.util.concurrent.Executors;
62+
import java.util.concurrent.ThreadLocalRandom;
63+
import com.wolfssl.provider.jsse.WolfSSLProvider;
64+
65+
public class MultiThreadedSSLClient
66+
{
67+
String tmfImpl = "SunX509"; /* TrustManagerFactory provider */
68+
String kmfImpl = "SunX509"; /* KeyManagerFactory provider */
69+
String ctxImpl = "wolfJSSE"; /* SSLContext provider */
70+
71+
String srvHost = "127.0.0.1"; /* server host */
72+
int srvPort = 11118; /* server port */
73+
74+
int numClientConnections = 10; /* number of client connection threads */
75+
int startedClientConnections = 0; /* active clients connected to server */
76+
int successClientConnections = 0; /* successful client connections */
77+
int failedClientConnections = 0; /* failed client connections */
78+
79+
long totalConnectionTimeMs = 0; /* total handshake time, across clients */
80+
final Object timeLock = new Object();
81+
82+
class ClientThread implements Runnable
83+
{
84+
private KeyManagerFactory km = null;
85+
private TrustManagerFactory tm = null;
86+
private CountDownLatch latch;
87+
88+
public ClientThread(KeyManagerFactory km, TrustManagerFactory tm,
89+
CountDownLatch latch) {
90+
this.km = km;
91+
this.tm = tm;
92+
this.latch = latch;
93+
}
94+
95+
public void run() {
96+
97+
byte[] back = new byte[80];
98+
String msg = "Too legit to quit";
99+
100+
/* max sleep is 3 seconds */
101+
int maxSleep = 3000;
102+
103+
/* get random sleep value before calling connect() */
104+
int randConnectSleep =
105+
ThreadLocalRandom.current().nextInt(0, maxSleep + 1);
106+
107+
/* get random sleep value before doing I/O after handshake */
108+
int randIOSleep =
109+
ThreadLocalRandom.current().nextInt(0, maxSleep +1);
110+
111+
try {
112+
SSLContext ctx = SSLContext.getInstance("TLS", ctxImpl);
113+
ctx.init(km.getKeyManagers(), tm.getTrustManagers(), null);
114+
115+
SSLSocket sock = (SSLSocket)ctx.getSocketFactory()
116+
.createSocket();
117+
118+
Thread.sleep(randConnectSleep);
119+
120+
sock.connect(new InetSocketAddress(srvHost, srvPort));
121+
122+
final long startTime = System.currentTimeMillis();
123+
sock.startHandshake();
124+
final long endTime = System.currentTimeMillis();
125+
126+
synchronized (timeLock) {
127+
totalConnectionTimeMs += (endTime - startTime);
128+
}
129+
130+
Thread.sleep(randIOSleep);
131+
132+
sock.getOutputStream().write(msg.getBytes());
133+
sock.getInputStream().read(back);
134+
System.out.println("Server message : " + new String(back));
135+
136+
sock.close();
137+
successClientConnections++;
138+
139+
} catch (Exception e) {
140+
e.printStackTrace();
141+
failedClientConnections++;
142+
}
143+
144+
this.latch.countDown();
145+
}
146+
}
147+
148+
public MultiThreadedSSLClient(String[] args) {
149+
150+
Security.addProvider(new WolfSSLProvider());
151+
152+
String clientKS = "./examples/provider/client.jks";
153+
String clientTS = "./examples/provider/client.jks";
154+
String jkspass = "wolfSSL test";
155+
char[] passArr = jkspass.toCharArray();
156+
157+
if (args.length != 2) {
158+
printUsage();
159+
}
160+
161+
/* pull in command line options from user */
162+
for (int i = 0; i < args.length; i++)
163+
{
164+
String arg = args[i];
165+
166+
if (arg.equals("-n")) {
167+
if (args.length < i+2)
168+
printUsage();
169+
numClientConnections = Integer.parseInt(args[++i]);
170+
171+
} else {
172+
printUsage();
173+
}
174+
}
175+
176+
try {
177+
List<ClientThread> clientList = new ArrayList<ClientThread>();
178+
CountDownLatch latch = new CountDownLatch(numClientConnections);
179+
180+
/* set up client KeyStore */
181+
KeyStore clientKeyStore = KeyStore.getInstance("JKS");
182+
clientKeyStore.load(new FileInputStream(clientKS), passArr);
183+
184+
KeyManagerFactory clientKMF =
185+
KeyManagerFactory.getInstance(kmfImpl);
186+
clientKMF.init(clientKeyStore, passArr);
187+
188+
/* set up CA TrustManagerFactory */
189+
KeyStore caKeyStore = KeyStore.getInstance("JKS");
190+
caKeyStore.load(new FileInputStream(clientTS), passArr);
191+
192+
TrustManagerFactory tm = TrustManagerFactory.getInstance(tmfImpl);
193+
tm.init(caKeyStore);
194+
195+
for (int i = 0; i < numClientConnections; i++) {
196+
clientList.add(new ClientThread(clientKMF, tm, latch));
197+
}
198+
199+
ExecutorService executor = Executors.newFixedThreadPool(
200+
clientList.size());
201+
202+
for (final ClientThread c : clientList) {
203+
executor.execute(c);
204+
}
205+
206+
latch.await();
207+
executor.shutdown();
208+
209+
} catch (Exception e) {
210+
e.printStackTrace();
211+
}
212+
213+
Security.removeProvider("wolfJSSE");
214+
215+
System.out.println("================================================");
216+
System.out.println("All Client Connections Finished");
217+
System.out.println("Successful = " + successClientConnections);
218+
System.out.println("Failed = " + failedClientConnections);
219+
System.out.println("Avg handshake time = " +
220+
totalConnectionTimeMs / successClientConnections + " ms");
221+
System.out.println("================================================");
222+
}
223+
224+
225+
public static void main(String[] args) {
226+
new MultiThreadedSSLClient(args);
227+
}
228+
229+
private void printUsage() {
230+
System.out.println("Java wolfJSSE example threaded client usage:");
231+
System.out.println("-n <num>\tNumber of client connections");
232+
System.exit(1);
233+
}
234+
}
235+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/bin/bash
2+
3+
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./lib/:/usr/local/lib
4+
java -classpath ./lib/wolfssl.jar:./lib/wolfssl-jsse.jar:./examples/build -Dsun.boot.library.path=./lib/ -Dwolfjsse.debug=true MultiThreadedSSLClient $@
5+

examples/provider/MultiThreadedSSLServer.java

Lines changed: 27 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,15 @@
2424
*
2525
* This server waits in an infinite loop for client connections, and when
2626
* connected creates a new thread for each connection. This example is compiled
27-
* when 'ant' is run in the package root.
27+
* when 'ant examples' is run in the package root.
2828
*
29-
* $ ant
29+
* $ ant examples
3030
* $ ./examples/provider/MultiThreadedSSLServer.sh
3131
*
32-
* This can be tested against the normal wolfSSL example client. But, wolfSSL
33-
* will need to be compiled with WOLFSSL_ALT_TEST_STRINGS defined so that
34-
* the client strings are null terminated.
32+
* For multi threaded client testing, test against MultiThreadedSSLClient.sh.
33+
* For example, to connect 10 client threads:
34+
*
35+
* ./examples/provider/MultiThreadedSSLClient.sh -n 10
3536
*
3637
*/
3738
import java.util.*;
@@ -44,24 +45,29 @@
4445
public class MultiThreadedSSLServer
4546
{
4647
private char[] psw = "wolfSSL test".toCharArray();
47-
private String serverJKS = "./examples/provider/server.jks";
48+
private String serverKS = "./examples/provider/rsa.jks";
49+
private String serverTS = "./examples/provider/client.jks";
4850
int serverPort = 11118;
4951

5052
public MultiThreadedSSLServer() {
5153
try {
5254

5355
Security.addProvider(new WolfSSLProvider());
5456

55-
KeyStore pKey = KeyStore.getInstance("JKS");
56-
pKey.load(new FileInputStream(serverJKS), psw);
57-
KeyStore cert = KeyStore.getInstance("JKS");
58-
cert.load(new FileInputStream(serverJKS), psw);
57+
/* Set up KeyStore */
58+
KeyStore serverKeyStore = KeyStore.getInstance("JKS");
59+
serverKeyStore.load(new FileInputStream(serverKS), psw);
60+
61+
KeyManagerFactory km = KeyManagerFactory.getInstance("SunX509");
62+
km.init(serverKeyStore, psw);
63+
64+
/* Set up CA TrustManagerFactory */
65+
KeyStore caKeyStore = KeyStore.getInstance("JKS");
66+
caKeyStore.load(new FileInputStream(serverTS), psw);
5967

6068
TrustManagerFactory tm = TrustManagerFactory.getInstance("SunX509");
61-
tm.init(cert);
62-
63-
KeyManagerFactory km = KeyManagerFactory.getInstance("SunX509");
64-
km.init(pKey, psw);
69+
tm.init(caKeyStore);
70+
6571

6672
SSLContext ctx = SSLContext.getInstance("TLS", "wolfJSSE");
6773
ctx.init(km.getKeyManagers(), tm.getTrustManagers(), null);
@@ -91,26 +97,17 @@ public ClientHandler(SSLSocket s) {
9197

9298
public void run() {
9399

94-
try {
95-
96-
OutputStream rawOut = sock.getOutputStream();
100+
byte[] response = new byte[80];
101+
String msg = "I hear you fa shizzle, from Java!";
97102

98-
PrintWriter out = new PrintWriter(
99-
new BufferedWriter(
100-
new OutputStreamWriter(rawOut)));
101-
102-
BufferedReader in = new BufferedReader(
103-
new InputStreamReader(sock.getInputStream()));
103+
try {
104104

105-
String line = in.readLine();
106-
System.out.println("client: " + line);
105+
sock.startHandshake();
107106

108-
out.print("I hear you C client!");
109-
out.flush();
110-
out.close();
111-
in.close();
107+
sock.getInputStream().read(response);
108+
System.out.println("Client message : " + new String(response));
109+
sock.getOutputStream().write(msg.getBytes());
112110

113-
in.close();
114111
sock.close();
115112

116113
} catch (Exception e) {

0 commit comments

Comments
 (0)