From 7f299fb2a7a6a05e64fb41c9313194786358f720 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Fri, 22 Jun 2012 11:47:06 +0200 Subject: [PATCH] Performance fixes for TLS sockets. --- base/socket.cpp | 1 + base/tcpclient.cpp | 54 ++++++++++++++++++++++++----------- base/tcpclient.h | 9 ++++-- base/tlsclient.cpp | 70 +++++++++++++++++++++++++++------------------- base/tlsclient.h | 4 +-- 5 files changed, 88 insertions(+), 50 deletions(-) diff --git a/base/socket.cpp b/base/socket.cpp index f1f1815d2..fc90011ce 100644 --- a/base/socket.cpp +++ b/base/socket.cpp @@ -72,6 +72,7 @@ void Socket::SetFD(SOCKET fd) { unsigned long lTrue = 1; + /* mark the socket as non-blocking */ if (fd != INVALID_SOCKET) { #ifdef F_GETFL int flags; diff --git a/base/tcpclient.cpp b/base/tcpclient.cpp index 43b54987f..0314f132a 100644 --- a/base/tcpclient.cpp +++ b/base/tcpclient.cpp @@ -124,6 +124,20 @@ FIFO::Ptr TcpClient::GetSendQueue(void) return m_SendQueue; } +size_t TcpClient::FlushSendQueue(void) +{ + int rc; + + rc = send(GetFD(), (const char *)m_SendQueue->GetReadBuffer(), m_SendQueue->GetSize(), 0); + + if (rc <= 0) { + HandleSocketError(SocketException("send() failed", GetError())); + return 0; + } + + m_SendQueue->Read(NULL, rc); +} + /** * Retrieves the recv queue for the socket. * @@ -134,10 +148,7 @@ FIFO::Ptr TcpClient::GetRecvQueue(void) return m_RecvQueue; } -/** - * Processes data that is available for this socket. - */ -void TcpClient::ReadableEventHandler(void) +size_t TcpClient::FillRecvQueue(void) { int rc; @@ -150,16 +161,34 @@ void TcpClient::ReadableEventHandler(void) #else /* _WIN32 */ if (rc < 0 && errno == EAGAIN) #endif /* _WIN32 */ - return; + return 0; if (rc <= 0) { HandleSocketError(SocketException("recv() failed", GetError())); - return; + return 0; } m_RecvQueue->Write(NULL, rc); - OnDataAvailable(GetSelf()); + return rc; +} + +void TcpClient::Flush(void) +{ + /* try to speculatively flush the buffer if there's a reasonable amount + * of data, this may fail, e.g. when the socket cannot immediately + * send this much data - the event loop will take care of this later on */ + if (GetSendQueue()->GetSize() > 128 * 1024) + FlushSendQueue(); +} + +/** + * Processes data that is available for this socket. + */ +void TcpClient::ReadableEventHandler(void) +{ + if (FillRecvQueue() > 0) + OnDataAvailable(GetSelf()); } /** @@ -167,16 +196,7 @@ void TcpClient::ReadableEventHandler(void) */ void TcpClient::WritableEventHandler(void) { - int rc; - - rc = send(GetFD(), (const char *)m_SendQueue->GetReadBuffer(), m_SendQueue->GetSize(), 0); - - if (rc <= 0) { - HandleSocketError(SocketException("send() failed", GetError())); - return; - } - - m_SendQueue->Read(NULL, rc); + FlushSendQueue(); } /** diff --git a/base/tcpclient.h b/base/tcpclient.h index 970696d89..59e8392c1 100644 --- a/base/tcpclient.h +++ b/base/tcpclient.h @@ -58,6 +58,8 @@ public: FIFO::Ptr GetSendQueue(void); FIFO::Ptr GetRecvQueue(void); + void Flush(void); + virtual bool WantsToRead(void) const; virtual bool WantsToWrite(void) const; @@ -69,8 +71,11 @@ private: FIFO::Ptr m_SendQueue; FIFO::Ptr m_RecvQueue; - virtual void ReadableEventHandler(void); - virtual void WritableEventHandler(void); + virtual size_t FillRecvQueue(void); + virtual size_t FlushSendQueue(void); + + void ReadableEventHandler(void); + void WritableEventHandler(void); }; /** diff --git a/base/tlsclient.cpp b/base/tlsclient.cpp index 229e13d2e..03b750fbc 100644 --- a/base/tlsclient.cpp +++ b/base/tlsclient.cpp @@ -106,52 +106,62 @@ void TlsClient::Start(void) /** * Processes data that is available for this socket. */ -void TlsClient::ReadableEventHandler(void) +size_t TlsClient::FillRecvQueue(void) { - int rc; + int result; m_BlockRead = false; m_BlockWrite = false; - size_t bufferSize = FIFO::BlockSize / 2; - char *buffer = (char *)GetRecvQueue()->GetWriteBuffer(&bufferSize); - rc = SSL_read(m_SSL.get(), buffer, bufferSize); + result = 0; - if (rc <= 0) { - switch (SSL_get_error(m_SSL.get(), rc)) { - case SSL_ERROR_WANT_WRITE: - m_BlockRead = true; - /* fall through */ - case SSL_ERROR_WANT_READ: - return; - case SSL_ERROR_ZERO_RETURN: - Close(); - return; - default: - HandleSocketError(OpenSSLException( - "SSL_read failed", ERR_get_error())); - return; + for (;;) { + int rc; + size_t bufferSize = FIFO::BlockSize / 2; + char *buffer = (char *)GetRecvQueue()->GetWriteBuffer(&bufferSize); + rc = SSL_read(m_SSL.get(), buffer, bufferSize); + + if (rc <= 0) { + switch (SSL_get_error(m_SSL.get(), rc)) { + case SSL_ERROR_WANT_WRITE: + m_BlockRead = true; + /* fall through */ + case SSL_ERROR_WANT_READ: + return result; + case SSL_ERROR_ZERO_RETURN: + Close(); + return result; + default: + HandleSocketError(OpenSSLException( + "SSL_read failed", ERR_get_error())); + return result; + } } + + GetRecvQueue()->Write(NULL, rc); + + result += rc; } - GetRecvQueue()->Write(NULL, rc); - - OnDataAvailable(GetSelf()); + return result; } /** * Processes data that can be written for this socket. */ -void TlsClient::WritableEventHandler(void) +size_t TlsClient::FlushSendQueue(void) { int rc; + if (!WantsToWrite()) + return 0; + + std::cerr << "tls sendq: " << GetSendQueue()->GetSize() << " bytes" << std::endl; + m_BlockRead = false; m_BlockWrite = false; - size_t write_size = std::min(GetSendQueue()->GetSize(), (size_t)(16 * 1024)); - - rc = SSL_write(m_SSL.get(), (const char *)GetSendQueue()->GetReadBuffer(), write_size); + rc = SSL_write(m_SSL.get(), (const char *)GetSendQueue()->GetReadBuffer(), GetSendQueue()->GetSize()); if (rc <= 0) { switch (SSL_get_error(m_SSL.get(), rc)) { @@ -159,18 +169,20 @@ void TlsClient::WritableEventHandler(void) m_BlockWrite = true; /* fall through */ case SSL_ERROR_WANT_WRITE: - return; + return 0; case SSL_ERROR_ZERO_RETURN: Close(); - return; + return 0; default: HandleSocketError(OpenSSLException( "SSL_write failed", ERR_get_error())); - return; + return 0; } } GetSendQueue()->Read(NULL, rc); + + return rc; } /** diff --git a/base/tlsclient.h b/base/tlsclient.h index 5e5d2c409..ff44cc813 100644 --- a/base/tlsclient.h +++ b/base/tlsclient.h @@ -56,8 +56,8 @@ private: static int m_SSLIndex; static bool m_SSLIndexInitialized; - virtual void ReadableEventHandler(void); - virtual void WritableEventHandler(void); + virtual size_t FillRecvQueue(void); + virtual size_t FlushSendQueue(void); virtual void CloseInternal(bool from_dtor);