-
Notifications
You must be signed in to change notification settings - Fork 113
Closed
Description
Hello,
I have a issue as follow.
I have called set_pingresp_timeout(20s) in my mqtt client. I think if I pause the broker(or unplug network cable), mqtt client would call force_disconnect() and then on_error callback is called. but actually mqtt client block in force_disconnect() for more than 30 minutes.
following is the code for reproducing this issue.
using client_t = decltype(
MQTT_NS::make_tls_sync_client(
std::declval<boost::asio::io_context&>(),
std::string(),
std::string()
)
);
boost::asio::io_context ioc;
client_t c = nullptr ;
int main(int argc, char** argv) {
std::string host = "10.161.93.83";
std::string port = "8883";
std::string cacert = "/opt/emerson_mqtt/root.pem";
std::string cert = "/opt/emerson_mqtt/gt.pem";
std::string private_key = "/opt/emerson_mqtt/gt.key";
c = MQTT_NS::make_tls_sync_client(ioc, host, port, mqtt::protocol_version::v3_1_1);
using packet_id_t = typename std::remove_reference_t<decltype(*c)>::packet_id_t;
char cli_id[128]= {0};
int i_Rand = rand();
sprintf(cli_id, "%d", i_Rand);
c->set_client_id(cli_id);
c->set_clean_session(true);
c->set_keep_alive_sec(20,std::chrono::seconds(5));
c->get_ssl_context().load_verify_file(cacert);
c->get_ssl_context().use_certificate_chain_file(cert);
c->get_ssl_context().use_private_key_file(private_key, boost::asio::ssl::context::file_format::pem);
c->set_pingresp_timeout(std::chrono::seconds(20));
#if OPENSSL_VERSION_NUMBER >= 0x10101000L
SSL_CTX_set_keylog_callback(
c->get_ssl_context().native_handle(),
[](SSL const*, char const* line) {
std::cout <<"SSL_CTX callback keylog " << syscall(SYS_gettid) << std::endl;
}
);
#endif // OPENSSL_VERSION_NUMBER >= 0x10101000L
// Setup handlers
c->set_connack_handler(
[&c]
(bool sp, MQTT_NS::connect_return_code connack_return_code){
if (connack_return_code == MQTT_NS::connect_return_code::accepted) {
std::cout << "Connect successful" << std::endl;
}
return true;
});
c->set_close_handler(
[]
(){
std::cout << "close_handler: closed." << std::endl;
});
c->set_error_handler(
[]
(MQTT_NS::error_code ec){
std::cout << "ec.message: " << ec.message() <<" ec.value=" << ec.value() << " " << getDateTime() << std::endl;
});
c->set_pingresp_handler(
[&]
()
{
std::cout << "pingresp_handler. "<< getDateTime() << std::endl;
return true;
});
std::this_thread::sleep_until(std::chrono::steady_clock::now() + std::chrono::milliseconds(1000));
std::cout << "start connect to broker and run io_context" <<std::endl;
c->connect();
ioc.run();
std::cout << "io_context has released " <<std::endl;
while(1)
{
std::this_thread::sleep_until(std::chrono::steady_clock::now() + std::chrono::milliseconds(1000));
}
}
Following is the backtrace in GDB after I pause the broker.
#0 0xf796fb60 in poll () from /lib/arm-linux-gnueabihf/libc.so.6
#1 0x00418ddc in boost::asio::detail::socket_ops::poll_read (s=6, state=0 '\000', msec=-1, ec=...)
at /opt/arm-buildroot-linux-gnueabihf_sdk-buildroot/arm-buildroot-linux-gnueabihf/sysroot/usr/include/boost/asio/detail/impl/socket_ops.ipp:2244
#2 0x00418510 in boost::asio::detail::socket_ops::sync_recv1 (s=6, state=18 '\022', data=0x627b88,
size=17408, flags=0, ec=...)
at /opt/arm-buildroot-linux-gnueabihf_sdk-buildroot/arm-buildroot-linux-gnueabihf/sysroot/usr/include/boost/asio/detail/impl/socket_ops.ipp:894
#3 0x00488fdc in boost::asio::detail::reactive_socket_service_base::receive<boost::asio::mutable_buffer> (this=0x60441c, impl=..., buffers=..., flags=0, ec=...)
at /opt/arm-buildroot-linux-gnueabihf_sdk-buildroot/arm-buildroot-linux-gnueabihf/sysroot/usr/include/boost/asio/detail/reactive_socket_service_base.hpp:364
#4 0x00481108 in boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::any_io_executor>::read_some boost/asio/basic_stream_socket.hpp:978
#5 0x00554c48 in asio/ssl/detail/io.hpp:47
#6 0x00553bd4 in boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::--Type <RET> for more, q to quit, c to continue without paging--
asio::any_io_executor> >::shutdown (this=0x61a6f0, ec=...)
at /opt/arm-buildroot-linux-gnueabihf_sdk-buildroot/arm-buildroot-linux-gnueabihf/sysroot/usr/include/boost/asio/ssl/stream.hpp:562
#7 0x00550c50 in mqtt::tcp_endpoint<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::any_io_executor> >, boost::asio::strand<boost::asio::io_context::basic_executor_type<std::allocator<void>, 0u> > >::shutdown_and_close_impl (this=0x61a6e8, s=..., ec=...)
at ./mqtt/tcp_endpoint.hpp:171
#8 0x0054d2d8 in mqtt::tcp_endpoint<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::any_io_executor> >, boost::asio::strand<boost::asio::io_context::basic_executor_type<std::allocator<void>, 0u> > >::clean_shutdown_and_close (this=0x61a6e8, ec=...)
at ./mqtt/tcp_endpoint.hpp:102
#9 0x004822d8 in mqtt::endpoint<std::mutex, std::lock_guard, 2u>::sync_shutdown (this=0x5efdd0, s=...)
at ./mqtt/endpoint.hpp:5319
#10 0x00488624 in mqtt::endpoint<std::mutex, std::lock_guard, 2u>::force_disconnect (this=0x5efdd0)
at ./mqtt/endpoint.hpp:1103
#11 0x004807c0 in mqtt::endpoint<std::mutex, std::lock_guard, 2u>::set_pingresp_timer()::{lambda(boost::system::error_code)#1}::operator()(boost::system::error_code) const::{lambda()#1}::operator()() const (
this=0x60af80) at ./mqtt/endpoint.hpp:11543
#12 0x004a340c in std::_Function_handler<void (), mqtt::endpoint<std::mutex, std::lock_guard, 2u>::set_pingresp_timer()::{lambda(boost::system::error_code)#1}::operator()(boost::system::error_code) const::{lambda()#1}>::_M_invoke(std::_Any_data const&) (__functor=...)
at /opt/arm-buildroot-linux-gnueabihf_sdk-buildroot/arm-buildroot-linux-gnueabihf/include/c++/8.3.0/b--Type <RET> for more, q to quit, c to continue without paging--
its/std_function.h:297
I read the code of boost according to above backtrace.(the version of boost is boost_1_78_0). I found mqtt client is blocked at boost/asio/detail/impl/socket_ops.ipp:894.
// Wait for socket to become ready.
if (socket_ops::poll_read(s, 0, -1, ec) < 0)
because I have paused the broker , and the timeout is set to -1 to wait forever. so poll_read would never return.
Metadata
Metadata
Assignees
Labels
No labels