I am programming an UDP client. The protocol is written as a single response for a single request. I have a transaction class that sends the message and then runs a timer to wait for the response. If the response is received in expected time the timer is stopped and success callback is called. Otherwise the failure callback is called. Finally the finish callback is called unconditionally in both cases.
template <typename RequestType, typename ResponseType>
struct transaction{
boost::asio::io_service& _service;
boost::asio::deadline_timer _timer;
typename ResponseType::buffer_type _buff;
RequestType _request;
transaction(boost::asio::io_service& service, const RequestType& req): _service(service), _timer(service), _request(req){}
virtual ~transaction(){}
template <typename SuccessCallback, typename FailureCallback, typename FinishCallback>
void exec(boost::asio::ip::udp::endpoint& endpoint, boost::asio::ip::udp::socket& socket, unsigned wait_seconds, SuccessCallback success, FailureCallback failure, FinishCallback finish){
_timer.expires_from_now(boost::posix_time::seconds(wait_seconds));
_timer.async_wait([this, &failure, &finish](const boost::system::error_code& error){
if(!error){
std::cout << "failed to receive reply within deadline" << std::endl;
failure(_request);
finish(this);
}
});
socket.async_receive_from(boost::asio::buffer(_buff), endpoint, [this, &success, finish](const boost::system::error_code& error, std::size_t bytes_transferred){
if(!error && bytes_transferred > 0){
ResponseType reply;
reply.parse(_buff);
_timer.cancel();
success(reply);
finish(this);
}
});
socket.send_to(boost::asio::buffer(_request.buffer()), endpoint);
}
};
transaction is working fine for once. However I want to retry if it fails. Following is the knock function which is working fine for the first time. But in failure callback it calls knock again which results in segfault.
typedef transaction<request_knock, reply_knock> transaction_knock;
void knock(boost::asio::io_service& service, boost::asio::ip::udp::endpoint& endpoint, boost::asio::ip::udp::socket& socket){
request_knock knock_request(0);
transaction_knock* knock_transaction = new transaction_knock(service, knock_request);
knock_transaction->exec(endpoint, socket, 5, [](const reply_knock& reply){
std::cout << "success " << reply._data.id << std::endl;
}, [&service, &endpoint, &socket](const request_knock& req){
// FAILURE
knock(service, endpoint, socket);
}, [](transaction_knock* transaction){
delete transaction;
});
}
Following is the backtrace
#0 0x00007ffff7f0f244 in pthread_mutex_lock () from /usr/lib/libpthread.so.0
#1 0x000055555559f3c8 in boost::asio::detail::posix_mutex::lock (this=0xfbad2a8c) at /usr/include/boost/asio/detail/posix_mutex.hpp:52
#2 0x00005555555a7cb4 in boost::asio::detail::scoped_lock<boost::asio::detail::posix_mutex>::scoped_lock (this=0x7fffffffe2a0, m=...)
at /usr/include/boost/asio/detail/scoped_lock.hpp:46
#3 0x00005555555a02f5 in boost::asio::detail::service_registry::do_use_service (this=0xfbad2a84, key=...,
factory=0x5555555b4666 <boost::asio::detail::service_registry::create<boost::asio::detail::deadline_timer_service<boost::asio::time_traits<boost::posix_time::ptime> >, boost::asio::io_context>(void*)>, owner=0x7ffff7bbe5c0 <_IO_2_1_stdout_>)
at /usr/include/boost/asio/detail/impl/service_registry.ipp:117
#4 0x00005555555b39da in boost::asio::detail::service_registry::use_service<boost::asio::detail::deadline_timer_service<boost::asio::time_traits<boost::posix_time::ptime> > > (this=0xfbad2a84, owner=...) at /usr/include/boost/asio/detail/impl/service_registry.hpp:39
#5 0x00005555555b2219 in boost::asio::use_service<boost::asio::detail::deadline_timer_service<boost::asio::time_traits<boost::posix_time::ptime> > > (ioc=...) at /usr/include/boost/asio/impl/io_context.hpp:39
#6 0x00005555555b021d in boost::asio::basic_io_object<boost::asio::detail::deadline_timer_service<boost::asio::time_traits<boost::posix_time::ptime> >, true>::basic_io_object (this=0x5555555e2f20, io_context=...) at /usr/include/boost/asio/basic_io_object.hpp:224
#7 0x00005555555ad795 in boost::asio::basic_deadline_timer<boost::posix_time::ptime, boost::asio::time_traits<boost::posix_time::ptime> >::basic_deadline_timer (this=0x5555555e2f20, io_context=...) at /usr/include/boost/asio/basic_deadline_timer.hpp:159
#8 0x00005555555aa4ab in transaction<request_knock, reply_knock>::transaction (this=0x5555555e2f10, service=..., req=...)
at /home/else/Projects/comet/main.cpp:111
#9 0x000055555559a90c in knock (service=..., endpoint=..., socket=...) at /home/else/Projects/comet/main.cpp:192
#10 0x000055555559a8a2 in <lambda(const request_knock&)>::operator()(const request_knock &) const (__closure=0x7fffffffe3d0, req=...)
I am trying to figure out what is cause for this crash ?