Discussion:
Proper close of ASIO TLS connection and reuse afterwards
(too old to reply)
Sandra Schreiner
2016-02-04 08:03:03 UTC
Permalink
Hello,

I'm very new to asio. Therefore I'm a bit lost. Below you see my naive approach to have two seperate threads for send and receive.
The Client itself is started in the main thread of the application. io_service is a member of Client. I'm no longer using "asio::work".
However the code is not working because no data is read on client side (session calls async_write but callback is never executed).
What would be the right way to initiate an async_read on the client without blocking the client from initiating subsequent writes?

Client::Client(const TLSConfig& config, TLSClientListener& listener)
:AbstractTLSConnector(config), AbstractClient(listener){
mContext.reset(new asio::ssl::context(asio::ssl::context::tlsv12));
mContext->load_verify_file(mTLSConfig.getCACertificatePath());
connect();
}

void Client::connect(){
mSocket.reset(new TLSSocket_t(mIoService, *mContext));
mIoService.reset();
// [ ...verify and get iterator ... ]
asio::async_connect(mSocket->lowest_layer(), iterator, std::bind(&Client::connectCallback, this, std::placeholders::_1));
mIoService.run();
}

void Client::connectCallback(const asio::error_code& error){
if (!error){
doHandshake();
}
else{
//[... disconnect ...]
}
}

void Client::doHandshake(){
// [ ... async handshake ...]
}

void Client::doHandshakeCallback(const asio::error_code& error){
if (!error){
mReadThread.reset(new std::thread{[this](){ read();} });
}
else{
//[... disconnect ...]
}
}

void Client::write(const std::string& message){
mIoService.reset();
size_t dataLength = message.size();
asio::async_write((*mSocket),
asio::buffer(message, dataLength),
std::bind(&Client::writeCallback, this,
std::placeholders::_1, std::placeholders::_2));
mIoService.run();
}

void Client::writeCallback(const asio::error_code& err, size_t bytes_transferred){
if(!err && bytes_transferred == mSendMessage.size()) {
//read thread should be running
//read();
}
else {
//[... disconnect ...]
}
}

void Client::read(){
//read header
mTmpBuffer = new char[HEADER_LENGTH];
asio::error_code error;
size_t bytes_transferred = asio::read((*mSocket), asio::buffer(mTmpBuffer, HEADER_LENGTH),
asio::transfer_all(), error);
mReceiveHeader = std::string(mTmpBuffer, HEADER_LENGTH);
delete mTmpBuffer;
mTmpBuffer = nullptr;
if(!error && bytes_transferred == HEADER_LENGTH
&& decodeHeader(mReceiveHeader, mReceiveMessageLength)){
bytes_transferred = asio::read((*mSocket), asio::buffer(mTmpBuffer, mReceiveMessageLength), asio::transfer_all(), error);
mReceiveMessage = std::string(mTmpBuffer, mReceiveMessageLength);
delete mTmpBuffer;
mTmpBuffer = nullptr;
if (!error && bytes_transferred == mReceiveMessageLength){
//[... notify caller ...]
}
else{
//[... disconnect ...]
}
}
else{
//[... disconnect ...]
}
}

void Client::readContent(){
mTmpBuffer = new char[mReceiveMessageLength];
asio::async_read((*mSocket),
asio::buffer(mTmpBuffer, mReceiveMessageLength),
std::bind(&Client::readContentCallback, this, std::placeholders::_1, std::placeholders::_2));
}

void Client::readContentCallback(const asio::error_code& contentError,
size_t bytesTransferred){
mReceiveMessage = std::string(mTmpBuffer, mReceiveMessageLength);
delete mTmpBuffer;
mTmpBuffer = nullptr;
if (!contentError && bytesTransferred == mReceiveMessageLength){
//[... notify caller ...]
}
else{
//[... disconnect ...]
}
}

void Client::send(const std::string& sendData){
encodeHeader(sendData, mSendMessage);
write(mSendMessage);
}

void Client::disconnect(){
try{
mSocket->shutdown();
}catch(std::system_error &er){
mSocket->lowest_layer().close();
mSocket.reset();
}
}

Client::~Client(){
//[... join thread ...]
}

________________________________________
Von: Roger Austin (Australia) [***@innovyze.com]
Gesendet: Mittwoch, 3. Februar 2016 22:14
An: asio-***@lists.sourceforge.net
Betreff: Re: [asio-users] Proper close of ASIO TLS connection and reuse afterwards

Hi Sandra,

You can initiate an async_read on the client without blocking the client from initiating subsequent writes. However, if your client is single-threaded and blocked in io_service::Run (due to asio::work) it is hard to see how it could initiate anything.

Cheers,
Roger Austin

-----Original Message-----
From: Sandra Schreiner [mailto:***@stud.hs-kl.de]
Sent: Thursday, 4 February 2016 4:06 AM
To: asio-***@lists.sourceforge.net
Subject: Re: [asio-users] Proper close of ASIO TLS connection and reuse afterwards

Hello,

I managed to get this working for a one-directional close. The client can close the connection if it calls shutdown, catches the exception and the lowest_layer of the socket is closed in the catch block.

Unfortunately I don't know how I can initiate a shutdown from server side. The client is only reading on the socket if data was send from it in advance. As long as no data is send by the client 'asio::work' ensures that the io_service will not finish. But this also means that the shutdown of the session is pending and not retrieved on client side promptly.

