lundi 25 mai 2020

Boost asio resolver is unitialized

I am finding it a bit silly to ask, to because the minimal example I am posting here works, but when I implement it as part of my project, I get a segfault. But I will still go ahead and ask.

Below is my code

#include <iostream>
#include <thread>
#include <boost/array.hpp>
#include <boost/asio.hpp>

using boost::asio::ip::tcp;
using boost::asio::ip::udp;

class Transport
{
public:
  virtual bool connect() = 0;
  virtual void disconnect() = 0;
  virtual void read(boost::array<char, 4096> &buf, size_t &len) = 0;

  Transport(std::string address) : address_(address) {}

  void set_port(std::string port)
  {
    port_ = std::move(port);
  }

  std::string get_port()
  {
    return port_;
  }

  std::string get_host_ip()
  {
    return host_ip_;
  }

protected:
  std::string address_;
  std::string host_ip_;
  std::string port_;
  boost::asio::io_service io_service_;
};

class TCPTransport : public Transport
{
public:
    TCPTransport(std::string address) : Transport(address), socket_(io_service_) {}

    ~TCPTransport()
    {
      disconnect();
    }

    virtual bool connect()
    {
      try
      {
        std::cout << "io_service " << io_service_.stopped() << std::endl;
        tcp::resolver resolver(io_service_);
        tcp::resolver::query query(address_, port_);
        tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
        tcp::resolver::iterator end;

        boost::system::error_code error = boost::asio::error::host_not_found;
        while (error && endpoint_iterator != end)
        {
          socket_.close();
          socket_.connect(*endpoint_iterator++, error);
        }
        if (error)
        {
          throw boost::system::system_error(error);
        }
      }
      catch (std::exception& e)
      {
        std::cerr << e.what() << std::endl;
        return false;
      }
      return true;
    }

    virtual void disconnect()
    {
      std::cout << "disconnecting..." << std::endl;
      socket_.close();
    }

    void read(boost::array<char, 4096> &buf, size_t &len)
    {
      boost::system::error_code error;
      len = socket_.read_some(boost::asio::buffer(buf), error);
      if (error == boost::asio::error::eof)
        return; // Connection closed cleanly by peer.
      else if (error)
        throw boost::system::system_error(error); // Some other error.
    }

private:
    tcp::socket socket_;
};

class Writer
{
public:
  Writer(std::shared_ptr<Transport> &transport) : transport_(transport) {}

  void connect()
  {
    transport_->connect();
  }

  void start_read()
  {
    while(true)
    {
      size_t len;
      boost::array<char, 4096> buf;
      transport_->read(buf, len);
      // std::cout.write(buf.data(), len);
      std::cout << len << std::endl;
    }
  }

private:
  std::shared_ptr<Transport> transport_;
};

class ConnectionHolder
{
public:
  ConnectionHolder(std::shared_ptr<Transport> &transport) : transport_(transport) {}

  void init()
  {
    std::this_thread::sleep_for(std::chrono::seconds(1));
    transport_->set_port("8000");
    transport_->connect();
    writer_ = std::make_shared<Writer>(transport_);
  }

  void start()
  {
    writer_->start_read();
  }

private:
  std::shared_ptr<Transport> transport_;
  std::shared_ptr<Writer> writer_;
};

int main(int argc, char* argv[])
{
  if (argc != 3)
  {
    std::cerr << "Usage: client <host>" << std::endl;
    return 1;
  }

  std::shared_ptr<Transport> transport = std::make_shared<TCPTransport>(argv[1]);
  ConnectionHolder holder(transport);
  // transport->set_port(argv[2]);
  holder.init();


  holder.start();

  return 0;
}

Before I create a TCP socket, I need to request for a TCP handle. Once done, I can start reading from the device. The code attached above works well. But in case of my actual code, valgrind complains with:

==18714== Invalid read of size 8
==18714==    at 0x4C367E0: memmove (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==18714==    by 0x12EDF1: boost::asio::ip::basic_resolver_iterator<boost::asio::ip::tcp>::create(addrinfo*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (basic_resolver_iterator.hpp:99)
==18714==    by 0x12C657: boost::asio::detail::resolver_service<boost::asio::ip::tcp>::resolve(std::shared_ptr<void>&, boost::asio::ip::basic_resolver_query<boost::asio::ip::tcp> const&, boost::system::error_code&) (resolver_service.hpp:69)
==18714==    by 0x12989F: boost::asio::ip::resolver_service<boost::asio::ip::tcp>::resolve(std::shared_ptr<void>&, boost::asio::ip::basic_resolver_query<boost::asio::ip::tcp> const&, boost::system::error_code&) (resolver_service.hpp:113)
==18714==    by 0x126A8B: boost::asio::ip::basic_resolver<boost::asio::ip::tcp, boost::asio::ip::resolver_service<boost::asio::ip::tcp> >::resolve(boost::asio::ip::basic_resolver_query<boost::asio::ip::tcp> const&) (basic_resolver.hpp:102)
==18714==    by 0x12290D: TCPTransport::connect() (communication.h:99)
==18714==    by 0x137E3D: Interface::start_transmission() (pf_interface.cpp:94)
==18714==    by 0x117843: main (main.cpp:36)
==18714==  Address 0x10fe3fc000000000 is not stack'd, malloc'd or (recently) free'd
==18714== 
==18714== 
==18714== Process terminating with default action of signal 11 (SIGSEGV)
==18714==  General Protection Fault
==18714==    at 0x4C367E0: memmove (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==18714==    by 0x12EDF1: boost::asio::ip::basic_resolver_iterator<boost::asio::ip::tcp>::create(addrinfo*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (basic_resolver_iterator.hpp:99)
==18714==    by 0x12C657: boost::asio::detail::resolver_service<boost::asio::ip::tcp>::resolve(std::shared_ptr<void>&, boost::asio::ip::basic_resolver_query<boost::asio::ip::tcp> const&, boost::system::error_code&) (resolver_service.hpp:69)
==18714==    by 0x12989F: boost::asio::ip::resolver_service<boost::asio::ip::tcp>::resolve(std::shared_ptr<void>&, boost::asio::ip::basic_resolver_query<boost::asio::ip::tcp> const&, boost::system::error_code&) (resolver_service.hpp:113)
==18714==    by 0x126A8B: boost::asio::ip::basic_resolver<boost::asio::ip::tcp, boost::asio::ip::resolver_service<boost::asio::ip::tcp> >::resolve(boost::asio::ip::basic_resolver_query<boost::asio::ip::tcp> const&) (basic_resolver.hpp:102)
==18714==    by 0x12290D: TCPTransport::connect() (communication.h:99)
==18714==    by 0x137E3D: Interface::start_transmission() (pf_interface.cpp:94)
==18714==    by 0x117843: main (main.cpp:36)
--18714-- Discarding syms at 0x112cb350-0x112d1d7f in /lib/x86_64-linux-gnu/libnss_files-2.27.so due to munmap()

Does this mean that io_service object doesn't exist anymore by the time I call connect? I don't get it, because I am using a shared_ptr. The transport.h is exactly the same, just that instead of main.cpp, I call connect from another class.

Edit 1: I added the following line in constructor of Transport.

 io_service_thread_ = boost::thread(boost::bind(&boost::asio::io_service::run, &io_service_));

But I get the same error!

Aucun commentaire:

Enregistrer un commentaire