Discussion:
[asio-users] asio and async SSL stream: how to detect end of data/connection close?
Andrey Kulikov
2011-12-11 20:23:27 UTC
Permalink
Hello,

I'm trying to make asio and SSL friends.
Everything going well, but one thing is causing inconvenience: how to
detect if peer close connection, and distinguish it from situation
when peer just take a short break in sending data, aming to continue
it few seconds later?

boost 1.48
OpenSSL 1.0.0e
Compiled to 32-bit code using VS10
Working on W7 x64.

My confusion comes from the fact, that asio behaviour is different for
ordinary socjket and SSL-stream.
If I use tcp::socket - I receive EOF error when peer close connection.
But for boost::asio::ssl::stream<boost::asio::ip::tcp::socket> - it is
not hte case. Instead, async_read_some returns 0 as bytes transfered,
and if I try to continue to read from SSL stream - returns short_error
( http://www.boost.org/doc/libs/1_47_0/doc/h...re/streams.html ).

So, the questions is: is it expected behaviour, or I misconfigure anything?

Client code snippet:
class client
{
public:

// bla-bla-bla-bla-bla ....
//
void handle_write(const boost::system::error_code& error)
{
if (!error)
{
socket_.async_read_some(boost::asio::buffer(reply_, max_length),
boost::bind(&client::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
else
{
std::cout << "Write failed: " << error.message() << "\n";
}
}

void handle_read(const boost::system::error_code& error,
size_t bytes_transferred)
{

std::cout << "Bytes transfered: " << bytes_transferred << "\n";
if (!error)
{
std::cout << "Reply: ";
std::cout.write(reply_, bytes_transferred);
std::cout << "\n";

std::cout << "Reading...\n";
socket_.async_read_some(boost::asio::buffer(reply_, max_length),
boost::bind(&client::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
else if (0 != bytes_transferred)
{
std::cout << "Read failed: " << error.message() << ":"
<< error.value() << "\n";
}
}

private:
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_;
boost::asio::streambuf request_;
char reply_[max_length];
};

If we remove if (0 != bytes_transferred), we'll get "short read" :(.

If we'll use code as-ai, output will be something like this:

=====================
Request is:
GET / HTTP/1.0
Cookie: Nama-nama=Vala-vala

Bytes transfered: 1024

Reply: HTTP/1.0 200 ok
Content-type: text/html

<HTML><BODY BGCOLOR="#ffffff">
..... bla-bla-bla ....

Reading...
Bytes transfered: 1024

..... bla-bla-bla ....
..... bla-bla-bla ....
Reading...
Bytes transfered: 482

..... bla-bla-bla ....
</BODY></HTML>

Reading...
Bytes transfered: 0
=====================

At the same time, if instead async_read_some we write code, what for
ordinary socket will return EOF:
boost::asio::async_read(socket_, response_,
boost::asio::transfer_at_least(1),
boost::bind(&client::handle_read_content, this,
boost::asio::placeholders::error));

then for SSL-socket we'll get 0 as bytes transfered, and then short_read.

I know that there is not way to detect disconnect in case if peer, for
example, was just unplugged from the network.
But how to detect explicit clean peer disconnect from situation when
peer just do not send data for a some time, but may be will do it
little bit later?

Or, may be I do not understant something?

WBR,
Andrey

Loading...