fix for GH #1160: Poco::Net::NetException "SSL Exception: error:1409F07F:SSL routines:ssl3_write_pending:bad write retry

This commit is contained in:
Guenter Obiltschnig 2016-02-26 20:14:19 +01:00
parent 5076f60a5c
commit f7ba58c80f
2 changed files with 55 additions and 16 deletions

View File

@ -196,7 +196,21 @@ protected:
static bool isLocalHost(const std::string& hostName);
/// Returns true iff the given host name is the local host
/// (either "localhost" or "127.0.0.1").
bool mustRetry(int rc);
/// Returns true if the last operation should be retried,
/// otherwise false.
///
/// In case of an SSL_ERROR_WANT_READ error, and if the socket is
/// blocking, waits for the underlying socket to become readable.
///
/// In case of an SSL_ERROR_WANT_WRITE error, and if the socket is
/// blocking, waits for the underlying socket to become writable.
///
/// Can also throw a Poco::TimeoutException if the socket does
/// not become readable or writable within the sockets
/// receive or send timeout.
int handleError(int rc);
/// Handles an SSL error by throwing an appropriate exception.

View File

@ -270,7 +270,7 @@ int SecureSocketImpl::sendBytes(const void* buffer, int length, int flags)
{
rc = SSL_write(_pSSL, buffer, length);
}
while (rc <= 0 && _pSocket->lastError() == POCO_EINTR);
while (mustRetry(rc));
if (rc <= 0)
{
rc = handleError(rc);
@ -298,7 +298,7 @@ int SecureSocketImpl::receiveBytes(void* buffer, int length, int flags)
{
rc = SSL_read(_pSSL, buffer, length);
}
while (rc <= 0 && _pSocket->lastError() == POCO_EINTR);
while (mustRetry(rc));
if (rc <= 0)
{
return handleError(rc);
@ -325,7 +325,7 @@ int SecureSocketImpl::completeHandshake()
{
rc = SSL_do_handshake(_pSSL);
}
while (rc <= 0 && _pSocket->lastError() == POCO_EINTR);
while (mustRetry(rc));
if (rc <= 0)
{
return handleError(rc);
@ -390,6 +390,42 @@ X509* SecureSocketImpl::peerCertificate() const
}
bool SecureSocketImpl::mustRetry(int rc)
{
if (rc <= 0)
{
int sslError = SSL_get_error(_pSSL, rc);
int socketError = _pSocket->lastError();
switch (sslError)
{
case SSL_ERROR_WANT_READ:
if (_pSocket->getBlocking())
{
if (_pSocket->poll(_pSocket->getReceiveTimeout(), Poco::Net::Socket::SELECT_READ))
return true;
else
throw Poco::TimeoutException();
}
break;
case SSL_ERROR_WANT_WRITE:
if (_pSocket->getBlocking())
{
if (_pSocket->poll(_pSocket->getSendTimeout(), Poco::Net::Socket::SELECT_WRITE))
return true;
else
throw Poco::TimeoutException();
}
break;
case SSL_ERROR_SYSCALL:
return socketError == POCO_EAGAIN || socketError == POCO_EINTR;
default:
return socketError == POCO_EINTR;
}
}
return false;
}
int SecureSocketImpl::handleError(int rc)
{
if (rc > 0) return rc;
@ -402,13 +438,6 @@ int SecureSocketImpl::handleError(int rc)
case SSL_ERROR_ZERO_RETURN:
return 0;
case SSL_ERROR_WANT_READ:
if (_pSocket->getBlocking() && error != 0)
{
if (error == POCO_EAGAIN)
throw TimeoutException(error);
else
SocketImpl::error(error);
}
return SecureStreamSocket::ERR_SSL_WANT_READ;
case SSL_ERROR_WANT_WRITE:
return SecureStreamSocket::ERR_SSL_WANT_WRITE;
@ -421,11 +450,7 @@ int SecureSocketImpl::handleError(int rc)
case SSL_ERROR_SYSCALL:
if (error != 0)
{
if (_pSocket->getBlocking() && error == POCO_EAGAIN)
throw TimeoutException(error);
else
SocketImpl::error(error);
return rc;
SocketImpl::error(error);
}
// fallthrough
default: