I have client-server app that uses Boost.Asio and SSL. Server has many threads. Server uses async_read
and sometimes I get invoked async handler with bytes_received != bytes_expected
and ec == 0
. Most of the time app misses 1-500 bytes out of 2048-16384 bytes (usual size of logical packets in the app).
My issue similar to this one - Why boost::asio::async_read completion sometimes executed with bytes_transferred=0 and ec=0?.
To fix it I made dedicated io_service::strand
for each ssl::stream
and one io_service::strand
for ssl::context
(which is shared among threads). I wrapped all async invocations with io_service::strand::wrap()
(async_read, async_write, async_wait). Routine launched via io_service::strand::post()
. I made debug checks before each invocation of socket method (io_service::strand::running_in_this_thread()
). But I still have broken packets...
Due to this answer https://stackoverflow.com/a/12801042/1802974 during the processing of async_read
/async_write
Boost.Asio can make intermediate handlers
which must be inside the strand. This is the last chance to fix this weird issue. How can I check that all intermediate handlers
actually performed inside dedicated socket strand?
UPDATE
After a lot of debugging I found my issue - it is not connected to SSL at all. That was because of wrong manipulation of buffers...
In my app I use std::vector<char>
as a buffer (two vectors for each socket - one for read operations and one for write operations). Vectors created right after socket opened with default (zero) length.
I have a binary protocol. Each packet consists of a header and payload. Header contains length of payload. After server received header of a packet it checks that read buffer is sufficient to receive payload. If buffer is smaller than packet payload - server increases the buffer.
Code that was used to manage buffer size (do not do this ever):
if (buf.capacity() >= newSize)
{
return;
}
buf.resize(newSize);
After that I constructed asio buffer like this:
boost::asio::buffer(myVector, expectedPacketLength)
I.e. this overload was used: boost.org
Now we will see the error:
- Client sends packet of the length 400
- Server increases size of the buffer to 400 (size == 400, capacity == 400)
- Server successfully receives packet
- Client sends packet of the length 415
- Server increases size of the buffer to 415.
But `std::vector` has its own logic to increase capacity and reallocate data.
After 'resizing' actual parameters - capacity == 800, size == 415.
- Server successfully receives packet
- Client sends packet of the length 430
- Server try to increase size of a buffer, but capacity is already bigger than 430.
Nothing is done.
- Server creates buffer.
But mentioned overload of `boost::asio::buffer` has its own logic - size of created buffer 415.
- voila, we miss 15 last bytes of the packet
Why I post it here?
Be carefull with the buffers )) Just use std::vector::reserve
to increase size and use most basic overload of boost::asio::buffer
boost.org