0

I have a very simple class working with the boost::asio::ip::tcp::socket which offers this simple interface:

class SimpleClient{
    //private
        boost::scoped_ptr<boost::asio::ip::tcp::socket> signal_socket; 
    protected: 
        ClientState state; //0: Ready to be used, not connected,  -1: error, 1: Connected/active, 
    public: 
       SimpleClient();
       virtual bool connect(const char* ip_address);
       virtual void disconnect();
       virtual bool sendMessage(const char* msg, int length);
       virtual int getSignalData( char* msg, int length);
       virtual ClientState getState();
};

I'm trying to test the connect functionalities using boost.test but the test seems to crash before completion:

#define BOOST_AUTO_TEST_MAIN 
#define BOOST_TEST_DYN_LINK

#include "SimpleClient.hpp"
#include <boost/test/unit_test.hpp>

#include <string.h>

#define TARGET_IP "127.0.0.1"
#define BAD_IP "128.0.0.1"

BOOST_AUTO_TEST_CASE(basis_constructor_test){
    SimpleClient* ut = new SimpleClient();
    BOOST_CHECK_EQUAL(ut->getState(), ClientState::CL_READY);
    delete ut;
}


BOOST_AUTO_TEST_CASE(connection_test)  {
    bool ret;
    SimpleClient* ut = new SimpleClient();
    BOOST_CHECK_EQUAL(ut->getState(), ClientState::CL_UNCON);
    ret = ut->connect(BAD_IP);
    BOOST_CHECK(!ret);
    ret = ut->connect(TARGET_IP);
    std::cout<<"HEY3"<<std::endl;
    BOOST_CHECK(ret);
    std::cout<<"HEY4"<<std::endl<<"VAL "<<ret<<std::endl ;
    ut->disconnect();
    std::cout<<"HEY5"<<std::endl;
    try{
        delete ut;
    }
    catch(const std::exception& ex) {
        std::cout<<ex.what()<<std::endl;
    }
    catch(...) {
        std::cerr<<"ERROR NOT RECOGNIZED"<<std::endl;
    }
} 

This test gives this output, and does not give the usual summary that boost.test produces:

HEY0 HEY1 HEY2 HEY3 HEY4 VAL 1

For completeness I include the code of the constructor and the connect method:

SimpleClient::SimpleClient() {
    cmd_socket.reset();
    signal_socket.reset();
    status_socket.reset();
    state = ClientState::CL_UNCON;
}

bool SimpleClient::connect(const char* ip_address) {
    boost::asio::io_context io_context;
    boost::system::error_code ec;
    if (signal_socket != NULL && signal_socket->is_open() )
        return true;
    try {
        boost::asio::ip::tcp::endpoint signal_endpoint(boost::asio::ip::make_address(ip_address), OE_SIGNAL_PORT);
        boost::asio::socket_base::reuse_address option(true);
        signal_socket.reset(new boost::asio::ip::tcp::socket(io_context, signal_endpoint));
        
        signal_socket->set_option(option, ec);
        if(ec)
            std::cout<<ec.message()<<std::endl;
        signal_socket->connect(signal_endpoint, ec);
        std::cout<<"HEY0"<<std::endl;
        if(ec) {
            std::cout<<ec.message()<<ec.value()<<std::endl;
            return false;
        }
        std::cout<<"HEY1"<<std::endl;
    } catch(...) {//catch(const boost::system::system_error& ex) {
        std::cout<<"System Error: "<<std::endl;//<<ex.code()<<ip_address<<std::endl;
        return false;
    }
    std::cout<<"HEY2"<<std::endl;
    state = ClientState::CL_READY;
    return true;
}
void SimpleClient::disconnect() {
    if(signal_socket!=NULL && signal_socket->is_open()) {
        signal_socket->shutdown(boost::asio::socket_base::shutdown_both);
        signal_socket->close();
        signal_socket.reset();
    }
    state = ClientState::CL_UNCON;
}

This seems to be linked to the delete of the SimpleClient object, is there any operation that I should do before destroying a smart-pointer or before destroying a connected socket?

P.S. the application does not crash with any message and does not produce any dump or log files. I know that it does not complete correctly since the test report that boost.test generates on the console is not printed

Gionata Benelli
  • 357
  • 1
  • 3
  • 20
  • 4
    It doesn't seem to have anything to do with boost smart pointer (why don't you use `std::unique_ptr` ?). Check the stacktrace with your debugger. Most likely some issue with active socket being destroyed, but hard to tell without [mcve](https://stackoverflow.com/help/minimal-reproducible-example). – pptaszni Nov 17 '21 at 16:23
  • 2
    BTW, `SimpleClient* ut = new SimpleClient();` can be `SimpleClient ut;`, so no `delete`. – Jarod42 Nov 17 '21 at 16:51
  • Please provide a callstack of crashed thread. – Marek R Nov 17 '21 at 16:53
  • 2
    `boost::asio::ip::tcp::socket` (the managed class) can throw on destruction - _"...The guarantee that [`scoped_ptr`] does not throw exceptions depends on the requirement that the deleted object's destructor does not throw exceptions...."_ https://www.boost.org/doc/libs/1_62_0/libs/smart_ptr/scoped_ptr.htm The destructor (of `boost::asio::ip::tcp::socket`) calls `cancel` and this can throw https://www.boost.org/doc/libs/1_66_0/doc/html/boost_asio/reference/basic_stream_socket/cancel/overload1.html – Richard Critten Nov 17 '21 at 16:58
  • I suppose that it is something linked to the socket connection too, I tried to close the socket and it is still not working. – Gionata Benelli Nov 18 '21 at 10:03

0 Answers0