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; unsigned long lTrue = 1;
/* mark the socket as non-blocking */
if (fd != INVALID_SOCKET) { if (fd != INVALID_SOCKET) {
#ifdef F_GETFL #ifdef F_GETFL
int flags; int flags;

View File

@ -124,6 +124,20 @@ FIFO::Ptr TcpClient::GetSendQueue(void)
return m_SendQueue; 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. * Retrieves the recv queue for the socket.
* *
@ -134,10 +148,7 @@ FIFO::Ptr TcpClient::GetRecvQueue(void)
return m_RecvQueue; return m_RecvQueue;
} }
/** size_t TcpClient::FillRecvQueue(void)
* Processes data that is available for this socket.
*/
void TcpClient::ReadableEventHandler(void)
{ {
int rc; int rc;
@ -150,16 +161,34 @@ void TcpClient::ReadableEventHandler(void)
#else /* _WIN32 */ #else /* _WIN32 */
if (rc < 0 && errno == EAGAIN) if (rc < 0 && errno == EAGAIN)
#endif /* _WIN32 */ #endif /* _WIN32 */
return; return 0;
if (rc <= 0) { if (rc <= 0) {
HandleSocketError(SocketException("recv() failed", GetError())); HandleSocketError(SocketException("recv() failed", GetError()));
return; return 0;
} }
m_RecvQueue->Write(NULL, rc); 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) void TcpClient::WritableEventHandler(void)
{ {
int rc; FlushSendQueue();
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);
} }
/** /**

View File

@ -58,6 +58,8 @@ public:
FIFO::Ptr GetSendQueue(void); FIFO::Ptr GetSendQueue(void);
FIFO::Ptr GetRecvQueue(void); FIFO::Ptr GetRecvQueue(void);
void Flush(void);
virtual bool WantsToRead(void) const; virtual bool WantsToRead(void) const;
virtual bool WantsToWrite(void) const; virtual bool WantsToWrite(void) const;
@ -69,8 +71,11 @@ private:
FIFO::Ptr m_SendQueue; FIFO::Ptr m_SendQueue;
FIFO::Ptr m_RecvQueue; FIFO::Ptr m_RecvQueue;
virtual void ReadableEventHandler(void); virtual size_t FillRecvQueue(void);
virtual void WritableEventHandler(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. * 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_BlockRead = false;
m_BlockWrite = false; m_BlockWrite = false;
size_t bufferSize = FIFO::BlockSize / 2; result = 0;
char *buffer = (char *)GetRecvQueue()->GetWriteBuffer(&bufferSize);
rc = SSL_read(m_SSL.get(), buffer, bufferSize);
if (rc <= 0) { for (;;) {
switch (SSL_get_error(m_SSL.get(), rc)) { int rc;
case SSL_ERROR_WANT_WRITE: size_t bufferSize = FIFO::BlockSize / 2;
m_BlockRead = true; char *buffer = (char *)GetRecvQueue()->GetWriteBuffer(&bufferSize);
/* fall through */ rc = SSL_read(m_SSL.get(), buffer, bufferSize);
case SSL_ERROR_WANT_READ:
return; if (rc <= 0) {
case SSL_ERROR_ZERO_RETURN: switch (SSL_get_error(m_SSL.get(), rc)) {
Close(); case SSL_ERROR_WANT_WRITE:
return; m_BlockRead = true;
default: /* fall through */
HandleSocketError(OpenSSLException( case SSL_ERROR_WANT_READ:
"SSL_read failed", ERR_get_error())); return result;
return; 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); return result;
OnDataAvailable(GetSelf());
} }
/** /**
* Processes data that can be written for this socket. * Processes data that can be written for this socket.
*/ */
void TlsClient::WritableEventHandler(void) size_t TlsClient::FlushSendQueue(void)
{ {
int rc; int rc;
if (!WantsToWrite())
return 0;
std::cerr << "tls sendq: " << GetSendQueue()->GetSize() << " bytes" << std::endl;
m_BlockRead = false; m_BlockRead = false;
m_BlockWrite = 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(), GetSendQueue()->GetSize());
rc = SSL_write(m_SSL.get(), (const char *)GetSendQueue()->GetReadBuffer(), write_size);
if (rc <= 0) { if (rc <= 0) {
switch (SSL_get_error(m_SSL.get(), rc)) { switch (SSL_get_error(m_SSL.get(), rc)) {
@ -159,18 +169,20 @@ void TlsClient::WritableEventHandler(void)
m_BlockWrite = true; m_BlockWrite = true;
/* fall through */ /* fall through */
case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_WRITE:
return; return 0;
case SSL_ERROR_ZERO_RETURN: case SSL_ERROR_ZERO_RETURN:
Close(); Close();
return; return 0;
default: default:
HandleSocketError(OpenSSLException( HandleSocketError(OpenSSLException(
"SSL_write failed", ERR_get_error())); "SSL_write failed", ERR_get_error()));
return; return 0;
} }
} }
GetSendQueue()->Read(NULL, rc); GetSendQueue()->Read(NULL, rc);
return rc;
} }
/** /**

View File

@ -56,8 +56,8 @@ private:
static int m_SSLIndex; static int m_SSLIndex;
static bool m_SSLIndexInitialized; static bool m_SSLIndexInitialized;
virtual void ReadableEventHandler(void); virtual size_t FillRecvQueue(void);
virtual void WritableEventHandler(void); virtual size_t FlushSendQueue(void);
virtual void CloseInternal(bool from_dtor); virtual void CloseInternal(bool from_dtor);