Initial implementation of move-enable accept/async_accept. This commit adds support for the new form of accept and async_accept. In this form, rather than taking a socket by reference, the newly accepted socket is returned to the caller/callback as a movable socket object.
diff --git a/asio/include/asio/basic_socket_acceptor.hpp b/asio/include/asio/basic_socket_acceptor.hpp index 5e3109e..287652d 100644 --- a/asio/include/asio/basic_socket_acceptor.hpp +++ b/asio/include/asio/basic_socket_acceptor.hpp
@@ -1029,7 +1029,7 @@ * @code * asio::ip::tcp::acceptor acceptor(io_service); * ... - * asio::ip::tcp::soocket socket(io_service); + * asio::ip::tcp::socket socket(io_service); * asio::error_code ec; * acceptor.accept(socket, ec); * if (ec) @@ -1211,6 +1211,122 @@ return this->get_service().async_accept(this->get_implementation(), peer, &peer_endpoint, ASIO_MOVE_CAST(AcceptHandler)(handler)); } + +#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer. The function + * call will block until a new connection has been accepted successfully or + * an error occurs. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @returns A socket object representing the newly accepted connection. + * + * @throws asio::system_error Thrown on failure. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(io_service); + * ... + * asio::ip::tcp::socket socket(acceptor.accept()); + * @endcode + */ + typename Protocol::socket accept() + { + asio::error_code ec; + typename Protocol::socket peer( + this->get_service().accept( + this->get_implementation(), 0, 0, ec)); + asio::detail::throw_error(ec, "accept"); + return peer; + } + + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer. The function + * call will block until a new connection has been accepted successfully or + * an error occurs. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns On success, a socket object representing the newly accepted + * connection. On error, a socket object where is_open() is false. + * + * @par Example + * @code + * asio::ip::tcp::acceptor acceptor(io_service); + * ... + * asio::ip::tcp::socket socket(acceptor.accept(ec)); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + typename Protocol::socket accept(asio::error_code& ec) + { + return this->get_service().accept(this->get_implementation(), 0, 0, ec); + } + + /// Start an asynchronous accept. + /** + * This function is used to asynchronously accept a new connection. The + * function call always returns immediately. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param handler The handler to be called when the accept operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * typename Protocol::socket peer // On success, the newly accepted socket. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + * + * @par Example + * @code + * void accept_handler(const asio::error_code& error, + * asio::ip::tcp::socket peer) + * { + * if (!error) + * { + * // Accept succeeded. + * } + * } + * + * ... + * + * asio::ip::tcp::acceptor acceptor(io_service); + * ... + * asio::ip::tcp::socket socket(io_service); + * acceptor.async_accept(socket, accept_handler); + * @endcode + */ + template <typename MoveAcceptHandler> + ASIO_INITFN_RESULT_TYPE(MoveAcceptHandler, + void (asio::error_code, typename Protocol::socket)) + async_accept(ASIO_MOVE_ARG(MoveAcceptHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a MoveAcceptHandler. + ASIO_MOVE_ACCEPT_HANDLER_CHECK(MoveAcceptHandler, + handler, typename Protocol::socket) type_check; + + return this->get_service().async_accept(this->get_implementation(), + static_cast<endpoint_type*>(0), + ASIO_MOVE_CAST(MoveAcceptHandler)(handler)); + } +#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) }; } // namespace asio
diff --git a/asio/include/asio/detail/bind_handler.hpp b/asio/include/asio/detail/bind_handler.hpp index 7271a79..c01a7ac 100644 --- a/asio/include/asio/detail/bind_handler.hpp +++ b/asio/include/asio/detail/bind_handler.hpp
@@ -220,6 +220,132 @@ ASIO_MOVE_CAST(Handler)(handler), arg1, arg2); } +#if defined(ASIO_HAS_MOVE) + +template <typename Handler, typename Arg1> +class move_binder1 +{ +public: + move_binder1(int, ASIO_MOVE_ARG(Handler) handler, + ASIO_MOVE_ARG(Arg1) arg1) + : handler_(ASIO_MOVE_CAST(Handler)(handler)), + arg1_(ASIO_MOVE_CAST(Arg1)(arg1)) + { + } + + move_binder1(move_binder1&& other) + : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)), + arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)) + { + } + + void operator()() + { + handler_(ASIO_MOVE_CAST(Arg1)(arg1_)); + } + +//private: + Handler handler_; + Arg1 arg1_; +}; + +template <typename Handler, typename Arg1> +inline void* asio_handler_allocate(std::size_t size, + move_binder1<Handler, Arg1>* this_handler) +{ + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +} + +template <typename Handler, typename Arg1> +inline void asio_handler_deallocate(void* pointer, std::size_t size, + move_binder1<Handler, Arg1>* this_handler) +{ + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); +} + +template <typename Handler, typename Arg1> +inline bool asio_handler_is_continuation( + move_binder1<Handler, Arg1>* this_handler) +{ + return asio_handler_cont_helpers::is_continuation( + this_handler->handler_); +} + +template <typename Function, typename Handler, typename Arg1> +inline void asio_handler_invoke(ASIO_MOVE_ARG(Function) function, + move_binder1<Handler, Arg1>* this_handler) +{ + asio_handler_invoke_helpers::invoke( + ASIO_MOVE_CAST(Function)(function), this_handler->handler_); +} + +template <typename Handler, typename Arg1, typename Arg2> +class move_binder2 +{ +public: + move_binder2(int, ASIO_MOVE_ARG(Handler) handler, + const Arg1& arg1, ASIO_MOVE_ARG(Arg2) arg2) + : handler_(ASIO_MOVE_CAST(Handler)(handler)), + arg1_(arg1), + arg2_(ASIO_MOVE_CAST(Arg2)(arg2)) + { + } + + move_binder2(move_binder2&& other) + : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)), + arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)), + arg2_(ASIO_MOVE_CAST(Arg2)(other.arg2_)) + { + } + + void operator()() + { + handler_(static_cast<const Arg1&>(arg1_), + ASIO_MOVE_CAST(Arg2)(arg2_)); + } + +//private: + Handler handler_; + Arg1 arg1_; + Arg2 arg2_; +}; + +template <typename Handler, typename Arg1, typename Arg2> +inline void* asio_handler_allocate(std::size_t size, + move_binder2<Handler, Arg1, Arg2>* this_handler) +{ + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +} + +template <typename Handler, typename Arg1, typename Arg2> +inline void asio_handler_deallocate(void* pointer, std::size_t size, + move_binder2<Handler, Arg1, Arg2>* this_handler) +{ + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); +} + +template <typename Handler, typename Arg1, typename Arg2> +inline bool asio_handler_is_continuation( + move_binder2<Handler, Arg1, Arg2>* this_handler) +{ + return asio_handler_cont_helpers::is_continuation( + this_handler->handler_); +} + +template <typename Function, typename Handler, typename Arg1, typename Arg2> +inline void asio_handler_invoke(ASIO_MOVE_ARG(Function) function, + move_binder2<Handler, Arg1, Arg2>* this_handler) +{ + asio_handler_invoke_helpers::invoke( + ASIO_MOVE_CAST(Function)(function), this_handler->handler_); +} + +#endif // defined(ASIO_HAS_MOVE) + } // namespace detail template <typename Handler, typename Arg1, typename Allocator> @@ -270,6 +396,59 @@ } }; +#if defined(ASIO_HAS_MOVE) + +template <typename Handler, typename Arg1, typename Allocator> +struct associated_allocator<detail::move_binder1<Handler, Arg1>, Allocator> +{ + typedef typename associated_allocator<Handler, Allocator>::type type; + + static type get(const detail::move_binder1<Handler, Arg1>& h, + const Allocator& a = Allocator()) ASIO_NOEXCEPT + { + return associated_allocator<Handler, Allocator>::get(h.handler_, a); + } +}; + +template <typename Handler, typename Arg1, typename Arg2, typename Allocator> +struct associated_allocator< + detail::move_binder2<Handler, Arg1, Arg2>, Allocator> +{ + typedef typename associated_allocator<Handler, Allocator>::type type; + + static type get(const detail::move_binder2<Handler, Arg1, Arg2>& h, + const Allocator& a = Allocator()) ASIO_NOEXCEPT + { + return associated_allocator<Handler, Allocator>::get(h.handler_, a); + } +}; + +template <typename Handler, typename Arg1, typename Executor> +struct associated_executor<detail::move_binder1<Handler, Arg1>, Executor> +{ + typedef typename associated_executor<Handler, Executor>::type type; + + static type get(const detail::move_binder1<Handler, Arg1>& h, + const Executor& ex = Executor()) ASIO_NOEXCEPT + { + return associated_executor<Handler, Executor>::get(h.handler_, ex); + } +}; + +template <typename Handler, typename Arg1, typename Arg2, typename Executor> +struct associated_executor<detail::move_binder2<Handler, Arg1, Arg2>, Executor> +{ + typedef typename associated_executor<Handler, Executor>::type type; + + static type get(const detail::move_binder2<Handler, Arg1, Arg2>& h, + const Executor& ex = Executor()) ASIO_NOEXCEPT + { + return associated_executor<Handler, Executor>::get(h.handler_, ex); + } +}; + +#endif // defined(ASIO_HAS_MOVE) + } // namespace asio #include "asio/detail/pop_options.hpp"
diff --git a/asio/include/asio/detail/handler_type_requirements.hpp b/asio/include/asio/detail/handler_type_requirements.hpp index 8026278..e62596f 100644 --- a/asio/include/asio/detail/handler_type_requirements.hpp +++ b/asio/include/asio/detail/handler_type_requirements.hpp
@@ -100,6 +100,16 @@ template <typename Handler> char (&two_arg_handler_test(Handler, ...))[2]; +template <typename Handler, typename Arg1, typename Arg2> +auto two_arg_move_handler_test(Handler h, Arg1* a1, Arg2* a2) + -> decltype( + sizeof(Handler(ASIO_MOVE_CAST(Handler)(h))), + ((h)(*a1, ASIO_MOVE_CAST(Arg2)(*a2))), + char(0)); + +template <typename Handler> +char (&two_arg_move_handler_test(Handler, ...))[2]; + # define ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(expr, msg) \ static_assert(expr, msg); @@ -228,6 +238,33 @@ asio::detail::lvref<const asio::error_code>()), \ char(0))> ASIO_UNUSED_TYPEDEF +#define ASIO_MOVE_ACCEPT_HANDLER_CHECK( \ + handler_type, handler, socket_type) \ + \ + typedef ASIO_HANDLER_TYPE(handler_type, \ + void(asio::error_code, socket_type)) \ + asio_true_handler_type; \ + \ + ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(asio::detail::two_arg_move_handler_test( \ + asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast<const asio::error_code*>(0), \ + static_cast<socket_type*>(0))) == 1, \ + "MoveAcceptHandler type requirements not met") \ + \ + typedef asio::detail::handler_type_requirements< \ + sizeof( \ + asio::detail::argbyv( \ + asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + asio::detail::lvref< \ + asio_true_handler_type>()( \ + asio::detail::lvref<const asio::error_code>(), \ + asio::detail::rvref<socket_type>()), \ + char(0))> ASIO_UNUSED_TYPEDEF + #define ASIO_CONNECT_HANDLER_CHECK( \ handler_type, handler) \ \
diff --git a/asio/include/asio/detail/impl/reactive_socket_service_base.ipp b/asio/include/asio/detail/impl/reactive_socket_service_base.ipp index f6cf62a..7c262c2 100644 --- a/asio/include/asio/detail/impl/reactive_socket_service_base.ipp +++ b/asio/include/asio/detail/impl/reactive_socket_service_base.ipp
@@ -29,7 +29,8 @@ reactive_socket_service_base::reactive_socket_service_base( asio::io_service& io_service) - : reactor_(use_service<reactor>(io_service)) + : io_service_(io_service), + reactor_(use_service<reactor>(io_service)) { reactor_.init_task(); }
diff --git a/asio/include/asio/detail/reactive_socket_accept_op.hpp b/asio/include/asio/detail/reactive_socket_accept_op.hpp index ae6ca42..ea83190 100644 --- a/asio/include/asio/detail/reactive_socket_accept_op.hpp +++ b/asio/include/asio/detail/reactive_socket_accept_op.hpp
@@ -130,6 +130,70 @@ Handler handler_; }; +#if defined(ASIO_HAS_MOVE) + +template <typename Protocol, typename Handler> +class reactive_socket_move_accept_op : + private Protocol::socket, + public reactive_socket_accept_op_base<typename Protocol::socket, Protocol> +{ +public: + ASIO_DEFINE_HANDLER_PTR(reactive_socket_move_accept_op); + + reactive_socket_move_accept_op(io_service& ios, socket_type socket, + socket_ops::state_type state, const Protocol& protocol, + typename Protocol::endpoint* peer_endpoint, Handler& handler) + : Protocol::socket(ios), + reactive_socket_accept_op_base<typename Protocol::socket, Protocol>( + socket, state, *this, protocol, peer_endpoint, + &reactive_socket_move_accept_op::do_complete), + handler_(ASIO_MOVE_CAST(Handler)(handler)) + { + handler_work<Handler>::start(handler_); + } + + static void do_complete(void* owner, operation* base, + const asio::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_move_accept_op* o( + static_cast<reactive_socket_move_accept_op*>(base)); + ptr p = { asio::detail::addressof(o->handler_), o, o }; + typename Protocol::socket peer( + ASIO_MOVE_CAST(typename Protocol::socket)(*o)); + handler_work<Handler> w(o->handler_); + + ASIO_HANDLER_COMPLETION((o)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::move_binder2<Handler, asio::error_code, typename Protocol::socket> + handler(0, ASIO_MOVE_CAST(Handler)(o->handler_), o->ec_, + ASIO_MOVE_CAST(typename Protocol::socket)(peer)); + p.h = asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; +}; + +#endif // defined(ASIO_HAS_MOVE) + } // namespace detail } // namespace asio
diff --git a/asio/include/asio/detail/reactive_socket_service.hpp b/asio/include/asio/detail/reactive_socket_service.hpp index 9566777..4d3c723 100644 --- a/asio/include/asio/detail/reactive_socket_service.hpp +++ b/asio/include/asio/detail/reactive_socket_service.hpp
@@ -388,8 +388,33 @@ return ec; } - // Start an asynchronous accept. The peer and peer_endpoint objects - // must be valid until the accept's handler is invoked. + // Accept a new connection. + typename Protocol::socket accept(implementation_type& impl, + io_service* peer_io_service, endpoint_type* peer_endpoint, + asio::error_code& ec) + { + typename Protocol::socket peer( + peer_io_service ? *peer_io_service : io_service_); + + std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0; + socket_holder new_socket(socket_ops::sync_accept(impl.socket_, + impl.state_, peer_endpoint ? peer_endpoint->data() : 0, + peer_endpoint ? &addr_len : 0, ec)); + + // On success, assign new connection to peer socket object. + if (new_socket.get() != invalid_socket) + { + if (peer_endpoint) + peer_endpoint->resize(addr_len); + if (!peer.assign(impl.protocol_, new_socket.get(), ec)) + new_socket.release(); + } + + return peer; + } + + // Start an asynchronous accept. The peer and peer_endpoint objects must be + // valid until the accept's handler is invoked. template <typename Socket, typename Handler> void async_accept(implementation_type& impl, Socket& peer, endpoint_type* peer_endpoint, Handler& handler) @@ -410,6 +435,30 @@ p.v = p.p = 0; } +#if defined(ASIO_HAS_MOVE) + // Start an asynchronous accept. The peer_endpoint object must be valid until + // the accept's handler is invoked. + template <typename Handler> + void async_accept(implementation_type& impl, + endpoint_type* peer_endpoint, Handler& handler) + { + bool is_continuation = + asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_socket_move_accept_op<Protocol, Handler> op; + typename op::ptr p = { asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(io_service_, impl.socket_, impl.state_, + impl.protocol_, peer_endpoint, handler); + + ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_accept")); + + start_accept_op(impl, p.p, is_continuation, false); + p.v = p.p = 0; + } +#endif // defined(ASIO_HAS_MOVE) + // Connect the socket to the specified endpoint. asio::error_code connect(implementation_type& impl, const endpoint_type& peer_endpoint, asio::error_code& ec)
diff --git a/asio/include/asio/detail/reactive_socket_service_base.hpp b/asio/include/asio/detail/reactive_socket_service_base.hpp index d30fcae..d252cd2 100644 --- a/asio/include/asio/detail/reactive_socket_service_base.hpp +++ b/asio/include/asio/detail/reactive_socket_service_base.hpp
@@ -490,6 +490,9 @@ reactor_op* op, bool is_continuation, const socket_addr_type* addr, size_t addrlen); + // The io_service that owns this socket service. + io_service& io_service_; + // The selector that performs event demultiplexing for the service. reactor& reactor_; };
diff --git a/asio/include/asio/detail/win_iocp_socket_service.hpp b/asio/include/asio/detail/win_iocp_socket_service.hpp index 0bb6178..7903258 100644 --- a/asio/include/asio/detail/win_iocp_socket_service.hpp +++ b/asio/include/asio/detail/win_iocp_socket_service.hpp
@@ -457,6 +457,31 @@ return ec; } + // Accept a new connection. + typename Protocol::socket accept(implementation_type& impl, + io_service* peer_io_service, endpoint_type* peer_endpoint, + asio::error_code& ec) + { + typename Protocol::socket peer( + peer_io_service ? *peer_io_service : get_io_service()); + + std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0; + socket_holder new_socket(socket_ops::sync_accept(impl.socket_, + impl.state_, peer_endpoint ? peer_endpoint->data() : 0, + peer_endpoint ? &addr_len : 0, ec)); + + // On success, assign new connection to peer socket object. + if (new_socket.get() != invalid_socket) + { + if (peer_endpoint) + peer_endpoint->resize(addr_len); + if (!peer.assign(impl.protocol_, new_socket.get(), ec)) + new_socket.release(); + } + + return ec; + } + // Start an asynchronous accept. The peer and peer_endpoint objects // must be valid until the accept's handler is invoked. template <typename Socket, typename Handler>
diff --git a/asio/include/asio/socket_acceptor_service.hpp b/asio/include/asio/socket_acceptor_service.hpp index 9844dc2..a1fe502 100644 --- a/asio/include/asio/socket_acceptor_service.hpp +++ b/asio/include/asio/socket_acceptor_service.hpp
@@ -276,6 +276,16 @@ return service_impl_.accept(impl, peer, peer_endpoint, ec); } +#if defined(ASIO_HAS_MOVE) + /// Accept a new connection. + typename Protocol::socket accept(implementation_type& impl, + io_service* peer_io_service, endpoint_type* peer_endpoint, + asio::error_code& ec) + { + return service_impl_.accept(impl, peer_io_service, peer_endpoint, ec); + } +#endif // defined(ASIO_HAS_MOVE) + /// Start an asynchronous accept. template <typename Protocol1, typename SocketService, typename AcceptHandler> ASIO_INITFN_RESULT_TYPE(AcceptHandler, @@ -294,6 +304,24 @@ return init.result.get(); } +#if defined(ASIO_HAS_MOVE) + /// Start an asynchronous accept. + template <typename MoveAcceptHandler> + ASIO_INITFN_RESULT_TYPE(MoveAcceptHandler, + void (asio::error_code, typename Protocol::socket)) + async_accept(implementation_type& impl, + endpoint_type* peer_endpoint, + ASIO_MOVE_ARG(MoveAcceptHandler) handler) + { + async_completion<MoveAcceptHandler, + void (asio::error_code, typename Protocol::socket)> init(handler); + + service_impl_.async_accept(impl, peer_endpoint, init.handler); + + return init.result.get(); + } +#endif // defined(ASIO_HAS_MOVE) + private: // Destroy all user-defined handler objects owned by the service. void shutdown_service()
diff --git a/asio/src/doc/quickref.xml b/asio/src/doc/quickref.xml index a7526ec..0a762c2 100644 --- a/asio/src/doc/quickref.xml +++ b/asio/src/doc/quickref.xml
@@ -346,6 +346,7 @@ </simplelist> <bridgehead renderas="sect3">Type Requirements</bridgehead> <simplelist type="vert" columns="1"> + <member><link linkend="asio.reference.AcceptableProtocol">AcceptableProtocol</link></member> <member><link linkend="asio.reference.AcceptHandler">AcceptHandler</link></member> <member><link linkend="asio.reference.ComposedConnectHandler">ComposedConnectHandler</link></member> <member><link linkend="asio.reference.ConnectHandler">ConnectHandler</link></member>
diff --git a/asio/src/doc/reference.xsl b/asio/src/doc/reference.xsl index d2dce4b..eb8dc5e 100644 --- a/asio/src/doc/reference.xsl +++ b/asio/src/doc/reference.xsl
@@ -37,6 +37,7 @@ [xinclude quickref.xml] [include requirements/asynchronous_operations.qbk] +[include requirements/AcceptableProtocol.qbk] [include requirements/AcceptHandler.qbk] [include requirements/AsyncRandomAccessReadDevice.qbk] [include requirements/AsyncRandomAccessWriteDevice.qbk]
diff --git a/asio/src/doc/requirements/AcceptableProtocol.qbk b/asio/src/doc/requirements/AcceptableProtocol.qbk new file mode 100644 index 0000000..2cd3bf2 --- /dev/null +++ b/asio/src/doc/requirements/AcceptableProtocol.qbk
@@ -0,0 +1,25 @@ +[/ + / Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com) + / + / Distributed under the Boost Software License, Version 1.0. (See accompanying + / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + /] + +[section:AcceptableProtocol Acceptable protocol requirements] + +An acceptable protocol must meet the requirements for a [link +asio.reference.Protocol protocol] as well as the additional requirements listed +below. + +In the table below, `X` denotes an acceptable protocol class. + +[table AcceptableProtocol requirements + [[expression] [return type] [assertion/note\npre/post-conditions]] + [ + [`X::socket`] + [` + [The type of a socket for the protocol.] + ] +] + +[endsect]
diff --git a/asio/src/doc/requirements/MoveAcceptHandler.qbk b/asio/src/doc/requirements/MoveAcceptHandler.qbk new file mode 100644 index 0000000..c8f6080 --- /dev/null +++ b/asio/src/doc/requirements/MoveAcceptHandler.qbk
@@ -0,0 +1,41 @@ +[/ + / Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com) + / + / Distributed under the Boost Software License, Version 1.0. (See accompanying + / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + /] + +[section:MoveAcceptHandler Move accept handler requirements] + +A move accept handler must meet the requirements for a [link +asio.reference.Handler handler]. A value `h` of a move accept handler class +should work correctly in the expression `h(ec, s)`, where `ec` is an lvalue of +type `const error_code` and `s` is an lvalue of the nested type +`Protocol::socket` for the type `Protocol` of the socket class template. + +[heading Examples] + +A free function as a move accept handler: + + void connect_handler( + const asio::error_code& ec, + asio::ip::tcp::socket s) + { + ... + } + +A move accept handler function object: + + struct connect_handler + { + ... + void operator()( + const asio::error_code& ec, + asio::ip::tcp::socket s) + { + ... + } + ... + }; + +[endsect]
diff --git a/asio/src/examples/cpp11/echo/async_tcp_echo_server.cpp b/asio/src/examples/cpp11/echo/async_tcp_echo_server.cpp index 85f1520..7c9a2cb 100644 --- a/asio/src/examples/cpp11/echo/async_tcp_echo_server.cpp +++ b/asio/src/examples/cpp11/echo/async_tcp_echo_server.cpp
@@ -66,8 +66,7 @@ { public: server(asio::io_service& io_service, short port) - : acceptor_(io_service, tcp::endpoint(tcp::v4(), port)), - socket_(io_service) + : acceptor_(io_service, tcp::endpoint(tcp::v4(), port)) { do_accept(); } @@ -75,12 +74,12 @@ private: void do_accept() { - acceptor_.async_accept(socket_, - [this](std::error_code ec) + acceptor_.async_accept( + [this](std::error_code ec, tcp::socket socket) { if (!ec) { - std::make_shared<session>(std::move(socket_))->start(); + std::make_shared<session>(std::move(socket))->start(); } do_accept(); @@ -88,7 +87,6 @@ } tcp::acceptor acceptor_; - tcp::socket socket_; }; int main(int argc, char* argv[])
diff --git a/asio/src/examples/cpp11/echo/blocking_tcp_echo_server.cpp b/asio/src/examples/cpp11/echo/blocking_tcp_echo_server.cpp index 6a071fc..2fff5bf 100644 --- a/asio/src/examples/cpp11/echo/blocking_tcp_echo_server.cpp +++ b/asio/src/examples/cpp11/echo/blocking_tcp_echo_server.cpp
@@ -47,9 +47,7 @@ tcp::acceptor a(io_service, tcp::endpoint(tcp::v4(), port)); for (;;) { - tcp::socket sock(io_service); - a.accept(sock); - std::thread(session, std::move(sock)).detach(); + std::thread(session, a.accept()).detach(); } }