added nonblocking support for SSL

origin
steffen 6 years ago
parent eb8b60d2cf
commit 9888a7411a

@ -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: 2019-03-04:
- added: TCP connections have set up a timeout of 2 seconds. - 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 - fixed: TCP connect set up the sock struct too fast so threaded applications had some

@ -113,18 +113,26 @@ private:
int writecnt; int writecnt;
string certfile; string certfile;
string keyfile; string keyfile;
int timeout;
SSL *ssl; SSL *ssl;
SSL_CTX *ctx; SSL_CTX *ctx;
struct timeval timeout_start;
int NewServerCTX(); int NewServerCTX();
int NewClientCTX(); int NewClientCTX();
const string GetSSLErrorText(int err); void TimeoutReset();
int TimeoutTime();
public: public:
int sslerror;
SSLSocket(); SSLSocket();
~SSLSocket(); ~SSLSocket();
const string GetSSLErrorText(int err);
int SetCertificat(string certf, string keyf); int SetCertificat(string certf, string keyf);
int Connect(int sockfd); int Connect(int sockfd, int block_timeout);
int Accept(int sockfd); int Accept(int sockfd, int block_timeout);
long int Read(char *buffer, long int len); long int Read(char *buffer, long int len);
long int Write(char *buffer, long int len); long int Write(char *buffer, long int len);
int Close(); // returns socket int Close(); // returns socket

