1

I have a library which communicates with TCP and UDP sockets using boost::asio. This library is cross-platform and delegates some operations to the application using it via callbacks. In the case of sockets, the following must occur:

  1. Library opens a socket (for an outbound connection).
  2. Application receives a callback allowing it to customise behaviour
  3. Library connects a socket and uses it
  4. Application receives a callback allowing it to do any necessary cleanup
  5. Library closes the socket

Here's how I thought I can achieve this:

class CustomizableTcpSocket {
public:
  template <typename T, typename U>
  auto async_connect(T&& endpoint, U&& handler) {
    boost::system::error_code ec;
    socket_.open(endpoint.protocol(), ec);
    native_code_.socket_did_open(socket_.native_handle());
    return socket_.async_connect(std::forward<U>(handler));
  }

  // same for async_write_some as well
  template <typename... Args>
  auto async_read_some(Args&&... args) {
    return socket_.async_read_some(std::forward<Args>(args)...);
  }

  ~CustomizableTcpSocket() {
    if (socket_.is_open()) {
      native_code_.socket_will_close(socket_.native_handle());
    }
  }

private:
  NativeCode native_code_;
  boost::asio::ip::tcp::socket socket_;
};

What I'm finding is that asio is sometimes closing the socket (at the OS level) before my destructor fires.

Is there a way I can be notified of a socket closing before asio actually does it?

  • I would suggest go through the documentation thoroughly. https://stackoverflow.com/questions/818665/how-to-check-if-socket-is-closed-in-boost-asio may help. – Yogesh May 27 '19 at 11:52

1 Answers1

1

ASIO has a debugging feature called handler tracking.

You could use it to intercept socket closures which are invoked as:

  BOOST_ASIO_HANDLER_OPERATION((reactor_.context(), "socket", &impl, impl.socket_, "close"));

Just #define BOOST_ASIO_HANDLER_OPERATION(...) to whatever function you want called and in there check that arg 5 == "close".

Here's an example of how to use handler tracking.

For reference: the actual close() operation is not straightforward. Better to leave that as it is.

rustyx
  • 80,671
  • 25
  • 200
  • 267
  • Thank you, so far this appears to be exactly what I need! Word of warning to anyone else doing this: It changes the class hierarchy of things inside `boost/asio` - define the macro using `-DBOOST_ASIO_CUSTOM_HANDLER_TRACKING="myheader.hpp"` else you'll end up with memory corruption in any place that doesn't have that macro defined before including boost. – Silvija Ida May 28 '19 at 09:13