Performance fixes for TLS sockets.

This commit is contained in:
Gunnar Beutner 2012-06-22 11:47:06 +02:00
parent e2253b8624
commit 7f299fb2a7
5 changed files with 88 additions and 50 deletions

View File

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

View File

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

View File

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

View File

@ -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;
}
/**

View File

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