how to cancel a `boost::asio::read` operation while it's waiting - c++

I am using boost::asio to transfer data to & fro from client to server. I have a reader thread on client side to read data received on the socket on client side. Please note that I am using boost::asio::read on client side & boost::asio::writeon server side.
Not using async_read or async_write. Everything works great.
However when I close my application, 2 out 10 times the app does not cleanly tear down or close properly. It gets hung while closing down The issue is the following:
My closing function gets called when destructors get called during my app's close down. Following is the code of the Close function:
socket.cancel();
socket.close();
boost::system::error_code ec;
socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
The problem is that the boost::asio::read call does not return when it does not get any data & keeps waiting on it. This should be fine as long as I can cancel it. I am trying to do a socket.cancel on it to cancel all read operations while exiting.
However, it doesn't seems to work. I read in some forums that socket.cancel only cancels async_read operations. Is it so ? Then what is the way to cancel a boost::asio::read` operation when my app needs to exit ?

That's the nature of blocking IO.
Indeed socket.cancel() (or even io_service::stop()) will not work on synchronous operations.
The only way to interrupt this is to use socket-level timeouts (but Asio doesn't expose that) or to use asynchronous signals (e.g. pressing Ctrl-C in a terminal sends the child process a SIGINT).
I've previously created a poor-man's wrapper if you insist on running single operations with a timeout:
boost::asio + std::future - Access violation after closing socket

boost::system::error_code _error_code;
client_socket_->shutdown(boost::asio::ip::tcp::socket::shutdown_both, _error_code);
Above code help me close sync read immediately.
And sync read wiil return with error code: boost::asio::error::eof
I wonder why your code socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); did not work.
Maybe you should try again.

The error is due to the call to socket.close() before the call to socket.shutdown(). If you close a socket while there is a pending synchronous read(), you will occasionally get that error. It is really due to an expected data race in the underlying asio socket code.
Try removing the socket.close() call. Assuming your socket is wrapped in some kind of shared_ptr, you can let the socket destructor close the underlying socket.
You will still want to call socket.cancel() and socket.shutdown() explicitly in your use case in order to cancel outstanding operations.

Related

Asio end socket functions: cancel, shutdown, close, release

Which is the correct way to close and clean up a socket?
I have the io_service running in a secondary thread and I need to close the connection from the main thread:
void closeConnection()
{
ioc.post([&socket]() {
// Which ones do I have to call?
// In what order?
// What do they do?
//socket.cancel();
//socket.shutdown(asio::ip::tcp::socket::shutdown_both);
//socket.close();
//socket.release();
});
secondaryThread.join();
}
What is the difference between all these functions?
I've tried with this sequence ...
socket.cancel();
socket.close();
socket.release();
and seems to close up the connection without errors but takes too much time (about 5-10 seconds), so I guess I'm doing something wrong.
I presume you're talking about a graceful close, i.e. read/write any outstanding data, then close the socket.
The proper steps are:
Call shutdown() to indicate that you will not write any more data to the socket.
Continue to (async-) read from the socket until you get either an error or the connection is closed.
Now close() the socket (in the async read handler).
If you don't do this, you may end up closing the connection while the other side is still sending data. This will result in an ungraceful close.
cancel() and release() aren't the calls you use in a normal flow:
cancel() cancels all outstanding asynchronous operations.
release() releases ownership of the underlying native socket.

Boost asio asynchronous read and then write

In my socket communication I have a server where at each connection I want to read data first and after I finished reading, I want to write a response. However I want to do it asynchronously, so I can process many incoming connections. The problem with async_read and async_write is, that obviously they are asynchronous and when I start to read, the write operation immediately starts too.
So basically my question is:
How to start reading from a socket, then interrupt reading (when I decided by the communication protocol that all data has been sent) and then start writing and finally close the socket?
Concerning the second part of your question, look for example at this link.
The async_read function has the parameters CompletionCondition completion_condition and ReadHandler handler. These are callbacks. The completion condition should return 0 if you decide that you've read everything you need. Once you are done reading, the handler callback is called. You can call async_write from the handler.