But it is also not possible to start a read operation per default (which should wait for the session shutdown) because the client might also want to send data. Because everything is currently in one thread, the read would block the write. I thought about using two threads - one for reading and one for writing - on the clientside, but I'm not sure if this is the 'best-practice' solution.

Any ideas on that matter?

Many thanks for any hints in advance.
Best regards
Sandra

________________________________________
Von: Sandra Schreiner [***@stud.hs-kl.de]
Gesendet: Mittwoch, 3. Februar 2016 14:22
An: asio-***@lists.sourceforge.net
Betreff: [asio-users] Proper close of ASIO TLS connection and reuse afterwards

Hello,

I really would like to close the connection between client and server and reopen it afterwards. After I tried out various approaches, it seems i can't get a proper solution without any error message to work.

Beside different other solutions I tried checked out this post http://stackoverflow.com/questions/25587403/boost-asio-ssl-async-shutdown-always-finishes-with-an-error and tested the following variations of the accepted answer:
A) PartyA initiates shutdown() and waits for PartyB to respond with a shutdown()
B) PartyA initiates shutdown() but does not wait for PartyB to respond

In case (A), if I use shutdown on client and session side, I get the mentioned EoF error. But without any possibility to fetch the error, because the only available socket.shutdown() does have void as return value and does not take any parameters. Im using asio standalone version 1.10.6.

In case (B) the callback for the write operation is never called. Therefore the program just hangs.

Server accept start
Server accept success
Session start
Server accept start
Client connect success
Session handshake success
Client handshake success
Client initiateDisconnect enter
Session Read failed
Session shutdown

The code is the following (in first run I would like to cancel the connection by client):

Client (io_service is used with asio::work)
---------------------------------------------
void close(const asio::error_code &err){
std::cout << "Client close enter" << "\n"; } void initiateDisconnect(){
std::cout << "Client initiateDisconnect enter" << "\n";
socket_.async_shutdown(std::bind(&client::close, this, std::placeholders::_1));
std::string dummy = "s";
asio::async_write(socket_,
asio::buffer(dummy, dummy.size()),
std::bind(&client::handle_write, this,
std::placeholders::_1,
std::placeholders::_2)); } void handle_write(const asio::error_code& error, size_t bytes_transferred){
std::cout << "Client handle_write";
//... check error
}

Session (waits in handle_read)
---------------------

void handleShutdown(){
if(!isDown){
std::cout << " Session shutdown "<< "\n";
socket_.shutdown();
isDown = true;
delete this;
}
}
void handle_read(const asio::error_code& error,
size_t bytes_transferred) {
if (!error) {
std::cout << " Session Read success "<< "\n";
asio::async_write(socket_,
asio::buffer(data_, bytes_transferred),
std::bind(&session::handle_write, this,
std::placeholders::_1));
}
else {
std::cout << " Session Read failed "<< "\n";
handleShutdown();
}
}

How is a proper connection close done?
Many thanks for any help in advance,
Best regards
Sandra
------------------------------------------------------------------------------
Site24x7 APM Insight: Get Deep Visibility into Application Performance APM + Mobile APM + RUM: Monitor 3 App instances at just $35/Month Monitor end-to-end web transactions and take corrective actions now Troubleshoot faster and improve end-user experience. Signup Now!
http://pubads.g.doubleclick.net/gampad/clk?id=267308311&iu=/4140
_______________________________________________
asio-users mailing list
asio-***@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/asio-users
_______________________________________________
Using Asio? List your project at
http://think-async.com/Asio/WhoIsUsingAsio

------------------------------------------------------------------------------
Site24x7 APM Insight: Get Deep Visibility into Application Performance APM + Mobile APM + RUM: Monitor 3 App instances at just $35/Month Monitor end-to-end web transactions and take corrective actions now Troubleshoot faster and improve end-user experience. Signup Now!
http://pubads.g.doubleclick.net/gampad/clk?id=267308311&iu=/4140
_______________________________________________
asio-users mailing list
asio-***@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/asio-users
_______________________________________________
Using Asio? List your project at
http://think-async.com/Asio/WhoIsUsingAsio

------------------------------------------------------------------------------
Site24x7 APM Insight: Get Deep Visibility into Application Performance
APM + Mobile APM + RUM: Monitor 3 App instances at just $35/Month
Monitor end-to-end web transactions and take corrective actions now
Troubleshoot faster and improve end-user experience. Signup Now!
http://pubads.g.doubleclick.net/gampad/clk?id=272487151&iu=/4140
_______________________________________________
asio-users mailing list
asio-***@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/asio-users
_______________________________________________
Using Asio? List your project at
http://think-async.com/Asio/WhoIsUsingAsio

------------------------------------------------------------------------------
Site24x7 APM Insight: Get Deep Visibility into Application Performance
APM + Mobile APM + RUM: Monitor 3 App instances at just $35/Month
Monitor end-to-end web transactions and take corrective actions now
Troubleshoot faster and improve end-user experience. Signup Now!
http://pubads.g.doubleclick.net/gampad/clk?id=272487151&iu=/4140
_______________________________________________
asio-users mailing list
asio-***@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/asio-users
_______________________________________________
Using Asio? List your project at
http://think-async.com/Asio/WhoIsUsingAsio

Loading...