When writing data over an OpenSSL::SSL::SSLSocket, we have two buffers that can fill-in: the TCPSocket and the SSLSocket.
When the TCPSocket buffer is full, the TcpClient#write method wait for the socket to be writable again, and retry the operation;
When the SSLSocket buffer is full, the SSLClient#write method wait for the socket to be writable again, and retry the operation.
However, SSLClient#write is a wrapper around TcpClient#write, and when it retry after caching a OpenSSL::SSL::SSLErrorWaitWritable it has no idea of the amount of data that got send and restart a full transfer of the data with TcpClient#write. When this happen, the new transfer can fail in a similar fashion any number of time and will eventually come to completion after sending multiple partial copies of the message followed by a complete copy, which is just garbage for Riemann on the other side. Riemann will discard the message and return an error that will be passed to the calling code.
In order to fix this, make TcpClient#write aware of IO::WaitWritable (a base class of OpenSSL::SSL::SSLErrorWaitWritable) and remove the SSLClient#write method so that the parent class method is used directly instead.
While here, do the same for TcpClient#read / SSLClient#read for consistency.
While here, also handle IO::WaitReadable exception in TcpClient#write to cope with TLS renegociation as recommended in the IO#select documentation.
When writing data over an
OpenSSL::SSL::SSLSocket
, we have two buffers that can fill-in: theTCPSocket
and theSSLSocket
.TCPSocket
buffer is full, theTcpClient#write
method wait for the socket to be writable again, andretry
the operation;SSLSocket
buffer is full, theSSLClient#write
method wait for the socket to be writable again, andretry
the operation.However,
SSLClient#write
is a wrapper aroundTcpClient#write
, and when itretry
after caching aOpenSSL::SSL::SSLErrorWaitWritable
it has no idea of the amount of data that got send and restart a full transfer of the data withTcpClient#write
. When this happen, the new transfer can fail in a similar fashion any number of time and will eventually come to completion after sending multiple partial copies of the message followed by a complete copy, which is just garbage for Riemann on the other side. Riemann will discard the message and return an error that will be passed to the calling code.In order to fix this, make
TcpClient#write
aware ofIO::WaitWritable
(a base class ofOpenSSL::SSL::SSLErrorWaitWritable
) and remove theSSLClient#write
method so that the parent class method is used directly instead.While here, do the same for
TcpClient#read
/SSLClient#read
for consistency.While here, also handle
IO::WaitReadable
exception inTcpClient#write
to cope with TLS renegociation as recommended in theIO#select
documentation.