Why does async_connect() call listen()?
Hi there, By coincidence, I ended up looking at a stack trace where my application calls async_connect() on a asio::ip::tcp::socket. Two things took me by surprise: 1. Asio calls listen() under the hood. Why does it do that when I'm just trying to make an outbound TCP connection? 2. If the listen() call above is indeed required, why does it happen on the same thread where I call async_connect()? I thought the point of the method was to defer the work to the reactor? (For what it's worth, I've had a case on a customer's machine where the call to listen() would hang for 30 seconds before returning -- probably because of a bad firewall -- causing my entire app to hang since the code assumes async_connect() is indeed async.) I've included the full stack trace below. Thanks, Soren 0:000> k ChildEBP RetAddr 0117db50 0f681c65 WS2_32!listen 0117db70 0f691013 EvoClr!boost::asio::detail::socket_ops::listen+0x35 [c:\private\src\vendor\boost_1_55_0_sdk\include\boost\asio\detail\impl\socket_ops.ipp @ 658] 0117dbd8 0f690e9f EvoClr!boost::asio::detail::socket_select_interrupter::open_descriptors+0x163 [c:\private\src\vendor\boost_1_55_0_sdk\include\boost\asio\detail\impl\socket_select_interrupter.ipp @ 78] 0117dbe4 0f690cc0 EvoClr!boost::asio::detail::socket_select_interrupter::socket_select_interrupter+0xf [c:\private\src\vendor\boost_1_55_0_sdk\include\boost\asio\detail\impl\socket_select_interrupter.ipp @ 42] 0117dc1c 0f690c1e EvoClr!boost::asio::detail::select_reactor::select_reactor+0x70 [c:\private\src\vendor\boost_1_55_0_sdk\include\boost\asio\detail\impl\select_reactor.ipp @ 48] 0117dc44 0f17837e EvoClr!boost::asio::detail::service_registry::create<boost::asio::detail::select_reactor>+0x4e [c:\private\src\vendor\boost_1_55_0_sdk\include\boost\asio\detail\impl\service_registry.hpp @ 81] 0117dc80 0f6909e9 EvoClr!boost::asio::detail::service_registry::do_use_service+0x9e [c:\private\src\vendor\boost_1_55_0_sdk\include\boost\asio\detail\impl\service_registry.ipp @ 123] 0117dca0 0f6908ee EvoClr!boost::asio::detail::service_registry::use_service<boost::asio::detail::select_reactor>+0x39 [c:\private\src\vendor\boost_1_55_0_sdk\include\boost\asio\detail\impl\service_registry.hpp @ 49] 0117dca8 0f68fab0 EvoClr!boost::asio::use_service<boost::asio::detail::select_reactor>+0xe [c:\private\src\vendor\boost_1_55_0_sdk\include\boost\asio\impl\io_service.hpp @ 34] 0117dcbc 0f68f731 EvoClr!boost::asio::detail::win_iocp_socket_service_base::get_reactor+0x30 [c:\private\src\vendor\boost_1_55_0_sdk\include\boost\asio\detail\impl\win_iocp_socket_service_base.ipp @ 620] 0117dce4 0f68f6f1 EvoClr!boost::asio::detail::win_iocp_socket_service_base::start_connect_op+0x11 [c:\private\src\vendor\boost_1_55_0_sdk\include\boost\asio\detail\impl\win_iocp_socket_service_base.ipp @ 550] 0117dd28 0f68ed22 EvoClr!boost::asio::detail::win_iocp_socket_service<boost::asio::ip::tcp>::async_connect<boost::_bi::bind_t<void,boost::_mfi::mf1<void,Swift::BoostConnection,boost::system::error_code const &>,boost::_bi::list2<boost::_bi::value<boost::shared_ptr<Swift::BoostConnection>
,boost::arg<1> > > >+0xc1 [c:\private\src\vendor\boost_1_55_0_sdk\include\boost\asio\detail\win_iocp_socket_service.hpp @ 515] 0117dd68 0f68c41a EvoClr!boost::asio::stream_socket_service<boost::asio::ip::tcp>::async_connect<boost::_bi::bind_t<void,boost::_mfi::mf1<void,Swift::BoostConnection,boost::system::error_code const &>,boost::_bi::list2<boost::_bi::value<boost::shared_ptr<Swift::BoostConnection> ,boost::arg<1> > > >+0x52 [c:\private\src\vendor\boost_1_55_0_sdk\include\boost\asio\stream_socket_service.hpp @ 234] 0117ddec 0f68a32e EvoClr!boost::asio::basic_socket<boost::asio::ip::tcp,boost::asio::stream_socket_service<boost::asio::ip::tcp> ::async_connect<boost::_bi::bind_t<void,boost::_mfi::mf1<void,Swift::BoostConnection,boost::system::error_code const &>,boost::_bi::list2<boost::_bi::value<boost::shared_ptr<Swift::BoostConnection> ,boost::arg<1> > > >+0x11a [c:\private\src\vendor\boost_1_55_0_sdk\include\boost\asio\basic_socket.hpp @ 779] 0117de9c 0f210146 EvoClr!Swift::BoostConnection::connect+0x11e [c:\private\src\vendor\swift\swiften\network\boostconnection.cpp @ 70]
"Soren Dreijer" <dreijer@echobit.net> wrote:
By coincidence, I ended up looking at a stack trace where my application calls async_connect() on a asio::ip::tcp::socket. Two things took me by surprise:
1. Asio calls listen() under the hood. Why does it do that when I'm just trying to make an outbound TCP connection?
The call is made by the class socket_select_interrupter. The socket it is calling listen() on is an internal one bound to 127.0.0.1. If a firewall interferes with that then the firewall is horribly bugged. I believe the socket is set up so that a thread that is blocking on a call to ::select() (for example in io_service::run()), can be interrupted from another thread. This interruption is probably used when io_service::stop() is called for example.
2. If the listen() call above is indeed required, why does it happen on the same thread where I call async_connect()? I thought the point of the method was to defer the work to the reactor?
It only has to defer work that would block or that the documentation explicitly promises it will defer. Regards Niklas Angare
Thanks for the clarification Niklas. I'll have to dig deeper and figure out what's blocking the listen() call on these machines. On Tue, May 20, 2014 at 2:34 PM, Niklas Angare <li51ckf02@sneakemail.com>wrote:
"Soren Dreijer" <dreijer@echobit.net> wrote:
By coincidence, I ended up looking at a stack trace where my application calls async_connect() on a asio::ip::tcp::socket. Two things took me by surprise:
1. Asio calls listen() under the hood. Why does it do that when I'm just trying to make an outbound TCP connection?
The call is made by the class socket_select_interrupter. The socket it is calling listen() on is an internal one bound to 127.0.0.1. If a firewall interferes with that then the firewall is horribly bugged. I believe the socket is set up so that a thread that is blocking on a call to ::select() (for example in io_service::run()), can be interrupted from another thread. This interruption is probably used when io_service::stop() is called for example.
2. If the listen() call above is indeed required, why does it happen on
the same thread where I call async_connect()? I thought the point of the method was to defer the work to the reactor?
It only has to defer work that would block or that the documentation explicitly promises it will defer.
Regards
Niklas Angare
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
I don't see why it is necessary in this case, since the calling thread is not doing work that needs to be interrupted in case of calling io_service::stop. On Tue, May 20, 2014 at 9:49 PM, Soren Dreijer <dreijer+list@echobit.net> wrote:
Thanks for the clarification Niklas. I'll have to dig deeper and figure out what's blocking the listen() call on these machines.
On Tue, May 20, 2014 at 2:34 PM, Niklas Angare <li51ckf02@sneakemail.com> wrote:
"Soren Dreijer" <dreijer@echobit.net> wrote:
By coincidence, I ended up looking at a stack trace where my application calls async_connect() on a asio::ip::tcp::socket. Two things took me by surprise:
1. Asio calls listen() under the hood. Why does it do that when I'm just trying to make an outbound TCP connection?
The call is made by the class socket_select_interrupter. The socket it is calling listen() on is an internal one bound to 127.0.0.1. If a firewall interferes with that then the firewall is horribly bugged. I believe the socket is set up so that a thread that is blocking on a call to ::select() (for example in io_service::run()), can be interrupted from another thread. This interruption is probably used when io_service::stop() is called for example.
2. If the listen() call above is indeed required, why does it happen on
the same thread where I call async_connect()? I thought the point of the method was to defer the work to the reactor?
It only has to defer work that would block or that the documentation explicitly promises it will defer.
Regards
Niklas Angare
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
"Nathaniel Fries" <nfries88@gmail.com> wrote:
Niklas Angare <li51ckf02@sneakemail.com> wrote:
"Soren Dreijer" <dreijer@echobit.net> wrote:
1. Asio calls listen() under the hood. Why does it do that when I'm just trying to make an outbound TCP connection?
The call is made by the class socket_select_interrupter. The socket it is calling listen() on is an internal one bound to 127.0.0.1. I believe the socket is set up so that a thread that is blocking on a call to ::select() (for example in io_service::run()), can be interrupted from another thread. This interruption is probably used when io_service::stop() is called for example.
I don't see why it is necessary in this case, since the calling thread is not doing work that needs to be interrupted in case of calling io_service::stop.
Soren said only that he calls async_connect(). Imagine he then calls io_service::run(). That thread is now blocked in a call to ::select() waiting for the connect to finish. If another thread then did anything with that io_service, such as another async call or indeed stop(), the original thread would have to be interrupted somehow. Regards, Niklas Angare
participants (4)
-
Nathaniel Fries
-
Niklas Angare
-
Soren Dreijer
-
Soren Dreijer