2016-11-06 22:17:58 -06:00
|
|
|
/* client-tls-perf.c
|
|
|
|
*
|
2020-01-03 18:08:42 -06:00
|
|
|
* Copyright (C) 2006-2020 wolfSSL Inc.
|
2016-11-06 22:17:58 -06:00
|
|
|
*
|
|
|
|
* This file is part of wolfSSL. (formerly known as CyaSSL)
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*=============================================================================
|
|
|
|
*
|
|
|
|
* This is an example of a TCP Client that uses non blocking input and output to
|
|
|
|
* handle a large number of connections.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/epoll.h>
|
|
|
|
|
|
|
|
#include <wolfssl/options.h>
|
|
|
|
#include <wolfssl/ssl.h>
|
|
|
|
|
|
|
|
#include <wolfssl/test.h>
|
|
|
|
|
|
|
|
|
|
|
|
/* Default port to listen on. */
|
|
|
|
#define DEFAULT_PORT 11111
|
|
|
|
/* The number of concurrent connections to support. */
|
|
|
|
#define SSL_NUM_CONN 15
|
|
|
|
/* The number of bytes to read from server. */
|
|
|
|
#define NUM_READ_BYTES 16384
|
|
|
|
/* The number of bytes to write to server. */
|
|
|
|
#define NUM_WRITE_BYTES 16384
|
|
|
|
/* The maximum number of bytes to send in a run. */
|
|
|
|
#define MAX_BYTES -1
|
|
|
|
/* The maximum number of connections to perform in this run. */
|
|
|
|
#define MAX_CONNECTIONS 100
|
|
|
|
|
|
|
|
/* The command line options. */
|
|
|
|
#define OPTIONS "?p:v:l:c:k:A:rn:N:R:W:B:"
|
|
|
|
|
|
|
|
/* The default client certificate. */
|
|
|
|
#define CLI_CERT "../certs/client-cert.pem"
|
|
|
|
/* The default client private key. */
|
|
|
|
#define CLI_KEY "../certs/client-key.pem"
|
|
|
|
/* The default CA file for the server. */
|
|
|
|
#define CA_CERT "../certs/ca-cert.pem"
|
|
|
|
|
|
|
|
|
|
|
|
/* The states of the SSL connection. */
|
2016-11-17 21:15:47 -06:00
|
|
|
typedef enum SSLState { INIT, CONNECT, WRITE, READ_WAIT, READ, CLOSE } SSLState;
|
2016-11-06 22:17:58 -06:00
|
|
|
|
|
|
|
/* Data for each active connection. */
|
|
|
|
typedef struct SSLConn {
|
|
|
|
/* The socket listening on, reading from and writing to. */
|
|
|
|
int sockfd;
|
|
|
|
/* The wolfSSL object to perform TLS communications. */
|
|
|
|
WOLFSSL* ssl;
|
|
|
|
/* Session to resume. */
|
|
|
|
WOLFSSL_SESSION* session;
|
|
|
|
/* The current state of the SSL/TLS connection. */
|
|
|
|
SSLState state;
|
|
|
|
/* Last error from connect/read/write. */
|
|
|
|
int err;
|
|
|
|
} SSLConn;
|
|
|
|
|
|
|
|
/* The information about SSL/TLS connections. */
|
|
|
|
typedef struct SSLConnCtx {
|
|
|
|
/* An array of active connections. */
|
|
|
|
SSLConn* sslConn;
|
|
|
|
/* The number of active connections. */
|
|
|
|
int numConns;
|
|
|
|
/* Count of currently active connections. */
|
|
|
|
int cnt;
|
|
|
|
|
|
|
|
/* Resume the session on subsequent connections. */
|
|
|
|
int resume;
|
|
|
|
|
|
|
|
/* The buffer for the server data. */
|
|
|
|
char* buffer;
|
|
|
|
/* Size of the server data buffer. */
|
|
|
|
int bufferLen;
|
|
|
|
/* The data to reply with. */
|
|
|
|
char* reply;
|
|
|
|
/* Number of bytes to write. */
|
|
|
|
int replyLen;
|
|
|
|
|
|
|
|
/* Number of created connections. */
|
|
|
|
int numCreated;
|
|
|
|
/* Number of connections handled. */
|
|
|
|
int numConnections;
|
|
|
|
/* Number of resumed connections handled. */
|
|
|
|
int numResumed;
|
|
|
|
/* Maximum number of connections to perform. */
|
|
|
|
int maxConnections;
|
|
|
|
|
|
|
|
/* Total number of bytes read. */
|
|
|
|
int totalReadBytes;
|
|
|
|
/* Total number of bytes written. */
|
|
|
|
int totalWriteBytes;
|
|
|
|
/* Maximum number of bytes to read/write. */
|
|
|
|
int maxBytes;
|
|
|
|
|
|
|
|
/* Total time handling connects. */
|
|
|
|
double connTime;
|
|
|
|
/* Total time handling resumed connections. */
|
|
|
|
double resumeTime;
|
|
|
|
#ifdef WOLFSSL_ASYNC_CRYPT
|
2021-06-09 11:03:36 -05:00
|
|
|
/* Total time handling asynchronous operations. */
|
2016-11-06 22:17:58 -06:00
|
|
|
double asyncTime;
|
|
|
|
#endif
|
|
|
|
/* Total time handling reading. */
|
|
|
|
double readTime;
|
|
|
|
/* Total time handling writing. */
|
|
|
|
double writeTime;
|
|
|
|
/* Total time handling connections. */
|
|
|
|
double totalTime;
|
|
|
|
} SSLConn_CTX;
|
|
|
|
|
|
|
|
|
|
|
|
static void SSLConn_Free(SSLConn_CTX* ctx);
|
|
|
|
|
|
|
|
|
|
|
|
/* The index of the command line option. */
|
|
|
|
int myoptind = 0;
|
|
|
|
/* The current command line option. */
|
|
|
|
char* myoptarg = NULL;
|
|
|
|
#ifdef WOLFSSL_ASYNC_CRYPT
|
|
|
|
/* Global device identifier. */
|
|
|
|
static int devId = INVALID_DEVID;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2017-01-26 19:11:32 -06:00
|
|
|
/* Get the wolfSSL client method function for the specified version.
|
2016-11-06 22:17:58 -06:00
|
|
|
*
|
|
|
|
* version Protocol version to use.
|
2017-01-26 19:11:32 -06:00
|
|
|
* returns The client method function or NULL when version not supported.
|
2016-11-06 22:17:58 -06:00
|
|
|
*/
|
|
|
|
static wolfSSL_method_func SSL_GetMethod(int version)
|
|
|
|
{
|
|
|
|
wolfSSL_method_func method = NULL;
|
|
|
|
|
|
|
|
switch (version) {
|
|
|
|
#ifndef NO_OLD_TLS
|
|
|
|
#ifdef WOLFSSL_ALLOW_SSLV3
|
|
|
|
case 0:
|
|
|
|
method = wolfSSLv3_client_method_ex;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef NO_TLS
|
2018-09-06 14:11:24 -05:00
|
|
|
#ifdef WOLFSSL_ALLOW_TLSV10
|
2016-11-06 22:17:58 -06:00
|
|
|
case 1:
|
|
|
|
method = wolfTLSv1_client_method_ex;
|
|
|
|
break;
|
2018-09-06 14:11:24 -05:00
|
|
|
#endif
|
2016-11-06 22:17:58 -06:00
|
|
|
|
2018-09-06 14:11:24 -05:00
|
|
|
#ifndef NO_OLD_TLS
|
2016-11-06 22:17:58 -06:00
|
|
|
case 2:
|
|
|
|
method = wolfTLSv1_1_client_method_ex;
|
|
|
|
break;
|
2018-09-06 14:11:24 -05:00
|
|
|
#endif
|
2016-11-06 22:17:58 -06:00
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef NO_TLS
|
|
|
|
case 3:
|
|
|
|
method = wolfTLSv1_2_client_method_ex;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
return method;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Write data to a server.
|
|
|
|
*
|
|
|
|
* ssl The wolfSSL object.
|
|
|
|
* reply The data to send to the server.
|
|
|
|
* replyLen The length of the data to send to the server.
|
|
|
|
* totalBytes The total number of bytes sent to servers.
|
|
|
|
* writeTime The amount of time spent writing data to server.
|
|
|
|
* returns 0 on failure, 1 on success, 2 on want read and 3 on want write.
|
|
|
|
*/
|
|
|
|
static int SSL_Write(WOLFSSL* ssl, char* reply, int replyLen, int* totalBytes,
|
|
|
|
double* writeTime)
|
|
|
|
{
|
|
|
|
int rwret = 0;
|
|
|
|
int error;
|
|
|
|
double start;
|
|
|
|
|
|
|
|
start = current_time(1);
|
|
|
|
rwret = wolfSSL_write(ssl, reply, replyLen);
|
|
|
|
*writeTime += current_time(0) - start;
|
|
|
|
if (rwret == 0) {
|
|
|
|
fprintf(stderr, "The server has closed the connection!\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rwret > 0)
|
|
|
|
*totalBytes += rwret;
|
|
|
|
if (rwret == replyLen)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
error = wolfSSL_get_error(ssl, 0);
|
|
|
|
if (error == SSL_ERROR_WANT_READ)
|
|
|
|
return 2;
|
|
|
|
if (error == SSL_ERROR_WANT_WRITE)
|
|
|
|
return 3;
|
2017-01-30 16:25:51 -06:00
|
|
|
if (error == WC_PENDING_E)
|
|
|
|
return 4;
|
2016-11-06 22:17:58 -06:00
|
|
|
if (error == 0)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* Cannot do anything about other errors. */
|
|
|
|
fprintf(stderr, "wolfSSL_read/write error = %d\n", error);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Reads data from a server.
|
|
|
|
*
|
|
|
|
* ssl The wolfSSL object.
|
|
|
|
* buffer The buffer to place server data into.
|
|
|
|
* len The length of the buffer.
|
|
|
|
* totalBytes The total number of bytes read from servers.
|
|
|
|
* readTime The amount of time spent reading data from server.
|
|
|
|
* returns 0 on failure, 1 on success, 2 on want read and 3 on want write.
|
|
|
|
*/
|
|
|
|
static int SSL_Read(WOLFSSL* ssl, char* buffer, int len, int* totalBytes,
|
|
|
|
double* readTime)
|
|
|
|
{
|
|
|
|
int rwret = 0;
|
|
|
|
int error;
|
|
|
|
double start;
|
|
|
|
|
|
|
|
start = current_time(1);
|
|
|
|
rwret = wolfSSL_read(ssl, buffer, len);
|
|
|
|
*readTime += current_time(0) - start;
|
|
|
|
if (rwret == 0) {
|
|
|
|
fprintf(stderr, "The server has closed the connection!\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rwret > 0)
|
|
|
|
*totalBytes += rwret;
|
|
|
|
|
|
|
|
error = wolfSSL_get_error(ssl, 0);
|
|
|
|
if (error == SSL_ERROR_WANT_READ)
|
|
|
|
return 2;
|
|
|
|
if (error == SSL_ERROR_WANT_WRITE)
|
|
|
|
return 3;
|
|
|
|
if (error == WC_PENDING_E)
|
|
|
|
return 4;
|
|
|
|
if (error == 0)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* Cannot do anything about other errors. */
|
|
|
|
fprintf(stderr, "wolfSSL_read/write error = %d\n", error);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Connect/negotiate a secure connection.
|
|
|
|
*
|
|
|
|
* ssl The wolfSSL object.
|
|
|
|
* resume Resume the session.
|
|
|
|
* session Session to resume.
|
|
|
|
* connTime The amount of time spent connecting to the server.
|
|
|
|
* resumeTime The amount of time spent resuming a connection with the server.
|
|
|
|
* returns 0 on failure, 1 on success, 2 on want read and 3 on want write.
|
|
|
|
*/
|
|
|
|
static int SSL_Connect(WOLFSSL* ssl, int resume, WOLFSSL_SESSION* session,
|
|
|
|
double* connTime, double* resumeTime)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
int error;
|
|
|
|
double start;
|
|
|
|
|
|
|
|
start = current_time(1);
|
|
|
|
if (resume && (session != NULL))
|
|
|
|
wolfSSL_set_session(ssl, session);
|
|
|
|
/* Connect to the server. */
|
|
|
|
ret = wolfSSL_connect(ssl);
|
|
|
|
if (!wolfSSL_session_reused(ssl))
|
|
|
|
*connTime += current_time(0) - start;
|
|
|
|
else
|
|
|
|
*resumeTime += current_time(0) - start;
|
|
|
|
if (ret == 0) {
|
|
|
|
fprintf(stderr, "The server has closed the connection!\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret == SSL_SUCCESS)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
error = wolfSSL_get_error(ssl, 0);
|
|
|
|
if (error == SSL_ERROR_WANT_READ)
|
|
|
|
return 2;
|
|
|
|
if (error == SSL_ERROR_WANT_WRITE)
|
|
|
|
return 3;
|
|
|
|
if (error == WC_PENDING_E)
|
|
|
|
return 4;
|
|
|
|
if (error == 0)
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
|
|
|
|
/* Cannot do anything about other errors. */
|
|
|
|
fprintf(stderr, "wolfSSL_read/write error = %d\n", error);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create a random reply.
|
|
|
|
*
|
|
|
|
* reply The buffer to put the random data into.
|
|
|
|
* replyLen The amount of data to generate.
|
|
|
|
*/
|
|
|
|
static void RandomReply(char* reply, int replyLen)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
WC_RNG rng;
|
|
|
|
|
|
|
|
ret = wc_InitRng(&rng);
|
|
|
|
if (ret != 0) {
|
|
|
|
fprintf(stderr, "Error: initialize random\n");
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = wc_RNG_GenerateBlock(&rng, (byte*)reply, replyLen);
|
|
|
|
wc_FreeRng(&rng);
|
|
|
|
if (ret != 0) {
|
|
|
|
fprintf(stderr, "Error: initialize random\n");
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Create a new SSL/TLS connection data object.
|
|
|
|
*
|
|
|
|
* numConns The number of concurrent connections.
|
|
|
|
* bufferLen The number of data bytes to read from server.
|
|
|
|
* replyLen The number of data bytes to send to servers.
|
|
|
|
* maxConns The number of connections to process this run.
|
|
|
|
* -1 indicates no maximum.
|
|
|
|
* maxBytes The number of bytes to send this run.
|
|
|
|
* -1 indicates no maximum.
|
|
|
|
* returns an allocated and initialized connection data object or NULL on error.
|
|
|
|
*/
|
|
|
|
static SSLConn_CTX* SSLConn_New(int numConns, int bufferLen, int replyLen,
|
|
|
|
int maxConns, int maxBytes, int resume)
|
|
|
|
{
|
|
|
|
SSLConn_CTX* ctx;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
ctx = (SSLConn_CTX*)malloc(sizeof(*ctx));
|
|
|
|
if (ctx == NULL)
|
|
|
|
return NULL;
|
|
|
|
memset(ctx, 0, sizeof(*ctx));
|
|
|
|
|
|
|
|
ctx->resume = resume;
|
|
|
|
ctx->numConns = numConns;
|
|
|
|
ctx->bufferLen = bufferLen;
|
|
|
|
ctx->replyLen = replyLen;
|
|
|
|
ctx->maxConnections = maxConns;
|
|
|
|
ctx->maxBytes = maxBytes;
|
|
|
|
|
|
|
|
/* Create an entry for each concurrent connection. */
|
|
|
|
ctx->sslConn = (SSLConn*)malloc(ctx->numConns * sizeof(*ctx->sslConn));
|
|
|
|
if (ctx->sslConn == NULL) {
|
|
|
|
SSLConn_Free(ctx);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
for (i = 0; i < ctx->numConns; i++) {
|
|
|
|
ctx->sslConn[i].sockfd = -1;
|
|
|
|
ctx->sslConn[i].ssl = NULL;
|
|
|
|
ctx->sslConn[i].session = NULL;
|
|
|
|
ctx->sslConn[i].state = INIT;
|
|
|
|
ctx->sslConn[i].err = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create a buffer for server data. */
|
|
|
|
ctx->buffer = (char*)malloc(bufferLen);
|
|
|
|
if (ctx->buffer == NULL) {
|
|
|
|
SSLConn_Free(ctx);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create a reply that contains rand data. */
|
|
|
|
ctx->reply = (char*)malloc(replyLen);
|
|
|
|
if (ctx->reply == NULL) {
|
|
|
|
SSLConn_Free(ctx);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
RandomReply(ctx->reply, replyLen);
|
|
|
|
|
|
|
|
return ctx;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Free the SSL/TLS connection data.
|
|
|
|
*
|
|
|
|
* ctx The connection data.
|
|
|
|
*/
|
|
|
|
static void SSLConn_Free(SSLConn_CTX* ctx)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (ctx == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (ctx->sslConn != NULL) {
|
|
|
|
for (i = 0; i < ctx->numConns; i++)
|
|
|
|
if (ctx->sslConn[i].ssl != NULL) {
|
|
|
|
wolfSSL_free(ctx->sslConn[i].ssl);
|
|
|
|
close(ctx->sslConn[i].sockfd);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ctx->sslConn != NULL)
|
|
|
|
free(ctx->sslConn);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ctx->buffer != NULL)
|
|
|
|
free(ctx->buffer);
|
|
|
|
|
|
|
|
if (ctx->reply != NULL)
|
|
|
|
free(ctx->reply);
|
|
|
|
|
|
|
|
free(ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Close an active connection.
|
|
|
|
*
|
|
|
|
* ctx The SSL/TLS connection data.
|
|
|
|
* sslConn The SSL connection to close.
|
|
|
|
*/
|
|
|
|
static void SSLConn_Close(SSLConn_CTX* ctx, SSLConn* sslConn)
|
|
|
|
{
|
|
|
|
if (wolfSSL_session_reused(sslConn->ssl))
|
|
|
|
ctx->numResumed++;
|
|
|
|
ctx->numConnections++;
|
|
|
|
|
|
|
|
if (ctx->resume)
|
|
|
|
sslConn->session = wolfSSL_get_session(sslConn->ssl);
|
|
|
|
wolfSSL_free(sslConn->ssl);
|
|
|
|
sslConn->ssl = NULL;
|
|
|
|
|
|
|
|
close(sslConn->sockfd);
|
|
|
|
sslConn->sockfd = -1;
|
|
|
|
|
|
|
|
sslConn->state = INIT;
|
|
|
|
|
|
|
|
ctx->cnt--;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Checks wether this run is done i.e. maximum number of connections or bytes
|
|
|
|
* have been server.
|
|
|
|
*
|
|
|
|
* ctx The SSL/TLS connection data.
|
|
|
|
* returns 1 if the run is done or 0 otherwise.
|
|
|
|
*/
|
|
|
|
static int SSLConn_Done(SSLConn_CTX* ctx) {
|
|
|
|
if (ctx->maxConnections > 0)
|
|
|
|
return (ctx->numConnections >= ctx->maxConnections);
|
|
|
|
return (ctx->totalWriteBytes >= ctx->maxBytes) &&
|
|
|
|
(ctx->totalReadBytes >= ctx->maxBytes);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Connects to the server.
|
|
|
|
*
|
|
|
|
* ctx The SSL/TLS connection data.
|
|
|
|
* sslCtx The SSL/TLS context.
|
|
|
|
* sockfd The socket for communicating with the server.
|
|
|
|
* sslConn The SSL connection.
|
|
|
|
* returns EXIT_SUCCESS if a new connection connected or EXIT_FAILURE otherwise.
|
|
|
|
*/
|
|
|
|
static int SSLConn_Connect(SSLConn_CTX* ctx, WOLFSSL_CTX* sslCtx, int sockfd,
|
|
|
|
SSLConn* sslConn)
|
|
|
|
{
|
|
|
|
ctx->numCreated++;
|
|
|
|
|
|
|
|
/* Setup connection. */
|
|
|
|
sslConn->sockfd = sockfd;
|
|
|
|
if ((sslConn->ssl = wolfSSL_new(sslCtx)) == NULL) {
|
|
|
|
fprintf(stderr, "wolfSSL_new error.\n");
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
sslConn->state = CONNECT;
|
|
|
|
/* Set the socket to communicate over. */
|
|
|
|
wolfSSL_set_fd(sslConn->ssl, sslConn->sockfd);
|
|
|
|
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Select on the socket and wait.
|
|
|
|
*
|
|
|
|
* socketfd The socket to select on.
|
|
|
|
* to_sec The length of time that select waits for.
|
|
|
|
* returns TEST_SELECT when the select times out, -1 on select error, 0 when
|
|
|
|
* there is an error on the socket and 1 on success.
|
|
|
|
*/
|
|
|
|
static int TCP_Select(SOCKET_T socketfd, int to_sec)
|
|
|
|
{
|
|
|
|
fd_set recvfds, errfds;
|
|
|
|
SOCKET_T nfds = socketfd + 1;
|
|
|
|
struct timeval timeout = { (to_sec > 0) ? to_sec : 0, 0};
|
|
|
|
int result;
|
|
|
|
|
|
|
|
FD_ZERO(&recvfds);
|
|
|
|
FD_SET(socketfd, &recvfds);
|
|
|
|
FD_ZERO(&errfds);
|
|
|
|
FD_SET(socketfd, &errfds);
|
|
|
|
|
|
|
|
result = select(nfds, &recvfds, NULL, &errfds, &timeout);
|
|
|
|
|
|
|
|
if (result == 0)
|
|
|
|
return -1;
|
|
|
|
else if (result > 0) {
|
|
|
|
if (FD_ISSET(socketfd, &recvfds))
|
|
|
|
return 1;
|
|
|
|
else if(FD_ISSET(socketfd, &errfds))
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TEST_SELECT_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Read/write from/to server at the specified socket.
|
|
|
|
*
|
|
|
|
* ctx The SSL/TLS connection data.
|
|
|
|
* sslConn The SSL connection.
|
|
|
|
* returns EXIT_FAILURE on failure and EXIT_SUCCESS otherwise.
|
|
|
|
*/
|
|
|
|
static int SSLConn_ReadWrite(SSLConn_CTX* ctx, SSLConn* sslConn)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
int len;
|
|
|
|
|
|
|
|
switch (sslConn->state) {
|
|
|
|
case INIT:
|
|
|
|
case CLOSE:
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Perform TLS handshake. */
|
|
|
|
case CONNECT:
|
|
|
|
ret = SSL_Connect(sslConn->ssl, ctx->resume, sslConn->session,
|
|
|
|
&ctx->connTime, &ctx->resumeTime);
|
|
|
|
if (ret == 0) {
|
|
|
|
sslConn->state = CLOSE;
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret == 1) {
|
|
|
|
sslConn->state = WRITE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WRITE:
|
|
|
|
len = ctx->replyLen;
|
|
|
|
if (ctx->maxBytes > 0) {
|
|
|
|
len = min(len, ctx->maxBytes - ctx->totalWriteBytes);
|
|
|
|
}
|
|
|
|
/* Don't write if we are done. */
|
|
|
|
if (len == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Write application data. */
|
|
|
|
ret = SSL_Write(sslConn->ssl, ctx->reply, len,
|
|
|
|
&ctx->totalWriteBytes, &ctx->writeTime);
|
|
|
|
if (ret == 0) {
|
|
|
|
sslConn->state = CLOSE;
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret == 1)
|
2016-11-17 21:15:47 -06:00
|
|
|
sslConn->state = READ_WAIT;
|
2016-11-06 22:17:58 -06:00
|
|
|
break;
|
|
|
|
|
2016-11-17 21:15:47 -06:00
|
|
|
case READ_WAIT:
|
2016-11-06 22:17:58 -06:00
|
|
|
ret = TCP_Select(sslConn->sockfd, 0);
|
|
|
|
if (ret != 1)
|
|
|
|
break;
|
2016-11-17 21:15:47 -06:00
|
|
|
sslConn->state = READ;
|
2016-11-06 22:17:58 -06:00
|
|
|
|
2016-11-17 21:15:47 -06:00
|
|
|
case READ:
|
2016-11-06 22:17:58 -06:00
|
|
|
len = ctx->bufferLen;
|
|
|
|
if (ctx->maxBytes > 0) {
|
|
|
|
len = min(len, ctx->maxBytes - ctx->totalReadBytes);
|
|
|
|
}
|
|
|
|
/* Don't read if we are done. */
|
|
|
|
if (len == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Read application data. */
|
|
|
|
ret = SSL_Read(sslConn->ssl, ctx->buffer, len, &ctx->totalReadBytes,
|
|
|
|
&ctx->readTime);
|
|
|
|
if (ret == 0) {
|
|
|
|
sslConn->state = CLOSE;
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret == 1) {
|
|
|
|
if (ctx->maxConnections > 0)
|
|
|
|
sslConn->state = CLOSE;
|
|
|
|
else
|
|
|
|
sslConn->state = WRITE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
sslConn->err = ret;
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Print the connection statistics.
|
|
|
|
*
|
|
|
|
* ctx The SSL/TLS connection data.
|
|
|
|
*/
|
|
|
|
static void SSLConn_PrintStats(SSLConn_CTX* ctx)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "wolfSSL Client Benchmark %d bytes\n"
|
|
|
|
"\tNum Conns : %9d\n"
|
|
|
|
"\tTotal : %9.3f ms\n"
|
|
|
|
"\tTotal Avg : %9.3f ms\n"
|
|
|
|
"\tt/s : %9.3f\n"
|
|
|
|
"\tConnect : %9.3f ms\n"
|
|
|
|
"\tConnect Avg : %9.3f ms\n",
|
|
|
|
ctx->replyLen,
|
|
|
|
ctx->numConnections - ctx->numResumed,
|
|
|
|
ctx->totalTime * 1000,
|
|
|
|
ctx->totalTime * 1000 / ctx->numConnections,
|
|
|
|
ctx->numConnections / ctx->totalTime,
|
|
|
|
ctx->connTime * 1000,
|
|
|
|
ctx->connTime * 1000 / (ctx->numConnections - ctx->numResumed));
|
|
|
|
if (ctx->resume) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"\tResumed Conns : %9d\n"
|
|
|
|
"\tResume : %9.3f ms\n"
|
|
|
|
"\tResume Avg : %9.3f ms\n",
|
|
|
|
ctx->numResumed,
|
|
|
|
ctx->resumeTime * 1000,
|
|
|
|
ctx->resumeTime * 1000 / ctx->numResumed);
|
|
|
|
}
|
|
|
|
#ifdef WOLFSSL_ASYNC_CRYPT
|
|
|
|
fprintf(stderr,
|
|
|
|
"\tAsync : %9.3f ms\n"
|
|
|
|
"\tAsync Avg : %9.3f ms\n",
|
|
|
|
ctx->asyncTime * 1000,
|
|
|
|
ctx->asyncTime * 1000 / ctx->numConnections);
|
|
|
|
#endif
|
|
|
|
fprintf(stderr,
|
|
|
|
"\tTotal Read bytes : %9d bytes\n"
|
|
|
|
"\tTotal Write bytes : %9d bytes\n"
|
|
|
|
"\tRead : %9.3f ms (%9.3f MBps)\n"
|
|
|
|
"\tWrite : %9.3f ms (%9.3f MBps)\n",
|
|
|
|
ctx->totalReadBytes,
|
|
|
|
ctx->totalWriteBytes,
|
|
|
|
ctx->readTime * 1000,
|
|
|
|
ctx->totalReadBytes / ctx->readTime / 1024 / 1024,
|
|
|
|
ctx->writeTime * 1000,
|
|
|
|
ctx->totalWriteBytes / ctx->writeTime / 1024 / 1024 );
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initialize the wolfSSL library and create a wolfSSL context.
|
|
|
|
*
|
|
|
|
* version The protocol version.
|
|
|
|
* cert The client certificate for client authentication.
|
|
|
|
* key The client private key for client authentication.
|
|
|
|
* verifyCert The CA certificate for server authentication.
|
|
|
|
* cipherList The list of ciphers, as a string, to negotiate.
|
|
|
|
* wolfsslCtx The new wolfSSL context object.
|
|
|
|
* returns EXIT_SUCCESS when a wolfSSL context object is created and
|
|
|
|
* EXIT_FAILURE otherwise.
|
|
|
|
*/
|
|
|
|
static int WolfSSLCtx_Init(int version, char* cert, char* key, char* verifyCert,
|
|
|
|
char* cipherList, WOLFSSL_CTX** wolfsslCtx)
|
|
|
|
{
|
|
|
|
WOLFSSL_CTX* ctx;
|
|
|
|
wolfSSL_method_func method = NULL;
|
|
|
|
|
|
|
|
method = SSL_GetMethod(version);
|
|
|
|
if (method == NULL)
|
|
|
|
return(EXIT_FAILURE);
|
|
|
|
|
|
|
|
/* Create and initialize WOLFSSL_CTX structure */
|
|
|
|
if ((ctx = wolfSSL_CTX_new(method(NULL))) == NULL) {
|
|
|
|
fprintf(stderr, "wolfSSL_CTX_new error.\n");
|
|
|
|
return(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef WOLFSSL_ASYNC_CRYPT
|
|
|
|
if (wolfAsync_DevOpen(&devId) != 0) {
|
2016-11-18 13:32:50 -06:00
|
|
|
fprintf(stderr, "Async device open failed\nRunning without async\n");
|
2016-11-06 22:17:58 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
wolfSSL_CTX_UseAsync(ctx, devId);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (cipherList) {
|
|
|
|
if (wolfSSL_CTX_set_cipher_list(ctx, cipherList) != SSL_SUCCESS)
|
|
|
|
err_sys("client can't set cipher list 1");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* load CA certificates into wolfSSL_CTX. which will verify the server */
|
|
|
|
if (wolfSSL_CTX_load_verify_locations(ctx, verifyCert, 0) != SSL_SUCCESS) {
|
|
|
|
printf("Error loading %s. Please check the file.\n", verifyCert);
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (wolfSSL_CTX_use_certificate_chain_file(ctx, cert) != SSL_SUCCESS) {
|
|
|
|
printf("Error loading %s. Please check the file.\n", cert);
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (wolfSSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM)
|
|
|
|
!= SSL_SUCCESS) {
|
|
|
|
printf("Error loading %s. Please check the file.\n", key);
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
*wolfsslCtx = ctx;
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Cleanup the wolfSSL context and wolfSSL library.
|
|
|
|
*
|
|
|
|
* ctx The wolfSSL context object.
|
|
|
|
*/
|
|
|
|
static void WolfSSLCtx_Final(WOLFSSL_CTX* ctx)
|
|
|
|
{
|
2017-01-26 19:11:32 -06:00
|
|
|
wolfSSL_CTX_free(ctx);
|
2016-11-06 22:17:58 -06:00
|
|
|
#ifdef WOLFSSL_ASYNC_CRYPT
|
|
|
|
wolfAsync_DevClose(&devId);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2021-06-09 11:03:36 -05:00
|
|
|
/* Create a socket to talk to server on and connect.
|
2016-11-06 22:17:58 -06:00
|
|
|
*
|
|
|
|
* port The port the server is listening on.
|
|
|
|
* socketfd The connected socket.
|
|
|
|
* returns EXIT_SUCCESS when the socket is connected and EXIT_FAILURE otherwise.
|
|
|
|
*/
|
|
|
|
static int CreateSocketConnect(int port, socklen_t* socketfd)
|
|
|
|
{
|
|
|
|
int on = 1;
|
|
|
|
socklen_t len = sizeof(on);
|
|
|
|
struct sockaddr_in serverAddr = {0};
|
|
|
|
socklen_t sockfd;
|
|
|
|
|
|
|
|
/* Create a non-blocking socket to listen on for new connections. */
|
|
|
|
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
if (sockfd == (socklen_t)-1) {
|
|
|
|
fprintf(stderr, "ERROR: failed to create the socket\n");
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the new socket to be non-blocking. */
|
|
|
|
fcntl(sockfd, F_SETFL, O_NONBLOCK);
|
|
|
|
|
|
|
|
/* Set the server's address. */
|
|
|
|
memset((char *)&serverAddr, 0, sizeof(serverAddr));
|
|
|
|
serverAddr.sin_family = AF_INET;
|
|
|
|
serverAddr.sin_addr.s_addr = INADDR_ANY;
|
|
|
|
serverAddr.sin_port = htons(port);
|
|
|
|
|
|
|
|
if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &on, len) < 0)
|
|
|
|
fprintf(stderr, "setsockopt TCP_NODELAY failed\n");
|
|
|
|
|
|
|
|
/* Connect to the server. */
|
|
|
|
while (connect(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)))
|
|
|
|
;
|
|
|
|
|
|
|
|
*socketfd = sockfd;
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Display the usage for the program.
|
|
|
|
*/
|
|
|
|
static void Usage(void)
|
|
|
|
{
|
|
|
|
printf("perf " LIBWOLFSSL_VERSION_STRING
|
|
|
|
" (NOTE: All files relative to wolfSSL home dir)\n");
|
|
|
|
printf("-? Help, print this usage\n");
|
|
|
|
printf("-p <num> Port to listen on, not 0, default %d\n", wolfSSLPort);
|
|
|
|
printf("-v <num> SSL version [0-3], SSLv3(0) - TLS1.2(3)), default %d\n",
|
|
|
|
SERVER_DEFAULT_VERSION);
|
|
|
|
printf("-l <str> Cipher suite list (: delimited)\n");
|
|
|
|
printf("-c <file> Certificate file, default %s\n", CLI_CERT);
|
|
|
|
printf("-k <file> Key file, default %s\n", CLI_KEY);
|
|
|
|
printf("-A <file> Certificate Authority file, default %s\n", CA_CERT);
|
|
|
|
printf("-r Resume session\n");
|
|
|
|
printf("-n <num> Benchmark <num> connections\n");
|
|
|
|
printf("-N <num> <num> concurrent connections\n");
|
|
|
|
printf("-R <num> <num> bytes read from client\n");
|
|
|
|
printf("-W <num> <num> bytes written to client\n");
|
|
|
|
printf("-B <num> Benchmark <num> written bytes\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Main entry point for the program.
|
|
|
|
*
|
|
|
|
* argc The count of command line arguments.
|
|
|
|
* argv The command line arguments.
|
|
|
|
* returns 0 on success and 1 otherwise.
|
|
|
|
*/
|
|
|
|
int main(int argc, char* argv[])
|
|
|
|
{
|
2017-01-26 19:11:32 -06:00
|
|
|
socklen_t socketfd = -1;
|
2016-11-06 22:17:58 -06:00
|
|
|
int ch;
|
|
|
|
WOLFSSL_CTX* ctx = NULL;
|
|
|
|
SSLConn_CTX* sslConnCtx;
|
|
|
|
word16 port = wolfSSLPort;
|
|
|
|
int resumeSession = 0;
|
|
|
|
char* cipherList = NULL;
|
|
|
|
char* ourCert = CLI_CERT;
|
|
|
|
char* ourKey = CLI_KEY;
|
|
|
|
char* verifyCert = CA_CERT;
|
|
|
|
int version = SERVER_DEFAULT_VERSION;
|
|
|
|
int numConns = SSL_NUM_CONN;
|
|
|
|
int numBytesRead = NUM_READ_BYTES;
|
|
|
|
int numBytesWrite = NUM_WRITE_BYTES;
|
|
|
|
int maxBytes = MAX_BYTES;
|
|
|
|
int maxConns = MAX_CONNECTIONS;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Parse the command line arguments. */
|
|
|
|
while ((ch = mygetopt(argc, argv, OPTIONS)) != -1) {
|
|
|
|
switch (ch) {
|
|
|
|
/* Help with command line options. */
|
|
|
|
case '?':
|
|
|
|
Usage();
|
|
|
|
exit(EXIT_SUCCESS);
|
|
|
|
|
|
|
|
/* Port number to connect to. */
|
|
|
|
case 'p':
|
|
|
|
port = (word16)atoi(myoptarg);
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Version of SSL/TLS to use. */
|
|
|
|
case 'v':
|
|
|
|
version = atoi(myoptarg);
|
|
|
|
if (version < 0 || version > 3) {
|
|
|
|
Usage();
|
|
|
|
exit(MY_EX_USAGE);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* List of cipher suites to use. */
|
|
|
|
case 'l':
|
|
|
|
cipherList = myoptarg;
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* File name of client certificate for client authentication. */
|
|
|
|
case 'c':
|
|
|
|
ourCert = myoptarg;
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* File name of client private key for client authentication. */
|
|
|
|
case 'k':
|
|
|
|
ourKey = myoptarg;
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* File name of server certificate/CA for peer verification. */
|
|
|
|
case 'A':
|
|
|
|
verifyCert = myoptarg;
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Resume sessions. */
|
|
|
|
case 'r':
|
|
|
|
resumeSession = 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Number of connections to make. */
|
|
|
|
case 'n':
|
|
|
|
maxConns = atoi(myoptarg);
|
|
|
|
if (maxConns < 0 || maxConns > 1000000) {
|
|
|
|
Usage();
|
|
|
|
exit(MY_EX_USAGE);
|
|
|
|
}
|
|
|
|
maxBytes = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Number of conncurrent connections to use. */
|
|
|
|
case 'N':
|
|
|
|
numConns = atoi(myoptarg);
|
|
|
|
if (numConns < 0 || numConns > 1000000) {
|
|
|
|
Usage();
|
|
|
|
exit(MY_EX_USAGE);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Number of bytes to read each call. */
|
|
|
|
case 'R':
|
|
|
|
numBytesRead = atoi(myoptarg);
|
|
|
|
if (numBytesRead <= 0) {
|
|
|
|
Usage();
|
|
|
|
exit(MY_EX_USAGE);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Number of bytes to write each call. */
|
|
|
|
case 'W':
|
|
|
|
numBytesWrite = atoi(myoptarg);
|
|
|
|
if (numBytesWrite <= 0) {
|
|
|
|
Usage();
|
|
|
|
exit(MY_EX_USAGE);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Maximum number of read and write bytes (separate counts). */
|
|
|
|
case 'B':
|
|
|
|
maxBytes = atoi(myoptarg);
|
|
|
|
if (maxBytes <= 0) {
|
|
|
|
Usage();
|
|
|
|
exit(MY_EX_USAGE);
|
|
|
|
}
|
|
|
|
maxConns = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Unrecognized command line argument. */
|
|
|
|
default:
|
|
|
|
Usage();
|
|
|
|
exit(MY_EX_USAGE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-26 19:11:32 -06:00
|
|
|
|
|
|
|
#ifdef DEBUG_WOLFSSL
|
|
|
|
wolfSSL_Debugging_ON();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Initialize wolfSSL */
|
|
|
|
wolfSSL_Init();
|
|
|
|
|
2016-11-06 22:17:58 -06:00
|
|
|
/* Initialize wolfSSL and create a context object. */
|
|
|
|
if (WolfSSLCtx_Init(version, ourCert, ourKey, verifyCert, cipherList, &ctx)
|
|
|
|
== EXIT_FAILURE)
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
|
|
|
|
/* Create SSL/TLS connection data object. */
|
|
|
|
sslConnCtx = SSLConn_New(numConns, numBytesRead, numBytesWrite,
|
|
|
|
maxConns, maxBytes, resumeSession);
|
|
|
|
if (sslConnCtx == NULL)
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
|
|
|
|
/* Keep handling connections until all done. */
|
|
|
|
for (i = 0; !SSLConn_Done(sslConnCtx); i = (i + 1) % numConns) {
|
|
|
|
SSLConn* sslConn = &sslConnCtx->sslConn[i];
|
|
|
|
|
|
|
|
/* Perform close if in CLOSE state. */
|
|
|
|
if (sslConn->state == CLOSE) {
|
|
|
|
if (sslConnCtx->numConnections == 0) {
|
|
|
|
WOLFSSL_CIPHER* cipher;
|
|
|
|
cipher = wolfSSL_get_current_cipher(sslConn->ssl);
|
|
|
|
printf("SSL cipher suite is %s\n",
|
|
|
|
wolfSSL_CIPHER_get_name(cipher));
|
|
|
|
}
|
|
|
|
SSLConn_Close(sslConnCtx, sslConn);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create TCP connection and connect if in INIT state. */
|
|
|
|
if ((sslConn->state == INIT) &&
|
|
|
|
((sslConnCtx->maxConnections <= 0) ||
|
|
|
|
(sslConnCtx->numCreated < sslConnCtx->maxConnections))) {
|
|
|
|
if (CreateSocketConnect(port, &socketfd) == EXIT_FAILURE) {
|
|
|
|
printf("ERROR: failed to connect to server\n");
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
SSLConn_Connect(sslConnCtx, ctx, socketfd, sslConn);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef WOLFSSL_ASYNC_CRYPT
|
|
|
|
if (sslConn->err == 4) {
|
|
|
|
int ret;
|
|
|
|
double start;
|
|
|
|
|
|
|
|
start = current_time(1);
|
|
|
|
ret = wolfSSL_AsyncPoll(sslConn->ssl, WOLF_POLL_FLAG_CHECK_HW);
|
|
|
|
sslConnCtx->asyncTime += current_time(0) - start;
|
|
|
|
if (ret < 0) {
|
|
|
|
printf("ERROR: failed in async polling\n");
|
|
|
|
break;
|
|
|
|
}
|
2017-01-30 16:25:51 -06:00
|
|
|
if (ret == 0)
|
2016-11-06 22:17:58 -06:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
sslConn->err = 0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Handle other SSL states. */
|
|
|
|
if (sslConnCtx->totalTime == 0)
|
|
|
|
sslConnCtx->totalTime = current_time(1);
|
|
|
|
if (SSLConn_ReadWrite(sslConnCtx, sslConn) == EXIT_FAILURE) {
|
|
|
|
if (sslConnCtx->maxConnections > 0)
|
|
|
|
sslConn->state = CLOSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sslConnCtx->totalTime = current_time(0) - sslConnCtx->totalTime;
|
|
|
|
|
|
|
|
SSLConn_PrintStats(sslConnCtx);
|
|
|
|
SSLConn_Free(sslConnCtx);
|
|
|
|
|
|
|
|
WolfSSLCtx_Final(ctx);
|
|
|
|
|
2017-01-26 19:11:32 -06:00
|
|
|
wolfSSL_Cleanup();
|
|
|
|
|
2016-11-06 22:17:58 -06:00
|
|
|
exit(EXIT_SUCCESS);
|
|
|
|
}
|
|
|
|
|