DEEPANSH NAGARIA
DEEPANSH NAGARIA

Reputation: 113

Boost Asio async connect resetting local endpoint bind

I am using boost beast WebSocket, and trying to bind it locally to a particular interface via bind, the bind happens(reflected in log), but in async connect handler I see some other endpoint (default interface), instead of the local one. Why can this be happening?

        boost::optional<boost::beast::websocket::stream<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>>> stream_;
        boost::asio::socket_base::reuse_address option(true);
        stream_->next_layer().next_layer().open(boost::asio::ip::tcp::v4());
        stream_->next_layer().next_layer().set_option(option); 
        stream_->next_layer().next_layer().bind(boost::asio::ip::tcp::endpoint(
            boost::asio::ip::address::from_string(interface_), 0));

        auto local_endpoint = stream_->next_layer().next_layer().local_endpoint();
        LOG("WS session:", session_id_, " from:", local_endpoint.address().to_string(),
            local_endpoint.port(), interface_, stream_->next_layer().next_layer().native_handle());

here the logging is correct.

boost::asio::async_connect( stream_->next_layer().next_layer(), res.begin(), res.end(), boost::bind(&WebSocketSession::on_connect, this, boost::asio::placeholders::error) );

post this, in the handler (on_connect) the bind seems to be resetted to some other interface(default interface of the machine).

void on_connect(const boost::system::error_code& error) { auto tp = language::datetime::clock_realtime(); auto local_endpoint = stream_->next_layer().next_layer().local_endpoint(); LOG("WS session: on_connect from:", local_endpoint.address().to_string(), local_endpoint.port(),interface_,stream_->next_layer().next_layer().is_open(), stream_->next_layer().next_layer().native_handle());

In both cases is_open is logged as true and the native file descriptor is also same in both

Upvotes: 0

Views: 393

Answers (1)

MountainLovers
MountainLovers

Reputation: 1

I basically have a same problem. I noticed that there are a lots of answers said asio::connect() static method will close the opened socket and re-open it. So the socket binded IP was closed and the new socket is set to default.

Link: ans1 ans2

I guess async_connect() static method is similar. So I check the connect.hpp file:

template <typename Protocol, typename SocketService, typename Iterator,
    typename ConnectCondition, typename ComposedConnectHandler>
inline BOOST_ASIO_INITFN_RESULT_TYPE(ComposedConnectHandler,
    void (boost::system::error_code, Iterator))
async_connect(basic_socket<Protocol, SocketService>& s,
    Iterator begin, Iterator end, ConnectCondition connect_condition,
    BOOST_ASIO_MOVE_ARG(ComposedConnectHandler) handler)
{
  // If you get an error on the following line it means that your handler does
  // not meet the documented type requirements for a ComposedConnectHandler.
  BOOST_ASIO_COMPOSED_CONNECT_HANDLER_CHECK(
      ComposedConnectHandler, handler, Iterator) type_check;

  detail::async_result_init<ComposedConnectHandler,
    void (boost::system::error_code, Iterator)> init(
      BOOST_ASIO_MOVE_CAST(ComposedConnectHandler)(handler));

  detail::connect_op<Protocol, SocketService, Iterator,
    ConnectCondition, BOOST_ASIO_HANDLER_TYPE(
      ComposedConnectHandler, void (boost::system::error_code, Iterator))>(s,
        begin, end, connect_condition, init.handler)(
          boost::system::error_code(), 1);

  return init.result.get();
}

Actually it calls detail::connect_op:

    void operator()(boost::system::error_code ec, int start = 0)
    {
      switch (start_ = start)
      {
        case 1:
        for (;;)
        {
          this->check_condition(ec, iter_, end_);

          if (iter_ != end_)
          {
            socket_.close(ec);   // <---- HERE!
            socket_.async_connect(*iter_,
                BOOST_ASIO_MOVE_CAST(connect_op)(*this));
            return;
          }

          if (start)
          {
            ec = boost::asio::error::not_found;
            socket_.get_io_service().post(detail::bind_handler(*this, ec));
            return;
          }

In summary, please use socket.async_connect() instead of asio::async_connect().

Upvotes: 0

Related Questions