Skip to content

when I disable broker, client which use set_pingresp_timeout(2s) would block in force_disconnect() for more than 30 minutes. #976

@ForrestGt

Description

@ForrestGt

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

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions