chriskohlhoff / asio

Asio C++ Library
http://think-async.com/Asio
4.88k stars 1.21k forks source link

Potential bug in asio::ssl_stream::write_some() #456

Closed brjoha closed 4 years ago

brjoha commented 4 years ago

Boost v1.71.0

Hi,

I have a large message that is written in increments using ssl::stream::write_some(). When the (non-blocking) socket gets congested, it seems the behavior is not consistent with the documentation...

https://www.boost.org/doc/libs/1_71_0/doc/html/boost_asio/reference/ssl__stream/write_some/overload2.html

It states that 0 is returned if an error occurs, but I'm seeing both a return value equal to the passed buffer length and a boost::asio::error::would_block error.

Once the socket is writable again, I've tried to resume writing as if no bytes were written as well as if all bytes were written. Both result in a corrupted SSL stream (sslv3 alert bad record mac).

Am I missing something subtle?

brjoha commented 4 years ago

As a subsequent test, I tried writing directly to the TCP stream via ssl::stream::next_layer::write_some() where I did get the expected EWOULDBLOCK behavior. That is, the first call returned bytes for a partial write, and the next call returned zero bytes and error::would_block.

Obviously this corrupted the SSL stream as well, but helped to further isolate the issue. So ssl::stream seems to not be properly handling the EWOULDBLOCK condition.

brjoha commented 4 years ago

Found this discussion...

chriskohlhoff/asio#271

...and everything worked after disabling non-blocking mode.

This is confusing to me though. Doesn't write_some() become a blocking call if non-blocking mode is not set? Under what circumstances would it return a value other than 0 or the full buffer length?

I should add that this is in a coroutine environment within an implicit strand, where one couroutine is handling rx operations and another is handling tx operations.