add multi-threaded JSSE provider client and server example
parent
4f60a888d8
commit
09a18dbfba
|
@ -0,0 +1,235 @@
|
||||||
|
/* MultiThreadedSSLClient.java
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006-2021 wolfSSL Inc.
|
||||||
|
*
|
||||||
|
* This file is part of wolfSSL.
|
||||||
|
*
|
||||||
|
* wolfSSL is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* wolfSSL is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multi threaded SSLSocket example that connects a specified number of
|
||||||
|
* client threads to a server. Intended to test multi-threading with wolfJSSE.
|
||||||
|
*
|
||||||
|
* This example creates a specified number of client threads to a server
|
||||||
|
* located at 127.0.0.1:11118. This example is set up to use the SSLSocket
|
||||||
|
* class. It makes one connection (handshake), sends/receives data, and shuts
|
||||||
|
* down.
|
||||||
|
*
|
||||||
|
* A random amount of time is injected into each client thread before:
|
||||||
|
* 1) The SSL/TLS handshake
|
||||||
|
* 2) Doing I/O operations after the handshake
|
||||||
|
*
|
||||||
|
* The maximum amount of sleep time for each of those is "maxSleep", or
|
||||||
|
* 3 seconds by default. This is intended to add some randomness into the
|
||||||
|
* the client thread operations.
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
*
|
||||||
|
* $ ant examples
|
||||||
|
* $ ./examples/provider/MultiThreadedSSLClient.java
|
||||||
|
*
|
||||||
|
* This example is designed to connect against the MultiThreadedSSLServer
|
||||||
|
* example:
|
||||||
|
*
|
||||||
|
* $ ./examples/provider/MultiThreadedSSLServer.java
|
||||||
|
*
|
||||||
|
* This example also prints out average SSL/TLS handshake time, which is
|
||||||
|
* measured in milliseconds on the "startHandshake()" API call.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.*;
|
||||||
|
import javax.net.ssl.*;
|
||||||
|
import java.security.*;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
import com.wolfssl.provider.jsse.WolfSSLProvider;
|
||||||
|
|
||||||
|
public class MultiThreadedSSLClient
|
||||||
|
{
|
||||||
|
String tmfImpl = "SunX509"; /* TrustManagerFactory provider */
|
||||||
|
String kmfImpl = "SunX509"; /* KeyManagerFactory provider */
|
||||||
|
String ctxImpl = "wolfJSSE"; /* SSLContext provider */
|
||||||
|
|
||||||
|
String srvHost = "127.0.0.1"; /* server host */
|
||||||
|
int srvPort = 11118; /* server port */
|
||||||
|
|
||||||
|
int numClientConnections = 10; /* number of client connection threads */
|
||||||
|
int startedClientConnections = 0; /* active clients connected to server */
|
||||||
|
int successClientConnections = 0; /* successful client connections */
|
||||||
|
int failedClientConnections = 0; /* failed client connections */
|
||||||
|
|
||||||
|
long totalConnectionTimeMs = 0; /* total handshake time, across clients */
|
||||||
|
final Object timeLock = new Object();
|
||||||
|
|
||||||
|
class ClientThread implements Runnable
|
||||||
|
{
|
||||||
|
private KeyManagerFactory km = null;
|
||||||
|
private TrustManagerFactory tm = null;
|
||||||
|
private CountDownLatch latch;
|
||||||
|
|
||||||
|
public ClientThread(KeyManagerFactory km, TrustManagerFactory tm,
|
||||||
|
CountDownLatch latch) {
|
||||||
|
this.km = km;
|
||||||
|
this.tm = tm;
|
||||||
|
this.latch = latch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
|
||||||
|
byte[] back = new byte[80];
|
||||||
|
String msg = "Too legit to quit";
|
||||||
|
|
||||||
|
/* max sleep is 3 seconds */
|
||||||
|
int maxSleep = 3000;
|
||||||
|
|
||||||
|
/* get random sleep value before calling connect() */
|
||||||
|
int randConnectSleep =
|
||||||
|
ThreadLocalRandom.current().nextInt(0, maxSleep + 1);
|
||||||
|
|
||||||
|
/* get random sleep value before doing I/O after handshake */
|
||||||
|
int randIOSleep =
|
||||||
|
ThreadLocalRandom.current().nextInt(0, maxSleep +1);
|
||||||
|
|
||||||
|
try {
|
||||||
|
SSLContext ctx = SSLContext.getInstance("TLS", ctxImpl);
|
||||||
|
ctx.init(km.getKeyManagers(), tm.getTrustManagers(), null);
|
||||||
|
|
||||||
|
SSLSocket sock = (SSLSocket)ctx.getSocketFactory()
|
||||||
|
.createSocket();
|
||||||
|
|
||||||
|
Thread.sleep(randConnectSleep);
|
||||||
|
|
||||||
|
sock.connect(new InetSocketAddress(srvHost, srvPort));
|
||||||
|
|
||||||
|
final long startTime = System.currentTimeMillis();
|
||||||
|
sock.startHandshake();
|
||||||
|
final long endTime = System.currentTimeMillis();
|
||||||
|
|
||||||
|
synchronized (timeLock) {
|
||||||
|
totalConnectionTimeMs += (endTime - startTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread.sleep(randIOSleep);
|
||||||
|
|
||||||
|
sock.getOutputStream().write(msg.getBytes());
|
||||||
|
sock.getInputStream().read(back);
|
||||||
|
System.out.println("Server message : " + new String(back));
|
||||||
|
|
||||||
|
sock.close();
|
||||||
|
successClientConnections++;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
failedClientConnections++;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.latch.countDown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public MultiThreadedSSLClient(String[] args) {
|
||||||
|
|
||||||
|
Security.addProvider(new WolfSSLProvider());
|
||||||
|
|
||||||
|
String clientKS = "./examples/provider/client.jks";
|
||||||
|
String clientTS = "./examples/provider/client.jks";
|
||||||
|
String jkspass = "wolfSSL test";
|
||||||
|
char[] passArr = jkspass.toCharArray();
|
||||||
|
|
||||||
|
if (args.length != 2) {
|
||||||
|
printUsage();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pull in command line options from user */
|
||||||
|
for (int i = 0; i < args.length; i++)
|
||||||
|
{
|
||||||
|
String arg = args[i];
|
||||||
|
|
||||||
|
if (arg.equals("-n")) {
|
||||||
|
if (args.length < i+2)
|
||||||
|
printUsage();
|
||||||
|
numClientConnections = Integer.parseInt(args[++i]);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
printUsage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
List<ClientThread> clientList = new ArrayList<ClientThread>();
|
||||||
|
CountDownLatch latch = new CountDownLatch(numClientConnections);
|
||||||
|
|
||||||
|
/* set up client KeyStore */
|
||||||
|
KeyStore clientKeyStore = KeyStore.getInstance("JKS");
|
||||||
|
clientKeyStore.load(new FileInputStream(clientKS), passArr);
|
||||||
|
|
||||||
|
KeyManagerFactory clientKMF =
|
||||||
|
KeyManagerFactory.getInstance(kmfImpl);
|
||||||
|
clientKMF.init(clientKeyStore, passArr);
|
||||||
|
|
||||||
|
/* set up CA TrustManagerFactory */
|
||||||
|
KeyStore caKeyStore = KeyStore.getInstance("JKS");
|
||||||
|
caKeyStore.load(new FileInputStream(clientTS), passArr);
|
||||||
|
|
||||||
|
TrustManagerFactory tm = TrustManagerFactory.getInstance(tmfImpl);
|
||||||
|
tm.init(caKeyStore);
|
||||||
|
|
||||||
|
for (int i = 0; i < numClientConnections; i++) {
|
||||||
|
clientList.add(new ClientThread(clientKMF, tm, latch));
|
||||||
|
}
|
||||||
|
|
||||||
|
ExecutorService executor = Executors.newFixedThreadPool(
|
||||||
|
clientList.size());
|
||||||
|
|
||||||
|
for (final ClientThread c : clientList) {
|
||||||
|
executor.execute(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
latch.await();
|
||||||
|
executor.shutdown();
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
Security.removeProvider("wolfJSSE");
|
||||||
|
|
||||||
|
System.out.println("================================================");
|
||||||
|
System.out.println("All Client Connections Finished");
|
||||||
|
System.out.println("Successful = " + successClientConnections);
|
||||||
|
System.out.println("Failed = " + failedClientConnections);
|
||||||
|
System.out.println("Avg handshake time = " +
|
||||||
|
totalConnectionTimeMs / successClientConnections + " ms");
|
||||||
|
System.out.println("================================================");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
new MultiThreadedSSLClient(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void printUsage() {
|
||||||
|
System.out.println("Java wolfJSSE example threaded client usage:");
|
||||||
|
System.out.println("-n <num>\tNumber of client connections");
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./lib/:/usr/local/lib
|
||||||
|
java -classpath ./lib/wolfssl.jar:./lib/wolfssl-jsse.jar:./examples/build -Dsun.boot.library.path=./lib/ -Dwolfjsse.debug=true MultiThreadedSSLClient $@
|
||||||
|
|
|
@ -24,14 +24,15 @@
|
||||||
*
|
*
|
||||||
* This server waits in an infinite loop for client connections, and when
|
* This server waits in an infinite loop for client connections, and when
|
||||||
* connected creates a new thread for each connection. This example is compiled
|
* connected creates a new thread for each connection. This example is compiled
|
||||||
* when 'ant' is run in the package root.
|
* when 'ant examples' is run in the package root.
|
||||||
*
|
*
|
||||||
* $ ant
|
* $ ant examples
|
||||||
* $ ./examples/provider/MultiThreadedSSLServer.sh
|
* $ ./examples/provider/MultiThreadedSSLServer.sh
|
||||||
*
|
*
|
||||||
* This can be tested against the normal wolfSSL example client. But, wolfSSL
|
* For multi threaded client testing, test against MultiThreadedSSLClient.sh.
|
||||||
* will need to be compiled with WOLFSSL_ALT_TEST_STRINGS defined so that
|
* For example, to connect 10 client threads:
|
||||||
* the client strings are null terminated.
|
*
|
||||||
|
* ./examples/provider/MultiThreadedSSLClient.sh -n 10
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
@ -44,7 +45,8 @@ import com.wolfssl.provider.jsse.WolfSSLProvider;
|
||||||
public class MultiThreadedSSLServer
|
public class MultiThreadedSSLServer
|
||||||
{
|
{
|
||||||
private char[] psw = "wolfSSL test".toCharArray();
|
private char[] psw = "wolfSSL test".toCharArray();
|
||||||
private String serverJKS = "./examples/provider/server.jks";
|
private String serverKS = "./examples/provider/rsa.jks";
|
||||||
|
private String serverTS = "./examples/provider/client.jks";
|
||||||
int serverPort = 11118;
|
int serverPort = 11118;
|
||||||
|
|
||||||
public MultiThreadedSSLServer() {
|
public MultiThreadedSSLServer() {
|
||||||
|
@ -52,16 +54,20 @@ public class MultiThreadedSSLServer
|
||||||
|
|
||||||
Security.addProvider(new WolfSSLProvider());
|
Security.addProvider(new WolfSSLProvider());
|
||||||
|
|
||||||
KeyStore pKey = KeyStore.getInstance("JKS");
|
/* Set up KeyStore */
|
||||||
pKey.load(new FileInputStream(serverJKS), psw);
|
KeyStore serverKeyStore = KeyStore.getInstance("JKS");
|
||||||
KeyStore cert = KeyStore.getInstance("JKS");
|
serverKeyStore.load(new FileInputStream(serverKS), psw);
|
||||||
cert.load(new FileInputStream(serverJKS), psw);
|
|
||||||
|
|
||||||
TrustManagerFactory tm = TrustManagerFactory.getInstance("SunX509");
|
|
||||||
tm.init(cert);
|
|
||||||
|
|
||||||
KeyManagerFactory km = KeyManagerFactory.getInstance("SunX509");
|
KeyManagerFactory km = KeyManagerFactory.getInstance("SunX509");
|
||||||
km.init(pKey, psw);
|
km.init(serverKeyStore, psw);
|
||||||
|
|
||||||
|
/* Set up CA TrustManagerFactory */
|
||||||
|
KeyStore caKeyStore = KeyStore.getInstance("JKS");
|
||||||
|
caKeyStore.load(new FileInputStream(serverTS), psw);
|
||||||
|
|
||||||
|
TrustManagerFactory tm = TrustManagerFactory.getInstance("SunX509");
|
||||||
|
tm.init(caKeyStore);
|
||||||
|
|
||||||
|
|
||||||
SSLContext ctx = SSLContext.getInstance("TLS", "wolfJSSE");
|
SSLContext ctx = SSLContext.getInstance("TLS", "wolfJSSE");
|
||||||
ctx.init(km.getKeyManagers(), tm.getTrustManagers(), null);
|
ctx.init(km.getKeyManagers(), tm.getTrustManagers(), null);
|
||||||
|
@ -91,26 +97,17 @@ public class MultiThreadedSSLServer
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
|
|
||||||
|
byte[] response = new byte[80];
|
||||||
|
String msg = "I hear you fa shizzle, from Java!";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
OutputStream rawOut = sock.getOutputStream();
|
sock.startHandshake();
|
||||||
|
|
||||||
PrintWriter out = new PrintWriter(
|
sock.getInputStream().read(response);
|
||||||
new BufferedWriter(
|
System.out.println("Client message : " + new String(response));
|
||||||
new OutputStreamWriter(rawOut)));
|
sock.getOutputStream().write(msg.getBytes());
|
||||||
|
|
||||||
BufferedReader in = new BufferedReader(
|
|
||||||
new InputStreamReader(sock.getInputStream()));
|
|
||||||
|
|
||||||
String line = in.readLine();
|
|
||||||
System.out.println("client: " + line);
|
|
||||||
|
|
||||||
out.print("I hear you C client!");
|
|
||||||
out.flush();
|
|
||||||
out.close();
|
|
||||||
in.close();
|
|
||||||
|
|
||||||
in.close();
|
|
||||||
sock.close();
|
sock.close();
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|
Loading…
Reference in New Issue