diff --git a/examples/benchmark/tls_bench.c b/examples/benchmark/tls_bench.c index dcfb07948..43c272a97 100644 --- a/examples/benchmark/tls_bench.c +++ b/examples/benchmark/tls_bench.c @@ -105,6 +105,16 @@ bench_tls(args); #endif #endif +#ifdef WOLFSSL_DTLS + #ifdef BENCH_EMBEDDED + /* WOLFSSL_MAX_MTU in internal.h */ + #define TEST_DTLS_PACKET_SIZE (1500) + #else + /* MAX_UDP_SIZE in interna.h */ + #define TEST_DTLS_PACKET_SIZE (8092) + #endif +#endif + /* In memory transfer buffer maximum size */ /* Must be large enough to handle max TLS packet size plus max TLS header MAX_MSG_EXTRA */ #define MEM_BUFFER_SZ (TEST_PACKET_SIZE + 38 + WC_MAX_DIGEST_SIZE) @@ -275,6 +285,17 @@ typedef struct { int showVerbose; #ifndef NO_WOLFSSL_SERVER int listenFd; +#endif +#ifdef WOLFSSL_DTLS + int doDTLS; + struct sockaddr_in serverAddr; + struct sockaddr_in clientAddr; +#ifdef HAVE_PTHREAD + int serverReady; + int clientOrserverOnly; + pthread_mutex_t dtls_mutex; + pthread_cond_t dtls_cond; +#endif #endif side_t client; side_t server; @@ -300,6 +321,9 @@ typedef struct { int myoptind = 0; char* myoptarg = NULL; +#ifdef WOLFSSL_DTLS +int DoneHandShake = 0; +#endif static double gettime_secs(int reset) { @@ -495,6 +519,99 @@ static int SocketSend(int sockFd, char* buf, int sz) } return sent; } +#ifdef WOLFSSL_DTLS +static int ReceiveFrom(WOLFSSL *ssl, int sd, char *buf, int sz) +{ + int recvd; + int dtls_timeout = wolfSSL_dtls_get_current_timeout(ssl); + struct sockaddr peer; + socklen_t peerSz; + + if (DoneHandShake) dtls_timeout = 0; + + if (!wolfSSL_get_using_nonblock(ssl)) { + struct timeval timeout; + XMEMSET(&timeout, 0, sizeof(timeout)); + timeout.tv_sec = dtls_timeout; + + if (setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, + sizeof(timeout)) != 0) { + printf("setsockopt rcvtimeo failed\n"); + } + } + + recvd = (int)recvfrom(sd, buf, sz, 0, (SOCKADDR*)&peer, &peerSz); + + if (recvd < 0) { + + if (errno == SOCKET_EWOULDBLOCK || errno == SOCKET_EAGAIN) { + if (wolfSSL_dtls_get_using_nonblock(ssl)) { + return WOLFSSL_CBIO_ERR_WANT_READ; + } + else { + return WOLFSSL_CBIO_ERR_TIMEOUT; + } + } + else if (errno == SOCKET_ECONNRESET) { + return WOLFSSL_CBIO_ERR_CONN_RST; + } + else if (errno == SOCKET_EINTR) { + return WOLFSSL_CBIO_ERR_ISR; + } + else if (errno == SOCKET_ECONNREFUSED) { + return WOLFSSL_CBIO_ERR_WANT_READ; + } + else { + return WOLFSSL_CBIO_ERR_GENERAL; + } + } + else { + if (recvd == 0) { + return WOLFSSL_CBIO_ERR_CONN_CLOSE; + } + } + + return recvd; +} + +static int SendTo(int sd, char *buf, int sz, const struct sockaddr *peer, + socklen_t peerSz) +{ + int sent; + int len = sz; + + sent = (int)sendto(sd, &buf[sz - len], len, 0, peer, peerSz); + + if (sent < 0) { + if (errno == SOCKET_EWOULDBLOCK || errno == SOCKET_EAGAIN) { + return WOLFSSL_CBIO_ERR_WANT_WRITE; + } + else if (errno == SOCKET_ECONNRESET) { + return WOLFSSL_CBIO_ERR_CONN_RST; + } + else if (errno == SOCKET_EINTR) { + return WOLFSSL_CBIO_ERR_ISR; + } + else if (errno == SOCKET_EPIPE) { + return WOLFSSL_CBIO_ERR_CONN_CLOSE; + } + else { + return WOLFSSL_CBIO_ERR_GENERAL; + } + } + + return sent; +} + +static int myDoneHsCb(WOLFSSL* ssl, void* user_ctx) +{ + (void) ssl; + (void) user_ctx; + + DoneHandShake = 1; + return 1; +} +#endif #ifndef NO_WOLFSSL_SERVER static int ServerSend(WOLFSSL* ssl, char* buf, int sz, void* ctx) @@ -505,7 +622,13 @@ static int ServerSend(WOLFSSL* ssl, char* buf, int sz, void* ctx) if (info->useLocalMem) return ServerMemSend(info, buf, sz); #endif - return SocketSend(info->server.sockFd, buf, sz); +#ifdef WOLFSSL_DTLS + if (info->doDTLS) { + return SendTo(info->server.sockFd, buf, sz, + (const struct sockaddr*)&info->clientAddr, sizeof(info->clientAddr)); + } else +#endif + return SocketSend(info->server.sockFd, buf, sz); } static int ServerRecv(WOLFSSL* ssl, char* buf, int sz, void* ctx) { @@ -515,7 +638,12 @@ static int ServerRecv(WOLFSSL* ssl, char* buf, int sz, void* ctx) if (info->useLocalMem) return ServerMemRecv(info, buf, sz); #endif - return SocketRecv(info->server.sockFd, buf, sz); +#ifdef WOLFSSL_DTLS + if (info->doDTLS) { + return ReceiveFrom(ssl, info->server.sockFd, buf, sz); + } else +#endif + return SocketRecv(info->server.sockFd, buf, sz); } #endif /* !NO_WOLFSSL_SERVER */ @@ -528,7 +656,13 @@ static int ClientSend(WOLFSSL* ssl, char* buf, int sz, void* ctx) if (info->useLocalMem) return ClientMemSend(info, buf, sz); #endif - return SocketSend(info->client.sockFd, buf, sz); +#ifdef WOLFSSL_DTLS + if (info->doDTLS) { + return SendTo(info->client.sockFd, buf, sz, + (const struct sockaddr*)&info->serverAddr, sizeof(info->serverAddr)); + } else +#endif + return SocketSend(info->client.sockFd, buf, sz); } static int ClientRecv(WOLFSSL* ssl, char* buf, int sz, void* ctx) { @@ -538,7 +672,12 @@ static int ClientRecv(WOLFSSL* ssl, char* buf, int sz, void* ctx) if (info->useLocalMem) return ClientMemRecv(info, buf, sz); #endif - return SocketRecv(info->client.sockFd, buf, sz); +#ifdef WOLFSSL_DTLS + if (info->doDTLS) { + return ReceiveFrom(ssl, info->client.sockFd, buf, sz); + } else +#endif + return SocketRecv(info->client.sockFd, buf, sz); } #endif /* !NO_WOLFSSL_CLIENT */ @@ -548,6 +687,9 @@ static void CloseAndCleanupSocket(int* sockFd) close(*sockFd); *sockFd = -1; } +#ifdef WOLFSSL_DTLS + DoneHandShake = 0; +#endif } #ifdef BENCH_USE_NONBLOCK @@ -589,6 +731,17 @@ static int SetupSocketAndConnect(info_t* info, const char* host, servAddr.sin_addr.s_addr = inet_addr(host); } +#ifdef WOLFSSL_DTLS + if (info->doDTLS) { + /* Create the SOCK_DGRAM socket type is implemented on the User + * Datagram Protocol/Internet Protocol(UDP/IP protocol).*/ + if ((info->client.sockFd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + printf("ERROR: failed to create the SOCK_DGRAM socket\n"); + return -1; + } + XMEMCPY(&info->serverAddr, &servAddr, sizeof(servAddr)); + } else { +#endif /* Create a socket that uses an Internet IPv4 address, * Sets the socket to be stream based (TCP), * 0 means choose the default protocol. */ @@ -603,6 +756,9 @@ static int SetupSocketAndConnect(info_t* info, const char* host, printf("ERROR: failed to connect\n"); return -1; } +#ifdef WOLFSSL_DTLS + } +#endif #ifdef BENCH_USE_NONBLOCK if (SetSocketNonBlocking(info->client.sockFd) != 0) { @@ -631,11 +787,20 @@ static int bench_tls_client(info_t* info) total = gettime_secs(0); /* set up client */ +#ifdef WOLFSSL_DTLS + if(info->doDTLS) { + if (tls13) return WOLFSSL_SUCCESS; + cli_ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method()); + } else +#endif #ifdef WOLFSSL_TLS13 if (tls13) cli_ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()); #endif if (!tls13) +#ifdef WOLFSSL_DTLS + if(!info->doDTLS) +#endif #if !defined(WOLFSSL_TLS13) cli_ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()); #elif !defined(WOLFSSL_NO_TLS12) @@ -721,9 +886,36 @@ static int bench_tls_client(info_t* info) goto exit; } +#ifdef WOLFSSL_DTLS + if (info->doDTLS) { + ret = wolfSSL_dtls_set_peer(cli_ssl, &info->serverAddr, + sizeof(info->serverAddr)); + if (ret != WOLFSSL_SUCCESS) { + printf("error setting dtls peer\n"); + goto exit; + } + ret = wolfSSL_SetHsDoneCb(cli_ssl, myDoneHsCb, NULL); + if (ret != WOLFSSL_SUCCESS) { + printf("error handshake done callback\n"); + goto exit; + } + } +#endif wolfSSL_SetIOReadCtx(cli_ssl, info); wolfSSL_SetIOWriteCtx(cli_ssl, info); +#if defined(HAVE_PTHREAD) && defined(WOLFSSL_DTLS) + /* synchronize with server */ + if (info->doDTLS && !info->clientOrserverOnly) { + pthread_mutex_lock(&info->dtls_mutex); + if (info->serverReady != 1) { + pthread_cond_wait(&info->dtls_cond, &info->dtls_mutex); + } + /* for next loop */ + info->serverReady = 0; + pthread_mutex_unlock(&info->dtls_mutex); + } +#endif /* perform connect */ start = gettime_secs(1); #ifndef BENCH_USE_NONBLOCK @@ -870,7 +1062,7 @@ static void* client_thread(void* args) #ifndef NO_WOLFSSL_SERVER -static int SetupSocketAndListen(int* listenFd, word32 port) +static int SetupSocketAndListen(int* listenFd, word32 port, int doDTLS) { struct sockaddr_in servAddr; #if defined(_MSC_VER) || defined(__MINGW32__) @@ -878,13 +1070,25 @@ static int SetupSocketAndListen(int* listenFd, word32 port) #else int optval = 1; #endif - +#ifndef WOLFSSL_DTLS + (void) doDTLS; +#endif /* Setup server address */ XMEMSET(&servAddr, 0, sizeof(servAddr)); servAddr.sin_family = AF_INET; servAddr.sin_port = htons(port); servAddr.sin_addr.s_addr = INADDR_ANY; +#ifdef WOLFSSL_DTLS + if (doDTLS) { + /* Create a socket that is implemented on the User Datagram Protocol/ + * Interet Protocol(UDP/IP protocol). */ + if((*listenFd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { + printf("ERROR: failed to create the socket\n"); + return -1; + } + } else +#endif /* Create a socket that uses an Internet IPv4 address, * Sets the socket to be stream based (TCP), * 0 means choose the default protocol. */ @@ -906,7 +1110,9 @@ static int SetupSocketAndListen(int* listenFd, word32 port) printf("ERROR: failed to bind\n"); return -1; } - +#ifdef WOLFSSL_DTLS + if (!doDTLS) +#endif if (listen(*listenFd, 5) != 0) { printf("ERROR: failed to listen\n"); return -1; @@ -926,7 +1132,28 @@ static int SocketWaitClient(info_t* info) int connd; struct sockaddr_in clientAddr; socklen_t size = sizeof(clientAddr); +#ifdef WOLFSSL_DTLS + char msg[64]; + if (info->doDTLS) { +#ifdef HAVE_PTHREAD + if (!info->clientOrserverOnly) { + pthread_mutex_lock(&info->dtls_mutex); + info->serverReady = 1; + pthread_cond_signal(&info->dtls_cond); + pthread_mutex_unlock(&info->dtls_mutex); + } +#endif + connd = (int)recvfrom(info->listenFd, (char *)msg, sizeof(msg), + MSG_PEEK, (struct sockaddr*)&clientAddr, &size); + if (connd < -1) { + printf("ERROR: failed to accept the connection\n"); + return -1; + } + XMEMCPY(&info->clientAddr, &clientAddr, sizeof(clientAddr)); + info->server.sockFd = info->listenFd; + } else { +#endif if ((connd = accept(info->listenFd, (struct sockaddr*)&clientAddr, &size)) == -1) { if (errno == SOCKET_EWOULDBLOCK) return -2; @@ -934,6 +1161,9 @@ static int SocketWaitClient(info_t* info) return -1; } info->server.sockFd = connd; +#ifdef WOLFSSL_DTLS + } +#endif if (info->showVerbose) { printf("Got client %d\n", connd); @@ -960,12 +1190,21 @@ static int bench_tls_server(info_t* info) int total_sz; /* set up server */ +#ifdef WOLFSSL_DTLS + if(info->doDTLS) { + if(tls13) return WOLFSSL_SUCCESS; + srv_ctx = wolfSSL_CTX_new(wolfDTLSv1_2_server_method()); + } else { +#endif #ifdef WOLFSSL_TLS13 if (tls13) srv_ctx = wolfSSL_CTX_new(wolfTLSv1_3_server_method()); #endif if (!tls13) srv_ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()); +#ifdef WOLFSSL_DTLS + } +#endif if (srv_ctx == NULL) { printf("error creating server ctx\n"); ret = MEMORY_E; goto exit; @@ -1059,10 +1298,19 @@ static int bench_tls_server(info_t* info) printf("error creating server object\n"); ret = MEMORY_E; goto exit; } +#ifdef WOLFSSL_DTLS + if (info->doDTLS) { + ret = wolfSSL_dtls_set_peer(srv_ssl, &info->clientAddr, + sizeof(info->clientAddr)); + if (ret != WOLFSSL_SUCCESS) { + printf("error setting dtls peer\n"); + goto exit; + } + } +#endif wolfSSL_SetIOReadCtx(srv_ssl, info); wolfSSL_SetIOWriteCtx(srv_ssl, info); - #ifndef NO_DH wolfSSL_SetTmpDH(srv_ssl, p, sizeof(p), g, sizeof(g)); #endif @@ -1153,6 +1401,12 @@ static int bench_tls_server(info_t* info) wolfSSL_free(srv_ssl); srv_ssl = NULL; +#ifdef WOLFSSL_DTLS + if (info->doDTLS) { + SetupSocketAndListen(&info->listenFd, info->port, info->doDTLS); + } +#endif + } exit: @@ -1182,7 +1436,11 @@ static void* server_thread(void* args) if (!info->useLocalMem) { /* Setup TLS server listener */ - ret = SetupSocketAndListen(&info->listenFd, info->port); +#ifdef WOLFSSL_DTLS + ret = SetupSocketAndListen(&info->listenFd, info->port, info->doDTLS); +#else + ret = SetupSocketAndListen(&info->listenFd, info->port, 0); +#endif } if (ret == 0) { ret = bench_tls_server(info); @@ -1252,6 +1510,9 @@ static void Usage(void) printf("-l Cipher suite list (: delimited)\n"); printf("-t Time (seconds) to run each test (default %d)\n", BENCH_RUNTIME_SEC); printf("-p The packet size in bytes [1-16kB] (default %d)\n", TEST_PACKET_SIZE); +#ifdef WOLFSSL_DTLS + printf(" In the case of DTLS, [1-8kB] (default %d)\n", TEST_DTLS_PACKET_SIZE); +#endif printf("-S The total size in bytes (default %d)\n", TEST_MAX_SIZE); printf("-v Show verbose output\n"); #ifdef DEBUG_WOLFSSL @@ -1261,6 +1522,9 @@ static void Usage(void) printf("-T Number of threaded server/client pairs (default %d)\n", NUM_THREAD_PAIRS); printf("-m Use local memory, not socket\n"); #endif +#ifdef WOLFSSL_DTLS + printf("-u Use DTLS\n"); +#endif } static void ShowCiphers(void) @@ -1307,7 +1571,10 @@ int bench_tls(void* args) int argLocalMem = 0; int listenFd = -1; #endif - +#ifdef WOLFSSL_DTLS + int doDTLS = 0; + int option_p = 0; +#endif if (args != NULL) { argc = ((func_args*)args)->argc; argv = ((func_args*)args)->argv; @@ -1318,7 +1585,7 @@ int bench_tls(void* args) wolfSSL_Init(); /* Parse command line arguments */ - while ((ch = mygetopt(argc, argv, "?" "deil:p:t:vT:sch:P:mS:")) != -1) { + while ((ch = mygetopt(argc, argv, "?" "udeil:p:t:vT:sch:P:mS:")) != -1) { switch (ch) { case '?' : Usage(); @@ -1365,6 +1632,9 @@ int bench_tls(void* args) Usage(); ret = MY_EX_USAGE; goto exit; } + #ifdef WOLFSSL_DTLS + option_p = 1; + #endif break; case 'S' : @@ -1390,7 +1660,17 @@ int bench_tls(void* args) argLocalMem = 1; #endif break; - + case 'u': + #ifdef WOLFSSL_DTLS + doDTLS = 1; + #ifdef BENCH_USE_NONBLOCK + printf("tls_bench hasn't yet supported DTLS " + "non-blocking mode.\n"); + Usage(); + ret = MY_EX_USAGE; goto exit; + #endif + #endif + break; default: Usage(); ret = MY_EX_USAGE; goto exit; @@ -1438,11 +1718,32 @@ int bench_tls(void* args) /* Use same listen socket to avoid timing issues between client and server */ if (argServerOnly && !argLocalMem) { /* Setup TLS server listener */ - ret = SetupSocketAndListen(&listenFd, argPort); +#ifdef WOLFSSL_DTLS + ret = SetupSocketAndListen(&listenFd, argPort, doDTLS); +#else + ret = SetupSocketAndListen(&listenFd, argPort, 0); +#endif if (ret != 0) goto exit; } #endif +#ifdef WOLFSSL_DTLS + if (doDTLS) { + if (argLocalMem) { + printf("tls_bench hasn't yet supported DTLS with local memory.\n"); + ret = MY_EX_USAGE; goto exit; + } + if (option_p && argTestPacketSize > TEST_DTLS_PACKET_SIZE){ + printf("Invalid packet size %d\n", argTestPacketSize); + Usage(); + ret = MY_EX_USAGE; goto exit; + } else { + /* argTestPacketSize would be default for tcp packet */ + if (argTestPacketSize >= TEST_PACKET_SIZE) + argTestPacketSize = TEST_DTLS_PACKET_SIZE; + } + } +#endif printf("Running TLS Benchmarks...\n"); /* parse by : */ @@ -1464,6 +1765,7 @@ int bench_tls(void* args) info->port = argPort + i; /* threads must have separate ports */ info->cipher = cipher; info->packetSize = argTestPacketSize; + info->runTimeSec = argRuntimeSec; info->maxSize = argTestMaxSize; info->showPeerInfo = argShowPeerInfo; @@ -1474,6 +1776,15 @@ int bench_tls(void* args) info->client.sockFd = -1; info->server.sockFd = -1; + #ifdef WOLFSSL_DTLS + info->doDTLS = doDTLS; + #ifdef HAVE_PTHREAD + info->serverReady = 0; + if (argServerOnly || argClientOnly) { + info->clientOrserverOnly = 1; + } + #endif + #endif if (argClientOnly) { #ifndef NO_WOLFSSL_CLIENT ret = bench_tls_client(info); @@ -1489,6 +1800,10 @@ int bench_tls(void* args) info->useLocalMem = argLocalMem; pthread_mutex_init(&info->to_server.mutex, NULL); pthread_mutex_init(&info->to_client.mutex, NULL); + #ifdef WOLFSSL_DTLS + pthread_mutex_init(&info->dtls_mutex, NULL); + pthread_cond_init(&info->dtls_cond, NULL); + #endif pthread_cond_init(&info->to_server.cond, NULL); pthread_cond_init(&info->to_client.cond, NULL); diff --git a/wolfssl/test.h b/wolfssl/test.h index e521c3a11..2f133f985 100644 --- a/wolfssl/test.h +++ b/wolfssl/test.h @@ -498,6 +498,13 @@ static WC_INLINE int mygetopt(int argc, char** argv, const char* optstring) char c; char* cp; + /* Added sanity check becuase scan-build complains argv[myoptind] access + * results in a null pointer dereference. */ + if (argv == NULL) { + myoptarg = NULL; + return -1; + } + if (myoptind == 0) next = NULL; /* we're starting new/over */