2

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

Community
  • 1
  • 1
Victor Mezrin
  • 2,797
  • 2
  • 32
  • 48
  • Can you provide a Could a minimal example reproducing the issue described in the first paragraph ? Maybe using `strand` is not the _fix_ that it needs. – Arunmu Nov 22 '16 at 06:04
  • You could wrap the handlers in a custom functor that logs/checks the strand identity. However, you could also show us how you wrap the async operations in the strand for review. – sehe Nov 22 '16 at 13:14

0 Answers0