SEG fault in async_read_until() - c++

I am facing an issue in reading through boost::asio::async_read_until(). The server code I have been using is as follows:
boost::asio::streambuf buffer;
boost::asio::async_read_until(socket_,buffer,DELIMITER,boost::bind(
&chat_session::handle_read_body,
shared_from_this(),
placeholders::error,
placeholders::bytes_transferred()
)
);
void chat_session::handle_read_body(const boost::system::error_code& error,std::size_t bytes_transferred)
{
FILE_LOG(logINFO)<<"Entry chat_session::handle_read_body\n";
FILE_LOG(logINFO)<<"Bytes Received:\t"<<bytes_transferred<<endl;
}
When my client send some data with delimiter, the server comes up with a dialog for segmentation fault and the file in the background opened is read_until.hpp.The control does not come to the handle_read_body() function.
Please help!

shared_from_this(),
this is your problem - pardon the pun.
Without seeing the crash, one of two things is probably happening:
a) Your code turns shared_from_this() into an rvalue from which a pointer is obtained, the shared object is then unref'd and the object gets destroyed after the callback has been queued,
b) The callback handler is trying to use the value of shared_from_this() to populate this, which is illegal (it doesn't know to call shared_from_this().get())
You might want to try the following:
~chat_session()
{
LOG("~chat_session(%p)", this);
}
// ...
auto ptr = shared_from_this();
LOG("this=%p, shared=%p, cs=%p, aru", this, ptr, (chat_session*)ptr);
boost::asio::async_read_until(socket_,buffer,DELIMITER,boost::bind(
&chat_session::handle_read_body,
ptr,
placeholders::error,
placeholders::bytes_transferred()
)

Related

Cancelling boost::asio::async_read gracefully

I have a class that looks like this:
class MyConnector : public boost::noncopyable, public boost::enable_shared_from_this<MyConnector>
{
public:
typedef MyConnector this_type;
boost::asio::ip::tcp::socket _plainSocket;
boost::shared_ptr<std::vector<uint8_t>> _readBuffer;
// lot of obvious stuff removed....
void readProtocol()
{
_readBuffer = boost::make_shared<std::vector<uint8_t>>(12, 0);
boost::asio::async_read(_plainSocket, boost::asio::buffer(&_readBuffer->at(0), 12),
boost::bind(&this_type::handleReadProtocol, shared_from_this(),
boost::asio::placeholders::bytes_transferred, boost::asio::placeholders::error));
}
void handleReadProtocol(size_t bytesRead,const boost::system::error_code& error)
{
// handling code removed
}
};
This class instance is generally waiting to receive 12 bytes protocol, before trying to read the full message. However, when I try to cancel this read operation and destroy the object, it doesn't happen. When I call _plainSocket.cancel(ec), it doesn't call handleReadProtocol with that ec. Socket disconnects, but the handler is not called.
boost::system::error_code ec;
_plainSocket.cancel(ec);
And the shared_ptr of MyConnector object that was passed using shared_from_this() is not released. The object remains like a zombie in the heap memory. How do I cancel the async_read() in such a way that the MyConnector object reference count is decremented, allowing the object to destroy itself?
Two things: one, in handleReadProtocol, make sure that, if there is an error, that readProtocol is not called. Canceled operations still call the handler, but with an error code set.
Second, asio recommends shutting down and closing the socket if you're finished with the connection. For example:
asio::post([this] {
if (_plainSocket.is_open()) {
asio::error_code ec;
/* For portable behaviour with respect to graceful closure of a connected socket, call
* shutdown() before closing the socket. */
_plainSocket.shutdown(asio::ip::tcp::socket::shutdown_both, ec);
if (ec) {
Log(fmt::format("Socket shutdown error {}.", ec.message()));
ec.clear();
}
_plainSocket.close(ec);
if (ec)
Log(fmt::format("Socket close error {}.", ec.message()));
}
});

what is the easiest way to extend an existing data structure to include semaphore or similar methods in c++?

I have an existing c++ code.
boost::asio::ip::address m_sender_IP_address;
void Udp_comm::start_receive()
{
//receive UDP message
m_sock_r.async_receive_from(
boost::asio::buffer(m_recv_buffer),
m_sender_endpoint,
boost::bind(&Udp_comm::handle_receive, this, boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void Udp_comm::handle_receive(const boost::system::error_code& error, const std::size_t bytes_transferred)
{
std::string recvd_message(m_recv_buffer.begin(), m_recv_buffer.begin() + bytes_transferred);
m_sender_IP_address = m_sender_endpoint.address();//////////wait here
//continue to listening to future messages
start_receive();
process_message(m_sender_IP_addres.to_string(), recvd_message);
}
How to protect m_sender_IP_address from getting overwritten by next UDP message received? I want lock access to that variable from 2nd line in handle_receive method to the 1st line in process_message method
can I also acheive something similar without using locks?
A semaphore is not necessary here. You can use a strand to ensure an asynchronous handler is invoked concurrently once at most. To do this, create a wrapped handler for the async_receieve_from() callback
void Udp_comm::start_receive()
{
//receive UDP message
m_sock_r.async_receive_from(
boost::asio::buffer(m_recv_buffer),
m_sender_endpoint,
m_strand.wrap(
boost::bind(
&Udp_comm::handle_receive,
this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred
)
)
);
}
Here m_strand is a member of Udp_comm. Doing this will guarantee only one thread can mutate m_sender_IP_address.

Am I getting a race condition with my boost asio async_read?

bool Connection::Receive(){
std::vector<uint8_t> buf(1000);
boost::asio::async_read(socket_,boost::asio::buffer(buf,1000),
boost::bind(&Connection::handler, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
int rcvlen=buf.size();
ByteBuffer b((std::shared_ptr<uint8_t>)buf.data(),rcvlen);
if(rcvlen <= 0){
buf.clear();
return false;
}
OnReceived(b);
buf.clear();
return true;
}
The method works fine but only when I make a breakpoint inside it. Is there an issue with timing as it waits to receive? Without the breakpoint, nothing is received.
You are trying to read from the receive buffer immediately after starting the asynchronous operation, without waiting for it to complete, that is why it works when you set a breakpoint.
The code after your async_read belongs into Connection::handler, since that is the callback you told async_read to invoke after receiving some data.
What you usually want is a start_read and a handle_read_some function:
void connection::start_read()
{
socket_->async_read_some(boost::asio::buffer(read_buffer_),
boost::bind(&connection::handle_read_some, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void connection::handle_read_some(const boost::system::error_code& error, size_t bytes_transferred)
{
if (!error)
{
// Use the data here!
start_read();
}
}
Note the shared_from_this, it's important if you want the lifetime of your connection to be automatically taken care of by the number of outstanding I/O requests. Make sure to derive your class from boost::enable_shared_from_this<connection> and to only create it with make_shared<connection>.
To enforce this, your constructor should be private and you can add a friend declaration (C++0x version; if your compiler does not support this, you will have to insert the correct number of arguments yourself):
template<typename T, typename... Arg> friend boost::shared_ptr<T> boost::make_shared(const Arg&...);
Also make sure your receive buffer is still alive by the time the callback is invoked, preferably by using a statically sized buffer member variable of your connection class.

boost::asio::async_read texutal stop condition?

I'm writing a server with Boost, something pretty simple - accept an XML message, process, reply. But I'm running into trouble at telling it when to stop reading.
This is what I have right now: (_index is the buffer into which the data is read)
std::size_t tcp_connection::completion_condition(const boost::system::error_code& error,
std::size_t bytes_transferred)
{
int ret = -1;
std::istream is(&_index);
std::string s;
is >> s;
if (s.find("</end_tag>") != std::string.npos) ret = 0;
return ret;
}
void tcp_connection::start()
{
// Get index from server
boost::asio::async_read(_socket, _index, &(tcp_connection::completion_condition),
boost::bind(&tcp_connection::handle_read, shared_from_this(), boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
This doesn't compile, since I have to define completion_condition as static to pass it to async_read; and I can't define _index as static since (obviously) I need it to be specific to the class.
Is there some other way to give parameters to completion_condition? How do I get it to recognize the ending tag and call the reading handler?
You can pass pointers to member functions. The syntax for doing it with C++ is tricky, but boost::bind hides it and makes it fairly easy to do.
An example would be making completion_condition non-static and passing it to async_read as such:boost::bind(&tcp_connection::completion_condition, this, _1, _2)
&tcp_connection::completion_condition is a pointer to the function. this is the object of type tcp_connection to call the function on. _1 and _2 are placeholders; they will be replaced with the two parameters the function is called with.

boost::asio error "The I/O operation has been aborted..."

I am receiving this error message
"The I/O operation has been aborted because of either a thread exit or an application request"
when using boost::asio::socket::async_read_some()
What does the error mean? What should I be looking for?
Here is the relevant code:
void tcp_connection::start()
{
printf("Connected to simulator\n");
socket_.async_read_some(boost::asio::buffer(myBuffer,256),
boost::bind(&tcp_connection::read_sim_handler,this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void tcp_connection::read_sim_handler(
const boost::system::error_code& error, // Result of operation.
std::size_t len ) // Number of bytes read.
{
try {
if (error == boost::asio::error::eof) {
// Connection closed cleanly by peer.
printf("Sim connection closed\n");
return;
} else if (error) {
throw boost::system::system_error(error); // Some other error. if( ! error )
}
socket_.async_read_some(boost::asio::buffer(myBuffer,256),
boost::bind(&tcp_connection::read_sim_handler,this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
}
When I replace the call to async_read_some() with read_some() in the start() method, everything works fine ( except the server blocks waiting for a message! )
Following a comment i see that tcp_connection is going out of scope. I copied the code from http://www.boost.org/doc/libs/1_45_0/doc/html/boost_asio/tutorial/tutdaytime3.html
which says this:
"We will use shared_ptr and enable_shared_from_this because we want to keep the tcp_connection object alive as long as there is an operation that refers to it."
I confess that I do not know what all that means. So I have broken it somehow?
Following further comments, the answer is
void tcp_connection::start()
{
printf("Connected to simulator\n");
socket_.async_read_some(boost::asio::buffer(myBuffer,256),
boost::bind(&tcp_connection::read_sim_handler,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
Passing shared_from_this() rather than this employs the clever ( too clever? ) keep alive infrastructure established by the server code, even though the connection manager is not in scope, by normal means. For technical details, see comments under accepted answer.
Your tcp_connection object or your buffer object is likely going out of scope prior to the async operation completing.
Since your program is based on one of the tutorial examples, why don't you check out another of the examples that reads some data as well: http://www.boost.org/doc/libs/1_45_0/doc/html/boost_asio/example/echo/async_tcp_echo_server.cpp
The reason your class goes out of scope is that you are no longer using shared_from_this(). What this does is create a shared_ptr to your class that is stored by the bind handler. This means that the shared_ptr will keep your class alive until your handler is called.
This is also why you need to inherit from enable_shared_from_this.
The last shared_ptr that goes out of scope will delete your class instance.