Fix implementation of asynchronous connect operation so that it can cope with spurious readiness notifications from the reactor.
diff --git a/asio/include/asio/detail/impl/socket_ops.ipp b/asio/include/asio/detail/impl/socket_ops.ipp index aaf93ab..51fbdde 100644 --- a/asio/include/asio/detail/impl/socket_ops.ipp +++ b/asio/include/asio/detail/impl/socket_ops.ipp
@@ -507,8 +507,19 @@ asio::error::get_system_category()); } -bool non_blocking_connect(socket_type s, asio::error_code& ec) +bool non_blocking_connect(socket_type s, + const socket_addr_type* addr, std::size_t addrlen, + asio::error_code& ec) { + // Check if the connect operation has finished. This is required since we may + // get spurious readiness notifications from the reactor. + socket_ops::connect(s, addr, addrlen, ec); + if (ec == asio::error::already_started) + { + // The asynchronous connect operation is still in progress. + return false; + } + // Get the error code from the connect operation. int connect_error = 0; size_t connect_error_len = sizeof(connect_error);
diff --git a/asio/include/asio/detail/reactive_socket_connect_op.hpp b/asio/include/asio/detail/reactive_socket_connect_op.hpp index 65f140a..7eeb049 100644 --- a/asio/include/asio/detail/reactive_socket_connect_op.hpp +++ b/asio/include/asio/detail/reactive_socket_connect_op.hpp
@@ -28,12 +28,15 @@ namespace asio { namespace detail { +template <typename Protocol> class reactive_socket_connect_op_base : public reactor_op { public: - reactive_socket_connect_op_base(socket_type socket, func_type complete_func) + reactive_socket_connect_op_base(socket_type socket, + const typename Protocol::endpoint& peer_endpoint, func_type complete_func) : reactor_op(&reactive_socket_connect_op_base::do_perform, complete_func), - socket_(socket) + socket_(socket), + peer_endpoint_(peer_endpoint) { } @@ -42,21 +45,25 @@ reactive_socket_connect_op_base* o( static_cast<reactive_socket_connect_op_base*>(base)); - return socket_ops::non_blocking_connect(o->socket_, o->ec_); + return socket_ops::non_blocking_connect(o->socket_, + o->peer_endpoint_.data(), o->peer_endpoint_.size(), o->ec_); } private: socket_type socket_; + typename Protocol::endpoint peer_endpoint_; }; -template <typename Handler> -class reactive_socket_connect_op : public reactive_socket_connect_op_base +template <typename Protocol, typename Handler> +class reactive_socket_connect_op : + public reactive_socket_connect_op_base<Protocol> { public: ASIO_DEFINE_HANDLER_PTR(reactive_socket_connect_op); - reactive_socket_connect_op(socket_type socket, Handler& handler) - : reactive_socket_connect_op_base(socket, + reactive_socket_connect_op(socket_type socket, + const typename Protocol::endpoint& peer_endpoint, Handler& handler) + : reactive_socket_connect_op_base<Protocol>(socket, peer_endpoint, &reactive_socket_connect_op::do_complete), handler_(ASIO_MOVE_CAST(Handler)(handler)) {
diff --git a/asio/include/asio/detail/reactive_socket_service.hpp b/asio/include/asio/detail/reactive_socket_service.hpp index c786733..4ef4b3f 100644 --- a/asio/include/asio/detail/reactive_socket_service.hpp +++ b/asio/include/asio/detail/reactive_socket_service.hpp
@@ -421,11 +421,11 @@ asio_handler_cont_helpers::is_continuation(handler); // Allocate and construct an operation to wrap the handler. - typedef reactive_socket_connect_op<Handler> op; + typedef reactive_socket_connect_op<Protocol, Handler> op; typename op::ptr p = { asio::detail::addressof(handler), asio_handler_alloc_helpers::allocate( sizeof(op), handler), 0 }; - p.p = new (p.v) op(impl.socket_, handler); + p.p = new (p.v) op(impl.socket_, peer_endpoint, handler); ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_connect"));
diff --git a/asio/include/asio/detail/socket_ops.hpp b/asio/include/asio/detail/socket_ops.hpp index 000a88b..67450ed 100644 --- a/asio/include/asio/detail/socket_ops.hpp +++ b/asio/include/asio/detail/socket_ops.hpp
@@ -105,8 +105,9 @@ ASIO_DECL void sync_connect(socket_type s, const socket_addr_type* addr, std::size_t addrlen, asio::error_code& ec); -ASIO_DECL bool non_blocking_connect( - socket_type s, asio::error_code& ec); +ASIO_DECL bool non_blocking_connect(socket_type s, + const socket_addr_type* addr, std::size_t addrlen, + asio::error_code& ec); ASIO_DECL int socketpair(int af, int type, int protocol, socket_type sv[2], asio::error_code& ec);
diff --git a/asio/include/asio/detail/win_iocp_socket_service.hpp b/asio/include/asio/detail/win_iocp_socket_service.hpp index 43e42d1..8247421 100644 --- a/asio/include/asio/detail/win_iocp_socket_service.hpp +++ b/asio/include/asio/detail/win_iocp_socket_service.hpp
@@ -483,11 +483,11 @@ const endpoint_type& peer_endpoint, Handler& handler) { // Allocate and construct an operation to wrap the handler. - typedef reactive_socket_connect_op<Handler> op; + typedef reactive_socket_connect_op<Protocol, Handler> op; typename op::ptr p = { asio::detail::addressof(handler), asio_handler_alloc_helpers::allocate( sizeof(op), handler), 0 }; - p.p = new (p.v) op(impl.socket_, handler); + p.p = new (p.v) op(impl.socket_, peer_endpoint, handler); ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_connect"));