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();
}
}