How do I get an OpenSSL server using blocking BIO to shutdown cleanly?

In a larger server app I have one thread with a basic OpenSSL server using BIO in blocking mode because that seemed the simplest way. My code accepts a single type of request from a phone (Android or iOS, and I'm not writing that code) and returns a hex string wrapped in basic HTML (describing part of my server state). I've gone with SSL and a psuedo-HTTPS server because that makes things easier for the phone developer. If there's anything in the request that the server doesn't understand I return a 404. This all works.
The problem : When my server shuts down this thread doesn't exit because of the blocking BIO_do_accept call.
I have tried BIO_get_fd() and setsockopt() to put a timeout on the underlying socket but it still blocks. Somewhat worryingly SSL_state() stays at "before/accept initialization", but looping on that obviously won't work.
I assume other people have server code like this, and those servers can shut down gracefully. How do they do that? Is there some way for another thread to break that block and get the accept call to return with an error? Or do I have to drop the idea of blocking calls and grind through the apparently awful non-blocking version?
When my server shuts down this thread doesn't exit because of the blocking BIO_do_accept call.
To stop the blocking, close the associated socket. It will return immediately.
Perform the shutdown from your signal handler.
Don't do anything else in the signal handler with respect to OpenSSL because it is not async-signal safe. Let the main thread cleanup once your worker thread has returned. See, for example, libcrypto Thread Safety.

C++ Can I make boost::asio connection socket without timer?

I have a window server socket and a Linux client socket. Client connect to server and send a message. After, the server will call a external executable. The problem is : when server is not available, Client is blocking with timeout at connect function, But I don't want it. I hope if the connection is not made, client socket will be closed straight away.
Somebody can give me some advice?
Warning: Pseudo-Code ahead.
You can do that. But it is not as straight forward as you might hope.
You need to use async_connect() from your client to not block. Then you also need a deadline_timer set to whatever timeout you deem appropriate. Zero will not work, you need to give the async_connect() some time. But i guess one or two seconds should be fine.
The timers handler will then have to cancel() all async operations on the socket (you need to make sure that is only the connect, use more sockets if needed).
Mind the socket will not be closed by that. Ideally you will close it in the handler of the async_connect whenever the passed error_code indicates a negative result. For example, if it was canceled, the handler will be called with OPERATION_ABORTED as error_code.
Of course, if you check only for that, you could as well close() the socket in the timers handler after the cancel(). But that would leave you with an open socket whenever the async_connect failed for some other reason.
I would assume from your question that you want your socket to get closed whenever the async_connect() passes any error_code but SUCCESS. And SUCCESS is the only error_code implicitly converted to 0 when used as a boolean, so checking for that in your handler is easy. ^^
Do not forget to cancel the deadline_timer in the handler of the async_connect() and to make sure the timers handler was not called with OPERATION_ABORTED before it closes the socket. ^^

Cancelling a blocking read operation in Thrift

I am using Apache thrift in C++ on Windows and I would like to ask for your help with cancellation of a blocking read operation that is in progress. The read operation (for example – TProtocol::readByte) is blocked until the data is received. When I close the transport from another thread, I get a failed assertion about a null pointer.
Is there any other way to cancel a blocked read operation?
Assuming you are running on Windows (according to the tags on your question): You can cancel a blocking socket operation with WSACancelBlockingCall (although this operation is deprecated, it should still work). Your socket will then return the error code WSAEINTR (Interrupted function call) instead of WSAETIMEDOUT.
In Thrift, you can use TSocket::getSocketFD() or TPipe::getPipeHandle() to get the according handle for canceling the current operation.
if you're using blocking mode, so the only option to abort the read operation is set a timeout on the TSocket before read it.