@ -6,10 +6,12 @@
#include <unistd.h> /* close() */ #include <unistd.h> /* close() */
#include <stdlib.h> #include <stdlib.h>
#include <string.h> /* memset() */ #include <string.h> /* memset() */
#include <sys/stat.h>
#include <errno.h> #include <errno.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include <openssl/err.h> #include <openssl/err.h>
@ -22,6 +24,8 @@ SSLSocket::SSLSocket() {
writecnt = 0; writecnt = 0;
certfile = ""; certfile = "";
keyfile = ""; keyfile = "";
sslerror = SSL_ERROR_NONE;
timeout = 0;
ctx = NULL; ctx = NULL;
ssl = NULL; ssl = NULL;
if (ssl_init == 0) { 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(); 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 = SSL_new(ctx);
SSL_set_fd (ssl, sockfd); 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; return 1;
}; };
int SSLSocket::Accept (int sockfd) { int SSLSocket::Accept (int sockfd, int block_timeout) {
int err; int flags, res;
TimeoutReset();
sslerror = SSL_ERROR_NONE;
timeout = block_timeout;
NewServerCTX(); 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 = SSL_new(ctx);
SSL_set_fd (ssl, sockfd); SSL_set_fd (ssl, sockfd);
if (SSL_accept(ssl) == -1 ) { do {
err = SSL_get_error(ssl, -1); res = SSL_accept(ssl);
printf ("%s %s:%d error: %s\n", __FUNCTION__, __FILE__, __LINE__, GetSSLErrorText(err).c_str()); if (res == -1) sslerror = SSL_get_error(ssl, -1);
return 0; } while (res == -1 && TimeoutTime() < timeout &&
} (sslerror == SSL_ERROR_WANT_READ || sslerror == SSL_ERROR_WANT_WRITE));
return 1; return 1;
}; };
@ -175,6 +200,7 @@ const string SSLSocket::GetSSLErrorText(int err) {
// close ssl and return socket. // close ssl and return socket.
int SSLSocket::Close () { int SSLSocket::Close () {
int sock = 0; int sock = 0;
int flags;
if (ssl) { if (ssl) {
sock = SSL_get_fd(ssl); sock = SSL_get_fd(ssl);
@ -187,37 +213,74 @@ int SSLSocket::Close () {
ctx = NULL; ctx = NULL;
} }
if (sock > 0 && timeout > 0) {
flags = fcntl(sock, F_GETFL, 0);
fcntl(sock, F_SETFL, flags & ~(O_NONBLOCK));
}
return sock; return sock;
}; };
// //
// need to add timeout currently data is blocking //
long int SSLSocket::Read (char *buffer, long int len) { long int SSLSocket::Read (char *buffer, long int len) {
int ret; int ret;
sslerror = SSL_ERROR_NONE;
TimeoutReset();
if (!ssl) { if (!ssl) {
errno = EPROTO; errno = EPROTO;
return -1; 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; return ret;
}; };
// //
// need to add timeout currently data is blocking //
long int SSLSocket::Write (char *buffer, long int len) { long int SSLSocket::Write (char *buffer, long int len) {
int ret; int ret;
sslerror = SSL_ERROR_NONE;
TimeoutReset();
if (!ssl) { if (!ssl) {
errno = EPROTO; errno = EPROTO;
return -1; 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; 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);
};

@ -13,6 +13,8 @@ void server () {
SSLSocket ssl; SSLSocket ssl;
int i, timeout; int i, timeout;
pid_t pid; pid_t pid;
time_t time_start = time (NULL);
time_t time_now = time (NULL);
char buffer[NET_BUFFERSIZE]; char buffer[NET_BUFFERSIZE];
// //
@ -31,7 +33,7 @@ void server () {
// //
// check for connections // check for connections
for (timeout = 10; timeout > 0; timeout--) { for (;time_now - time_start < 10; time_now = time(NULL)) {
connection = tcpserver.Accept(); connection = tcpserver.Accept();
if (connection != NULL) { if (connection != NULL) {
// //
@ -47,7 +49,7 @@ void server () {
// returns. // returns.
tcpserver.Close(); 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)); printf ("could not establish SSL connection:%s\n", strerror(errno));
exit (1); exit (1);
} }
@ -75,7 +77,7 @@ void server () {
delete (connection); delete (connection);
} }
} }
sleep (1); usleep (25000);
} }
}; };
@ -83,9 +85,8 @@ void server () {
void client () { void client () {
TCP tcpclient; TCP tcpclient;
SSLSocket ssl; SSLSocket ssl;
char buffer[NET_BUFFERSIZE]; char buffer[NET_BUFFERSIZE];
int i; int i, res;
sleep (1); // wait one second to start the server sleep (1); // wait one second to start the server
@ -96,8 +97,9 @@ void client () {
exit (1); exit (1);
} }
if (ssl.Connect(tcpclient.GetSocket()) != 1) { res = ssl.Connect(tcpclient.GetSocket(), 100);
printf ("could not establish SSL connection:%s\n", strerror(errno)); if (res == -1) {
printf ("could not establish SSL connection:errno:%s sslerror:%s\n", strerror(errno), ssl.GetSSLErrorText(ssl.sslerror).c_str());
exit (1); exit (1);
} }
@ -105,8 +107,9 @@ void client () {
// send some data // send some data
snprintf (buffer, NET_BUFFERSIZE, "nur ein kleiner Test."); snprintf (buffer, NET_BUFFERSIZE, "nur ein kleiner Test.");
printf ("client:send '%s' to the server.\n", buffer); printf ("client:send '%s' to the server.\n", buffer);
if (ssl.Write(buffer, strlen (buffer)) != strlen (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); exit (1);
} }

@ -12,6 +12,8 @@ void server () {
TCP *connection; TCP *connection;
int i, timeout; int i, timeout;
pid_t pid; pid_t pid;
time_t time_start = time (NULL);
time_t time_now = time (NULL);
char buffer[NET_BUFFERSIZE]; char buffer[NET_BUFFERSIZE];
// //
@ -23,7 +25,7 @@ void server () {
// //
// check for connections // check for connections
for (timeout = 5; timeout > 0; timeout--) { for (;time_now - time_start < 10; time_now = time(NULL)) {
connection = tcpserver.Accept(); connection = tcpserver.Accept();
if (connection != NULL) { if (connection != NULL) {
// //
@ -38,7 +40,7 @@ void server () {
// by the parent process. Make sure the client exits and never // by the parent process. Make sure the client exits and never
// returns. // returns.
tcpserver.Close(); tcpserver.Close();
i = connection->ReadTimeout(buffer, NET_BUFFERSIZE, 1000); i = connection->Read(buffer, NET_BUFFERSIZE);
if (i > 0) { if (i > 0) {
int c; int c;
@ -61,7 +63,7 @@ void server () {
delete (connection); delete (connection);
} }
} }
sleep (1); usleep (25000);
} }
}; };
@ -80,6 +82,8 @@ void client () {
exit (1); exit (1);
} }
sleep (1);
// //
// send some data // send some data
snprintf (buffer, NET_BUFFERSIZE, "nur ein kleiner Test."); snprintf (buffer, NET_BUFFERSIZE, "nur ein kleiner Test.");

Loading…
Cancel
Save