From 9888a7411a2407393a3d2b412608105a56510464 Mon Sep 17 00:00:00 2001 From: steffen Date: Sun, 5 May 2019 21:36:25 +0000 Subject: [PATCH] added nonblocking support for SSL --- Changelog | 4 ++ UDPTCPNetwork.h | 14 +++++-- ssl.cc | 99 ++++++++++++++++++++++++++++++++++++++++--------- test-ssl.cc | 19 ++++++---- test-tcp.cc | 10 +++-- 5 files changed, 114 insertions(+), 32 deletions(-) diff --git a/Changelog b/Changelog index 319d98e..b06c5a4 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,7 @@ +2019-05-05: +- added SSLSocket support. SSL.Connect (TCP.GetSocket()) + it supports as well as non blocking connections with a defined timeout. + 2019-03-04: - added: TCP connections have set up a timeout of 2 seconds. - fixed: TCP connect set up the sock struct too fast so threaded applications had some diff --git a/UDPTCPNetwork.h b/UDPTCPNetwork.h index 19d3061..7daa136 100644 --- a/UDPTCPNetwork.h +++ b/UDPTCPNetwork.h @@ -113,18 +113,26 @@ private: int writecnt; string certfile; string keyfile; + int timeout; SSL *ssl; SSL_CTX *ctx; + struct timeval timeout_start; + int NewServerCTX(); int NewClientCTX(); - const string GetSSLErrorText(int err); + void TimeoutReset(); + int TimeoutTime(); + public: + int sslerror; + SSLSocket(); ~SSLSocket(); + const string GetSSLErrorText(int err); int SetCertificat(string certf, string keyf); - int Connect(int sockfd); - int Accept(int sockfd); + int Connect(int sockfd, int block_timeout); + int Accept(int sockfd, int block_timeout); long int Read(char *buffer, long int len); long int Write(char *buffer, long int len); int Close(); // returns socket diff --git a/ssl.cc b/ssl.cc index 047715a..0d39e9d 100644 --- a/ssl.cc +++ b/ssl.cc @@ -6,10 +6,12 @@ #include /* close() */ #include #include /* memset() */ -#include #include #include #include +#include +#include +#include #include #include @@ -22,6 +24,8 @@ SSLSocket::SSLSocket() { writecnt = 0; certfile = ""; keyfile = ""; + sslerror = SSL_ERROR_NONE; + timeout = 0; ctx = NULL; ssl = NULL; if (ssl_init == 0) { @@ -95,33 +99,54 @@ int SSLSocket::SetCertificat(string certf, string keyf) { }; -int SSLSocket::Connect (int sockfd) { +int SSLSocket::Connect (int sockfd, int block_timeout) { + int flags, res; + + TimeoutReset(); + sslerror = SSL_ERROR_NONE; NewClientCTX(); + timeout = block_timeout; + + if (sockfd > 0 && block_timeout > 0) { + flags = fcntl(sockfd, F_GETFL, 0); + fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); + } ssl = SSL_new(ctx); SSL_set_fd (ssl, sockfd); - if (SSL_connect(ssl) == -1 ) { - printf ("ssl connect: error\n"); - ERR_print_errors_fp(stderr); - exit (1); - } + do { + res = SSL_connect(ssl); + if (res == -1) sslerror = SSL_get_error(ssl, -1); + } while (res == -1 && TimeoutTime() < timeout && + (sslerror == SSL_ERROR_WANT_READ || sslerror == SSL_ERROR_WANT_WRITE)); + + if (res == -1) return 0; return 1; }; -int SSLSocket::Accept (int sockfd) { - int err; +int SSLSocket::Accept (int sockfd, int block_timeout) { + int flags, res; + + TimeoutReset(); + sslerror = SSL_ERROR_NONE; + timeout = block_timeout; NewServerCTX(); + if (sockfd > 0 && block_timeout > 0) { + flags = fcntl(sockfd, F_GETFL, 0); + fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); + } + ssl = SSL_new(ctx); SSL_set_fd (ssl, sockfd); - if (SSL_accept(ssl) == -1 ) { - err = SSL_get_error(ssl, -1); - printf ("%s %s:%d error: %s\n", __FUNCTION__, __FILE__, __LINE__, GetSSLErrorText(err).c_str()); - return 0; - } + do { + res = SSL_accept(ssl); + if (res == -1) sslerror = SSL_get_error(ssl, -1); + } while (res == -1 && TimeoutTime() < timeout && + (sslerror == SSL_ERROR_WANT_READ || sslerror == SSL_ERROR_WANT_WRITE)); return 1; }; @@ -175,6 +200,7 @@ const string SSLSocket::GetSSLErrorText(int err) { // close ssl and return socket. int SSLSocket::Close () { int sock = 0; + int flags; if (ssl) { sock = SSL_get_fd(ssl); @@ -187,37 +213,74 @@ int SSLSocket::Close () { ctx = NULL; } + if (sock > 0 && timeout > 0) { + flags = fcntl(sock, F_GETFL, 0); + fcntl(sock, F_SETFL, flags & ~(O_NONBLOCK)); + } + return sock; }; // -// need to add timeout currently data is blocking +// long int SSLSocket::Read (char *buffer, long int len) { int ret; + sslerror = SSL_ERROR_NONE; + + TimeoutReset(); if (!ssl) { errno = EPROTO; return -1; } - ret = SSL_read(ssl, buffer, len); + do { + ret = SSL_read(ssl, buffer, len); + if (ret == -1) sslerror = SSL_get_error(ssl, -1); + } while (ret == -1 && TimeoutTime() < timeout && + (sslerror == SSL_ERROR_WANT_READ || sslerror == SSL_ERROR_WANT_WRITE)); return ret; }; // -// need to add timeout currently data is blocking +// long int SSLSocket::Write (char *buffer, long int len) { int ret; + sslerror = SSL_ERROR_NONE; + TimeoutReset(); if (!ssl) { errno = EPROTO; return -1; } - ret = SSL_write(ssl, buffer, len); + do { + ret = SSL_write(ssl, buffer, len); + if (ret == -1) sslerror = SSL_get_error(ssl, -1); + } while (ret == -1 && TimeoutTime() < timeout && + (sslerror == SSL_ERROR_WANT_READ || sslerror == SSL_ERROR_WANT_WRITE)); return ret; }; + + +// +// Reset Timeout Timer +void SSLSocket::TimeoutReset() { + gettimeofday (&timeout_start, NULL); +}; + + +// +// Return time which has past since reset in ms. +int SSLSocket::TimeoutTime() { + struct timeval tv; + gettimeofday (&tv, NULL); + + return ((tv.tv_sec-timeout_start.tv_sec) * 1000) + + ((tv.tv_usec-timeout_start.tv_usec) / 1000); +}; + diff --git a/test-ssl.cc b/test-ssl.cc index a36f54b..182614b 100644 --- a/test-ssl.cc +++ b/test-ssl.cc @@ -13,6 +13,8 @@ void server () { SSLSocket ssl; int i, timeout; pid_t pid; + time_t time_start = time (NULL); + time_t time_now = time (NULL); char buffer[NET_BUFFERSIZE]; // @@ -31,7 +33,7 @@ void server () { // // check for connections - for (timeout = 10; timeout > 0; timeout--) { + for (;time_now - time_start < 10; time_now = time(NULL)) { connection = tcpserver.Accept(); if (connection != NULL) { // @@ -47,7 +49,7 @@ void server () { // returns. tcpserver.Close(); - if (ssl.Accept(connection->GetSocket()) != 1) { + if (ssl.Accept(connection->GetSocket(), 0) != 1) { printf ("could not establish SSL connection:%s\n", strerror(errno)); exit (1); } @@ -75,7 +77,7 @@ void server () { delete (connection); } } - sleep (1); + usleep (25000); } }; @@ -83,9 +85,8 @@ void server () { void client () { TCP tcpclient; SSLSocket ssl; - char buffer[NET_BUFFERSIZE]; - int i; + int i, res; sleep (1); // wait one second to start the server @@ -96,8 +97,9 @@ void client () { exit (1); } - if (ssl.Connect(tcpclient.GetSocket()) != 1) { - printf ("could not establish SSL connection:%s\n", strerror(errno)); + res = ssl.Connect(tcpclient.GetSocket(), 100); + if (res == -1) { + printf ("could not establish SSL connection:errno:%s sslerror:%s\n", strerror(errno), ssl.GetSSLErrorText(ssl.sslerror).c_str()); exit (1); } @@ -105,8 +107,9 @@ void client () { // send some data snprintf (buffer, NET_BUFFERSIZE, "nur ein kleiner Test."); printf ("client:send '%s' to the server.\n", buffer); + if (ssl.Write(buffer, strlen (buffer)) != strlen (buffer)) { - printf ("could not send all data.\n"); + printf ("could not send all data. errno:%s sslerror:%s\n", strerror(errno), ssl.GetSSLErrorText(ssl.sslerror).c_str()); exit (1); } diff --git a/test-tcp.cc b/test-tcp.cc index cf30f82..f9ab309 100644 --- a/test-tcp.cc +++ b/test-tcp.cc @@ -12,6 +12,8 @@ void server () { TCP *connection; int i, timeout; pid_t pid; + time_t time_start = time (NULL); + time_t time_now = time (NULL); char buffer[NET_BUFFERSIZE]; // @@ -23,7 +25,7 @@ void server () { // // check for connections - for (timeout = 5; timeout > 0; timeout--) { + for (;time_now - time_start < 10; time_now = time(NULL)) { connection = tcpserver.Accept(); if (connection != NULL) { // @@ -38,7 +40,7 @@ void server () { // by the parent process. Make sure the client exits and never // returns. tcpserver.Close(); - i = connection->ReadTimeout(buffer, NET_BUFFERSIZE, 1000); + i = connection->Read(buffer, NET_BUFFERSIZE); if (i > 0) { int c; @@ -61,7 +63,7 @@ void server () { delete (connection); } } - sleep (1); + usleep (25000); } }; @@ -80,6 +82,8 @@ void client () { exit (1); } + sleep (1); + // // send some data snprintf (buffer, NET_BUFFERSIZE, "nur ein kleiner Test.");