I think code below might help others to solve the issue. It is not fully tested take it as inspiration.
//Nonblocking SSL accept based on ACE/ace/SSL/SSL_SOCK_Acceptor.cpp
SSL_CTX* ctx;
ctx = initServerCTX(); // initialize SSL
loadCertificates(ctx, certificate, privateKey); // load certs
...
SSL* ssl = SSL_new(ctx); /* get new SSL state with context */
SSL_set_fd(ssl, fd); /* set connection socket to SSL state */
int flags = fcntl(fd, F_GETFL, 0);
if (flags < 0)
{
printf("fcntl: F_GETFL
");
return false;
}
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)
{
printf("fcntl: F_SETFL
");
return false;
}
int status = -1;
struct timeval tv, tvRestore;
tv.tv_sec = 2;
tv.tv_usec = 0;
tvRestore = tv;
fd_set writeFdSet;
fd_set readFdSet;
do
{
tv = tvRestore;
FD_ZERO(&writeFdSet);
FD_ZERO(&readFdSet);
status = ::SSL_accept(ssl);
switch (::SSL_get_error(ssl, status))
{
case SSL_ERROR_NONE:
status = 0; // To tell caller about success
break; // Done
case SSL_ERROR_WANT_WRITE:
FD_SET(fd, &writeFdSet);
status = 1; // Wait for more activity
break;
case SSL_ERROR_WANT_READ:
FD_SET(fd, &readFdSet);
status = 1; // Wait for more activity
break;
case SSL_ERROR_ZERO_RETURN:
case SSL_ERROR_SYSCALL:
// The peer has notified us that it is shutting down via
// the SSL "close_notify" message so we need to
// shutdown, too.
printf("Peer closed connection during SSL handshake,status:%d", status);
status = -1;
break;
default:
printf("Unexpected error during SSL handshake,status:%d", status);
status = -1;
break;
}
if (status == 1)
{
// Must have at least one handle to wait for at this point.
status = select(fd + 1, &readFdSet, &writeFdSet, NULL, &tv);
// 0 is timeout, so we re done.
// -1 is error, so we re done.
// Could be both handles set (same handle in both masks) so
// set to 1.
if (status >= 1)
{
status = 1;
}
else // Timeout or failure
{
printf("SSL handshake - peer timeout or failure");
status = -1;
}
}
}
while (status == 1 && !SSL_is_init_finished(ssl));
flags = fcntl(fd, F_GETFL, 0);
if (flags < 0)
{
printf("fcntl: F_GETFL
");
return false;
}
if (fcntl(fd, F_SETFL, flags & (~O_NONBLOCK)) < 0)
{
printf("fcntl: F_SETFL
");
return false;
}
return (status >= 0);