Boost logo

Boost Users :

From: Maria Tirindelli (maria.tirindelli_at_[hidden])
Date: 2024-03-06 12:42:44


I am experiencing an issue with boost 1.74 on linux. I am trying to have a server that asynchronously reads data from a tcp socket, and then closes when the client disconnect. My code looks like:


class SimpleTCPServerTest::SocketHandler {
public:
    explicit SocketHandler(boost::asio::ip::tcp::socket inputSocket
    ) : socket(std::move(inputSocket)) {
        socket.set_option(boost::asio::socket_base::keep_alive(true));
    }

    boost::asio::ip::tcp::socket socket;

};


SimpleTCPServerTest::SimpleTCPServerTest(std::string address, int port) :
        m_address(std::move(address)), m_port(port), m_ioc(boost::asio::io_context(1)),
        m_acceptor(boost::asio::ip::tcp::acceptor(m_ioc)),
        readTimer(m_ioc){

    std::vector<char> buffer_data(1024);
    this->m_buffer = boost::asio::buffer(buffer_data);

}

bool SimpleTCPServerTest::open() {

    //auto const address = boost::asio::ip::make_address(ip);
    boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), static_cast<unsigned short>(m_port));

    boost::system::error_code ec;

    // Open the acceptor
    m_acceptor.open(endpoint.protocol(), ec);
    if (ec) {
        LOG_ERROR("SimpleTCPServerTest", "Failed to open acceptor: " << ec.message());
        return false;
    }

    // Allow address reuse
    m_acceptor.set_option(boost::asio::socket_base::reuse_address(true), ec);
    if (ec) {
        LOG_ERROR("SimpleTCPServerTest", "Failed to set reuse option in acceptor: " << ec.message());
        return false;
    }

    // Bind to the server address
    m_acceptor.bind(endpoint, ec);
    if (ec) {
        LOG_ERROR("SimpleTCPServerTest", "Failed to bind acceptor: " << ec.message());
        return false;
    }

    // Start listening for connections
    m_acceptor.listen(boost::asio::socket_base::max_listen_connections, ec);
    if (ec) {
        LOG_ERROR("SimpleTCPServerTest", "acceptor failed to start listening: " << ec.message());
        return false;
    }

    m_acceptor.async_accept(boost::asio::make_strand(m_ioc),
                            [this](boost::system::error_code ec, boost::asio::ip::tcp::socket socket) {
                                on_accept(ec, std::move(socket));
                            });

    m_iocRunThread = boost::thread([this] {
        m_ioc.run();
      LOG_INFO("Exiting run thread");
    });

    return true;
}

}

void SimpleTCPServerTest::on_accept(boost::system::error_code ec, boost::asio::ip::tcp::socket socket) {

    LOG_INFO("Client is connected");
    m_socketHandler = std::make_unique<SocketHandler>(std::move(socket));

    read();

}

void SimpleTCPServerTest::read() {

   LOG_INFO("SimpleTCPServerTest", "Waiting a new message");
   readTimer.expires_from_now(boost::posix_time::milliseconds(50));
   readTimer.async_wait([this](boost::system::error_code ec) {
       LOG_INFO("Timer expired");
       if (ec != boost::asio::error::operation_aborted)
           return;

       LOG_INFO("Timer expired with error");
       m_socketHandler->socket.cancel(); });

   m_socketHandler->socket.async_read_some(m_buffer,

                           [this](const boost::system::error_code error, // Result of operation.
                                  std::size_t bytes_transferred) {


                               if (error)
                               {
                                   LOG_INFO("Client disconnected: " << error.message());
                                   signalReadyToStop.emitSignal();

                                    // HERE IT CRASHES
                                   return;
                               }

                               std::string dataString(boost::asio::buffer_cast<const char*>(m_buffer), bytes_transferred);
                               LOG_INFO("Data was received: Size: " << bytes_transferred << " " << dataString);

                               // Reset the buffer
                               std::vector<char> buffer_data(1024);
                               this->m_buffer = boost::asio::buffer(buffer_data);

                               this->read();
                           });
}

SimpleTCPServerTest::~SimpleTCPServerTest() {
   LOG_INFO("Terminating");

   readTimer.cancel();
   m_acceptor.cancel();
   m_socketHandler->socket.cancel();
   m_ioc.stop();
   m_iocRunThread.join();

}

The client is a simple python client that sends a few messages before disconnecting. my main.cpp is like:

std::atomic<bool> m_runFlag = true;

    SimpleTCPServerTest server;
    server.signalReadyToStop.connect([&m_runFlag](){
        m_runFlag =false;
        });

    server.open();

    while(m_runFlag)
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    }
    LOG_INFO("Exiting test");
}

The problem is that the code always crashes when returning from the async_read (indicated with "HERE IT CRASHES COMMENT") with error SIGABRT tcache_thread_shutdown(): unaligned tcache chunk detected. Even if I remove the return statement there, I still have the crash when calling m_ioc.stop(). It seems the error occurs when exiting from the m_iocRunThread (the "Exiting run thread" log is executed)

What am I doing wrong?

Thanks everyone



Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net