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:
- 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

@ -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

@ -6,10 +6,12 @@
#include <unistd.h> /* close() */
#include <stdlib.h>
#include <string.h> /* memset() */
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
@ -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);
};

@ -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);
}

@ -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.");

Loading…
Cancel
Save