From 696e3ff902c6601fd706fa21021e711e9993e0a6 Mon Sep 17 00:00:00 2001 From: Vincent Richard Date: Fri, 3 Jan 2014 21:54:32 +0100 Subject: Loop on SSL_write/gnutls_record_send in blocking send. OpenSSL reports SSL3_WRITE_PENDING on slow network connections, this patch fixes it (and is the correct way to do). --- src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.cpp | 34 ++++++++++++++++--------- src/vmime/net/tls/openssl/TLSSocket_OpenSSL.cpp | 26 ++++++++++++++++++- 2 files changed, 47 insertions(+), 13 deletions(-) diff --git a/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.cpp b/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.cpp index 5a90565b..18ea352d 100644 --- a/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.cpp +++ b/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.cpp @@ -179,22 +179,32 @@ size_t TLSSocket_GnuTLS::receiveRaw(byte_t* buffer, const size_t count) void TLSSocket_GnuTLS::sendRaw(const byte_t* buffer, const size_t count) { - ssize_t ret = gnutls_record_send - (*m_session->m_gnutlsSession, - buffer, static_cast (count)); - - if (m_ex) - internalThrow(); + m_status &= ~STATUS_WOULDBLOCK; - if (ret < 0) + for (size_t size = count ; size > 0 ; ) { - if (ret == GNUTLS_E_AGAIN) + ssize_t ret = gnutls_record_send + (*m_session->m_gnutlsSession, + buffer, static_cast (size)); + + if (m_ex) + internalThrow(); + + if (ret < 0) { - m_status |= STATUS_WOULDBLOCK; - return; - } + if (ret == GNUTLS_E_AGAIN) + { + platform::getHandler()->wait(); + continue; + } - TLSSession_GnuTLS::throwTLSException("gnutls_record_send", static_cast (ret)); + TLSSession_GnuTLS::throwTLSException("gnutls_record_send", static_cast (ret)); + } + else + { + buffer += ret; + size -= ret; + } } } diff --git a/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.cpp b/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.cpp index ef6647d6..9857b8fb 100644 --- a/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.cpp +++ b/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.cpp @@ -119,6 +119,7 @@ void TLSSocket_OpenSSL::createSSLHandle() SSL_set_bio(m_ssl, sockBio, sockBio); SSL_set_connect_state(m_ssl); + SSL_set_mode(m_ssl, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); } else { @@ -234,7 +235,30 @@ size_t TLSSocket_OpenSSL::receiveRaw(byte_t* buffer, const size_t count) void TLSSocket_OpenSSL::sendRaw(const byte_t* buffer, const size_t count) { - sendRawNonBlocking(buffer, count); + m_status &= ~STATUS_WOULDBLOCK; + + for (size_t size = count ; size > 0 ; ) + { + int rc = SSL_write(m_ssl, buffer, static_cast (size)); + + if (rc <= 0) + { + int error = SSL_get_error(m_ssl, rc); + + if (error == SSL_ERROR_WANT_WRITE || error == SSL_ERROR_WANT_READ) + { + platform::getHandler()->wait(); + continue; + } + + handleError(rc); + } + else + { + buffer += rc; + size -= rc; + } + } } -- cgit v1.2.3